@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 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
- if (level === 'full')
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
- if (total <= COMPACT_MEMBER_ROWS)
113
- return entity;
114
- const kept = entity.members.slice(0, COMPACT_MEMBER_ROWS);
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 - COMPACT_MEMBER_ROWS} more (${total} members)`,
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). */
@@ -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
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yalehwang/plantuml-js",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Pure-TypeScript PlantUML class diagram renderer (MIT)",
5
5
  "type": "module",
6
6
  "license": "MIT",