@knowvah/dot-engine 1.2.4 → 1.2.5

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/README.md CHANGED
@@ -172,6 +172,21 @@ Trade-off: the built-in model is reproducible across machines; the host-faithful
172
172
  path matches the rendering font but is platform-dependent (as native graphviz is).
173
173
  See the Text measurement guide for the full contract.
174
174
 
175
+ `CanvasTextMeasurer` accepts **any** 2D context that implements `font` +
176
+ `measureText().width` — the `canvas` package is one provider, not a requirement.
177
+ `@napi-rs/canvas` (prebuilt N-API binaries, no `prebuild-install`) works too:
178
+
179
+ ```ts
180
+ import { createCanvas } from '@napi-rs/canvas';
181
+ setTextMeasurer(new CanvasTextMeasurer(createCanvas(0, 0).getContext('2d') as unknown as CanvasRenderingContext2D));
182
+ ```
183
+
184
+ Pick the engine you **render** with: the two libraries resolve system fonts
185
+ differently (measured on macOS: `bold` Helvetica and Times/Courier substitution
186
+ diverge by 4–14% between them, while regular-weight Helvetica/Arial agree to
187
+ <0.2%). "Host-faithful" means measuring with the same font stack that later
188
+ draws the text — mixing engines reintroduces the mismatch you opted in to avoid.
189
+
175
190
  ## Security
176
191
 
177
192
  **Treat rendered output as attacker-controlled markup whenever the DOT source is
