@knowvah/dot-engine 2.6.6 → 2.6.7

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/render.js CHANGED
@@ -5982,13 +5982,14 @@ function skipSpace(text, i) {
5982
5982
  return j;
5983
5983
  }
5984
5984
  var byteLength = (s) => new TextEncoder().encode(s).length;
5985
- function fedBytes(unit, isText) {
5986
- if (!isText) return byteLength(unit);
5987
- let text = unit.replace(/&([^;&<]*);/g, (m, name) => {
5985
+ function fedText(piece, endsUnit) {
5986
+ const text = piece.replace(/&([^;&<]*);/g, (m, name) => {
5988
5987
  return name.length >= 2 && Object.hasOwn(HTML_ENTITIES, name) ? `&#${HTML_ENTITIES[name]};` : m;
5989
5988
  });
5990
- if (text.endsWith("]")) text = `${text.slice(0, -1)}&#93;`;
5991
- return byteLength(text);
5989
+ return endsUnit && text.endsWith("]") ? `${text.slice(0, -1)}&#93;` : text;
5990
+ }
5991
+ function fedBytes(unit, isText) {
5992
+ return byteLength(isText ? fedText(unit, true) : unit);
5992
5993
  }
5993
5994
  function scanValue(text, j) {
5994
5995
  const q = text[j];
@@ -6090,26 +6091,45 @@ function scanMarkup(text, p) {
6090
6091
  if (c === "!") return { scan: scanDeclaration(text, p), kind: "tag" };
6091
6092
  return { scan: scanStartTag(text, p), kind: "tag" };
6092
6093
  }
6093
- function scanContent(text, base) {
6094
+ var CDATA_OPEN = "<![CDATA[";
6095
+ var CDATA_CLOSE = "]]>";
6096
+ function scanCdata(text, p, base, dataOf, tokens) {
6097
+ const close = text.indexOf(CDATA_CLOSE, p);
6098
+ const end = close < 0 ? text.length : close;
6099
+ if (end > p) tokens.push({ kind: "cdata", start: base + p, end: base + end, data: dataOf(base + p, base + end) });
6100
+ return close < 0 ? -1 : close + CDATA_CLOSE.length;
6101
+ }
6102
+ function scanText(text, p, base, tokens) {
6103
+ const e = text.indexOf("<", p);
6104
+ const end = e < 0 ? text.length : e;
6105
+ tokens.push({ kind: "text", start: base + p, end: base + end });
6106
+ return end;
6107
+ }
6108
+ function scanContent(text, base, inCdata, dataOf) {
6094
6109
  const tokens = [];
6095
6110
  let p = 0;
6111
+ let inSection = inCdata;
6096
6112
  while (p < text.length) {
6113
+ if (inSection || text.startsWith(CDATA_OPEN, p)) {
6114
+ const after2 = scanCdata(text, inSection ? p : p + CDATA_OPEN.length, base, dataOf, tokens);
6115
+ if (after2 < 0) return { tokens, consumed: text.length, inCdata: true };
6116
+ inSection = false;
6117
+ p = after2;
6118
+ continue;
6119
+ }
6097
6120
  if (text[p] !== "<") {
6098
- const e = text.indexOf("<", p);
6099
- const end = e < 0 ? text.length : e;
6100
- tokens.push({ kind: "text", start: base + p, end: base + end });
6101
- p = end;
6121
+ p = scanText(text, p, base, tokens);
6102
6122
  continue;
6103
6123
  }
6104
6124
  const { scan, kind } = scanMarkup(text, p);
6105
- if (scan.kind === "invalid") return { tokens, consumed: p, invalid: base + scan.offset };
6106
- if (scan.kind === "partial") return { tokens, consumed: p };
6125
+ if (scan.kind === "invalid") return { tokens, consumed: p, invalid: base + scan.offset, inCdata: false };
6126
+ if (scan.kind === "partial") return { tokens, consumed: p, inCdata: false };
6107
6127
  const tok = { kind, start: base + p, end: base + scan.end };
6108
6128
  if (scan.dup !== void 0) tok.dup = base + scan.dup;
6109
6129
  tokens.push(tok);
6110
6130
  p = scan.end;
6111
6131
  }
6112
- return { tokens, consumed: p };
6132
+ return { tokens, consumed: p, inCdata: inSection };
6113
6133
  }
6114
6134
  var InputBuffer = class {
6115
6135
  size = 0;
@@ -6160,24 +6180,42 @@ var ExpatFeed = class {
6160
6180
  buffer = new InputBuffer();
6161
6181
  heldStart = 0;
6162
6182
  fedEnd = 0;
6183
+ inCdata = false;
6184
+ /** Source ranges of the text units fed so far: their bytes went through findNext's rewrite. */
6185
+ textUnits = [];
6163
6186
  /** Start of the token expat still holds, or undefined when it holds nothing. */
6164
6187
  get held() {
6165
6188
  return this.heldStart < this.fedEnd ? this.heldStart : void 0;
6166
6189
  }
6167
- /** One `XML_Parse(parser, src[start, end), nbytes, 0)`. */
6168
- feed(start, end, nbytes) {
6169
- this.buffer.append(nbytes);
6190
+ /** One `XML_Parse(parser, src[start, end), nbytes, 0)`; `isText` for a text unit. */
6191
+ feed(start, end, isText) {
6192
+ if (isText) this.textUnits.push([start, end]);
6193
+ this.buffer.append(fedBytes(this.src.slice(start, end), isText));
6170
6194
  this.fedEnd = end;
6171
6195
  if (!this.buffer.enough) return { tokens: [] };
6172
6196
  const text = this.src.slice(this.heldStart, end);
6173
- const scan = scanContent(text, this.heldStart);
6197
+ const scan = scanContent(text, this.heldStart, this.inCdata, (a, b) => this.fedBetween(a, b));
6174
6198
  if (scan.invalid !== void 0) {
6175
6199
  return { tokens: scan.tokens, invalid: { message: XML_ERROR_INVALID_TOKEN, offset: scan.invalid } };
6176
6200
  }
6201
+ this.inCdata = scan.inCdata;
6177
6202
  this.heldStart += scan.consumed;
6178
6203
  this.buffer.consumedTo(byteLength(this.src.slice(this.heldStart, end)), scan.consumed > 0);
6179
6204
  return { tokens: scan.tokens };
6180
6205
  }
6206
+ /** What expat read for source offsets [start, end): text-unit pieces as findNext rewrote them. */
6207
+ fedBetween(start, end) {
6208
+ let out = "";
6209
+ let p = start;
6210
+ for (const [us, ue] of this.textUnits) {
6211
+ if (ue <= p || us >= end) continue;
6212
+ if (us > p) out += this.src.slice(p, us);
6213
+ const e = Math.min(ue, end);
6214
+ out += fedText(this.src.slice(Math.max(us, p), e), e === ue);
6215
+ p = e;
6216
+ }
6217
+ return out + this.src.slice(p, end);
6218
+ }
6181
6219
  };
6182
6220
  var XML_PREDEFINED_ENTITIES = /* @__PURE__ */ new Set(["lt", "gt", "amp", "quot", "apos"]);
6183
6221
  var ENTITY_NAME = /^[A-Za-z_:][\w.:-]*$/;
@@ -6202,6 +6240,46 @@ function parseTagChunk(chunk) {
6202
6240
  return { close, selfClose: !close && body.endsWith("/"), name };
6203
6241
  }
6204
6242
 
6243
+ // src/common/htmltable-lex-chardata.ts
6244
+ var initialCharData = () => ({ inCell: true, xb: "" });
6245
+ function startInCell(name, inCell) {
6246
+ if (name === "TABLE" || name === "TR" || name === "TH") return false;
6247
+ return name === "TD" ? true : inCell;
6248
+ }
6249
+ function endInCell(name, inCell) {
6250
+ if (name === "TABLE") return true;
6251
+ return name === "TD" ? false : inCell;
6252
+ }
6253
+ function tagInCell(st, tag) {
6254
+ const name = tag.name.toUpperCase();
6255
+ if (tag.close) {
6256
+ st.inCell = endInCell(name, st.inCell);
6257
+ return;
6258
+ }
6259
+ st.inCell = startInCell(name, st.inCell);
6260
+ if (tag.selfClose) st.inCell = endInCell(name, st.inCell);
6261
+ }
6262
+ function keepLostText(st, lost) {
6263
+ for (const t of lost) if (t.type === "text") st.xb += t.value;
6264
+ }
6265
+ function releaseXb(st, first) {
6266
+ if (st.xb === "") return;
6267
+ if (first.type === "text") first.value = st.xb + first.value;
6268
+ else if (first.type === "open" && first.tag === "TABLE") first.heldText = st.xb;
6269
+ else return;
6270
+ st.xb = "";
6271
+ }
6272
+ function cleanText(decoded) {
6273
+ return decoded.replace(/[\x00-\x1f]/g, "");
6274
+ }
6275
+ function textTokens(raw) {
6276
+ return charDataTokens(htmlEntityUTF8(raw));
6277
+ }
6278
+ function charDataTokens(decoded) {
6279
+ const clean = cleanText(decoded);
6280
+ return clean.length > 0 ? [{ type: "text", value: clean }] : [];
6281
+ }
6282
+
6205
6283
  // src/common/htmltable-lex-units.ts
6206
6284
  var UNCLOSED_COMMENT = "Warning: Unclosed comment\n";
6207
6285
  var LABEL_CLOSED = "Warning: Label closed before end of HTML element\n";
@@ -6306,20 +6384,17 @@ function parseCloseToken(inner) {
6306
6384
  checkTag(tag);
6307
6385
  return { type: "close", tag: normalizeTag(tag) };
6308
6386
  }
6309
- function cleanText(raw) {
6310
- const isKeep = (c) => c === " " || c === " " || c === "\n" || c === "\r";
6311
- return raw.replace(/[\x00-\x1f\x7f]/g, (c) => isKeep(c) ? c : "");
6312
- }
6313
- function textTokens(raw) {
6314
- const clean = htmlEntityUTF8(cleanText(raw));
6315
- return clean.length > 0 ? [{ type: "text", value: clean }] : [];
6316
- }
6387
+ var EMPTY_ELEMENTS = /* @__PURE__ */ new Set(["BR", "HR", "VR", "IMG"]);
6317
6388
  function tagTokens(text) {
6318
6389
  const inner = text.slice(1, -1).trim();
6319
6390
  if (inner.startsWith("/")) return [parseCloseToken(inner)];
6320
6391
  if (inner.endsWith("/")) {
6321
6392
  const open = parseOpenToken(inner.slice(0, -1).trim());
6322
- return [open, { type: "close", tag: open.tag }];
6393
+ if (EMPTY_ELEMENTS.has(open.tag)) return [open, { type: "close", tag: open.tag }];
6394
+ const close = { type: "close", tag: open.tag };
6395
+ if (open.warnings !== void 0) close.warnings = open.warnings;
6396
+ if (open.warn === true) close.warn = true;
6397
+ return [close];
6323
6398
  }
6324
6399
  return [parseOpenToken(inner)];
6325
6400
  }
@@ -6392,6 +6467,7 @@ function eventTokens(site) {
6392
6467
  const { src, tok, st } = site;
6393
6468
  const text = src.slice(tok.start, tok.end);
6394
6469
  if (tok.kind === "comment" || tok.kind === "pi") return [];
6470
+ if (tok.kind === "cdata") return charDataTokens(tok.data ?? "");
6395
6471
  if (tok.kind === "tag") {
6396
6472
  checkTagToken(site);
6397
6473
  return tagTokens(text);
@@ -6417,7 +6493,13 @@ function absorb(carry, lost) {
6417
6493
  function eventGroups(run, res) {
6418
6494
  const groups = [];
6419
6495
  for (const tok of res.tokens) {
6420
- const tokens = eventTokens({ src: run.src, tok, st: run.st });
6496
+ let tokens = eventTokens({ src: run.src, tok, st: run.st });
6497
+ if (tok.kind === "tag") {
6498
+ const tag = parseTagChunk(run.src.slice(tok.start, tok.end));
6499
+ if (tag !== void 0) tagInCell(run.cd, tag);
6500
+ } else if (!run.cd.inCell) {
6501
+ tokens = [];
6502
+ }
6421
6503
  if (tokens.length > 0) groups.push({ tokens, tok });
6422
6504
  }
6423
6505
  if (res.invalid !== void 0) {
@@ -6428,6 +6510,7 @@ function eventGroups(run, res) {
6428
6510
  }
6429
6511
  function deliver(run, last) {
6430
6512
  const first = last.tokens[0];
6513
+ releaseXb(run.cd, first);
6431
6514
  attachCarry(run.carry, first);
6432
6515
  const info = { src: run.src, pos: last.tok.start, end: last.tok.end, context: run.st.prev + run.st.curr };
6433
6516
  const prev = run.tokens.at(-1);
@@ -6442,7 +6525,10 @@ function deliver(run, last) {
6442
6525
  function runEvents(run, res) {
6443
6526
  const groups = eventGroups(run, res);
6444
6527
  const last = groups.pop();
6445
- for (const g of groups) absorb(run.carry, g.tokens);
6528
+ for (const g of groups) {
6529
+ absorb(run.carry, g.tokens);
6530
+ keepLostText(run.cd, g.tokens);
6531
+ }
6446
6532
  if (last !== void 0) deliver(run, last);
6447
6533
  }
6448
6534
  function appendString(into, more) {
@@ -6473,7 +6559,8 @@ function tokenizeDeferred(src, label = { start: 0, end: src.length }) {
6473
6559
  tokens: [],
6474
6560
  st: { stack: [], prev: "", curr: "" },
6475
6561
  expat: new ExpatFeed(src),
6476
- carry: { warnings: [], warn: false }
6562
+ carry: { warnings: [], warn: false },
6563
+ cd: initialCharData()
6477
6564
  };
6478
6565
  let error;
6479
6566
  try {
@@ -6482,8 +6569,7 @@ function tokenizeDeferred(src, label = { start: 0, end: src.length }) {
6482
6569
  run.st.curr = src.slice(u.start, u.end);
6483
6570
  run.carry.warnings.push(...u.warnings);
6484
6571
  if (u.warn) run.carry.warn = true;
6485
- const nbytes = fedBytes(run.st.curr, !run.st.curr.startsWith("<"));
6486
- runEvents(run, run.expat.feed(u.start, u.end, nbytes));
6572
+ runEvents(run, run.expat.feed(u.start, u.end, !run.st.curr.startsWith("<")));
6487
6573
  }
6488
6574
  const held = run.expat.held;
6489
6575
  if (held !== void 0) error = unfinishedError(run, held);
@@ -6648,7 +6734,8 @@ var tableFont = (fontStack) => {
6648
6734
  var MSG_SYNTAX_ERROR = "syntax error";
6649
6735
  var MSG_TEXT_BEFORE_TABLE = "Syntax error: non-space string used before <TABLE>";
6650
6736
  var MSG_TEXT_AFTER_TABLE = "Syntax error: non-space string used after </TABLE>";
6651
- var nonSpace = (text) => /[^ \t\n\r]/.test(text);
6737
+ var nonSpace = (text) => /[^ ]/.test(text);
6738
+ var heldNonSpace = (tbl) => tbl?.type === "open" && nonSpace(tbl.heldText ?? "");
6652
6739
  var parseError = (s, tok, message) => {
6653
6740
  if (tok !== void 0) emitWarnings(s, tok);
6654
6741
  else emitEof(s);
@@ -6669,41 +6756,29 @@ var applyBrTag = (s, t, fontStack, items) => {
6669
6756
  items.push({ br: true, brAlign: parseAlign(t.attrs["align"] ?? ""), ...fontItemProps(font) });
6670
6757
  consumeClose(s, "BR");
6671
6758
  };
6672
- var applyFontTag = (s, t, fontStack, items) => {
6673
- consume(s);
6674
- const font = fontStack[fontStack.length - 1] ?? {};
6675
- fontStack.push(mergeFontState(font, {
6676
- fontColor: t.attrs["color"],
6677
- fontFace: t.attrs["face"],
6678
- fontSize: num(t.attrs["point-size"])
6679
- }));
6759
+ var parseStyledText = (s, tag, fontStack, items) => {
6680
6760
  const inner = parseText(s, fontStack);
6681
6761
  fontStack.pop();
6682
- items.push(...inner.items);
6683
6762
  const nxt = peek(s);
6684
- if (nxt?.type === "close" && nxt.tag === "FONT") consume(s);
6763
+ if (inner.items.length === 0 || nxt?.type !== "close" || nxt.tag !== tag) {
6764
+ throw parseError(s, nxt, MSG_SYNTAX_ERROR);
6765
+ }
6766
+ items.push(...inner.items);
6767
+ consume(s);
6685
6768
  };
6686
- var applyInlineTag = (s, t, fontStack, items) => {
6769
+ var applyStyleTag = (s, t, fontStack, items) => {
6687
6770
  consume(s);
6688
- const font = fontStack[fontStack.length - 1] ?? {};
6689
- fontStack.push(mergeFontState(font, inlineFontState(t.tag, t.attrs)));
6690
- const inner = parseText(s, fontStack);
6691
- fontStack.pop();
6692
- items.push(...inner.items);
6693
- const nxt = peek(s);
6694
- if (nxt?.type === "close" && nxt.tag === t.tag) consume(s);
6771
+ const own = t.tag === "FONT" ? { fontColor: t.attrs["color"], fontFace: t.attrs["face"], fontSize: num(t.attrs["point-size"]) } : inlineFontState(t.tag, t.attrs);
6772
+ fontStack.push(mergeFontState(fontStack[fontStack.length - 1] ?? {}, own));
6773
+ parseStyledText(s, t.tag, fontStack, items);
6695
6774
  };
6696
6775
  var applyOpenTag = (s, t, fontStack, items) => {
6697
6776
  if (t.tag === "BR") {
6698
6777
  applyBrTag(s, t, fontStack, items);
6699
6778
  return true;
6700
6779
  }
6701
- if (t.tag === "FONT") {
6702
- applyFontTag(s, t, fontStack, items);
6703
- return true;
6704
- }
6705
- if (isInlineTag(t.tag)) {
6706
- applyInlineTag(s, t, fontStack, items);
6780
+ if (t.tag === "FONT" || isInlineTag(t.tag)) {
6781
+ applyStyleTag(s, t, fontStack, items);
6707
6782
  return true;
6708
6783
  }
6709
6784
  return false;
@@ -6746,7 +6821,7 @@ var parseFontTable = (s, open, fontStack) => {
6746
6821
  fontStack.push(wrapperFont(open, fontStack));
6747
6822
  const textBefore = skipStrings(s);
6748
6823
  const tblTok = peek(s);
6749
- if (textBefore && tblTok !== void 0) throw parseError(s, tblTok, MSG_TEXT_BEFORE_TABLE);
6824
+ if ((textBefore || heldNonSpace(tblTok)) && tblTok !== void 0) throw parseError(s, tblTok, MSG_TEXT_BEFORE_TABLE);
6750
6825
  const table = parseTable(s, fontStack);
6751
6826
  const textAfter = skipStrings(s);
6752
6827
  const close = peek(s);
@@ -6775,7 +6850,7 @@ var parseImgContent = (s, t, cellAttrs) => {
6775
6850
  };
6776
6851
  var scanCellTable = (s, t, fontStack, st) => {
6777
6852
  if (st.kind === "image" || st.kind === "table") throw parseError(s, t, MSG_SYNTAX_ERROR);
6778
- if (st.textNonSpace) throw parseError(s, t, MSG_TEXT_BEFORE_TABLE);
6853
+ if (st.textNonSpace || heldNonSpace(t)) throw parseError(s, t, MSG_TEXT_BEFORE_TABLE);
6779
6854
  const tbl = parseTable(s, fontStack);
6780
6855
  st.kind = "table";
6781
6856
  return [tbl];
@@ -6930,14 +7005,14 @@ var consumeRowHr = (s, rows) => {
6930
7005
  var findFirstRealToken = (tokens, start) => {
6931
7006
  for (let i = start; i < tokens.length; i++) {
6932
7007
  const tk = tokens[i];
6933
- if (tk.type !== "text" || tk.value.trim() !== "") return tk;
7008
+ if (tk.type !== "text" || nonSpace(tk.value)) return tk;
6934
7009
  }
6935
7010
  return void 0;
6936
7011
  };
6937
7012
  var skipLeadingWs = (s) => {
6938
7013
  while (true) {
6939
7014
  const nxt = peek(s);
6940
- if (!nxt || nxt.type !== "text" || nxt.value.trim() !== "") break;
7015
+ if (!nxt || nxt.type !== "text" || nonSpace(nxt.value)) break;
6941
7016
  consume(s);
6942
7017
  }
6943
7018
  };
@@ -6963,6 +7038,7 @@ var parseFontTableLabel = (s, open, fontStack) => {
6963
7038
  };
6964
7039
  var parseTableLabel = (s, fontStack) => {
6965
7040
  skipLeadingWs(s);
7041
+ if (heldNonSpace(peek(s))) throw parseError(s, peek(s), MSG_TEXT_BEFORE_TABLE);
6966
7042
  const table = parseTable(s, fontStack);
6967
7043
  finishTableLabel(s);
6968
7044
  return { kind: "table", table };