@scrider/formatter 1.8.1 → 1.8.3
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 +175 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +204 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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,10 +564,44 @@ 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) : "";
|
|
548
|
-
|
|
602
|
+
const rowHeight = data.rowHeights?.[row];
|
|
603
|
+
const trStyle = rowHeight !== void 0 && rowHeight > 0 ? ` style="height: ${rowHeight}px"` : "";
|
|
604
|
+
let html = `${ind(2)}<tr${trStyle}>${nl}`;
|
|
549
605
|
for (let c = 0; c < cols; c++) {
|
|
550
606
|
const key = `${row}:${c}`;
|
|
551
607
|
const cell = data.cells[key];
|
|
@@ -559,11 +615,16 @@ function renderExtendedRow(data, row, cols, defaultCellTag, context, pretty) {
|
|
|
559
615
|
if (cell.rowspan && cell.rowspan > 1) {
|
|
560
616
|
attrs.push(`rowspan="${cell.rowspan}"`);
|
|
561
617
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
}
|
|
618
|
+
const colDefault = data.colAligns?.[c] ?? "left";
|
|
619
|
+
const effectiveAlign = resolveCellHorizontalAlign(cell, c, data.colAligns);
|
|
620
|
+
let alignStyle = null;
|
|
621
|
+
if (effectiveAlign !== "left") {
|
|
622
|
+
alignStyle = `text-align: ${effectiveAlign}`;
|
|
623
|
+
} else if (cell.align === "left" && colDefault !== "left") {
|
|
624
|
+
alignStyle = "text-align: left";
|
|
625
|
+
}
|
|
626
|
+
if (alignStyle) {
|
|
627
|
+
attrs.push(`style="${alignStyle}"`);
|
|
567
628
|
}
|
|
568
629
|
const attrStr = attrs.length > 0 ? " " + attrs.join(" ") : "";
|
|
569
630
|
let content = "";
|
|
@@ -579,6 +640,12 @@ function isGfmCompatible(data) {
|
|
|
579
640
|
if (data.colWidths && data.colWidths.some((w) => w > 0)) {
|
|
580
641
|
return false;
|
|
581
642
|
}
|
|
643
|
+
if (data.rowHeights && data.rowHeights.some((h) => h > 0)) {
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
for (const cell of Object.values(data.cells)) {
|
|
647
|
+
if (cell !== null && cell.align !== void 0) return false;
|
|
648
|
+
}
|
|
582
649
|
for (const cell of Object.values(data.cells)) {
|
|
583
650
|
if (cell === null) return false;
|
|
584
651
|
if (cell.colspan && cell.colspan > 1) return false;
|
|
@@ -688,15 +755,62 @@ function extractColWidths(table) {
|
|
|
688
755
|
}
|
|
689
756
|
return void 0;
|
|
690
757
|
}
|
|
758
|
+
function extractRowHeightPx(row) {
|
|
759
|
+
const style = row.getAttribute("style") || "";
|
|
760
|
+
const heightMatch = style.match(/(?:^|;)\s*height:\s*([\d.]+)px/i);
|
|
761
|
+
if (heightMatch?.[1]) {
|
|
762
|
+
const n = parseFloat(heightMatch[1]);
|
|
763
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
764
|
+
}
|
|
765
|
+
const minHeightMatch = style.match(/(?:^|;)\s*min-height:\s*([\d.]+)px/i);
|
|
766
|
+
if (minHeightMatch?.[1]) {
|
|
767
|
+
const n = parseFloat(minHeightMatch[1]);
|
|
768
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
769
|
+
}
|
|
770
|
+
const heightAttr = row.getAttribute("height");
|
|
771
|
+
if (heightAttr) {
|
|
772
|
+
const n = parseFloat(heightAttr);
|
|
773
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
774
|
+
}
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
function extractRowHeights(rows) {
|
|
778
|
+
const heights = [];
|
|
779
|
+
let any = false;
|
|
780
|
+
for (const row of rows) {
|
|
781
|
+
const h = extractRowHeightPx(row);
|
|
782
|
+
if (h != null) {
|
|
783
|
+
heights.push(h);
|
|
784
|
+
any = true;
|
|
785
|
+
} else {
|
|
786
|
+
heights.push(0);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return any ? heights : void 0;
|
|
790
|
+
}
|
|
691
791
|
function extractCellAlign(cell) {
|
|
692
|
-
const
|
|
693
|
-
if (
|
|
694
|
-
|
|
792
|
+
const direct = extractInlineHorizontalAlign(cell);
|
|
793
|
+
if (direct) return direct;
|
|
794
|
+
const children = cell.childNodes;
|
|
795
|
+
for (let i = 0; i < children.length; i++) {
|
|
796
|
+
const child = children[i];
|
|
797
|
+
if (!child || !isElement(child)) continue;
|
|
798
|
+
const tag = child.tagName.toLowerCase();
|
|
799
|
+
if (tag === "p" || tag === "div") {
|
|
800
|
+
const align = extractInlineHorizontalAlign(child);
|
|
801
|
+
if (align) return align;
|
|
802
|
+
}
|
|
695
803
|
}
|
|
696
|
-
|
|
697
|
-
|
|
804
|
+
return null;
|
|
805
|
+
}
|
|
806
|
+
function extractInlineHorizontalAlign(element) {
|
|
807
|
+
const textAlign = element.style?.textAlign || element.style?.getPropertyValue?.("text-align");
|
|
808
|
+
const fromStyle = parseHorizontalAlign(textAlign);
|
|
809
|
+
if (fromStyle) return fromStyle;
|
|
810
|
+
const style = element.getAttribute("style") || "";
|
|
811
|
+
const match = style.match(/text-align:\s*(left|center|right|justify)/i);
|
|
698
812
|
if (match?.[1]) {
|
|
699
|
-
return match[1];
|
|
813
|
+
return parseHorizontalAlign(match[1]);
|
|
700
814
|
}
|
|
701
815
|
return null;
|
|
702
816
|
}
|
|
@@ -705,6 +819,7 @@ function parseTableElement(table, context) {
|
|
|
705
819
|
if (rows.length === 0) return null;
|
|
706
820
|
const cells = {};
|
|
707
821
|
const colAligns = [];
|
|
822
|
+
const rawAligns = {};
|
|
708
823
|
let maxCol = 0;
|
|
709
824
|
let firstRowProcessed = false;
|
|
710
825
|
const occupied = /* @__PURE__ */ new Set();
|
|
@@ -733,10 +848,20 @@ function parseTableElement(table, context) {
|
|
|
733
848
|
} else {
|
|
734
849
|
ops = [{ insert: "\n" }];
|
|
735
850
|
}
|
|
736
|
-
|
|
851
|
+
let cellData = { ops };
|
|
737
852
|
if (colspan > 1) cellData.colspan = colspan;
|
|
738
853
|
if (rowspan > 1) cellData.rowspan = rowspan;
|
|
739
|
-
|
|
854
|
+
cellData = promoteAlignFromCellOps(cellData);
|
|
855
|
+
const htmlAlign = extractCellAlign(cell);
|
|
856
|
+
const effectiveAlign = htmlAlign ?? cellData.align ?? "left";
|
|
857
|
+
if (cellData.align !== void 0) {
|
|
858
|
+
const withoutAlign = { ...cellData };
|
|
859
|
+
delete withoutAlign.align;
|
|
860
|
+
cellData = withoutAlign;
|
|
861
|
+
}
|
|
862
|
+
const cellKey = `${rowIdx}:${colIdx}`;
|
|
863
|
+
cells[cellKey] = cellData;
|
|
864
|
+
rawAligns[cellKey] = effectiveAlign;
|
|
740
865
|
for (let dr = 0; dr < rowspan; dr++) {
|
|
741
866
|
for (let dc = 0; dc < colspan; dc++) {
|
|
742
867
|
if (dr === 0 && dc === 0) continue;
|
|
@@ -750,8 +875,9 @@ function parseTableElement(table, context) {
|
|
|
750
875
|
}
|
|
751
876
|
if (!firstRowProcessed) {
|
|
752
877
|
const align = extractCellAlign(cell);
|
|
878
|
+
const colAlign = align === "center" || align === "right" ? align : null;
|
|
753
879
|
for (let dc = 0; dc < colspan; dc++) {
|
|
754
|
-
colAligns.push(
|
|
880
|
+
colAligns.push(colAlign);
|
|
755
881
|
}
|
|
756
882
|
}
|
|
757
883
|
const cellEndCol = colIdx + colspan - 1;
|
|
@@ -787,11 +913,31 @@ function parseTableElement(table, context) {
|
|
|
787
913
|
if (colWidths.length > totalCols) colWidths.length = totalCols;
|
|
788
914
|
result.colWidths = colWidths;
|
|
789
915
|
}
|
|
916
|
+
const rowHeights = extractRowHeights(rows);
|
|
917
|
+
if (rowHeights) {
|
|
918
|
+
while (rowHeights.length < totalRows) rowHeights.push(0);
|
|
919
|
+
if (rowHeights.length > totalRows) rowHeights.length = totalRows;
|
|
920
|
+
if (rowHeights.some((h) => h > 0)) {
|
|
921
|
+
result.rowHeights = rowHeights;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
790
924
|
if (colAligns.length > 0 && colAligns.some((a) => a !== null)) {
|
|
791
925
|
while (colAligns.length < totalCols) colAligns.push(null);
|
|
792
926
|
if (colAligns.length > totalCols) colAligns.length = totalCols;
|
|
793
927
|
result.colAligns = colAligns;
|
|
794
928
|
}
|
|
929
|
+
for (let r = 0; r < totalRows; r++) {
|
|
930
|
+
for (let c = 0; c < totalCols; c++) {
|
|
931
|
+
const key = `${r}:${c}`;
|
|
932
|
+
const cell = result.cells[key];
|
|
933
|
+
if (cell == null) continue;
|
|
934
|
+
const colDefault = result.colAligns?.[c] ?? "left";
|
|
935
|
+
const effective = rawAligns[key] ?? "left";
|
|
936
|
+
if (effective !== colDefault) {
|
|
937
|
+
result.cells[key] = { ...cell, align: effective };
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
795
941
|
return result;
|
|
796
942
|
}
|
|
797
943
|
var tableBlockHandler = {
|
|
@@ -834,6 +980,14 @@ var tableBlockHandler = {
|
|
|
834
980
|
if (typeof w !== "number" || w < 0) return false;
|
|
835
981
|
}
|
|
836
982
|
}
|
|
983
|
+
if (data.rowHeights !== void 0) {
|
|
984
|
+
if (!Array.isArray(data.rowHeights) || data.rowHeights.length !== rows) {
|
|
985
|
+
return false;
|
|
986
|
+
}
|
|
987
|
+
for (const h of data.rowHeights) {
|
|
988
|
+
if (typeof h !== "number" || h < 0) return false;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
837
991
|
if (data.colAligns !== void 0) {
|
|
838
992
|
if (!Array.isArray(data.colAligns) || data.colAligns.length !== cols) {
|
|
839
993
|
return false;
|
|
@@ -903,8 +1057,11 @@ var tableBlockHandler = {
|
|
|
903
1057
|
for (const [key, cell] of Object.entries(data.cells)) {
|
|
904
1058
|
if (cell !== null) {
|
|
905
1059
|
const normalized = normalizeDelta(new import_delta2.Delta(cell.ops), registry);
|
|
906
|
-
|
|
907
|
-
|
|
1060
|
+
const promoted = promoteAlignFromCellOps(
|
|
1061
|
+
normalized.ops !== cell.ops ? { ...cell, ops: normalized.ops } : cell
|
|
1062
|
+
);
|
|
1063
|
+
if (promoted.ops !== cell.ops || promoted.align !== cell.align) {
|
|
1064
|
+
newCells[key] = promoted;
|
|
908
1065
|
changed = true;
|
|
909
1066
|
} else {
|
|
910
1067
|
newCells[key] = cell;
|