umlimator 0.21.0 → 0.22.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.
@@ -44,7 +44,7 @@ export interface MapNode {
44
44
  /** A typed element in schema version 2's envelope (docs/diagrams/model.md §1): a node, a member, a typed edge, a
45
45
  * fragment. Nodes, edges, members and fragments share one id space; an id never contains "->". A typed edge is an
46
46
  * Element with `from` and `to`, which may name a member. A typed view is a MapView with `diagram` (uml.class), and may
47
- * have `subject`, `direction` ('right' | 'down'), `notation`, `present`, `fragments` and `timeline`. umlimator/all draws `uml.class` (0.18.0), `uml.object` and `uml.package` (0.19.0), `uml.sequence` and `uml.communication` (0.20.0), `uml.use-case`, `uml.activity`, `uml.state-machine` and `uml.interaction-overview` (0.21.0); other types draw as plain cards.
47
+ * have `subject`, `direction` ('right' | 'down'), `notation`, `present`, `fragments` and `timeline`. umlimator/all draws `uml.class` (0.18.0), `uml.object` and `uml.package` (0.19.0), `uml.sequence` and `uml.communication` (0.20.0), `uml.use-case`, `uml.activity`, `uml.state-machine` and `uml.interaction-overview` (0.21.0), `uml.component`, `uml.deployment` and `uml.composite-structure` (0.22.0); other types draw as plain cards.
48
48
  * From 0.19.0 the class, object and package types draw a shown package that owns something the view shows as a box holding it (`parent`), and
49
49
  * qualify names (`sales::Order`) from the nearest shown owner, the view's `subject`, or the top. */
50
50
  export interface Element {
@@ -157,6 +157,43 @@ export interface UmlTransitionProps { trigger?: string; guard?: string; effect?:
157
157
  export type UmlInteractionOverviewElementType = 'uml.InitialNode' | 'uml.ActivityFinalNode' | 'uml.FlowFinalNode' | 'uml.DecisionNode'
158
158
  | 'uml.MergeNode' | 'uml.ForkNode' | 'uml.JoinNode' | 'uml.InteractionUse' | 'uml.Interaction' | 'uml.Comment';
159
159
  export type UmlInteractionOverviewLineType = 'uml.ControlFlow' | 'uml.CommentLink';
160
+ /** The component diagram's vocabulary (a view with `diagram: 'uml.component'`, umlimator/all from 0.22.0;
161
+ * docs/conformance/uml-component.md). A component's `parent` is a component (drawn nested, a box) or a package; its
162
+ * ports (a class's too) are members, drawn on its border. A provided interface is always an `uml.Interface` node, joined
163
+ * to its provider (a component, a class or a port) by a realization and to its requirers by usages; `present.<id>.as:
164
+ * 'ball'` draws it as a ball, a usage to it ending in a socket. */
165
+ export type UmlComponentElementType = 'uml.Component' | 'uml.Interface' | 'uml.Artifact' | 'uml.Package' | 'uml.Comment';
166
+ export type UmlComponentMemberType = 'uml.Port';
167
+ export type UmlComponentLineType = 'uml.InterfaceRealization' | 'uml.ComponentRealization' | 'uml.Usage' | 'uml.Connector' | 'uml.Dependency'
168
+ | 'uml.Manifestation' | 'uml.CommentLink';
169
+ /** A port's props: its type, drawn `name : Type` beside it. */
170
+ export interface UmlPortProps { valueType?: string; stereotypes?: string[]; [key: string]: unknown }
171
+ /** A connector's props: in a component view its kind (an assembly when left out); in a composite structure view, an end
172
+ * through a part (UML's partWithPort): `ends.from.part` or `ends.to.part` names the part, `from` or `to` the port of its type. */
173
+ export interface UmlConnectorProps { kind?: 'assembly' | 'delegation'; ends?: { from?: { part?: string }; to?: { part?: string } }; stereotypes?: string[]; [key: string]: unknown }
174
+ /** What a component or composite structure view shows of one element, beside UmlPresent: an interface as a ball; a port's
175
+ * side; on a part, each of its type's ports' sides. */
176
+ export interface UmlStructurePresent { as?: 'ball'; side?: 'left' | 'right' | 'top' | 'bottom'; ports?: Record<string, { side?: 'left' | 'right' | 'top' | 'bottom' }> }
177
+ /** The deployment diagram's vocabulary (a view with `diagram: 'uml.deployment'`, umlimator/all from 0.22.0;
178
+ * docs/conformance/uml-deployment.md). A node, device or execution environment that holds something shown is a box drawn
179
+ * as a cube; an artifact or deployment specification whose `parent` is one is deployed on it, a `uml.Deployment` line
180
+ * from it to one is the other form. */
181
+ export type UmlDeploymentElementType = 'uml.Node' | 'uml.Device' | 'uml.ExecutionEnvironment' | 'uml.Artifact' | 'uml.DeploymentSpecification'
182
+ | 'uml.Component' | 'uml.Comment';
183
+ export type UmlDeploymentLineType = 'uml.Deployment' | 'uml.Manifestation' | 'uml.CommunicationPath' | 'uml.Dependency' | 'uml.CommentLink';
184
+ /** The composite structure diagram's vocabulary (a view with `diagram: 'uml.composite-structure'`, umlimator/all from
185
+ * 0.22.0; docs/conformance/uml-composite-structure.md). The view's `subject` (a class, component or collaboration, listed
186
+ * in `nodeIds`) is drawn as a box holding its parts (`uml.Property` members) and collaboration uses (`parent` the
187
+ * subject); a part shows the ports of the class or component its `valueType` names by label, each drawn under the id
188
+ * `<part>-><port>`. An open collaboration (listed in `nodeIds`) is a dashed ellipse round its roles. A role binding runs
189
+ * from a part to a collaboration use, its `label` the role. */
190
+ export type UmlCompositeStructureElementType = 'uml.Class' | 'uml.Component' | 'uml.Collaboration' | 'uml.CollaborationUse' | 'uml.Comment';
191
+ export type UmlCompositeStructureMemberType = 'uml.Property' | 'uml.Port';
192
+ export type UmlCompositeStructureLineType = 'uml.Connector' | 'uml.RoleBinding' | 'uml.CommentLink';
193
+ /** A part's (or role's) props: the class or component it is, by label; its multiplicity; shared parts are drawn dashed. */
194
+ export interface UmlPartProps { valueType?: string; multiplicity?: string; aggregation?: 'composite' | 'shared'; stereotypes?: string[]; [key: string]: unknown }
195
+ /** A collaboration use's props: the collaboration it uses, by label. */
196
+ export interface UmlCollaborationUseProps { collaboration?: string; stereotypes?: string[]; [key: string]: unknown }
160
197
  /** What a line means, drawn as its colour: calls (the default), feeds (hands work on), triggers (suggests, offers, fires),
161
198
  * state (reads or writes a file, board or config: a thinner line, a muted label, no flow) and guard (a hook steps in).
162
199
  * Colours are --um-w-<kind>. An edge's `style` (emphasis, dashed, security) wins over its kind's colour. */
package/lib/umlimator.js CHANGED
@@ -123,7 +123,7 @@ function registerDiagramType(name, def = {}) {
123
123
  reroute is no registry field: reroute: false goes in the dg the type's own layout passes to layoutTyped (src/typed/layout.js).
124
124
  Stage 4's (notes/stage-4.md §12.1, §15): edits.rename(model, view, id, text); a hook's { pick, then }; name: false and
125
125
  opens on a palette entry; a line's cut, its label's width (150); rows(model, view, id) and word(model, id), the PDF's.
126
- Stage 5's: a line's fromPort, toPort, inner, portRank, a box's pad, round, a view's labelGaps (src/typed/layout.js);
126
+ Stage 5's: a line's fromPort, toPort, inner, portRank, a box's pad, round, head, a view's labelGaps (src/typed/layout.js);
127
127
  edits.member, edits.key (src/typed/edit.js). */
128
128
 
129
129
  /* A view's type: the map for a view with no diagram, the registered type, or null for one this release does not draw */
@@ -131,7 +131,9 @@ const diagramOf = view => TYPES.get(view && view.diagram != null ? view.diagram
131
131
 
132
132
  /* What only a registered type's geometry uses, installed at load time by the files under src/typed/, which only
133
133
  lib/umlimator-all.js holds (tools/build.mjs): rows, rooms and routes in layoutPass, a typed line's ends in svgOf, the
134
- gestures of edit.js it takes over (edit). Empty in umlimator.js, where no view is laid out but as a map (risks.md C5) */
134
+ gestures of edit.js it takes over (edit), diff()'s words for typed models (diff, order: src/uml/diff.js). Empty in
135
+ umlimator.js, where no view is laid out but as a map (risks.md C5).
136
+ Stage 6's: across(model), validate()'s rules on the whole model; fields(model, x), more panel fields (notes/stage-6.md §5) */
135
137
  const TYPED = {};
136
138
 
137
139
  const propRefs = type => Object.assign({}, ...[...TYPES.values()].map(T => T.refs && Object.hasOwn(T.refs, type) && T.refs[type]));
@@ -248,6 +250,7 @@ function refs(m, ids, only) {
248
250
  arr(v.nodes).forEach((n, j) => element(n, [...at, 'nodes', j], false));
249
251
  arr(v.edges).forEach((e, j) => { if (has(e)) say([...at, 'edges', j], 'view'); else element(e, [...at, 'edges', j], true); });
250
252
  arr(v.fragments).forEach((f, j) => element(f, [...at, 'fragments', j], false));
253
+ ['changes', 'constraints'].forEach(k => arr(isObj(v.timeline) && v.timeline[k]).forEach((c, j) => isObj(c) && ['lifeline', 'from', 'to'].forEach(f => { if (has(c[f])) say([...at, 'timeline', k, j, f], 'end'); })));
251
254
  [['layout', 'pin'], ['present', 'present'], ['nodeOverrides', 'override']].forEach(([k, kind]) => Object.keys(isObj(v[k]) ? v[k] : {}).forEach(id => { if (has(id)) say([...at, k, id], kind); }));
252
255
  if (has(v.subject)) say([...at, 'subject'], 'subject');
253
256
  if (!only) ['parent', 'node'].forEach(k => { if (has(v[k])) say([...at, k], 'parent'); }); // a view opened from a card
@@ -374,9 +377,9 @@ function run(m, c, gone) {
374
377
  const take = id => { const r = at.get(id); if (!r || now.has(id)) return; now.add(id);
375
378
  arr(r.x.members).forEach(y => isObj(y) && take(y.id)); arr(kids.get(id)).forEach(take); }; // what it owns goes with it
376
379
  take(c.id);
377
- // lines to what is gone go too, lines to those lines, and what a type's refs cascade (a reply with its call)
380
+ // lines to what is gone go too, lines to those lines, a timeline's items, and what a type's refs cascade (a reply with its call)
378
381
  const cascade = x => Object.entries(propRefs(x.type)).some(([p, how]) => how === 'cascade' && [].concat(dig(x, p)).some(id => now.has(id)));
379
- for (let more = true; more;) { more = false; for (const [k, o] of at) if (!now.has(k) && (o.kind === 'edge' && (now.has(o.x.from) || now.has(o.x.to)) || cascade(o.x))) { take(k); more = true; } }
382
+ for (let more = true; more;) { more = false; for (const [k, o] of at) if (!now.has(k) && (o.kind === 'edge' && (now.has(o.x.from) || now.has(o.x.to)) || o.kind === 'time' && [o.x.lifeline, o.x.from, o.x.to].some(i => now.has(i)) || cascade(o.x))) { take(k); more = true; } }
380
383
  // what stays in something gone goes to its nearest owner left; an operand's messages to its fragment's parent
381
384
  const above = id => { const r = at.get(id); return r && (r.x.parent ?? (r.owner && above(r.owner.id))); };
382
385
  for (const [k, o] of at) if (!now.has(k) && now.has(o.x.parent)) { let p = o.x.parent;
@@ -1035,7 +1038,7 @@ function layoutPass(dg, map, room, last) { // room: { x: { col: px }, y: { row:
1035
1038
  // A typed view's boxes (notes/stage-2.md §3.2) take the same code as a map's: their title is the type's (`title`), and a box
1036
1039
  // grows to hold it; laid out turned (direction down), the 24 px header room goes left, the side that becomes the top
1037
1040
  const familyDefs = dg.containers || [], tagged = n => map && (n.author || n.k === 'm-ext'), TB = !map && dg.turned; // tagged: a name tag hangs under the card
1038
- const headW = f => textW(!map && f.title || f.label || f.id, 11) + 16; // a box's title, as the audit measures it
1041
+ const headW = f => textW(!map && f.title || f.label || f.id, !map && f.head ? 12 : 11) + 16; // a box's title, as the audit measures it (two lines: at 12 px)
1039
1042
  const framesNow = () => { const cache = Object.create(null); // a box may be named 'constructor'
1040
1043
  const frameOf = (f, trail = new Set()) => {
1041
1044
  if (cache[f.id]) return cache[f.id];
@@ -1048,7 +1051,7 @@ function layoutPass(dg, map, room, last) { // room: { x: { col: px }, y: { row:
1048
1051
  const p = 12, x = Math.min(...rects.map(r => r.x)) - p - (TB ? 24 : 0), y = Math.min(...rects.map(r => r.y)) - p - (TB ? 0 : 24);
1049
1052
  const b = {...f, x, y, w:Math.max(...rects.map(r => r.x+r.w)) + p - x, h:Math.max(...rects.map(r => r.y+r.h)) + p - y};
1050
1053
  if (!map) b[TB ? 'h' : 'w'] = Math.max(b[TB ? 'h' : 'w'], headW(f) + 16);
1051
- return cache[f.id] = dg.typed ? TYPED.frame(b) : b;
1054
+ return cache[f.id] = dg.typed ? TYPED.frame(b, TB) : b;
1052
1055
  };
1053
1056
  const out = familyDefs.map(f => frameOf(f)).filter(Boolean);
1054
1057
  if (map) out.forEach(f => { // the box fits its title and its badges, which are tabs on its top border, at the right
@@ -1450,7 +1453,7 @@ function layoutPass(dg, map, room, last) { // room: { x: { col: px }, y: { row:
1450
1453
  const runRouting = order => {
1451
1454
  routed.length = 0; reserved.length = 0; placed.length = 0; stats = {};
1452
1455
  (dg.blocks || []).forEach(b => { reserved.push(b); placed.push(b); });
1453
- families.forEach(f => { const h = TB ? { x: f.x + 3, y: f.y + 8, w: 22, h: headOf(f) } : { x: f.x + 8, y: f.y + 3, w: headOf(f), h: 22 }; reserved.push(h); placed.push(h);
1456
+ families.forEach(f => { const t = 22 + (!map && f.head || 0), h = TB ? { x: f.x + 3, y: f.y + 8, w: t, h: headOf(f) } : { x: f.x + 8, y: f.y + 3, w: headOf(f), h: t }; reserved.push(h); placed.push(h);
1454
1457
  placed.push(...[{ x: f.x, y: f.y - 3, w: f.w, h: 6 }, { x: f.x, y: f.y + f.h - 3, w: f.w, h: 6 }, { x: f.x - 3, y: f.y, w: 6, h: f.h }, { x: f.x + f.w - 3, y: f.y, w: 6, h: f.h }].map(r => ({ ...r, band: true }))); }); // lane headers and arrows stay clear
1455
1458
  edges.filter(e => e.fixed).forEach(e => { routed.push(e); if (e.under || e[OWN_ROUTE]) { placeLabel(e); stats[e.how] = (stats[e.how] || 0) + 1; return; } if (e.lbl) { placed.push(e.lbl); reserved.push({ x: e.lbl.x - 3, y: e.lbl.y - 3, w: e.lbl.w + 6, h: e.lbl.h + 6 }); } stats.comb = (stats.comb || 0) + 1; });
1456
1459
  order.forEach(e => {
@@ -1687,7 +1690,7 @@ function routeAudit(geo, where, only, refs) { // only: a set of edges; counts ju
1687
1690
  if (f.parent && (!parent || !inside(parent,f))) say(`${where}: family "${f.label}" sticks out of its parent`, f);
1688
1691
  (f.nodeIds || []).forEach(id => { const n = geo.byId[id]; if (n && !inside(f,n)) say(`${where}: family "${f.label}" does not contain "${n.label}"`, f, n); });
1689
1692
  families.filter(g => g !== f && g.parent === f.parent && g.id > f.id).forEach(g => { if (hit(f,g,-1)) say(`${where}: families "${f.label}" and "${g.label}" overlap`, f, g); });
1690
- geo.edges.forEach((e,i) => { if (segHit({x:f.x+8,y:f.y+3,w:Math.min(f.w-16,textW(f.label || f.id,11)+16),h:22},i)) say(`${where}: family "${f.label}": header crossed by edge ${name(e)}`, f, e); });
1693
+ geo.edges.forEach((e,i) => { if (segHit({x:f.x+8,y:f.y+3,w:Math.min(f.w-16,textW(f.label || f.id,11)+16),h:22+(!geo.map&&f.head||0)},i)) say(`${where}: family "${f.label}": header crossed by edge ${name(e)}`, f, e); });
1691
1694
  geo.edges.forEach((e,i) => { if (segs[i].some(([a,b]) => { const v = a[0] === b[0], c = v ? a[0] : a[1], p = v ? [a[1], b[1]] : [a[0], b[0]];
1692
1695
  const lo = Math.max(Math.min(...p), v ? f.y : f.x), hi = Math.min(Math.max(...p), v ? f.y + f.h : f.x + f.w);
1693
1696
  return hi - lo > 40 && (v ? [f.x, f.x + f.w] : [f.y, f.y + f.h]).some(u => Math.abs(c - u) < 8); })) say(`${where}: edge ${name(e)} runs along the border of family "${f.label}"`, e, f); });
@@ -1702,7 +1705,7 @@ const box = n => ({ x: n.x, y: n.y, w: n.w, h: n.h });
1702
1705
  function overlapIssues(geo, where, refs) {
1703
1706
  const issues = [], nodes = geo.nodes, say = teller(issues, refs);
1704
1707
  const inside = (a, b) => a.x >= b.x - 1 && a.y >= b.y - 1 && a.x + a.w <= b.x + b.w + 1 && a.y + a.h <= b.y + b.h + 1;
1705
- const holds = (a, b) => (a.holder && inside(b, a)) || (b.holder && inside(a, b)); // a holder (a sequence's frame) may hold what it meets, not cross it
1708
+ const holds = (a, b) => (a.holder && inside(b, a)) || (b.holder && inside(a, b)) || !geo.map && ((a.owner || 0) === b.id || (b.owner || 0) === a.id); // a holder (a sequence's frame) may hold what it meets, not cross it; a port its owner
1706
1709
  for (let i = 0; i < nodes.length; i++) for (let j = i + 1; j < nodes.length; j++) if (hit(box(nodes[i]), box(nodes[j]), -1) && !holds(nodes[i], nodes[j])) say(`${where}: nodes "${nodes[i].label}" and "${nodes[j].label}" overlap`, nodes[i], nodes[j]);
1707
1710
  return issues;
1708
1711
  }
@@ -2614,9 +2617,10 @@ export function validate(model) {
2614
2617
  out.push(...typedProblems(m).filter(p => !(p.level === 'error' && said.has(p.path))));
2615
2618
  views.forEach((v, i) => { const at = `views[${i}].diagram`; // a well-formed name of a type this release does not draw (M13)
2616
2619
  if (typedView(v) && !diagramOf(v) && !out.some(p => p.path === at)) warn(at, `diagram "${v.diagram}" is not drawn by this release: its nodes are drawn as plain cards`); });
2617
- const once = new Set(); // each view's type's rules, a problem once; a validate(model) that takes no view, once a type
2618
- views.filter(typedView).forEach(v => { const T = diagramOf(v); if (!T || !T.validate || once.has(T)) return; if (T.validate.length < 2) once.add(T);
2619
- T.validate(m, v).forEach(p => { const k = JSON.stringify([p.level, p.path, p.message]); if (!once.has(k)) { once.add(k); out.push(p); } }); });
2620
+ const once = new Set(), say = p => { const k = JSON.stringify([p.level, p.path, p.message]); if (!once.has(k)) { once.add(k); out.push(p); } };
2621
+ // each view's type's rules, a problem once; a validate(model) that takes no view, once a type
2622
+ views.filter(typedView).forEach(v => { const T = diagramOf(v); if (!T || !T.validate || once.has(T)) return; if (T.validate.length < 2) once.add(T); T.validate(m, v).forEach(say); });
2623
+ if (TYPED.across) arrOf(TYPED.across(m)).forEach(say);
2620
2624
  }
2621
2625
  return out;
2622
2626
  }
@@ -2773,14 +2777,16 @@ export function diff(before, after) {
2773
2777
  if (h === 'removed') said.push(`removes ${name(n.id)}`);
2774
2778
  if (h === 'changed') { const [o, x] = was.get(n), keys = diffKeys([o, x]), rest = keys.filter(k => k !== 'label'), p0 = o.parent ?? null, p1 = x.parent ?? null;
2775
2779
  if (keys.join() === 'parent' && p0 !== p1 && A.schemaVersion === 2 && out.schemaVersion === 2) return said.push(`moves ${name(n.id)} ${p1 != null ? 'into ' + name(p1) : 'out of ' + name(p0)}`); // a re-own (schema version 2; absent or null is no owner)
2780
+ const t = TYPED.diff && TYPED.diff(o, x, name, [A, out]); if (t) return said.push(...t); // a typed element's own words (src/uml/diff.js)
2776
2781
  said.push((keys.includes('label') ? `renames ${o.label || o.id} to ${x.label || x.id}` : `changes ${name(n.id)}`) + (rest.length ? ` (${rest.join(', ')})` : '')); } });
2777
2782
  lines.forEach(e => { const h = how.get(e); if (!h || cardHow.get(e.from) === h && h !== 'changed' || cardHow.get(e.to) === h && h !== 'changed') return;
2778
2783
  const ends = `${name(e.from)} to ${name(e.to)}`, lab = e.label ? ` (${e.label})` : '';
2779
2784
  if (h === 'added') said.push(`adds a line from ${ends}${lab}`);
2780
2785
  if (h === 'removed') said.push(`removes the line from ${ends}${lab}`);
2781
- if (h === 'changed') { const [o, x] = was.get(e);
2786
+ if (h === 'changed') { const [o, x] = was.get(e), t = TYPED.diff && TYPED.diff(o, x, name, [A, out]); if (t) return said.push(...t);
2782
2787
  said.push(`changes the line from ${ends} (${diffKeys([o, x]).map(k => k === 'label' ? `label ${o.label ?? '-'} → ${x.label ?? '-'}` : k).join(', ')})`); } });
2783
2788
  moved.forEach(([verb, id, v]) => said.push(`${verb} ${name(id)} ${verb === 'puts' ? 'in' : 'out of'} the view ${v.title || v.id}`));
2789
+ if (TYPED.order) TYPED.order(A, out, views, V0, said, touched, name);
2784
2790
 
2785
2791
  // the views that show a change: a card or line the diff marks, or a card it put in or took out
2786
2792
  const changed = views.filter(v => v && (touched.has(v.id) || arr(v.nodeIds).some(id => cardHow.has(id)) || linesOf(out, v).some(e => how.has(e)))).map(v => v.id);
@@ -2834,9 +2840,11 @@ const walkFrom = (edges, start, back) => { const seen = new Set([start]); // bre
2834
2840
  for (let q = [start]; q.length;) { const u = q.shift(); edges.forEach(e => { const [a, b] = back ? [e.to, e.from] : [e.from, e.to]; if (a === u && !seen.has(b)) { seen.add(b); q.push(b); } }); }
2835
2841
  return seen; };
2836
2842
 
2843
+ const viewType = (model, viewId) => model && model.schemaVersion === 2 && diagramOf(arrOf(model.views).find(v => v && v.id === viewId));
2837
2844
  /** Every card and line on a path from one card to another, following lines forward: the cards both reachable from `from`
2838
2845
  * and leading to `to`, and the lines between them. [] when no path joins them. */
2839
2846
  export function paths(model, viewId, from, to) {
2847
+ const T = viewType(model, viewId); if (T && T.paths) return T.paths(model, viewId, from, to); // a type's own walk (a sequence's, in time)
2840
2848
  const { ids, edges } = lineGraph(model, viewId);
2841
2849
  if (!ids.includes(from) || !ids.includes(to)) return [];
2842
2850
  const F = walkFrom(edges, from), B = walkFrom(edges, to, true), on = id => F.has(id) && B.has(id);
@@ -2861,7 +2869,7 @@ export function reach(model, viewId, from, options = {}) {
2861
2869
  /** A view in plain sentences: its cards and their kinds, its boxes, what each card's lines do (in run order on a sequence
2862
2870
  * view), and the cards with no line. The same model gives the same words: a text alternative, docs, or an AI's context. */
2863
2871
  export function describe(model, viewId) {
2864
- const T = model && model.schemaVersion === 2 && diagramOf(arrOf(model.views).find(v => v && v.id === viewId)); if (T && T.describe) return T.describe(model, viewId); // a type's own words (1.9)
2872
+ const T = viewType(model, viewId); if (T && T.describe) return T.describe(model, viewId); // a type's own words (1.9)
2865
2873
  const { ctx, v, ids, edges } = lineGraph(model, viewId), boxes = (v.containers || []).filter(c => c && c.id);
2866
2874
  const name = id => ctx.N[id] ? ctx.nodeIn(id, viewId).label || id : (boxes.find(c => c.id === id) || {}).label || id;
2867
2875
  const list = xs => xs.length < 3 ? xs.join(' and ') : xs.slice(0, -1).join(', ') + ' and ' + xs[xs.length - 1];
@@ -3642,7 +3650,7 @@ function typedEditor(api) {
3642
3650
  function props() {
3643
3651
  const at = elementsOf(model()), id = selId(at), e = id && at.get(id);
3644
3652
  if (!e) return '<h3>Properties</h3><p class="um-note">Select a card or a line</p>';
3645
- const x = e.x, P = isRec(x.props) ? x.props : {}, schema = arrOf(isRec(def().props) ? def().props[x.type] : null).filter(f => isRec(f) && typeof f.key === 'string');
3653
+ const x = e.x, P = isRec(x.props) ? x.props : {}, F = a => arrOf(a).filter(f => isRec(f) && typeof f.key === 'string'), own = F(isRec(def().props) ? def().props[x.type] : null), schema = [...own, ...F(TYPED.fields && TYPED.fields(model(), x))];
3646
3654
  const off = can('rename') ? '' : ' disabled'; // the editable flags: a field the host does not offer is shown, to read
3647
3655
  const text = (f, v, name, more = '') => `<label>${esc(name)}<input data-f="${esc(f)}" data-was="${esc(v)}" value="${esc(v)}"${more}${off}></label>`;
3648
3656
  let h = `<h3>Properties${x.type != null ? ': ' + esc(x.type) : ''}</h3>` + text('label', x.label ?? '', 'Name');
@@ -3657,7 +3665,7 @@ function typedEditor(api) {
3657
3665
  const offer = Array.isArray(os) && [{ id: '', label: 'none' }, ...os.filter(o => isRec(o) && o.id != null && !under(o.id))];
3658
3666
  if (offer && x.parent != null && !offer.some(o => o.id === x.parent)) offer.push({ id: x.parent, label: (at.get(x.parent) || { x: {} }).x.label });
3659
3667
  if (offer) h += `<label>Owner<select data-f="owner" data-owner${can('move') ? '' : ' disabled'}>${offer.map(o => `<option value="${esc(o.id)}"${o.id === (x.parent ?? '') ? ' selected' : ''}>${esc(o.label ?? o.id)}</option>`).join('')}</select></label>`;
3660
- const rest = schema.length ? [] : Object.entries(P); // no schema: what it holds, to read
3668
+ const rest = own.length ? [] : Object.entries(P); // no schema: what it holds, to read
3661
3669
  if (rest.length) h += '<dl>' + rest.map(([k, v]) => `<dt>${esc(k)}</dt><dd>${esc(typeof v === 'string' ? v : JSON.stringify(v))}</dd>`).join('') + '</dl>';
3662
3670
  const M = def().member;
3663
3671
  if (e.kind === 'node' && !(M && M.holds && !M.holds(x))) { // a comment holds none
@@ -3843,7 +3851,7 @@ export function render(container, model, options = {}) {
3843
3851
  const emitSel = (again = false) => {
3844
3852
  const now = JSON.stringify(picked()); if (now === said && !again) return; said = now;
3845
3853
  say(!sel ? 'Nothing selected' : (sel.type === 'node' ? nameOf(sel.id) : sel.type === 'edge' ? (e => e ? `Line from ${nameOf(e.from)} to ${nameOf(e.to)}` : 'Line')(geo.edges[edgeIndex(sel)])
3846
- : `Box ${(svg.querySelector(`.family[data-family="${CSS.escape(sel.id)}"] .family-title`) || {}).textContent || sel.id}`) + (more.length ? `, ${more.length + 1} ${picked().every(r => r.type === 'node') ? 'cards ' : ''}selected` : ', selected'));
3854
+ : `Box ${[...svg.querySelectorAll(`.family[data-family="${CSS.escape(sel.id)}"] .family-title`)].map(t => t.textContent).join(' ') || sel.id}`) + (more.length ? `, ${more.length + 1} ${picked().every(r => r.type === 'node') ? 'cards ' : ''}selected` : ', selected'));
3847
3855
  emit('select', { target: copyRef(sel), targets: picked() });
3848
3856
  };
3849
3857
  const edgeRef = e => ({ type: 'edge', ids: edgeRefIds(e), view: cur });
@@ -4288,7 +4296,7 @@ export function render(container, model, options = {}) {
4288
4296
  if (ref.type === 'node') { const n = geo.byId[ref.id]; return n ? { x: n.x + 50, y: n.y + n.h / 2 - 13, w: n.w - 58, h: 26 } : null; }
4289
4297
  if (ref.type === 'edge') { const e = geo.edges[edgeIndex(ref)]; if (!e) return null; const L = e.lbl, m = e.pts[Math.floor(e.pts.length / 2)];
4290
4298
  return L ? { x: L.x - 8, y: L.y - 2, w: L.w + 16, h: L.h + 4 } : { x: m[0] - 60, y: m[1] - 12, w: 120, h: 24 }; }
4291
- const f = ref.type === 'container' && (geo.families || []).find(x => x.id === ref.id); return f ? { x: f.x + 8, y: f.y + 2, w: Math.min(f.w - 16, 220), h: 24 } : null; };
4299
+ const f = ref.type === 'container' && (geo.families || []).find(x => x.id === ref.id); return f ? { x: f.x + 8, y: f.y + 2 + (f.head || 0), w: Math.min(f.w - 16, 220), h: 24 } : null; };
4292
4300
  function editor(where, text, done, ref = null) { // where: a box in map units (a new card's), or ref names what the field sits over
4293
4301
  if (naming) naming.close(false);
4294
4302
  const inp = document.createElement('input');
@@ -411,7 +411,7 @@
411
411
  }
412
412
  },
413
413
  "type": {
414
- "description": "Schema version 2: the element's type, <notation>.<Name> (uml.Class). validate() checks typed fields only in a model with schemaVersion 2. The class diagram (uml.class, 0.18.0): uml.Class, uml.Interface, uml.Enumeration, uml.DataType, uml.PrimitiveType, uml.Package and uml.Comment; their members uml.Property, uml.Operation and uml.EnumerationLiteral. The object diagram (uml.object, 0.19.0): uml.InstanceSpecification and uml.Comment; an instance's members uml.Slot. The package diagram (uml.package, 0.19.0): uml.Package and the class diagram's classifiers, and uml.Comment. The sequence and communication diagrams (uml.sequence, uml.communication, 0.20.0): uml.Lifeline. The use case diagram (uml.use-case, 0.21.0): uml.Actor, uml.UseCase, uml.Subject and uml.Comment; a use case's members uml.ExtensionPoint. The activity diagram (uml.activity, 0.21.0): uml.InitialNode, uml.ActivityFinalNode, uml.FlowFinalNode, uml.Action, uml.CallBehaviorAction, uml.SendSignalAction, uml.AcceptEventAction, uml.DecisionNode, uml.MergeNode, uml.ForkNode, uml.JoinNode, uml.ObjectNode, uml.DataStoreNode, uml.ActivityPartition and uml.Comment. The state machine diagram (uml.state-machine, 0.21.0): uml.State, uml.Pseudostate, uml.FinalState and uml.Comment; a state's members uml.Region and uml.InternalTransition. The interaction overview diagram (uml.interaction-overview, 0.21.0): the activity's control nodes, uml.InteractionUse, uml.Interaction (an inline interaction) and uml.Comment.",
414
+ "description": "Schema version 2: the element's type, <notation>.<Name> (uml.Class). validate() checks typed fields only in a model with schemaVersion 2. The class diagram (uml.class, 0.18.0): uml.Class, uml.Interface, uml.Enumeration, uml.DataType, uml.PrimitiveType, uml.Package and uml.Comment; their members uml.Property, uml.Operation and uml.EnumerationLiteral. The object diagram (uml.object, 0.19.0): uml.InstanceSpecification and uml.Comment; an instance's members uml.Slot. The package diagram (uml.package, 0.19.0): uml.Package and the class diagram's classifiers, and uml.Comment. The sequence and communication diagrams (uml.sequence, uml.communication, 0.20.0): uml.Lifeline. The use case diagram (uml.use-case, 0.21.0): uml.Actor, uml.UseCase, uml.Subject and uml.Comment; a use case's members uml.ExtensionPoint. The activity diagram (uml.activity, 0.21.0): uml.InitialNode, uml.ActivityFinalNode, uml.FlowFinalNode, uml.Action, uml.CallBehaviorAction, uml.SendSignalAction, uml.AcceptEventAction, uml.DecisionNode, uml.MergeNode, uml.ForkNode, uml.JoinNode, uml.ObjectNode, uml.DataStoreNode, uml.ActivityPartition and uml.Comment. The state machine diagram (uml.state-machine, 0.21.0): uml.State, uml.Pseudostate, uml.FinalState and uml.Comment; a state's members uml.Region and uml.InternalTransition. The interaction overview diagram (uml.interaction-overview, 0.21.0): the activity's control nodes, uml.InteractionUse, uml.Interaction (an inline interaction) and uml.Comment. The component diagram (uml.component, 0.22.0): uml.Component, uml.Interface, uml.Artifact, uml.Package and uml.Comment; a component's (or class's) members uml.Port. The deployment diagram (uml.deployment, 0.22.0): uml.Node, uml.Device, uml.ExecutionEnvironment, uml.Artifact, uml.DeploymentSpecification, uml.Component and uml.Comment. The composite structure diagram (uml.composite-structure, 0.22.0): the view's subject (a uml.Class, uml.Component or uml.Collaboration), uml.Collaboration, uml.CollaborationUse and uml.Comment; the subject's members uml.Property (its parts) and uml.Port, a collaboration's uml.Property (its roles).",
415
415
  "examples": [
416
416
  "uml.Class",
417
417
  "uml.Interface",
@@ -432,14 +432,22 @@
432
432
  "uml.Pseudostate",
433
433
  "uml.FinalState",
434
434
  "uml.InteractionUse",
435
- "uml.Interaction"
435
+ "uml.Interaction",
436
+ "uml.Component",
437
+ "uml.Artifact",
438
+ "uml.Node",
439
+ "uml.Device",
440
+ "uml.ExecutionEnvironment",
441
+ "uml.DeploymentSpecification",
442
+ "uml.Collaboration",
443
+ "uml.CollaborationUse"
436
444
  ]
437
445
  },
438
446
  "parent": {
439
- "description": "Schema version 2: the element that owns it (a package, a composite state, a lane). From 0.19.0 a class, object or package view draws a shown package that owns something it shows as a box holding it. A use case's: a subject or a package. An activity node's: its partition (lane); a partition's: the partition it is nested in. A substate's or pseudostate's: a state, or a region (a member) of one."
447
+ "description": "Schema version 2: the element that owns it (a package, a composite state, a lane). From 0.19.0 a class, object or package view draws a shown package that owns something it shows as a box holding it. A use case's: a subject or a package. An activity node's: its partition (lane); a partition's: the partition it is nested in. A substate's or pseudostate's: a state, or a region (a member) of one. A component's: a component (drawn nested) or a package. A node's, device's or execution environment's: one of the three (UML's nestedNode); an artifact's or deployment specification's: the target it is deployed on. A collaboration use's: the subject of its composite structure view (0.22.0)."
440
448
  },
441
449
  "props": {
442
- "description": "Schema version 2: the type's own properties. The class diagram (uml.class, 0.18.0): isAbstract and stereotypes on a classifier; on a member, the fields of its UML text (docs/conformance/uml-class.md). The object diagram (uml.object, 0.19.0): an instance's classifier and stereotypes; a slot's value (docs/conformance/uml-object.md). The sequence and communication diagrams (uml.sequence, uml.communication, 0.20.0): a lifeline's represents, and stereotypes (actor draws «actor» over its name). The state machine diagram (uml.state-machine, 0.21.0): a state's entry, do and exit, a pseudostate's kind (docs/conformance/uml-state-machine.md).",
450
+ "description": "Schema version 2: the type's own properties. The class diagram (uml.class, 0.18.0): isAbstract and stereotypes on a classifier; on a member, the fields of its UML text (docs/conformance/uml-class.md). The object diagram (uml.object, 0.19.0): an instance's classifier and stereotypes; a slot's value (docs/conformance/uml-object.md). The sequence and communication diagrams (uml.sequence, uml.communication, 0.20.0): a lifeline's represents, and stereotypes (actor draws «actor» over its name). The state machine diagram (uml.state-machine, 0.21.0): a state's entry, do and exit, a pseudostate's kind (docs/conformance/uml-state-machine.md). The composite structure diagram (uml.composite-structure, 0.22.0): a collaboration use's collaboration (docs/conformance/uml-composite-structure.md).",
443
451
  "anyOf": [
444
452
  {
445
453
  "type": "object",
@@ -477,6 +485,9 @@
477
485
  "deepHistory",
478
486
  "terminate"
479
487
  ]
488
+ },
489
+ "collaboration": {
490
+ "description": "uml.CollaborationUse: the collaboration it uses, by label, as text; drawn name : Collaboration."
480
491
  }
481
492
  }
482
493
  },
@@ -484,7 +495,7 @@
484
495
  ]
485
496
  },
486
497
  "members": {
487
- "description": "Schema version 2: owned parts, in display order (attributes, ports, regions, lanes), each a typed element. The class diagram (uml.class, 0.18.0): a classifier's attributes (uml.Property) and operations (uml.Operation), an enumeration's literals (uml.EnumerationLiteral). The object diagram (uml.object, 0.19.0): an instance's slots (uml.Slot), each a feature = value row. The use case diagram (uml.use-case, 0.21.0): a use case's extension points (uml.ExtensionPoint, by name). The state machine diagram (uml.state-machine, 0.21.0): a state's regions (uml.Region, by name) and internal transitions (uml.InternalTransition, trigger [guard] / effect).",
498
+ "description": "Schema version 2: owned parts, in display order (attributes, ports, regions, lanes), each a typed element. The class diagram (uml.class, 0.18.0): a classifier's attributes (uml.Property) and operations (uml.Operation), an enumeration's literals (uml.EnumerationLiteral). The object diagram (uml.object, 0.19.0): an instance's slots (uml.Slot), each a feature = value row. The use case diagram (uml.use-case, 0.21.0): a use case's extension points (uml.ExtensionPoint, by name). The state machine diagram (uml.state-machine, 0.21.0): a state's regions (uml.Region, by name) and internal transitions (uml.InternalTransition, trigger [guard] / effect). The component diagram (uml.component, 0.22.0): a component's or class's ports (uml.Port), drawn on its border. The composite structure diagram (uml.composite-structure, 0.22.0): the subject's parts (uml.Property, name : Type [multiplicity]) and ports (uml.Port); a collaboration's roles (uml.Property).",
488
499
  "anyOf": [
489
500
  {
490
501
  "type": "array",
@@ -498,7 +509,7 @@
498
509
  "description": "Unique among every node, edge and member of the model."
499
510
  },
500
511
  "type": {
501
- "description": "uml.Property, uml.Operation or uml.EnumerationLiteral in a class diagram; uml.Slot in an object diagram. uml.ExtensionPoint in a use case diagram; uml.Region or uml.InternalTransition in a state machine diagram."
512
+ "description": "uml.Property, uml.Operation or uml.EnumerationLiteral in a class diagram; uml.Slot in an object diagram. uml.ExtensionPoint in a use case diagram; uml.Region or uml.InternalTransition in a state machine diagram. uml.Port on a component or class (component and composite structure diagrams); uml.Property as a part or a role in a composite structure diagram (0.22.0)."
502
513
  },
503
514
  "label": {
504
515
  "description": "The member's name (a slot's: the feature it gives a value); the rest of its UML text is in props."
@@ -519,7 +530,7 @@
519
530
  "description": "uml.Property, uml.Operation: public, private, protected or package (+ - # ~)."
520
531
  },
521
532
  "valueType": {
522
- "description": "uml.Property, and each of an operation's parameters: its type, as text (Money, String[], Map<K, V>)."
533
+ "description": "uml.Property, and each of an operation's parameters: its type, as text (Money, String[], Map<K, V>). uml.Port: its type, drawn name : Type beside it (0.22.0). A part's or role's: the class or component it is, by label (a part shows that type's ports)."
523
534
  },
524
535
  "multiplicity": {
525
536
  "description": "uml.Property: 1, *, n..m or n..* (0..1, 1..*), kept as written."
@@ -550,6 +561,13 @@
550
561
  },
551
562
  "effect": {
552
563
  "description": "uml.InternalTransition: its effect, as text, drawn after /."
564
+ },
565
+ "aggregation": {
566
+ "description": "uml.Property as a part (composite structure, 0.22.0): composite (the default) or shared, drawn dashed.",
567
+ "examples": [
568
+ "composite",
569
+ "shared"
570
+ ]
553
571
  }
554
572
  }
555
573
  },
@@ -852,7 +870,7 @@
852
870
  "description": "When the line is used."
853
871
  },
854
872
  "type": {
855
- "description": "Schema version 2: the element's type, <notation>.<Name> (uml.Class). The class diagram (uml.class, 0.18.0): uml.Association, uml.Generalization (from the specific to the general), uml.InterfaceRealization (to the interface), uml.Dependency (from the client) and uml.CommentLink (from the comment). The object diagram (uml.object, 0.19.0): uml.Link and uml.CommentLink. The package diagram (uml.package, 0.19.0): uml.PackageImport and uml.PackageMerge (from the importing or merging package), uml.Dependency and uml.CommentLink. The sequence diagram (uml.sequence, 0.20.0): uml.Message, inline in its view's edges, in time order. The communication diagram (uml.communication, 0.20.0): uml.Connector and uml.Message, model lines its view lists, connectors first; only the messages' order means anything. The use case diagram (uml.use-case, 0.21.0): uml.Association (an actor and a use case), uml.Include and uml.Extend (from the including or extending use case), uml.Generalization (from the specific to the general) and uml.CommentLink. The activity diagram (uml.activity, 0.21.0): uml.ControlFlow, uml.ObjectFlow and uml.CommentLink. The state machine diagram (uml.state-machine, 0.21.0): uml.Transition and uml.CommentLink. The interaction overview diagram (uml.interaction-overview, 0.21.0): uml.ControlFlow and uml.CommentLink.",
873
+ "description": "Schema version 2: the element's type, <notation>.<Name> (uml.Class). The class diagram (uml.class, 0.18.0): uml.Association, uml.Generalization (from the specific to the general), uml.InterfaceRealization (to the interface), uml.Dependency (from the client) and uml.CommentLink (from the comment). The object diagram (uml.object, 0.19.0): uml.Link and uml.CommentLink. The package diagram (uml.package, 0.19.0): uml.PackageImport and uml.PackageMerge (from the importing or merging package), uml.Dependency and uml.CommentLink. The sequence diagram (uml.sequence, 0.20.0): uml.Message, inline in its view's edges, in time order. The communication diagram (uml.communication, 0.20.0): uml.Connector and uml.Message, model lines its view lists, connectors first; only the messages' order means anything. The use case diagram (uml.use-case, 0.21.0): uml.Association (an actor and a use case), uml.Include and uml.Extend (from the including or extending use case), uml.Generalization (from the specific to the general) and uml.CommentLink. The activity diagram (uml.activity, 0.21.0): uml.ControlFlow, uml.ObjectFlow and uml.CommentLink. The state machine diagram (uml.state-machine, 0.21.0): uml.Transition and uml.CommentLink. The interaction overview diagram (uml.interaction-overview, 0.21.0): uml.ControlFlow and uml.CommentLink. The component diagram (uml.component, 0.22.0): uml.InterfaceRealization (from a component, a class or a port to the interface: a plain stem to a ball), uml.Usage (to the interface: a socket at a ball, else a dashed «use» arrow), uml.ComponentRealization (from the realizing classifier to the component), uml.Connector (props.kind assembly or delegation; from or to a port), uml.Dependency, uml.Manifestation (from an artifact) and uml.CommentLink. The deployment diagram (uml.deployment, 0.22.0): uml.Deployment (from an artifact or deployment specification to its target), uml.Manifestation, uml.CommunicationPath (between two targets), uml.Dependency and uml.CommentLink. The composite structure diagram (uml.composite-structure, 0.22.0): uml.Connector (between parts and ports; an end through a part keeps props.ends.<end>.part), uml.RoleBinding (from a part to a collaboration use; its label the role) and uml.CommentLink.",
856
874
  "examples": [
857
875
  "uml.Association",
858
876
  "uml.Generalization",
@@ -868,20 +886,26 @@
868
886
  "uml.Extend",
869
887
  "uml.ControlFlow",
870
888
  "uml.ObjectFlow",
871
- "uml.Transition"
889
+ "uml.Transition",
890
+ "uml.Usage",
891
+ "uml.ComponentRealization",
892
+ "uml.Manifestation",
893
+ "uml.Deployment",
894
+ "uml.CommunicationPath",
895
+ "uml.RoleBinding"
872
896
  ]
873
897
  },
874
898
  "parent": {
875
899
  "description": "Schema version 2: the element that owns it (a package, a composite state, a lane). In a sequence view: the operand (uml.InteractionOperand) of one of its fragments that holds the message; none at the top level."
876
900
  },
877
901
  "props": {
878
- "description": "Schema version 2: the type's own properties. The class diagram (uml.class, 0.18.0): an association's ends, and stereotypes on any line («use» on a dependency). The object diagram (uml.object, 0.19.0): a link's association and the roles at its ends. The package diagram (uml.package, 0.19.0): a package import's visibility. The sequence and communication diagrams (0.20.0): a message's sort and replyTo. The use case diagram (0.21.0): an extend's extensionPoints and condition. The activity and interaction overview diagrams (0.21.0): a flow's guard (its label is its name). The state machine diagram (0.21.0): a transition's trigger, guard and effect, drawn trigger [guard] / effect.",
902
+ "description": "Schema version 2: the type's own properties. The class diagram (uml.class, 0.18.0): an association's ends, and stereotypes on any line («use» on a dependency). The object diagram (uml.object, 0.19.0): a link's association and the roles at its ends. The package diagram (uml.package, 0.19.0): a package import's visibility. The sequence and communication diagrams (0.20.0): a message's sort and replyTo. The use case diagram (0.21.0): an extend's extensionPoints and condition. The activity and interaction overview diagrams (0.21.0): a flow's guard (its label is its name). The state machine diagram (0.21.0): a transition's trigger, guard and effect, drawn trigger [guard] / effect. The component diagram (0.22.0): a connector's kind (assembly or delegation). The composite structure diagram (0.22.0): a connector end's part (ends.from.part, ends.to.part), UML's partWithPort.",
879
903
  "anyOf": [
880
904
  {
881
905
  "type": "object",
882
906
  "properties": {
883
907
  "ends": {
884
- "description": "uml.Association: { from, to }, each end's role, multiplicity, aggregation and navigability. uml.Link: each end's role.",
908
+ "description": "uml.Association: { from, to }, each end's role, multiplicity, aggregation and navigability. uml.Link: each end's role. uml.Connector (composite structure, 0.22.0): an end through a part, { part }: the end (from or to) is a port of the part's type, reached through that part.",
885
909
  "anyOf": [
886
910
  {
887
911
  "type": "object",
@@ -903,6 +927,9 @@
903
927
  },
904
928
  "navigable": {
905
929
  "description": "true draws an open arrowhead at this end."
930
+ },
931
+ "part": {
932
+ "description": "uml.Connector (composite structure, 0.22.0): the part (a member id of the subject) this end's port is reached through."
906
933
  }
907
934
  }
908
935
  },
@@ -926,6 +953,9 @@
926
953
  },
927
954
  "navigable": {
928
955
  "description": "true draws an open arrowhead at this end."
956
+ },
957
+ "part": {
958
+ "description": "uml.Connector (composite structure, 0.22.0): the part (a member id of the subject) this end's port is reached through."
929
959
  }
930
960
  }
931
961
  },
@@ -973,6 +1003,13 @@
973
1003
  },
974
1004
  "effect": {
975
1005
  "description": "uml.Transition: its effect, as text, drawn after /."
1006
+ },
1007
+ "kind": {
1008
+ "description": "uml.Connector in a component diagram (0.22.0): assembly (two components or their ports, neither inside the other) or delegation (a component's port and something inside it; an open arrow at its to end). Left out: an assembly.",
1009
+ "examples": [
1010
+ "assembly",
1011
+ "delegation"
1012
+ ]
976
1013
  }
977
1014
  }
978
1015
  },
@@ -1254,7 +1291,7 @@
1254
1291
  "description": "Guess a line's kind from its label's words when its edges name none (render() and layout(); the standalone page always does)."
1255
1292
  },
1256
1293
  "diagram": {
1257
- "description": "Schema version 2: the view's diagram type; without it the view is a map. uml.class draws a class diagram (0.18.0, lib/umlimator-all.js), uml.object an object diagram and uml.package a package diagram (0.19.0), uml.sequence a sequence diagram and uml.communication a communication diagram (0.20.0), uml.use-case a use case diagram, uml.activity an activity diagram, uml.state-machine a state machine diagram and uml.interaction-overview an interaction overview diagram (0.21.0); a type this release does not draw is drawn as plain cards, with a warning.",
1294
+ "description": "Schema version 2: the view's diagram type; without it the view is a map. uml.class draws a class diagram (0.18.0, lib/umlimator-all.js), uml.object an object diagram and uml.package a package diagram (0.19.0), uml.sequence a sequence diagram and uml.communication a communication diagram (0.20.0), uml.use-case a use case diagram, uml.activity an activity diagram, uml.state-machine a state machine diagram and uml.interaction-overview an interaction overview diagram (0.21.0), uml.component a component diagram, uml.deployment a deployment diagram and uml.composite-structure a composite structure diagram (0.22.0); a type this release does not draw is drawn as plain cards, with a warning.",
1258
1295
  "examples": [
1259
1296
  "uml.class",
1260
1297
  "uml.object",
@@ -1264,11 +1301,14 @@
1264
1301
  "uml.use-case",
1265
1302
  "uml.activity",
1266
1303
  "uml.state-machine",
1267
- "uml.interaction-overview"
1304
+ "uml.interaction-overview",
1305
+ "uml.component",
1306
+ "uml.deployment",
1307
+ "uml.composite-structure"
1268
1308
  ]
1269
1309
  },
1270
1310
  "subject": {
1271
- "description": "Schema version 2: the element this diagram is the inside of. In a class, object or package view, the package names are qualified from (sales::Order without sales:: in a view of sales); not drawn unless the view lists it."
1311
+ "description": "Schema version 2: the element this diagram is the inside of. In a class, object or package view, the package names are qualified from (sales::Order without sales:: in a view of sales); not drawn unless the view lists it. In a composite structure view (0.22.0): the class, component or collaboration whose parts and ports it draws, listed in nodeIds."
1272
1312
  },
1273
1313
  "direction": {
1274
1314
  "description": "Schema version 2: a typed view's layout direction (default right). A map stays left to right. A sequence view is always down; another direction is a warning."
@@ -1277,7 +1317,7 @@
1277
1317
  "description": "Schema version 2: a skin of the diagram type (crowsfoot for er)."
1278
1318
  },
1279
1319
  "present": {
1280
- "description": "Schema version 2: what the layout cannot derive, per element: collapsed compartments, rows shown before +n more.",
1320
+ "description": "Schema version 2: what the layout cannot derive, per element: collapsed compartments, rows shown before +n more. A component view's interface drawn as a ball (as: 'ball'), and a port's side (side); a port on a part, by the part's id: ports.<port>.side (0.22.0).",
1281
1321
  "anyOf": [
1282
1322
  {
1283
1323
  "type": "object",
@@ -1292,6 +1332,24 @@
1292
1332
  },
1293
1333
  "rows": {
1294
1334
  "description": "At most this many rows in each compartment, then \"+k more\"."
1335
+ },
1336
+ "as": {
1337
+ "description": "uml.Interface in a component view (0.22.0): 'ball' draws it as a ball (a 16 px circle); left out, a rectangle with «interface».",
1338
+ "examples": [
1339
+ "ball"
1340
+ ]
1341
+ },
1342
+ "side": {
1343
+ "description": "uml.Port (0.22.0): the side of its owner it is drawn on; left out, the side facing most of its lines.",
1344
+ "examples": [
1345
+ "left",
1346
+ "right",
1347
+ "top",
1348
+ "bottom"
1349
+ ]
1350
+ },
1351
+ "ports": {
1352
+ "description": "A part in a composite structure view (0.22.0): by port id, { side }, the side of the part each of its type's ports is drawn on."
1295
1353
  }
1296
1354
  }
1297
1355
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umlimator",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Embeddable, layered architecture maps: layout, orthogonal routing and an interactive canvas in one ES module.",
5
5
  "keywords": ["architecture", "diagram", "c4", "map", "svg", "layout", "orthogonal-routing", "drill-down"],
6
6
  "homepage": "https://zintaen.github.io/umlimator/",