@likec4/core 1.4.0 → 1.6.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.
- package/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/colors/element.d.ts +1 -1
- package/dist/colors/element.js +1 -1
- package/dist/colors/index.d.ts +2 -2
- package/dist/colors/index.js +1 -1
- package/dist/types/expression.d.ts +18 -3
- package/dist/types/expression.js +4 -1
- package/dist/types/model.d.ts +2 -2
- package/dist/types/relation.d.ts +1 -1
- package/dist/types/theme.d.ts +1 -1
- package/dist/types/view.d.ts +24 -30
- package/dist/types/view.js +2 -2
- package/dist/utils/fqn.d.ts +5 -0
- package/dist/utils/fqn.js +4 -0
- package/package.json +8 -8
- package/src/colors/element.ts +1 -1
- package/src/colors/index.ts +1 -1
- package/src/types/expression.ts +24 -4
- package/src/types/model.ts +2 -2
- package/src/types/relation.ts +2 -0
- package/src/types/theme.ts +1 -1
- package/src/types/view.ts +26 -38
- package/src/utils/fqn.ts +7 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2024 Denis Davydkov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
package/dist/colors/element.d.ts
CHANGED
package/dist/colors/element.js
CHANGED
package/dist/colors/index.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export declare const defaultTheme: {
|
|
|
60
60
|
readonly fill: "#A35829";
|
|
61
61
|
readonly stroke: "#7E451D";
|
|
62
62
|
readonly hiContrast: "#FFE0C2";
|
|
63
|
-
readonly loContrast: "#
|
|
63
|
+
readonly loContrast: "#f9b27c";
|
|
64
64
|
};
|
|
65
65
|
readonly indigo: {
|
|
66
66
|
readonly fill: "#6366f1";
|
|
@@ -126,7 +126,7 @@ export declare const defaultTheme: {
|
|
|
126
126
|
labelColor: "#cbd5e1";
|
|
127
127
|
};
|
|
128
128
|
};
|
|
129
|
-
font: "
|
|
129
|
+
font: "Arial";
|
|
130
130
|
shadow: "#0a0a0a";
|
|
131
131
|
};
|
|
132
132
|
export { ElementColors, RelationshipColors };
|
package/dist/colors/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IconUrl } from './_common';
|
|
2
2
|
import type { BorderStyle, ElementKind, ElementShape, Fqn, Tag } from './element';
|
|
3
|
+
import type { RelationshipArrowType, RelationshipLineType } from './relation';
|
|
3
4
|
import type { ThemeColor } from './theme';
|
|
4
5
|
import type { ViewID } from './view';
|
|
5
6
|
interface BaseExpr {
|
|
@@ -16,6 +17,7 @@ interface BaseExpr {
|
|
|
16
17
|
inout?: never;
|
|
17
18
|
incoming?: never;
|
|
18
19
|
outgoing?: never;
|
|
20
|
+
customRelation?: never;
|
|
19
21
|
}
|
|
20
22
|
export interface ElementRefExpr extends Omit<BaseExpr, 'element' | 'isDescedants'> {
|
|
21
23
|
element: Fqn;
|
|
@@ -57,6 +59,7 @@ export interface ElementTagExpr extends Omit<BaseExpr, 'elementTag' | 'isEqual'>
|
|
|
57
59
|
export declare function isElementTagExpr(expr: Expression): expr is ElementTagExpr;
|
|
58
60
|
export type ElementExpression = ElementRefExpr | WildcardExpr | ElementKindExpr | ElementTagExpr | ExpandedElementExpr;
|
|
59
61
|
export declare function isElement(expr: Expression): expr is ElementExpression;
|
|
62
|
+
export type ElementPredicateExpression = ElementExpression | CustomElementExpr;
|
|
60
63
|
export interface RelationExpr extends Omit<BaseExpr, 'source' | 'target'> {
|
|
61
64
|
source: ElementExpression;
|
|
62
65
|
target: ElementExpression;
|
|
@@ -75,8 +78,20 @@ export interface OutgoingExpr extends Omit<BaseExpr, 'outgoing'> {
|
|
|
75
78
|
outgoing: ElementExpression;
|
|
76
79
|
}
|
|
77
80
|
export declare function isOutgoing(expr: Expression): expr is OutgoingExpr;
|
|
78
|
-
export
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
export interface CustomRelationExpr extends Omit<BaseExpr, 'customRelation'> {
|
|
82
|
+
customRelation: {
|
|
83
|
+
relation: RelationExpr;
|
|
84
|
+
title?: string;
|
|
85
|
+
color?: ThemeColor;
|
|
86
|
+
line?: RelationshipLineType;
|
|
87
|
+
head?: RelationshipArrowType;
|
|
88
|
+
tail?: RelationshipArrowType;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export declare function isCustomRelationExpr(expr: Expression): expr is CustomRelationExpr;
|
|
92
|
+
export type RelationExpression = RelationExpr | InOutExpr | IncomingExpr | OutgoingExpr;
|
|
93
|
+
export type RelationPredicateExpression = RelationExpression | CustomRelationExpr;
|
|
94
|
+
export declare function isAnyRelation(expr: Expression): expr is RelationPredicateExpression;
|
|
95
|
+
export type Expression = ElementPredicateExpression | RelationPredicateExpression;
|
|
81
96
|
export {};
|
|
82
97
|
//# sourceMappingURL=expression.d.ts.map
|
package/dist/types/expression.js
CHANGED
|
@@ -35,8 +35,11 @@ export function isIncoming(expr) {
|
|
|
35
35
|
export function isOutgoing(expr) {
|
|
36
36
|
return 'outgoing' in expr;
|
|
37
37
|
}
|
|
38
|
+
export function isCustomRelationExpr(expr) {
|
|
39
|
+
return 'customRelation' in expr;
|
|
40
|
+
}
|
|
38
41
|
export function isAnyRelation(expr) {
|
|
39
|
-
return isRelation(expr) || isInOut(expr) || isIncoming(expr) || isOutgoing(expr);
|
|
42
|
+
return isRelation(expr) || isInOut(expr) || isIncoming(expr) || isOutgoing(expr) || isCustomRelationExpr(expr);
|
|
40
43
|
}
|
|
41
44
|
// export const Expr = {
|
|
42
45
|
// isElementRef,
|
package/dist/types/model.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Element, Fqn } from './element';
|
|
2
2
|
import type { Relation, RelationID } from './relation';
|
|
3
|
-
import type { ComputedView,
|
|
3
|
+
import type { ComputedView, LikeC4View, ViewID } from './view';
|
|
4
4
|
export interface LikeC4Model {
|
|
5
5
|
elements: Record<Fqn, Element>;
|
|
6
6
|
relations: Record<RelationID, Relation>;
|
|
7
|
-
views: Record<ViewID,
|
|
7
|
+
views: Record<ViewID, LikeC4View>;
|
|
8
8
|
}
|
|
9
9
|
export interface LikeC4ComputedModel {
|
|
10
10
|
elements: Record<Fqn, Element>;
|
package/dist/types/relation.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { ThemeColor } from './theme';
|
|
|
5
5
|
export type RelationID = Opaque<string, 'RelationID'>;
|
|
6
6
|
export type RelationshipKind = Opaque<string, 'RelationshipKind'>;
|
|
7
7
|
export type RelationshipLineType = 'dashed' | 'solid' | 'dotted';
|
|
8
|
-
export type RelationshipArrowType = 'none' | 'normal' | 'onormal' | 'diamond' | 'odiamond' | 'crow' | 'open' | 'vee';
|
|
8
|
+
export type RelationshipArrowType = 'none' | 'normal' | 'onormal' | 'dot' | 'odot' | 'diamond' | 'odiamond' | 'crow' | 'open' | 'vee';
|
|
9
9
|
export declare const DefaultLineStyle = "dashed";
|
|
10
10
|
export declare const DefaultArrowType = "normal";
|
|
11
11
|
export declare const DefaultRelationshipColor = "gray";
|
package/dist/types/theme.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type RelationshipThemeColors = {
|
|
|
19
19
|
[key in ThemeColor]: RelationshipThemeColorValues;
|
|
20
20
|
};
|
|
21
21
|
export interface LikeC4Theme {
|
|
22
|
-
font: '
|
|
22
|
+
font: 'Arial';
|
|
23
23
|
shadow: ColorLiteral;
|
|
24
24
|
relationships: RelationshipThemeColors;
|
|
25
25
|
elements: ElementThemeColors;
|
package/dist/types/view.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type { IconUrl, NonEmptyArray, Point, XYPosition } from './_common';
|
|
2
2
|
import type { ElementKind, ElementShape, ElementStyle, Fqn, Tag } from './element';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ElementExpression, ElementPredicateExpression, Expression } from './expression';
|
|
4
4
|
import type { Opaque } from './opaque';
|
|
5
5
|
import type { RelationID, RelationshipArrowType, RelationshipLineType } from './relation';
|
|
6
|
-
import type {
|
|
6
|
+
import type { ThemeColor } from './theme';
|
|
7
7
|
export type ViewID = Opaque<string, 'ViewID'>;
|
|
8
|
-
export type
|
|
8
|
+
export type ViewRulePredicate = {
|
|
9
9
|
include: Expression[];
|
|
10
10
|
exclude?: never;
|
|
11
11
|
} | {
|
|
12
12
|
include?: never;
|
|
13
13
|
exclude: Expression[];
|
|
14
14
|
};
|
|
15
|
-
export declare function
|
|
15
|
+
export declare function isViewRulePredicate(rule: ViewRule): rule is ViewRulePredicate;
|
|
16
16
|
export interface ViewRuleStyle {
|
|
17
17
|
targets: ElementExpression[];
|
|
18
18
|
style: ElementStyle & {
|
|
@@ -27,8 +27,8 @@ export interface ViewRuleAutoLayout {
|
|
|
27
27
|
autoLayout: AutoLayoutDirection;
|
|
28
28
|
}
|
|
29
29
|
export declare function isViewRuleAutoLayout(rule: ViewRule): rule is ViewRuleAutoLayout;
|
|
30
|
-
export type ViewRule =
|
|
31
|
-
export interface BasicView<ViewType extends 'element' | 'dynamic'
|
|
30
|
+
export type ViewRule = ViewRulePredicate | ViewRuleStyle | ViewRuleAutoLayout;
|
|
31
|
+
export interface BasicView<ViewType extends 'element' | 'dynamic'> {
|
|
32
32
|
readonly __?: ViewType;
|
|
33
33
|
readonly id: ViewID;
|
|
34
34
|
readonly title: string | null;
|
|
@@ -59,13 +59,13 @@ export interface BasicElementView extends BasicView<'element'> {
|
|
|
59
59
|
readonly viewOf?: Fqn;
|
|
60
60
|
readonly rules: ViewRule[];
|
|
61
61
|
}
|
|
62
|
-
export interface
|
|
62
|
+
export interface ScopedElementView extends BasicElementView {
|
|
63
63
|
readonly viewOf: Fqn;
|
|
64
64
|
}
|
|
65
65
|
export interface ExtendsElementView extends BasicElementView {
|
|
66
66
|
readonly extends: ViewID;
|
|
67
67
|
}
|
|
68
|
-
export type ElementView =
|
|
68
|
+
export type ElementView = ScopedElementView | ExtendsElementView | BasicElementView;
|
|
69
69
|
export interface DynamicViewStep {
|
|
70
70
|
readonly source: Fqn;
|
|
71
71
|
readonly target: Fqn;
|
|
@@ -73,7 +73,7 @@ export interface DynamicViewStep {
|
|
|
73
73
|
readonly isBackward?: boolean;
|
|
74
74
|
}
|
|
75
75
|
export type DynamicViewIncludeRule = {
|
|
76
|
-
include:
|
|
76
|
+
include: ElementPredicateExpression[];
|
|
77
77
|
};
|
|
78
78
|
export declare function isDynamicViewIncludeRule(rule: DynamicViewRule): rule is DynamicViewIncludeRule;
|
|
79
79
|
export type DynamicViewRule = DynamicViewIncludeRule | ViewRuleStyle | ViewRuleAutoLayout;
|
|
@@ -82,11 +82,11 @@ export interface DynamicView extends BasicView<'dynamic'> {
|
|
|
82
82
|
readonly steps: DynamicViewStep[];
|
|
83
83
|
readonly rules: DynamicViewRule[];
|
|
84
84
|
}
|
|
85
|
-
export type
|
|
86
|
-
export declare function isDynamicView(view:
|
|
87
|
-
export declare function isElementView(view:
|
|
88
|
-
export declare function isExtendsElementView(view:
|
|
89
|
-
export declare function
|
|
85
|
+
export type LikeC4View = ElementView | DynamicView;
|
|
86
|
+
export declare function isDynamicView(view: LikeC4View): view is DynamicView;
|
|
87
|
+
export declare function isElementView(view: LikeC4View): view is ElementView;
|
|
88
|
+
export declare function isExtendsElementView(view: LikeC4View): view is ExtendsElementView;
|
|
89
|
+
export declare function isScopedElementView(view: LikeC4View): view is ScopedElementView;
|
|
90
90
|
export type NodeId = Fqn;
|
|
91
91
|
export type EdgeId = Opaque<string, 'EdgeId'>;
|
|
92
92
|
export type StepEdgeIdLiteral = `step-${number}`;
|
|
@@ -119,6 +119,10 @@ export interface ComputedNode {
|
|
|
119
119
|
navigateTo?: ViewID;
|
|
120
120
|
level: number;
|
|
121
121
|
depth?: number;
|
|
122
|
+
/**
|
|
123
|
+
* If this node was customized in the view
|
|
124
|
+
*/
|
|
125
|
+
isCustomized?: boolean;
|
|
122
126
|
}
|
|
123
127
|
export interface ComputedEdge {
|
|
124
128
|
id: EdgeId;
|
|
@@ -131,6 +135,10 @@ export interface ComputedEdge {
|
|
|
131
135
|
line?: RelationshipLineType;
|
|
132
136
|
head?: RelationshipArrowType;
|
|
133
137
|
tail?: RelationshipArrowType;
|
|
138
|
+
/**
|
|
139
|
+
* If this edge is derived from custom relationship predicate
|
|
140
|
+
*/
|
|
141
|
+
isCustomized?: boolean;
|
|
134
142
|
/**
|
|
135
143
|
* For layouting purposes
|
|
136
144
|
* @default 'forward'
|
|
@@ -157,29 +165,15 @@ export type BBox = {
|
|
|
157
165
|
width: number;
|
|
158
166
|
height: number;
|
|
159
167
|
};
|
|
160
|
-
export interface DiagramLabel {
|
|
161
|
-
align: 'left' | 'right' | 'center';
|
|
162
|
-
fontStyle?: 'bold' | 'normal';
|
|
163
|
-
color?: ColorLiteral;
|
|
164
|
-
fontSize: number;
|
|
165
|
-
pt: Point;
|
|
166
|
-
width: number;
|
|
167
|
-
text: string;
|
|
168
|
-
}
|
|
169
168
|
export interface DiagramNode extends ComputedNode {
|
|
170
169
|
width: number;
|
|
171
170
|
height: number;
|
|
172
171
|
position: Point;
|
|
173
|
-
|
|
172
|
+
labelBBox: BBox;
|
|
174
173
|
}
|
|
175
174
|
export interface DiagramEdge extends ComputedEdge {
|
|
176
175
|
points: NonEmptyArray<Point>;
|
|
177
|
-
|
|
178
|
-
headArrowPoint?: Point;
|
|
179
|
-
tailArrow?: NonEmptyArray<Point>;
|
|
180
|
-
tailArrowPoint?: Point;
|
|
181
|
-
labels?: NonEmptyArray<DiagramLabel>;
|
|
182
|
-
labelBBox?: BBox;
|
|
176
|
+
labelBBox?: BBox | null;
|
|
183
177
|
}
|
|
184
178
|
export interface DiagramView extends Omit<ComputedView, 'nodes' | 'edges'> {
|
|
185
179
|
readonly nodes: DiagramNode[];
|
package/dist/types/view.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isNullish } from 'remeda';
|
|
2
|
-
export function
|
|
2
|
+
export function isViewRulePredicate(rule) {
|
|
3
3
|
return (('include' in rule && Array.isArray(rule.include))
|
|
4
4
|
|| ('exclude' in rule && Array.isArray(rule.exclude)));
|
|
5
5
|
}
|
|
@@ -21,7 +21,7 @@ export function isElementView(view) {
|
|
|
21
21
|
export function isExtendsElementView(view) {
|
|
22
22
|
return isElementView(view) && 'extends' in view;
|
|
23
23
|
}
|
|
24
|
-
export function
|
|
24
|
+
export function isScopedElementView(view) {
|
|
25
25
|
return isElementView(view) && 'viewOf' in view;
|
|
26
26
|
}
|
|
27
27
|
export function StepEdgeId(step) {
|
package/dist/utils/fqn.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Element, Fqn } from '../types';
|
|
2
|
+
type Predicate<T> = (x: T) => boolean;
|
|
2
3
|
export declare function nameFromFqn(fqn: Fqn): string;
|
|
3
4
|
export declare function isAncestor<E extends {
|
|
4
5
|
id: Fqn;
|
|
@@ -12,6 +13,9 @@ export declare function isDescendantOf<E extends {
|
|
|
12
13
|
export declare function notDescendantOf(ancestors: Element[]): (e: Element) => boolean;
|
|
13
14
|
export declare function commonAncestor(first: Fqn, second: Fqn): Fqn | null;
|
|
14
15
|
export declare function parentFqn(fqn: Fqn): Fqn | null;
|
|
16
|
+
export declare function parentFqnPredicate<T extends {
|
|
17
|
+
parent: Fqn | null;
|
|
18
|
+
}>(parent: Fqn): Predicate<T>;
|
|
15
19
|
/**
|
|
16
20
|
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
17
21
|
* (from closest to root)
|
|
@@ -31,4 +35,5 @@ export declare function compareFqnHierarchically<T extends string = string>(a: T
|
|
|
31
35
|
export declare function compareByFqnHierarchically<T extends {
|
|
32
36
|
id: string;
|
|
33
37
|
}>(a: T, b: T): number;
|
|
38
|
+
export {};
|
|
34
39
|
//# sourceMappingURL=fqn.d.ts.map
|
package/dist/utils/fqn.js
CHANGED
|
@@ -52,6 +52,10 @@ export function parentFqn(fqn) {
|
|
|
52
52
|
}
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
|
+
export function parentFqnPredicate(parent) {
|
|
56
|
+
const prefix = parent + '.';
|
|
57
|
+
return (e) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix));
|
|
58
|
+
}
|
|
55
59
|
/**
|
|
56
60
|
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
57
61
|
* (from closest to root)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"homepage": "https://likec4.dev",
|
|
6
6
|
"author": "Denis Davydkov <denis@davydkov.com>",
|
|
@@ -66,16 +66,16 @@
|
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"remeda": "^
|
|
69
|
+
"remeda": "^2.3.0",
|
|
70
70
|
"ts-custom-error": "^3.3.1",
|
|
71
|
-
"type-fest": "^4.
|
|
71
|
+
"type-fest": "^4.21.0"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@likec4/tsconfig": "1.
|
|
74
|
+
"@likec4/tsconfig": "1.6.0",
|
|
75
75
|
"@total-typescript/ts-reset": "^0.5.1",
|
|
76
|
-
"execa": "^9.
|
|
77
|
-
"typescript": "^5.
|
|
78
|
-
"vitest": "~
|
|
76
|
+
"execa": "^9.3.0",
|
|
77
|
+
"typescript": "^5.5.3",
|
|
78
|
+
"vitest": "~2.0.3"
|
|
79
79
|
},
|
|
80
|
-
"packageManager": "yarn@4.3.
|
|
80
|
+
"packageManager": "yarn@4.3.1"
|
|
81
81
|
}
|
package/src/colors/element.ts
CHANGED
package/src/colors/index.ts
CHANGED
package/src/types/expression.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IconUrl } from './_common'
|
|
2
2
|
import type { BorderStyle, ElementKind, ElementShape, Fqn, Tag } from './element'
|
|
3
|
+
import type { RelationshipArrowType, RelationshipLineType } from './relation'
|
|
3
4
|
import type { ThemeColor } from './theme'
|
|
4
5
|
import type { ViewID } from './view'
|
|
5
6
|
|
|
@@ -17,6 +18,7 @@ interface BaseExpr {
|
|
|
17
18
|
inout?: never
|
|
18
19
|
incoming?: never
|
|
19
20
|
outgoing?: never
|
|
21
|
+
customRelation?: never
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export interface ElementRefExpr extends Omit<BaseExpr, 'element' | 'isDescedants'> {
|
|
@@ -89,6 +91,8 @@ export function isElement(expr: Expression): expr is ElementExpression {
|
|
|
89
91
|
|| isExpandedElementExpr(expr)
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
export type ElementPredicateExpression = ElementExpression | CustomElementExpr
|
|
95
|
+
|
|
92
96
|
export interface RelationExpr extends Omit<BaseExpr, 'source' | 'target'> {
|
|
93
97
|
source: ElementExpression
|
|
94
98
|
target: ElementExpression
|
|
@@ -118,13 +122,29 @@ export function isOutgoing(expr: Expression): expr is OutgoingExpr {
|
|
|
118
122
|
return 'outgoing' in expr
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
export
|
|
125
|
+
export interface CustomRelationExpr extends Omit<BaseExpr, 'customRelation'> {
|
|
126
|
+
customRelation: {
|
|
127
|
+
relation: RelationExpr
|
|
128
|
+
title?: string
|
|
129
|
+
color?: ThemeColor
|
|
130
|
+
line?: RelationshipLineType
|
|
131
|
+
head?: RelationshipArrowType
|
|
132
|
+
tail?: RelationshipArrowType
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export function isCustomRelationExpr(expr: Expression): expr is CustomRelationExpr {
|
|
136
|
+
return 'customRelation' in expr
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export type RelationExpression = RelationExpr | InOutExpr | IncomingExpr | OutgoingExpr
|
|
140
|
+
|
|
141
|
+
export type RelationPredicateExpression = RelationExpression | CustomRelationExpr
|
|
122
142
|
|
|
123
|
-
export function isAnyRelation(expr: Expression): expr is
|
|
124
|
-
return isRelation(expr) || isInOut(expr) || isIncoming(expr) || isOutgoing(expr)
|
|
143
|
+
export function isAnyRelation(expr: Expression): expr is RelationPredicateExpression {
|
|
144
|
+
return isRelation(expr) || isInOut(expr) || isIncoming(expr) || isOutgoing(expr) || isCustomRelationExpr(expr)
|
|
125
145
|
}
|
|
126
146
|
|
|
127
|
-
export type Expression =
|
|
147
|
+
export type Expression = ElementPredicateExpression | RelationPredicateExpression
|
|
128
148
|
|
|
129
149
|
// export const Expr = {
|
|
130
150
|
// isElementRef,
|
package/src/types/model.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Element, Fqn } from './element'
|
|
2
2
|
import type { Relation, RelationID } from './relation'
|
|
3
|
-
import type { ComputedView,
|
|
3
|
+
import type { ComputedView, LikeC4View, ViewID } from './view'
|
|
4
4
|
|
|
5
5
|
export interface LikeC4Model {
|
|
6
6
|
elements: Record<Fqn, Element>
|
|
7
7
|
relations: Record<RelationID, Relation>
|
|
8
|
-
views: Record<ViewID,
|
|
8
|
+
views: Record<ViewID, LikeC4View>
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface LikeC4ComputedModel {
|
package/src/types/relation.ts
CHANGED
package/src/types/theme.ts
CHANGED
package/src/types/view.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { isNullish } from 'remeda'
|
|
2
2
|
import type { IconUrl, NonEmptyArray, Point, XYPosition } from './_common'
|
|
3
3
|
import type { ElementKind, ElementShape, ElementStyle, Fqn, Tag } from './element'
|
|
4
|
-
import type {
|
|
4
|
+
import type { ElementExpression, ElementPredicateExpression, Expression } from './expression'
|
|
5
5
|
import type { Opaque } from './opaque'
|
|
6
6
|
import type { RelationID, RelationshipArrowType, RelationshipLineType } from './relation'
|
|
7
|
-
import type {
|
|
7
|
+
import type { ThemeColor } from './theme'
|
|
8
8
|
|
|
9
9
|
// Full-qualified-name
|
|
10
10
|
export type ViewID = Opaque<string, 'ViewID'>
|
|
11
11
|
|
|
12
|
-
export type
|
|
12
|
+
export type ViewRulePredicate =
|
|
13
13
|
| {
|
|
14
14
|
include: Expression[]
|
|
15
15
|
exclude?: never
|
|
@@ -18,7 +18,7 @@ export type ViewRuleExpression =
|
|
|
18
18
|
include?: never
|
|
19
19
|
exclude: Expression[]
|
|
20
20
|
}
|
|
21
|
-
export function
|
|
21
|
+
export function isViewRulePredicate(rule: ViewRule): rule is ViewRulePredicate {
|
|
22
22
|
return (
|
|
23
23
|
('include' in rule && Array.isArray(rule.include))
|
|
24
24
|
|| ('exclude' in rule && Array.isArray(rule.exclude))
|
|
@@ -45,9 +45,9 @@ export function isViewRuleAutoLayout(rule: ViewRule): rule is ViewRuleAutoLayout
|
|
|
45
45
|
return 'autoLayout' in rule
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
export type ViewRule =
|
|
48
|
+
export type ViewRule = ViewRulePredicate | ViewRuleStyle | ViewRuleAutoLayout
|
|
49
49
|
|
|
50
|
-
export interface BasicView<ViewType extends 'element' | 'dynamic'
|
|
50
|
+
export interface BasicView<ViewType extends 'element' | 'dynamic'> {
|
|
51
51
|
readonly __?: ViewType
|
|
52
52
|
readonly id: ViewID
|
|
53
53
|
readonly title: string | null
|
|
@@ -81,14 +81,14 @@ export interface BasicElementView extends BasicView<'element'> {
|
|
|
81
81
|
readonly viewOf?: Fqn
|
|
82
82
|
readonly rules: ViewRule[]
|
|
83
83
|
}
|
|
84
|
-
export interface
|
|
84
|
+
export interface ScopedElementView extends BasicElementView {
|
|
85
85
|
readonly viewOf: Fqn
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
export interface ExtendsElementView extends BasicElementView {
|
|
89
89
|
readonly extends: ViewID
|
|
90
90
|
}
|
|
91
|
-
export type ElementView =
|
|
91
|
+
export type ElementView = ScopedElementView | ExtendsElementView | BasicElementView
|
|
92
92
|
|
|
93
93
|
export interface DynamicViewStep {
|
|
94
94
|
readonly source: Fqn
|
|
@@ -98,7 +98,7 @@ export interface DynamicViewStep {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
export type DynamicViewIncludeRule = {
|
|
101
|
-
include:
|
|
101
|
+
include: ElementPredicateExpression[]
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
export function isDynamicViewIncludeRule(rule: DynamicViewRule): rule is DynamicViewIncludeRule {
|
|
@@ -114,27 +114,26 @@ export interface DynamicView extends BasicView<'dynamic'> {
|
|
|
114
114
|
readonly rules: DynamicViewRule[]
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
export type
|
|
117
|
+
export type LikeC4View = ElementView | DynamicView
|
|
118
118
|
|
|
119
|
-
export function isDynamicView(view:
|
|
119
|
+
export function isDynamicView(view: LikeC4View): view is DynamicView {
|
|
120
120
|
return view.__ === 'dynamic'
|
|
121
121
|
}
|
|
122
|
-
export function isElementView(view:
|
|
122
|
+
export function isElementView(view: LikeC4View): view is ElementView {
|
|
123
123
|
return isNullish(view.__) || view.__ === 'element'
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
export function isExtendsElementView(view:
|
|
126
|
+
export function isExtendsElementView(view: LikeC4View): view is ExtendsElementView {
|
|
127
127
|
return isElementView(view) && 'extends' in view
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
export function
|
|
130
|
+
export function isScopedElementView(view: LikeC4View): view is ScopedElementView {
|
|
131
131
|
return isElementView(view) && 'viewOf' in view
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
export type NodeId = Fqn
|
|
135
135
|
|
|
136
136
|
export type EdgeId = Opaque<string, 'EdgeId'>
|
|
137
|
-
|
|
138
137
|
export type StepEdgeIdLiteral = `step-${number}`
|
|
139
138
|
export type StepEdgeId = Opaque<StepEdgeIdLiteral, 'EdgeId'>
|
|
140
139
|
export function StepEdgeId(step: number): StepEdgeId {
|
|
@@ -177,6 +176,10 @@ export interface ComputedNode {
|
|
|
177
176
|
level: number
|
|
178
177
|
// For compound nodes, the max depth of nested nodes
|
|
179
178
|
depth?: number
|
|
179
|
+
/**
|
|
180
|
+
* If this node was customized in the view
|
|
181
|
+
*/
|
|
182
|
+
isCustomized?: boolean
|
|
180
183
|
}
|
|
181
184
|
|
|
182
185
|
export interface ComputedEdge {
|
|
@@ -190,7 +193,10 @@ export interface ComputedEdge {
|
|
|
190
193
|
line?: RelationshipLineType
|
|
191
194
|
head?: RelationshipArrowType
|
|
192
195
|
tail?: RelationshipArrowType
|
|
193
|
-
|
|
196
|
+
/**
|
|
197
|
+
* If this edge is derived from custom relationship predicate
|
|
198
|
+
*/
|
|
199
|
+
isCustomized?: boolean
|
|
194
200
|
/**
|
|
195
201
|
* For layouting purposes
|
|
196
202
|
* @default 'forward'
|
|
@@ -227,35 +233,17 @@ export type BBox = {
|
|
|
227
233
|
height: number
|
|
228
234
|
}
|
|
229
235
|
|
|
230
|
-
export interface DiagramLabel {
|
|
231
|
-
align: 'left' | 'right' | 'center'
|
|
232
|
-
fontStyle?: 'bold' | 'normal'
|
|
233
|
-
color?: ColorLiteral
|
|
234
|
-
fontSize: number
|
|
235
|
-
pt: Point
|
|
236
|
-
width: number
|
|
237
|
-
text: string
|
|
238
|
-
}
|
|
239
|
-
|
|
240
236
|
export interface DiagramNode extends ComputedNode {
|
|
241
237
|
width: number
|
|
242
238
|
height: number
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
239
|
+
// Absolute position, top left
|
|
240
|
+
position: Point
|
|
241
|
+
labelBBox: BBox
|
|
246
242
|
}
|
|
247
243
|
|
|
248
244
|
export interface DiagramEdge extends ComputedEdge {
|
|
249
245
|
points: NonEmptyArray<Point>
|
|
250
|
-
|
|
251
|
-
headArrow?: NonEmptyArray<Point>
|
|
252
|
-
// Draw arrow from the last point of the edge to this point
|
|
253
|
-
headArrowPoint?: Point
|
|
254
|
-
tailArrow?: NonEmptyArray<Point>
|
|
255
|
-
// Draw arrow from the first point of the edge to this point
|
|
256
|
-
tailArrowPoint?: Point
|
|
257
|
-
labels?: NonEmptyArray<DiagramLabel>
|
|
258
|
-
labelBBox?: BBox
|
|
246
|
+
labelBBox?: BBox | null
|
|
259
247
|
}
|
|
260
248
|
|
|
261
249
|
export interface DiagramView extends Omit<ComputedView, 'nodes' | 'edges'> {
|
package/src/utils/fqn.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Element, Fqn } from '../types'
|
|
2
2
|
import { isString } from './guards'
|
|
3
3
|
|
|
4
|
+
type Predicate<T> = (x: T) => boolean
|
|
5
|
+
|
|
4
6
|
export function nameFromFqn(fqn: Fqn) {
|
|
5
7
|
const lastDot = fqn.lastIndexOf('.')
|
|
6
8
|
if (lastDot > 0) {
|
|
@@ -64,6 +66,11 @@ export function parentFqn(fqn: Fqn): Fqn | null {
|
|
|
64
66
|
return null
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
export function parentFqnPredicate<T extends { parent: Fqn | null }>(parent: Fqn): Predicate<T> {
|
|
70
|
+
const prefix = parent + '.'
|
|
71
|
+
return (e: T) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix))
|
|
72
|
+
}
|
|
73
|
+
|
|
67
74
|
/**
|
|
68
75
|
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
69
76
|
* (from closest to root)
|