@superdoc/mcp 1.7.0-next.7 → 1.7.0-next.8

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.
Files changed (2) hide show
  1. package/dist/index.js +300 -25
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -31600,7 +31600,7 @@ var init_host = __esm(() => {
31600
31600
  });
31601
31601
 
31602
31602
  // ../../packages/sdk/langs/node/src/runtime/sdk-version.generated.ts
31603
- var SDK_VERSION = "2.20.0-next.7";
31603
+ var SDK_VERSION = "2.20.0-next.8";
31604
31604
 
31605
31605
  // ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
31606
31606
  import { accessSync, chmodSync, constants, existsSync, statSync } from "node:fs";
@@ -107235,10 +107235,17 @@ var init_sd_fragment_schema = __esm(() => {
107235
107235
  bottom: { type: "number", minimum: 0 },
107236
107236
  left: { type: "number", minimum: 0 }
107237
107237
  }),
107238
+ SDInboundCellBorders: objectSchema({
107239
+ top: { type: "string" },
107240
+ right: { type: "string" },
107241
+ bottom: { type: "string" },
107242
+ left: { type: "string" }
107243
+ }),
107238
107244
  SDInboundCellProps: objectSchema({
107239
107245
  verticalAlign: { enum: ["top", "center", "bottom"] },
107240
107246
  shading: ref("SDInboundColor"),
107241
- padding: ref("SDInboundCellPadding")
107247
+ padding: ref("SDInboundCellPadding"),
107248
+ borders: ref("SDInboundCellBorders")
107242
107249
  }),
