@likec4/language-server 1.15.0 → 1.15.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/dist/browser.cjs +1 -1
- package/dist/browser.mjs +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/model-graph/index.cjs +1 -1
- package/dist/model-graph/index.mjs +1 -1
- package/dist/shared/{language-server.80ITEDo5.cjs → language-server.B8s2wfT_.cjs} +7 -4
- package/dist/shared/{language-server.DXC9g4_f.mjs → language-server.BT4WTbFI.mjs} +7 -4
- package/dist/shared/{language-server.zY53FGJE.mjs → language-server.BuChFlda.mjs} +43 -14
- package/dist/shared/{language-server.BUtiWTKg.cjs → language-server.DfjkvknB.cjs} +43 -14
- package/package.json +6 -6
- package/src/formatting/LikeC4Formatter.ts +44 -4
- package/src/lsp/SemanticTokenProvider.ts +3 -1
- package/src/model/model-builder.ts +13 -6
- package/src/model-graph/compute-view/__test__/fixture.ts +51 -25
- package/src/model-graph/utils/applyCustomRelationProperties.ts +7 -38
- package/src/model-graph/utils/relationExpressionToPredicates.ts +43 -0
package/dist/browser.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const lsp = require('langium/lsp');
|
|
4
4
|
const browser = require('vscode-languageserver/browser');
|
|
5
|
-
const module$1 = require('./shared/language-server.
|
|
5
|
+
const module$1 = require('./shared/language-server.DfjkvknB.cjs');
|
|
6
6
|
|
|
7
7
|
function startLanguageServer() {
|
|
8
8
|
const messageReader = new browser.BrowserMessageReader(self);
|
package/dist/browser.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { startLanguageServer as startLanguageServer$1 } from 'langium/lsp';
|
|
2
2
|
import { BrowserMessageReader, BrowserMessageWriter, createConnection } from 'vscode-languageserver/browser';
|
|
3
|
-
import { c as createLanguageServices } from './shared/language-server.
|
|
4
|
-
export { L as LikeC4Module, a as createCustomLanguageServices, s as setLogLevel } from './shared/language-server.
|
|
3
|
+
import { c as createLanguageServices } from './shared/language-server.BuChFlda.mjs';
|
|
4
|
+
export { L as LikeC4Module, a as createCustomLanguageServices, s as setLogLevel } from './shared/language-server.BuChFlda.mjs';
|
|
5
5
|
|
|
6
6
|
function startLanguageServer() {
|
|
7
7
|
const messageReader = new BrowserMessageReader(self);
|
package/dist/index.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const lsp = require('langium/lsp');
|
|
4
4
|
const node$1 = require('langium/node');
|
|
5
5
|
const node = require('vscode-languageserver/node');
|
|
6
|
-
const module$1 = require('./shared/language-server.
|
|
6
|
+
const module$1 = require('./shared/language-server.DfjkvknB.cjs');
|
|
7
7
|
|
|
8
8
|
function startLanguageServer() {
|
|
9
9
|
const connection = node.createConnection(node.ProposedFeatures.all);
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { startLanguageServer as startLanguageServer$1 } from 'langium/lsp';
|
|
2
2
|
import { NodeFileSystem } from 'langium/node';
|
|
3
3
|
import { createConnection, ProposedFeatures } from 'vscode-languageserver/node';
|
|
4
|
-
import { c as createLanguageServices } from './shared/language-server.
|
|
5
|
-
export { L as LikeC4Module, a as createCustomLanguageServices, l as lspLogger, s as setLogLevel } from './shared/language-server.
|
|
4
|
+
import { c as createLanguageServices } from './shared/language-server.BuChFlda.mjs';
|
|
5
|
+
export { L as LikeC4Module, a as createCustomLanguageServices, l as lspLogger, s as setLogLevel } from './shared/language-server.BuChFlda.mjs';
|
|
6
6
|
|
|
7
7
|
function startLanguageServer() {
|
|
8
8
|
const connection = createConnection(ProposedFeatures.all);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { L as LikeC4ModelGraph, b as computeDynamicView, c as computeElementView, a as computeView } from '../shared/language-server.
|
|
1
|
+
export { L as LikeC4ModelGraph, b as computeDynamicView, c as computeElementView, a as computeView } from '../shared/language-server.BT4WTbFI.mjs';
|
|
@@ -121,7 +121,9 @@ function applyCustomElementProperties(_rules, _nodes) {
|
|
|
121
121
|
function relationExpressionToPredicates(expr) {
|
|
122
122
|
switch (true) {
|
|
123
123
|
case core.Expr.isRelationWhere(expr):
|
|
124
|
-
|
|
124
|
+
const predicate = relationExpressionToPredicates(expr.where.expr);
|
|
125
|
+
const where = core.whereOperatorAsPredicate(expr.where.condition);
|
|
126
|
+
return (e) => predicate(e) && where(e);
|
|
125
127
|
case core.Expr.isRelation(expr): {
|
|
126
128
|
const isSource = elementExprToPredicate(expr.source);
|
|
127
129
|
const isTarget = elementExprToPredicate(expr.target);
|
|
@@ -145,6 +147,7 @@ function relationExpressionToPredicates(expr) {
|
|
|
145
147
|
core.nonexhaustive(expr);
|
|
146
148
|
}
|
|
147
149
|
}
|
|
150
|
+
|
|
148
151
|
function applyCustomRelationProperties(_rules, nodes, _edges) {
|
|
149
152
|
const rules = _rules.flatMap(flattenGroupRules(core.Expr.isCustomRelationExpr));
|
|
150
153
|
const edges = Array.from(_edges);
|
|
@@ -162,12 +165,12 @@ function applyCustomRelationProperties(_rules, nodes, _edges) {
|
|
|
162
165
|
if (!source || !target) {
|
|
163
166
|
return;
|
|
164
167
|
}
|
|
165
|
-
if (satisfies({ source, target })) {
|
|
168
|
+
if (satisfies({ source, target, ...remeda.pick(edge, ["kind", "tags"]) })) {
|
|
166
169
|
edges[i] = {
|
|
167
170
|
...edge,
|
|
171
|
+
...props,
|
|
168
172
|
label: title ?? edge.label,
|
|
169
|
-
isCustomized: true
|
|
170
|
-
...props
|
|
173
|
+
isCustomized: true
|
|
171
174
|
};
|
|
172
175
|
}
|
|
173
176
|
});
|
|
@@ -114,7 +114,9 @@ function applyCustomElementProperties(_rules, _nodes) {
|
|
|
114
114
|
function relationExpressionToPredicates(expr) {
|
|
115
115
|
switch (true) {
|
|
116
116
|
case Expr.isRelationWhere(expr):
|
|
117
|
-
|
|
117
|
+
const predicate = relationExpressionToPredicates(expr.where.expr);
|
|
118
|
+
const where = whereOperatorAsPredicate(expr.where.condition);
|
|
119
|
+
return (e) => predicate(e) && where(e);
|
|
118
120
|
case Expr.isRelation(expr): {
|
|
119
121
|
const isSource = elementExprToPredicate(expr.source);
|
|
120
122
|
const isTarget = elementExprToPredicate(expr.target);
|
|
@@ -138,6 +140,7 @@ function relationExpressionToPredicates(expr) {
|
|
|
138
140
|
nonexhaustive(expr);
|
|
139
141
|
}
|
|
140
142
|
}
|
|
143
|
+
|
|
141
144
|
function applyCustomRelationProperties(_rules, nodes, _edges) {
|
|
142
145
|
const rules = _rules.flatMap(flattenGroupRules(Expr.isCustomRelationExpr));
|
|
143
146
|
const edges = Array.from(_edges);
|
|
@@ -155,12 +158,12 @@ function applyCustomRelationProperties(_rules, nodes, _edges) {
|
|
|
155
158
|
if (!source || !target) {
|
|
156
159
|
return;
|
|
157
160
|
}
|
|
158
|
-
if (satisfies({ source, target })) {
|
|
161
|
+
if (satisfies({ source, target, ...pick(edge, ["kind", "tags"]) })) {
|
|
159
162
|
edges[i] = {
|
|
160
163
|
...edge,
|
|
164
|
+
...props,
|
|
161
165
|
label: title ?? edge.label,
|
|
162
|
-
isCustomized: true
|
|
163
|
-
...props
|
|
166
|
+
isCustomized: true
|
|
164
167
|
};
|
|
165
168
|
}
|
|
166
169
|
});
|
|
@@ -13,7 +13,7 @@ import { URI as URI$1 } from 'vscode-uri';
|
|
|
13
13
|
import stripIndent from 'strip-indent';
|
|
14
14
|
import hash from 'string-hash';
|
|
15
15
|
import { deepEqual } from 'fast-equals';
|
|
16
|
-
import { G as Graph, i as isAcyclic, f as findCycles, p as postorder, L as LikeC4ModelGraph, a as computeView, b as computeDynamicView } from './language-server.
|
|
16
|
+
import { G as Graph, i as isAcyclic, f as findCycles, p as postorder, L as LikeC4ModelGraph, a as computeView, b as computeDynamicView } from './language-server.BT4WTbFI.mjs';
|
|
17
17
|
import { hasProtocol, hasLeadingSlash, isRelative, withoutLeadingSlash, withoutBase, parsePath } from 'ufo';
|
|
18
18
|
import { DocumentHighlight, DocumentHighlightKind } from 'vscode-languageserver';
|
|
19
19
|
|
|
@@ -2410,7 +2410,7 @@ class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
2410
2410
|
SemanticTokenModifiers.readonly
|
|
2411
2411
|
]
|
|
2412
2412
|
});
|
|
2413
|
-
return;
|
|
2413
|
+
return "prune";
|
|
2414
2414
|
}
|
|
2415
2415
|
if (isWhereRelationKind(node) && isTruthy(node.value)) {
|
|
2416
2416
|
acceptor({
|
|
@@ -2439,6 +2439,7 @@ class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
2439
2439
|
type: SemanticTokenTypes.type,
|
|
2440
2440
|
modifier: [SemanticTokenModifiers.definition]
|
|
2441
2441
|
});
|
|
2442
|
+
return "prune";
|
|
2442
2443
|
}
|
|
2443
2444
|
if (isElementTagExpression(node) && isTruthy(node.tag)) {
|
|
2444
2445
|
acceptor({
|
|
@@ -2447,6 +2448,7 @@ class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
2447
2448
|
type: SemanticTokenTypes.type,
|
|
2448
2449
|
modifier: [SemanticTokenModifiers.definition]
|
|
2449
2450
|
});
|
|
2451
|
+
return "prune";
|
|
2450
2452
|
}
|
|
2451
2453
|
if (isElementRef(node) || isFqnElementRef(node)) {
|
|
2452
2454
|
acceptor({
|
|
@@ -3139,17 +3141,22 @@ function buildModel(services, docs) {
|
|
|
3139
3141
|
const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
|
|
3140
3142
|
return {
|
|
3141
3143
|
...model,
|
|
3144
|
+
customColorDefinitions,
|
|
3142
3145
|
tags,
|
|
3143
3146
|
links,
|
|
3144
3147
|
docUri,
|
|
3145
3148
|
description,
|
|
3146
3149
|
title,
|
|
3147
|
-
id
|
|
3148
|
-
customColorDefinitions
|
|
3150
|
+
id
|
|
3149
3151
|
};
|
|
3150
3152
|
};
|
|
3151
3153
|
}
|
|
3152
|
-
const parsedViews =
|
|
3154
|
+
const parsedViews = pipe(
|
|
3155
|
+
docs,
|
|
3156
|
+
flatMap((d) => map(d.c4Views, toC4View(d))),
|
|
3157
|
+
// Resolve relative paths and sort by
|
|
3158
|
+
resolveRelativePaths
|
|
3159
|
+
);
|
|
3153
3160
|
if (!parsedViews.some((v) => v.id === "index")) {
|
|
3154
3161
|
parsedViews.unshift({
|
|
3155
3162
|
__: "element",
|
|
@@ -3172,7 +3179,6 @@ function buildModel(services, docs) {
|
|
|
3172
3179
|
}
|
|
3173
3180
|
const views = pipe(
|
|
3174
3181
|
parsedViews,
|
|
3175
|
-
resolveRelativePaths,
|
|
3176
3182
|
indexBy(prop("id")),
|
|
3177
3183
|
resolveRulesExtendedViews
|
|
3178
3184
|
);
|
|
@@ -3235,7 +3241,7 @@ class LikeC4ModelBuilder {
|
|
|
3235
3241
|
logger.debug("[ModelBuilder] No documents to build model from");
|
|
3236
3242
|
return null;
|
|
3237
3243
|
}
|
|
3238
|
-
logger.debug(`[ModelBuilder]
|
|
3244
|
+
logger.debug(`[ModelBuilder] buildModel (${docs.length} docs)`);
|
|
3239
3245
|
return buildModel(this.services, docs);
|
|
3240
3246
|
});
|
|
3241
3247
|
}
|
|
@@ -3264,7 +3270,8 @@ class LikeC4ModelBuilder {
|
|
|
3264
3270
|
const index = new LikeC4ModelGraph(model);
|
|
3265
3271
|
const allViews = [];
|
|
3266
3272
|
for (const view of values(model.views)) {
|
|
3267
|
-
const
|
|
3273
|
+
const resolvedView = resolveGlobalRules(view, model.globals.styles);
|
|
3274
|
+
const result = isElementView$1(resolvedView) ? computeView(resolvedView, index) : computeDynamicView(resolvedView, index);
|
|
3268
3275
|
if (!result.isSuccess) {
|
|
3269
3276
|
logWarnError(result.error);
|
|
3270
3277
|
continue;
|
|
@@ -5822,16 +5829,19 @@ class LikeC4Formatter extends AbstractFormatter {
|
|
|
5822
5829
|
this.removeIndentFromTopLevelStatements(node);
|
|
5823
5830
|
this.indentContentInBraces(node);
|
|
5824
5831
|
this.formatSpecificationRule(node);
|
|
5832
|
+
this.formatGlobals(node);
|
|
5825
5833
|
this.formatElementDeclaration(node);
|
|
5826
5834
|
this.formatRelation(node);
|
|
5835
|
+
this.formatMetadataProperty(node);
|
|
5827
5836
|
this.formatView(node);
|
|
5828
|
-
this.
|
|
5837
|
+
this.formatViewRuleGroup(node);
|
|
5838
|
+
this.formatViewRuleGlobalStyle(node);
|
|
5829
5839
|
this.formatIncludeExcludeExpressions(node);
|
|
5830
5840
|
this.formatWhereExpression(node);
|
|
5841
|
+
this.formatAutolayoutProperty(node);
|
|
5831
5842
|
this.formatWithPredicate(node);
|
|
5843
|
+
this.formatViewRuleStyle(node);
|
|
5832
5844
|
this.formatLeafProperty(node);
|
|
5833
|
-
this.formatMetadataProperty(node);
|
|
5834
|
-
this.formatAutolayoutProperty(node);
|
|
5835
5845
|
this.formatLinkProperty(node);
|
|
5836
5846
|
this.formatNavigateToProperty(node);
|
|
5837
5847
|
this.formatTags(node);
|
|
@@ -5868,13 +5878,13 @@ class LikeC4Formatter extends AbstractFormatter {
|
|
|
5868
5878
|
this.on(node, isInOutRelationExpression)?.keyword("->").prepend(FormattingOptions.oneSpace);
|
|
5869
5879
|
}
|
|
5870
5880
|
removeIndentFromTopLevelStatements(node) {
|
|
5871
|
-
if (isModel(node) || isSpecificationRule(node) || isModelViews(node) || isLikeC4Lib(node)) {
|
|
5881
|
+
if (isModel(node) || isSpecificationRule(node) || isModelViews(node) || isLikeC4Lib(node) || isGlobals(node)) {
|
|
5872
5882
|
const formatter = this.getNodeFormatter(node);
|
|
5873
|
-
formatter.keywords("specification", "model", "views", "likec4lib").prepend(FormattingOptions.noIndent);
|
|
5883
|
+
formatter.keywords("specification", "model", "views", "likec4lib", "global").prepend(FormattingOptions.noIndent);
|
|
5874
5884
|
}
|
|
5875
5885
|
}
|
|
5876
5886
|
indentContentInBraces(node) {
|
|
5877
|
-
if (isLikeC4Lib(node) || isSpecificationRule(node) || isSpecificationElementKind(node) || isSpecificationRelationshipKind(node) || isModel(node) || isElementBody(node) || isExtendElementBody(node) || isRelationBody(node) || isRelationStyleProperty(node) || isMetadataBody(node) || isModelViews(node) || isElementViewBody(node) || isDynamicViewBody(node) || isViewRuleStyle(node) || isCustomElementProperties(node) || isCustomRelationProperties(node) || isElementStyleProperty(node) || isDynamicViewParallelSteps(node)) {
|
|
5887
|
+
if (isLikeC4Lib(node) || isSpecificationRule(node) || isSpecificationElementKind(node) || isSpecificationRelationshipKind(node) || isGlobals(node) || isGlobalStyle(node) || isGlobalStyleGroup(node) || isModel(node) || isElementBody(node) || isExtendElementBody(node) || isRelationBody(node) || isRelationStyleProperty(node) || isMetadataBody(node) || isModelViews(node) || isElementViewBody(node) || isDynamicViewBody(node) || isViewRuleStyle(node) || isViewRuleGroup(node) || isCustomElementProperties(node) || isCustomRelationProperties(node) || isElementStyleProperty(node) || isDynamicViewParallelSteps(node)) {
|
|
5878
5888
|
const formatter = this.getNodeFormatter(node);
|
|
5879
5889
|
const openBrace = formatter.keywords("{");
|
|
5880
5890
|
const closeBrace = formatter.keywords("}");
|
|
@@ -5968,6 +5978,15 @@ class LikeC4Formatter extends AbstractFormatter {
|
|
|
5968
5978
|
f.properties("props").prepend(FormattingOptions.oneSpace);
|
|
5969
5979
|
});
|
|
5970
5980
|
}
|
|
5981
|
+
formatGlobals(node) {
|
|
5982
|
+
this.on(node, isGlobalStyle, (n, f) => {
|
|
5983
|
+
f.keyword("style").append(FormattingOptions.oneSpace);
|
|
5984
|
+
f.property("id").append(FormattingOptions.oneSpace);
|
|
5985
|
+
});
|
|
5986
|
+
this.on(node, isGlobalStyleGroup, (n, f) => {
|
|
5987
|
+
f.keyword("styleGroup").append(FormattingOptions.oneSpace);
|
|
5988
|
+
});
|
|
5989
|
+
}
|
|
5971
5990
|
formatSpecificationRule(node) {
|
|
5972
5991
|
if (isSpecificationElementKind(node) || isSpecificationRelationshipKind(node) || isSpecificationTag(node)) {
|
|
5973
5992
|
const formatter = this.getNodeFormatter(node);
|
|
@@ -5985,6 +6004,16 @@ class LikeC4Formatter extends AbstractFormatter {
|
|
|
5985
6004
|
formatter.keyword("with").prepend(FormattingOptions.oneSpace);
|
|
5986
6005
|
}
|
|
5987
6006
|
}
|
|
6007
|
+
formatViewRuleGlobalStyle(node) {
|
|
6008
|
+
this.on(node, isViewRuleGlobalStyle, (n, f) => {
|
|
6009
|
+
f.keywords("global", "style").append(FormattingOptions.oneSpace);
|
|
6010
|
+
});
|
|
6011
|
+
}
|
|
6012
|
+
formatViewRuleGroup(node) {
|
|
6013
|
+
this.on(node, isViewRuleGroup, (n, f) => {
|
|
6014
|
+
f.keyword("group").append(FormattingOptions.oneSpace);
|
|
6015
|
+
});
|
|
6016
|
+
}
|
|
5988
6017
|
formatViewRuleStyle(node) {
|
|
5989
6018
|
this.on(node, isViewRuleStyle)?.keyword("style").append(FormattingOptions.oneSpace);
|
|
5990
6019
|
this.on(node, isElementExpressionsIterator)?.keyword(",").prepend(FormattingOptions.noSpace).append(FormattingOptions.oneSpace);
|
|
@@ -15,7 +15,7 @@ const vscodeUri = require('vscode-uri');
|
|
|
15
15
|
const stripIndent = require('strip-indent');
|
|
16
16
|
const hash = require('string-hash');
|
|
17
17
|
const fastEquals = require('fast-equals');
|
|
18
|
-
const LikeC4ModelGraph = require('./language-server.
|
|
18
|
+
const LikeC4ModelGraph = require('./language-server.B8s2wfT_.cjs');
|
|
19
19
|
const ufo = require('ufo');
|
|
20
20
|
const vscodeLanguageserver = require('vscode-languageserver');
|
|
21
21
|
|
|
@@ -2418,7 +2418,7 @@ class LikeC4SemanticTokenProvider extends lsp.AbstractSemanticTokenProvider {
|
|
|
2418
2418
|
vscodeLanguageserverTypes.SemanticTokenModifiers.readonly
|
|
2419
2419
|
]
|
|
2420
2420
|
});
|
|
2421
|
-
return;
|
|
2421
|
+
return "prune";
|
|
2422
2422
|
}
|
|
2423
2423
|
if (isWhereRelationKind(node) && remeda.isTruthy(node.value)) {
|
|
2424
2424
|
acceptor({
|
|
@@ -2447,6 +2447,7 @@ class LikeC4SemanticTokenProvider extends lsp.AbstractSemanticTokenProvider {
|
|
|
2447
2447
|
type: vscodeLanguageserverTypes.SemanticTokenTypes.type,
|
|
2448
2448
|
modifier: [vscodeLanguageserverTypes.SemanticTokenModifiers.definition]
|
|
2449
2449
|
});
|
|
2450
|
+
return "prune";
|
|
2450
2451
|
}
|
|
2451
2452
|
if (isElementTagExpression(node) && remeda.isTruthy(node.tag)) {
|
|
2452
2453
|
acceptor({
|
|
@@ -2455,6 +2456,7 @@ class LikeC4SemanticTokenProvider extends lsp.AbstractSemanticTokenProvider {
|
|
|
2455
2456
|
type: vscodeLanguageserverTypes.SemanticTokenTypes.type,
|
|
2456
2457
|
modifier: [vscodeLanguageserverTypes.SemanticTokenModifiers.definition]
|
|
2457
2458
|
});
|
|
2459
|
+
return "prune";
|
|
2458
2460
|
}
|
|
2459
2461
|
if (isElementRef(node) || isFqnElementRef(node)) {
|
|
2460
2462
|
acceptor({
|
|
@@ -3147,17 +3149,22 @@ function buildModel(services, docs) {
|
|
|
3147
3149
|
const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
|
|
3148
3150
|
return {
|
|
3149
3151
|
...model,
|
|
3152
|
+
customColorDefinitions,
|
|
3150
3153
|
tags,
|
|
3151
3154
|
links,
|
|
3152
3155
|
docUri,
|
|
3153
3156
|
description,
|
|
3154
3157
|
title,
|
|
3155
|
-
id
|
|
3156
|
-
customColorDefinitions
|
|
3158
|
+
id
|
|
3157
3159
|
};
|
|
3158
3160
|
};
|
|
3159
3161
|
}
|
|
3160
|
-
const parsedViews =
|
|
3162
|
+
const parsedViews = remeda.pipe(
|
|
3163
|
+
docs,
|
|
3164
|
+
remeda.flatMap((d) => remeda.map(d.c4Views, toC4View(d))),
|
|
3165
|
+
// Resolve relative paths and sort by
|
|
3166
|
+
resolveRelativePaths
|
|
3167
|
+
);
|
|
3161
3168
|
if (!parsedViews.some((v) => v.id === "index")) {
|
|
3162
3169
|
parsedViews.unshift({
|
|
3163
3170
|
__: "element",
|
|
@@ -3180,7 +3187,6 @@ function buildModel(services, docs) {
|
|
|
3180
3187
|
}
|
|
3181
3188
|
const views = remeda.pipe(
|
|
3182
3189
|
parsedViews,
|
|
3183
|
-
resolveRelativePaths,
|
|
3184
3190
|
remeda.indexBy(remeda.prop("id")),
|
|
3185
3191
|
resolveRulesExtendedViews
|
|
3186
3192
|
);
|
|
@@ -3243,7 +3249,7 @@ class LikeC4ModelBuilder {
|
|
|
3243
3249
|
logger.debug("[ModelBuilder] No documents to build model from");
|
|
3244
3250
|
return null;
|
|
3245
3251
|
}
|
|
3246
|
-
logger.debug(`[ModelBuilder]
|
|
3252
|
+
logger.debug(`[ModelBuilder] buildModel (${docs.length} docs)`);
|
|
3247
3253
|
return buildModel(this.services, docs);
|
|
3248
3254
|
});
|
|
3249
3255
|
}
|
|
@@ -3272,7 +3278,8 @@ class LikeC4ModelBuilder {
|
|
|
3272
3278
|
const index = new LikeC4ModelGraph.LikeC4ModelGraph(model);
|
|
3273
3279
|
const allViews = [];
|
|
3274
3280
|
for (const view of remeda.values(model.views)) {
|
|
3275
|
-
const
|
|
3281
|
+
const resolvedView = resolveGlobalRules(view, model.globals.styles);
|
|
3282
|
+
const result = core.isElementView(resolvedView) ? LikeC4ModelGraph.computeView(resolvedView, index) : LikeC4ModelGraph.computeDynamicView(resolvedView, index);
|
|
3276
3283
|
if (!result.isSuccess) {
|
|
3277
3284
|
logWarnError(result.error);
|
|
3278
3285
|
continue;
|
|
@@ -5830,16 +5837,19 @@ class LikeC4Formatter extends lsp.AbstractFormatter {
|
|
|
5830
5837
|
this.removeIndentFromTopLevelStatements(node);
|
|
5831
5838
|
this.indentContentInBraces(node);
|
|
5832
5839
|
this.formatSpecificationRule(node);
|
|
5840
|
+
this.formatGlobals(node);
|
|
5833
5841
|
this.formatElementDeclaration(node);
|
|
5834
5842
|
this.formatRelation(node);
|
|
5843
|
+
this.formatMetadataProperty(node);
|
|
5835
5844
|
this.formatView(node);
|
|
5836
|
-
this.
|
|
5845
|
+
this.formatViewRuleGroup(node);
|
|
5846
|
+
this.formatViewRuleGlobalStyle(node);
|
|
5837
5847
|
this.formatIncludeExcludeExpressions(node);
|
|
5838
5848
|
this.formatWhereExpression(node);
|
|
5849
|
+
this.formatAutolayoutProperty(node);
|
|
5839
5850
|
this.formatWithPredicate(node);
|
|
5851
|
+
this.formatViewRuleStyle(node);
|
|
5840
5852
|
this.formatLeafProperty(node);
|
|
5841
|
-
this.formatMetadataProperty(node);
|
|
5842
|
-
this.formatAutolayoutProperty(node);
|
|
5843
5853
|
this.formatLinkProperty(node);
|
|
5844
5854
|
this.formatNavigateToProperty(node);
|
|
5845
5855
|
this.formatTags(node);
|
|
@@ -5876,13 +5886,13 @@ class LikeC4Formatter extends lsp.AbstractFormatter {
|
|
|
5876
5886
|
this.on(node, isInOutRelationExpression)?.keyword("->").prepend(FormattingOptions.oneSpace);
|
|
5877
5887
|
}
|
|
5878
5888
|
removeIndentFromTopLevelStatements(node) {
|
|
5879
|
-
if (isModel(node) || isSpecificationRule(node) || isModelViews(node) || isLikeC4Lib(node)) {
|
|
5889
|
+
if (isModel(node) || isSpecificationRule(node) || isModelViews(node) || isLikeC4Lib(node) || isGlobals(node)) {
|
|
5880
5890
|
const formatter = this.getNodeFormatter(node);
|
|
5881
|
-
formatter.keywords("specification", "model", "views", "likec4lib").prepend(FormattingOptions.noIndent);
|
|
5891
|
+
formatter.keywords("specification", "model", "views", "likec4lib", "global").prepend(FormattingOptions.noIndent);
|
|
5882
5892
|
}
|
|
5883
5893
|
}
|
|
5884
5894
|
indentContentInBraces(node) {
|
|
5885
|
-
if (isLikeC4Lib(node) || isSpecificationRule(node) || isSpecificationElementKind(node) || isSpecificationRelationshipKind(node) || isModel(node) || isElementBody(node) || isExtendElementBody(node) || isRelationBody(node) || isRelationStyleProperty(node) || isMetadataBody(node) || isModelViews(node) || isElementViewBody(node) || isDynamicViewBody(node) || isViewRuleStyle(node) || isCustomElementProperties(node) || isCustomRelationProperties(node) || isElementStyleProperty(node) || isDynamicViewParallelSteps(node)) {
|
|
5895
|
+
if (isLikeC4Lib(node) || isSpecificationRule(node) || isSpecificationElementKind(node) || isSpecificationRelationshipKind(node) || isGlobals(node) || isGlobalStyle(node) || isGlobalStyleGroup(node) || isModel(node) || isElementBody(node) || isExtendElementBody(node) || isRelationBody(node) || isRelationStyleProperty(node) || isMetadataBody(node) || isModelViews(node) || isElementViewBody(node) || isDynamicViewBody(node) || isViewRuleStyle(node) || isViewRuleGroup(node) || isCustomElementProperties(node) || isCustomRelationProperties(node) || isElementStyleProperty(node) || isDynamicViewParallelSteps(node)) {
|
|
5886
5896
|
const formatter = this.getNodeFormatter(node);
|
|
5887
5897
|
const openBrace = formatter.keywords("{");
|
|
5888
5898
|
const closeBrace = formatter.keywords("}");
|
|
@@ -5976,6 +5986,15 @@ class LikeC4Formatter extends lsp.AbstractFormatter {
|
|
|
5976
5986
|
f.properties("props").prepend(FormattingOptions.oneSpace);
|
|
5977
5987
|
});
|
|
5978
5988
|
}
|
|
5989
|
+
formatGlobals(node) {
|
|
5990
|
+
this.on(node, isGlobalStyle, (n, f) => {
|
|
5991
|
+
f.keyword("style").append(FormattingOptions.oneSpace);
|
|
5992
|
+
f.property("id").append(FormattingOptions.oneSpace);
|
|
5993
|
+
});
|
|
5994
|
+
this.on(node, isGlobalStyleGroup, (n, f) => {
|
|
5995
|
+
f.keyword("styleGroup").append(FormattingOptions.oneSpace);
|
|
5996
|
+
});
|
|
5997
|
+
}
|
|
5979
5998
|
formatSpecificationRule(node) {
|
|
5980
5999
|
if (isSpecificationElementKind(node) || isSpecificationRelationshipKind(node) || isSpecificationTag(node)) {
|
|
5981
6000
|
const formatter = this.getNodeFormatter(node);
|
|
@@ -5993,6 +6012,16 @@ class LikeC4Formatter extends lsp.AbstractFormatter {
|
|
|
5993
6012
|
formatter.keyword("with").prepend(FormattingOptions.oneSpace);
|
|
5994
6013
|
}
|
|
5995
6014
|
}
|
|
6015
|
+
formatViewRuleGlobalStyle(node) {
|
|
6016
|
+
this.on(node, isViewRuleGlobalStyle, (n, f) => {
|
|
6017
|
+
f.keywords("global", "style").append(FormattingOptions.oneSpace);
|
|
6018
|
+
});
|
|
6019
|
+
}
|
|
6020
|
+
formatViewRuleGroup(node) {
|
|
6021
|
+
this.on(node, isViewRuleGroup, (n, f) => {
|
|
6022
|
+
f.keyword("group").append(FormattingOptions.oneSpace);
|
|
6023
|
+
});
|
|
6024
|
+
}
|
|
5996
6025
|
formatViewRuleStyle(node) {
|
|
5997
6026
|
this.on(node, isViewRuleStyle)?.keyword("style").append(FormattingOptions.oneSpace);
|
|
5998
6027
|
this.on(node, isElementExpressionsIterator)?.keyword(",").prepend(FormattingOptions.noSpace).append(FormattingOptions.oneSpace);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/language-server",
|
|
3
3
|
"description": "LikeC4 Language Server",
|
|
4
|
-
"version": "1.15.
|
|
4
|
+
"version": "1.15.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
7
7
|
"homepage": "https://likec4.dev",
|
|
@@ -112,8 +112,8 @@
|
|
|
112
112
|
},
|
|
113
113
|
"dependencies": {
|
|
114
114
|
"@dagrejs/dagre": "^1.1.4",
|
|
115
|
-
"@likec4/core": "1.15.
|
|
116
|
-
"@likec4/log": "1.15.
|
|
115
|
+
"@likec4/core": "1.15.1",
|
|
116
|
+
"@likec4/log": "1.15.1",
|
|
117
117
|
"@msgpack/msgpack": "^3.0.0-beta2",
|
|
118
118
|
"@smithy/util-base64": "^3.0.0",
|
|
119
119
|
"fast-equals": "^5.0.1",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"langium": "3.2.0",
|
|
123
123
|
"object-hash": "^3.0.0",
|
|
124
124
|
"p-debounce": "^4.0.0",
|
|
125
|
-
"remeda": "^2.
|
|
125
|
+
"remeda": "^2.16.0",
|
|
126
126
|
"string-hash": "^1.1.3",
|
|
127
127
|
"strip-indent": "^4.0.0",
|
|
128
128
|
"type-fest": "4.26.1",
|
|
@@ -133,8 +133,8 @@
|
|
|
133
133
|
"vscode-uri": "3.0.8"
|
|
134
134
|
},
|
|
135
135
|
"devDependencies": {
|
|
136
|
-
"@likec4/icons": "1.15.
|
|
137
|
-
"@likec4/tsconfig": "1.15.
|
|
136
|
+
"@likec4/icons": "1.15.1",
|
|
137
|
+
"@likec4/tsconfig": "1.15.1",
|
|
138
138
|
"@types/node": "^20.16.14",
|
|
139
139
|
"@types/object-hash": "^3.0.6",
|
|
140
140
|
"@types/string-hash": "^1.1.3",
|
|
@@ -17,17 +17,29 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
17
17
|
this.removeIndentFromTopLevelStatements(node)
|
|
18
18
|
this.indentContentInBraces(node)
|
|
19
19
|
|
|
20
|
+
// Specification
|
|
20
21
|
this.formatSpecificationRule(node)
|
|
22
|
+
|
|
23
|
+
// Globals
|
|
24
|
+
this.formatGlobals(node)
|
|
25
|
+
|
|
26
|
+
// Models
|
|
21
27
|
this.formatElementDeclaration(node)
|
|
22
28
|
this.formatRelation(node)
|
|
29
|
+
this.formatMetadataProperty(node)
|
|
30
|
+
|
|
31
|
+
// Views
|
|
23
32
|
this.formatView(node)
|
|
24
|
-
this.
|
|
33
|
+
this.formatViewRuleGroup(node)
|
|
34
|
+
this.formatViewRuleGlobalStyle(node)
|
|
25
35
|
this.formatIncludeExcludeExpressions(node)
|
|
26
36
|
this.formatWhereExpression(node)
|
|
37
|
+
this.formatAutolayoutProperty(node)
|
|
27
38
|
this.formatWithPredicate(node)
|
|
39
|
+
|
|
40
|
+
// Common
|
|
41
|
+
this.formatViewRuleStyle(node)
|
|
28
42
|
this.formatLeafProperty(node)
|
|
29
|
-
this.formatMetadataProperty(node)
|
|
30
|
-
this.formatAutolayoutProperty(node)
|
|
31
43
|
this.formatLinkProperty(node)
|
|
32
44
|
this.formatNavigateToProperty(node)
|
|
33
45
|
this.formatTags(node)
|
|
@@ -92,9 +104,10 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
92
104
|
|| ast.isSpecificationRule(node)
|
|
93
105
|
|| ast.isModelViews(node)
|
|
94
106
|
|| ast.isLikeC4Lib(node)
|
|
107
|
+
|| ast.isGlobals(node)
|
|
95
108
|
) {
|
|
96
109
|
const formatter = this.getNodeFormatter(node)
|
|
97
|
-
formatter.keywords('specification', 'model', 'views', 'likec4lib')
|
|
110
|
+
formatter.keywords('specification', 'model', 'views', 'likec4lib', 'global')
|
|
98
111
|
.prepend(FormattingOptions.noIndent)
|
|
99
112
|
}
|
|
100
113
|
}
|
|
@@ -105,6 +118,9 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
105
118
|
|| ast.isSpecificationRule(node)
|
|
106
119
|
|| ast.isSpecificationElementKind(node)
|
|
107
120
|
|| ast.isSpecificationRelationshipKind(node)
|
|
121
|
+
|| ast.isGlobals(node)
|
|
122
|
+
|| ast.isGlobalStyle(node)
|
|
123
|
+
|| ast.isGlobalStyleGroup(node)
|
|
108
124
|
|| ast.isModel(node)
|
|
109
125
|
|| ast.isElementBody(node)
|
|
110
126
|
|| ast.isExtendElementBody(node)
|
|
@@ -115,6 +131,7 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
115
131
|
|| ast.isElementViewBody(node)
|
|
116
132
|
|| ast.isDynamicViewBody(node)
|
|
117
133
|
|| ast.isViewRuleStyle(node)
|
|
134
|
+
|| ast.isViewRuleGroup(node)
|
|
118
135
|
|| ast.isCustomElementProperties(node)
|
|
119
136
|
|| ast.isCustomRelationProperties(node)
|
|
120
137
|
|| ast.isElementStyleProperty(node)
|
|
@@ -270,6 +287,17 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
270
287
|
})
|
|
271
288
|
}
|
|
272
289
|
|
|
290
|
+
protected formatGlobals(node: AstNode) {
|
|
291
|
+
this.on(node, ast.isGlobalStyle, (n, f) => {
|
|
292
|
+
f.keyword('style').append(FormattingOptions.oneSpace)
|
|
293
|
+
f.property('id').append(FormattingOptions.oneSpace)
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
this.on(node, ast.isGlobalStyleGroup, (n, f) => {
|
|
297
|
+
f.keyword('styleGroup').append(FormattingOptions.oneSpace)
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
|
|
273
301
|
protected formatSpecificationRule(node: AstNode) {
|
|
274
302
|
if (
|
|
275
303
|
ast.isSpecificationElementKind(node)
|
|
@@ -300,6 +328,18 @@ export class LikeC4Formatter extends AbstractFormatter {
|
|
|
300
328
|
}
|
|
301
329
|
}
|
|
302
330
|
|
|
331
|
+
protected formatViewRuleGlobalStyle(node: AstNode) {
|
|
332
|
+
this.on(node, ast.isViewRuleGlobalStyle, (n, f) => {
|
|
333
|
+
f.keywords('global', 'style').append(FormattingOptions.oneSpace)
|
|
334
|
+
})
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
protected formatViewRuleGroup(node: AstNode) {
|
|
338
|
+
this.on(node, ast.isViewRuleGroup, (n, f) => {
|
|
339
|
+
f.keyword('group').append(FormattingOptions.oneSpace)
|
|
340
|
+
})
|
|
341
|
+
}
|
|
342
|
+
|
|
303
343
|
protected formatViewRuleStyle(node: AstNode) {
|
|
304
344
|
this.on(node, ast.isViewRuleStyle)
|
|
305
345
|
?.keyword('style').append(FormattingOptions.oneSpace)
|
|
@@ -68,7 +68,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
68
68
|
SemanticTokenModifiers.readonly
|
|
69
69
|
]
|
|
70
70
|
})
|
|
71
|
-
return
|
|
71
|
+
return 'prune'
|
|
72
72
|
}
|
|
73
73
|
if (ast.isWhereRelationKind(node) && isTruthy(node.value)) {
|
|
74
74
|
acceptor({
|
|
@@ -97,6 +97,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
97
97
|
type: SemanticTokenTypes.type,
|
|
98
98
|
modifier: [SemanticTokenModifiers.definition]
|
|
99
99
|
})
|
|
100
|
+
return 'prune'
|
|
100
101
|
}
|
|
101
102
|
if (ast.isElementTagExpression(node) && isTruthy(node.tag)) {
|
|
102
103
|
acceptor({
|
|
@@ -105,6 +106,7 @@ export class LikeC4SemanticTokenProvider extends AbstractSemanticTokenProvider {
|
|
|
105
106
|
type: SemanticTokenTypes.type,
|
|
106
107
|
modifier: [SemanticTokenModifiers.definition]
|
|
107
108
|
})
|
|
109
|
+
return 'prune'
|
|
108
110
|
}
|
|
109
111
|
if (ast.isElementRef(node) || ast.isFqnElementRef(node)) {
|
|
110
112
|
acceptor({
|
|
@@ -255,18 +255,23 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
255
255
|
|
|
256
256
|
return {
|
|
257
257
|
...model,
|
|
258
|
+
customColorDefinitions,
|
|
258
259
|
tags,
|
|
259
260
|
links,
|
|
260
261
|
docUri,
|
|
261
262
|
description,
|
|
262
263
|
title,
|
|
263
|
-
id
|
|
264
|
-
customColorDefinitions
|
|
264
|
+
id
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
-
const parsedViews =
|
|
269
|
+
const parsedViews = pipe(
|
|
270
|
+
docs,
|
|
271
|
+
flatMap(d => map(d.c4Views, toC4View(d))),
|
|
272
|
+
// Resolve relative paths and sort by
|
|
273
|
+
resolveRelativePaths
|
|
274
|
+
)
|
|
270
275
|
// Add index view if not present
|
|
271
276
|
if (!parsedViews.some(v => v.id === 'index')) {
|
|
272
277
|
parsedViews.unshift({
|
|
@@ -291,7 +296,6 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
|
|
|
291
296
|
|
|
292
297
|
const views = pipe(
|
|
293
298
|
parsedViews,
|
|
294
|
-
resolveRelativePaths,
|
|
295
299
|
indexBy(prop('id')),
|
|
296
300
|
resolveRulesExtendedViews
|
|
297
301
|
)
|
|
@@ -362,7 +366,7 @@ export class LikeC4ModelBuilder {
|
|
|
362
366
|
logger.debug('[ModelBuilder] No documents to build model from')
|
|
363
367
|
return null
|
|
364
368
|
}
|
|
365
|
-
logger.debug(`[ModelBuilder]
|
|
369
|
+
logger.debug(`[ModelBuilder] buildModel (${docs.length} docs)`)
|
|
366
370
|
return buildModel(this.services, docs)
|
|
367
371
|
})
|
|
368
372
|
}
|
|
@@ -395,7 +399,10 @@ export class LikeC4ModelBuilder {
|
|
|
395
399
|
|
|
396
400
|
const allViews = [] as c4.ComputedView[]
|
|
397
401
|
for (const view of values(model.views)) {
|
|
398
|
-
const
|
|
402
|
+
const resolvedView = resolveGlobalRules(view, model.globals.styles)
|
|
403
|
+
const result = isElementView(resolvedView)
|
|
404
|
+
? computeView(resolvedView, index)
|
|
405
|
+
: computeDynamicView(resolvedView, index)
|
|
399
406
|
if (!result.isSuccess) {
|
|
400
407
|
logWarnError(result.error)
|
|
401
408
|
continue
|
|
@@ -11,12 +11,16 @@ import {
|
|
|
11
11
|
type ElementWhereExpr,
|
|
12
12
|
type Expression as C4Expression,
|
|
13
13
|
type Fqn,
|
|
14
|
+
type IncomingExpr as C4IncomingExpr,
|
|
15
|
+
type InOutExpr as C4InOutExpr,
|
|
14
16
|
isElementRef,
|
|
15
17
|
isElementWhere,
|
|
16
18
|
isRelationExpression,
|
|
17
19
|
isRelationWhere,
|
|
18
20
|
type NonEmptyArray,
|
|
21
|
+
type OutgoingExpr as C4OutgoingExpr,
|
|
19
22
|
type Relation,
|
|
23
|
+
type RelationExpr as C4RelationExpr,
|
|
20
24
|
type RelationID,
|
|
21
25
|
type RelationshipArrowType,
|
|
22
26
|
type RelationshipLineType,
|
|
@@ -414,6 +418,49 @@ export function $where(
|
|
|
414
418
|
}
|
|
415
419
|
}
|
|
416
420
|
|
|
421
|
+
export function $inout(
|
|
422
|
+
expr: InOutExpr | C4ElementExpression
|
|
423
|
+
): C4InOutExpr {
|
|
424
|
+
const innerExpression = !isString(expr)
|
|
425
|
+
? expr as C4Expression
|
|
426
|
+
: $expr(expr.replace(/->/g, '').trim() as ElementRefExpr) as any
|
|
427
|
+
|
|
428
|
+
return { inout: innerExpression }
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export function $incoming(
|
|
432
|
+
expr: IncomingExpr | C4ElementExpression
|
|
433
|
+
): C4IncomingExpr {
|
|
434
|
+
const innerExpression = !isString(expr)
|
|
435
|
+
? expr as C4Expression
|
|
436
|
+
: $expr(expr.replace('-> ', '') as ElementRefExpr) as any
|
|
437
|
+
|
|
438
|
+
return { incoming: innerExpression }
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export function $outgoing(
|
|
442
|
+
expr: OutgoingExpr | C4ElementExpression
|
|
443
|
+
): C4OutgoingExpr {
|
|
444
|
+
const innerExpression = !isString(expr)
|
|
445
|
+
? expr as C4Expression
|
|
446
|
+
: $expr(expr.replace(' ->', '') as ElementRefExpr) as any
|
|
447
|
+
|
|
448
|
+
return { outgoing: innerExpression }
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
export function $relation(
|
|
452
|
+
expr: RelationExpr
|
|
453
|
+
): C4RelationExpr {
|
|
454
|
+
const [source, target] = expr.split(/ -> | <-> /)
|
|
455
|
+
const isBidirectional = expr.includes(' <-> ')
|
|
456
|
+
|
|
457
|
+
return {
|
|
458
|
+
source: $expr(source as ElementRefExpr) as any,
|
|
459
|
+
target: $expr(target as ElementRefExpr) as any,
|
|
460
|
+
...(isBidirectional && { isBidirectional })
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
417
464
|
export function $expr(expr: Expression | C4Expression): C4Expression {
|
|
418
465
|
if (!isString(expr)) {
|
|
419
466
|
return expr as C4Expression
|
|
@@ -422,34 +469,13 @@ export function $expr(expr: Expression | C4Expression): C4Expression {
|
|
|
422
469
|
return { wildcard: true }
|
|
423
470
|
}
|
|
424
471
|
if (expr.startsWith('->')) {
|
|
425
|
-
|
|
426
|
-
return {
|
|
427
|
-
inout: $expr(expr.replace(/->/g, '').trim() as ElementRefExpr) as any
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return {
|
|
431
|
-
incoming: $expr(expr.replace('-> ', '') as ElementRefExpr) as any
|
|
432
|
-
}
|
|
472
|
+
return expr.endsWith('->') ? $inout(expr as InOutExpr) : $incoming(expr as IncomingExpr)
|
|
433
473
|
}
|
|
434
474
|
if (expr.endsWith(' ->')) {
|
|
435
|
-
return
|
|
436
|
-
outgoing: $expr(expr.replace(' ->', '') as ElementRefExpr) as any
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
if (expr.includes(' <-> ')) {
|
|
440
|
-
const [source, target] = expr.split(' <-> ')
|
|
441
|
-
return {
|
|
442
|
-
source: $expr(source as ElementRefExpr) as any,
|
|
443
|
-
target: $expr(target as ElementRefExpr) as any,
|
|
444
|
-
isBidirectional: true
|
|
445
|
-
}
|
|
475
|
+
return $outgoing(expr as OutgoingExpr)
|
|
446
476
|
}
|
|
447
|
-
if (expr.includes(' -> ')) {
|
|
448
|
-
|
|
449
|
-
return {
|
|
450
|
-
source: $expr(source as ElementRefExpr) as any,
|
|
451
|
-
target: $expr(target as ElementRefExpr) as any
|
|
452
|
-
}
|
|
477
|
+
if (expr.includes(' -> ') || expr.includes(' <-> ')) {
|
|
478
|
+
return $relation(expr as RelationExpr)
|
|
453
479
|
}
|
|
454
480
|
if (expr.endsWith('._')) {
|
|
455
481
|
return {
|
|
@@ -1,39 +1,8 @@
|
|
|
1
|
-
import type { ComputedEdge, ComputedNode,
|
|
2
|
-
import { Expr
|
|
3
|
-
import { isNullish, omitBy } from 'remeda'
|
|
1
|
+
import type { ComputedEdge, ComputedNode, ViewRule } from '@likec4/core'
|
|
2
|
+
import { Expr } from '@likec4/core'
|
|
3
|
+
import { isNullish, omitBy, pick } from 'remeda'
|
|
4
4
|
import { flattenGroupRules } from './applyCustomElementProperties'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
function relationExpressionToPredicates(
|
|
8
|
-
expr: Expr.RelationExpression | Expr.RelationWhereExpr
|
|
9
|
-
): (edge: { source: Element; target: Element }) => boolean {
|
|
10
|
-
switch (true) {
|
|
11
|
-
case Expr.isRelationWhere(expr):
|
|
12
|
-
return relationExpressionToPredicates(expr.where.expr)
|
|
13
|
-
case Expr.isRelation(expr): {
|
|
14
|
-
const isSource = elementExprToPredicate(expr.source)
|
|
15
|
-
const isTarget = elementExprToPredicate(expr.target)
|
|
16
|
-
return edge => {
|
|
17
|
-
return (isSource(edge.source) && isTarget(edge.target))
|
|
18
|
-
|| (!!expr.isBidirectional && isSource(edge.target) && isTarget(edge.source))
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
case Expr.isInOut(expr): {
|
|
22
|
-
const isInOut = elementExprToPredicate(expr.inout)
|
|
23
|
-
return edge => isInOut(edge.source) || isInOut(edge.target)
|
|
24
|
-
}
|
|
25
|
-
case Expr.isIncoming(expr): {
|
|
26
|
-
const isTarget = elementExprToPredicate(expr.incoming)
|
|
27
|
-
return edge => isTarget(edge.target)
|
|
28
|
-
}
|
|
29
|
-
case Expr.isOutgoing(expr): {
|
|
30
|
-
const isSource = elementExprToPredicate(expr.outgoing)
|
|
31
|
-
return edge => isSource(edge.source)
|
|
32
|
-
}
|
|
33
|
-
default:
|
|
34
|
-
nonexhaustive(expr)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
5
|
+
import { relationExpressionToPredicates } from './relationExpressionToPredicates'
|
|
37
6
|
|
|
38
7
|
export function applyCustomRelationProperties(
|
|
39
8
|
_rules: ViewRule[],
|
|
@@ -58,12 +27,12 @@ export function applyCustomRelationProperties(
|
|
|
58
27
|
if (!source || !target) {
|
|
59
28
|
return
|
|
60
29
|
}
|
|
61
|
-
if (satisfies({ source, target })) {
|
|
30
|
+
if (satisfies({ source, target, ...pick(edge, ['kind', 'tags']) })) {
|
|
62
31
|
edges[i] = {
|
|
63
32
|
...edge,
|
|
33
|
+
...props,
|
|
64
34
|
label: title ?? edge.label,
|
|
65
|
-
isCustomized: true
|
|
66
|
-
...props
|
|
35
|
+
isCustomized: true
|
|
67
36
|
}
|
|
68
37
|
}
|
|
69
38
|
})
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
+
}
|