@@ -1 +1 @@
1
- {"version":3,"file":"graph-init.d.ts","sourceRoot":"","sources":["../../src/common/graph-init.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAa/C,yCAAyC;AACzC,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,yCAAyC;AACzC,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,yCAAyC;AACzC,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,yCAAyC;AACzC,eAAO,MAAM,UAAU,IAAI,CAAC;AAQ5B;;;GAGG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAKzC,8DAA8D;AAC9D,eAAO,MAAM,SAAS,IAAI,CAAC;AAC3B,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,SAAS,IAAI,CAAC;AAW3B;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAY5C;AAsJD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAsG7D"}
1
+ {"version":3,"file":"graph-init.d.ts","sourceRoot":"","sources":["../../src/common/graph-init.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAa/C,yCAAyC;AACzC,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,yCAAyC;AACzC,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,yCAAyC;AACzC,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,yCAAyC;AACzC,eAAO,MAAM,UAAU,IAAI,CAAC;AAQ5B;;;GAGG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAKzC,8DAA8D;AAC9D,eAAO,MAAM,SAAS,IAAI,CAAC;AAC3B,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,SAAS,IAAI,CAAC;AAW3B;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAY5C;AA2JD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAsG7D"}
@@ -18,4 +18,12 @@ export declare const ARR_NORM = 1;
18
18
  export declare function newSpline(e: Edge, sz: number): Bezier;
19
19
  /** @see lib/common/splines.c:clip_and_install */
20
20
  export declare function clipAndInstall(fe: Edge, hn: Node, ps: Point[], pn: number, info: SplineInfo): void;
21
+ /**
22
+ * Stage-dump hook for the clip/install output (diagnosis only; null in
23
+ * production — same pattern as splines-routespl.ts:setRouteDump).
24
+ */
25
+ type ClipDumpFn = (stage: string, tail: string, head: string, payload: unknown) => void;
26
+ /** Install (or clear) the clip-stage dump callback. Diagnosis only. */
27
+ export declare function setClipDump(fn: ClipDumpFn | null): void;
28
+ export {};
21
29
  //# sourceMappingURL=splines-clip.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"splines-clip.d.ts","sourceRoot":"","sources":["../../src/common/splines-clip.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAO,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAqB,MAAM,kBAAkB,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAS7C,gFAAgF;AAChF,eAAO,MAAM,QAAQ,IAAI,CAAC;AAia1B,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAQrD;AAMD,iDAAiD;AACjD,wBAAgB,cAAc,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAgBlG"}
1
+ {"version":3,"file":"splines-clip.d.ts","sourceRoot":"","sources":["../../src/common/splines-clip.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAO,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAqB,MAAM,kBAAkB,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAS7C,gFAAgF;AAChF,eAAO,MAAM,QAAQ,IAAI,CAAC;AAia1B,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAQrD;AAMD,iDAAiD;AACjD,wBAAgB,cAAc,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CA6BlG;AAED;;;GAGG;AACH,KAAK,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;AAGxF,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAEvD"}
@@ -8,6 +8,10 @@
8
8
  */
9
9
  import type { Point, Box } from '../model/geom.js';
10
10
  import type { Path } from './types.js';
11
+ /** Stage payload consumer installed by a diagnosis harness. */
12
+ export type RouteDumpFn = (stage: string, tail: string, head: string, payload: unknown) => void;
13
+ /** Install (or clear) the routing stage-dump callback. Diagnosis only. */
14
+ export declare function setRouteDump(fn: RouteDumpFn | null): void;
11
15
  /**
12
16
  * Repairs minor errors in the box path (gaps, slight overlaps).
13
17
  * Returns true on hard failure; false on success.
@@ -1 +1 @@
1
- {"version":3,"file":"splines-routespl.d.ts","sourceRoot":"","sources":["../../src/common/splines-routespl.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAsGvC;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAwBvE;AAqDD;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,GAAG,EAAE,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,KAAK,EAAE,EACZ,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GACZ,IAAI,CAKN;AAkND;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,IAAI,GAAG,KAAK,EAAE,GAAG,IAAI,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,IAAI,GAAG,KAAK,EAAE,GAAG,IAAI,CAEvD"}
1
+ {"version":3,"file":"splines-routespl.d.ts","sourceRoot":"","sources":["../../src/common/splines-routespl.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAavC,+DAA+D;AAC/D,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KACxD,IAAI,CAAC;AAIV,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAEzD;AA2HD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAwBvE;AAqDD;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,GAAG,EAAE,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,KAAK,EAAE,EACZ,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GACZ,IAAI,CAKN;AAwOD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,IAAI,GAAG,KAAK,EAAE,GAAG,IAAI,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,IAAI,GAAG,KAAK,EAAE,GAAG,IAAI,CAEvD"}
package/dist/index.js CHANGED
@@ -18427,7 +18427,23 @@ function clipAndInstall(fe, hn, ps, pn, info) {
18427
18427
  };
18428
18428
  SplineClipHelper.arrowClip(fe, hn, ps, bounds, newspl, info);
18429
18429
  SplineClipHelper.copyToBezier(newspl, ps, bounds.start, bounds.end, g.info.bb);
18430
+ if (clipDump) {
18431
+ let cur = fe;
18432
+ while (cur.info.to_orig != null && cur.info.edge_type !== 0) cur = cur.info.to_orig;
18433
+ clipDump("S5_CLIP", cur.tail.name, cur.head.name, {
18434
+ inputPn: pn,
18435
+ bounds: { start: bounds.start, end: bounds.end },
18436
+ sflag: newspl.sflag,
18437
+ eflag: newspl.eflag,
18438
+ sp: { ...newspl.sp },
18439
+ ep: { ...newspl.ep },
18440
+ size: newspl.size,
18441
+ // emit reads bz.size, not list.length (memory: bezier-emit-size-not-length)
18442
+ list: newspl.list.slice(0, newspl.size).map((p) => ({ ...p }))
18443
+ });
18444
+ }
18430
18445
  }
18446
+ var clipDump = null;
18431
18447
 
18432
18448
  // src/common/splines-selfedge.ts
18433
18449
  var SIDE_VERTICES = [12, 4, 6, 2, 3, 1, 9, 8];
@@ -23789,10 +23805,12 @@ function parseRatioKind(g) {
23789
23805
  }
23790
23806
  function parseRatioDrawing(g) {
23791
23807
  const kind = parseRatioKind(g);
23792
- if (kind !== "compress" && kind !== "fill") return;
23808
+ if (kind !== "compress" && kind !== "fill" && kind !== "value") return;
23793
23809
  const sz = parseSizePoints(g.attrs.get("size"));
23794
23810
  g.info.drawing = makeDrawing({
23795
23811
  ratioKind: kind,
23812
+ // C: GD_drawing(g)->ratio = atof(p), set only for R_VALUE (setRatio).
23813
+ ratio: kind === "value" ? Number.parseFloat(g.attrs.get("ratio")) : 0,
23796
23814
  size: sz ? { x: sz.x, y: sz.y } : { x: 0, y: 0 },
23797
23815
  filled: sz?.filled ?? false
23798
23816
  });
@@ -30462,6 +30480,19 @@ function obsPath(conf, p0, poly0, p1, poly1) {
30462
30480
  }
30463
30481
 
30464
30482
  // src/common/splines-routespl.ts
30483
+ var routeDump = null;
30484
+ function dumpIsVirtual(e) {
30485
+ return (e.info?.edge_type ?? 0) !== 0;
30486
+ }
30487
+ function dumpEdgeNames(pp) {
30488
+ let e = pp.data;
30489
+ while (e !== null && dumpIsVirtual(e)) e = e.info?.to_orig ?? null;
30490
+ if (e === null) return ["?", "?"];
30491
+ return [e.tail?.name ?? "?", e.head?.name ?? "?"];
30492
+ }
30493
+ function emitDump(stage, names, mk) {
30494
+ if (routeDump !== null && names !== null) routeDump(stage, names[0], names[1], mk());
30495
+ }
30465
30496
  function overlap(i0, i1, j0, j1) {
30466
30497
  if (i1 <= j0 || i0 >= j1) return 0;
30467
30498
  if (i0 <= j0 && i1 >= j1) return i1 - i0;
@@ -30713,8 +30744,21 @@ function runLimitLoop(boxes, boxn, ps, initLlx, initUrx) {
30713
30744
  }
30714
30745
  function routeSplinesInternal(pp, polyline) {
30715
30746
  const boxes = pp.boxes;
30747
+ const dumpNames = routeDump ? dumpEdgeNames(pp) : null;
30748
+ emitDump("S1_INPUT", dumpNames, () => ({
30749
+ nbox: pp.nbox,
30750
+ boxes: pp.boxes.slice(0, pp.nbox).map((b) => ({ ll: { ...b.ll }, ur: { ...b.ur } })),
30751
+ start: { p: { ...pp.start.p }, theta: pp.start.theta, constrained: pp.start.constrained },
30752
+ end: { p: { ...pp.end.p }, theta: pp.end.theta, constrained: pp.end.constrained }
30753
+ }));
30716
30754
  if (checkPath(pp.nbox, boxes, pp)) return null;
30717
30755
  const effectiveBoxn = pp.nbox;
30756
+ emitDump("S2_CHECKED", dumpNames, () => ({
30757
+ nbox: effectiveBoxn,
30758
+ boxes: boxes.slice(0, effectiveBoxn).map((b) => ({ ll: { ...b.ll }, ur: { ...b.ur } })),
30759
+ start: { p: { ...pp.start.p } },
30760
+ end: { p: { ...pp.end.p } }
30761
+ }));
30718
30762
  let flip = false;
30719
30763
  if (effectiveBoxn > 1 && boxes[0].ll.y > boxes[1].ll.y) {
30720
30764
  flip = true;
@@ -30742,6 +30786,11 @@ function routeSplinesInternal(pp, polyline) {
30742
30786
  console.warn("in routesplines, Pshortestpath failed");
30743
30787
  return null;
30744
30788
  }
30789
+ emitDump("S3_POLY", dumpNames, () => ({
30790
+ poly: polypoints.map((p) => ({ ...p })),
30791
+ eps: [{ ...eps[0] }, { ...eps[1] }],
30792
+ pl: pl.map((p) => ({ ...p }))
30793
+ }));
30745
30794
  let ps;
30746
30795
  if (polyline) {
30747
30796
  ps = makePolyline(pl);
@@ -30751,6 +30800,11 @@ function routeSplinesInternal(pp, polyline) {
30751
30800
  ps = routeSpline(edges, pl, evs);
30752
30801
  if (ps.length === 0) return null;
30753
30802
  }
30803
+ emitDump("S4_SPL", dumpNames, () => ({
30804
+ polyline,
30805
+ evs: polyline ? void 0 : buildConstraintVectors(pp).map((v) => ({ ...v })),
30806
+ ps: ps.map((p) => ({ ...p }))
30807
+ }));
30754
30808
  if (isTriviallyBounded(ps)) {
30755
30809
  applyTrivialBounds(boxes, effectiveBoxn, ps);
30756
30810
  return ps;