@diagrammo/dgmo 0.36.0 → 0.37.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/advanced.js CHANGED
@@ -16730,6 +16730,7 @@ function parseInfra(content) {
16730
16730
  let currentGroup = null;
16731
16731
  let currentTagGroup = null;
16732
16732
  let baseIndent = 0;
16733
+ let firstLineConsumed = false;
16733
16734
  function finishCurrentNode() {
16734
16735
  if (!currentNode) return;
16735
16736
  const key = currentNode.id;
@@ -16737,7 +16738,8 @@ function parseInfra(content) {
16737
16738
  if (existing) {
16738
16739
  const incomingDisplay = displayName(currentNode.label);
16739
16740
  const existingDisplay = displayName(existing.label);
16740
- if (incomingDisplay !== existingDisplay) {
16741
+ const isAliasRef = nameAliasMap.get(currentNode.label) === key;
16742
+ if (incomingDisplay !== existingDisplay && !isAliasRef) {
16741
16743
  result.diagnostics.push(
16742
16744
  makeDgmoError(
16743
16745
  currentNode.lineNumber,
@@ -16803,19 +16805,22 @@ function parseInfra(content) {
16803
16805
  if (indent === 0 && currentNode && !trimmed.startsWith("-")) {
16804
16806
  finishCurrentNode();
16805
16807
  }
16806
- const firstLineResult = parseFirstLine(trimmed);
16807
- if (firstLineResult) {
16808
- if (firstLineResult.chartType !== "infra") {
16809
- setError(
16810
- lineNumber,
16811
- `Expected chart type 'infra', got '${firstLineResult.chartType}'`
16812
- );
16813
- }
16814
- if (firstLineResult.title) {
16815
- result.title = firstLineResult.title;
16816
- result.titleLineNumber = lineNumber;
16808
+ if (!firstLineConsumed) {
16809
+ firstLineConsumed = true;
16810
+ const firstLineResult = parseFirstLine(trimmed);
16811
+ if (firstLineResult) {
16812
+ if (firstLineResult.chartType !== "infra") {
16813
+ setError(
16814
+ lineNumber,
16815
+ `Expected chart type 'infra', got '${firstLineResult.chartType}'`
16816
+ );
16817
+ }
16818
+ if (firstLineResult.title) {
16819
+ result.title = firstLineResult.title;
16820
+ result.titleLineNumber = lineNumber;
16821
+ }
16822
+ continue;
16817
16823
  }
16818
- continue;
16819
16824
  }
16820
16825
  if (/^direction-tb$/i.test(trimmed)) {
16821
16826
  result.direction = "TB";
@@ -16881,18 +16886,20 @@ function parseInfra(content) {
16881
16886
  if (compMatch) {
16882
16887
  finishCurrentNode();
16883
16888
  finishCurrentTagGroup();
16884
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
16889
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
16890
+ const rawName = (qname ?? uname ?? "").trim();
16885
16891
  const peeled = peelInfraDecorations(rawName, lineNumber);
16886
16892
  const name = peeled.label;
16887
- const rest = compMatch[3] || "";
16893
+ const alias = asAlias ?? peeled.alias;
16894
+ const rest = meta ?? "";
16888
16895
  const { tags } = extractPipeMetadata(rest);
16889
16896
  warnUnknownMetaKeys(
16890
16897
  tags,
16891
16898
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
16892
16899
  (msg) => warn(lineNumber, msg)
16893
16900
  );
16894
- const id = nodeId2(name);
16895
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
16901
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
16902
+ if (alias) nameAliasMap.set(alias, id);
16896
16903
  const isEdge = EDGE_NODE_NAMES.has(id.toLowerCase());
16897
16904
  currentNode = {
16898
16905
  id,
@@ -16976,18 +16983,20 @@ function parseInfra(content) {
16976
16983
  const compMatch = trimmed.match(COMPONENT_RE);
16977
16984
  if (compMatch) {
16978
16985
  finishCurrentTagGroup();
16979
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
16986
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
16987
+ const rawName = (qname ?? uname ?? "").trim();
16980
16988
  const peeled = peelInfraDecorations(rawName, lineNumber);
16981
16989
  const name = peeled.label;
16982
- const rest = compMatch[3] || "";
16990
+ const alias = asAlias ?? peeled.alias;
16991
+ const rest = meta ?? "";
16983
16992
  const { tags: nodeTags } = extractPipeMetadata(rest);
16984
16993
  warnUnknownMetaKeys(
16985
16994
  nodeTags,
16986
16995
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
16987
16996
  (msg) => warn(lineNumber, msg)
16988
16997
  );
16989
- const id = nodeId2(name);
16990
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
16998
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
16999
+ if (alias) nameAliasMap.set(alias, id);
16991
17000
  const tags = currentGroup.metadata ? { ...currentGroup.metadata, ...nodeTags } : nodeTags;
16992
17001
  currentNode = {
16993
17002
  id,
@@ -17178,6 +17187,11 @@ function parseInfra(content) {
17178
17187
  }
17179
17188
  continue;
17180
17189
  }
17190
+ if (currentNode && tagAliasSet.has(normalizeName(key))) {
17191
+ const mut = nodeMutableTags.get(currentNode.id);
17192
+ if (mut) mut[tagAttrKey(key)] = rawVal;
17193
+ continue;
17194
+ }
17181
17195
  if (!INFRA_BEHAVIOR_KEYS.has(key) && !EDGE_ONLY_KEYS.has(key)) {
17182
17196
  const allKeys = [...INFRA_BEHAVIOR_KEYS, ...EDGE_ONLY_KEYS];
17183
17197
  const hint = suggest(key, allKeys);
@@ -17243,18 +17257,20 @@ function parseInfra(content) {
17243
17257
  finishCurrentNode();
17244
17258
  const compMatch = trimmed.match(COMPONENT_RE);
17245
17259
  if (compMatch) {
17246
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
17260
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
17261
+ const rawName = (qname ?? uname ?? "").trim();
17247
17262
  const peeled = peelInfraDecorations(rawName, lineNumber);
17248
17263
  const name = peeled.label;
17249
- const rest = compMatch[3] || "";
17264
+ const alias = asAlias ?? peeled.alias;
17265
+ const rest = meta ?? "";
17250
17266
  const { tags: nodeTags } = extractPipeMetadata(rest);
17251
17267
  warnUnknownMetaKeys(
17252
17268
  nodeTags,
17253
17269
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
17254
17270
  (msg) => warn(lineNumber, msg)
17255
17271
  );
17256
- const id = nodeId2(name);
17257
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
17272
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
17273
+ if (alias) nameAliasMap.set(alias, id);
17258
17274
  const tags = currentGroup.metadata ? { ...currentGroup.metadata, ...nodeTags } : nodeTags;
17259
17275
  currentNode = {
17260
17276
  id,
@@ -17276,18 +17292,20 @@ function parseInfra(content) {
17276
17292
  finishCurrentNode();
17277
17293
  finishCurrentTagGroup();
17278
17294
  currentGroup = null;
17279
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
17295
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
17296
+ const rawName = (qname ?? uname ?? "").trim();
17280
17297
  const peeled = peelInfraDecorations(rawName, lineNumber);
17281
17298
  const name = peeled.label;
17282
- const rest = compMatch[3] || "";
17299
+ const alias = asAlias ?? peeled.alias;
17300
+ const rest = meta ?? "";
17283
17301
  const { tags } = extractPipeMetadata(rest);
17284
17302
  warnUnknownMetaKeys(
17285
17303
  tags,
17286
17304
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
17287
17305
  (msg) => warn(lineNumber, msg)
17288
17306
  );
17289
- const id = nodeId2(name);
17290
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
17307
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
17308
+ if (alias) nameAliasMap.set(alias, id);
17291
17309
  currentNode = {
17292
17310
  id,
17293
17311
  label: name,
@@ -17487,7 +17505,7 @@ var init_parser15 = __esm({
17487
17505
  DEPRECATED_FANOUT_RE = /\bx(\d+)\s*$/;
17488
17506
  GROUP_RE = /^\[([^\]]+)\]\s*(?:as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*)?((?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
17489
17507
  TAG_VALUE_RE = /^(\w[\w\s]+?)\s*$/;
17490
- COMPONENT_RE = /^(?:"([^"]+)"|([a-zA-Z_][\w -]*?))\s*((?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
17508
+ COMPONENT_RE = /^(?:"(?<qname>[^"]+)"|(?<uname>[a-zA-Z_][\w -]*?))(?:\s+as\s+(?<alias>[A-Za-z][A-Za-z0-9_]{0,11}))?\s*(?<meta>(?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
17491
17509
  PIPE_META_RE = /[|,]\s*(\w+)\s*:\s*([^|,]+)/g;
17492
17510
  SAMELINE_META_RE = /(?:^|[\s,])(\w+)\s*:\s*([^,]+?)(?=\s*,|\s*$)/g;
17493
17511
  PROPERTY_RE = /^([\w-]+):\s*(.+)$/;
@@ -18971,8 +18989,8 @@ function parseMap(content, palette) {
18971
18989
  continue;
18972
18990
  }
18973
18991
  if (open.route && indent > open.route.indent) {
18974
- const leg = parseLeg(trimmed, lineNumber, open.route.route.style);
18975
- open.route.route.legs.push(leg);
18992
+ const leg = parseLeg(trimmed, lineNumber);
18993
+ if (leg) open.route.route.legs.push(leg);
18976
18994
  continue;
18977
18995
  }
18978
18996
  if (open.poi && indent > open.poi.indent) {
@@ -19001,6 +19019,14 @@ function parseMap(content, palette) {
19001
19019
  Object.assign(open.poi.poi.meta, split.meta);
19002
19020
  continue;
19003
19021
  }
19022
+ if (split.name) {
19023
+ const src = open.poi.poi.alias ?? poiName(open.poi.poi.pos) ?? "the poi";
19024
+ pushError(
19025
+ lineNumber,
19026
+ `Malformed hub edge: "${trimmed}" \u2014 an indented line under a poi is an edge from "${src}" and needs an arrow glyph (\`-> dest\`, \`~> dest\`, or labeled \`-label-> dest\`). For a standalone place, declare it at the top level. (\xA724B.5)`
19027
+ );
19028
+ continue;
19029
+ }
19004
19030
  }
19005
19031
  closeBlocks();
19006
19032
  const firstWord = trimmed.split(/\s+/)[0];
@@ -19249,31 +19275,44 @@ function parseMap(content, palette) {
19249
19275
  const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
19250
19276
  const originLabel = meta["label"];
19251
19277
  const originValue = meta["value"];
19252
- const style = meta["style"] === "arc" ? "arc" : "straight";
19278
+ if (meta["style"] !== void 0) {
19279
+ pushError(
19280
+ line11,
19281
+ "route header no longer takes `style:` \u2014 set leg shape with the arrow glyph instead (`~\u2026~>` for an arc leg, `-\u2026->` for a straight one). (\xA724B.6)"
19282
+ );
19283
+ }
19253
19284
  const route = {
19254
19285
  origin: pos,
19255
19286
  ...split.alias !== void 0 && { originAlias: split.alias },
19256
19287
  ...originLabel !== void 0 && { originLabel },
19257
19288
  ...originValue !== void 0 && { originValue },
19258
19289
  originTags: tags,
19259
- style,
19260
19290
  legs: [],
19261
19291
  lineNumber: line11
19262
19292
  };
19263
19293
  routes.push(route);
19264
19294
  open.route = { route, indent };
19265
19295
  }
19266
- function parseLeg(trimmed, line11, headerStyle) {
19267
- let arrowStyle = "straight";
19268
- let label;
19269
- let rest = trimmed;
19296
+ function parseLeg(trimmed, line11) {
19270
19297
  const m = trimmed.match(LEG_ARROW_RE);
19271
- if (m) {
19272
- const arr = classifyArrow(m[1], line11);
19273
- arrowStyle = arr.style;
19274
- label = arr.label;
19275
- rest = m[2];
19298
+ if (!m) {
19299
+ pushError(
19300
+ line11,
19301
+ `Malformed route leg: "${trimmed}" \u2014 a leg needs an arrow glyph (\`-> dest\`, \`~> dest\`, or labeled \`-label-> dest\` / \`~label~> dest\`). (\xA724B.6)`
19302
+ );
19303
+ return null;
19276
19304
  }
19305
+ const arr = classifyArrow(m[1], line11);
19306
+ if (!arr.directed) {
19307
+ pushError(
19308
+ line11,
19309
+ `A route leg is directional \u2014 "${trimmed}" uses an undirected glyph; use \`-> \` (straight) or \`~> \` (arc). (\xA724B.6)`
19310
+ );
19311
+ return null;
19312
+ }
19313
+ const arrowStyle = arr.style;
19314
+ const label = arr.label;
19315
+ const rest = m[2];
19277
19316
  const split = splitNameAndMeta(
19278
19317
  rest,
19279
19318
  registry(),
@@ -19289,10 +19328,9 @@ function parseMap(content, palette) {
19289
19328
  const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
19290
19329
  const value = meta["value"];
19291
19330
  const destLabel = meta["label"];
19292
- const style = arrowStyle === "arc" || headerStyle === "arc" ? "arc" : "straight";
19293
19331
  return {
19294
19332
  ...label !== void 0 && { label },
19295
- style,
19333
+ style: arrowStyle,
19296
19334
  ...value !== void 0 && { value },
19297
19335
  dest: pos,
19298
19336
  ...split.alias !== void 0 && { destAlias: split.alias },
@@ -54107,13 +54145,15 @@ function layoutMap(resolvedIn, data, size, opts) {
54107
54145
  labelY: lp.y
54108
54146
  };
54109
54147
  const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
54148
+ const routeVal = Number(leg.value);
54110
54149
  legs.push({
54111
54150
  d: legPath(a, b, bow.curved, bow.offset),
54112
- width: routeWidthFor(Number(leg.value)),
54151
+ width: routeWidthFor(routeVal),
54113
54152
  color: lineColor(leg.tags) ?? mix(palette.text, palette.bg, 72),
54114
54153
  arrow: true,
54115
54154
  fromId: leg.fromId,
54116
54155
  toId: leg.toId,
54156
+ ...Number.isFinite(routeVal) && routeVal > 0 && { value: routeVal },
54117
54157
  ...Object.keys(leg.tags).length > 0 && { tags: leg.tags },
54118
54158
  lineNumber: leg.lineNumber,
54119
54159
  ...leg.label !== void 0 && {
@@ -54160,6 +54200,7 @@ function layoutMap(resolvedIn, data, size, opts) {
54160
54200
  labelY: lp.y
54161
54201
  };
54162
54202
  const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
54203
+ const edgeVal = Number(e.meta["value"]);
54163
54204
  legs.push({
54164
54205
  d: legPath(a, b, bow.curved, bow.offset),
54165
54206
  width: widthFor(e),
@@ -54167,6 +54208,7 @@ function layoutMap(resolvedIn, data, size, opts) {
54167
54208
  arrow: e.directed,
54168
54209
  fromId: e.fromId,
54169
54210
  toId: e.toId,
54211
+ ...Number.isFinite(edgeVal) && edgeVal > 0 && { value: edgeVal },
54170
54212
  ...Object.keys(e.tags).length > 0 && { tags: e.tags },
54171
54213
  lineNumber: e.lineNumber,
54172
54214
  ...e.label !== void 0 && {
@@ -54324,18 +54366,49 @@ function layoutMap(resolvedIn, data, size, opts) {
54324
54366
  const SHORT_HOP_MAX = Math.max(46, Math.min(width, height) * 0.11);
54325
54367
  const STEP = 4;
54326
54368
  const HOP_GAP = 9;
54369
+ const CLEAR_STEP = 6;
54370
+ const CLEAR_MAX = SHORT_HOP_MAX * 3;
54371
+ const CLEAR_TOL = CLEAR_STEP;
54372
+ const clearanceAt = (px, py, ox, oy) => {
54373
+ const baseAng = Math.atan2(oy, ox);
54374
+ let minClear = CLEAR_MAX;
54375
+ for (let k = -2; k <= 2; k++) {
54376
+ const a = baseAng + k * Math.PI / 4;
54377
+ const rx = Math.cos(a);
54378
+ const ry = Math.sin(a);
54379
+ let d = CLEAR_STEP;
54380
+ for (; d <= CLEAR_MAX; d += CLEAR_STEP) {
54381
+ const qx = px + rx * d;
54382
+ const qy = py + ry * d;
54383
+ if (qx < FIT_PAD || qy < topPad || qx > width - FIT_PAD || qy > height - FIT_PAD)
54384
+ break;
54385
+ if (fillAt(qx, qy) !== water) break;
54386
+ }
54387
+ if (d < minClear) minClear = d;
54388
+ }
54389
+ return minClear;
54390
+ };
54327
54391
  const tryShortHopCallout = (cx, cy, fill2, name, value, font = FONT2, gap = HOP_GAP, maxLen = SHORT_HOP_MAX) => {
54328
54392
  const chipW = stackW(name, value, font);
54329
54393
  const chipH = stackH(value !== void 0, font);
54394
+ const D = Math.SQRT1_2;
54330
54395
  const dirs = [
54331
54396
  [0, -1],
54332
- // north (over Canada)
54397
+ // north
54333
54398
  [0, 1],
54334
- // south (over Mexico / Gulf)
54399
+ // south
54335
54400
  [1, 0],
54336
- // east (Atlantic)
54337
- [-1, 0]
54338
- // west (Pacific)
54401
+ // east
54402
+ [-1, 0],
54403
+ // west
54404
+ [D, -D],
54405
+ // NE
54406
+ [D, D],
54407
+ // SE
54408
+ [-D, -D],
54409
+ // NW
54410
+ [-D, D]
54411
+ // SW
54339
54412
  ];
54340
54413
  let best = null;
54341
54414
  for (const [dx, dy] of dirs) {
@@ -54385,13 +54458,16 @@ function layoutMap(resolvedIn, data, size, opts) {
54385
54458
  (p) => segmentRectOverlap(cx, cy, innerX, innerY, p)
54386
54459
  ))
54387
54460
  continue;
54388
- if (best === null || len < best.len)
54461
+ const clear = clearanceAt(ccx, ccy, dx, dy);
54462
+ const better = best === null || clear > best.clear + CLEAR_TOL || clear >= best.clear - CLEAR_TOL && len < best.len;
54463
+ if (better)
54389
54464
  best = {
54390
54465
  x: ccx,
54391
54466
  y: ccy,
54392
54467
  rect,
54393
54468
  leader: [cx, cy, innerX, innerY],
54394
- len
54469
+ len,
54470
+ clear
54395
54471
  };
54396
54472
  }
54397
54473
  return best ? { x: best.x, y: best.y, rect: best.rect, leader: best.leader } : null;
@@ -55052,6 +55128,9 @@ function layoutMap(resolvedIn, data, size, opts) {
55052
55128
  const nx = -dy / len;
55053
55129
  const ny = dx / len;
55054
55130
  const perp = labelH + 2;
55131
+ const stroke2 = lg.width ?? W_MIN;
55132
+ const clearW = stroke2 / 2 + labelH / 2 + 3;
55133
+ const offList = stroke2 >= 4 ? [clearW, -clearW, clearW + perp, -(clearW + perp), 0] : [0, perp, -perp, 2 * perp, -2 * perp];
55055
55134
  const pm = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
55056
55135
  lg.d
55057
55136
  );
@@ -55071,7 +55150,7 @@ function layoutMap(resolvedIn, data, size, opts) {
55071
55150
  return [a.cx + dx * t, a.cy + dy * t];
55072
55151
  };
55073
55152
  const candidates = [];
55074
- for (const off of [0, perp, -perp, 2 * perp, -2 * perp])
55153
+ for (const off of offList)
55075
55154
  for (const t of T_LIST) {
55076
55155
  const [bx, by] = pointAt(t);
55077
55156
  candidates.push([bx + nx * off, by + ny * off - 4]);
@@ -55822,6 +55901,12 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
55822
55901
  }
55823
55902
  }
55824
55903
  wireSync(p, leg.lineNumber);
55904
+ if (leg.value !== void 0) {
55905
+ p.attr("data-value", leg.value);
55906
+ p.append("title").text(
55907
+ leg.label !== void 0 ? `${leg.label}: ${leg.value}` : `${leg.value}`
55908
+ );
55909
+ }
55825
55910
  if (arrowTri) {
55826
55911
  gLegs.append("path").attr("d", arrowTri).attr("fill", leg.color).attr("stroke", leg.color).attr("stroke-width", 1).attr("stroke-linejoin", "round").attr("data-from-id", leg.fromId).attr("data-to-id", leg.toId);
55827
55912
  }