@bendyline/squisq 2.11.0 → 2.11.2

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.
@@ -30,7 +30,7 @@ import {
30
30
  templateRegistry,
31
31
  writeCustomTemplatesToFrontmatter,
32
32
  writeCustomThemesToFrontmatter
33
- } from "./chunk-ZYCSRDSX.js";
33
+ } from "./chunk-RO7WVERN.js";
34
34
  import {
35
35
  iconMarker
36
36
  } from "./chunk-7ZAAICW4.js";
@@ -45,11 +45,12 @@ import {
45
45
  detectAsciiDiagram,
46
46
  isHoriz,
47
47
  isJunction,
48
+ isLineChar,
48
49
  isVert,
49
50
  toCells,
50
51
  toGrid,
51
52
  traceBoxes
52
- } from "./chunk-CUYHFOFL.js";
53
+ } from "./chunk-6ATZOUCQ.js";
53
54
  import {
54
55
  defaultPageStyle,
55
56
  resolveMediaSchedule
@@ -5115,6 +5116,19 @@ function pickSides(s, t) {
5115
5116
  gaps.sort((a, b) => a.gap - b.gap);
5116
5117
  return { exit: gaps[0].side, enter: gaps[0].side };
5117
5118
  }
5119
+ function blockedAttachmentColumns(p) {
5120
+ const blocked = /* @__PURE__ */ new Set();
5121
+ const innerW = p.rect.c1 - p.rect.c0 - 1;
5122
+ const lines = p.isContainer ? p.labelLines.slice(1) : p.labelLines;
5123
+ for (const line of lines) {
5124
+ const cells = toCells(line);
5125
+ const pad = Math.max(0, Math.floor((innerW - cells.length) / 2));
5126
+ cells.forEach((ch, j) => {
5127
+ if (isLineChar(ch)) blocked.add(p.rect.c0 + 1 + pad + j);
5128
+ });
5129
+ }
5130
+ return blocked;
5131
+ }
5118
5132
  function assignAttachments(plans, placed) {
5119
5133
  const bySide = /* @__PURE__ */ new Map();
5120
5134
  plans.forEach((plan, i) => {
@@ -5143,13 +5157,31 @@ function assignAttachments(plans, placed) {
5143
5157
  const to = horizontal ? node.rect.c1 - 1 : node.rect.r1 - 1;
5144
5158
  const inner = Math.max(1, to - from + 1);
5145
5159
  const k = list2.length;
5160
+ const blocked = horizontal ? blockedAttachmentColumns(node) : /* @__PURE__ */ new Set();
5161
+ const taken = [];
5162
+ const place = (want) => {
5163
+ const free = (pos) => pos >= from && pos <= to && !blocked.has(pos) && taken.every((t) => Math.abs(t - pos) >= 2);
5164
+ for (let d = 0; d <= inner; d++) {
5165
+ for (const pos of d === 0 ? [want] : [want - d, want + d]) {
5166
+ if (!free(pos)) continue;
5167
+ taken.push(pos);
5168
+ return pos;
5169
+ }
5170
+ }
5171
+ taken.push(want);
5172
+ return want;
5173
+ };
5146
5174
  if (k === 1) {
5147
- result.set(list2[0].key, { pos: from + Math.floor((inner - 1) / 2), index: 0, count: 1 });
5175
+ result.set(list2[0].key, {
5176
+ pos: place(from + Math.floor((inner - 1) / 2)),
5177
+ index: 0,
5178
+ count: 1
5179
+ });
5148
5180
  } else {
5149
5181
  const span = 2 * k - 1;
5150
5182
  const start = from + Math.max(0, Math.floor((inner - span) / 2));
5151
5183
  list2.forEach((req, i) => {
5152
- result.set(req.key, { pos: Math.min(to, start + 2 * i), index: i, count: k });
5184
+ result.set(req.key, { pos: place(Math.min(to, start + 2 * i)), index: i, count: k });
5153
5185
  });
5154
5186
  }
5155
5187
  }
@@ -176,6 +176,11 @@ function parseAsciiDiagramWithStats(text) {
176
176
  const style = detectStyle(grid);
177
177
  const rects = traceBoxes(grid);
178
178
  const boxes = buildBoxes(grid, rects, warnings);
179
+ const boxNodes = boxes.length;
180
+ const railBoxes = findRailLabels(grid, boxes);
181
+ for (const rail of railBoxes) boxes.push(rail);
182
+ const railNodes = railBoxes.length;
183
+ if (railNodes > 0) warnings.push(`rail-labels(${railNodes})`);
179
184
  const mask = new Uint8Array(W * H);
180
185
  const perimeterOwners = /* @__PURE__ */ new Map();
181
186
  for (let b = 0; b < boxes.length; b++) {
@@ -248,18 +253,21 @@ function parseAsciiDiagramWithStats(text) {
248
253
  if (looseRuns.length > MAX_LOOSE_WARNINGS) {
249
254
  warnings.push(`loose-text (+${looseRuns.length - MAX_LOOSE_WARNINGS} more)`);
250
255
  }
251
- const nodes = boxes.map((box) => ({
252
- id: box.id,
253
- label: box.labelLines.join("\n"),
254
- col: box.c0,
255
- row: box.r0,
256
- wCols: box.c1 - box.c0 + 1,
257
- hRows: box.r1 - box.r0 + 1,
258
- ...box.parentIdx >= 0 ? { containerId: boxes[box.parentIdx].id } : {}
259
- }));
256
+ const nodes = boxes.map((box) => {
257
+ const rect = box.emit ?? box;
258
+ return {
259
+ id: box.id,
260
+ label: box.labelLines.join("\n"),
261
+ col: rect.c0,
262
+ row: rect.r0,
263
+ wCols: rect.c1 - rect.c0 + 1,
264
+ hRows: rect.r1 - rect.r0 + 1,
265
+ ...box.parentIdx >= 0 ? { containerId: boxes[box.parentIdx].id } : {}
266
+ };
267
+ }).sort((a, b) => a.row - b.row || a.col - b.col);
260
268
  return {
261
269
  diagram: { nodes, edges, style, warnings },
262
- stats: { totalNonSpaceCells, looseNonSpaceCells, hasWideChars }
270
+ stats: { totalNonSpaceCells, looseNonSpaceCells, hasWideChars, boxNodes, railNodes }
263
271
  };
264
272
  }
265
273
  function buildGrid(text, warnings) {
@@ -497,6 +505,176 @@ function slugify(s) {
497
505
  const slug2 = s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
498
506
  return slug2 || "node";
499
507
  }
508
+ var BUS_LABEL_LOOKASIDE = 3;
509
+ var RAIL_LABEL_PAD = 1;
510
+ var BOX_SPILL_GAP = 2;
511
+ var RAIL_ROW_SCALE = 3;
512
+ var RAIL_COL_SCALE = 2;
513
+ function railRect(text, lines, boxScale) {
514
+ if (boxScale) {
515
+ const r0 = text.r0 * RAIL_ROW_SCALE;
516
+ const c0 = text.c0 * RAIL_COL_SCALE;
517
+ return {
518
+ r0,
519
+ c0,
520
+ r1: r0 + Math.max(3, lines + 2) - 1,
521
+ c1: c0 + Math.max(3, text.c1 - text.c0 + 1 + 4) - 1
522
+ };
523
+ }
524
+ const top = Math.max(0, text.r0 - RAIL_LABEL_PAD);
525
+ const left = Math.max(0, text.c0 - RAIL_LABEL_PAD);
526
+ return {
527
+ r0: top,
528
+ c0: left,
529
+ r1: top + (text.r1 - text.r0) + 2 * RAIL_LABEL_PAD,
530
+ c1: left + (text.c1 - text.c0) + 2 * RAIL_LABEL_PAD
531
+ };
532
+ }
533
+ function findRailLabels(grid, boxes) {
534
+ const H = grid.length;
535
+ const W = H > 0 ? grid[0].length : 0;
536
+ if (H === 0 || W === 0) return [];
537
+ const inBox = new Uint8Array(W * H);
538
+ for (const box of boxes) {
539
+ for (let r = Math.max(0, box.r0); r <= Math.min(H - 1, box.r1); r++) {
540
+ for (let c = Math.max(0, box.c0); c <= Math.min(W - 1, box.c1); c++) inBox[r * W + c] = 1;
541
+ }
542
+ }
543
+ const at = (r, c) => r >= 0 && r < H && c >= 0 && c < W ? grid[r][c] : " ";
544
+ const joins = (ch) => isLineChar(ch) || isJunction(ch) || isPlus(ch) || isAnyCorner(ch);
545
+ const vertJoins = (ch) => {
546
+ const arrow = arrowDirection(ch);
547
+ return joins(ch) || arrow === "up" || arrow === "down";
548
+ };
549
+ const horizJoins = (ch) => {
550
+ const arrow = arrowDirection(ch);
551
+ return joins(ch) || arrow === "left" || arrow === "right";
552
+ };
553
+ const routingRow = [];
554
+ for (let r = 0; r < H; r++) {
555
+ let any = false;
556
+ let all = true;
557
+ for (let c = 0; c < W && all; c++) {
558
+ const ch = grid[r][c];
559
+ if (ch === " ") continue;
560
+ any = true;
561
+ if (!isLineChar(ch) && arrowDirection(ch) === null) all = false;
562
+ }
563
+ routingRow.push(any && all);
564
+ }
565
+ const structural = (r, c) => {
566
+ const ch = at(r, c);
567
+ if (ch === " ") return false;
568
+ if (arrowDirection(ch) !== null) return true;
569
+ const ascii = asciiArrowDirection(ch);
570
+ if (ascii !== null && asciiArrowGate(grid, r, c, ascii)) return true;
571
+ if (!isLineChar(ch)) return false;
572
+ if (routingRow[r]) return true;
573
+ const vert = vertJoins(at(r - 1, c)) || vertJoins(at(r + 1, c));
574
+ if (isVert(ch)) return vert;
575
+ const horiz = horizJoins(at(r, c - 1)) || horizJoins(at(r, c + 1));
576
+ if (isHoriz(ch)) return horiz;
577
+ return vert || horiz;
578
+ };
579
+ const isTextCell = (r, c) => c >= 0 && c < W && grid[r][c] !== " " && !inBox[r * W + c] && !structural(r, c);
580
+ const runs = [];
581
+ for (let r = 0; r < H; r++) {
582
+ let start = -1;
583
+ let end = -1;
584
+ const flush = () => {
585
+ if (start >= 0) {
586
+ const text = grid[r].slice(start, end + 1).join("").trim();
587
+ if (text.length > 0) runs.push({ row: r, c0: start, c1: end, text });
588
+ }
589
+ start = -1;
590
+ };
591
+ for (let c = 0; c < W; c++) {
592
+ if (isTextCell(r, c)) {
593
+ if (start < 0) start = c;
594
+ end = c;
595
+ } else if (start >= 0 && grid[r][c] === " " && isTextCell(r, c + 1)) {
596
+ continue;
597
+ } else {
598
+ flush();
599
+ }
600
+ }
601
+ flush();
602
+ }
603
+ const abutsRail = (run) => [-1, 1].some((dir) => {
604
+ for (let step = 1; step <= BUS_LABEL_LOOKASIDE; step++) {
605
+ const c = dir < 0 ? run.c0 - step : run.c1 + step;
606
+ if (at(run.row, c) === " ") continue;
607
+ return structural(run.row, c);
608
+ }
609
+ return false;
610
+ });
611
+ const spillsFromBox = (run) => boxes.some(
612
+ (box) => run.row >= box.r0 && run.row <= box.r1 && run.c0 <= box.c1 + BOX_SPILL_GAP && run.c1 >= box.c0 - BOX_SPILL_GAP
613
+ );
614
+ const candidates = runs.filter(
615
+ (run) => /[a-z0-9]/i.test(run.text) && !abutsRail(run) && !spillsFromBox(run)
616
+ );
617
+ const groups = [];
618
+ let previousRow = [];
619
+ for (let r = 0; r < H; r++) {
620
+ const rowRuns = candidates.filter((run) => run.row === r);
621
+ const currentRow = [];
622
+ for (const run of rowRuns) {
623
+ const host = previousRow.find((group) => {
624
+ const last = group[group.length - 1];
625
+ return last.row === r - 1 && last.c0 <= run.c1 && run.c0 <= last.c1;
626
+ });
627
+ if (host) {
628
+ host.push(run);
629
+ currentRow.push(host);
630
+ } else {
631
+ const group = [run];
632
+ groups.push(group);
633
+ currentRow.push(group);
634
+ }
635
+ }
636
+ previousRow = currentRow;
637
+ }
638
+ const railHead = (r, c) => {
639
+ if (r < 0 || r >= H || inBox[r * W + c] === 1 || !structural(r, c)) return false;
640
+ const ch = grid[r][c];
641
+ const arrow = arrowDirection(ch) ?? asciiArrowDirection(ch);
642
+ return isVert(ch) || isJunction(ch) || isPlus(ch) || arrow === "up" || arrow === "down";
643
+ };
644
+ const railAdjacent = (group) => group.some(
645
+ (run) => [run.row - 1, run.row + 1].some((r) => {
646
+ for (let c = Math.max(0, run.c0 - 1); c <= Math.min(W - 1, run.c1 + 1); c++) {
647
+ if (railHead(r, c)) return true;
648
+ }
649
+ return false;
650
+ })
651
+ );
652
+ const usedIds = /* @__PURE__ */ new Map();
653
+ for (const box of boxes) usedIds.set(box.id, (usedIds.get(box.id) ?? 0) + 1);
654
+ const out = [];
655
+ for (const group of groups) {
656
+ if (!railAdjacent(group)) continue;
657
+ const labelLines = group.map((run) => run.text);
658
+ const r0 = group[0].row;
659
+ const r1 = group[group.length - 1].row;
660
+ const c0 = Math.min(...group.map((run) => run.c0));
661
+ const c1 = Math.max(...group.map((run) => run.c1));
662
+ const base = slugify(labelLines[0]);
663
+ const count = usedIds.get(base) ?? 0;
664
+ usedIds.set(base, count + 1);
665
+ out.push({
666
+ r0,
667
+ c0,
668
+ r1,
669
+ c1,
670
+ parentIdx: -1,
671
+ labelLines,
672
+ id: count === 0 ? base : `${base}-${count + 1}`,
673
+ emit: railRect({ r0, c0, r1, c1 }, labelLines.length, boxes.length === 0)
674
+ });
675
+ }
676
+ return out;
677
+ }
500
678
  function extractEdges(grid, mask, perimeterOwners, boxes, warnings) {
501
679
  const H = grid.length;
502
680
  const W = H > 0 ? grid[0].length : 0;
@@ -687,6 +865,26 @@ function extractEdges(grid, mask, perimeterOwners, boxes, warnings) {
687
865
  attachmentsByBox.set(boxIdx, { boxIdx, isArrowEnd: false });
688
866
  }
689
867
  }
868
+ if (attachmentsByBox.size < 2) {
869
+ for (const idx of component) {
870
+ const r = Math.floor(idx / W);
871
+ const c = idx % W;
872
+ const ch = grid[r][c];
873
+ const axis = isVert(ch) ? [
874
+ [-1, 0],
875
+ [1, 0]
876
+ ] : isHoriz(ch) ? [
877
+ [0, -1],
878
+ [0, 1]
879
+ ] : [];
880
+ for (const [dr, dc] of axis) {
881
+ const boxIdx = nearestOwner(r + dr, c + dc);
882
+ if (boxIdx !== null && !attachmentsByBox.has(boxIdx)) {
883
+ attachmentsByBox.set(boxIdx, { boxIdx, isArrowEnd: false });
884
+ }
885
+ }
886
+ }
887
+ }
690
888
  const attachments = [...attachmentsByBox.values()].sort(
691
889
  (a, b) => boxes[a.boxIdx].r0 - boxes[b.boxIdx].r0 || boxes[a.boxIdx].c0 - boxes[b.boxIdx].c0
692
890
  );
@@ -908,6 +1106,7 @@ var MAX_LINES = 400;
908
1106
  var MAX_COLS = 400;
909
1107
  var MIN_LINES = 3;
910
1108
  var MAX_LOOSE_RATIO = 0.25;
1109
+ var ROUTING_ROW = /^[\s\u2500-\u257F+\-|^v<>\u25B2\u25BC\u25C0\u25B6\u25C4\u25BA\u2190\u2192\u2191\u2193]+$/;
911
1110
  var STRUCTURAL_IN_LABEL = /[│┃║┌┐└┘├┤┬┴┼╭╮╰╯┏┓┗┛╔╗╚╝┣┫┳┻╋╠╣╦╩╬╞╡╥╨╫╪]/;
912
1111
  function isEligibleAsciiFenceLang(lang) {
913
1112
  if (lang === null || lang === void 0) return true;
@@ -940,8 +1139,14 @@ function detectAsciiDiagram(text, opts = {}) {
940
1139
  const plusMatches = line.match(/\+[-+]/g);
941
1140
  tlCandidates += plusMatches ? plusMatches.length : 0;
942
1141
  }
943
- if (tlCandidates < 2) {
944
- return { isDiagram: false, reasons: [`too-few-corner-candidates(${tlCandidates})`] };
1142
+ const routingRows = lines.filter(
1143
+ (line) => line.trim().length > 0 && ROUTING_ROW.test(line)
1144
+ ).length;
1145
+ if (tlCandidates < 2 && routingRows < 2) {
1146
+ return {
1147
+ isDiagram: false,
1148
+ reasons: [`too-few-corner-candidates(${tlCandidates}) routing-rows(${routingRows})`]
1149
+ };
945
1150
  }
946
1151
  }
947
1152
  const nonBlank = lines.filter((l) => l.trim().length > 0);
@@ -960,6 +1165,9 @@ function detectAsciiDiagram(text, opts = {}) {
960
1165
  return { isDiagram: false, reasons: [`garbled-labels(${garbled}/${diagram.nodes.length})`] };
961
1166
  }
962
1167
  if (!explicit) {
1168
+ if (stats.boxNodes === 0 && diagram.edges.length === 0) {
1169
+ return { isDiagram: false, reasons: [`rail-labels-unconnected(${stats.railNodes})`] };
1170
+ }
963
1171
  if (diagram.edges.length === 0 && diagram.nodes.length >= 4 && isLattice(diagram)) {
964
1172
  return { isDiagram: false, reasons: ["table-lattice"] };
965
1173
  }
@@ -1961,7 +2169,7 @@ function detectAsciiTimeline(text, options = {}) {
1961
2169
  if (!explicit && lines.some((line) => BOX_TOP_EDGE_RE.test(line))) {
1962
2170
  return { isTimeline: false, reasons: ["has-box-corners"] };
1963
2171
  }
1964
- const boxes = parseAsciiDiagramWithStats(text).diagram.nodes.length;
2172
+ const boxes = parseAsciiDiagramWithStats(text).stats.boxNodes;
1965
2173
  if (boxes >= (explicit ? 2 : 1)) {
1966
2174
  return { isTimeline: false, reasons: [`has-boxes(${boxes})`] };
1967
2175
  }
@@ -2205,7 +2413,7 @@ function detectTree(text, opts = {}) {
2205
2413
  if (!explicit && detectAsciiTimeline(text).isTimeline) {
2206
2414
  return { isTree: false, reasons: ["is-timeline"] };
2207
2415
  }
2208
- const boxes = parseAsciiDiagramWithStats(text).diagram.nodes.length;
2416
+ const boxes = parseAsciiDiagramWithStats(text).stats.boxNodes;
2209
2417
  if (boxes >= 2) {
2210
2418
  return { isTree: false, reasons: [`has-boxes(${boxes})`] };
2211
2419
  }
@@ -2488,6 +2696,7 @@ export {
2488
2696
  isVert,
2489
2697
  isJunction,
2490
2698
  arrowDirection,
2699
+ isLineChar,
2491
2700
  UNICODE_VOCAB,
2492
2701
  ASCII_VOCAB,
2493
2702
  MAX_BRIDGE_GAP,
@@ -40,14 +40,96 @@ function categorizeLintKind(kind) {
40
40
 
41
41
  // src/proof/masking.ts
42
42
  var ANNOTATION_RE = /\{\[[^\n]*?\]\}/g;
43
- function blankProtectedSpans(text) {
43
+ function blankProtectedSpans(text, options = {}) {
44
+ const ranges = [];
45
+ ANNOTATION_RE.lastIndex = 0;
46
+ let match;
47
+ while ((match = ANNOTATION_RE.exec(text)) !== null) {
48
+ ranges.push({ start: match.index, end: match.index + match[0].length });
49
+ }
50
+ if (options.markdownCode) ranges.push(...markdownCodeRanges(text));
51
+ if (ranges.length === 0) return { text, blanked: [] };
52
+ ranges.sort((a, b) => a.start - b.start || a.end - b.end);
44
53
  const blanked = [];
45
- const out = text.replace(ANNOTATION_RE, (match, offset) => {
46
- blanked.push({ start: offset, end: offset + match.length });
47
- return " ".repeat(match.length);
48
- });
54
+ for (const range of ranges) {
55
+ const last = blanked[blanked.length - 1];
56
+ if (last && range.start <= last.end) last.end = Math.max(last.end, range.end);
57
+ else blanked.push({ ...range });
58
+ }
59
+ let out = "";
60
+ let cursor = 0;
61
+ for (const range of blanked) {
62
+ out += text.slice(cursor, range.start);
63
+ out += text.slice(range.start, range.end).replace(/[^\n]/g, " ");
64
+ cursor = range.end;
65
+ }
66
+ out += text.slice(cursor);
49
67
  return { text: out, blanked };
50
68
  }
69
+ function markdownCodeRanges(text) {
70
+ const fences = fencedCodeRanges(text);
71
+ const ranges = [...fences];
72
+ let cursor = 0;
73
+ for (const fence of fences) {
74
+ collectInlineCodeRanges(text, cursor, fence.start, ranges);
75
+ cursor = fence.end;
76
+ }
77
+ collectInlineCodeRanges(text, cursor, text.length, ranges);
78
+ return ranges;
79
+ }
80
+ var FENCE_RE = /^( {0,3})(`{3,}|~{3,})(.*)$/;
81
+ function fencedCodeRanges(text) {
82
+ const ranges = [];
83
+ let lineStart = 0;
84
+ let open = null;
85
+ for (; ; ) {
86
+ const newline = text.indexOf("\n", lineStart);
87
+ const lineEnd = newline === -1 ? text.length : newline;
88
+ const match = FENCE_RE.exec(text.slice(lineStart, lineEnd));
89
+ if (!open) {
90
+ if (match) open = { start: lineStart, marker: match[2] };
91
+ } else if (match && // A closing fence is the same character, at least as long, and bare.
92
+ match[2][0] === open.marker[0] && match[2].length >= open.marker.length && match[3].trim() === "") {
93
+ ranges.push({ start: open.start, end: lineEnd });
94
+ open = null;
95
+ }
96
+ if (newline === -1) break;
97
+ lineStart = newline + 1;
98
+ }
99
+ if (open) ranges.push({ start: open.start, end: text.length });
100
+ return ranges;
101
+ }
102
+ function collectInlineCodeRanges(text, from, to, out) {
103
+ let i = from;
104
+ let openStart = -1;
105
+ let openLength = 0;
106
+ while (i < to) {
107
+ if (text[i] === "`") {
108
+ let run = 1;
109
+ while (i + run < to && text[i + run] === "`") run++;
110
+ if (openStart < 0) {
111
+ openStart = i;
112
+ openLength = run;
113
+ } else if (run === openLength) {
114
+ out.push({ start: openStart, end: i + run });
115
+ openStart = -1;
116
+ openLength = 0;
117
+ }
118
+ i += run;
119
+ continue;
120
+ }
121
+ if (openStart >= 0 && text[i] === "\n" && startsBlankLine(text, i + 1, to)) {
122
+ openStart = -1;
123
+ openLength = 0;
124
+ }
125
+ i++;
126
+ }
127
+ }
128
+ function startsBlankLine(text, index, to) {
129
+ let i = index;
130
+ while (i < to && (text[i] === " " || text[i] === " ")) i++;
131
+ return i >= to || text[i] === "\n";
132
+ }
51
133
  function dropMaskedFindings(findings, blanked) {
52
134
  if (blanked.length === 0) return [...findings];
53
135
  return findings.filter(
@@ -3,7 +3,7 @@ import {
3
3
  expectedSyllablesAt,
4
4
  flattenRenderableBlocks,
5
5
  wordPosAtExpectedSyllables
6
- } from "./chunk-ZYCSRDSX.js";
6
+ } from "./chunk-RO7WVERN.js";
7
7
 
8
8
  // src/narration/types.ts
9
9
  var DEFAULT_FEATURE_CONFIG = Object.freeze({
@@ -21,7 +21,7 @@ import {
21
21
  parseAsciiTimeline,
22
22
  pickAutoTemplate,
23
23
  profileBlockContents
24
- } from "./chunk-CUYHFOFL.js";
24
+ } from "./chunk-6ATZOUCQ.js";
25
25
  import {
26
26
  DEFAULT_THEME,
27
27
  FRONTMATTER_CUSTOM_TEMPLATES_KEY,
@@ -1513,9 +1513,11 @@ function renderMarkdownBlocksHtml(nodes) {
1513
1513
  return "<hr>";
1514
1514
  case "table": {
1515
1515
  const [head, ...body] = node.children;
1516
- const row = (cells, header) => `<tr>${cells.map((cell) => {
1516
+ const row = (cells, header) => `<tr>${cells.map((cell, columnIndex) => {
1517
1517
  const tag = header ? "th" : "td";
1518
- return `<${tag}>${renderInlineHtml(cell.children)}</${tag}>`;
1518
+ const alignment = node.align?.[columnIndex];
1519
+ const alignAttribute = alignment ? ` align="${alignment}"` : "";
1520
+ return `<${tag}${alignAttribute}>${renderInlineHtml(cell.children)}</${tag}>`;
1519
1521
  }).join("")}</tr>`;
1520
1522
  const thead = head ? `<thead>${row(head.children, true)}</thead>` : "";
1521
1523
  const tbody = body.length ? `<tbody>${body.map((item) => row(item.children, false)).join("")}</tbody>` : "";
package/dist/doc/index.js CHANGED
@@ -70,7 +70,7 @@ import {
70
70
  validateMarkdownDoc,
71
71
  validateMarkdownSource,
72
72
  writeDashboardLayoutsToFrontmatter
73
- } from "../chunk-EH4S7HXE.js";
73
+ } from "../chunk-56MJWI5M.js";
74
74
  import {
75
75
  ASCII_CHAR_H,
76
76
  ASCII_CHAR_W,
@@ -192,7 +192,7 @@ import {
192
192
  wrapWithPersistentLayers,
193
193
  writeCustomTemplatesToFrontmatter,
194
194
  writeCustomThemesToFrontmatter
195
- } from "../chunk-ZYCSRDSX.js";
195
+ } from "../chunk-RO7WVERN.js";
196
196
  import {
197
197
  PATH_SHAPE_KINDS,
198
198
  anchorPoint,
@@ -229,7 +229,7 @@ import {
229
229
  parseAsciiTimelineWithStats,
230
230
  parseTree,
231
231
  parseWrappedFlowTimeline
232
- } from "../chunk-CUYHFOFL.js";
232
+ } from "../chunk-6ATZOUCQ.js";
233
233
  import "../chunk-GAZKTT4R.js";
234
234
  import {
235
235
  DEFAULT_THEME,
package/dist/index.d.ts CHANGED
@@ -26,5 +26,5 @@ export { IconSuggestion, canonicalIconToken, iconGlyph, looksLikeIconToken, reso
26
26
  export { BlockContentProfile, RecommendationResult, profileBlockContents, recommendTemplatesForBlock } from './recommend/index.js';
27
27
  export { AdvanceCoverage, AlignConfig, AlignInput, BandpassState, BuildAdvanceTimingOptions, BuildNarrationTimingOptions, BuildScriptOptions, DEFAULT_ALIGN_CONFIG, DEFAULT_FEATURE_CONFIG, DEFAULT_NUCLEI_CONFIG, DEFAULT_PACING_CONFIG, DEFAULT_VAD_CONFIG, EMPTY_ADVANCE_LOG, FeatureConfig, FeatureState, FrameFeatures, NarrationAlignment, NarrationBlockRange, NarrationScript, NarrationSessionConfig, NarrationSessionState, NarrationTimingBlock, NarrationTimingJsonV3, NarrationTimingMethod, NarrationTrace, NucleiConfig, NucleiState, PacingConfig, PacingState, PacingTick, ScriptBlockRange, ScriptToken, SlideAdvance, SlideAdvanceLog, TraceSample, VadConfig, VadState, WordTiming, advanceCoverage, alignNarration, bandpassRun, buildAdvanceTimingJson, buildNarrationScript, buildNarrationTimingJson, createBandpass, createFeatureState, createNarrationSession, createNucleiState, createPacingState, createVadState, detectSyllableOnsets, downsampleTrace, estimateSyllables, expectedSyllablesAt, extractFrameFeatures, featureStep, narrationSessionStep, nucleiStep, pacingStep, parseNarrationTimingJson, reanchorPacing, reanchorSession, recordSlideShown, traceWordPosAt, vadStep, wordIndexAtChar, wordIndexAtTime, wordPosAtExpectedSyllables } from './narration/index.js';
28
28
  export { FenceRenderContext, FenceRenderer, FenceRendererMap, fenceRendererLangs } from './fence/index.js';
29
- export { BlankedText, DEFAULT_PROOF_SETTINGS, JoinedSegments, LINT_KIND_CATEGORIES, PROOF_DIALECTS, PROOF_FRONTMATTER_KEYS, PROOF_JOIN_SEPARATOR, ProofCategory, ProofDialect, ProofFinding, ProofRange, ProofSuggestion, ProofSuggestionKind, ProofingSettings, SegmentSpan, blankProtectedSpans, buildJoinedText, categorizeLintKind, dropMaskedFindings, formatProofDictionary, mapJoinedSpanToSegment, parseProofDictionary, readProofingSettings, resolveProofDialect } from './proof/index.js';
29
+ export { BlankProtectedSpansOptions, BlankedText, DEFAULT_PROOF_SETTINGS, JoinedSegments, LINT_KIND_CATEGORIES, PROOF_DIALECTS, PROOF_FRONTMATTER_KEYS, PROOF_JOIN_SEPARATOR, ProofCategory, ProofDialect, ProofFinding, ProofRange, ProofSuggestion, ProofSuggestionKind, ProofingSettings, SegmentSpan, blankProtectedSpans, buildJoinedText, categorizeLintKind, dropMaskedFindings, formatProofDictionary, mapJoinedSpanToSegment, parseProofDictionary, readProofingSettings, resolveProofDialect } from './proof/index.js';
30
30
  import './viewState-lTZS-hP_.js';
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  recordSlideShown,
28
28
  traceWordPosAt,
29
29
  vadStep
30
- } from "./chunk-ZWID3HM5.js";
30
+ } from "./chunk-QWN5CLCP.js";
31
31
  import {
32
32
  fenceRendererLangs
33
33
  } from "./chunk-PGI7HSWE.js";
@@ -46,7 +46,7 @@ import {
46
46
  parseProofDictionary,
47
47
  readProofingSettings,
48
48
  resolveProofDialect
49
- } from "./chunk-T3B4WJBR.js";
49
+ } from "./chunk-B3AK7SLZ.js";
50
50
  import {
51
51
  DEFAULT_TRANSFORM_STYLE_ID,
52
52
  analyzeBlocks,
@@ -227,7 +227,7 @@ import {
227
227
  validateMarkdownDoc,
228
228
  validateMarkdownSource,
229
229
  writeDashboardLayoutsToFrontmatter
230
- } from "./chunk-EH4S7HXE.js";
230
+ } from "./chunk-56MJWI5M.js";
231
231
  import {
232
232
  ASCII_CHAR_H,
233
233
  ASCII_CHAR_W,
@@ -357,7 +357,7 @@ import {
357
357
  wrapWithPersistentLayers,
358
358
  writeCustomTemplatesToFrontmatter,
359
359
  writeCustomThemesToFrontmatter
360
- } from "./chunk-ZYCSRDSX.js";
360
+ } from "./chunk-RO7WVERN.js";
361
361
  import {
362
362
  PATH_SHAPE_KINDS,
363
363
  anchorPoint,
@@ -402,7 +402,7 @@ import {
402
402
  parseWrappedFlowTimeline,
403
403
  profileBlockContents,
404
404
  recommendTemplatesForBlock
405
- } from "./chunk-CUYHFOFL.js";
405
+ } from "./chunk-6ATZOUCQ.js";
406
406
  import {
407
407
  defaultPageStyle,
408
408
  getDocPlaybackDuration,
@@ -27,7 +27,7 @@ import {
27
27
  recordSlideShown,
28
28
  traceWordPosAt,
29
29
  vadStep
30
- } from "../chunk-ZWID3HM5.js";
30
+ } from "../chunk-QWN5CLCP.js";
31
31
  import {
32
32
  buildNarrationScript,
33
33
  buildNarrationTimingJson,
@@ -37,9 +37,9 @@ import {
37
37
  wordIndexAtChar,
38
38
  wordIndexAtTime,
39
39
  wordPosAtExpectedSyllables
40
- } from "../chunk-ZYCSRDSX.js";
40
+ } from "../chunk-RO7WVERN.js";
41
41
  import "../chunk-PUS54YU6.js";
42
- import "../chunk-CUYHFOFL.js";
42
+ import "../chunk-6ATZOUCQ.js";
43
43
  import "../chunk-SBAX4ZPO.js";
44
44
  import "../chunk-BAOV476U.js";
45
45
  import "../chunk-TMOHAFYE.js";
@@ -73,6 +73,15 @@ declare function categorizeLintKind(kind: string): ProofCategory;
73
73
  * spaces — every surrounding offset stays byte-identical — and afterwards
74
74
  * drop any finding that intersects a blanked range (which also swallows
75
75
  * the whitespace-formatting lints the blank runs themselves can induce).
76
+ *
77
+ * MARKDOWN SOURCE carries a second family of machine vocabulary: code.
78
+ * A fence is a program, and an inline span is an identifier or a signature
79
+ * (``raycast(origin, dir, maxDist)`` draws a spelling lint on every one of
80
+ * those words), so `markdownCode` blanks both. It is off by default because
81
+ * it is only meaningful for source text: the Write view lints the editor's
82
+ * PLAIN TEXT, where code is a ProseMirror mark with no backticks to find
83
+ * (`writeViewText.ts` blanks it during collection instead). Newlines are
84
+ * never blanked, so a line/column mapping over the result stays exact.
76
85
  */
77
86
 
78
87
  interface BlankedText {
@@ -81,8 +90,18 @@ interface BlankedText {
81
90
  /** The replaced ranges, in ascending order. */
82
91
  blanked: ProofRange[];
83
92
  }
84
- /** Blank `{[…]}` annotation spans to equal-length spaces. */
85
- declare function blankProtectedSpans(text: string): BlankedText;
93
+ interface BlankProtectedSpansOptions {
94
+ /**
95
+ * Also blank markdown code: fenced blocks (delimiters and info string
96
+ * included) and inline code spans. Only correct for markdown SOURCE text.
97
+ */
98
+ markdownCode?: boolean;
99
+ }
100
+ /**
101
+ * Blank protected spans to equal-length runs of spaces: `{[…]}` annotations
102
+ * always, and markdown code when `markdownCode` is set.
103
+ */
104
+ declare function blankProtectedSpans(text: string, options?: BlankProtectedSpansOptions): BlankedText;
86
105
  /** Keep only findings whose span does not intersect any blanked range. */
87
106
  declare function dropMaskedFindings<T extends ProofRange>(findings: readonly T[], blanked: readonly ProofRange[]): T[];
88
107
 
@@ -176,4 +195,4 @@ declare function formatProofDictionary(words: readonly string[]): string | null;
176
195
  /** Read all proofing settings from a parsed frontmatter record. */
177
196
  declare function readProofingSettings(frontmatter: Record<string, unknown> | undefined): ProofingSettings;
178
197
 
179
- export { type BlankedText, DEFAULT_PROOF_SETTINGS, type JoinedSegments, LINT_KIND_CATEGORIES, PROOF_DIALECTS, PROOF_FRONTMATTER_KEYS, PROOF_JOIN_SEPARATOR, type ProofCategory, type ProofDialect, type ProofFinding, type ProofRange, type ProofSuggestion, type ProofSuggestionKind, type ProofingSettings, type SegmentSpan, blankProtectedSpans, buildJoinedText, categorizeLintKind, dropMaskedFindings, formatProofDictionary, mapJoinedSpanToSegment, parseProofDictionary, readProofingSettings, resolveProofDialect };
198
+ export { type BlankProtectedSpansOptions, type BlankedText, DEFAULT_PROOF_SETTINGS, type JoinedSegments, LINT_KIND_CATEGORIES, PROOF_DIALECTS, PROOF_FRONTMATTER_KEYS, PROOF_JOIN_SEPARATOR, type ProofCategory, type ProofDialect, type ProofFinding, type ProofRange, type ProofSuggestion, type ProofSuggestionKind, type ProofingSettings, type SegmentSpan, blankProtectedSpans, buildJoinedText, categorizeLintKind, dropMaskedFindings, formatProofDictionary, mapJoinedSpanToSegment, parseProofDictionary, readProofingSettings, resolveProofDialect };
@@ -13,7 +13,7 @@ import {
13
13
  parseProofDictionary,
14
14
  readProofingSettings,
15
15
  resolveProofDialect
16
- } from "../chunk-T3B4WJBR.js";
16
+ } from "../chunk-B3AK7SLZ.js";
17
17
  export {
18
18
  DEFAULT_PROOF_SETTINGS,
19
19
  LINT_KIND_CATEGORIES,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  profileBlockContents,
3
3
  recommendTemplatesForBlock
4
- } from "../chunk-CUYHFOFL.js";
4
+ } from "../chunk-6ATZOUCQ.js";
5
5
  import "../chunk-O7JILDEF.js";
6
6
  export {
7
7
  profileBlockContents,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq",
3
- "version": "2.11.0",
3
+ "version": "2.11.2",
4
4
  "description": "Headless utilities for doc/block rendering, spatial math, Markdown, and storage",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",