107243
107250
  SDInboundRun: objectSchema({
107244
107251
  ...idProperty,
@@ -195776,13 +195783,13 @@ function renderPasteTableBlock(spec) {
195776
195783
  const columnWidth = Math.max(1, Math.floor(PASTE_TABLE_GRID_TWIPS / columnCount));
195777
195784
  const grid = `<w:tblGrid>${`<w:gridCol w:w="${columnWidth}"/>`.repeat(columnCount)}</w:tblGrid>`;
195778
195785
  const rows = renderPasteTableRows(spec);
195779
- return `<w:tbl>${renderPasteTableProperties(spec.styleRef, spec.cellSpacingPt)}${grid}${rows}</w:tbl>`;
195786
+ return `<w:tbl>${renderPasteTableProperties(spec)}${grid}${rows}</w:tbl>`;
195780
195787
  }
195781
195788
  function renderTrackedPasteTableBlock(spec, stamp) {
195782
195789
  const columnCount = tableColumnCount(spec);
195783
195790
  const columnWidth = Math.max(1, Math.floor(PASTE_TABLE_GRID_TWIPS / columnCount));
195784
195791
  const grid = `<w:tblGrid>${`<w:gridCol w:w="${columnWidth}"/>`.repeat(columnCount)}</w:tblGrid>`;
195785
- return `<w:tbl>${renderPasteTableProperties(spec.styleRef, spec.cellSpacingPt)}${grid}${renderTrackedPasteTableRows(spec, stamp)}</w:tbl>`;
195792
+ return `<w:tbl>${renderPasteTableProperties(spec)}${grid}${renderTrackedPasteTableRows(spec, stamp)}</w:tbl>`;
195786
195793
  }
195787
195794
  function renderPasteTableRows(tableSpec) {
195788
195795
  return tableSpec.rows.map((row) => {
@@ -195811,7 +195818,14 @@ function renderPasteTableCell(cell, renderParagraph = renderPasteParagraphBlock,
195811
195818
  ];
195812
195819
  const margins = marginSides.flatMap(([side, points]) => points === undefined ? [] : [`<w:${side} w:w="${Math.round(points * 20)}" w:type="dxa"/>`]).join("");
195813
195820
  const tcMar = margins ? `<w:tcMar>${margins}</w:tcMar>` : "";
195814
- const tcPr = `<w:tcPr><w:tcW w:w="0" w:type="auto"/>` + (gridSpan > 1 ? `<w:gridSpan w:val="${gridSpan}"/>` : "") + shading + tcMar + "</w:tcPr>";
195821
+ const borderSides = ["top", "left", "bottom", "right"];
195822
+ const borders = borderSides.flatMap((side) => {
195823
+ const border = cell.borders?.[side];
195824
+ return border ? [border.lineStyle === "nil" ? `<w:${side} w:val="nil"/>` : `<w:${side} w:val="${escapeXmlAttribute(border.lineStyle)}" w:sz="${Math.max(1, Math.round(border.lineWeightPt * 8))}" w:color="${escapeXmlAttribute(border.color.toUpperCase())}"/>`] : [];
195825
+ }).join("");
195826
+ const tcBorders = borders ? `<w:tcBorders>${borders}</w:tcBorders>` : "";
195827
+ const verticalAlign = cell.verticalAlign ? `<w:vAlign w:val="${cell.verticalAlign}"/>` : "";
195828
+ const tcPr = `<w:tcPr><w:tcW w:w="0" w:type="auto"/>` + (gridSpan > 1 ? `<w:gridSpan w:val="${gridSpan}"/>` : "") + tcBorders + shading + tcMar + verticalAlign + "</w:tcPr>";
195815
195829
  return `<w:tc>${tcPr}${cell.paragraphs.map((block) => ("rows" in block) ? renderTable(block) : renderParagraph(block)).join("")}</w:tc>`;
195816
195830
  }
195817
195831
  function renderPasteRunProperties(run, options) {
@@ -196027,10 +196041,17 @@ function renderTrackedChangeOpen(kind, id, stamp, includeRsid, wordPrefix = "w",
196027
196041
  function tableColumnCount(spec) {
196028
196042
  return Math.max(1, ...spec.rows.map((row) => row.cells.reduce((sum, cell) => sum + Math.max(1, cell.gridSpan ?? 1), 0)));
196029
196043
  }
196030
- function renderPasteTableProperties(styleRef, cellSpacingPt) {
196044
+ function tableHasExplicitlySuppressedBorders(spec) {
196045
+ return spec.rows.length > 0 && spec.rows.every((row) => row.cells.length > 0 && row.cells.every((cell) => ["top", "right", "bottom", "left"].every((side) => {
196046
+ const border = cell.borders?.[side];
196047
+ return border?.lineStyle === "nil" && border.lineWeightPt === 0 && border.color === "auto";
196048
+ })));
196049
+ }
196050
+ function renderPasteTableProperties(spec) {
196051
+ const { styleRef, cellSpacingPt } = spec;
196031
196052
  const border = (name) => `<w:${name} w:val="single" w:sz="4" w:space="0" w:color="auto"/>`;
196032
196053
  const style = styleRef ? `<w:tblStyle w:val="${escapeXmlAttribute(styleRef)}"/>` : "";
196033
- const borders = styleRef ? "" : "<w:tblBorders>" + border("top") + border("left") + border("bottom") + border("right") + border("insideH") + border("insideV") + "</w:tblBorders>";
196054
+ const borders = styleRef || tableHasExplicitlySuppressedBorders(spec) ? "" : "<w:tblBorders>" + border("top") + border("left") + border("bottom") + border("right") + border("insideH") + border("insideV") + "</w:tblBorders>";
196034
196055
  const spacing = cellSpacingPt === undefined ? "" : `<w:tblCellSpacing w:w="${Math.round(cellSpacingPt * 20)}" w:type="dxa"/>`;
196035
196056
  return `<w:tblPr>${style}<w:tblW w:w="5000" w:type="pct"/>${spacing}${borders}</w:tblPr>`;
196036
196057
  }
@@ -227699,6 +227720,8 @@ function pasteTableSpec(block, mintNextParaId, bindW14NamespaceInline, runs = (b
227699
227720
  ...cell.gridSpan !== undefined ? { gridSpan: cell.gridSpan } : {},
227700
227721
  ...cell.shadingColor !== undefined ? { shadingColor: cell.shadingColor } : {},
227701
227722
  ...cell.padding !== undefined ? { padding: cell.padding } : {},
227723
+ ...cell.verticalAlign !== undefined ? { verticalAlign: cell.verticalAlign } : {},
227724
+ ...cell.borders !== undefined ? { borders: cell.borders } : {},
227702
227725
  paragraphs: cell.blocks.map((child) => child.kind === "table" ? pasteTableSpec(child, mintNextParaId, bindW14NamespaceInline, runs) : {
227703
227726
  paraId: mintNextParaId(),
227704
227727
  bindW14NamespaceInline,
@@ -245709,6 +245732,21 @@ function validateBlocks(blocks) {
245709
245732
  if (!hasPaddingSide)
245710
245733
  return { ok: false, reason: "paste-structure-unsupported" };
245711
245734
  }
245735
+ if (cell.verticalAlign !== undefined && !["top", "center", "bottom"].includes(cell.verticalAlign)) {
245736
+ return { ok: false, reason: "paste-structure-unsupported" };
245737
+ }
245738
+ if (cell.borders !== undefined) {
245739
+ if (typeof cell.borders !== "object" || cell.borders === null || Array.isArray(cell.borders)) {
245740
+ return { ok: false, reason: "paste-structure-unsupported" };
245741
+ }
245742
+ for (const side of ["top", "right", "bottom", "left"]) {
245743
+ const border = cell.borders[side];
245744
+ if (border === undefined)
245745
+ continue;
245746
+ if (typeof border !== "object" || border === null || Array.isArray(border) || typeof border.lineStyle !== "string" || (border.lineStyle === "nil" ? border.lineWeightPt !== 0 || border.color !== "auto" : !["single", "dashed", "dotted", "double"].includes(border.lineStyle) || typeof border.lineWeightPt !== "number" || !Number.isFinite(border.lineWeightPt) || border.lineWeightPt <= 0 || !Number.isSafeInteger(Math.round(border.lineWeightPt * 8)) || typeof border.color !== "string" || !/^[0-9A-F]{6}$/i.test(border.color)))
245747
+ return { ok: false, reason: "paste-structure-unsupported" };
245748
+ }
245749
+ }
245712
245750
  budget.blocks += Number(cell.blocks[0]?.kind === "table") + Number(cell.blocks.at(-1)?.kind === "table");
245713
245751
  if (budget.blocks > MAX_PASTE_BLOCKS)
245714
245752
  return { ok: false, reason: "paste-payload-too-large" };
@@ -270802,10 +270840,17 @@ var init_sd_fragment_schema2 = __esm(() => {
270802
270840
  bottom: { type: "number", minimum: 0 },
270803
270841
  left: { type: "number", minimum: 0 }
270804
270842
  }),
270843
+ SDInboundCellBorders: objectSchema3({
270844
+ top: { type: "string" },
270845
+ right: { type: "string" },
270846
+ bottom: { type: "string" },
270847
+ left: { type: "string" }
270848
+ }),
270805
270849
  SDInboundCellProps: objectSchema3({
270806
270850
  verticalAlign: { enum: ["top", "center", "bottom"] },
270807
270851
  shading: ref3("SDInboundColor"),
270808
- padding: ref3("SDInboundCellPadding")
270852
+ padding: ref3("SDInboundCellPadding"),
270853
+ borders: ref3("SDInboundCellBorders")
270809
270854
  }),
270810
270855
  SDInboundRun: objectSchema3({
270811
270856
  ...idProperty2,
@@ -320447,8 +320492,17 @@ function resolvedDeclarations(element, sheet) {
320447
320492
  if (cached2)
320448
320493
  return cached2;
320449
320494
  const winners = new Map;
320495
+ const rejectedBorders = [];
320496
+ const rejectInvalidBorder = (declaration) => {
320497
+ if (!/^border(?:-(?:top|right|bottom|left))?$/.test(declaration.property) || normalizeCellBorder(declaration.value) !== null)
320498
+ return false;
320499
+ rejectedBorders.push(declaration);
320500
+ return true;
320501
+ };
320450
320502
  for (const rule of matchingRules(element, sheet)) {
320451
320503
  for (const declaration of rule.declarations) {
320504
+ if (rejectInvalidBorder(declaration))
320505
+ continue;
320452
320506
  const current = winners.get(declaration.property);
320453
320507
  if (!current || rule.specificity > current.specificity || rule.specificity === current.specificity && declaration.order >= current.order) {
320454
320508
  winners.set(declaration.property, { ...declaration, specificity: rule.specificity });
@@ -320456,11 +320510,15 @@ function resolvedDeclarations(element, sheet) {
320456
320510
  }
320457
320511
  }
320458
320512
  const styleRange = sourceRangeForAttribute(element, "style");
320459
- const inline = parseDeclarations(attributeValue2(element, "style") ?? "", () => Number.MAX_SAFE_INTEGER, styleRange);
320513
+ const inlineCss = attributeValue2(element, "style") ?? "";
320514
+ let inlineOrder = Number.MAX_SAFE_INTEGER - inlineCss.length - 1;
320515
+ const inline = parseDeclarations(inlineCss, () => inlineOrder++, styleRange);
320460
320516
  for (const declaration of inline) {
320517
+ if (rejectInvalidBorder(declaration))
320518
+ continue;
320461
320519
  winners.set(declaration.property, { ...declaration, specificity: 1000 });
320462
320520
  }
320463
- const resolved = [...winners.values()].sort((left, right) => left.order - right.order);
320521
+ const resolved = [...winners.values(), ...rejectedBorders].sort((left, right) => left.order - right.order);
320464
320522
  sheet.resolved.set(element, resolved);
320465
320523
  return resolved;
320466
320524
  }
@@ -320532,6 +320590,12 @@ function parseDeclarations(css, nextOrder, range) {
320532
320590
  if (!property2 || !value2)
320533
320591
  continue;
320534
320592
  const order = nextOrder();
320593
+ if (property2 === "border" && normalizeCellBorder(value2) !== null) {
320594
+ for (const side of ["top", "right", "bottom", "left"]) {
320595
+ declarations.push({ property: `border-${side}`, value: value2, order, ...range ? { range } : {} });
320596
+ }
320597
+ continue;
320598
+ }
320535
320599
  if (property2 === "margin") {
320536
320600
  const tokens = value2.split(/\s+/);
320537
320601
  if (tokens.length >= 1 && tokens.length <= 4) {
@@ -320723,6 +320787,29 @@ function applyCellDeclaration(props, declaration) {
320723
320787
  props.padding = values;
320724
320788
  return true;
320725
320789
  }
320790
+ if (declaration.property === "vertical-align") {
320791
+ const value2 = declaration.value.trim().toLowerCase();
320792
+ if (value2 === "top" || value2 === "bottom")
320793
+ props.verticalAlign = value2;
320794
+ else if (value2 === "middle" || value2 === "center")
320795
+ props.verticalAlign = "center";
320796
+ else
320797
+ return false;
320798
+ return true;
320799
+ }
320800
+ const borderSide = {
320801
+ "border-top": "top",
320802
+ "border-right": "right",
320803
+ "border-bottom": "bottom",
320804
+ "border-left": "left"
320805
+ }[declaration.property];
320806
+ if (declaration.property === "border" || borderSide) {
320807
+ const border = normalizeCellBorder(declaration.value);
320808
+ if (!border)
320809
+ return false;
320810
+ props.borders = declaration.property === "border" ? { top: border, right: border, bottom: border, left: border } : { ...props.borders, [borderSide]: border };
320811
+ return true;
320812
+ }
320726
320813
  const side = {
320727
320814
  "padding-top": "top",
320728
320815
  "padding-right": "right",
@@ -320773,6 +320860,13 @@ function expandBoxLengths(value2) {
320773
320860
  return { top, right, bottom, left };
320774
320861
  }
320775
320862
  function cssLengthToPoints(value2, allowNegative = false) {
320863
+ const points = cssAbsoluteLengthToPoints(value2, allowNegative);
320864
+ if (points === null)
320865
+ return null;
320866
+ const twips = Math.round(points * 20);
320867
+ return Number.isSafeInteger(twips) && Math.abs(points * 20 - twips) <= 0.00000001 ? twips / 20 : null;
320868
+ }
320869
+ function cssAbsoluteLengthToPoints(value2, allowNegative = false) {
320776
320870
  const trimmed = value2.trim();
320777
320871
  if (trimmed === "0")
320778
320872
  return 0;
@@ -320784,7 +320878,50 @@ function cssLengthToPoints(value2, allowNegative = false) {
320784
320878
  return null;
320785
320879
  const factor = { px: 0.75, pt: 1, in: 72, cm: 72 / 2.54, mm: 72 / 25.4, pc: 12 }[match[2].toLowerCase()];
320786
320880
  const points = amount * factor;
320787
- return Number.isFinite(points) && Number.isSafeInteger(points * 20) ? points : null;
320881
+ return Number.isFinite(points) ? points : null;
320882
+ }
320883
+ function normalizeCellBorder(value2) {
320884
+ if (value2.trim().toLowerCase() === "none")
320885
+ return "none";
320886
+ let lineStyle;
320887
+ let lineWeightPt;
320888
+ let zeroWidth = false;
320889
+ let color;
320890
+ for (const token of value2.trim().match(/rgb\([^)]*\)|\S+/gi) ?? []) {
320891
+ const cssStyle = token.toLowerCase();
320892
+ const mappedStyle = { solid: "single", dashed: "dashed", dotted: "dotted", double: "double", none: "nil" }[cssStyle];
320893
+ if (mappedStyle) {
320894
+ if (lineStyle)
320895
+ return null;
320896
+ lineStyle = mappedStyle;
320897
+ continue;
320898
+ }
320899
+ const points = cssAbsoluteLengthToPoints(token);
320900
+ if (points !== null) {
320901
+ if (lineWeightPt !== undefined || zeroWidth)
320902
+ return null;
320903
+ if (!Number.isSafeInteger(Math.round(points * 8)))
320904
+ return null;
320905
+ if (points === 0)
320906
+ zeroWidth = true;
320907
+ else
320908
+ lineWeightPt = points;
320909
+ continue;
320910
+ }
320911
+ const parsedColor = cssColor(token);
320912
+ if (parsedColor?.model === "rgb") {
320913
+ if (color)
320914
+ return null;
320915
+ color = parsedColor.value;
320916
+ continue;
320917
+ }
320918
+ return null;
320919
+ }
320920
+ if (zeroWidth || lineStyle === "nil")
320921
+ return "none";
320922
+ if (!lineStyle || !color)
320923
+ return null;
320924
+ return lineWeightPt !== undefined ? `${lineStyle} ${lineWeightPt}pt #${color}` : null;
320788
320925
  }
320789
320926
  function cssColor(value2) {
320790
320927
  const trimmed = value2.trim();
@@ -320859,9 +320996,15 @@ var init_css = __esm(() => {
320859
320996
  "padding-right",
320860
320997
  "padding-bottom",
320861
320998
  "padding-left",
320862
- "vertical-align"
320999
+ "vertical-align",
321000
+ "border",
321001
+ "border-top",
321002
+ "border-right",
321003
+ "border-bottom",
321004
+ "border-left"
320863
321005
  ]);
320864
321006
  NAMED_COLORS2 = {
321007
+ windowtext: "000000",
320865
321008
  black: "000000",
320866
321009
  silver: "C0C0C0",
320867
321010
  gray: "808080",
@@ -321815,6 +321958,8 @@ function convertTable(table, context, inherited, path6) {
321815
321958
  const suppressedStyleStart = context.suppressedTableStyleDiagnosticCount;
321816
321959
  context.tableStyleAggregationDepth += 1;
321817
321960
  const tableContext = inlineContextForElement(table, context, inherited, path6);
321961
+ const tableCellProps = cellPropsForElement(table, context.sheet, cssContext(context, path6));
321962
+ const tableBorderSuppression = tableCellProps?.borders && ["top", "right", "bottom", "left"].every((side) => tableCellProps.borders?.[side] === "none");
321818
321963
  const convertedRows = [];
321819
321964
  for (const { row, path: rowPath } of rows) {
321820
321965
  const cells = [];
@@ -321828,7 +321973,14 @@ function convertTable(table, context, inherited, path6) {
321828
321973
  const cellContext = inlineContextForElement(cell, context, tableContext, cellPath, undefined, CELL_NON_RUN_CSS);
321829
321974
  const droppedContentStart = context.droppedContentCount;
321830
321975
  const content = convertFlowChildren(cell.childNodes, context, cellContext, cellPath);
321831
- const props = cellPropsForElement(cell, context.sheet, cssContext(context, cellPath));
321976
+ const directProps = cellPropsForElement(cell, context.sheet, cssContext(context, cellPath));
321977
+ const props = tableBorderSuppression ? {
321978
+ ...directProps,
321979
+ borders: {
321980
+ ...tableCellProps.borders,
321981
+ ...directProps?.borders
321982
+ }
321983
+ } : directProps;
321832
321984
  cells.push({
321833
321985
  ...props ? { props } : {},
321834
321986
  ...colSpan !== undefined && colSpan > 1 ? { colSpan } : {},
@@ -336087,7 +336239,7 @@ function emphasizeHeaderCellBlock(block) {
336087
336239
  function lowerCellProperties(props, path7) {
336088
336240
  if (!props)
336089
336241
  return {};
336090
- const supported = new Set(["shading", "padding"]);
336242
+ const supported = new Set(["shading", "padding", "verticalAlign", "borders"]);
336091
336243
  const unsupportedKeys = Object.keys(props).filter((key2) => !supported.has(key2));
336092
336244
  if (unsupportedKeys.length > 0) {
336093
336245
  unsupported4(path7, `Table-cell properties are not materializable: ${unsupportedKeys.sort().join(", ")}.`);
@@ -336105,11 +336257,29 @@ function lowerCellProperties(props, path7) {
336105
336257
  ...props.padding.bottom !== undefined ? { bottomPt: safeScaledNonnegative(props.padding.bottom, 20, [...path7, "padding", "bottom"]) } : {},
336106
336258
  ...props.padding.left !== undefined ? { leftPt: safeScaledNonnegative(props.padding.left, 20, [...path7, "padding", "left"]) } : {}
336107
336259
  } : undefined;
336260
+ const borders = props.borders ? Object.fromEntries(["top", "right", "bottom", "left"].flatMap((side) => {
336261
+ const border = props.borders?.[side];
336262
+ return border ? [[side, lowerCellBorder(border, [...path7, "borders", side])]] : [];
336263
+ })) : undefined;
336108
336264
  return {
336109
336265
  ...shadingColor ? { shadingColor } : {},
336110
- ...padding && Object.keys(padding).length > 0 ? { padding } : {}
336266
+ ...padding && Object.keys(padding).length > 0 ? { padding } : {},
336267
+ ...props.verticalAlign ? { verticalAlign: props.verticalAlign } : {},
336268
+ ...borders && Object.keys(borders).length > 0 ? { borders } : {}
336111
336269
  };
336112
336270
  }
336271
+ function lowerCellBorder(value2, path7) {
336272
+ if (value2 === "none")
336273
+ return { lineStyle: "nil", lineWeightPt: 0, color: "auto" };
336274
+ const match = /^(single|dashed|dotted|double) (\d+(?:\.\d+)?)pt #([0-9A-F]{6})$/.exec(value2);
336275
+ if (!match)
336276
+ unsupported4(path7, "Only normalized solid, dashed, dotted, or double RGB cell borders are materializable.");
336277
+ const lineWeightPt = Number.parseFloat(match[2]);
336278
+ if (!Number.isFinite(lineWeightPt) || lineWeightPt <= 0 || !Number.isSafeInteger(Math.round(lineWeightPt * 8))) {
336279
+ unsupported4(path7, "Cell border weight must produce a positive safe OOXML eighth-point measure.");
336280
+ }
336281
+ return { lineStyle: match[1], lineWeightPt, color: match[3] };
336282
+ }
336113
336283
  function positiveInteger(value2, path7) {
336114
336284
  if (!Number.isSafeInteger(value2) || value2 < 1 || value2 > MAX_SIGNED_32_BIT_INTEGER4) {
336115
336285
  invalid3(path7, "Value must be a positive signed 32-bit integer.");
@@ -337374,6 +337544,43 @@ function normalizeTableBlock(block, index2, version2) {
337374
337544
  return fail4("Paste table cell padding requires at least one side.");
337375
337545
  padding = normalized;
337376
337546
  }
337547
+ let verticalAlign;
337548
+ if (cell.verticalAlign !== undefined) {
337549
+ if (cell.verticalAlign !== "top" && cell.verticalAlign !== "center" && cell.verticalAlign !== "bottom") {
337550
+ return fail4("Paste table cell verticalAlign must be top, center, or bottom.");
337551
+ }
337552
+ verticalAlign = cell.verticalAlign;
337553
+ }
337554
+ let borders;
337555
+ if (cell.borders !== undefined) {
337556
+ if (!isRecord14(cell.borders))
337557
+ return fail4("Paste table cell borders must be an object.");
337558
+ const normalized = {};
337559
+ let hasSide = false;
337560
+ for (const side of ["top", "right", "bottom", "left"]) {
337561
+ const border = cell.borders[side];
337562
+ if (border === undefined)
337563
+ continue;
337564
+ if (!isRecord14(border))
337565
+ return fail4(`Paste table cell borders.${side} must be a supported RGB OOXML border.`);
337566
+ const isExplicitNone = border.lineStyle === "nil" && border.lineWeightPt === 0 && border.color === "auto";
337567
+ if (isExplicitNone) {
337568
+ normalized[side] = { lineStyle: "nil", lineWeightPt: 0, color: "auto" };
337569
+ } else {
337570
+ if (typeof border.lineStyle !== "string" || !["single", "dashed", "dotted", "double"].includes(border.lineStyle) || typeof border.lineWeightPt !== "number" || !Number.isFinite(border.lineWeightPt) || border.lineWeightPt <= 0 || !Number.isSafeInteger(Math.round(border.lineWeightPt * 8)) || typeof border.color !== "string" || !/^[0-9a-f]{6}$/i.test(border.color))
337571
+ return fail4(`Paste table cell borders.${side} must be a supported RGB OOXML border.`);
337572
+ normalized[side] = {
337573
+ lineStyle: border.lineStyle,
337574
+ lineWeightPt: border.lineWeightPt,
337575
+ color: border.color.toUpperCase()
337576
+ };
337577
+ }
337578
+ hasSide = true;
337579
+ }
337580
+ if (!hasSide)
337581
+ return fail4("Paste table cell borders requires at least one side.");
337582
+ borders = normalized;
337583
+ }
337377
337584
  const cellBlocks = [];
337378
337585
  for (const [cellBlockIndex, cellBlock] of cell.blocks.entries()) {
337379
337586
  const paragraph3 = normalizeParagraphBlock(cellBlock, ["blocks", index2, "rows", rowIndex, "cells", cellIndex, "blocks", cellBlockIndex], version2, false);
@@ -337389,6 +337596,8 @@ function normalizeTableBlock(block, index2, version2) {
337389
337596
  ...cell.gridSpan !== undefined ? { gridSpan: cell.gridSpan } : {},
337390
337597
  ...shadingColor ? { shadingColor } : {},
337391
337598
  ...padding ? { padding } : {},
337599
+ ...verticalAlign ? { verticalAlign } : {},
337600
+ ...borders ? { borders } : {},
337392
337601
  ...cellSourcePath ? { sourcePath: cellSourcePath } : {}
337393
337602
  });
337394
337603
  }
@@ -339626,18 +339835,17 @@ function readParagraphProperties2(paragraphXml) {
339626
339835
  };
339627
339836
  }
339628
339837
  function readCellFormattingForParagraph(bytes, catalog, paragraphByteStart, notes) {
339629
- const cell = catalog.tables.flatMap((table) => table.rows).flatMap((row) => row.cells).find((candidate2) => paragraphByteStart >= candidate2.cellByteStart && paragraphByteStart < candidate2.cellByteEnd);
339630
- if (!cell)
339631
- return {};
339632
- const cellXml = SERIALIZE_TD.decode(bytes.subarray(cell.cellByteStart, cell.cellByteEnd));
339633
- const tcPrMatch = /<(?:[\w.-]+:)?tcPr\b(?:[^>]*\/>|[^>]*>[\s\S]*?<\/(?:[\w.-]+:)?tcPr\s*>)/.exec(cellXml);
339634
- if (!tcPrMatch)
339838
+ const location2 = catalog.tables.flatMap((table2) => table2.rows.flatMap((row2) => row2.cells.map((cell2) => ({ table: table2, row: row2, cell: cell2 })))).find(({ cell: cell2 }) => paragraphByteStart >= cell2.cellByteStart && paragraphByteStart < cell2.cellByteEnd);
339839
+ if (!location2)
339635
339840
  return {};
339636
- let tcPr = tcPrMatch[0];
339637
- if (/<(?:[\w.-]+:)?tcPrChange\b/.test(tcPr)) {
339638
- tcPr = tcPr.replace(/<(?:[\w.-]+:)?tcPrChange\b(?:[^>]*\/>|[^>]*>[\s\S]*?<\/(?:[\w.-]+:)?tcPrChange\s*>)/g, "");
339841
+ const { table, row, cell } = location2;
339842
+ const originalCellXml = SERIALIZE_TD.decode(bytes.subarray(cell.cellByteStart, cell.cellByteEnd));
339843
+ const cellXml = originalCellXml.replace(/<(?:[\w.-]+:)?tcPrChange\b(?:[^>]*\/>|[^>]*>[\s\S]*?<\/(?:[\w.-]+:)?tcPrChange\s*>)/g, "");
339844
+ if (cellXml !== originalCellXml) {
339639
339845
  notes.add("tcprchange", "Tracked table-cell formatting history is not preserved by copy.", "info");
339640
339846
  }
339847
+ const tcPrMatch = /<(?:[\w.-]+:)?tcPr\b(?:[^>]*\/>|[^>]*>[\s\S]*?<\/(?:[\w.-]+:)?tcPr\s*>)/.exec(cellXml);
339848
+ const tcPr = tcPrMatch?.[0] ?? "";
339641
339849
  let shadingColor;
339642
339850
  const shadingAttrs = /<(?:[\w.-]+:)?shd\b([^>]*)\/>/.exec(tcPr)?.[1];
339643
339851
  if (shadingAttrs !== undefined) {
@@ -339647,6 +339855,57 @@ function readCellFormattingForParagraph(bytes, catalog, paragraphByteStart, note
339647
339855
  else
339648
339856
  notes.add("cell-shading", "Theme or non-solid table-cell shading is not preserved by copy.");
339649
339857
  }
339858
+ const verticalAlignValue = /<(?:[\w.-]+:)?vAlign\b([^>]*)\/?>(?:<\/(?:[\w.-]+:)?vAlign>)?/.exec(tcPr)?.[1];
339859
+ const verticalAlignRaw = verticalAlignValue ? /\b(?:[\w.-]+:)?val\s*=\s*["']([^"']+)["']/.exec(verticalAlignValue)?.[1] : undefined;
339860
+ const verticalAlign = verticalAlignRaw === "top" || verticalAlignRaw === "center" || verticalAlignRaw === "bottom" ? verticalAlignRaw : undefined;
339861
+ if (verticalAlignRaw && !verticalAlign) {
339862
+ notes.add("cell-vertical-alignment", "Unsupported table-cell vertical alignment is not preserved by copy.", "info");
339863
+ }
339864
+ const borders = {};
339865
+ const parseBorder2 = (attrs) => {
339866
+ const value2 = /\b(?:[\w.-]+:)?val\s*=\s*["']([^"']+)["']/.exec(attrs)?.[1];
339867
+ if (value2 === "nil" || value2 === "none")
339868
+ return { lineStyle: "nil", lineWeightPt: 0, color: "auto" };
339869
+ const rawColor = /\b(?:[\w.-]+:)?color\s*=\s*["']([^"']+)["']/.exec(attrs)?.[1];
339870
+ const color2 = rawColor === undefined || rawColor === "auto" ? "000000" : rawColor;
339871
+ const size = /\b(?:[\w.-]+:)?sz\s*=\s*["']([^"']+)["']/.exec(attrs)?.[1];
339872
+ const sizeInEighthPoints = size === undefined ? NaN : Number(size);
339873
+ if (size?.trim() && sizeInEighthPoints === 0 && (value2 === "single" || value2 === "dashed" || value2 === "dotted" || value2 === "double")) {
339874
+ return { lineStyle: "nil", lineWeightPt: 0, color: "auto" };
339875
+ }
339876
+ if ((value2 === "single" || value2 === "dashed" || value2 === "dotted" || value2 === "double") && color2 !== undefined && /^[0-9a-f]{6}$/i.test(color2) && Number.isSafeInteger(sizeInEighthPoints) && sizeInEighthPoints > 0)
339877
+ return { lineStyle: value2, lineWeightPt: sizeInEighthPoints / 8, color: color2.toUpperCase() };
339878
+ notes.add("cell-borders", "Unsupported table-cell border is not preserved by copy.", "info");
339879
+ return;
339880
+ };
339881
+ const readBorders = (container, sides) => Object.fromEntries(sides.flatMap((side) => {
339882
+ const attrs = new RegExp(`<(?:[\\w.-]+:)?${side}\\b([^>]*)\\/?>(?:<\\/(?:[\\w.-]+:)?${side}>)?`).exec(container)?.[1];
339883
+ const border = attrs ? parseBorder2(attrs) : undefined;
339884
+ return border ? [[side, border]] : [];
339885
+ }));
339886
+ const tcBorders = /<(?:[\w.-]+:)?tcBorders\b(?:[^>]*\/>|[^>]*>[\s\S]*?<\/(?:[\w.-]+:)?tcBorders\s*>)/.exec(tcPr)?.[0];
339887
+ Object.assign(borders, tcBorders ? readBorders(tcBorders, ["top", "right", "bottom", "left"]) : {});
339888
+ const tableXml = SERIALIZE_TD.decode(bytes.subarray(table.tableByteStart, table.tableByteEnd)).replace(/<(?:[\w.-]+:)?tblPrChange\b(?:[^>]*\/>|[^>]*>[\s\S]*?<\/(?:[\w.-]+:)?tblPrChange\s*>)/g, "");
339889
+ const tblPr = /<(?:[\w.-]+:)?tblPr\b(?:[^>]*\/>|[^>]*>[\s\S]*?<\/(?:[\w.-]+:)?tblPr\s*>)/.exec(tableXml)?.[0];
339890
+ const tblBorders = tblPr && /<(?:[\w.-]+:)?tblBorders\b(?:[^>]*\/>|[^>]*>[\s\S]*?<\/(?:[\w.-]+:)?tblBorders\s*>)/.exec(tblPr)?.[0];
339891
+ if (tblBorders) {
339892
+ const tableBorders = readBorders(tblBorders, ["top", "right", "bottom", "left", "insideH", "insideV"]);
339893
+ const columnCount = Math.max(table.gridColumnCount, ...table.rows.map((candidate2) => candidate2.gridCellCount));
339894
+ const atTop = row.rowIndex === 0;
339895
+ const atBottom = row.rowIndex === table.rows.length - 1;
339896
+ const atLeft = cell.gridColumnStart === 0;
339897
+ const atRight = cell.gridColumnStart + cell.gridSpan >= columnCount;
339898
+ const fallbackEdges = {
339899
+ top: tableBorders[atTop ? "top" : "insideH"],
339900
+ right: tableBorders[atRight ? "right" : "insideV"],
339901
+ bottom: tableBorders[atBottom ? "bottom" : "insideH"],
339902
+ left: tableBorders[atLeft ? "left" : "insideV"]
339903
+ };
339904
+ for (const side of ["top", "right", "bottom", "left"]) {
339905
+ if (borders[side] === undefined && fallbackEdges[side] !== undefined)
339906
+ borders[side] = fallbackEdges[side];
339907
+ }
339908
+ }
339650
339909
  const padding = {};
339651
339910
  const tcMar = /<(?:[\w.-]+:)?tcMar\b(?:[^>]*\/>|[^>]*>[\s\S]*?<\/(?:[\w.-]+:)?tcMar\s*>)/.exec(tcPr)?.[0];
339652
339911
  if (tcMar) {
@@ -339668,7 +339927,9 @@ function readCellFormattingForParagraph(bytes, catalog, paragraphByteStart, note
339668
339927
  }
339669
339928
  return {
339670
339929
  ...shadingColor ? { shadingColor } : {},
339671
- ...Object.keys(padding).length > 0 ? { padding } : {}
339930
+ ...Object.keys(padding).length > 0 ? { padding } : {},
339931
+ ...verticalAlign ? { verticalAlign } : {},
339932
+ ...Object.keys(borders).length > 0 ? { borders } : {}
339672
339933
  };
339673
339934
  }
339674
339935
  function readTableCellSpacingForParagraph(bytes, catalog, paragraphByteStart, notes) {
@@ -339727,6 +339988,8 @@ function groupTableBlocks(blocks) {
339727
339988
  ...coord.gridSpan !== undefined ? { gridSpan: coord.gridSpan } : {},
339728
339989
  ...coord.shadingColor !== undefined ? { shadingColor: coord.shadingColor } : {},
339729
339990
  ...coord.padding !== undefined ? { padding: coord.padding } : {},
339991
+ ...coord.verticalAlign !== undefined ? { verticalAlign: coord.verticalAlign } : {},
339992
+ ...coord.borders !== undefined ? { borders: coord.borders } : {},
339730
339993
  blocks: []
339731
339994
  };
339732
339995
  row.cells.push(cell);
@@ -339808,6 +340071,8 @@ function fragmentBlockFor(grouped) {
339808
340071
  ...cell.gridSpan !== undefined ? { gridSpan: cell.gridSpan } : {},
339809
340072
  ...cell.shadingColor !== undefined ? { shadingColor: cell.shadingColor } : {},
339810
340073
  ...cell.padding !== undefined ? { padding: cell.padding } : {},
340074
+ ...cell.verticalAlign !== undefined ? { verticalAlign: cell.verticalAlign } : {},
340075
+ ...cell.borders !== undefined ? { borders: cell.borders } : {},
339811
340076
  blocks: cell.blocks.map(paragraphFragmentFor)
339812
340077
  }))
339813
340078
  }))
@@ -339825,6 +340090,8 @@ function richFragmentBlockFor(grouped) {
339825
340090
  ...cell.gridSpan !== undefined ? { gridSpan: cell.gridSpan } : {},
339826
340091
  ...cell.shadingColor !== undefined ? { shadingColor: cell.shadingColor } : {},
339827
340092
  ...cell.padding !== undefined ? { padding: cell.padding } : {},
340093
+ ...cell.verticalAlign !== undefined ? { verticalAlign: cell.verticalAlign } : {},
340094
+ ...cell.borders !== undefined ? { borders: cell.borders } : {},
339828
340095
  blocks: cell.blocks.map(richParagraphFragmentFor)
339829
340096
  }))
339830
340097
  }))
@@ -339918,6 +340185,14 @@ function tableCellHtmlStyle(cell) {
339918
340185
  const styles = [];
339919
340186
  if (cell.shadingColor)
339920
340187
  styles.push(`background-color: #${cell.shadingColor}`);
340188
+ if (cell.verticalAlign)
340189
+ styles.push(`vertical-align: ${cell.verticalAlign === "center" ? "middle" : cell.verticalAlign}`);
340190
+ for (const side of ["top", "right", "bottom", "left"]) {
340191
+ const border = cell.borders?.[side];
340192
+ if (!border)
340193
+ continue;
340194
+ styles.push(border.lineStyle === "nil" ? `border-${side}: none` : `border-${side}: ${border.lineStyle === "single" ? "solid" : border.lineStyle} ${border.lineWeightPt}pt #${border.color}`);
340195
+ }
339921
340196
  const padding = cell.padding;
339922
340197
  if (padding) {
339923
340198
  const sides = [padding.topPt, padding.rightPt, padding.bottomPt, padding.leftPt];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superdoc/mcp",
3
- "version": "1.7.0-next.7",
3
+ "version": "1.7.0-next.8",
4
4
  "description": "Model Context Protocol server for SuperDoc, giving an AI agent tools to read and edit .docx files.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0",
@@ -24,13 +24,13 @@
24
24
  ],
25
25
  "dependencies": {
26
26
  "@modelcontextprotocol/sdk": "^1.26.0",
27
- "@superdoc/sdk": "2.20.0-next.7",
27
+ "@superdoc/sdk": "2.20.0-next.8",
28
28
  "debug": "^4.4.3",
29
29
  "zod": "^4.3.6"
30
30
  },
31
31
  "devDependencies": {
32
- "superdoc": "2.23.0-next.7",
33
- "@superdoc/docx-engine": "0.22.0-next.7",
32
+ "superdoc": "2.23.0-next.8",
33
+ "@superdoc/docx-engine": "0.22.0-next.8",
34
34
  "@superdoc/document-api": "0.1.0-alpha.0",
35
35
  "@types/bun": "^1.3.8",
36
36
  "@types/node": "22.19.2",