@likec4/core 0.2.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 (48) hide show
  1. package/dist/compute-view/EdgeBuilder.d.ts +7 -0
  2. package/dist/compute-view/EdgeBuilder.js +31 -0
  3. package/dist/compute-view/compute-view.d.ts +11 -0
  4. package/dist/compute-view/compute-view.js +14 -0
  5. package/dist/compute-view/compute.element-view.d.ts +4 -0
  6. package/dist/compute-view/compute.element-view.js +163 -0
  7. package/dist/compute-view/index.d.ts +2 -0
  8. package/dist/compute-view/index.js +1 -0
  9. package/dist/compute-view/utils/anyPossibleRelations.d.ts +2 -0
  10. package/dist/compute-view/utils/anyPossibleRelations.js +12 -0
  11. package/dist/compute-view/utils/evaluate-expression.d.ts +10 -0
  12. package/dist/compute-view/utils/evaluate-expression.js +201 -0
  13. package/dist/compute-view/utils/sortNodes.d.ts +2 -0
  14. package/dist/compute-view/utils/sortNodes.js +42 -0
  15. package/dist/index.d.ts +4 -0
  16. package/dist/index.js +3 -0
  17. package/dist/model-index/index.d.ts +1 -0
  18. package/dist/model-index/index.js +1 -0
  19. package/dist/model-index/model-index.d.ts +30 -0
  20. package/dist/model-index/model-index.js +141 -0
  21. package/dist/types/computed-view.d.ts +29 -0
  22. package/dist/types/computed-view.js +1 -0
  23. package/dist/types/diagram.d.ts +25 -0
  24. package/dist/types/diagram.js +1 -0
  25. package/dist/types/element.d.ts +26 -0
  26. package/dist/types/element.js +5 -0
  27. package/dist/types/expression.d.ts +43 -0
  28. package/dist/types/expression.js +24 -0
  29. package/dist/types/index.d.ts +10 -0
  30. package/dist/types/index.js +2 -0
  31. package/dist/types/model.d.ts +9 -0
  32. package/dist/types/model.js +1 -0
  33. package/dist/types/opaque.d.ts +102 -0
  34. package/dist/types/opaque.js +1 -0
  35. package/dist/types/relation.d.ts +10 -0
  36. package/dist/types/relation.js +1 -0
  37. package/dist/types/view.d.ts +25 -0
  38. package/dist/types/view.js +6 -0
  39. package/dist/utils/fqn.d.ts +10 -0
  40. package/dist/utils/fqn.js +51 -0
  41. package/dist/utils/guards.d.ts +3 -0
  42. package/dist/utils/guards.js +10 -0
  43. package/dist/utils/index.d.ts +3 -0
  44. package/dist/utils/index.js +3 -0
  45. package/dist/utils/relations.d.ts +11 -0
  46. package/dist/utils/relations.js +26 -0
  47. package/package.json +72 -0
  48. package/src/index.ts +5 -0
