@scrider/formatter 1.8.1 → 1.8.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.
package/dist/index.cjs CHANGED
@@ -492,6 +492,13 @@ function isTextNode(node) {
492
492
  }
493
493
 
494
494
  // src/schema/blocks/table.ts
495
+ var VALID_CELL_HORIZONTAL_ALIGNS = [
496
+ "left",
497
+ "center",
498
+ "right",
499
+ "justify"
500
+ ];
501
+ var VALID_CELL_VERTICAL_ALIGNS = ["top", "middle", "bottom"];
495
502
  var CELL_KEY_RE = /^(\d+):(\d+)$/;
496
503
  function parseCellKey(key) {
497
504
  const match = CELL_KEY_RE.exec(key);
@@ -512,7 +519,22 @@ function getGridDimensions(cells) {
512
519
  return [maxRow + 1, maxCol + 1];
513
520
  }
514
521
  function isValidCellData(cell) {
515
- return typeof cell === "object" && cell !== null && Array.isArray(cell.ops) && cell.ops.length > 0 && (cell.colspan === void 0 || Number.isInteger(cell.colspan) && cell.colspan >= 1) && (cell.rowspan === void 0 || Number.isInteger(cell.rowspan) && cell.rowspan >= 1);
522
+ if (typeof cell !== "object" || cell === null || !Array.isArray(cell.ops) || cell.ops.length === 0) {
523
+ return false;
524
+ }
525
+ if (cell.colspan !== void 0 && (!Number.isInteger(cell.colspan) || cell.colspan < 1)) {
526
+ return false;
527
+ }
528
+ if (cell.rowspan !== void 0 && (!Number.isInteger(cell.rowspan) || cell.rowspan < 1)) {
529
+ return false;
530
+ }
531
+ if (cell.align !== void 0 && !VALID_CELL_HORIZONTAL_ALIGNS.includes(cell.align)) {
532
+ return false;
533
+ }
534
+ if (cell.vAlign !== void 0 && !VALID_CELL_VERTICAL_ALIGNS.includes(cell.vAlign)) {
535
+ return false;
536
+ }
537
+ return true;
516
538
  }
517
539
  function validateMergedCells(cells, rows, cols) {
518
540
  const covered = /* @__PURE__ */ new Set();
@@ -542,6 +564,38 @@ function validateMergedCells(cells, rows, cols) {
542
564
  }
543
565
  return true;
544
566
  }
567
+ function parseHorizontalAlign(value) {
568
+ const normalized = value?.trim().toLowerCase();
569
+ if (normalized === "left" || normalized === "center" || normalized === "right") {
570
+ return normalized;
571
+ }
572
+ if (normalized === "justify") return "justify";
573
+ return null;
574
+ }
575
+ function resolveCellHorizontalAlign(cell, col, colAligns) {
576
+ if (cell.align !== void 0) return cell.align;
577
+ const colAlign = colAligns?.[col];
578
+ if (colAlign) return colAlign;
579
+ return "left";
580
+ }
581
+ function promoteAlignFromCellOps(cell) {
582
+ if (cell.align !== void 0) return cell;
583
+ for (let i = cell.ops.length - 1; i >= 0; i--) {
584
+ const op = cell.ops[i];
585
+ if (!op || !(0, import_delta2.isInsert)(op) || !(0, import_delta2.isTextInsert)(op) || !op.insert.includes("\n")) continue;
586
+ const align = op.attributes?.align;
587
+ const parsed = typeof align === "string" ? parseHorizontalAlign(align) : null;
588
+ if (!parsed) continue;
589
+ const ops = cell.ops.map((item, idx) => {
590
+ if (idx !== i || !(0, import_delta2.isInsert)(item) || item.attributes == null) return item;
591
+ const rest = { ...item.attributes };
592
+ delete rest.align;
593
+ return Object.keys(rest).length > 0 ? { insert: item.insert, attributes: rest } : { insert: item.insert };
594
+ });
595
+ return { ...cell, ops, align: parsed };
596
+ }
597
+ return cell;
598
+ }
545
599
  function renderExtendedRow(data, row, cols, defaultCellTag, context, pretty) {
546
600
  const nl = pretty ? "\n" : "";
547
601
  const ind = (level) => pretty ? " ".repeat(level) : "";
@@ -559,11 +613,16 @@ function renderExtendedRow(data, row, cols, defaultCellTag, context, pretty) {
559
613
  if (cell.rowspan && cell.rowspan > 1) {
560
614
  attrs.push(`rowspan="${cell.rowspan}"`);
561
615
  }
562
- if (data.colAligns) {
563
- const align = data.colAligns[c];
564
- if (align && align !== "left") {
565
- attrs.push(`style="text-align: ${align}"`);
566
- }
616
+ const colDefault = data.colAligns?.[c] ?? "left";
617
+ const effectiveAlign = resolveCellHorizontalAlign(cell, c, data.colAligns);
618
+ let alignStyle = null;
619
+ if (effectiveAlign !== "left") {
620
+ alignStyle = `text-align: ${effectiveAlign}`;
621
+ } else if (cell.align === "left" && colDefault !== "left") {
622
+ alignStyle = "text-align: left";
623
+ }
624
+ if (alignStyle) {
625
+ attrs.push(`style="${alignStyle}"`);
567
626
  }
568
627
  const attrStr = attrs.length > 0 ? " " + attrs.join(" ") : "";
569
628
  let content = "";
@@ -579,6 +638,9 @@ function isGfmCompatible(data) {
579
638
  if (data.colWidths && data.colWidths.some((w) => w > 0)) {
580
639
  return false;
581
640
  }
641
+ for (const cell of Object.values(data.cells)) {
642
+ if (cell !== null && cell.align !== void 0) return false;
643
+ }
582
644
  for (const cell of Object.values(data.cells)) {
583
645
  if (cell === null) return false;
584
646
  if (cell.colspan && cell.colspan > 1) return false;
@@ -689,14 +751,28 @@ function extractColWidths(table) {
689
751
  return void 0;
690
752
  }
691
753
  function extractCellAlign(cell) {
692
- const textAlign = cell.style?.textAlign || cell.style?.getPropertyValue?.("text-align");
693
- if (textAlign === "left" || textAlign === "center" || textAlign === "right") {
694
- return textAlign;
754
+ const direct = extractInlineHorizontalAlign(cell);
755
+ if (direct) return direct;
756
+ const children = cell.childNodes;
757
+ for (let i = 0; i < children.length; i++) {
758
+ const child = children[i];
759
+ if (!child || !isElement(child)) continue;
760
+ const tag = child.tagName.toLowerCase();
761
+ if (tag === "p" || tag === "div") {
762
+ const align = extractInlineHorizontalAlign(child);
763
+ if (align) return align;
764
+ }
695
765
  }
696
- const style = cell.getAttribute("style") || "";
697
- const match = style.match(/text-align:\s*(left|center|right)/);
766
+ return null;
767
+ }
768
+ function extractInlineHorizontalAlign(element) {
769
+ const textAlign = element.style?.textAlign || element.style?.getPropertyValue?.("text-align");
770
+ const fromStyle = parseHorizontalAlign(textAlign);
771
+ if (fromStyle) return fromStyle;
772
+ const style = element.getAttribute("style") || "";
773
+ const match = style.match(/text-align:\s*(left|center|right|justify)/i);
698
774
  if (match?.[1]) {
699
- return match[1];
775
+ return parseHorizontalAlign(match[1]);
700
776
  }
701
777
  return null;
702
778
  }
@@ -705,6 +781,7 @@ function parseTableElement(table, context) {
705
781
  if (rows.length === 0) return null;
706
782
  const cells = {};
707
783
  const colAligns = [];
784
+ const rawAligns = {};
708
785
  let maxCol = 0;
709
786
  let firstRowProcessed = false;
710
787
  const occupied = /* @__PURE__ */ new Set();
@@ -733,10 +810,20 @@ function parseTableElement(table, context) {
733
810
  } else {
734
811
  ops = [{ insert: "\n" }];
735
812
  }
736
- const cellData = { ops };
813
+ let cellData = { ops };
737
814
  if (colspan > 1) cellData.colspan = colspan;
738
815
  if (rowspan > 1) cellData.rowspan = rowspan;
739
- cells[`${rowIdx}:${colIdx}`] = cellData;
816
+ cellData = promoteAlignFromCellOps(cellData);
817
+ const htmlAlign = extractCellAlign(cell);
818
+ const effectiveAlign = htmlAlign ?? cellData.align ?? "left";
819
+ if (cellData.align !== void 0) {
820
+ const withoutAlign = { ...cellData };
821
+ delete withoutAlign.align;
822
+ cellData = withoutAlign;
823
+ }
824
+ const cellKey = `${rowIdx}:${colIdx}`;
825
+ cells[cellKey] = cellData;
826
+ rawAligns[cellKey] = effectiveAlign;
740
827
  for (let dr = 0; dr < rowspan; dr++) {
741
828
  for (let dc = 0; dc < colspan; dc++) {
742
829
  if (dr === 0 && dc === 0) continue;
@@ -750,8 +837,9 @@ function parseTableElement(table, context) {
750
837
  }
751
838
  if (!firstRowProcessed) {
752
839
  const align = extractCellAlign(cell);
840
+ const colAlign = align === "center" || align === "right" ? align : null;
753
841
  for (let dc = 0; dc < colspan; dc++) {
754
- colAligns.push(align);
842
+ colAligns.push(colAlign);
755
843
  }
756
844
  }
757
845
  const cellEndCol = colIdx + colspan - 1;
@@ -792,6 +880,18 @@ function parseTableElement(table, context) {
792
880
  if (colAligns.length > totalCols) colAligns.length = totalCols;
793
881
  result.colAligns = colAligns;
794
882
  }
883
+ for (let r = 0; r < totalRows; r++) {
884
+ for (let c = 0; c < totalCols; c++) {
885
+ const key = `${r}:${c}`;
886
+ const cell = result.cells[key];
887
+ if (cell == null) continue;
888
+ const colDefault = result.colAligns?.[c] ?? "left";
889
+ const effective = rawAligns[key] ?? "left";
890
+ if (effective !== colDefault) {
891
+ result.cells[key] = { ...cell, align: effective };
892
+ }
893
+ }
894
+ }
795
895
  return result;
796
896
  }
797
897
  var tableBlockHandler = {
@@ -903,8 +1003,11 @@ var tableBlockHandler = {
903
1003
  for (const [key, cell] of Object.entries(data.cells)) {
904
1004
  if (cell !== null) {
905
1005
  const normalized = normalizeDelta(new import_delta2.Delta(cell.ops), registry);
906
- if (normalized.ops !== cell.ops) {
907
- newCells[key] = { ...cell, ops: normalized.ops };
1006
+ const promoted = promoteAlignFromCellOps(
1007
+ normalized.ops !== cell.ops ? { ...cell, ops: normalized.ops } : cell
1008
+ );
1009
+ if (promoted.ops !== cell.ops || promoted.align !== cell.align) {
1010
+ newCells[key] = promoted;
908
1011
  changed = true;
909
1012
  } else {
910
1013
  newCells[key] = cell;