@likec4/language-server 1.21.1 → 1.22.1
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/README.md +4 -1
- package/bin/likec4-language-server.mjs +5 -2
- package/dist/LikeC4FileSystem.js +2 -2
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +15 -2
- package/dist/bundled.d.ts +8 -0
- package/dist/bundled.js +25 -0
- package/dist/bundled.mjs +2555 -4022
- package/dist/index.d.ts +3 -3
- package/dist/index.js +19 -2
- package/dist/logger.d.ts +10 -3
- package/dist/logger.js +56 -50
- package/dist/model/fqn-computation.js +2 -2
- package/dist/model/model-builder.js +13 -14
- package/dist/model-change/ModelChanges.js +2 -2
- package/dist/module.js +1 -4
- package/dist/references/scope-provider.js +3 -3
- package/dist/view-utils/manual-layout.js +2 -2
- package/dist/views/configurable-layouter.js +4 -4
- package/dist/views/likec4-views.d.ts +2 -1
- package/dist/views/likec4-views.js +2 -2
- package/package.json +14 -12
- package/dist/test/setup.d.ts +0 -1
- package/dist/test/setup.js +0 -7
- package/src/LikeC4FileSystem.ts +0 -38
- package/src/Rpc.ts +0 -134
- package/src/ast.ts +0 -556
- package/src/browser.ts +0 -35
- package/src/documentation/documentation-provider.ts +0 -52
- package/src/documentation/index.ts +0 -1
- package/src/formatting/LikeC4Formatter.ts +0 -639
- package/src/formatting/utils.ts +0 -26
- package/src/generated/ast.ts +0 -3735
- package/src/generated/grammar.ts +0 -10
- package/src/generated/module.ts +0 -33
- package/src/generated-lib/icons.ts +0 -1538
- package/src/index.ts +0 -30
- package/src/like-c4.langium +0 -901
- package/src/likec4lib.ts +0 -6
- package/src/logger.ts +0 -80
- package/src/lsp/CodeLensProvider.ts +0 -50
- package/src/lsp/CompletionProvider.ts +0 -147
- package/src/lsp/DocumentHighlightProvider.ts +0 -12
- package/src/lsp/DocumentLinkProvider.ts +0 -65
- package/src/lsp/DocumentSymbolProvider.ts +0 -313
- package/src/lsp/HoverProvider.ts +0 -92
- package/src/lsp/RenameProvider.ts +0 -8
- package/src/lsp/SemanticTokenProvider.ts +0 -383
- package/src/lsp/index.ts +0 -8
- package/src/model/deployments-index.ts +0 -209
- package/src/model/fqn-computation.ts +0 -83
- package/src/model/fqn-index.ts +0 -138
- package/src/model/index.ts +0 -6
- package/src/model/model-builder.ts +0 -724
- package/src/model/model-locator.ts +0 -146
- package/src/model/model-parser-where.ts +0 -84
- package/src/model/model-parser.ts +0 -86
- package/src/model/parser/Base.ts +0 -113
- package/src/model/parser/DeploymentModelParser.ts +0 -192
- package/src/model/parser/DeploymentViewParser.ts +0 -122
- package/src/model/parser/FqnRefParser.ts +0 -143
- package/src/model/parser/GlobalsParser.ts +0 -96
- package/src/model/parser/ModelParser.ts +0 -170
- package/src/model/parser/PredicatesParser.ts +0 -315
- package/src/model/parser/SpecificationParser.ts +0 -133
- package/src/model/parser/ViewsParser.ts +0 -428
- package/src/model-change/ModelChanges.ts +0 -101
- package/src/model-change/changeElementStyle.ts +0 -172
- package/src/model-change/changeViewLayout.ts +0 -47
- package/src/model-change/saveManualLayout.ts +0 -41
- package/src/module.ts +0 -255
- package/src/protocol.ts +0 -93
- package/src/references/index.ts +0 -3
- package/src/references/name-provider.ts +0 -37
- package/src/references/scope-computation.ts +0 -364
- package/src/references/scope-provider.ts +0 -201
- package/src/shared/NodeKindProvider.ts +0 -121
- package/src/shared/WorkspaceManager.ts +0 -48
- package/src/shared/WorkspaceSymbolProvider.ts +0 -3
- package/src/shared/index.ts +0 -3
- package/src/test/index.ts +0 -1
- package/src/test/setup.ts +0 -8
- package/src/test/testServices.ts +0 -152
- package/src/utils/disposable.ts +0 -30
- package/src/utils/elementRef.ts +0 -26
- package/src/utils/fqnRef.ts +0 -56
- package/src/utils/index.ts +0 -2
- package/src/utils/printDocs.ts +0 -3
- package/src/utils/stringHash.ts +0 -6
- package/src/validation/_shared.ts +0 -29
- package/src/validation/deployment-checks.ts +0 -131
- package/src/validation/dynamic-view-rule.ts +0 -23
- package/src/validation/dynamic-view-step.ts +0 -36
- package/src/validation/element.ts +0 -56
- package/src/validation/index.ts +0 -171
- package/src/validation/property-checks.ts +0 -52
- package/src/validation/relation.ts +0 -63
- package/src/validation/specification.ts +0 -205
- package/src/validation/view-predicates/element-with.ts +0 -36
- package/src/validation/view-predicates/expanded-element.ts +0 -16
- package/src/validation/view-predicates/expression-v2.ts +0 -101
- package/src/validation/view-predicates/incoming.ts +0 -20
- package/src/validation/view-predicates/index.ts +0 -6
- package/src/validation/view-predicates/outgoing.ts +0 -20
- package/src/validation/view-predicates/relation-with.ts +0 -17
- package/src/validation/view.ts +0 -37
- package/src/view-utils/assignNavigateTo.ts +0 -31
- package/src/view-utils/index.ts +0 -2
- package/src/view-utils/manual-layout.ts +0 -116
- package/src/view-utils/resolve-relative-paths.ts +0 -90
- package/src/views/configurable-layouter.ts +0 -65
- package/src/views/index.ts +0 -1
- package/src/views/likec4-views.ts +0 -139
package/src/validation/index.ts
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { type AstNode, DocumentState } from 'langium'
|
|
2
|
-
import { isNullish } from 'remeda'
|
|
3
|
-
import { DiagnosticSeverity } from 'vscode-languageserver-types'
|
|
4
|
-
import { type LikeC4AstNode, type LikeC4LangiumDocument, ast } from '../ast'
|
|
5
|
-
import { logger } from '../logger'
|
|
6
|
-
import type { LikeC4Services } from '../module'
|
|
7
|
-
import { deployedInstanceChecks, deploymentNodeChecks, deploymentRelationChecks } from './deployment-checks'
|
|
8
|
-
import { dynamicViewRulePredicate } from './dynamic-view-rule'
|
|
9
|
-
import { dynamicViewStep } from './dynamic-view-step'
|
|
10
|
-
import { elementChecks } from './element'
|
|
11
|
-
import { iconPropertyRuleChecks, notesPropertyRuleChecks, opacityPropertyRuleChecks } from './property-checks'
|
|
12
|
-
import { relationBodyChecks, relationChecks } from './relation'
|
|
13
|
-
import {
|
|
14
|
-
deploymentNodeKindChecks,
|
|
15
|
-
elementKindChecks,
|
|
16
|
-
globalPredicateChecks,
|
|
17
|
-
globalsChecks,
|
|
18
|
-
globalStyleIdChecks,
|
|
19
|
-
modelRuleChecks,
|
|
20
|
-
relationshipChecks,
|
|
21
|
-
specificationRuleChecks,
|
|
22
|
-
tagChecks,
|
|
23
|
-
} from './specification'
|
|
24
|
-
import { viewChecks } from './view'
|
|
25
|
-
import {
|
|
26
|
-
elementPredicateWithChecks,
|
|
27
|
-
expandElementExprChecks,
|
|
28
|
-
fqnRefExprChecks,
|
|
29
|
-
incomingExpressionChecks,
|
|
30
|
-
outgoingExpressionChecks,
|
|
31
|
-
relationExprChecks,
|
|
32
|
-
relationPredicateWithChecks,
|
|
33
|
-
} from './view-predicates'
|
|
34
|
-
|
|
35
|
-
type Guard<N extends AstNode> = (n: AstNode) => n is N
|
|
36
|
-
type Guarded<G> = G extends Guard<infer N> ? N : never
|
|
37
|
-
|
|
38
|
-
function validatableAstNodeGuards<const Predicates extends Guard<AstNode>[]>(
|
|
39
|
-
predicates: Predicates,
|
|
40
|
-
) {
|
|
41
|
-
return (n: AstNode): n is Guarded<Predicates[number]> => predicates.some(p => p(n))
|
|
42
|
-
}
|
|
43
|
-
const isValidatableAstNode = validatableAstNodeGuards([
|
|
44
|
-
ast.isGlobals,
|
|
45
|
-
ast.isGlobalPredicateGroup,
|
|
46
|
-
ast.isGlobalDynamicPredicateGroup,
|
|
47
|
-
ast.isGlobalStyle,
|
|
48
|
-
ast.isGlobalStyleGroup,
|
|
49
|
-
ast.isDynamicViewPredicateIterator,
|
|
50
|
-
ast.isElementPredicateWith,
|
|
51
|
-
ast.isRelationPredicateWith,
|
|
52
|
-
ast.isElementExpression,
|
|
53
|
-
ast.isRelationExpression,
|
|
54
|
-
ast.isDynamicViewParallelSteps,
|
|
55
|
-
ast.isDynamicViewStep,
|
|
56
|
-
ast.isDeploymentViewRule,
|
|
57
|
-
ast.isDeploymentViewRulePredicate,
|
|
58
|
-
ast.isExpressionV2,
|
|
59
|
-
ast.isRelationExpr,
|
|
60
|
-
ast.isFqnRefExpr,
|
|
61
|
-
ast.isViewProperty,
|
|
62
|
-
ast.isStyleProperty,
|
|
63
|
-
ast.isPredicate,
|
|
64
|
-
ast.isTags,
|
|
65
|
-
ast.isViewRule,
|
|
66
|
-
ast.isDynamicViewRule,
|
|
67
|
-
ast.isLikeC4View,
|
|
68
|
-
ast.isViewRuleStyleOrGlobalRef,
|
|
69
|
-
ast.isDeployedInstance,
|
|
70
|
-
ast.isDeploymentNode,
|
|
71
|
-
ast.isDeploymentRelation,
|
|
72
|
-
ast.isRelationshipStyleProperty,
|
|
73
|
-
ast.isMetadataProperty,
|
|
74
|
-
ast.isRelation,
|
|
75
|
-
ast.isElementProperty,
|
|
76
|
-
ast.isStringProperty,
|
|
77
|
-
ast.isNavigateToProperty,
|
|
78
|
-
ast.isElement,
|
|
79
|
-
ast.isExtendElement,
|
|
80
|
-
ast.isSpecificationElementKind,
|
|
81
|
-
ast.isSpecificationRelationshipKind,
|
|
82
|
-
ast.isSpecificationDeploymentNodeKind,
|
|
83
|
-
ast.isSpecificationTag,
|
|
84
|
-
ast.isSpecificationColor,
|
|
85
|
-
ast.isSpecificationRule,
|
|
86
|
-
])
|
|
87
|
-
type ValidatableAstNode = Guarded<typeof isValidatableAstNode>
|
|
88
|
-
|
|
89
|
-
const findInvalidContainer = (node: LikeC4AstNode): ValidatableAstNode | undefined => {
|
|
90
|
-
let nd = node as LikeC4AstNode['$container']
|
|
91
|
-
while (nd && !ast.isLikeC4Grammar(nd)) {
|
|
92
|
-
if (isValidatableAstNode(nd)) {
|
|
93
|
-
return nd
|
|
94
|
-
}
|
|
95
|
-
nd = nd.$container
|
|
96
|
-
}
|
|
97
|
-
return undefined
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function checksFromDiagnostics(doc: LikeC4LangiumDocument) {
|
|
101
|
-
const errors = doc.state >= DocumentState.Validated
|
|
102
|
-
? (doc.diagnostics?.filter(d => d.severity === DiagnosticSeverity.Error) ?? [])
|
|
103
|
-
: []
|
|
104
|
-
const invalidNodes = new WeakSet()
|
|
105
|
-
for (const { node } of errors) {
|
|
106
|
-
if (isNullish(node) || invalidNodes.has(node)) {
|
|
107
|
-
continue
|
|
108
|
-
}
|
|
109
|
-
invalidNodes.add(node)
|
|
110
|
-
const container = findInvalidContainer(node)
|
|
111
|
-
if (container) {
|
|
112
|
-
invalidNodes.add(container)
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
const isValid = (n: ValidatableAstNode) => !invalidNodes.has(n)
|
|
116
|
-
return {
|
|
117
|
-
isValid,
|
|
118
|
-
invalidNodes,
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
export type ChecksFromDiagnostics = ReturnType<typeof checksFromDiagnostics>
|
|
122
|
-
export type IsValidFn = ChecksFromDiagnostics['isValid']
|
|
123
|
-
|
|
124
|
-
export function registerValidationChecks(services: LikeC4Services) {
|
|
125
|
-
logger.debug('registerValidationChecks')
|
|
126
|
-
const registry = services.validation.ValidationRegistry
|
|
127
|
-
registry.register<ast.LikeC4AstType>({
|
|
128
|
-
DeployedInstance: deployedInstanceChecks(services),
|
|
129
|
-
DeploymentNodeKind: deploymentNodeKindChecks(services),
|
|
130
|
-
DeploymentNode: deploymentNodeChecks(services),
|
|
131
|
-
DeploymentRelation: deploymentRelationChecks(services),
|
|
132
|
-
FqnRefExpr: fqnRefExprChecks(services),
|
|
133
|
-
RelationExpr: relationExprChecks(services),
|
|
134
|
-
NotesProperty: notesPropertyRuleChecks(services),
|
|
135
|
-
OpacityProperty: opacityPropertyRuleChecks(services),
|
|
136
|
-
IconProperty: iconPropertyRuleChecks(services),
|
|
137
|
-
SpecificationRule: specificationRuleChecks(services),
|
|
138
|
-
Model: modelRuleChecks(services),
|
|
139
|
-
Globals: globalsChecks(services),
|
|
140
|
-
GlobalPredicateGroup: globalPredicateChecks(services),
|
|
141
|
-
GlobalDynamicPredicateGroup: globalPredicateChecks(services),
|
|
142
|
-
GlobalStyleId: globalStyleIdChecks(services),
|
|
143
|
-
DynamicViewStep: dynamicViewStep(services),
|
|
144
|
-
LikeC4View: viewChecks(services),
|
|
145
|
-
Element: elementChecks(services),
|
|
146
|
-
ElementKind: elementKindChecks(services),
|
|
147
|
-
Relation: relationChecks(services),
|
|
148
|
-
RelationBody: relationBodyChecks(services),
|
|
149
|
-
Tag: tagChecks(services),
|
|
150
|
-
DynamicViewPredicateIterator: dynamicViewRulePredicate(services),
|
|
151
|
-
ElementPredicateWith: elementPredicateWithChecks(services),
|
|
152
|
-
RelationPredicateWith: relationPredicateWithChecks(services),
|
|
153
|
-
ExpandElementExpression: expandElementExprChecks(services),
|
|
154
|
-
RelationshipKind: relationshipChecks(services),
|
|
155
|
-
IncomingRelationExpression: incomingExpressionChecks(services),
|
|
156
|
-
OutgoingRelationExpression: outgoingExpressionChecks(services),
|
|
157
|
-
})
|
|
158
|
-
const connection = services.shared.lsp.Connection
|
|
159
|
-
if (connection) {
|
|
160
|
-
// workaround for bug in langium
|
|
161
|
-
services.shared.workspace.DocumentBuilder.onUpdate((_, deleted) => {
|
|
162
|
-
for (const uri of deleted) {
|
|
163
|
-
logger.debug(`clear diagnostics for deleted ${uri.path}`)
|
|
164
|
-
void connection.sendDiagnostics({
|
|
165
|
-
uri: uri.toString(),
|
|
166
|
-
diagnostics: [],
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
})
|
|
170
|
-
}
|
|
171
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { type ValidationCheck, AstUtils } from 'langium'
|
|
2
|
-
import { ast } from '../ast'
|
|
3
|
-
import type { LikeC4Services } from '../module'
|
|
4
|
-
import { tryOrLog } from './_shared'
|
|
5
|
-
|
|
6
|
-
export const opacityPropertyRuleChecks = (
|
|
7
|
-
_: LikeC4Services,
|
|
8
|
-
): ValidationCheck<ast.OpacityProperty> => {
|
|
9
|
-
return tryOrLog((node, accept) => {
|
|
10
|
-
const opacity = parseFloat(node.value)
|
|
11
|
-
if (isNaN(opacity) || opacity < 0 || opacity > 100) {
|
|
12
|
-
accept('warning', `Value ignored, must be between 0% and 100%`, {
|
|
13
|
-
node,
|
|
14
|
-
property: 'value',
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const iconPropertyRuleChecks = (
|
|
21
|
-
_: LikeC4Services,
|
|
22
|
-
): ValidationCheck<ast.IconProperty> => {
|
|
23
|
-
return (node, accept) => {
|
|
24
|
-
const container = node.$container
|
|
25
|
-
const anotherIcon = container.props.some(p => ast.isIconProperty(p) && p !== node)
|
|
26
|
-
if (anotherIcon) {
|
|
27
|
-
accept('error', `Icon must be defined once`, {
|
|
28
|
-
node,
|
|
29
|
-
})
|
|
30
|
-
}
|
|
31
|
-
if (
|
|
32
|
-
ast.isElementStyleProperty(container) && ast.isElementBody(container.$container)
|
|
33
|
-
&& container.$container.props.some(p => ast.isIconProperty(p))
|
|
34
|
-
) {
|
|
35
|
-
accept('warning', `Redundant as icon defined on element`, {
|
|
36
|
-
node,
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const notesPropertyRuleChecks = (
|
|
43
|
-
_: LikeC4Services,
|
|
44
|
-
): ValidationCheck<ast.NotesProperty> => {
|
|
45
|
-
return (node, accept) => {
|
|
46
|
-
if (!AstUtils.hasContainerOfType(node, ast.isDynamicViewStep)) {
|
|
47
|
-
accept('error', `Notes can be defined only inside dynamic view`, {
|
|
48
|
-
node,
|
|
49
|
-
})
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { isSameHierarchy } from '@likec4/core'
|
|
2
|
-
import type { ValidationCheck } from 'langium'
|
|
3
|
-
import { isDefined } from 'remeda'
|
|
4
|
-
import { ast } from '../ast'
|
|
5
|
-
import type { LikeC4Services } from '../module'
|
|
6
|
-
import { elementRef } from '../utils/elementRef'
|
|
7
|
-
import { tryOrLog } from './_shared'
|
|
8
|
-
|
|
9
|
-
export const relationChecks = (services: LikeC4Services): ValidationCheck<ast.Relation> => {
|
|
10
|
-
const fqnIndex = services.likec4.FqnIndex
|
|
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', {
|
|
25
|
-
node: el,
|
|
26
|
-
property: 'source'
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
} else {
|
|
30
|
-
if (!ast.isElementBody(el.$container)) {
|
|
31
|
-
return accept('error', 'Sourceless relation must be nested', {
|
|
32
|
-
node: el
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
sourceEl = el.$container.$container
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const source = fqnIndex.getFqn(sourceEl)
|
|
39
|
-
|
|
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
|
-
})
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
}
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import { type ValidationCheck, AstUtils } from 'langium'
|
|
2
|
-
import { ast } from '../ast'
|
|
3
|
-
import type { LikeC4Services } from '../module'
|
|
4
|
-
import { RESERVED_WORDS, tryOrLog } from './_shared'
|
|
5
|
-
|
|
6
|
-
export const specificationRuleChecks = (
|
|
7
|
-
_: LikeC4Services,
|
|
8
|
-
): ValidationCheck<ast.SpecificationRule> => {
|
|
9
|
-
return tryOrLog((node, accept) => {
|
|
10
|
-
if (node.$containerIndex && node.$containerIndex > 0) {
|
|
11
|
-
accept('warning', `Prefer one specification per document`, {
|
|
12
|
-
node: node,
|
|
13
|
-
property: 'name',
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const modelRuleChecks = (_: LikeC4Services): ValidationCheck<ast.Model> => {
|
|
20
|
-
return tryOrLog((node, accept) => {
|
|
21
|
-
if (node.$containerIndex && node.$containerIndex > 0) {
|
|
22
|
-
accept('warning', `Prefer one model per document`, {
|
|
23
|
-
node: node,
|
|
24
|
-
property: 'name',
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export const globalsChecks = (_: LikeC4Services): ValidationCheck<ast.Globals> => {
|
|
31
|
-
return tryOrLog((node, accept) => {
|
|
32
|
-
if (node.$containerIndex && node.$containerIndex > 0) {
|
|
33
|
-
accept('warning', `Prefer one global block per document`, {
|
|
34
|
-
node: node,
|
|
35
|
-
property: 'name',
|
|
36
|
-
})
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export const elementKindChecks = (services: LikeC4Services): ValidationCheck<ast.ElementKind> => {
|
|
42
|
-
const index = services.shared.workspace.IndexManager
|
|
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
|
-
}
|
|
50
|
-
const sameKind = index
|
|
51
|
-
.allElements(ast.ElementKind)
|
|
52
|
-
.filter(n => n.name === node.name && n.node !== node)
|
|
53
|
-
.head()
|
|
54
|
-
if (sameKind) {
|
|
55
|
-
const isAnotherDoc = sameKind.documentUri !== AstUtils.getDocument(node).uri
|
|
56
|
-
accept('error', `Duplicate element kind '${node.name}'`, {
|
|
57
|
-
node: node,
|
|
58
|
-
property: 'name',
|
|
59
|
-
...isAnotherDoc && {
|
|
60
|
-
relatedInformation: [
|
|
61
|
-
{
|
|
62
|
-
location: {
|
|
63
|
-
range: sameKind.nameSegment!.range,
|
|
64
|
-
uri: sameKind.documentUri.toString(),
|
|
65
|
-
},
|
|
66
|
-
message: `conflicting definition`,
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export const deploymentNodeKindChecks = (services: LikeC4Services): ValidationCheck<ast.DeploymentNodeKind> => {
|
|
76
|
-
const index = services.shared.workspace.IndexManager
|
|
77
|
-
return tryOrLog((node, accept) => {
|
|
78
|
-
if (RESERVED_WORDS.includes(node.name)) {
|
|
79
|
-
accept('error', `Reserved word: ${node.name}`, {
|
|
80
|
-
node: node,
|
|
81
|
-
property: 'name',
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
const sameKind = index
|
|
85
|
-
.allElements(ast.DeploymentNodeKind)
|
|
86
|
-
.filter(n => n.name === node.name && n.node !== node)
|
|
87
|
-
.head()
|
|
88
|
-
if (sameKind) {
|
|
89
|
-
const isAnotherDoc = sameKind.documentUri !== AstUtils.getDocument(node).uri
|
|
90
|
-
accept('error', `Duplicate deploymentNode kind '${node.name}'`, {
|
|
91
|
-
node: node,
|
|
92
|
-
property: 'name',
|
|
93
|
-
...isAnotherDoc && {
|
|
94
|
-
relatedInformation: [
|
|
95
|
-
{
|
|
96
|
-
location: {
|
|
97
|
-
range: sameKind.nameSegment!.range,
|
|
98
|
-
uri: sameKind.documentUri.toString(),
|
|
99
|
-
},
|
|
100
|
-
message: `conflicting definition`,
|
|
101
|
-
},
|
|
102
|
-
],
|
|
103
|
-
},
|
|
104
|
-
})
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export const tagChecks = (services: LikeC4Services): ValidationCheck<ast.Tag> => {
|
|
110
|
-
const index = services.shared.workspace.IndexManager
|
|
111
|
-
return tryOrLog((node, accept) => {
|
|
112
|
-
const tagname = '#' + node.name
|
|
113
|
-
const sameTag = index
|
|
114
|
-
.allElements(ast.Tag)
|
|
115
|
-
.filter(n => n.name === tagname && n.node !== node)
|
|
116
|
-
.head()
|
|
117
|
-
if (sameTag) {
|
|
118
|
-
const isAnotherDoc = sameTag.documentUri !== AstUtils.getDocument(node).uri
|
|
119
|
-
accept(
|
|
120
|
-
'error',
|
|
121
|
-
`Duplicate tag '${node.name}'`,
|
|
122
|
-
{
|
|
123
|
-
node,
|
|
124
|
-
property: 'name',
|
|
125
|
-
...isAnotherDoc && {
|
|
126
|
-
relatedInformation: [
|
|
127
|
-
{
|
|
128
|
-
location: {
|
|
129
|
-
range: sameTag.nameSegment!.range,
|
|
130
|
-
uri: sameTag.documentUri.toString(),
|
|
131
|
-
},
|
|
132
|
-
message: `conflicting definition`,
|
|
133
|
-
},
|
|
134
|
-
],
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export const relationshipChecks = (
|
|
143
|
-
services: LikeC4Services,
|
|
144
|
-
): ValidationCheck<ast.RelationshipKind> => {
|
|
145
|
-
const index = services.shared.workspace.IndexManager
|
|
146
|
-
return tryOrLog((node, accept) => {
|
|
147
|
-
if (RESERVED_WORDS.includes(node.name)) {
|
|
148
|
-
accept('error', `Reserved word: ${node.name}`, {
|
|
149
|
-
node: node,
|
|
150
|
-
property: 'name',
|
|
151
|
-
})
|
|
152
|
-
}
|
|
153
|
-
const sameKinds = index
|
|
154
|
-
.allElements(ast.RelationshipKind)
|
|
155
|
-
.filter(n => n.name === node.name)
|
|
156
|
-
.limit(2)
|
|
157
|
-
.count()
|
|
158
|
-
if (sameKinds > 1) {
|
|
159
|
-
accept('error', `Duplicate RelationshipKind '${node.name}'`, {
|
|
160
|
-
node: node,
|
|
161
|
-
property: 'name',
|
|
162
|
-
})
|
|
163
|
-
}
|
|
164
|
-
})
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export const globalPredicateChecks = (
|
|
168
|
-
services: LikeC4Services,
|
|
169
|
-
): ValidationCheck<ast.GlobalPredicateGroup | ast.GlobalDynamicPredicateGroup> => {
|
|
170
|
-
const index = services.shared.workspace.IndexManager
|
|
171
|
-
return tryOrLog((node, accept) => {
|
|
172
|
-
const predicateGroups = index.allElements(ast.GlobalPredicateGroup)
|
|
173
|
-
const dynamicPredicateGroups = index.allElements(ast.GlobalDynamicPredicateGroup)
|
|
174
|
-
const sameName = predicateGroups
|
|
175
|
-
.concat(dynamicPredicateGroups)
|
|
176
|
-
.filter(s => s.name === node.name)
|
|
177
|
-
.limit(2)
|
|
178
|
-
.count()
|
|
179
|
-
if (sameName > 1) {
|
|
180
|
-
accept('error', `Duplicate GlobalPredicateGroup or GlobalDynamicPredicateGroup name '${node.name}'`, {
|
|
181
|
-
node: node,
|
|
182
|
-
property: 'name',
|
|
183
|
-
})
|
|
184
|
-
}
|
|
185
|
-
})
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export const globalStyleIdChecks = (
|
|
189
|
-
services: LikeC4Services,
|
|
190
|
-
): ValidationCheck<ast.GlobalStyleId> => {
|
|
191
|
-
const index = services.shared.workspace.IndexManager
|
|
192
|
-
return tryOrLog((node, accept) => {
|
|
193
|
-
const sameName = index
|
|
194
|
-
.allElements(ast.GlobalStyleId)
|
|
195
|
-
.filter(s => s.name === node.name)
|
|
196
|
-
.limit(2)
|
|
197
|
-
.count()
|
|
198
|
-
if (sameName > 1) {
|
|
199
|
-
accept('error', `Duplicate GlobalStyleId name '${node.name}'`, {
|
|
200
|
-
node: node,
|
|
201
|
-
property: 'name',
|
|
202
|
-
})
|
|
203
|
-
}
|
|
204
|
-
})
|
|
205
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { nonexhaustive } from '@likec4/core'
|
|
2
|
-
import type { ValidationCheck } from 'langium'
|
|
3
|
-
import { AstUtils } from 'langium'
|
|
4
|
-
import { ast } from '../../ast'
|
|
5
|
-
import type { LikeC4Services } from '../../module'
|
|
6
|
-
import { tryOrLog } from '../_shared'
|
|
7
|
-
|
|
8
|
-
export const elementPredicateWithChecks = (
|
|
9
|
-
_services: LikeC4Services,
|
|
10
|
-
): ValidationCheck<ast.ElementPredicateWith> => {
|
|
11
|
-
return tryOrLog((el, accept) => {
|
|
12
|
-
const container = AstUtils.getContainerOfType(el, ast.isViewRulePredicate)
|
|
13
|
-
if (ast.isExcludePredicate(container)) {
|
|
14
|
-
accept('error', 'Invalid usage inside "exclude"', {
|
|
15
|
-
node: el,
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
const subject = ast.isElementPredicateWhere(el.subject) ? el.subject.subject : el.subject
|
|
19
|
-
switch (true) {
|
|
20
|
-
case ast.isElementRef(subject):
|
|
21
|
-
case ast.isElementDescedantsExpression(subject):
|
|
22
|
-
case ast.isExpandElementExpression(subject):
|
|
23
|
-
case ast.isWildcardExpression(subject):
|
|
24
|
-
return
|
|
25
|
-
case ast.isElementKindExpression(subject):
|
|
26
|
-
case ast.isElementTagExpression(subject):
|
|
27
|
-
accept('error', 'Invalid target (expect reference to specific element)', {
|
|
28
|
-
node: el,
|
|
29
|
-
property: 'subject',
|
|
30
|
-
})
|
|
31
|
-
return
|
|
32
|
-
default:
|
|
33
|
-
nonexhaustive(subject)
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { type ValidationCheck, AstUtils } from 'langium'
|
|
2
|
-
import { ast } from '../../ast'
|
|
3
|
-
import type { LikeC4Services } from '../../module'
|
|
4
|
-
import { tryOrLog } from '../_shared'
|
|
5
|
-
|
|
6
|
-
export const expandElementExprChecks = (
|
|
7
|
-
_services: LikeC4Services,
|
|
8
|
-
): ValidationCheck<ast.ExpandElementExpression> => {
|
|
9
|
-
return tryOrLog((el, accept) => {
|
|
10
|
-
if (AstUtils.hasContainerOfType(el, ast.isRelationExpression)) {
|
|
11
|
-
accept('warning', `Redundant usage, expand predicate resolves parent element only when used in relations`, {
|
|
12
|
-
node: el,
|
|
13
|
-
})
|
|
14
|
-
}
|
|
15
|
-
})
|
|
16
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { FqnExpr, FqnRef } from '@likec4/core'
|
|
2
|
-
import { AstUtils, type ValidationCheck } from 'langium'
|
|
3
|
-
import { isNonNullish, isNullish } from 'remeda'
|
|
4
|
-
import { ast } from '../../ast'
|
|
5
|
-
import type { LikeC4Services } from '../../module'
|
|
6
|
-
import { tryOrLog } from '../_shared'
|
|
7
|
-
|
|
8
|
-
export const relationExprChecks = (services: LikeC4Services): ValidationCheck<ast.RelationExpr> => {
|
|
9
|
-
const ModelParser = services.likec4.ModelParser
|
|
10
|
-
return tryOrLog((node, accept) => {
|
|
11
|
-
if (node.$container.$type !== 'DeploymentViewRulePredicateExpression') {
|
|
12
|
-
// skip validation for this node, validated by container
|
|
13
|
-
return
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const predicate = AstUtils.getContainerOfType(node, ast.isDeploymentViewRulePredicate)
|
|
17
|
-
if (!predicate || predicate.isInclude !== true) {
|
|
18
|
-
// no restriction for exclude predicate
|
|
19
|
-
return
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const doc = AstUtils.getDocument(node)
|
|
23
|
-
const parser = ModelParser.forDocument(doc)
|
|
24
|
-
|
|
25
|
-
const ModelRefOnlyExclude = 'Model reference is allowed in exclude predicate only'
|
|
26
|
-
|
|
27
|
-
if (ast.isDirectedRelationExpr(node)) {
|
|
28
|
-
if (FqnExpr.isModelRef(parser.parseFqnExpr(node.source.from))) {
|
|
29
|
-
accept('error', ModelRefOnlyExclude, {
|
|
30
|
-
node: node.source,
|
|
31
|
-
property: 'from'
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (FqnExpr.isModelRef(parser.parseFqnExpr(node.target))) {
|
|
36
|
-
accept('error', ModelRefOnlyExclude, {
|
|
37
|
-
node,
|
|
38
|
-
property: 'target'
|
|
39
|
-
})
|
|
40
|
-
}
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let expr: ast.FqnExpr
|
|
45
|
-
if (ast.isIncomingRelationExpr(node)) {
|
|
46
|
-
expr = node.to
|
|
47
|
-
} else if (ast.isOutgoingRelationExpr(node)) {
|
|
48
|
-
expr = node.from
|
|
49
|
-
} else {
|
|
50
|
-
expr = node.inout.to
|
|
51
|
-
}
|
|
52
|
-
if (FqnExpr.isModelRef(parser.parseFqnExpr(expr))) {
|
|
53
|
-
accept('error', ModelRefOnlyExclude, {
|
|
54
|
-
node
|
|
55
|
-
})
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export const fqnRefExprChecks = (services: LikeC4Services): ValidationCheck<ast.FqnRefExpr> => {
|
|
62
|
-
const ModelParser = services.likec4.ModelParser
|
|
63
|
-
// const DeploymentsIndex = services.likec4.DeploymentsIndex
|
|
64
|
-
// const Names = services.references.NameProvider as LikeC4NameProvider
|
|
65
|
-
// const Locator = services.workspace.AstNodeLocator
|
|
66
|
-
// const fqnIndex = services.likec4.FqnIndex
|
|
67
|
-
return tryOrLog((node, accept) => {
|
|
68
|
-
const referenceTo = node.ref.value.ref
|
|
69
|
-
if (isNullish(referenceTo)) {
|
|
70
|
-
accept('error', 'Invalid empty reference', {
|
|
71
|
-
node
|
|
72
|
-
})
|
|
73
|
-
return
|
|
74
|
-
}
|
|
75
|
-
const doc = AstUtils.getDocument(node)
|
|
76
|
-
const expr = ModelParser.forDocument(doc).parseFqnRefExpr(node)
|
|
77
|
-
|
|
78
|
-
// This expression is part of element predicate
|
|
79
|
-
if (node.$container.$type === 'DeploymentViewRulePredicateExpression') {
|
|
80
|
-
if (FqnExpr.isModelRef(expr)) {
|
|
81
|
-
accept('error', 'Deployment view predicate must reference deployment model', {
|
|
82
|
-
node
|
|
83
|
-
})
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
if (FqnExpr.isDeploymentRef(expr) && FqnRef.isInsideInstanceRef(expr.ref)) {
|
|
87
|
-
accept('error', 'Must reference deployment nodes or instances, but not internals', {
|
|
88
|
-
node
|
|
89
|
-
})
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (!ast.isDeploymentNode(referenceTo) && isNonNullish(node.selector)) {
|
|
95
|
-
accept('warning', `Selector '${node.selector}' applies to deployment nodes only, ignored here`, {
|
|
96
|
-
node,
|
|
97
|
-
property: 'selector'
|
|
98
|
-
})
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type ValidationCheck, AstUtils } from 'langium'
|
|
2
|
-
import { isNullish } from 'remeda'
|
|
3
|
-
import { ast } from '../../ast'
|
|
4
|
-
import type { LikeC4Services } from '../../module'
|
|
5
|
-
import { tryOrLog } from '../_shared'
|
|
6
|
-
|
|
7
|
-
export const incomingExpressionChecks = (
|
|
8
|
-
_services: LikeC4Services,
|
|
9
|
-
): ValidationCheck<ast.IncomingRelationExpression> => {
|
|
10
|
-
return tryOrLog((el, accept) => {
|
|
11
|
-
if (ast.isWildcardExpression(el.to) && !ast.isInOutRelationExpression(el.$container)) {
|
|
12
|
-
const view = AstUtils.getContainerOfType(el, ast.isElementView)
|
|
13
|
-
if (isNullish(view?.viewOf)) {
|
|
14
|
-
accept('warning', 'Predicate is ignored as it concerns all relationships', {
|
|
15
|
-
node: el,
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type ValidationCheck, AstUtils } from 'langium'
|
|
2
|
-
import { isNullish } from 'remeda'
|
|
3
|
-
import { ast } from '../../ast'
|
|
4
|
-
import type { LikeC4Services } from '../../module'
|
|
5
|
-
import { tryOrLog } from '../_shared'
|
|
6
|
-
|
|
7
|
-
export const outgoingExpressionChecks = (
|
|
8
|
-
_services: LikeC4Services,
|
|
9
|
-
): ValidationCheck<ast.OutgoingRelationExpression> => {
|
|
10
|
-
return tryOrLog((el, accept) => {
|
|
11
|
-
if (ast.isWildcardExpression(el.from) && !ast.isDirectedRelationExpression(el.$container)) {
|
|
12
|
-
const view = AstUtils.getContainerOfType(el, ast.isElementView)
|
|
13
|
-
if (isNullish(view?.viewOf)) {
|
|
14
|
-
accept('warning', 'Predicate is ignored as it concerns all relationships', {
|
|
15
|
-
node: el,
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
}
|