@@ -0,0 +1,7 @@
1
+ import type { Fqn, Relation } from '../types';
2
+ import type { ComputedEdge } from '../types/computed-view';
3
+ export declare class EdgeBuilder {
4
+ private _relationsObj;
5
+ add(source: Fqn, target: Fqn, relation: Relation): this;
6
+ build(): ComputedEdge[];
7
+ }
@@ -0,0 +1,31 @@
1
+ import { equals, keys, pluck, reject } from 'rambdax';
2
+ import { commonAncestor, compareFqnHierarchically } from '../utils';
3
+ export class EdgeBuilder {
4
+ _relationsObj = {};
5
+ add(source, target, relation) {
6
+ const bySource = this._relationsObj[source] ?? {};
7
+ const relations = bySource[target] ?? [];
8
+ relations.push(relation);
9
+ bySource[target] = relations;
10
+ this._relationsObj[source] = bySource;
11
+ return this;
12
+ }
13
+ build() {
14
+ return keys(this._relationsObj).sort(compareFqnHierarchically).reverse().flatMap(source => {
15
+ const targets = this._relationsObj[source] ?? {};
16
+ return keys(targets).sort(compareFqnHierarchically).reverse().map(target => {
17
+ const relations = targets[target] ?? [];
18
+ const titles = reject(equals(''), pluck('title', relations));
19
+ const label = titles.length === 1 ? titles[0] : null;
20
+ return {
21
+ id: `${source}:${target}`,
22
+ parent: commonAncestor(source, target),
23
+ source,
24
+ target,
25
+ label,
26
+ relations: pluck('id', relations)
27
+ };
28
+ });
29
+ });
30
+ }
31
+ }
@@ -0,0 +1,11 @@
1
+ import { ModelIndex } from '../model-index';
2
+ import type { Element, ElementView, Fqn, LikeC4Model, Relation, RelationID, ViewID } from '../types';
3
+ import type { ComputedView } from '../types/computed-view';
4
+ export declare function computeView(view: ElementView, index: ModelIndex): ComputedView;
5
+ type InputModel = {
6
+ elements: Record<Fqn, Element>;
7
+ relations: Record<RelationID, Relation>;
8
+ views: Record<ViewID, ElementView>;
9
+ };
10
+ export declare function computeViews(model: InputModel): LikeC4Model;
11
+ export {};
@@ -0,0 +1,14 @@
1
+ import { map } from 'rambdax';
2
+ import { ModelIndex } from '../model-index';
3
+ import { computeElementView } from './compute.element-view';
4
+ export function computeView(view, index) {
5
+ return computeElementView(view, index);
6
+ }
7
+ export function computeViews(model) {
8
+ const index = ModelIndex.from(model);
9
+ return {
10
+ elements: model.elements,
11
+ relations: model.relations,
12
+ views: map(v => computeElementView(v, index), model.views)
13
+ };
14
+ }
@@ -0,0 +1,4 @@
1
+ import type { ModelIndex } from '../model-index';
2
+ import { type ElementView } from '../types';
3
+ import type { ComputedView } from '../types/computed-view';
4
+ export declare function computeElementView(view: ElementView, index: ModelIndex): ComputedView;
@@ -0,0 +1,163 @@
1
+ import { anyPass, filter } from 'rambdax';
2
+ import { DefaultElementShape, DefaultThemeColor } from '../types';
3
+ import * as Expression from '../types/expression';
4
+ import { isViewRuleExpression, isViewRuleStyle } from '../types/view';
5
+ import { Relations, compareByFqnHierarchically, failExpectedNever, isSameHierarchy, parentFqn } from '../utils';
6
+ import { EdgeBuilder } from './EdgeBuilder';
7
+ import { anyPossibleRelations } from './utils/anyPossibleRelations';
8
+ import { evaluateExpression } from './utils/evaluate-expression';
9
+ import { sortNodes } from './utils/sortNodes';
10
+ function updateSetWith(set, elements, addToSet = true) {
11
+ for (const e of elements) {
12
+ addToSet ? set.add(e) : set.delete(e);
13
+ }
14
+ }
15
+ function transformToNodes(elementsIterator, index) {
16
+ return [...elementsIterator].sort(compareByFqnHierarchically).reduce((map, { id, title, color, shape, description }) => {
17
+ let parent = parentFqn(id);
18
+ while (parent) {
19
+ if (map.has(parent)) {
20
+ break;
21
+ }
22
+ parent = parentFqn(parent);
23
+ }
24
+ const navigateTo = index.defaultViewOf(id);
25
+ map.set(id, Object.assign({
26
+ id,
27
+ parent,
28
+ title,
29
+ color: color ?? DefaultThemeColor,
30
+ shape: shape ?? DefaultElementShape,
31
+ children: [],
32
+ }, description ? { description } : {}, navigateTo ? { navigateTo } : {}));
33
+ if (parent) {
34
+ map.get(parent)?.children.push(id);
35
+ }
36
+ return map;
37
+ }, new Map());
38
+ }
39
+ function applyViewRuleStyles(rules, nodes) {
40
+ for (const rule of rules) {
41
+ const predicates = [];
42
+ if (!rule.style.color && !rule.style.shape) {
43
+ // skip empty
44
+ continue;
45
+ }
46
+ for (const target of rule.targets) {
47
+ if (Expression.isWildcard(target)) {
48
+ predicates.push(() => true);
49
+ break;
50
+ }
51
+ if (Expression.isElementRef(target)) {
52
+ const { element, isDescedants } = target;
53
+ predicates.push(isDescedants
54
+ ? (n) => n.id.startsWith(element + '.')
55
+ : (n) => n.id === element);
56
+ continue;
57
+ }
58
+ failExpectedNever(target);
59
+ }
60
+ filter(anyPass(predicates), nodes).forEach(n => {
61
+ n.shape = rule.style.shape ?? n.shape;
62
+ n.color = rule.style.color ?? n.color;
63
+ });
64
+ }
65
+ return nodes;
66
+ }
67
+ export function computeElementView(view, index) {
68
+ const relations = new Set();
69
+ const elements = new Set();
70
+ const neighbours = new Set();
71
+ const rootElement = view.viewOf ?? null;
72
+ const rulesInclude = view.rules.filter(isViewRuleExpression);
73
+ if (rootElement && rulesInclude.length == 0) {
74
+ elements.add(index.find(rootElement));
75
+ }
76
+ for (const { isInclude, exprs } of rulesInclude) {
77
+ for (const expr of exprs) {
78
+ let { elements: newElements, neighbours: newNeighbours, relations: newRelations } = evaluateExpression(index, expr, rootElement);
79
+ if (isInclude) {
80
+ const filters = [];
81
+ // When include element(s) without newNeighbours, include in-out relations
82
+ if (elements.size > 0 && newElements.length > 0 && newNeighbours.length === 0 && Expression.isElement(expr)) {
83
+ for (const e of elements) {
84
+ for (const newE of newElements) {
85
+ if (!isSameHierarchy(e, newE)) {
86
+ filters.push(Relations.isAnyBetween(e.id, newE.id));
87
+ }
88
+ }
89
+ }
90
+ }
91
+ // // When include elements by tag or kind, include in-out relations
92
+ // if (elements.size > 0 && newElements.length > 0 && (Expression.isElementKind(expr) || Expression.isElementTag(expr))) {
93
+ // for (const e of elements) {
94
+ // for (const newE of newElements) {
95
+ // if (e.id !== newE.id && !isAncestor(e, newE) && !isAncestor(newE, e)) {
96
+ // filters.push(isAnyRelationBetween(e.id, newE.id))
97
+ // }
98
+ // }
99
+ // }
100
+ // }
101
+ if (filters.length > 0) {
102
+ newRelations = newRelations.concat(index.filterRelations(anyPass(filters)));
103
+ }
104
+ }
105
+ else {
106
+ if (Expression.isAnyRelation(expr)) {
107
+ // Exclude only relations, but not elements and neighbours
108
+ newNeighbours = [];
109
+ newElements = [];
110
+ }
111
+ else {
112
+ newNeighbours = newNeighbours.concat(newElements);
113
+ // Also exclude nested elements from current neighbours
114
+ // for (const n of neighbours) {
115
+ // if (newNeighbours.some(e => n.id.startsWith(e.id + '.'))) {
116
+ // newNeighbours.push(n)
117
+ // }
118
+ // }
119
+ // Do not exclude relations
120
+ newRelations = [];
121
+ }
122
+ }
123
+ updateSetWith(elements, newElements, isInclude);
124
+ updateSetWith(relations, newRelations, isInclude);
125
+ updateSetWith(neighbours, newNeighbours, isInclude);
126
+ }
127
+ }
128
+ const elementsIds = new Set([...elements].map(e => e.id));
129
+ const edgeBuilder = new EdgeBuilder();
130
+ const resolvedRelations = [...relations];
131
+ for (const [source, target] of anyPossibleRelations([...elements, ...neighbours])) {
132
+ if (!elementsIds.has(source.id) && !elementsIds.has(target.id)) {
133
+ continue;
134
+ }
135
+ const findPredicate = Relations.isBetween(source.id, target.id);
136
+ let idx = resolvedRelations.findIndex(findPredicate);
137
+ while (idx >= 0) {
138
+ const [rel] = resolvedRelations.splice(idx, 1);
139
+ if (rel) {
140
+ elements.add(source);
141
+ elements.add(target);
142
+ edgeBuilder.add(source.id, target.id, rel);
143
+ }
144
+ idx = resolvedRelations.findIndex(findPredicate);
145
+ }
146
+ }
147
+ const nodesreg = transformToNodes(elements, index);
148
+ const edges = edgeBuilder.build().map(edge => {
149
+ while (edge.parent) {
150
+ if (nodesreg.has(edge.parent)) {
151
+ break;
152
+ }
153
+ edge.parent = parentFqn(edge.parent);
154
+ }
155
+ return edge;
156
+ });
157
+ const nodes = applyViewRuleStyles(view.rules.filter(isViewRuleStyle), sortNodes(nodesreg, edges));
158
+ return {
159
+ ...view,
160
+ nodes,
161
+ edges
162
+ };
163
+ }
@@ -0,0 +1,2 @@
1
+ export { computeView, computeViews } from './compute-view';
2
+ export type * from '../types/computed-view';
@@ -0,0 +1 @@
1
+ export { computeView, computeViews } from './compute-view';
@@ -0,0 +1,2 @@
1
+ import type { Element } from '../../types';
2
+ export declare function anyPossibleRelations(elements: Element[]): Generator<[source: Element, target: Element]>;
@@ -0,0 +1,12 @@
1
+ import { prop, uniqBy } from 'rambdax';
2
+ import { compareByFqnHierarchically, isAncestor } from '../../utils/fqn';
3
+ export function* anyPossibleRelations(elements) {
4
+ const uniqElements = uniqBy(prop('id'), elements).sort(compareByFqnHierarchically).reverse();
5
+ for (const source of uniqElements) {
6
+ for (const target of uniqElements) {
7
+ if (source !== target && !isAncestor(source, target) && !isAncestor(target, source)) {
8
+ yield [source, target];
9
+ }
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,10 @@
1
+ import type { ModelIndex } from '../../model-index';
2
+ import type { Element, Fqn, Relation, Expression } from '../../types';
3
+ export declare const keepLeafs: (elements: Element[]) => Element[];
4
+ interface EvaluateViewExpressionResult {
5
+ elements: Element[];
6
+ neighbours: Element[];
7
+ relations: Relation[];
8
+ }
9
+ export declare function evaluateExpression(index: ModelIndex, expr: Expression, rootElement: Fqn | null): EvaluateViewExpressionResult;
10
+ export {};
@@ -0,0 +1,201 @@
1
+ import { anyPass, map, pluck, uniq } from 'rambdax';
2
+ import * as Expr from '../../types/expression';
3
+ import { failExpectedNever, isAncestor } from '../../utils';
4
+ import { isBetween, isIncoming, isOutgoing } from '../../utils/relations';
5
+ import { anyPossibleRelations } from './anyPossibleRelations';
6
+ const dropNested = (elements) => {
7
+ return elements.reduce((acc, current) => {
8
+ if (acc.length === 0)
9
+ return [current];
10
+ // current is a child of some in acc
11
+ if (acc.some(p => p.id === current.id || isAncestor(p, current))) {
12
+ return acc;
13
+ }
14
+ return [
15
+ // drop children of current
16
+ ...acc.filter(e => !isAncestor(current, e)),
17
+ current
18
+ ];
19
+ }, []);
20
+ };
21
+ export const keepLeafs = (elements) => {
22
+ return elements.reduce((acc, current) => {
23
+ if (acc.length === 0)
24
+ return [current];
25
+ // current is an ancestor of some in acc
26
+ if (acc.some(p => p.id === current.id || isAncestor(current, p))) {
27
+ return acc;
28
+ }
29
+ return [
30
+ // drop ancestors of current
31
+ ...acc.filter(e => !isAncestor(e, current)),
32
+ current
33
+ ];
34
+ }, []);
35
+ };
36
+ const evaluateElementExpression = (index, expr, rootElement = null) => {
37
+ let elements = [];
38
+ let neighbours = [];
39
+ let relations = [];
40
+ // const inOutRelations = (elements: Element[]) => {
41
+ // if (elements.length == 0) return []
42
+ // const filters = dropNested(elements).map(e => isAnyInOut(e.id))
43
+ // return index.filterRelations(anyPass(filters))
44
+ // }
45
+ const allRelationsBetween = (elements) => {
46
+ if (elements.length <= 1)
47
+ return [];
48
+ const filters = [];
49
+ for (const [source, target] of anyPossibleRelations(elements)) {
50
+ filters.push(isBetween(source.id, target.id));
51
+ }
52
+ return filters.length ? index.filterRelations(anyPass(filters)) : [];
53
+ };
54
+ // WildcardExpression
55
+ if (Expr.isWildcard(expr)) {
56
+ if (rootElement) {
57
+ elements = [
58
+ index.find(rootElement),
59
+ ...index.children(rootElement)
60
+ ];
61
+ neighbours = [
62
+ ...index.siblings(rootElement),
63
+ ...index.ancestors(rootElement).flatMap(a => [
64
+ ...index.siblings(a.id)
65
+ ])
66
+ ];
67
+ relations = index.filterRelations(anyPass([
68
+ isBetween(rootElement),
69
+ isIncoming(rootElement),
70
+ isOutgoing(rootElement),
71
+ ]));
72
+ }
73
+ else {
74
+ elements = index.rootElements();
75
+ neighbours = elements;
76
+ relations = allRelationsBetween(elements);
77
+ }
78
+ return {
79
+ elements,
80
+ neighbours,
81
+ relations
82
+ };
83
+ }
84
+ // Identifier
85
+ if (Expr.isElementRef(expr)) {
86
+ elements = expr.isDescedants ? index.children(expr.element) : [index.find(expr.element)];
87
+ if (expr.isDescedants) {
88
+ relations = index.filterRelations(isBetween(expr.element));
89
+ // relations = index.filterRelations(anyPass([
90
+ // isBetween(expr.element),
91
+ // isIncoming(expr.element),
92
+ // isOutgoing(expr.element),
93
+ // ]))
94
+ // } else {
95
+ // relations = index.filterRelations(anyPass([
96
+ // isIncoming(expr.element),
97
+ // isOutgoing(expr.element)
98
+ // ]))
99
+ }
100
+ return {
101
+ elements,
102
+ neighbours,
103
+ relations
104
+ };
105
+ }
106
+ failExpectedNever(expr);
107
+ };
108
+ export function evaluateExpression(index, expr, rootElement) {
109
+ const elements = [];
110
+ let neighbours = [];
111
+ let relations = [];
112
+ if (Expr.isInOut(expr)) {
113
+ const targets = evaluateElementExpression(index, expr.inout).elements;
114
+ for (const target of targets) {
115
+ const incoming = index.filterRelations(isIncoming(target.id));
116
+ const outgoing = index.filterRelations(isOutgoing(target.id));
117
+ if (incoming.length + outgoing.length > 0) {
118
+ elements.push(target);
119
+ neighbours = neighbours.concat(map(index.find, [
120
+ ...pluck('source', incoming),
121
+ ...pluck('target', outgoing),
122
+ ]));
123
+ relations = relations.concat([
124
+ ...incoming,
125
+ ...outgoing
126
+ ]);
127
+ }
128
+ }
129
+ return {
130
+ elements: uniq(elements),
131
+ neighbours: dropNested(neighbours),
132
+ relations: uniq(relations)
133
+ };
134
+ }
135
+ if (Expr.isIncoming(expr)) {
136
+ const targets = evaluateElementExpression(index, expr.incoming).elements;
137
+ for (const target of targets) {
138
+ const incoming = index.filterRelations(isIncoming(target.id));
139
+ if (incoming.length > 0) {
140
+ elements.push(target);
141
+ neighbours = neighbours.concat(map(index.find, pluck('source', incoming)));
142
+ relations = relations.concat(incoming);
143
+ }
144
+ }
145
+ return {
146
+ elements: uniq(elements),
147
+ neighbours: dropNested(neighbours),
148
+ relations: uniq(relations)
149
+ };
150
+ }
151
+ if (Expr.isOutgoing(expr)) {
152
+ const sources = evaluateElementExpression(index, expr.outgoing).elements;
153
+ for (const source of sources) {
154
+ const outgoing = index.filterRelations(isOutgoing(source.id));
155
+ if (outgoing.length > 0) {
156
+ elements.push(source);
157
+ neighbours = neighbours.concat(map(index.find, pluck('target', outgoing)));
158
+ relations = relations.concat(outgoing);
159
+ }
160
+ }
161
+ return {
162
+ elements: uniq(elements),
163
+ neighbours: dropNested(neighbours),
164
+ relations: uniq(relations)
165
+ };
166
+ }
167
+ if (Expr.isRelation(expr)) {
168
+ const isSourceWildcard = Expr.isWildcard(expr.source);
169
+ const isTargetWildcard = Expr.isWildcard(expr.target);
170
+ if (isSourceWildcard && !isTargetWildcard) {
171
+ return evaluateExpression(index, {
172
+ incoming: expr.target
173
+ }, rootElement);
174
+ }
175
+ if (!isSourceWildcard && isTargetWildcard) {
176
+ return evaluateExpression(index, {
177
+ outgoing: expr.source
178
+ }, rootElement);
179
+ }
180
+ const sources = evaluateElementExpression(index, expr.source).elements;
181
+ const targets = evaluateElementExpression(index, expr.target).elements;
182
+ for (const source of sources) {
183
+ for (const target of targets) {
184
+ if (isAncestor(source.id, target.id) || isAncestor(target.id, source.id)) {
185
+ continue;
186
+ }
187
+ const foundRelations = index.filterRelations(isBetween(source.id, target.id));
188
+ if (foundRelations.length > 0) {
189
+ relations = relations.concat(foundRelations);
190
+ neighbours.push(source, target);
191
+ }
192
+ }
193
+ }
194
+ return {
195
+ elements,
196
+ neighbours: uniq(neighbours),
197
+ relations: uniq(relations)
198
+ };
199
+ }
200
+ return evaluateElementExpression(index, expr, rootElement);
201
+ }
@@ -0,0 +1,2 @@
1
+ import type { ComputedEdge, ComputedNode, Fqn } from '../../types';
2
+ export declare function sortNodes(_nodes: Map<Fqn, ComputedNode>, edges: ComputedEdge[]): ComputedNode[];
@@ -0,0 +1,42 @@
1
+ import { Graph, alg } from '@dagrejs/graphlib';
2
+ export function sortNodes(_nodes, edges) {
3
+ const g = new Graph({
4
+ compound: true,
5
+ directed: true,
6
+ multigraph: false
7
+ });
8
+ for (const nd of _nodes.values()) {
9
+ g.setNode(nd.id);
10
+ // console.log(`add ${nd.id}`)
11
+ if (nd.parent) {
12
+ g.setEdge(nd.parent, nd.id);
13
+ // console.log(`${nd.parent} -> ${nd.id}`)
14
+ }
15
+ }
16
+ for (const edge of edges) {
17
+ const source = _nodes.get(edge.source);
18
+ let target = _nodes.get(edge.target);
19
+ while (source && target) {
20
+ if (!g.hasEdge(source.id, target.id)) {
21
+ g.setEdge(source.id, target.id);
22
+ // console.log(`${source.id} -> ${target.id}`)
23
+ if (!alg.isAcyclic(g)) {
24
+ g.removeEdge(source.id, target.id);
25
+ // console.log(`remove ${source.id} -> ${target.id}`)
26
+ }
27
+ }
28
+ if (target.parent && target.parent !== edge.parent) {
29
+ target = _nodes.get(target.parent);
30
+ }
31
+ else {
32
+ target = undefined;
33
+ }
34
+ }
35
+ }
36
+ const sorted = alg.topsort(g);
37
+ const nodes = sorted.map(id => _nodes.get(id));
38
+ for (const node of nodes) {
39
+ node.children = nodes.flatMap(n => n.parent === node.id ? n.id : []);
40
+ }
41
+ return nodes;
42
+ }
@@ -0,0 +1,4 @@
1
+ export type * as likec4 from './types';
2
+ export { computeView } from './compute-view';
3
+ export * from './utils';
4
+ export * from './model-index';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { computeView } from './compute-view';
2
+ export * from './utils';
3
+ export * from './model-index';
@@ -0,0 +1 @@
1
+ export * from './model-index';
@@ -0,0 +1 @@
1
+ export * from './model-index';
@@ -0,0 +1,30 @@
1
+ import type { Predicate } from 'rambdax';
2
+ import type { Element, ElementView, Fqn, Relation, RelationID, ViewID } from '../types';
3
+ type ModelInput = {
4
+ elements: Record<Fqn, Element>;
5
+ relations: Record<RelationID, Relation>;
6
+ views: Record<ViewID, ElementView>;
7
+ };
8
+ export declare class ModelIndex {
9
+ private root;
10
+ private _elements;
11
+ private _relations;
12
+ private _defaultElementView;
13
+ get relations(): Relation[];
14
+ filterRelations: (predicate: Predicate<Relation>) => Relation[];
15
+ static from({ elements, relations, views }: ModelInput): ModelIndex;
16
+ addElement(el: Element): void;
17
+ private locateTrie;
18
+ find: (id: Fqn) => Element;
19
+ children: (id: Fqn) => Element[];
20
+ siblings: (id: Fqn) => Element[];
21
+ /**
22
+ * Ancestors from closest parent to root
23
+ */
24
+ ancestors: (id: Fqn) => Element[];
25
+ rootElements(): Element[];
26
+ get elements(): Element[];
27
+ addRelation(rel: Relation): void;
28
+ defaultViewOf: (id: Fqn) => ViewID | undefined;
29
+ }
30
+ export {};