@likec4/core 0.18.0 → 0.19.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.
@@ -1,4 +1,4 @@
1
- import { anyPass, filter, head, uniq } from 'rambdax';
1
+ import { anyPass, filter, head, uniq, isNil } from 'rambdax';
2
2
  import { DefaultThemeColor, DefaultElementShape } from '../types';
3
3
  import * as Expression from '../types/expression';
4
4
  import { isViewRuleAutoLayout, isViewRuleExpression, isViewRuleStyle } from '../types/view';
@@ -12,7 +12,7 @@ import invariant from 'tiny-invariant';
12
12
  function transformToNodes(elementsIterator, index, currentViewid) {
13
13
  return Array.from(elementsIterator)
14
14
  .sort(compareByFqnHierarchically)
15
- .reduce((map, { id, title, color, shape, description }) => {
15
+ .reduce((map, { id, kind, title, color, shape, description }) => {
16
16
  let parent = parentFqn(id);
17
17
  while (parent) {
18
18
  if (map.has(parent)) {
@@ -28,6 +28,7 @@ function transformToNodes(elementsIterator, index, currentViewid) {
28
28
  }
29
29
  const node = {
30
30
  id,
31
+ kind,
31
32
  parent,
32
33
  title,
33
34
  color: color ?? DefaultThemeColor,
@@ -52,6 +53,16 @@ function applyViewRuleStyles(rules, nodes) {
52
53
  predicates.push(() => true);
53
54
  break;
54
55
  }
56
+ if (Expression.isElementKindExpr(target)) {
57
+ predicates.push(target.isEqual ? n => n.kind === target.elementKind : n => n.kind !== target.elementKind);
58
+ continue;
59
+ }
60
+ if (Expression.isElementTagExpr(target)) {
61
+ predicates.push(target.isEqual
62
+ ? ({ tags }) => !!tags && tags.includes(target.elementTag)
63
+ : ({ tags }) => isNil(tags) || !tags.includes(target.elementTag));
64
+ continue;
65
+ }
55
66
  if (Expression.isElementRef(target)) {
56
67
  const { element, isDescedants } = target;
57
68
  predicates.push(isDescedants ? n => n.id.startsWith(element + '.') : n => n.id === element);
@@ -100,6 +111,37 @@ const excludeElementRef = (ctx, expr) => {
100
111
  const relations = [...ctx.relations].filter(r => elementsIds.includes(r.source) || elementsIds.includes(r.target));
101
112
  return ctx.exclude({ elements, relations });
102
113
  };
114
+ const asElementPredicate = (expr) => {
115
+ if (expr.isEqual) {
116
+ if (Expression.isElementKindExpr(expr)) {
117
+ return e => e.kind === expr.elementKind;
118
+ }
119
+ else {
120
+ return ({ tags }) => !!tags && tags.includes(expr.elementTag);
121
+ }
122
+ }
123
+ else {
124
+ if (Expression.isElementKindExpr(expr)) {
125
+ return e => e.kind !== expr.elementKind;
126
+ }
127
+ else {
128
+ return ({ tags }) => isNil(tags) || tags.length === 0 || !tags.includes(expr.elementTag);
129
+ }
130
+ }
131
+ };
132
+ const includeElementKindOrTag = (ctx, expr) => {
133
+ const elements = ctx.index.elements.filter(asElementPredicate(expr));
134
+ return elements.reduce((accCtx, el) => includeElementRef(accCtx, {
135
+ element: el.id,
136
+ isDescedants: false
137
+ }), ctx);
138
+ };
139
+ const excludeElementKindOrTag = (ctx, expr) => {
140
+ const predicate = asElementPredicate(expr);
141
+ const elements = [...ctx.elements].filter(predicate);
142
+ const implicits = [...ctx.implicits].filter(predicate);
143
+ return ctx.exclude({ elements, implicits });
144
+ };
103
145
  const includeWildcardRef = (ctx, _expr) => {
104
146
  const { root } = ctx;
105
147
  if (root) {
@@ -122,10 +164,7 @@ const includeWildcardRef = (ctx, _expr) => {
122
164
  }
123
165
  return ctx.include({
124
166
  elements,
125
- relations: [
126
- ...ctx.index.filterRelations(isInside(root)),
127
- ...relations,
128
- ],
167
+ relations: [...ctx.index.filterRelations(isInside(root)), ...relations],
129
168
  implicits: implicits
130
169
  });
131
170
  }
@@ -165,13 +204,28 @@ const resolveElements = (ctx, expr) => {
165
204
  return ctx.index.rootElements();
166
205
  }
167
206
  }
207
+ if (Expression.isElementKindExpr(expr)) {
208
+ return ctx.index.elements.filter(el => {
209
+ if (expr.isEqual) {
210
+ return el.kind === expr.elementKind;
211
+ }
212
+ return el.kind !== expr.elementKind;
213
+ });
214
+ }
215
+ if (Expression.isElementTagExpr(expr)) {
216
+ return ctx.index.elements.filter(el => {
217
+ const tags = el.tags;
218
+ if (expr.isEqual) {
219
+ return !!tags && tags.includes(expr.elementTag);
220
+ }
221
+ return isNil(tags) || tags.length === 0 || !tags.includes(expr.elementTag);
222
+ });
223
+ }
224
+ if (expr.isDescedants) {
225
+ return ctx.index.children(expr.element);
226
+ }
168
227
  else {
169
- if (expr.isDescedants) {
170
- return ctx.index.children(expr.element);
171
- }
172
- else {
173
- return [ctx.index.find(expr.element)];
174
- }
228
+ return [ctx.index.find(expr.element)];
175
229
  }
176
230
  };
177
231
  const includeIncomingExpr = (ctx, expr) => {
@@ -349,6 +403,10 @@ export function computeElementView(view, index) {
349
403
  }
350
404
  for (const { isInclude, exprs } of rulesInclude) {
351
405
  for (const expr of exprs) {
406
+ if (Expression.isElementKindExpr(expr) || Expression.isElementTagExpr(expr)) {
407
+ ctx = isInclude ? includeElementKindOrTag(ctx, expr) : excludeElementKindOrTag(ctx, expr);
408
+ continue;
409
+ }
352
410
  if (Expression.isElementRef(expr)) {
353
411
  ctx = isInclude ? includeElementRef(ctx, expr) : excludeElementRef(ctx, expr);
354
412
  continue;
@@ -1,15 +1,17 @@
1
1
  import type { Opaque } from './opaque';
2
- import type { ElementShape, Fqn, ThemeColor } from './element';
2
+ import type { ElementKind, ElementShape, Fqn, Tag, ThemeColor } from './element';
3
3
  import type { RelationID } from './relation';
4
4
  import type { ElementView, ViewID, ViewRuleAutoLayout } from './view';
5
5
  export type NodeId = Fqn;
6
6
  export type EdgeId = Opaque<string, 'EdgeId'>;
7
7
  export interface ComputedNode {
8
8
  id: NodeId;
9
+ kind: ElementKind;
9
10
  parent: NodeId | null;
10
11
  title: string;
11
12
  description?: string;
12
13
  technology?: string;
14
+ tags?: Tag[];
13
15
  children: NodeId[];
14
16
  shape: ElementShape;
15
17
  color: ThemeColor;
@@ -1,6 +1,9 @@
1
- import type { Fqn } from './element';
1
+ import type { ElementKind, Fqn, Tag } from './element';
2
2
  interface BaseExr {
3
3
  element?: never;
4
+ elementKind?: never;
5
+ elementTag?: never;
6
+ isEqual?: never;
4
7
  isDescedants?: never;
5
8
  wildcard?: never;
6
9
  source?: never;
@@ -18,7 +21,17 @@ export interface WildcardExpr extends Omit<BaseExr, 'wildcard'> {
18
21
  wildcard: true;
19
22
  }
20
23
  export declare function isWildcard(expr: Expression): expr is WildcardExpr;
21
- export type ElementExpression = ElementRefExpr | WildcardExpr;
24
+ export interface ElementKindExpr extends Omit<BaseExr, 'elementKind' | 'isEqual'> {
25
+ elementKind: ElementKind;
26
+ isEqual: boolean;
27
+ }
28
+ export declare function isElementKindExpr(expr: Expression): expr is ElementKindExpr;
29
+ export interface ElementTagExpr extends Omit<BaseExr, 'elementTag' | 'isEqual'> {
30
+ elementTag: Tag;
31
+ isEqual: boolean;
32
+ }
33
+ export declare function isElementTagExpr(expr: Expression): expr is ElementTagExpr;
34
+ export type ElementExpression = ElementRefExpr | WildcardExpr | ElementKindExpr | ElementTagExpr;
22
35
  export declare function isElement(expr: Expression): expr is ElementExpression;
23
36
  export interface RelationExpr extends Omit<BaseExr, 'source' | 'target'> {
24
37
  source: ElementExpression;
@@ -4,8 +4,14 @@ export function isElementRef(expr) {
4
4
  export function isWildcard(expr) {
5
5
  return 'wildcard' in expr;
6
6
  }
7
+ export function isElementKindExpr(expr) {
8
+ return 'elementKind' in expr && 'isEqual' in expr;
9
+ }
10
+ export function isElementTagExpr(expr) {
11
+ return 'elementTag' in expr && 'isEqual' in expr;
12
+ }
7
13
  export function isElement(expr) {
8
- return isElementRef(expr) || isWildcard(expr);
14
+ return isElementRef(expr) || isWildcard(expr) || isElementKindExpr(expr) || isElementTagExpr(expr);
9
15
  }
10
16
  export function isRelation(expr) {
11
17
  return 'source' in expr && 'target' in expr;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@likec4/core",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "license": "MIT",
5
5
  "bugs": "https://github.com/likec4/likec4/issues",
6
6
  "homepage": "https://likec4.dev",