@knowvah/dot-engine 2.6.8 → 2.6.10
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/common/htmltable-emit-fill.d.ts +1 -1
- package/dist/common/htmltable-emit-fill.d.ts.map +1 -1
- package/dist/common/htmltable-emit.d.ts +8 -0
- package/dist/common/htmltable-emit.d.ts.map +1 -1
- package/dist/common/htmltable-style.d.ts +22 -0
- package/dist/common/htmltable-style.d.ts.map +1 -0
- package/dist/common/subst.d.ts +8 -0
- package/dist/common/subst.d.ts.map +1 -1
- package/dist/gvc/anchor.d.ts.map +1 -1
- package/dist/index.js +428 -290
- package/dist/index.js.map +4 -4
- package/dist/render/xml-escape.d.ts +8 -6
- package/dist/render/xml-escape.d.ts.map +1 -1
- package/dist/render.js +173 -35
- package/dist/render.js.map +4 -4
- package/package.json +1 -1
- package/src/common/htmltable-emit-fill.ts +7 -6
- package/src/common/htmltable-emit.ts +5 -22
- package/src/common/htmltable-style.ts +38 -0
- package/src/common/poly-gencode.ts +2 -2
- package/src/common/subst.ts +12 -0
- package/src/gvc/anchor.ts +6 -5
- package/src/render/xml-escape.ts +23 -33
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Base XML escape (gv_xml_escape with flags {0}): ids,
|
|
3
|
-
* @see lib/util/xml.c
|
|
2
|
+
* Base XML escape (gv_xml_escape with flags {0}): ids, hrefs.
|
|
3
|
+
* @see lib/util/xml.c:gv_xml_escape
|
|
4
4
|
*/
|
|
5
5
|
export declare function escapeXml(s: string): string;
|
|
6
6
|
/**
|
|
@@ -12,10 +12,12 @@ export declare function escapeXml(s: string): string;
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function escapeXmlTitle(s: string): string;
|
|
14
14
|
/**
|
|
15
|
-
* Text/tooltip XML escape (gv_xml_escape with flags {raw, dash, nbsp}):
|
|
16
|
-
*
|
|
17
|
-
* spaces→ . Used for
|
|
18
|
-
*
|
|
15
|
+
* Text/tooltip XML escape (gv_xml_escape with flags {raw, dash, nbsp}): raw
|
|
16
|
+
* escapes every '&' -- entity-looking or not -- and newline/CR to
|
|
17
|
+
* / ; also '-'→- and 2nd+ consecutive spaces→ . Used for
|
|
18
|
+
* textspans and xlink:title.
|
|
19
|
+
* @see plugin/core/gvrender_core_svg.c:svg_textspan, svg_begin_anchor
|
|
20
|
+
* @see lib/util/xml.c:xml_core (`flags.raw || !xml_isentity(s)`)
|
|
19
21
|
*/
|
|
20
22
|
export declare function escapeXmlText(s: string): string;
|
|
21
23
|
//# sourceMappingURL=xml-escape.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xml-escape.d.ts","sourceRoot":"","sources":["../../src/render/xml-escape.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"xml-escape.d.ts","sourceRoot":"","sources":["../../src/render/xml-escape.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C"}
|
package/dist/render.js
CHANGED
|
@@ -8436,6 +8436,9 @@ function interpretCRNL(str) {
|
|
|
8436
8436
|
}
|
|
8437
8437
|
return out;
|
|
8438
8438
|
}
|
|
8439
|
+
function preprocessTooltip(s) {
|
|
8440
|
+
return interpretCRNL(htmlEntityUTF8(s));
|
|
8441
|
+
}
|
|
8439
8442
|
|
|
8440
8443
|
// src/model/graphInfo.ts
|
|
8441
8444
|
function makeGraphInfo() {
|
|
@@ -11289,6 +11292,37 @@ function underlineDraw(ring, coord, filled, ctx) {
|
|
|
11289
11292
|
renderShapePolyline([ring[2], ring[3]], coord, ctx);
|
|
11290
11293
|
}
|
|
11291
11294
|
|
|
11295
|
+
// src/common/htmltable-style.ts
|
|
11296
|
+
function htmlStyle(style2) {
|
|
11297
|
+
const s = { radial: false, rounded: false, invisible: false, dotted: false, dashed: false };
|
|
11298
|
+
if (style2 === void 0) return s;
|
|
11299
|
+
for (const tk of style2.split(/[ ,]+/)) {
|
|
11300
|
+
switch (tk.toUpperCase()) {
|
|
11301
|
+
case "ROUNDED":
|
|
11302
|
+
s.rounded = true;
|
|
11303
|
+
break;
|
|
11304
|
+
case "RADIAL":
|
|
11305
|
+
s.radial = true;
|
|
11306
|
+
break;
|
|
11307
|
+
case "SOLID":
|
|
11308
|
+
s.dotted = false;
|
|
11309
|
+
s.dashed = false;
|
|
11310
|
+
break;
|
|
11311
|
+
case "INVISIBLE":
|
|
11312
|
+
case "INVIS":
|
|
11313
|
+
s.invisible = true;
|
|
11314
|
+
break;
|
|
11315
|
+
case "DOTTED":
|
|
11316
|
+
s.dotted = true;
|
|
11317
|
+
break;
|
|
11318
|
+
case "DASHED":
|
|
11319
|
+
s.dashed = true;
|
|
11320
|
+
break;
|
|
11321
|
+
}
|
|
11322
|
+
}
|
|
11323
|
+
return s;
|
|
11324
|
+
}
|
|
11325
|
+
|
|
11292
11326
|
// src/common/htmltable-emit-rules.ts
|
|
11293
11327
|
function emitHtmlRules(ctx) {
|
|
11294
11328
|
withHtmlPaint({ fill: ctx.color, pen: ctx.color, penWidth: 1 }, ctx.job, () => {
|
|
@@ -11435,14 +11469,14 @@ function bgFillPaint(ctx) {
|
|
|
11435
11469
|
fill: spec[0],
|
|
11436
11470
|
stop: spec[1],
|
|
11437
11471
|
gradientAngle: ctx.gradientangle ?? 0,
|
|
11438
|
-
radial: ctx.style
|
|
11472
|
+
radial: htmlStyle(ctx.style).radial,
|
|
11439
11473
|
penWidth
|
|
11440
11474
|
};
|
|
11441
11475
|
}
|
|
11442
11476
|
function emitBgFill(ctx) {
|
|
11443
11477
|
const { box, pos, border: border2, renderer, job } = ctx;
|
|
11444
11478
|
withHtmlPaint(bgFillPaint(ctx), job, () => {
|
|
11445
|
-
if (
|
|
11479
|
+
if (htmlStyle(ctx.style).rounded) {
|
|
11446
11480
|
emitRoundedBezier(mkPts(box, border2, pos), { x: 0, y: 0 }, true, { renderer, job });
|
|
11447
11481
|
return;
|
|
11448
11482
|
}
|
|
@@ -11508,13 +11542,6 @@ function emitHtmlImg(img, pos, renderer, job) {
|
|
|
11508
11542
|
}
|
|
11509
11543
|
renderer.usershape?.(img.src, b, job);
|
|
11510
11544
|
}
|
|
11511
|
-
function htmlStyleInvisible(style2) {
|
|
11512
|
-
if (style2 === void 0) return false;
|
|
11513
|
-
return style2.split(/[ ,]+/).some((tok) => {
|
|
11514
|
-
const t = tok.toUpperCase();
|
|
11515
|
-
return t === "INVIS" || t === "INVISIBLE";
|
|
11516
|
-
});
|
|
11517
|
-
}
|
|
11518
11545
|
function emitHtmlCell(cell2, pos, renderer, job) {
|
|
11519
11546
|
const inAnchor = initHtmlAnchor(
|
|
11520
11547
|
{ href: cell2.href, title: cell2.title, target: cell2.target, id: cell2.id },
|
|
@@ -11522,7 +11549,7 @@ function emitHtmlCell(cell2, pos, renderer, job) {
|
|
|
11522
11549
|
renderer,
|
|
11523
11550
|
job
|
|
11524
11551
|
);
|
|
11525
|
-
if (
|
|
11552
|
+
if (htmlStyle(cell2.style).invisible) {
|
|
11526
11553
|
if (inAnchor) endHtmlAnchor(renderer, job);
|
|
11527
11554
|
return;
|
|
11528
11555
|
}
|
|
@@ -11558,7 +11585,7 @@ function emitHtmlLabel(placed, pos, renderer, job) {
|
|
|
11558
11585
|
const tblBox = absBox(placed.box, pos);
|
|
11559
11586
|
const clustersLast = (job.flags & EMIT_CLUSTERS_LAST) !== 0;
|
|
11560
11587
|
const inAnchor = clustersLast ? false : initHtmlAnchor(anchorData, tblBox, renderer, job);
|
|
11561
|
-
const tblInvisible =
|
|
11588
|
+
const tblInvisible = htmlStyle(placed.style).invisible;
|
|
11562
11589
|
if (!tblInvisible) {
|
|
11563
11590
|
if (placed.bgcolor !== void 0) {
|
|
11564
11591
|
emitBgFill({
|
|
@@ -15698,31 +15725,141 @@ function stripedBox(job, pts, clrs, rotate, renderer) {
|
|
|
15698
15725
|
return error;
|
|
15699
15726
|
}
|
|
15700
15727
|
|
|
15728
|
+
// src/util/xml.ts
|
|
15729
|
+
function gvXmlEscape(s, flags) {
|
|
15730
|
+
return XmlEscaper.escape(s, flags);
|
|
15731
|
+
}
|
|
15732
|
+
var XmlEscaper = class _XmlEscaper {
|
|
15733
|
+
static escape(s, flags) {
|
|
15734
|
+
let result = "";
|
|
15735
|
+
let previous = "";
|
|
15736
|
+
let pos = 0;
|
|
15737
|
+
while (pos < s.length) {
|
|
15738
|
+
const prev = s[pos];
|
|
15739
|
+
const [fragment, consumed] = _XmlEscaper.core(previous, s, pos, flags);
|
|
15740
|
+
result += fragment;
|
|
15741
|
+
previous = prev;
|
|
15742
|
+
pos += consumed;
|
|
15743
|
+
}
|
|
15744
|
+
return result;
|
|
15745
|
+
}
|
|
15746
|
+
/**
|
|
15747
|
+
* Escape one character/codepoint at s[pos].
|
|
15748
|
+
* Returns [escaped_fragment, characters_consumed].
|
|
15749
|
+
* Delegates to focused helpers to stay within CCN limit.
|
|
15750
|
+
* @see lib/util/xml.c:xml_core
|
|
15751
|
+
*/
|
|
15752
|
+
static core(previous, s, pos, flags) {
|
|
15753
|
+
const special = _XmlEscaper.coreSpecial(previous, s, pos, flags);
|
|
15754
|
+
if (special !== null) return special;
|
|
15755
|
+
const code = s.charCodeAt(pos);
|
|
15756
|
+
if (code > 127 && flags.utf8) return _XmlEscaper.utf8Entity(s, pos);
|
|
15757
|
+
return [s[pos], 1];
|
|
15758
|
+
}
|
|
15759
|
+
/**
|
|
15760
|
+
* Handle all the fixed-escape cases (& < > - space " ' \n \r).
|
|
15761
|
+
* Returns null when none of those cases applies.
|
|
15762
|
+
* @see lib/util/xml.c:xml_core
|
|
15763
|
+
*/
|
|
15764
|
+
static coreSpecial(previous, s, pos, flags) {
|
|
15765
|
+
const c = s[pos];
|
|
15766
|
+
if (c === "&" && (flags.raw || !_XmlEscaper.isEntity(s, pos))) {
|
|
15767
|
+
return ["&", 1];
|
|
15768
|
+
}
|
|
15769
|
+
if (c === "<") return ["<", 1];
|
|
15770
|
+
if (c === ">") return [">", 1];
|
|
15771
|
+
if (c === '"') return [""", 1];
|
|
15772
|
+
if (c === "'") return ["'", 1];
|
|
15773
|
+
if (c === "-" && flags.dash) return ["-", 1];
|
|
15774
|
+
if (c === " " && previous === " " && flags.nbsp) return [" ", 1];
|
|
15775
|
+
if (c === "\n" && flags.raw) return [" ", 1];
|
|
15776
|
+
if (c === "\r" && flags.raw) return [" ", 1];
|
|
15777
|
+
return null;
|
|
15778
|
+
}
|
|
15779
|
+
/**
|
|
15780
|
+
* Return true if s[pos] (which is '&') starts a valid XML entity:
|
|
15781
|
+
* &[A-Za-z]+; e.g. Ç
|
|
15782
|
+
* &#[0-9]*; e.g. &
|
|
15783
|
+
* &#x[0-9a-fA-F]*; e.g. 水
|
|
15784
|
+
* @see lib/util/xml.c:xml_isentity
|
|
15785
|
+
*/
|
|
15786
|
+
static isEntity(s, pos) {
|
|
15787
|
+
let i = pos + 1;
|
|
15788
|
+
if (i >= s.length || s[i] === ";") return false;
|
|
15789
|
+
i = s[i] === "#" ? _XmlEscaper.scanNumericRef(s, i) : _XmlEscaper.scanNamedRef(s, i);
|
|
15790
|
+
return i < s.length && s[i] === ";";
|
|
15791
|
+
}
|
|
15792
|
+
/** Scan a numeric entity body starting just after the '#'. */
|
|
15793
|
+
static scanNumericRef(s, hashPos) {
|
|
15794
|
+
let i = hashPos + 1;
|
|
15795
|
+
if (i < s.length && (s[i] === "x" || s[i] === "X")) {
|
|
15796
|
+
i++;
|
|
15797
|
+
while (i < s.length && _XmlEscaper.isXDigit(s[i])) i++;
|
|
15798
|
+
} else {
|
|
15799
|
+
while (i < s.length && _XmlEscaper.isDecDigit(s[i])) i++;
|
|
15800
|
+
}
|
|
15801
|
+
return i;
|
|
15802
|
+
}
|
|
15803
|
+
/** Scan a named entity body (alpha chars after the '&'). */
|
|
15804
|
+
static scanNamedRef(s, start) {
|
|
15805
|
+
let i = start;
|
|
15806
|
+
while (i < s.length && _XmlEscaper.isAlpha(s[i])) i++;
|
|
15807
|
+
return i;
|
|
15808
|
+
}
|
|
15809
|
+
/**
|
|
15810
|
+
* Emit &#xNNNN; for the Unicode code point at s[pos]. JS strings are
|
|
15811
|
+
* UTF-16, so the code point (what C decodes from UTF-8) comes from
|
|
15812
|
+
* codePointAt, and an astral character consumes two units.
|
|
15813
|
+
* @see lib/util/xml.c:xml_core (UTF-8 block)
|
|
15814
|
+
*/
|
|
15815
|
+
static utf8Entity(s, pos) {
|
|
15816
|
+
const cp = _XmlEscaper.decodeUtf8(s, pos);
|
|
15817
|
+
const consumed = _XmlEscaper.utf8ByteLen(cp);
|
|
15818
|
+
return [`&#x${cp.toString(16)};`, consumed];
|
|
15819
|
+
}
|
|
15820
|
+
/**
|
|
15821
|
+
* Return the code point at s[pos]. A lone surrogate is the analogue of
|
|
15822
|
+
* malformed UTF-8, where C reports an error and exits (xml.c:135).
|
|
15823
|
+
* @see lib/util/xml.c:xml_core (fprintf + graphviz_exit at xml.c:135)
|
|
15824
|
+
*/
|
|
15825
|
+
static decodeUtf8(s, pos) {
|
|
15826
|
+
const cp = s.codePointAt(pos);
|
|
15827
|
+
if (cp >= 55296 && cp <= 57343) {
|
|
15828
|
+
throw new RenderError(`gvXmlEscape: malformed UTF-8 at position ${pos}`, "RENDER_ERROR");
|
|
15829
|
+
}
|
|
15830
|
+
return cp;
|
|
15831
|
+
}
|
|
15832
|
+
/**
|
|
15833
|
+
* Return how many UTF-16 units encode the code point (C: the UTF-8 byte
|
|
15834
|
+
* length from the leading byte).
|
|
15835
|
+
* @see lib/util/xml.c:xml_core (length computation)
|
|
15836
|
+
*/
|
|
15837
|
+
static utf8ByteLen(cp) {
|
|
15838
|
+
return cp > 65535 ? 2 : 1;
|
|
15839
|
+
}
|
|
15840
|
+
static isDecDigit(c) {
|
|
15841
|
+
return c >= "0" && c <= "9";
|
|
15842
|
+
}
|
|
15843
|
+
static isAlpha(c) {
|
|
15844
|
+
return c >= "a" && c <= "z" || c >= "A" && c <= "Z";
|
|
15845
|
+
}
|
|
15846
|
+
static isXDigit(c) {
|
|
15847
|
+
return _XmlEscaper.isDecDigit(c) || c >= "a" && c <= "f" || c >= "A" && c <= "F";
|
|
15848
|
+
}
|
|
15849
|
+
};
|
|
15850
|
+
|
|
15701
15851
|
// src/render/xml-escape.ts
|
|
15702
|
-
var
|
|
15703
|
-
var
|
|
15704
|
-
var
|
|
15852
|
+
var FLAGS_BASE = { raw: false, dash: false, nbsp: false, utf8: false };
|
|
15853
|
+
var FLAGS_TITLE = { raw: false, dash: true, nbsp: true, utf8: false };
|
|
15854
|
+
var FLAGS_TEXT = { raw: true, dash: true, nbsp: true, utf8: false };
|
|
15705
15855
|
function escapeXml(s) {
|
|
15706
|
-
|
|
15707
|
-
r = r.replace(/</g, "<");
|
|
15708
|
-
r = r.replace(/>/g, ">");
|
|
15709
|
-
r = r.replace(RE_DQUOTE, """);
|
|
15710
|
-
r = r.replace(RE_SQUOTE, "'");
|
|
15711
|
-
return r;
|
|
15856
|
+
return gvXmlEscape(s, FLAGS_BASE);
|
|
15712
15857
|
}
|
|
15713
15858
|
function escapeXmlTitle(s) {
|
|
15714
|
-
|
|
15715
|
-
r = r.replace(/-/g, "-");
|
|
15716
|
-
r = r.replace(/ {2,}/g, (m) => " " + " ".repeat(m.length - 1));
|
|
15717
|
-
return r;
|
|
15859
|
+
return gvXmlEscape(s, FLAGS_TITLE);
|
|
15718
15860
|
}
|
|
15719
15861
|
function escapeXmlText(s) {
|
|
15720
|
-
|
|
15721
|
-
r = r.replace(/-/g, "-");
|
|
15722
|
-
r = r.replace(/\n/g, " ");
|
|
15723
|
-
r = r.replace(/\r/g, " ");
|
|
15724
|
-
r = r.replace(/ {2,}/g, (m) => " " + " ".repeat(m.length - 1));
|
|
15725
|
-
return r;
|
|
15862
|
+
return gvXmlEscape(s, FLAGS_TEXT);
|
|
15726
15863
|
}
|
|
15727
15864
|
|
|
15728
15865
|
// src/gvc/device-cluster.ts
|
|
@@ -15903,7 +16040,7 @@ function anchorAttr(n, key) {
|
|
|
15903
16040
|
return v !== void 0 && v !== "" ? v : void 0;
|
|
15904
16041
|
}
|
|
15905
16042
|
function resolveTooltip(n, tooltip) {
|
|
15906
|
-
if (tooltip !== void 0) return substObjAnchor(
|
|
16043
|
+
if (tooltip !== void 0) return substObjAnchor(preprocessTooltip(tooltip), n);
|
|
15907
16044
|
const label = n.info.label;
|
|
15908
16045
|
return label?.text ?? "";
|
|
15909
16046
|
}
|
|
@@ -20041,7 +20178,7 @@ function subst(s, obj) {
|
|
|
20041
20178
|
return substObjAnchor(s, obj);
|
|
20042
20179
|
}
|
|
20043
20180
|
function tip(s, obj) {
|
|
20044
|
-
return substObjAnchor(
|
|
20181
|
+
return substObjAnchor(preprocessTooltip(s), obj);
|
|
20045
20182
|
}
|
|
20046
20183
|
function textOf(lp) {
|
|
20047
20184
|
return lp?.text ?? null;
|
|
@@ -20820,8 +20957,9 @@ function resetHtmlFillPenWidth() {
|
|
|
20820
20957
|
htmlFillPen = 1;
|
|
20821
20958
|
}
|
|
20822
20959
|
function penTypeOf(style2) {
|
|
20823
|
-
|
|
20824
|
-
if (
|
|
20960
|
+
const st = htmlStyle(style2);
|
|
20961
|
+
if (st.dashed) return 1 /* Dashed */;
|
|
20962
|
+
if (st.dotted) return 2 /* Dotted */;
|
|
20825
20963
|
return 3 /* Solid */;
|
|
20826
20964
|
}
|
|
20827
20965
|
function withHtmlPaint(paint, job, drawFn) {
|
|
@@ -20888,7 +21026,7 @@ function doBorder(spec, renderer, job) {
|
|
|
20888
21026
|
const { box, pos, border: border2, color, sides: sides2, style: style2 } = spec;
|
|
20889
21027
|
htmlFillPen = border2;
|
|
20890
21028
|
withHtmlPaint({ pen: color, penWidth: border2, penStyle: style2 }, job, () => {
|
|
20891
|
-
if (
|
|
21029
|
+
if (htmlStyle(style2).rounded) {
|
|
20892
21030
|
emitRoundedBezier(mkPts(box, border2, pos), { x: 0, y: 0 }, false, { renderer, job });
|
|
20893
21031
|
return;
|
|
20894
21032
|
}
|