@yalehwang/plantuml-js 0.4.1 → 0.5.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/dist/core.d.ts +12 -0
- package/dist/core.js +4 -1
- package/dist/foundation/layout.d.ts +18 -1
- package/dist/foundation/layout.js +29 -7
- package/dist/foundation/model.d.ts +7 -0
- package/dist/render/svg.js +1 -1
- package/package.json +1 -1
package/dist/core.d.ts
CHANGED
|
@@ -46,6 +46,18 @@ export interface RendererOptions {
|
|
|
46
46
|
* Default: chosen by entity count (≤40 full, ≤150 compact, else names).
|
|
47
47
|
*/
|
|
48
48
|
detail?: DetailLevel;
|
|
49
|
+
/**
|
|
50
|
+
* Maximum member rows drawn per entity; surplus members collapse into the
|
|
51
|
+
* existing `… +N more (M members)` row. Applied before layout, so the box is
|
|
52
|
+
* sized for what is drawn. Default: unlimited for `full`, 4 for `compact`.
|
|
53
|
+
*/
|
|
54
|
+
memberMaxRows?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Cut each drawn member line to this many characters (ending with `…`).
|
|
57
|
+
* Only the drawn text changes: `PlantUmlMember.raw` keeps the full
|
|
58
|
+
* declaration. Default: unlimited.
|
|
59
|
+
*/
|
|
60
|
+
memberMaxChars?: number;
|
|
49
61
|
/**
|
|
50
62
|
* `'aggregate'` folds the relations between two packages into one weighted
|
|
51
63
|
* box-to-box corridor edge (originals kept in its `<title>`); `'raw'` draws
|
package/dist/core.js
CHANGED
|
@@ -68,7 +68,10 @@ export function createRenderer(options = {}) {
|
|
|
68
68
|
}
|
|
69
69
|
async function renderParsed(parsed, options, engine, renderEngine) {
|
|
70
70
|
const { model: transformed, hiddenTransitive } = transformForRender(parsed, options);
|
|
71
|
-
const model = applyDetail(transformed, options.detail
|
|
71
|
+
const model = applyDetail(transformed, options.detail, {
|
|
72
|
+
memberMaxRows: options.memberMaxRows,
|
|
73
|
+
memberMaxChars: options.memberMaxChars,
|
|
74
|
+
});
|
|
72
75
|
const started = performance.now();
|
|
73
76
|
const layout = await engine.layout(model);
|
|
74
77
|
const layoutMs = Math.round((performance.now() - started) * 100) / 100;
|
|
@@ -105,11 +105,28 @@ export declare const DETAIL_COMPACT_MAX_ENTITIES = 150;
|
|
|
105
105
|
/** Member rows kept per entity in `compact` mode. */
|
|
106
106
|
export declare const COMPACT_MEMBER_ROWS = 4;
|
|
107
107
|
export declare function autoDetail(entityCount: number): DetailLevel;
|
|
108
|
+
/**
|
|
109
|
+
* Optional caps on the member text a diagram draws. Both are applied by
|
|
110
|
+
* [[applyDetail]] before layout, so an entity is sized for exactly what the
|
|
111
|
+
* renderer emits; neither mutates `PlantUmlMember.raw`.
|
|
112
|
+
*/
|
|
113
|
+
export interface MemberDisplayLimits {
|
|
114
|
+
/** Maximum member rows drawn per entity; the rest collapse into the count row. */
|
|
115
|
+
memberMaxRows?: number;
|
|
116
|
+
/** Cut each drawn member line to this many characters, ending with `…`. */
|
|
117
|
+
memberMaxChars?: number;
|
|
118
|
+
}
|
|
108
119
|
/**
|
|
109
120
|
* Reduce member rows to the requested detail level *before* layout, so boxes
|
|
110
121
|
* are sized for what is actually drawn. `undefined` picks by entity count.
|
|
122
|
+
*
|
|
123
|
+
* `limits` caps the drawn rows per entity (`memberMaxRows`, replacing
|
|
124
|
+
* [[COMPACT_MEMBER_ROWS]] for `compact` and also capping `full`) and the width
|
|
125
|
+
* of each drawn line (`memberMaxChars`). Truncation only sets
|
|
126
|
+
* `PlantUmlMember.display`; `raw` keeps the full declaration. Without limits
|
|
127
|
+
* the result is byte-for-byte what it always was.
|
|
111
128
|
*/
|
|
112
|
-
export declare function applyDetail(model: PlantUmlModel, detail?: DetailLevel): PlantUmlModel;
|
|
129
|
+
export declare function applyDetail(model: PlantUmlModel, detail?: DetailLevel, limits?: MemberDisplayLimits): PlantUmlModel;
|
|
113
130
|
/**
|
|
114
131
|
* Group nodes into rows: within one package (or the top level), nodes whose
|
|
115
132
|
* vertical extents overlap belong to the same layered-layout rank. Returns
|
|
@@ -74,7 +74,7 @@ export function compartmentHeights(entity) {
|
|
|
74
74
|
export function estimateEntitySize(entity) {
|
|
75
75
|
const lines = [
|
|
76
76
|
displayName(entity),
|
|
77
|
-
...entity.members.map((m) => m.raw),
|
|
77
|
+
...entity.members.map((m) => m.display ?? m.raw),
|
|
78
78
|
];
|
|
79
79
|
const longest = lines.reduce((max, line) => Math.max(max, measureTextWidth(line, METRICS.fontSize)), 0);
|
|
80
80
|
const width = snapUp(Math.max(METRICS.minWidth, longest + METRICS.paddingX * 2));
|
|
@@ -98,26 +98,48 @@ export function autoDetail(entityCount) {
|
|
|
98
98
|
/**
|
|
99
99
|
* Reduce member rows to the requested detail level *before* layout, so boxes
|
|
100
100
|
* are sized for what is actually drawn. `undefined` picks by entity count.
|
|
101
|
+
*
|
|
102
|
+
* `limits` caps the drawn rows per entity (`memberMaxRows`, replacing
|
|
103
|
+
* [[COMPACT_MEMBER_ROWS]] for `compact` and also capping `full`) and the width
|
|
104
|
+
* of each drawn line (`memberMaxChars`). Truncation only sets
|
|
105
|
+
* `PlantUmlMember.display`; `raw` keeps the full declaration. Without limits
|
|
106
|
+
* the result is byte-for-byte what it always was.
|
|
101
107
|
*/
|
|
102
|
-
export function applyDetail(model, detail) {
|
|
108
|
+
export function applyDetail(model, detail, limits = {}) {
|
|
103
109
|
const level = detail ?? autoDetail(model.entities.length);
|
|
104
|
-
|
|
110
|
+
const { memberMaxRows, memberMaxChars } = limits;
|
|
111
|
+
const hasLimits = memberMaxRows !== undefined || memberMaxChars !== undefined;
|
|
112
|
+
if (level === 'full' && !hasLimits)
|
|
105
113
|
return model;
|
|
114
|
+
const limitMember = (member) => {
|
|
115
|
+
if (memberMaxChars === undefined || member.raw.length <= memberMaxChars)
|
|
116
|
+
return member;
|
|
117
|
+
return {
|
|
118
|
+
...member,
|
|
119
|
+
display: `${member.raw.slice(0, Math.max(0, memberMaxChars - 1))}…`,
|
|
120
|
+
};
|
|
121
|
+
};
|
|
106
122
|
return {
|
|
107
123
|
...model,
|
|
108
124
|
entities: model.entities.map((entity) => {
|
|
109
125
|
const total = entity.members.length;
|
|
110
126
|
if (level === 'names')
|
|
111
127
|
return total === 0 ? entity : { ...entity, members: [] };
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
128
|
+
const rowCap = memberMaxRows !== undefined
|
|
129
|
+
? memberMaxRows
|
|
130
|
+
: level === 'compact'
|
|
131
|
+
? COMPACT_MEMBER_ROWS
|
|
132
|
+
: total;
|
|
133
|
+
if (total <= rowCap) {
|
|
134
|
+
return hasLimits ? { ...entity, members: entity.members.map(limitMember) } : entity;
|
|
135
|
+
}
|
|
136
|
+
const kept = entity.members.slice(0, rowCap).map(limitMember);
|
|
115
137
|
const more = {
|
|
116
138
|
visibility: 'public',
|
|
117
139
|
name: '…',
|
|
118
140
|
kind: 'field',
|
|
119
141
|
modifiers: [],
|
|
120
|
-
raw: `… +${total -
|
|
142
|
+
raw: `… +${total - rowCap} more (${total} members)`,
|
|
121
143
|
};
|
|
122
144
|
return { ...entity, members: [...kept, more] };
|
|
123
145
|
}),
|
|
@@ -20,6 +20,13 @@ export interface PlantUmlMember {
|
|
|
20
20
|
optional?: boolean;
|
|
21
21
|
/** Full authored declaration incl. visibility symbol, for faithful display. */
|
|
22
22
|
raw: string;
|
|
23
|
+
/**
|
|
24
|
+
* Text actually drawn for this member, when it differs from `raw` (e.g. cut
|
|
25
|
+
* to a display width by `applyDetail`). Layout and rendering read
|
|
26
|
+
* `display ?? raw`; `raw` itself is never modified, so serialization and
|
|
27
|
+
* inspector views keep the full declaration.
|
|
28
|
+
*/
|
|
29
|
+
display?: string;
|
|
23
30
|
}
|
|
24
31
|
export interface PlantUmlEntity {
|
|
25
32
|
/** Stable node identity inside the diagram (the alias when `as` is used). */
|
package/dist/render/svg.js
CHANGED
|
@@ -166,7 +166,7 @@ function renderEntity(entity, node, theme) {
|
|
|
166
166
|
parts.push(rule(opsTop, 'ops'));
|
|
167
167
|
const titleBaseline = node.y + METRICS.paddingY + METRICS.fontSize + 1;
|
|
168
168
|
parts.push(textEl(displayName(entity), node.x + node.width / 2, titleBaseline, 'middle', font.size.title, font.weight.title, color.textTitle, theme, fontStyle));
|
|
169
|
-
const memberText = (member, idx, top, cls) => textEl(member.raw, node.x + METRICS.paddingX, top + METRICS.lineHeight * idx + METRICS.fontSize + 1, 'start', font.size.member, font.weight.member, color.textMember, theme, ` class="${cls}"`);
|
|
169
|
+
const memberText = (member, idx, top, cls) => textEl(member.display ?? member.raw, node.x + METRICS.paddingX, top + METRICS.lineHeight * idx + METRICS.fontSize + 1, 'start', font.size.member, font.weight.member, color.textMember, theme, ` class="${cls}"`);
|
|
170
170
|
attrs.forEach((member, i) => {
|
|
171
171
|
parts.push(memberText(member, i, titleBottom, 'uml-attr'));
|
|
172
172
|
});
|