@office-open/docx 0.6.2 → 0.6.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.mjs CHANGED
@@ -2004,9 +2004,12 @@ var init_hyperlink = __esmMin((() => {
2004
2004
  };
2005
2005
  ConcreteHyperlink = class extends XmlComponent {
2006
2006
  linkId;
2007
- constructor(children, relationshipId, anchor, tooltip, tgtFrame) {
2007
+ constructor(children, relationshipId, options) {
2008
2008
  super("w:hyperlink");
2009
2009
  this.linkId = relationshipId;
2010
+ const anchor = options?.anchor;
2011
+ const tooltip = options?.tooltip;
2012
+ const tgtFrame = options?.tgtFrame;
2010
2013
  const props = {
2011
2014
  anchor: anchor ? anchor : void 0,
2012
2015
  history: 1,
@@ -2028,7 +2031,10 @@ var init_hyperlink = __esmMin((() => {
2028
2031
  };
2029
2032
  InternalHyperlink = class extends ConcreteHyperlink {
2030
2033
  constructor(options) {
2031
- super(options.children, uniqueId(), options.anchor, options.tooltip);
2034
+ super(options.children, uniqueId(), {
2035
+ anchor: options.anchor,
2036
+ tooltip: options.tooltip
2037
+ });
2032
2038
  }
2033
2039
  };
2034
2040
  ExternalHyperlink = class extends XmlComponent {
@@ -6358,7 +6364,7 @@ var init_paragraph$1 = __esmMin((() => {
6358
6364
  }
6359
6365
  if (this.options.children) for (const rawChild of this.options.children) {
6360
6366
  if (rawChild instanceof ExternalHyperlink) {
6361
- const concreteHyperlink = new ConcreteHyperlink(rawChild.options.children, uniqueId());
6367
+ const concreteHyperlink = new ConcreteHyperlink(rawChild.options.children, uniqueId(), { tooltip: rawChild.options.tooltip });
6362
6368
  context.viewWrapper.Relationships.addRelationship(concreteHyperlink.linkId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", rawChild.options.link, TargetModeType.EXTERNAL);
6363
6369
  const obj = concreteHyperlink.prepForXml(context);
6364
6370
  if (obj) children.push(obj);
@@ -6383,14 +6389,17 @@ var init_paragraph$1 = __esmMin((() => {
6383
6389
  else if ("image" in rawChild) child = new ImageRun(rawChild.image);
6384
6390
  else if (typeof rawChild === "object" && rawChild !== null && "hyperlink" in rawChild) {
6385
6391
  const { hyperlink, ...runOpts } = rawChild;
6386
- const textRun = new TextRun(runOpts);
6392
+ const hlChildren = hyperlink.children;
6393
+ const textRuns = [];
6394
+ if (hlChildren && hlChildren.length > 0) for (const rc of hlChildren) textRuns.push(new TextRun(rc));
6395
+ else textRuns.push(new TextRun(runOpts));
6387
6396
  if ("link" in hyperlink) {
6388
6397
  const ext = new ExternalHyperlink({
6389
6398
  link: hyperlink.link,
6390
6399
  tooltip: hyperlink.tooltip,
6391
- children: [textRun]
6400
+ children: textRuns
6392
6401
  });
6393
- const concrete = new ConcreteHyperlink(ext.options.children, uniqueId());
6402
+ const concrete = new ConcreteHyperlink(ext.options.children, uniqueId(), { tooltip: ext.options.tooltip });
6394
6403
  context.viewWrapper.Relationships.addRelationship(concrete.linkId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", ext.options.link, TargetModeType.EXTERNAL);
6395
6404
  const obj = concrete.prepForXml(context);
6396
6405
  if (obj) children.push(obj);
@@ -6398,7 +6407,7 @@ var init_paragraph$1 = __esmMin((() => {
6398
6407
  const obj = new InternalHyperlink({
6399
6408
  anchor: hyperlink.anchor,
6400
6409
  tooltip: hyperlink.tooltip,
6401
- children: [textRun]
6410
+ children: textRuns
6402
6411
  }).prepForXml(context);
6403
6412
  if (obj) children.push(obj);
6404
6413
  }
@@ -6414,7 +6423,15 @@ var init_paragraph$1 = __esmMin((() => {
6414
6423
  else if ("commentRangeStart" in rawChild) child = new CommentRangeStart(rawChild.commentRangeStart);
6415
6424
  else if ("commentRangeEnd" in rawChild) child = new CommentRangeEnd(rawChild.commentRangeEnd);
6416
6425
  else if ("commentReference" in rawChild) child = new TextRun({ children: [new CommentReference(rawChild.commentReference)] });
6417
- else if ("insertion" in rawChild) child = new InsertedTextRun(rawChild.insertion);
6426
+ else if ("bookmarkStart" in rawChild) {
6427
+ const startObj = new BookmarkStart(rawChild.bookmarkStart.name, rawChild.bookmarkStart.id).prepForXml(context);
6428
+ if (startObj) children.push(startObj);
6429
+ continue;
6430
+ } else if ("bookmarkEnd" in rawChild) {
6431
+ const endObj = new BookmarkEnd(rawChild.bookmarkEnd).prepForXml(context);
6432
+ if (endObj) children.push(endObj);
6433
+ continue;
6434
+ } else if ("insertion" in rawChild) child = new InsertedTextRun(rawChild.insertion);
6418
6435
  else if ("deletion" in rawChild) child = new DeletedTextRun(rawChild.deletion);
6419
6436
  else child = new TextRun(rawChild);
6420
6437
  const obj = child.prepForXml(context);
@@ -15857,7 +15874,7 @@ const patchDocument = async ({ outputType, data, patches, keepOriginalStyles, pl
15857
15874
  ...patchValue,
15858
15875
  children: patchValue.children.map((element) => {
15859
15876
  if (element instanceof ExternalHyperlink) {
15860
- const concreteHyperlink = new ConcreteHyperlink(element.options.children, uniqueId());
15877
+ const concreteHyperlink = new ConcreteHyperlink(element.options.children, uniqueId(), { tooltip: element.options.tooltip });
15861
15878
  hyperlinkRelationshipAdditions.push({
15862
15879
  hyperlink: {
15863
15880
  id: concreteHyperlink.linkId,
@@ -15986,916 +16003,941 @@ const findPatchKeys = (text) => {
15986
16003
  return text.match(/(?<=\{\{).+?(?=\}\})/gs) ?? [];
15987
16004
  };
15988
16005
  //#endregion
15989
- //#region src/file/alt-chunk/alt-chunk-parse.ts
16006
+ //#region src/file/paragraph/run/run-parse.ts
15990
16007
  /**
15991
- * AltChunk parser for DOCX documents.
16008
+ * Run properties parser for DOCX documents.
15992
16009
  *
15993
- * Parses w:altChunk elements and extracts embedded content from the ZIP.
16010
+ * Parses w:rPr Element trees into RunPropertiesOptions objects.
15994
16011
  *
15995
16012
  * @module
15996
16013
  */
15997
16014
  /**
15998
- * Parse a w:altChunk element into AltChunkOptions.
15999
- * Reads the referenced data from the ZIP package.
16015
+ * Parse a w:rPr element into RunPropertiesOptions.
16000
16016
  */
16001
- function parseAltChunk(el, ctx) {
16002
- const rId = attr(el, "r:id");
16003
- if (!rId) throw new Error("w:altChunk missing r:id attribute");
16004
- const path = ctx.docx.partRefs.afChunks.get(rId);
16005
- if (!path) throw new Error(`AltChunk relationship ${rId} not found`);
16006
- const data = ctx.docx.doc.getRaw(path);
16007
- if (!data) throw new Error(`AltChunk data not found at ${path}`);
16008
- const ext = path.split(".").pop() ?? "txt";
16009
- let contentType;
16010
- let extension;
16011
- switch (ext) {
16012
- case "html":
16013
- contentType = "text/html";
16014
- extension = "html";
16015
- break;
16016
- case "rtf":
16017
- contentType = "application/rtf";
16018
- extension = "rtf";
16019
- break;
16020
- default:
16021
- contentType = "text/plain";
16022
- extension = "txt";
16023
- break;
16017
+ function parseRunProperties(el) {
16018
+ const opts = {};
16019
+ const rStyle = findChild(el, "w:rStyle");
16020
+ if (rStyle) opts.style = attr(rStyle, "w:val");
16021
+ const font = findChild(el, "w:rFonts");
16022
+ if (font) {
16023
+ const ascii = attr(font, "w:ascii");
16024
+ const eastAsia = attr(font, "w:eastAsia");
16025
+ const hAnsi = attr(font, "w:hAnsi");
16026
+ const cs = attr(font, "w:cs");
16027
+ const hint = attr(font, "w:hint");
16028
+ if (ascii && !eastAsia && !hAnsi && !cs) opts.font = hint ? {
16029
+ name: ascii,
16030
+ hint
16031
+ } : ascii;
16032
+ else {
16033
+ const fontObj = {};
16034
+ if (ascii) fontObj.ascii = ascii;
16035
+ if (eastAsia) fontObj.eastAsia = eastAsia;
16036
+ if (hAnsi) fontObj.hAnsi = hAnsi;
16037
+ if (cs) fontObj.cs = cs;
16038
+ if (hint) fontObj.hint = hint;
16039
+ opts.font = fontObj;
16040
+ }
16024
16041
  }
16025
- return {
16026
- data,
16027
- contentType,
16028
- extension
16029
- };
16042
+ const bold = findChild(el, "w:b");
16043
+ if (bold) opts.bold = attrBool(bold, "w:val") ?? true;
16044
+ const boldCs = findChild(el, "w:bCs");
16045
+ if (boldCs) opts.boldComplexScript = attrBool(boldCs, "w:val") ?? true;
16046
+ const italics = findChild(el, "w:i");
16047
+ if (italics) opts.italics = attrBool(italics, "w:val") ?? true;
16048
+ const italicsCs = findChild(el, "w:iCs");
16049
+ if (italicsCs) opts.italicsComplexScript = attrBool(italicsCs, "w:val") ?? true;
16050
+ const underline = findChild(el, "w:u");
16051
+ if (underline) {
16052
+ const ul = {};
16053
+ const uType = attr(underline, "w:val");
16054
+ if (uType) ul.type = uType;
16055
+ const uColor = colorAttr(underline, "w:color");
16056
+ if (uColor) ul.color = uColor;
16057
+ opts.underline = ul;
16058
+ }
16059
+ for (const [name, optKey] of [
16060
+ ["w:strike", "strike"],
16061
+ ["w:dstrike", "doubleStrike"],
16062
+ ["w:outline", "outline"],
16063
+ ["w:shadow", "shadow"],
16064
+ ["w:emboss", "emboss"],
16065
+ ["w:imprint", "imprint"],
16066
+ ["w:vanish", "vanish"],
16067
+ ["w:webHidden", "webHidden"],
16068
+ ["w:noProof", "noProof"],
16069
+ ["w:snapToGrid", "snapToGrid"],
16070
+ ["w:smallCaps", "smallCaps"],
16071
+ ["w:caps", "allCaps"],
16072
+ ["w:rtl", "rightToLeft"],
16073
+ ["w:cs", "complexScript"],
16074
+ ["w:specVanish", "specVanish"],
16075
+ ["w:math", "math"]
16076
+ ]) {
16077
+ const child = findChild(el, name);
16078
+ if (child) opts[optKey] = attrBool(child, "w:val") ?? true;
16079
+ }
16080
+ const color = findChild(el, "w:color");
16081
+ if (color) {
16082
+ const c = colorAttr(color, "w:val");
16083
+ if (c) opts.color = c;
16084
+ }
16085
+ const sz = findChild(el, "w:sz");
16086
+ if (sz) {
16087
+ const halfPts = attrNum(sz, "w:val");
16088
+ if (halfPts !== void 0) opts.size = halfPts;
16089
+ }
16090
+ const szCs = findChild(el, "w:szCs");
16091
+ if (szCs) {
16092
+ const halfPts = attrNum(szCs, "w:val");
16093
+ if (halfPts !== void 0) opts.sizeComplexScript = halfPts;
16094
+ }
16095
+ const highlight = findChild(el, "w:highlight");
16096
+ if (highlight) {
16097
+ const val = attr(highlight, "w:val");
16098
+ if (val) opts.highlight = val;
16099
+ }
16100
+ const highlightCs = findChild(el, "w:highlightCs");
16101
+ if (highlightCs) {
16102
+ const val = attr(highlightCs, "w:val");
16103
+ if (val) opts.highlightComplexScript = val;
16104
+ }
16105
+ const vertAlign = findChild(el, "w:vertAlign");
16106
+ if (vertAlign) {
16107
+ const val = attr(vertAlign, "w:val");
16108
+ if (val === "subscript") opts.subScript = true;
16109
+ else if (val === "superscript") opts.superScript = true;
16110
+ }
16111
+ const effect = findChild(el, "w:effect");
16112
+ if (effect) {
16113
+ const val = attr(effect, "w:val");
16114
+ if (val) opts.effect = val;
16115
+ }
16116
+ const emphasisMark = findChild(el, "w:em");
16117
+ if (emphasisMark) {
16118
+ const val = attr(emphasisMark, "w:val");
16119
+ if (val) opts.emphasisMark = { type: val };
16120
+ }
16121
+ const spacing = findChild(el, "w:spacing");
16122
+ if (spacing) {
16123
+ const val = attrNum(spacing, "w:val");
16124
+ if (val !== void 0) opts.characterSpacing = val;
16125
+ }
16126
+ const scale = findChild(el, "w:w");
16127
+ if (scale) {
16128
+ const val = attrNum(scale, "w:val");
16129
+ if (val !== void 0) opts.scale = val;
16130
+ }
16131
+ const kern = findChild(el, "w:kern");
16132
+ if (kern) {
16133
+ const val = attrNum(kern, "w:val");
16134
+ if (val !== void 0) opts.kern = val;
16135
+ }
16136
+ const position = findChild(el, "w:position");
16137
+ if (position) {
16138
+ const val = attr(position, "w:val");
16139
+ if (val !== void 0) opts.position = val;
16140
+ }
16141
+ const fitText = findChild(el, "w:fitText");
16142
+ if (fitText) {
16143
+ const val = attrNum(fitText, "w:val");
16144
+ if (val !== void 0) opts.fitText = val;
16145
+ }
16146
+ const lang = findChild(el, "w:lang");
16147
+ if (lang) {
16148
+ const langObj = {};
16149
+ const val = attr(lang, "w:val");
16150
+ if (val) langObj.val = val;
16151
+ const eastAsia = attr(lang, "w:eastAsia");
16152
+ if (eastAsia) langObj.eastAsia = eastAsia;
16153
+ const bidi = attr(lang, "w:bidi");
16154
+ if (bidi) langObj.bidi = bidi;
16155
+ if (Object.keys(langObj).length > 0) opts.language = langObj;
16156
+ }
16157
+ const bdr = findChild(el, "w:bdr");
16158
+ if (bdr) opts.border = parseBorder(bdr);
16159
+ const shd = findChild(el, "w:shd");
16160
+ if (shd) opts.shading = parseShading(shd);
16161
+ return opts;
16030
16162
  }
16031
- //#endregion
16032
- //#region src/file/drawing/drawing-parse.ts
16033
16163
  /**
16034
- * Drawing parser for DOCX documents.
16035
- *
16036
- * Parses w:drawing elements and extracts image, chart, or SmartArt data.
16037
- *
16038
- * @module
16164
+ * Parse a w:bdr element into BorderOptions.
16039
16165
  */
16166
+ function parseBorder(el) {
16167
+ const opts = {};
16168
+ const style = attr(el, "w:val");
16169
+ if (style) opts.style = style;
16170
+ const color = colorAttr(el, "w:color");
16171
+ if (color) opts.color = color;
16172
+ const size = attrNum(el, "w:sz");
16173
+ if (size !== void 0) opts.size = size;
16174
+ const space = attrNum(el, "w:space");
16175
+ if (space !== void 0) opts.space = space;
16176
+ const shadow = attrBool(el, "w:shadow");
16177
+ if (shadow !== void 0) opts.shadow = shadow;
16178
+ const frame = attrBool(el, "w:frame");
16179
+ if (frame !== void 0) opts.frame = frame;
16180
+ return opts;
16181
+ }
16040
16182
  /**
16041
- * Parse a w:drawing element and dispatch to the correct parser
16042
- * based on the graphicData URI.
16183
+ * Parse a w:shd element into ShadingAttributesProperties.
16043
16184
  */
16044
- function parseDrawingRun(el, ctx) {
16045
- const graphicData = findDeep(el, "a:graphicData")[0];
16046
- if (!graphicData) return void 0;
16047
- const uri = attr(graphicData, "uri") ?? "";
16048
- if (uri.includes("/chart")) return parseChartDrawing(el, ctx);
16049
- if (uri.includes("/diagram")) return parseSmartArtDrawing(el, ctx);
16050
- return parseImageRun(el, ctx);
16185
+ function parseShading(el) {
16186
+ const opts = {};
16187
+ const fill = colorAttr(el, "w:fill");
16188
+ if (fill) opts.fill = fill;
16189
+ const color = colorAttr(el, "w:color");
16190
+ if (color) opts.color = color;
16191
+ const type = attr(el, "w:val");
16192
+ if (type) opts.type = type;
16193
+ return opts;
16051
16194
  }
16195
+ /** Matches w:br[@w:type="page"] → PageBreak */
16196
+ const PARSED_PAGE_BREAK = Symbol("PageBreak");
16197
+ /** Matches w:br (line break) */
16198
+ const PARSED_LINE_BREAK = Symbol("LineBreak");
16199
+ /** Matches w:tab */
16200
+ const PARSED_TAB = Symbol("Tab");
16201
+ /** Matches w:cr */
16202
+ const PARSED_CR = Symbol("CarriageReturn");
16203
+ /** Matches w:noBreakHyphen */
16204
+ const PARSED_NO_BREAK_HYPHEN = Symbol("NoBreakHyphen");
16205
+ /** Matches w:softHyphen */
16206
+ const PARSED_SOFT_HYPHEN = Symbol("SoftHyphen");
16052
16207
  /**
16053
- * Determine image type from file extension or MIME type.
16208
+ * Parse a w:r element into run data.
16209
+ * Returns { properties, children } where children are parsed run content items.
16054
16210
  */
16055
- function imageTypeFromPath(path) {
16056
- switch (path.split(".").pop()?.toLowerCase() ?? "") {
16057
- case "jpg":
16058
- case "jpeg": return "jpg";
16059
- case "png": return "png";
16060
- case "gif": return "gif";
16061
- case "bmp": return "bmp";
16062
- case "tif":
16063
- case "tiff": return "tif";
16064
- case "ico": return "ico";
16065
- case "emf": return "emf";
16066
- case "wmf": return "wmf";
16067
- default: return "png";
16068
- }
16069
- }
16070
- /**
16071
- * Parse a w:drawing element and return image data wrapped in { image: ... }.
16072
- */
16073
- function parseImageRun(el, ctx) {
16074
- const inline = findDeep(el, "wp:inline")[0];
16075
- const anchor = inline ? void 0 : findDeep(el, "wp:anchor")[0];
16076
- const parent = inline ?? anchor;
16077
- if (!parent) return void 0;
16078
- const extent = findChild(parent, "wp:extent");
16079
- let width;
16080
- let height;
16081
- if (extent) {
16082
- const cxEmu = attrNum(extent, "cx");
16083
- const cyEmu = attrNum(extent, "cy");
16084
- if (cxEmu !== void 0) width = convertEmuToPixels(cxEmu);
16085
- if (cyEmu !== void 0) height = convertEmuToPixels(cyEmu);
16086
- }
16087
- const blip = findDeep(parent, "a:blip")[0];
16088
- if (!blip) return void 0;
16089
- const rEmbed = attr(blip, "r:embed");
16090
- if (!rEmbed) return void 0;
16091
- const mediaPath = ctx.docx.partRefs.media.get(rEmbed);
16092
- if (!mediaPath) return void 0;
16093
- const imageData = ctx.docx.doc.getRaw(mediaPath);
16094
- if (!imageData) return void 0;
16095
- const imageOpts = {
16096
- type: imageTypeFromPath(mediaPath),
16097
- data: imageData,
16098
- transformation: {
16099
- ...width !== void 0 ? { width } : {},
16100
- ...height !== void 0 ? { height } : {}
16101
- }
16102
- };
16103
- const docPr = findChild(parent, "wp:docPr");
16104
- if (docPr) {
16105
- const name = attr(docPr, "name");
16106
- const descr = attr(docPr, "descr");
16107
- if (name || descr) imageOpts.altText = {
16108
- ...name ? { name } : {},
16109
- ...descr ? { description: descr } : {}
16110
- };
16111
- }
16112
- if (anchor && !inline) {
16113
- const floating = {};
16114
- const posH = findChild(anchor, "wp:positionH");
16115
- if (posH) {
16116
- const align = findChild(posH, "wp:align");
16117
- const posOffset = findChild(posH, "wp:posOffset");
16118
- if (align) floating.horizontalPosition = { align: textOf(align) };
16119
- else if (posOffset) floating.horizontalPosition = { offset: attrNum(posOffset, "offset") ?? 0 };
16211
+ function parseRun(el, _ctx) {
16212
+ const rPr = findChild(el, "w:rPr");
16213
+ const properties = rPr ? parseRunProperties(rPr) : void 0;
16214
+ const children = [];
16215
+ for (const child of el.elements ?? []) switch (child.name) {
16216
+ case "w:rPr": break;
16217
+ case "w:t": {
16218
+ const preserveSpace = attrBool(child, "xml:space");
16219
+ let text = textOf(child);
16220
+ if (preserveSpace && text) {}
16221
+ children.push(text);
16222
+ break;
16120
16223
  }
16121
- const posV = findChild(anchor, "wp:positionV");
16122
- if (posV) {
16123
- const align = findChild(posV, "wp:align");
16124
- const posOffset = findChild(posV, "wp:posOffset");
16125
- if (align) floating.verticalPosition = { align: textOf(align) };
16126
- else if (posOffset) floating.verticalPosition = { offset: attrNum(posOffset, "offset") ?? 0 };
16224
+ case "w:br": {
16225
+ const brType = attr(child, "w:type");
16226
+ if (brType === "page") children.push(PARSED_PAGE_BREAK);
16227
+ else if (brType === "column") children.push(PARSED_PAGE_BREAK);
16228
+ else children.push(PARSED_LINE_BREAK);
16229
+ break;
16127
16230
  }
16128
- for (const wrapType of [
16129
- "wrapSquare",
16130
- "wrapTight",
16131
- "wrapTopAndBottom",
16132
- "wrapNone"
16133
- ]) if (findChild(anchor, `wp:${wrapType}`)) {
16134
- floating.wrap = wrapType;
16231
+ case "w:tab":
16232
+ children.push(PARSED_TAB);
16233
+ break;
16234
+ case "w:cr":
16235
+ children.push(PARSED_CR);
16236
+ break;
16237
+ case "w:noBreakHyphen":
16238
+ children.push(PARSED_NO_BREAK_HYPHEN);
16239
+ break;
16240
+ case "w:softHyphen":
16241
+ children.push(PARSED_SOFT_HYPHEN);
16242
+ break;
16243
+ case "w:commentReference": {
16244
+ const id = attrNum(child, "w:id");
16245
+ if (id !== void 0) children.push({ commentReference: id });
16135
16246
  break;
16136
16247
  }
16137
- if (attrBool(anchor, "behindDoc")) floating.behindDocument = true;
16138
- if (Object.keys(floating).length > 0) imageOpts.floating = floating;
16248
+ case "w:drawing":
16249
+ case "w:pict": break;
16250
+ case "w:footnoteReference":
16251
+ case "w:endnoteReference": break;
16252
+ default:
16253
+ if (child.name && child.elements && child.elements.length > 0) children.push(new RawPassthrough(child));
16254
+ break;
16139
16255
  }
16140
- return { image: imageOpts };
16141
- }
16142
- function getDrawingExtent(el) {
16143
- const inline = findDeep(el, "wp:inline")[0];
16144
- const anchor = inline ? void 0 : findDeep(el, "wp:anchor")[0];
16145
- const parent = inline ?? anchor;
16146
- if (!parent) return {};
16147
- const extent = findChild(parent, "wp:extent");
16148
- if (!extent) return {};
16149
- const cxEmu = attrNum(extent, "cx");
16150
- const cyEmu = attrNum(extent, "cy");
16151
16256
  return {
16152
- ...cxEmu !== void 0 ? { width: convertEmuToPixels(cxEmu) } : {},
16153
- ...cyEmu !== void 0 ? { height: convertEmuToPixels(cyEmu) } : {}
16257
+ properties,
16258
+ children
16154
16259
  };
16155
16260
  }
16156
16261
  /**
16157
- * Look up a relationship ID in a map, with fallback for double "rId" prefix
16158
- * that the library's generation code produces (e.g. "rIdrId7" → "rId7").
16262
+ * Convert parsed run data into an RunOptions suitable for the Document constructor.
16263
+ * Simplifies the parsed children into text + break format.
16264
+ * If the run contains only a commentReference, returns { commentReference: id } instead.
16159
16265
  */
16160
- function lookupRId(map, rId) {
16161
- if (!rId) return void 0;
16162
- const direct = map.get(rId);
16163
- if (direct) return direct;
16164
- if (rId.startsWith("rIdrId")) return map.get(rId.slice(3));
16165
- }
16166
- function parseChartDrawing(el, ctx) {
16167
- const chartRef = findDeep(el, "c:chart")[0];
16168
- if (!chartRef) return void 0;
16169
- const rId = attr(chartRef, "r:id");
16170
- const chartPath = lookupRId(ctx.docx.partRefs.charts, rId);
16171
- if (!chartPath) return void 0;
16172
- const chartXml = ctx.docx.doc.get(chartPath);
16173
- if (!chartXml) return void 0;
16174
- const opts = parseChartXml(chartXml);
16175
- if (!opts) return void 0;
16176
- const ext = getDrawingExtent(el);
16177
- if (ext.width !== void 0 || ext.height !== void 0) opts.transformation = { ...ext };
16178
- return { chart: opts };
16266
+ function parsedRunToOptions(parsed) {
16267
+ const opts = { ...parsed.properties };
16268
+ const commentRefs = parsed.children.filter((c) => typeof c === "object" && c !== null && "commentReference" in c);
16269
+ const nonCommentChildren = parsed.children.filter((c) => !(typeof c === "object" && c !== null && "commentReference" in c));
16270
+ if (commentRefs.length > 0 && nonCommentChildren.length === 0 && !parsed.properties) return commentRefs[0];
16271
+ const textParts = [];
16272
+ let breakCount = 0;
16273
+ for (const child of nonCommentChildren) if (typeof child === "string") textParts.push(child);
16274
+ else if (child === PARSED_LINE_BREAK) breakCount++;
16275
+ if (textParts.length > 0) opts.text = textParts.join("");
16276
+ if (breakCount > 0) opts.break = breakCount;
16277
+ return opts;
16179
16278
  }
16279
+ //#endregion
16280
+ //#region src/file/paragraph/paragraph-parse.ts
16180
16281
  /**
16181
- * Parse c:chartSpace element into ChartOptions.
16282
+ * Paragraph parser for DOCX documents.
16283
+ *
16284
+ * Parses w:p and w:pPr Element trees into ParagraphOptions objects.
16285
+ *
16286
+ * @module
16182
16287
  */
16183
- function parseChartXml(el) {
16184
- const chart = findChild(el, "c:chart");
16185
- if (!chart) return void 0;
16288
+ init_style();
16289
+ init_math_parse();
16290
+ const HEADING_MAP = {
16291
+ Heading1: HeadingLevel.HEADING_1,
16292
+ Heading2: HeadingLevel.HEADING_2,
16293
+ Heading3: HeadingLevel.HEADING_3,
16294
+ Heading4: HeadingLevel.HEADING_4,
16295
+ Heading5: HeadingLevel.HEADING_5,
16296
+ Heading6: HeadingLevel.HEADING_6,
16297
+ Title: HeadingLevel.TITLE
16298
+ };
16299
+ /**
16300
+ * Parse w:pPr element into paragraph properties (without children).
16301
+ */
16302
+ function parseParagraphProperties(el, _ctx) {
16186
16303
  const opts = {};
16187
- const titleEl = findChild(chart, "c:title");
16188
- if (titleEl) {
16189
- const rich = findDeep(titleEl, "c:rich")[0];
16190
- if (rich) {
16191
- const t = findDeep(rich, "a:t")[0];
16192
- if (t) {
16193
- const title = textOf(t);
16194
- if (title) opts.title = title;
16195
- }
16196
- }
16197
- }
16198
- const plotArea = findChild(chart, "c:plotArea");
16199
- if (!plotArea) return void 0;
16200
- let chartType;
16201
- let typeElement;
16202
- for (const child of plotArea.elements ?? []) {
16203
- switch (child.name) {
16204
- case "c:barChart": {
16205
- const barDir = findChild(child, "c:barDir");
16206
- chartType = barDir && attr(barDir, "val") === "bar" ? "bar" : "column";
16207
- typeElement = child;
16208
- break;
16209
- }
16210
- case "c:lineChart":
16211
- chartType = "line";
16212
- typeElement = child;
16213
- break;
16214
- case "c:pieChart":
16215
- chartType = "pie";
16216
- typeElement = child;
16217
- break;
16218
- case "c:areaChart":
16219
- chartType = "area";
16220
- typeElement = child;
16221
- break;
16222
- case "c:scatterChart":
16223
- chartType = "scatter";
16224
- typeElement = child;
16225
- break;
16226
- }
16227
- if (chartType) break;
16304
+ const pStyle = findChild(el, "w:pStyle");
16305
+ if (pStyle) {
16306
+ const styleVal = attr(pStyle, "w:val");
16307
+ if (styleVal) if (HEADING_MAP[styleVal]) opts.heading = HEADING_MAP[styleVal];
16308
+ else opts.style = styleVal;
16228
16309
  }
16229
- if (!chartType || !typeElement) return void 0;
16230
- opts.type = chartType;
16231
- const series = [];
16232
- let categories;
16233
- for (const serEl of typeElement.elements ?? []) {
16234
- if (serEl.name !== "c:ser") continue;
16235
- const nameParts = extractStrCache(serEl, "c:tx");
16236
- const cats = extractStrCache(serEl, "c:cat");
16237
- if (cats.length > 0 && !categories) categories = cats;
16238
- const vals = extractNumCache(serEl);
16239
- series.push({
16240
- name: nameParts[0] ?? "",
16241
- values: vals
16242
- });
16310
+ const jc = findChild(el, "w:jc");
16311
+ if (jc) {
16312
+ const val = attr(jc, "w:val");
16313
+ if (val) opts.alignment = val;
16243
16314
  }
16244
- opts.data = {
16245
- categories: categories ?? [],
16246
- series
16247
- };
16248
- opts.showLegend = findChild(chart, "c:legend") !== void 0;
16249
- const styleEl = findChild(el, "c:style");
16250
- if (styleEl) {
16251
- const val = attrNum(styleEl, "val");
16252
- if (val !== void 0) opts.style = val;
16253
- }
16254
- return opts;
16255
- }
16256
- /**
16257
- * Extract string values from c:strCache within a container element.
16258
- */
16259
- function extractStrCache(parent, containerName) {
16260
- const container = findChild(parent, containerName);
16261
- if (!container) return [];
16262
- const cache = findDeep(container, "c:strCache")[0];
16263
- if (!cache) return [];
16264
- const values = [];
16265
- for (const pt of cache.elements ?? []) {
16266
- if (pt.name !== "c:pt") continue;
16267
- const v = findChild(pt, "c:v");
16268
- if (v) values.push(textOf(v) ?? "");
16269
- }
16270
- return values;
16271
- }
16272
- /**
16273
- * Extract numeric values from c:numCache within a c:val container.
16274
- */
16275
- function extractNumCache(parent) {
16276
- const valEl = findChild(parent, "c:val");
16277
- if (!valEl) return [];
16278
- const cache = findDeep(valEl, "c:numCache")[0];
16279
- if (!cache) return [];
16280
- const values = [];
16281
- for (const pt of cache.elements ?? []) {
16282
- if (pt.name !== "c:pt") continue;
16283
- const v = findChild(pt, "c:v");
16284
- if (v) {
16285
- const num = Number(textOf(v));
16286
- if (!isNaN(num)) values.push(num);
16287
- }
16288
- }
16289
- return values;
16290
- }
16291
- function parseSmartArtDrawing(el, ctx) {
16292
- const relIds = findDeep(el, "dgm:relIds")[0];
16293
- if (!relIds) return void 0;
16294
- const rId = attr(relIds, "r:dm");
16295
- const dataPath = lookupRId(ctx.docx.partRefs.diagramData, rId);
16296
- if (!dataPath) return void 0;
16297
- const dataEl = ctx.docx.doc.get(dataPath);
16298
- if (!dataEl) return void 0;
16299
- const opts = parseSmartArtDataXml(dataEl);
16300
- if (!opts) return void 0;
16301
- const ext = getDrawingExtent(el);
16302
- if (ext.width !== void 0 || ext.height !== void 0) opts.transformation = { ...ext };
16303
- return { smartArt: opts };
16304
- }
16305
- /**
16306
- * Parse dgm:dataModel element into SmartArtOptions.
16307
- */
16308
- function parseSmartArtDataXml(el) {
16309
- const ptLst = findChild(el, "dgm:ptLst");
16310
- if (!ptLst) return void 0;
16311
- const opts = {};
16312
- const nodeMap = /* @__PURE__ */ new Map();
16313
- for (const pt of ptLst.elements ?? []) {
16314
- if (pt.name !== "dgm:pt") continue;
16315
- const type = attr(pt, "type");
16316
- const modelId = attr(pt, "modelId");
16317
- if (type === "doc") {
16318
- const prSet = findChild(pt, "dgm:prSet");
16319
- if (prSet) {
16320
- const loTypeId = attr(prSet, "loTypeId") ?? "";
16321
- const qsTypeId = attr(prSet, "qsTypeId") ?? "";
16322
- const csTypeId = attr(prSet, "csTypeId") ?? "";
16323
- const layout = loTypeId.split("/").pop();
16324
- if (layout) opts.layout = layout;
16325
- const style = qsTypeId.split("/").pop();
16326
- if (style) opts.style = style;
16327
- const color = csTypeId.split("/").pop();
16328
- if (color) opts.color = color;
16329
- }
16330
- } else if (type === "node" && modelId) {
16331
- const t = findDeep(pt, "a:t")[0];
16332
- nodeMap.set(modelId, t ? textOf(t) ?? "" : "");
16333
- }
16315
+ const spacing = findChild(el, "w:spacing");
16316
+ if (spacing) {
16317
+ const sp = {};
16318
+ const before = attrNum(spacing, "w:before");
16319
+ if (before !== void 0) sp.before = before;
16320
+ const after = attrNum(spacing, "w:after");
16321
+ if (after !== void 0) sp.after = after;
16322
+ const line = attrNum(spacing, "w:line");
16323
+ if (line !== void 0) sp.line = line;
16324
+ const lineRule = attr(spacing, "w:lineRule");
16325
+ if (lineRule) sp.lineRule = lineRule;
16326
+ const beforeAuto = attrBool(spacing, "w:beforeAutospacing") ?? attrBool(spacing, "w:beforeLines");
16327
+ if (beforeAuto !== void 0) sp.beforeAutoSpacing = beforeAuto;
16328
+ const afterAuto = attrBool(spacing, "w:afterAutospacing") ?? attrBool(spacing, "w:afterLines");
16329
+ if (afterAuto !== void 0) sp.afterAutoSpacing = afterAuto;
16330
+ if (Object.keys(sp).length > 0) opts.spacing = sp;
16334
16331
  }
16335
- const cxnLst = findChild(el, "dgm:cxnLst");
16336
- if (!cxnLst) {
16337
- opts.data = { nodes: [] };
16338
- return opts;
16332
+ const ind = findChild(el, "w:ind");
16333
+ if (ind) {
16334
+ const indentObj = {};
16335
+ const left = attrNum(ind, "w:left");
16336
+ if (left !== void 0) indentObj.left = left;
16337
+ const right = attrNum(ind, "w:right");
16338
+ if (right !== void 0) indentObj.right = right;
16339
+ const start = attrNum(ind, "w:start");
16340
+ if (start !== void 0) indentObj.start = start;
16341
+ const end = attrNum(ind, "w:end");
16342
+ if (end !== void 0) indentObj.end = end;
16343
+ const hanging = attrNum(ind, "w:hanging");
16344
+ if (hanging !== void 0) indentObj.hanging = hanging;
16345
+ const firstLine = attrNum(ind, "w:firstLine");
16346
+ if (firstLine !== void 0) indentObj.firstLine = firstLine;
16347
+ if (Object.keys(indentObj).length > 0) opts.indent = indentObj;
16339
16348
  }
16340
- const childrenMap = /* @__PURE__ */ new Map();
16341
- for (const cxn of cxnLst.elements ?? []) {
16342
- if (cxn.name !== "dgm:cxn") continue;
16343
- const srcId = attr(cxn, "srcId");
16344
- const destId = attr(cxn, "destId");
16345
- if (!srcId || !destId || !nodeMap.has(destId)) continue;
16346
- let arr = childrenMap.get(srcId);
16347
- if (!arr) {
16348
- arr = [];
16349
- childrenMap.set(srcId, arr);
16350
- }
16351
- arr.push(destId);
16349
+ const numPr = findChild(el, "w:numPr");
16350
+ if (numPr) {
16351
+ const ilvl = findChild(numPr, "w:ilvl");
16352
+ opts.bullet = { level: ilvl ? attrNum(ilvl, "w:val") ?? 0 : 0 };
16352
16353
  }
16353
- opts.data = { nodes: (childrenMap.get("0") ?? []).map((id) => buildSmartArtNode(id, nodeMap, childrenMap)) };
16354
- return opts;
16355
- }
16356
- function buildSmartArtNode(id, nodeMap, childrenMap) {
16357
- const text = nodeMap.get(id) ?? "";
16358
- const childIds = childrenMap.get(id) ?? [];
16359
- if (childIds.length === 0) return { text };
16360
- return {
16361
- text,
16362
- children: childIds.map((cid) => buildSmartArtNode(cid, nodeMap, childrenMap))
16363
- };
16364
- }
16365
- //#endregion
16366
- //#region src/file/paragraph/run/run-parse.ts
16367
- /**
16368
- * Run properties parser for DOCX documents.
16369
- *
16370
- * Parses w:rPr Element trees into RunPropertiesOptions objects.
16371
- *
16372
- * @module
16373
- */
16374
- /**
16375
- * Parse a w:rPr element into RunPropertiesOptions.
16376
- */
16377
- function parseRunProperties(el) {
16378
- const opts = {};
16379
- const rStyle = findChild(el, "w:rStyle");
16380
- if (rStyle) opts.style = attr(rStyle, "w:val");
16381
- const font = findChild(el, "w:rFonts");
16382
- if (font) {
16383
- const ascii = attr(font, "w:ascii");
16384
- const eastAsia = attr(font, "w:eastAsia");
16385
- const hAnsi = attr(font, "w:hAnsi");
16386
- const cs = attr(font, "w:cs");
16387
- const hint = attr(font, "w:hint");
16388
- if (ascii && !eastAsia && !hAnsi && !cs) opts.font = hint ? {
16389
- name: ascii,
16390
- hint
16391
- } : ascii;
16392
- else {
16393
- const fontObj = {};
16394
- if (ascii) fontObj.ascii = ascii;
16395
- if (eastAsia) fontObj.eastAsia = eastAsia;
16396
- if (hAnsi) fontObj.hAnsi = hAnsi;
16397
- if (cs) fontObj.cs = cs;
16398
- if (hint) fontObj.hint = hint;
16399
- opts.font = fontObj;
16354
+ const tabs = findChild(el, "w:tabs");
16355
+ if (tabs) {
16356
+ const tabStops = [];
16357
+ for (const tab of children(tabs, "w:tab")) {
16358
+ const tabObj = {};
16359
+ const pos = attrNum(tab, "w:pos");
16360
+ if (pos !== void 0) tabObj.position = pos;
16361
+ const val = attr(tab, "w:val");
16362
+ if (val) tabObj.type = val;
16363
+ const leader = attr(tab, "w:leader");
16364
+ if (leader) tabObj.leader = leader;
16365
+ tabStops.push(tabObj);
16400
16366
  }
16401
- }
16402
- const bold = findChild(el, "w:b");
16403
- if (bold) opts.bold = attrBool(bold, "w:val") ?? true;
16404
- const boldCs = findChild(el, "w:bCs");
16405
- if (boldCs) opts.boldComplexScript = attrBool(boldCs, "w:val") ?? true;
16406
- const italics = findChild(el, "w:i");
16407
- if (italics) opts.italics = attrBool(italics, "w:val") ?? true;
16408
- const italicsCs = findChild(el, "w:iCs");
16409
- if (italicsCs) opts.italicsComplexScript = attrBool(italicsCs, "w:val") ?? true;
16410
- const underline = findChild(el, "w:u");
16411
- if (underline) {
16412
- const ul = {};
16413
- const uType = attr(underline, "w:val");
16414
- if (uType) ul.type = uType;
16415
- const uColor = colorAttr(underline, "w:color");
16416
- if (uColor) ul.color = uColor;
16417
- opts.underline = ul;
16367
+ if (tabStops.length > 0) opts.tabStops = tabStops;
16418
16368
  }
16419
16369
  for (const [name, optKey] of [
16420
- ["w:strike", "strike"],
16421
- ["w:dstrike", "doubleStrike"],
16422
- ["w:outline", "outline"],
16423
- ["w:shadow", "shadow"],
16424
- ["w:emboss", "emboss"],
16425
- ["w:imprint", "imprint"],
16426
- ["w:vanish", "vanish"],
16427
- ["w:webHidden", "webHidden"],
16428
- ["w:noProof", "noProof"],
16370
+ ["w:keepNext", "keepNext"],
16371
+ ["w:keepLines", "keepLines"],
16372
+ ["w:pageBreakBefore", "pageBreakBefore"],
16373
+ ["w:widowControl", "widowControl"],
16374
+ ["w:suppressLineNumbers", "suppressLineNumbers"],
16375
+ ["w:contextualSpacing", "contextualSpacing"],
16376
+ ["w:bidi", "bidirectional"],
16377
+ ["w:wordWrap", "wordWrap"],
16378
+ ["w:suppressAutoHyphens", "suppressAutoHyphens"],
16379
+ ["w:adjustRightInd", "adjustRightInd"],
16429
16380
  ["w:snapToGrid", "snapToGrid"],
16430
- ["w:smallCaps", "smallCaps"],
16431
- ["w:caps", "allCaps"],
16432
- ["w:rtl", "rightToLeft"],
16433
- ["w:cs", "complexScript"],
16434
- ["w:specVanish", "specVanish"],
16435
- ["w:math", "math"]
16381
+ ["w:mirrorIndents", "mirrorIndents"],
16382
+ ["w:kinsoku", "kinsoku"],
16383
+ ["w:topLinePunct", "topLinePunct"],
16384
+ ["w:autoSpaceDE", "autoSpaceDE"],
16385
+ ["w:overflowPunct", "overflowPunctuation"],
16386
+ ["w:suppressOverlap", "suppressOverlap"]
16436
16387
  ]) {
16437
16388
  const child = findChild(el, name);
16438
16389
  if (child) opts[optKey] = attrBool(child, "w:val") ?? true;
16439
16390
  }
16440
- const color = findChild(el, "w:color");
16441
- if (color) {
16442
- const c = colorAttr(color, "w:val");
16443
- if (c) opts.color = c;
16444
- }
16445
- const sz = findChild(el, "w:sz");
16446
- if (sz) {
16447
- const halfPts = attrNum(sz, "w:val");
16448
- if (halfPts !== void 0) opts.size = halfPts;
16449
- }
16450
- const szCs = findChild(el, "w:szCs");
16451
- if (szCs) {
16452
- const halfPts = attrNum(szCs, "w:val");
16453
- if (halfPts !== void 0) opts.sizeComplexScript = halfPts;
16454
- }
16455
- const highlight = findChild(el, "w:highlight");
16456
- if (highlight) {
16457
- const val = attr(highlight, "w:val");
16458
- if (val) opts.highlight = val;
16459
- }
16460
- const highlightCs = findChild(el, "w:highlightCs");
16461
- if (highlightCs) {
16462
- const val = attr(highlightCs, "w:val");
16463
- if (val) opts.highlightComplexScript = val;
16464
- }
16465
- const vertAlign = findChild(el, "w:vertAlign");
16466
- if (vertAlign) {
16467
- const val = attr(vertAlign, "w:val");
16468
- if (val === "subscript") opts.subScript = true;
16469
- else if (val === "superscript") opts.superScript = true;
16470
- }
16471
- const effect = findChild(el, "w:effect");
16472
- if (effect) {
16473
- const val = attr(effect, "w:val");
16474
- if (val) opts.effect = val;
16475
- }
16476
- const emphasisMark = findChild(el, "w:em");
16477
- if (emphasisMark) {
16478
- const val = attr(emphasisMark, "w:val");
16479
- if (val) opts.emphasisMark = { type: val };
16480
- }
16481
- const spacing = findChild(el, "w:spacing");
16482
- if (spacing) {
16483
- const val = attrNum(spacing, "w:val");
16484
- if (val !== void 0) opts.characterSpacing = val;
16485
- }
16486
- const scale = findChild(el, "w:w");
16487
- if (scale) {
16488
- const val = attrNum(scale, "w:val");
16489
- if (val !== void 0) opts.scale = val;
16391
+ if (findChild(el, "w:pBdr")) {
16392
+ const pBdr = findChild(el, "w:pBdr");
16393
+ const border = {};
16394
+ for (const side of [
16395
+ "top",
16396
+ "bottom",
16397
+ "left",
16398
+ "right"
16399
+ ]) {
16400
+ const sideEl = findChild(pBdr, `w:${side}`);
16401
+ if (sideEl) {
16402
+ const sideOpts = {};
16403
+ const style = attr(sideEl, "w:val");
16404
+ if (style) sideOpts.style = style;
16405
+ const color = attr(sideEl, "w:color");
16406
+ if (color) sideOpts.color = color;
16407
+ const size = attrNum(sideEl, "w:sz");
16408
+ if (size !== void 0) sideOpts.size = size;
16409
+ const space = attrNum(sideEl, "w:space");
16410
+ if (space !== void 0) sideOpts.space = space;
16411
+ border[side] = sideOpts;
16412
+ }
16413
+ }
16414
+ if (Object.keys(border).length > 0) opts.border = border;
16490
16415
  }
16491
- const kern = findChild(el, "w:kern");
16492
- if (kern) {
16493
- const val = attrNum(kern, "w:val");
16494
- if (val !== void 0) opts.kern = val;
16416
+ const shd = findChild(el, "w:shd");
16417
+ if (shd) {
16418
+ const shdObj = {};
16419
+ const fill = attr(shd, "w:fill");
16420
+ if (fill) shdObj.fill = fill;
16421
+ const color = attr(shd, "w:color");
16422
+ if (color) shdObj.color = color;
16423
+ const val = attr(shd, "w:val");
16424
+ if (val) shdObj.type = val;
16425
+ if (Object.keys(shdObj).length > 0) opts.shading = shdObj;
16495
16426
  }
16496
- const position = findChild(el, "w:position");
16497
- if (position) {
16498
- const val = attr(position, "w:val");
16499
- if (val !== void 0) opts.position = val;
16427
+ const textAlignment = findChild(el, "w:textAlignment");
16428
+ if (textAlignment) {
16429
+ const val = attr(textAlignment, "w:val");
16430
+ if (val) opts.textAlignment = val;
16500
16431
  }
16501
- const fitText = findChild(el, "w:fitText");
16502
- if (fitText) {
16503
- const val = attrNum(fitText, "w:val");
16504
- if (val !== void 0) opts.fitText = val;
16432
+ const outlineLvl = findChild(el, "w:outlineLvl");
16433
+ if (outlineLvl) {
16434
+ const val = attrNum(outlineLvl, "w:val");
16435
+ if (val !== void 0) opts.outlineLevel = val;
16505
16436
  }
16506
- const lang = findChild(el, "w:lang");
16507
- if (lang) {
16508
- const langObj = {};
16509
- const val = attr(lang, "w:val");
16510
- if (val) langObj.val = val;
16511
- const eastAsia = attr(lang, "w:eastAsia");
16512
- if (eastAsia) langObj.eastAsia = eastAsia;
16513
- const bidi = attr(lang, "w:bidi");
16514
- if (bidi) langObj.bidi = bidi;
16515
- if (Object.keys(langObj).length > 0) opts.language = langObj;
16437
+ const cnfStyle = findChild(el, "w:cnfStyle");
16438
+ if (cnfStyle) {
16439
+ const val = attr(cnfStyle, "w:val");
16440
+ if (val) opts.cnfStyle = { val };
16516
16441
  }
16517
- const bdr = findChild(el, "w:bdr");
16518
- if (bdr) opts.border = parseBorder(bdr);
16519
- const shd = findChild(el, "w:shd");
16520
- if (shd) opts.shading = parseShading(shd);
16521
- return opts;
16522
- }
16523
- /**
16524
- * Parse a w:bdr element into BorderOptions.
16525
- */
16526
- function parseBorder(el) {
16527
- const opts = {};
16528
- const style = attr(el, "w:val");
16529
- if (style) opts.style = style;
16530
- const color = colorAttr(el, "w:color");
16531
- if (color) opts.color = color;
16532
- const size = attrNum(el, "w:sz");
16533
- if (size !== void 0) opts.size = size;
16534
- const space = attrNum(el, "w:space");
16535
- if (space !== void 0) opts.space = space;
16536
- const shadow = attrBool(el, "w:shadow");
16537
- if (shadow !== void 0) opts.shadow = shadow;
16538
- const frame = attrBool(el, "w:frame");
16539
- if (frame !== void 0) opts.frame = frame;
16540
- return opts;
16541
- }
16542
- /**
16543
- * Parse a w:shd element into ShadingAttributesProperties.
16544
- */
16545
- function parseShading(el) {
16546
- const opts = {};
16547
- const fill = colorAttr(el, "w:fill");
16548
- if (fill) opts.fill = fill;
16549
- const color = colorAttr(el, "w:color");
16550
- if (color) opts.color = color;
16551
- const type = attr(el, "w:val");
16552
- if (type) opts.type = type;
16553
- return opts;
16554
- }
16555
- /** Matches w:br[@w:type="page"] → PageBreak */
16556
- const PARSED_PAGE_BREAK = Symbol("PageBreak");
16557
- /** Matches w:br (line break) */
16558
- const PARSED_LINE_BREAK = Symbol("LineBreak");
16559
- /** Matches w:tab */
16560
- const PARSED_TAB = Symbol("Tab");
16561
- /** Matches w:cr */
16562
- const PARSED_CR = Symbol("CarriageReturn");
16563
- /** Matches w:noBreakHyphen */
16564
- const PARSED_NO_BREAK_HYPHEN = Symbol("NoBreakHyphen");
16565
- /** Matches w:softHyphen */
16566
- const PARSED_SOFT_HYPHEN = Symbol("SoftHyphen");
16442
+ const rPr = findChild(el, "w:rPr");
16443
+ if (rPr) opts.run = parseRunProperties(rPr);
16444
+ const framePr = findChild(el, "w:framePr");
16445
+ if (framePr) {
16446
+ const frame = {};
16447
+ for (const [attrName, optName] of [
16448
+ ["w:dropCap", "dropCap"],
16449
+ ["w:lines", "lines"],
16450
+ ["w:wrap", "wrap"],
16451
+ ["w:vAnchor", "vAnchor"],
16452
+ ["w:hAnchor", "hAnchor"],
16453
+ ["w:x", "x"],
16454
+ ["w:y", "y"],
16455
+ ["w:hRule", "hRule"],
16456
+ ["w:hSpace", "hSpace"],
16457
+ ["w:vSpace", "vSpace"]
16458
+ ]) {
16459
+ const val = attr(framePr, attrName);
16460
+ if (val !== void 0) frame[optName] = val;
16461
+ }
16462
+ const w = attrNum(framePr, "w:w");
16463
+ if (w !== void 0) frame.width = w;
16464
+ const h = attrNum(framePr, "w:h");
16465
+ if (h !== void 0) frame.height = h;
16466
+ if (Object.keys(frame).length > 0) opts.frame = frame;
16467
+ }
16468
+ return opts;
16469
+ }
16567
16470
  /**
16568
- * Parse a w:r element into run data.
16569
- * Returns { properties, children } where children are parsed run content items.
16471
+ * Parse a w:p element into ParagraphOptions.
16570
16472
  */
16571
- function parseRun(el, _ctx) {
16572
- const rPr = findChild(el, "w:rPr");
16573
- const properties = rPr ? parseRunProperties(rPr) : void 0;
16574
- const children = [];
16473
+ function parseParagraph(el, ctx) {
16474
+ const opts = {};
16475
+ const pPr = findChild(el, "w:pPr");
16476
+ if (pPr) Object.assign(opts, parseParagraphProperties(pPr, ctx));
16477
+ const childList = [];
16575
16478
  for (const child of el.elements ?? []) switch (child.name) {
16576
- case "w:rPr": break;
16577
- case "w:t": {
16578
- const preserveSpace = attrBool(child, "xml:space");
16579
- let text = textOf(child);
16580
- if (preserveSpace && text) {}
16581
- children.push(text);
16479
+ case "w:pPr": break;
16480
+ case "w:r": {
16481
+ const parsed = parseRun(child, ctx);
16482
+ const rawChildren = parsed.children.filter((c) => c instanceof RawPassthrough);
16483
+ const runOpts = parsedRunToOptions({
16484
+ ...parsed,
16485
+ children: parsed.children.filter((c) => !(c instanceof RawPassthrough))
16486
+ });
16487
+ childList.push(runOpts);
16488
+ childList.push(...rawChildren);
16582
16489
  break;
16583
16490
  }
16584
- case "w:br": {
16585
- const brType = attr(child, "w:type");
16586
- if (brType === "page") children.push(PARSED_PAGE_BREAK);
16587
- else if (brType === "column") children.push(PARSED_PAGE_BREAK);
16588
- else children.push(PARSED_LINE_BREAK);
16491
+ case "w:hyperlink": {
16492
+ const hl = {};
16493
+ const rId = attr(child, "r:id");
16494
+ if (rId) {
16495
+ const target = ctx.docx.partRefs.hyperlinks.get(rId);
16496
+ if (target) hl.link = target;
16497
+ }
16498
+ const anchor = attr(child, "w:anchor");
16499
+ if (anchor) hl.anchor = anchor;
16500
+ const tooltip = attr(child, "w:tooltip");
16501
+ if (tooltip) hl.tooltip = tooltip;
16502
+ const linkRuns = [];
16503
+ for (const sub of child.elements ?? []) if (sub.name === "w:r") {
16504
+ const runOpts = parsedRunToOptions(parseRun(sub, ctx));
16505
+ linkRuns.push(runOpts);
16506
+ }
16507
+ if (linkRuns.length > 0) {
16508
+ hl.children = linkRuns;
16509
+ childList.push({ hyperlink: hl });
16510
+ }
16589
16511
  break;
16590
16512
  }
16591
- case "w:tab":
16592
- children.push(PARSED_TAB);
16513
+ case "w:bookmarkStart": {
16514
+ const id = attrNum(child, "w:id");
16515
+ const name = attr(child, "w:name");
16516
+ if (id !== void 0 && name) childList.push({ bookmarkStart: {
16517
+ id,
16518
+ name
16519
+ } });
16593
16520
  break;
16594
- case "w:cr":
16595
- children.push(PARSED_CR);
16521
+ }
16522
+ case "w:bookmarkEnd": {
16523
+ const id = attrNum(child, "w:id");
16524
+ if (id !== void 0) childList.push({ bookmarkEnd: id });
16596
16525
  break;
16597
- case "w:noBreakHyphen":
16598
- children.push(PARSED_NO_BREAK_HYPHEN);
16526
+ }
16527
+ case "w:commentRangeStart": {
16528
+ const id = attrNum(child, "w:id");
16529
+ if (id !== void 0) childList.push({ commentRangeStart: id });
16599
16530
  break;
16600
- case "w:softHyphen":
16601
- children.push(PARSED_SOFT_HYPHEN);
16531
+ }
16532
+ case "w:commentRangeEnd": {
16533
+ const id = attrNum(child, "w:id");
16534
+ if (id !== void 0) childList.push({ commentRangeEnd: id });
16602
16535
  break;
16536
+ }
16603
16537
  case "w:commentReference": {
16604
16538
  const id = attrNum(child, "w:id");
16605
- if (id !== void 0) children.push({ commentReference: id });
16539
+ if (id !== void 0) childList.push({ commentReference: id });
16540
+ break;
16541
+ }
16542
+ case "m:oMath": {
16543
+ const mathChildren = parseMathChildren(child);
16544
+ childList.push({ math: { children: mathChildren } });
16606
16545
  break;
16607
16546
  }
16608
- case "w:drawing":
16609
- case "w:pict": break;
16610
- case "w:footnoteReference":
16611
- case "w:endnoteReference": break;
16612
16547
  default:
16613
- if (child.name && child.elements && child.elements.length > 0) children.push(new RawPassthrough(child));
16548
+ if (child.name && child.elements && child.elements.length > 0) childList.push(new RawPassthrough(child));
16549
+ break;
16550
+ }
16551
+ if (childList.length > 0) {
16552
+ if (childList.every((c) => typeof c === "object" && c !== null && "text" in c && Object.keys(c).length <= 2)) {
16553
+ const combined = childList.map((c) => c.text).join("");
16554
+ if (combined && Object.keys(opts).length === 0) return combined;
16555
+ if (combined) {
16556
+ opts.text = combined;
16557
+ return opts;
16558
+ }
16559
+ }
16560
+ opts.children = childList;
16561
+ }
16562
+ return opts;
16563
+ }
16564
+ //#endregion
16565
+ //#region src/file/alt-chunk/alt-chunk-parse.ts
16566
+ /**
16567
+ * AltChunk parser for DOCX documents.
16568
+ *
16569
+ * Parses w:altChunk elements and extracts embedded content from the ZIP.
16570
+ *
16571
+ * @module
16572
+ */
16573
+ /**
16574
+ * Parse a w:altChunk element into AltChunkOptions.
16575
+ * Reads the referenced data from the ZIP package.
16576
+ */
16577
+ function parseAltChunk(el, ctx) {
16578
+ const rId = attr(el, "r:id");
16579
+ if (!rId) throw new Error("w:altChunk missing r:id attribute");
16580
+ const path = ctx.docx.partRefs.afChunks.get(rId);
16581
+ if (!path) throw new Error(`AltChunk relationship ${rId} not found`);
16582
+ const data = ctx.docx.doc.getRaw(path);
16583
+ if (!data) throw new Error(`AltChunk data not found at ${path}`);
16584
+ const ext = path.split(".").pop() ?? "txt";
16585
+ let contentType;
16586
+ let extension;
16587
+ switch (ext) {
16588
+ case "html":
16589
+ contentType = "text/html";
16590
+ extension = "html";
16591
+ break;
16592
+ case "rtf":
16593
+ contentType = "application/rtf";
16594
+ extension = "rtf";
16595
+ break;
16596
+ default:
16597
+ contentType = "text/plain";
16598
+ extension = "txt";
16599
+ break;
16600
+ }
16601
+ return {
16602
+ data,
16603
+ contentType,
16604
+ extension
16605
+ };
16606
+ }
16607
+ //#endregion
16608
+ //#region src/file/drawing/drawing-parse.ts
16609
+ /**
16610
+ * Drawing parser for DOCX documents.
16611
+ *
16612
+ * Parses w:drawing elements and extracts image, chart, or SmartArt data.
16613
+ *
16614
+ * @module
16615
+ */
16616
+ /**
16617
+ * Parse a w:drawing element and dispatch to the correct parser
16618
+ * based on the graphicData URI.
16619
+ */
16620
+ function parseDrawingRun(el, ctx) {
16621
+ const graphicData = findDeep(el, "a:graphicData")[0];
16622
+ if (!graphicData) return void 0;
16623
+ const uri = attr(graphicData, "uri") ?? "";
16624
+ if (uri.includes("/chart")) return parseChartDrawing(el, ctx);
16625
+ if (uri.includes("/diagram")) return parseSmartArtDrawing(el, ctx);
16626
+ return parseImageRun(el, ctx);
16627
+ }
16628
+ /**
16629
+ * Determine image type from file extension or MIME type.
16630
+ */
16631
+ function imageTypeFromPath(path) {
16632
+ switch (path.split(".").pop()?.toLowerCase() ?? "") {
16633
+ case "jpg":
16634
+ case "jpeg": return "jpg";
16635
+ case "png": return "png";
16636
+ case "gif": return "gif";
16637
+ case "bmp": return "bmp";
16638
+ case "tif":
16639
+ case "tiff": return "tif";
16640
+ case "ico": return "ico";
16641
+ case "emf": return "emf";
16642
+ case "wmf": return "wmf";
16643
+ default: return "png";
16644
+ }
16645
+ }
16646
+ /**
16647
+ * Parse a w:drawing element and return image data wrapped in { image: ... }.
16648
+ */
16649
+ function parseImageRun(el, ctx) {
16650
+ const inline = findDeep(el, "wp:inline")[0];
16651
+ const anchor = inline ? void 0 : findDeep(el, "wp:anchor")[0];
16652
+ const parent = inline ?? anchor;
16653
+ if (!parent) return void 0;
16654
+ const extent = findChild(parent, "wp:extent");
16655
+ let width;
16656
+ let height;
16657
+ if (extent) {
16658
+ const cxEmu = attrNum(extent, "cx");
16659
+ const cyEmu = attrNum(extent, "cy");
16660
+ if (cxEmu !== void 0) width = convertEmuToPixels(cxEmu);
16661
+ if (cyEmu !== void 0) height = convertEmuToPixels(cyEmu);
16662
+ }
16663
+ const blip = findDeep(parent, "a:blip")[0];
16664
+ if (!blip) return void 0;
16665
+ const rEmbed = attr(blip, "r:embed");
16666
+ if (!rEmbed) return void 0;
16667
+ const mediaPath = ctx.docx.partRefs.media.get(rEmbed);
16668
+ if (!mediaPath) return void 0;
16669
+ const imageData = ctx.docx.doc.getRaw(mediaPath);
16670
+ if (!imageData) return void 0;
16671
+ const imageOpts = {
16672
+ type: imageTypeFromPath(mediaPath),
16673
+ data: imageData,
16674
+ transformation: {
16675
+ ...width !== void 0 ? { width } : {},
16676
+ ...height !== void 0 ? { height } : {}
16677
+ }
16678
+ };
16679
+ const docPr = findChild(parent, "wp:docPr");
16680
+ if (docPr) {
16681
+ const name = attr(docPr, "name");
16682
+ const descr = attr(docPr, "descr");
16683
+ if (name || descr) imageOpts.altText = {
16684
+ ...name ? { name } : {},
16685
+ ...descr ? { description: descr } : {}
16686
+ };
16687
+ }
16688
+ if (anchor && !inline) {
16689
+ const floating = {};
16690
+ const posH = findChild(anchor, "wp:positionH");
16691
+ if (posH) {
16692
+ const align = findChild(posH, "wp:align");
16693
+ const posOffset = findChild(posH, "wp:posOffset");
16694
+ if (align) floating.horizontalPosition = { align: textOf(align) };
16695
+ else if (posOffset) floating.horizontalPosition = { offset: attrNum(posOffset, "offset") ?? 0 };
16696
+ }
16697
+ const posV = findChild(anchor, "wp:positionV");
16698
+ if (posV) {
16699
+ const align = findChild(posV, "wp:align");
16700
+ const posOffset = findChild(posV, "wp:posOffset");
16701
+ if (align) floating.verticalPosition = { align: textOf(align) };
16702
+ else if (posOffset) floating.verticalPosition = { offset: attrNum(posOffset, "offset") ?? 0 };
16703
+ }
16704
+ for (const wrapType of [
16705
+ "wrapSquare",
16706
+ "wrapTight",
16707
+ "wrapTopAndBottom",
16708
+ "wrapNone"
16709
+ ]) if (findChild(anchor, `wp:${wrapType}`)) {
16710
+ floating.wrap = wrapType;
16614
16711
  break;
16712
+ }
16713
+ if (attrBool(anchor, "behindDoc")) floating.behindDocument = true;
16714
+ if (Object.keys(floating).length > 0) imageOpts.floating = floating;
16615
16715
  }
16716
+ return { image: imageOpts };
16717
+ }
16718
+ function getDrawingExtent(el) {
16719
+ const inline = findDeep(el, "wp:inline")[0];
16720
+ const anchor = inline ? void 0 : findDeep(el, "wp:anchor")[0];
16721
+ const parent = inline ?? anchor;
16722
+ if (!parent) return {};
16723
+ const extent = findChild(parent, "wp:extent");
16724
+ if (!extent) return {};
16725
+ const cxEmu = attrNum(extent, "cx");
16726
+ const cyEmu = attrNum(extent, "cy");
16616
16727
  return {
16617
- properties,
16618
- children
16728
+ ...cxEmu !== void 0 ? { width: convertEmuToPixels(cxEmu) } : {},
16729
+ ...cyEmu !== void 0 ? { height: convertEmuToPixels(cyEmu) } : {}
16619
16730
  };
16620
16731
  }
16621
16732
  /**
16622
- * Convert parsed run data into an RunOptions suitable for the Document constructor.
16623
- * Simplifies the parsed children into text + break format.
16624
- * If the run contains only a commentReference, returns { commentReference: id } instead.
16733
+ * Look up a relationship ID in a map, with fallback for double "rId" prefix
16734
+ * that the library's generation code produces (e.g. "rIdrId7" → "rId7").
16625
16735
  */
16626
- function parsedRunToOptions(parsed) {
16627
- const opts = { ...parsed.properties };
16628
- const commentRefs = parsed.children.filter((c) => typeof c === "object" && c !== null && "commentReference" in c);
16629
- const nonCommentChildren = parsed.children.filter((c) => !(typeof c === "object" && c !== null && "commentReference" in c));
16630
- if (commentRefs.length > 0 && nonCommentChildren.length === 0 && !parsed.properties) return commentRefs[0];
16631
- const textParts = [];
16632
- let breakCount = 0;
16633
- for (const child of nonCommentChildren) if (typeof child === "string") textParts.push(child);
16634
- else if (child === PARSED_LINE_BREAK) breakCount++;
16635
- if (textParts.length > 0) opts.text = textParts.join("");
16636
- if (breakCount > 0) opts.break = breakCount;
16637
- return opts;
16736
+ function lookupRId(map, rId) {
16737
+ if (!rId) return void 0;
16738
+ const direct = map.get(rId);
16739
+ if (direct) return direct;
16740
+ if (rId.startsWith("rIdrId")) return map.get(rId.slice(3));
16741
+ }
16742
+ function parseChartDrawing(el, ctx) {
16743
+ const chartRef = findDeep(el, "c:chart")[0];
16744
+ if (!chartRef) return void 0;
16745
+ const rId = attr(chartRef, "r:id");
16746
+ const chartPath = lookupRId(ctx.docx.partRefs.charts, rId);
16747
+ if (!chartPath) return void 0;
16748
+ const chartXml = ctx.docx.doc.get(chartPath);
16749
+ if (!chartXml) return void 0;
16750
+ const opts = parseChartXml(chartXml);
16751
+ if (!opts) return void 0;
16752
+ const ext = getDrawingExtent(el);
16753
+ if (ext.width !== void 0 || ext.height !== void 0) opts.transformation = { ...ext };
16754
+ return { chart: opts };
16638
16755
  }
16639
- //#endregion
16640
- //#region src/file/paragraph/paragraph-parse.ts
16641
- /**
16642
- * Paragraph parser for DOCX documents.
16643
- *
16644
- * Parses w:p and w:pPr Element trees into ParagraphOptions objects.
16645
- *
16646
- * @module
16647
- */
16648
- init_style();
16649
- init_math_parse();
16650
- const HEADING_MAP = {
16651
- Heading1: HeadingLevel.HEADING_1,
16652
- Heading2: HeadingLevel.HEADING_2,
16653
- Heading3: HeadingLevel.HEADING_3,
16654
- Heading4: HeadingLevel.HEADING_4,
16655
- Heading5: HeadingLevel.HEADING_5,
16656
- Heading6: HeadingLevel.HEADING_6,
16657
- Title: HeadingLevel.TITLE
16658
- };
16659
16756
  /**
16660
- * Parse w:pPr element into paragraph properties (without children).
16757
+ * Parse c:chartSpace element into ChartOptions.
16661
16758
  */
16662
- function parseParagraphProperties(el, _ctx) {
16759
+ function parseChartXml(el) {
16760
+ const chart = findChild(el, "c:chart");
16761
+ if (!chart) return void 0;
16663
16762
  const opts = {};
16664
- const pStyle = findChild(el, "w:pStyle");
16665
- if (pStyle) {
16666
- const styleVal = attr(pStyle, "w:val");
16667
- if (styleVal) if (HEADING_MAP[styleVal]) opts.heading = HEADING_MAP[styleVal];
16668
- else opts.style = styleVal;
16669
- }
16670
- const jc = findChild(el, "w:jc");
16671
- if (jc) {
16672
- const val = attr(jc, "w:val");
16673
- if (val) opts.alignment = val;
16674
- }
16675
- const spacing = findChild(el, "w:spacing");
16676
- if (spacing) {
16677
- const sp = {};
16678
- const before = attrNum(spacing, "w:before");
16679
- if (before !== void 0) sp.before = before;
16680
- const after = attrNum(spacing, "w:after");
16681
- if (after !== void 0) sp.after = after;
16682
- const line = attrNum(spacing, "w:line");
16683
- if (line !== void 0) sp.line = line;
16684
- const lineRule = attr(spacing, "w:lineRule");
16685
- if (lineRule) sp.lineRule = lineRule;
16686
- const beforeAuto = attrBool(spacing, "w:beforeAutospacing") ?? attrBool(spacing, "w:beforeLines");
16687
- if (beforeAuto !== void 0) sp.beforeAutoSpacing = beforeAuto;
16688
- const afterAuto = attrBool(spacing, "w:afterAutospacing") ?? attrBool(spacing, "w:afterLines");
16689
- if (afterAuto !== void 0) sp.afterAutoSpacing = afterAuto;
16690
- if (Object.keys(sp).length > 0) opts.spacing = sp;
16691
- }
16692
- const ind = findChild(el, "w:ind");
16693
- if (ind) {
16694
- const indentObj = {};
16695
- const left = attrNum(ind, "w:left");
16696
- if (left !== void 0) indentObj.left = left;
16697
- const right = attrNum(ind, "w:right");
16698
- if (right !== void 0) indentObj.right = right;
16699
- const start = attrNum(ind, "w:start");
16700
- if (start !== void 0) indentObj.start = start;
16701
- const end = attrNum(ind, "w:end");
16702
- if (end !== void 0) indentObj.end = end;
16703
- const hanging = attrNum(ind, "w:hanging");
16704
- if (hanging !== void 0) indentObj.hanging = hanging;
16705
- const firstLine = attrNum(ind, "w:firstLine");
16706
- if (firstLine !== void 0) indentObj.firstLine = firstLine;
16707
- if (Object.keys(indentObj).length > 0) opts.indent = indentObj;
16708
- }
16709
- const numPr = findChild(el, "w:numPr");
16710
- if (numPr) {
16711
- const ilvl = findChild(numPr, "w:ilvl");
16712
- opts.bullet = { level: ilvl ? attrNum(ilvl, "w:val") ?? 0 : 0 };
16713
- }
16714
- const tabs = findChild(el, "w:tabs");
16715
- if (tabs) {
16716
- const tabStops = [];
16717
- for (const tab of children(tabs, "w:tab")) {
16718
- const tabObj = {};
16719
- const pos = attrNum(tab, "w:pos");
16720
- if (pos !== void 0) tabObj.position = pos;
16721
- const val = attr(tab, "w:val");
16722
- if (val) tabObj.type = val;
16723
- const leader = attr(tab, "w:leader");
16724
- if (leader) tabObj.leader = leader;
16725
- tabStops.push(tabObj);
16763
+ const titleEl = findChild(chart, "c:title");
16764
+ if (titleEl) {
16765
+ const rich = findDeep(titleEl, "c:rich")[0];
16766
+ if (rich) {
16767
+ const t = findDeep(rich, "a:t")[0];
16768
+ if (t) {
16769
+ const title = textOf(t);
16770
+ if (title) opts.title = title;
16771
+ }
16726
16772
  }
16727
- if (tabStops.length > 0) opts.tabStops = tabStops;
16728
- }
16729
- for (const [name, optKey] of [
16730
- ["w:keepNext", "keepNext"],
16731
- ["w:keepLines", "keepLines"],
16732
- ["w:pageBreakBefore", "pageBreakBefore"],
16733
- ["w:widowControl", "widowControl"],
16734
- ["w:suppressLineNumbers", "suppressLineNumbers"],
16735
- ["w:contextualSpacing", "contextualSpacing"],
16736
- ["w:bidi", "bidirectional"],
16737
- ["w:wordWrap", "wordWrap"],
16738
- ["w:suppressAutoHyphens", "suppressAutoHyphens"],
16739
- ["w:adjustRightInd", "adjustRightInd"],
16740
- ["w:snapToGrid", "snapToGrid"],
16741
- ["w:mirrorIndents", "mirrorIndents"],
16742
- ["w:kinsoku", "kinsoku"],
16743
- ["w:topLinePunct", "topLinePunct"],
16744
- ["w:autoSpaceDE", "autoSpaceDE"],
16745
- ["w:overflowPunct", "overflowPunctuation"],
16746
- ["w:suppressOverlap", "suppressOverlap"]
16747
- ]) {
16748
- const child = findChild(el, name);
16749
- if (child) opts[optKey] = attrBool(child, "w:val") ?? true;
16750
16773
  }
16751
- if (findChild(el, "w:pBdr")) {
16752
- const pBdr = findChild(el, "w:pBdr");
16753
- const border = {};
16754
- for (const side of [
16755
- "top",
16756
- "bottom",
16757
- "left",
16758
- "right"
16759
- ]) {
16760
- const sideEl = findChild(pBdr, `w:${side}`);
16761
- if (sideEl) {
16762
- const sideOpts = {};
16763
- const style = attr(sideEl, "w:val");
16764
- if (style) sideOpts.style = style;
16765
- const color = attr(sideEl, "w:color");
16766
- if (color) sideOpts.color = color;
16767
- const size = attrNum(sideEl, "w:sz");
16768
- if (size !== void 0) sideOpts.size = size;
16769
- const space = attrNum(sideEl, "w:space");
16770
- if (space !== void 0) sideOpts.space = space;
16771
- border[side] = sideOpts;
16774
+ const plotArea = findChild(chart, "c:plotArea");
16775
+ if (!plotArea) return void 0;
16776
+ let chartType;
16777
+ let typeElement;
16778
+ for (const child of plotArea.elements ?? []) {
16779
+ switch (child.name) {
16780
+ case "c:barChart": {
16781
+ const barDir = findChild(child, "c:barDir");
16782
+ chartType = barDir && attr(barDir, "val") === "bar" ? "bar" : "column";
16783
+ typeElement = child;
16784
+ break;
16772
16785
  }
16786
+ case "c:lineChart":
16787
+ chartType = "line";
16788
+ typeElement = child;
16789
+ break;
16790
+ case "c:pieChart":
16791
+ chartType = "pie";
16792
+ typeElement = child;
16793
+ break;
16794
+ case "c:areaChart":
16795
+ chartType = "area";
16796
+ typeElement = child;
16797
+ break;
16798
+ case "c:scatterChart":
16799
+ chartType = "scatter";
16800
+ typeElement = child;
16801
+ break;
16773
16802
  }
16774
- if (Object.keys(border).length > 0) opts.border = border;
16775
- }
16776
- const shd = findChild(el, "w:shd");
16777
- if (shd) {
16778
- const shdObj = {};
16779
- const fill = attr(shd, "w:fill");
16780
- if (fill) shdObj.fill = fill;
16781
- const color = attr(shd, "w:color");
16782
- if (color) shdObj.color = color;
16783
- const val = attr(shd, "w:val");
16784
- if (val) shdObj.type = val;
16785
- if (Object.keys(shdObj).length > 0) opts.shading = shdObj;
16803
+ if (chartType) break;
16786
16804
  }
16787
- const textAlignment = findChild(el, "w:textAlignment");
16788
- if (textAlignment) {
16789
- const val = attr(textAlignment, "w:val");
16790
- if (val) opts.textAlignment = val;
16805
+ if (!chartType || !typeElement) return void 0;
16806
+ opts.type = chartType;
16807
+ const series = [];
16808
+ let categories;
16809
+ for (const serEl of typeElement.elements ?? []) {
16810
+ if (serEl.name !== "c:ser") continue;
16811
+ const nameParts = extractStrCache(serEl, "c:tx");
16812
+ const cats = extractStrCache(serEl, "c:cat");
16813
+ if (cats.length > 0 && !categories) categories = cats;
16814
+ const vals = extractNumCache(serEl);
16815
+ series.push({
16816
+ name: nameParts[0] ?? "",
16817
+ values: vals
16818
+ });
16791
16819
  }
16792
- const outlineLvl = findChild(el, "w:outlineLvl");
16793
- if (outlineLvl) {
16794
- const val = attrNum(outlineLvl, "w:val");
16795
- if (val !== void 0) opts.outlineLevel = val;
16820
+ opts.data = {
16821
+ categories: categories ?? [],
16822
+ series
16823
+ };
16824
+ opts.showLegend = findChild(chart, "c:legend") !== void 0;
16825
+ const styleEl = findChild(el, "c:style");
16826
+ if (styleEl) {
16827
+ const val = attrNum(styleEl, "val");
16828
+ if (val !== void 0) opts.style = val;
16796
16829
  }
16797
- const cnfStyle = findChild(el, "w:cnfStyle");
16798
- if (cnfStyle) {
16799
- const val = attr(cnfStyle, "w:val");
16800
- if (val) opts.cnfStyle = { val };
16830
+ return opts;
16831
+ }
16832
+ /**
16833
+ * Extract string values from c:strCache within a container element.
16834
+ */
16835
+ function extractStrCache(parent, containerName) {
16836
+ const container = findChild(parent, containerName);
16837
+ if (!container) return [];
16838
+ const cache = findDeep(container, "c:strCache")[0];
16839
+ if (!cache) return [];
16840
+ const values = [];
16841
+ for (const pt of cache.elements ?? []) {
16842
+ if (pt.name !== "c:pt") continue;
16843
+ const v = findChild(pt, "c:v");
16844
+ if (v) values.push(textOf(v) ?? "");
16801
16845
  }
16802
- const rPr = findChild(el, "w:rPr");
16803
- if (rPr) opts.run = parseRunProperties(rPr);
16804
- const framePr = findChild(el, "w:framePr");
16805
- if (framePr) {
16806
- const frame = {};
16807
- for (const [attrName, optName] of [
16808
- ["w:dropCap", "dropCap"],
16809
- ["w:lines", "lines"],
16810
- ["w:wrap", "wrap"],
16811
- ["w:vAnchor", "vAnchor"],
16812
- ["w:hAnchor", "hAnchor"],
16813
- ["w:x", "x"],
16814
- ["w:y", "y"],
16815
- ["w:hRule", "hRule"],
16816
- ["w:hSpace", "hSpace"],
16817
- ["w:vSpace", "vSpace"]
16818
- ]) {
16819
- const val = attr(framePr, attrName);
16820
- if (val !== void 0) frame[optName] = val;
16846
+ return values;
16847
+ }
16848
+ /**
16849
+ * Extract numeric values from c:numCache within a c:val container.
16850
+ */
16851
+ function extractNumCache(parent) {
16852
+ const valEl = findChild(parent, "c:val");
16853
+ if (!valEl) return [];
16854
+ const cache = findDeep(valEl, "c:numCache")[0];
16855
+ if (!cache) return [];
16856
+ const values = [];
16857
+ for (const pt of cache.elements ?? []) {
16858
+ if (pt.name !== "c:pt") continue;
16859
+ const v = findChild(pt, "c:v");
16860
+ if (v) {
16861
+ const num = Number(textOf(v));
16862
+ if (!isNaN(num)) values.push(num);
16821
16863
  }
16822
- const w = attrNum(framePr, "w:w");
16823
- if (w !== void 0) frame.width = w;
16824
- const h = attrNum(framePr, "w:h");
16825
- if (h !== void 0) frame.height = h;
16826
- if (Object.keys(frame).length > 0) opts.frame = frame;
16827
16864
  }
16828
- return opts;
16865
+ return values;
16866
+ }
16867
+ function parseSmartArtDrawing(el, ctx) {
16868
+ const relIds = findDeep(el, "dgm:relIds")[0];
16869
+ if (!relIds) return void 0;
16870
+ const rId = attr(relIds, "r:dm");
16871
+ const dataPath = lookupRId(ctx.docx.partRefs.diagramData, rId);
16872
+ if (!dataPath) return void 0;
16873
+ const dataEl = ctx.docx.doc.get(dataPath);
16874
+ if (!dataEl) return void 0;
16875
+ const opts = parseSmartArtDataXml(dataEl);
16876
+ if (!opts) return void 0;
16877
+ const ext = getDrawingExtent(el);
16878
+ if (ext.width !== void 0 || ext.height !== void 0) opts.transformation = { ...ext };
16879
+ return { smartArt: opts };
16829
16880
  }
16830
16881
  /**
16831
- * Parse a w:p element into ParagraphOptions.
16882
+ * Parse dgm:dataModel element into SmartArtOptions.
16832
16883
  */
16833
- function parseParagraph(el, ctx) {
16884
+ function parseSmartArtDataXml(el) {
16885
+ const ptLst = findChild(el, "dgm:ptLst");
16886
+ if (!ptLst) return void 0;
16834
16887
  const opts = {};
16835
- const pPr = findChild(el, "w:pPr");
16836
- if (pPr) Object.assign(opts, parseParagraphProperties(pPr, ctx));
16837
- const childList = [];
16838
- for (const child of el.elements ?? []) switch (child.name) {
16839
- case "w:pPr": break;
16840
- case "w:r": {
16841
- const parsed = parseRun(child, ctx);
16842
- const rawChildren = parsed.children.filter((c) => c instanceof RawPassthrough);
16843
- const runOpts = parsedRunToOptions({
16844
- ...parsed,
16845
- children: parsed.children.filter((c) => !(c instanceof RawPassthrough))
16846
- });
16847
- childList.push(runOpts);
16848
- childList.push(...rawChildren);
16849
- break;
16850
- }
16851
- case "w:hyperlink": {
16852
- const linkRuns = [];
16853
- for (const sub of child.elements ?? []) if (sub.name === "w:r") {
16854
- const runOpts = parsedRunToOptions(parseRun(sub, ctx));
16855
- linkRuns.push(runOpts);
16888
+ const nodeMap = /* @__PURE__ */ new Map();
16889
+ for (const pt of ptLst.elements ?? []) {
16890
+ if (pt.name !== "dgm:pt") continue;
16891
+ const type = attr(pt, "type");
16892
+ const modelId = attr(pt, "modelId");
16893
+ if (type === "doc") {
16894
+ const prSet = findChild(pt, "dgm:prSet");
16895
+ if (prSet) {
16896
+ const loTypeId = attr(prSet, "loTypeId") ?? "";
16897
+ const qsTypeId = attr(prSet, "qsTypeId") ?? "";
16898
+ const csTypeId = attr(prSet, "csTypeId") ?? "";
16899
+ const layout = loTypeId.split("/").pop();
16900
+ if (layout) opts.layout = layout;
16901
+ const style = qsTypeId.split("/").pop();
16902
+ if (style) opts.style = style;
16903
+ const color = csTypeId.split("/").pop();
16904
+ if (color) opts.color = color;
16856
16905
  }
16857
- childList.push(...linkRuns);
16858
- break;
16859
- }
16860
- case "w:bookmarkStart":
16861
- case "w:bookmarkEnd": break;
16862
- case "w:commentRangeStart": {
16863
- const id = attrNum(child, "w:id");
16864
- if (id !== void 0) childList.push({ commentRangeStart: id });
16865
- break;
16866
- }
16867
- case "w:commentRangeEnd": {
16868
- const id = attrNum(child, "w:id");
16869
- if (id !== void 0) childList.push({ commentRangeEnd: id });
16870
- break;
16871
- }
16872
- case "w:commentReference": {
16873
- const id = attrNum(child, "w:id");
16874
- if (id !== void 0) childList.push({ commentReference: id });
16875
- break;
16876
- }
16877
- case "m:oMath": {
16878
- const mathChildren = parseMathChildren(child);
16879
- childList.push({ math: { children: mathChildren } });
16880
- break;
16906
+ } else if (type === "node" && modelId) {
16907
+ const t = findDeep(pt, "a:t")[0];
16908
+ nodeMap.set(modelId, t ? textOf(t) ?? "" : "");
16881
16909
  }
16882
- default:
16883
- if (child.name && child.elements && child.elements.length > 0) childList.push(new RawPassthrough(child));
16884
- break;
16885
16910
  }
16886
- if (childList.length > 0) {
16887
- if (childList.every((c) => typeof c === "object" && c !== null && "text" in c && Object.keys(c).length <= 2)) {
16888
- const combined = childList.map((c) => c.text).join("");
16889
- if (combined && Object.keys(opts).length === 0) return combined;
16890
- if (combined) {
16891
- opts.text = combined;
16892
- return opts;
16893
- }
16911
+ const cxnLst = findChild(el, "dgm:cxnLst");
16912
+ if (!cxnLst) {
16913
+ opts.data = { nodes: [] };
16914
+ return opts;
16915
+ }
16916
+ const childrenMap = /* @__PURE__ */ new Map();
16917
+ for (const cxn of cxnLst.elements ?? []) {
16918
+ if (cxn.name !== "dgm:cxn") continue;
16919
+ const srcId = attr(cxn, "srcId");
16920
+ const destId = attr(cxn, "destId");
16921
+ if (!srcId || !destId || !nodeMap.has(destId)) continue;
16922
+ let arr = childrenMap.get(srcId);
16923
+ if (!arr) {
16924
+ arr = [];
16925
+ childrenMap.set(srcId, arr);
16894
16926
  }
16895
- opts.children = childList;
16927
+ arr.push(destId);
16896
16928
  }
16929
+ opts.data = { nodes: (childrenMap.get("0") ?? []).map((id) => buildSmartArtNode(id, nodeMap, childrenMap)) };
16897
16930
  return opts;
16898
16931
  }
16932
+ function buildSmartArtNode(id, nodeMap, childrenMap) {
16933
+ const text = nodeMap.get(id) ?? "";
16934
+ const childIds = childrenMap.get(id) ?? [];
16935
+ if (childIds.length === 0) return { text };
16936
+ return {
16937
+ text,
16938
+ children: childIds.map((cid) => buildSmartArtNode(cid, nodeMap, childrenMap))
16939
+ };
16940
+ }
16899
16941
  //#endregion
16900
16942
  //#region src/file/sdt/sdt-parse.ts
16901
16943
  /**
@@ -17763,6 +17805,135 @@ function parseCustomProperties(el) {
17763
17805
  return result;
17764
17806
  }
17765
17807
  //#endregion
17808
+ //#region src/parse/numbering.ts
17809
+ /**
17810
+ * Numbering definition parser for DOCX documents.
17811
+ *
17812
+ * Parses w:numbering elements into NumberingOptions objects for round-trip fidelity.
17813
+ *
17814
+ * @module
17815
+ */
17816
+ /**
17817
+ * Parse w:numbering element into NumberingOptions.
17818
+ */
17819
+ function parseNumberingDefinitions(el) {
17820
+ const abstractNums = /* @__PURE__ */ new Map();
17821
+ for (const child of el.elements ?? []) {
17822
+ if (child.name !== "w:abstractNum") continue;
17823
+ const id = attr(child, "w:abstractNumId");
17824
+ if (id !== void 0) abstractNums.set(id, child);
17825
+ }
17826
+ const numToAbstract = /* @__PURE__ */ new Map();
17827
+ for (const child of el.elements ?? []) {
17828
+ if (child.name !== "w:num") continue;
17829
+ const numId = attr(child, "w:numId");
17830
+ const abstractRef = findChild(child, "w:abstractNumId");
17831
+ const abstractId = abstractRef ? attr(abstractRef, "w:val") : void 0;
17832
+ if (numId !== void 0 && abstractId !== void 0) numToAbstract.set(numId, abstractId);
17833
+ }
17834
+ const configs = [];
17835
+ for (const [numId, abstractId] of numToAbstract) {
17836
+ const abstractEl = abstractNums.get(abstractId);
17837
+ if (!abstractEl) continue;
17838
+ const levels = [];
17839
+ for (const child of abstractEl.elements ?? []) {
17840
+ if (child.name !== "w:lvl") continue;
17841
+ const levelOpts = parseLevel(child);
17842
+ if (levelOpts) levels.push(levelOpts);
17843
+ }
17844
+ if (levels.length > 0) configs.push({
17845
+ reference: `list_${numId}`,
17846
+ levels
17847
+ });
17848
+ }
17849
+ if (configs.length === 0) return void 0;
17850
+ return { config: configs };
17851
+ }
17852
+ function parseLevel(el) {
17853
+ const opts = {};
17854
+ const level = attrNum(el, "w:ilvl");
17855
+ if (level !== void 0) opts.level = level;
17856
+ const start = findChild(el, "w:start");
17857
+ if (start) {
17858
+ const val = attrNum(start, "w:val");
17859
+ if (val !== void 0) opts.start = val;
17860
+ }
17861
+ const numFmt = findChild(el, "w:numFmt");
17862
+ if (numFmt) {
17863
+ const val = attr(numFmt, "w:val");
17864
+ if (val) opts.format = val;
17865
+ }
17866
+ const lvlText = findChild(el, "w:lvlText");
17867
+ if (lvlText) {
17868
+ const val = attr(lvlText, "w:val");
17869
+ if (val) opts.text = val;
17870
+ }
17871
+ const lvlJc = findChild(el, "w:lvlJc");
17872
+ if (lvlJc) {
17873
+ const val = attr(lvlJc, "w:val");
17874
+ if (val) opts.alignment = val;
17875
+ }
17876
+ const suff = findChild(el, "w:suff");
17877
+ if (suff) {
17878
+ const val = attr(suff, "w:val");
17879
+ if (val) opts.suffix = val;
17880
+ }
17881
+ if (findChild(el, "w:isLgl")) opts.isLegalNumberingStyle = true;
17882
+ const rPr = findChild(el, "w:rPr");
17883
+ if (rPr) {
17884
+ const style = {};
17885
+ const sz = findChild(rPr, "w:sz");
17886
+ if (sz) {
17887
+ const val = attrNum(sz, "w:val");
17888
+ if (val !== void 0) {
17889
+ if (!style.run) style.run = {};
17890
+ style.run.size = val;
17891
+ }
17892
+ }
17893
+ const rFonts = findChild(rPr, "w:rFonts");
17894
+ if (rFonts) {
17895
+ const ascii = attr(rFonts, "w:ascii");
17896
+ if (ascii) {
17897
+ if (!style.run) style.run = {};
17898
+ style.run.font = ascii;
17899
+ }
17900
+ }
17901
+ if (Object.keys(style).length > 0) opts.style = style;
17902
+ }
17903
+ const pPr = findChild(el, "w:pPr");
17904
+ if (pPr) {
17905
+ const style = opts.style ?? {};
17906
+ const paraStyle = {};
17907
+ const ind = findChild(pPr, "w:ind");
17908
+ if (ind) {
17909
+ const indent = {};
17910
+ const left = attrNum(ind, "w:left");
17911
+ if (left !== void 0) indent.left = left;
17912
+ const hanging = attrNum(ind, "w:hanging");
17913
+ if (hanging !== void 0) indent.hanging = hanging;
17914
+ if (Object.keys(indent).length > 0) paraStyle.indent = indent;
17915
+ }
17916
+ if (findChild(pPr, "w:tabs")) {
17917
+ const tabStops = [];
17918
+ for (const tab of pPr.elements ?? []) {
17919
+ if (tab.name !== "w:tab") continue;
17920
+ const tabObj = {};
17921
+ const pos = attrNum(tab, "w:pos");
17922
+ if (pos !== void 0) tabObj.position = pos;
17923
+ const val = attr(tab, "w:val");
17924
+ if (val) tabObj.type = val;
17925
+ tabStops.push(tabObj);
17926
+ }
17927
+ if (tabStops.length > 0) paraStyle.tabStops = tabStops;
17928
+ }
17929
+ if (Object.keys(paraStyle).length > 0) {
17930
+ style.paragraph = paraStyle;
17931
+ opts.style = style;
17932
+ }
17933
+ }
17934
+ return Object.keys(opts).length > 0 ? opts : void 0;
17935
+ }
17936
+ //#endregion
17766
17937
  //#region src/parse/settings.ts
17767
17938
  /**
17768
17939
  * Parse word/settings.xml Element into PropertiesOptions fields.
@@ -17845,10 +18016,11 @@ function parseSettings(el) {
17845
18016
  //#endregion
17846
18017
  //#region src/parse/styles.ts
17847
18018
  /**
17848
- * Style cache builder for DOCX parsing.
18019
+ * Style cache builder and definition parser for DOCX documents.
17849
18020
  *
17850
18021
  * Builds lookup maps from parsed styles.xml and numbering.xml elements
17851
18022
  * for efficient style resolution during document parsing.
18023
+ * Also parses full style definitions into StylesOptions for round-trip fidelity.
17852
18024
  *
17853
18025
  * @module
17854
18026
  */
@@ -17861,8 +18033,7 @@ function buildStyleCache(docx) {
17861
18033
  if (!docx.styles) return cache;
17862
18034
  for (const child of docx.styles.elements ?? []) {
17863
18035
  if (child.name !== "w:style") continue;
17864
- const styleIdEl = findChild(child, "w:styleId");
17865
- const styleId = styleIdEl ? attr(styleIdEl, "w:val") : void 0;
18036
+ const styleId = attr(child, "w:styleId");
17866
18037
  if (styleId) cache.set(styleId, child);
17867
18038
  }
17868
18039
  return cache;
@@ -17881,6 +18052,109 @@ function buildNumberingCache(docx) {
17881
18052
  }
17882
18053
  return cache;
17883
18054
  }
18055
+ /**
18056
+ * Parse w:styles element into StylesOptions.
18057
+ */
18058
+ function parseStyleDefinitions(el, ctx) {
18059
+ const opts = {};
18060
+ const paragraphStyles = [];
18061
+ const characterStyles = [];
18062
+ for (const child of el.elements ?? []) if (child.name === "w:docDefaults") {
18063
+ const defOpts = parseDocDefaults(child);
18064
+ if (defOpts) opts.default = defOpts;
18065
+ } else if (child.name === "w:style") {
18066
+ const styleOpts = parseStyleElement(child, ctx);
18067
+ if (!styleOpts) continue;
18068
+ const type = styleOpts._type;
18069
+ delete styleOpts._type;
18070
+ if (type === "paragraph") paragraphStyles.push(styleOpts);
18071
+ else if (type === "character") characterStyles.push(styleOpts);
18072
+ }
18073
+ if (paragraphStyles.length > 0) opts.paragraphStyles = paragraphStyles;
18074
+ if (characterStyles.length > 0) opts.characterStyles = characterStyles;
18075
+ return Object.keys(opts).length > 0 ? opts : void 0;
18076
+ }
18077
+ function parseDocDefaults(el) {
18078
+ const result = {};
18079
+ const docDefaults = {};
18080
+ const rPrDefault = findChild(el, "w:rPrDefault");
18081
+ if (rPrDefault) {
18082
+ const rPr = findChild(rPrDefault, "w:rPr");
18083
+ if (rPr) {
18084
+ const runDefaults = parseRunProperties(rPr);
18085
+ if (Object.keys(runDefaults).length > 0) docDefaults.run = runDefaults;
18086
+ }
18087
+ }
18088
+ const pPrDefault = findChild(el, "w:pPrDefault");
18089
+ if (pPrDefault) {
18090
+ const pPr = findChild(pPrDefault, "w:pPr");
18091
+ if (pPr) {
18092
+ const paraDefaults = {};
18093
+ const spacing = findChild(pPr, "w:spacing");
18094
+ if (spacing) {
18095
+ const sp = {};
18096
+ const before = attrNum(spacing, "w:before");
18097
+ if (before !== void 0) sp.before = before;
18098
+ const after = attrNum(spacing, "w:after");
18099
+ if (after !== void 0) sp.after = after;
18100
+ const line = attrNum(spacing, "w:line");
18101
+ if (line !== void 0) sp.line = line;
18102
+ if (Object.keys(sp).length > 0) paraDefaults.spacing = sp;
18103
+ }
18104
+ if (Object.keys(paraDefaults).length > 0) docDefaults.paragraph = paraDefaults;
18105
+ }
18106
+ }
18107
+ if (Object.keys(docDefaults).length > 0) result.document = docDefaults;
18108
+ return Object.keys(result).length > 0 ? result : void 0;
18109
+ }
18110
+ function parseStyleElement(el, ctx) {
18111
+ const opts = {};
18112
+ const type = attr(el, "w:type");
18113
+ if (type) opts._type = type;
18114
+ const id = attr(el, "w:styleId");
18115
+ if (id) opts.id = id;
18116
+ if (attrBool(el, "w:default")) opts.default = true;
18117
+ if (attrBool(el, "w:customStyle")) opts.customStyle = "1";
18118
+ const nameEl = findChild(el, "w:name");
18119
+ if (nameEl) {
18120
+ const name = attr(nameEl, "w:val");
18121
+ if (name) opts.name = name;
18122
+ }
18123
+ const basedOn = findChild(el, "w:basedOn");
18124
+ if (basedOn) {
18125
+ const val = attr(basedOn, "w:val");
18126
+ if (val) opts.basedOn = val;
18127
+ }
18128
+ const next = findChild(el, "w:next");
18129
+ if (next) {
18130
+ const val = attr(next, "w:val");
18131
+ if (val) opts.next = val;
18132
+ }
18133
+ const link = findChild(el, "w:link");
18134
+ if (link) {
18135
+ const val = attr(link, "w:val");
18136
+ if (val) opts.link = val;
18137
+ }
18138
+ const uiPriority = findChild(el, "w:uiPriority");
18139
+ if (uiPriority) {
18140
+ const val = attrNum(uiPriority, "w:val");
18141
+ if (val !== void 0) opts.uiPriority = val;
18142
+ }
18143
+ if (findChild(el, "w:qFormat")) opts.quickFormat = true;
18144
+ if (findChild(el, "w:semiHidden")) opts.semiHidden = true;
18145
+ if (findChild(el, "w:unhideWhenUsed")) opts.unhideWhenUsed = true;
18146
+ const pPr = findChild(el, "w:pPr");
18147
+ if (pPr) {
18148
+ const paraOpts = parseParagraphProperties(pPr, ctx);
18149
+ if (Object.keys(paraOpts).length > 0) opts.paragraph = paraOpts;
18150
+ }
18151
+ const rPr = findChild(el, "w:rPr");
18152
+ if (rPr) {
18153
+ const runOpts = parseRunProperties(rPr);
18154
+ if (Object.keys(runOpts).length > 0) opts.run = runOpts;
18155
+ }
18156
+ return opts;
18157
+ }
17884
18158
  //#endregion
17885
18159
  //#region src/parse.ts
17886
18160
  function resolveRelsPath(target) {
@@ -17892,6 +18166,7 @@ function parseDocPartRefs(doc) {
17892
18166
  const refs = {
17893
18167
  headers: /* @__PURE__ */ new Map(),
17894
18168
  footers: /* @__PURE__ */ new Map(),
18169
+ hyperlinks: /* @__PURE__ */ new Map(),
17895
18170
  charts: /* @__PURE__ */ new Map(),
17896
18171
  diagramData: /* @__PURE__ */ new Map(),
17897
18172
  media: /* @__PURE__ */ new Map(),
@@ -17917,6 +18192,7 @@ function parseDocPartRefs(doc) {
17917
18192
  else if (type.includes("/image") || type.includes("/media")) refs.media.set(id, path);
17918
18193
  else if (type.includes("/aFChunk")) refs.afChunks.set(id, path);
17919
18194
  else if (type.includes("/subDocument")) refs.subDocs.set(id, path);
18195
+ else if (type.includes("/hyperlink")) refs.hyperlinks.set(id, target);
17920
18196
  }
17921
18197
  return refs;
17922
18198
  }
@@ -17977,10 +18253,43 @@ function parseDocument(data) {
17977
18253
  if (cpEntries.length > 0) opts.customProperties = cpEntries;
17978
18254
  }
17979
18255
  }
18256
+ if (docx.partRefs.comments) {
18257
+ const commentsEl = docx.doc.get(docx.partRefs.comments);
18258
+ if (commentsEl) {
18259
+ const comments = parseComments(commentsEl, ctx);
18260
+ if (comments.length > 0) opts.comments = { children: comments };
18261
+ }
18262
+ }
18263
+ if (docx.partRefs.footnotes) {
18264
+ const footnotesEl = docx.doc.get(docx.partRefs.footnotes);
18265
+ if (footnotesEl) {
18266
+ const footnotes = parseNotesContent(footnotesEl, "w:footnote", ctx);
18267
+ const footnotesMap = {};
18268
+ for (const fn of footnotes) footnotesMap[String(fn.id)] = { children: fn.children };
18269
+ if (Object.keys(footnotesMap).length > 0) opts.footnotes = footnotesMap;
18270
+ }
18271
+ }
18272
+ if (docx.partRefs.endnotes) {
18273
+ const endnotesEl = docx.doc.get(docx.partRefs.endnotes);
18274
+ if (endnotesEl) {
18275
+ const endnotes = parseNotesContent(endnotesEl, "w:endnote", ctx);
18276
+ const endnotesMap = {};
18277
+ for (const en of endnotes) endnotesMap[String(en.id)] = { children: en.children };
18278
+ if (Object.keys(endnotesMap).length > 0) opts.endnotes = endnotesMap;
18279
+ }
18280
+ }
18281
+ if (docx.styles) {
18282
+ const styleOpts = parseStyleDefinitions(docx.styles, ctx);
18283
+ if (styleOpts) opts.styles = styleOpts;
18284
+ }
18285
+ if (docx.numbering) {
18286
+ const numOpts = parseNumberingDefinitions(docx.numbering);
18287
+ if (numOpts) opts.numbering = numOpts;
18288
+ }
17980
18289
  return opts;
17981
18290
  }
17982
18291
  function parseDocx(data) {
17983
- const doc = parseArchive(data);
18292
+ const doc = parseArchive(toUint8Array(data));
17984
18293
  const documentEl = doc.get("word/document.xml");
17985
18294
  if (!documentEl) throw new Error("word/document.xml not found");
17986
18295
  const body = documentEl.elements?.find((e) => e.name === "w:body");
@@ -18006,6 +18315,52 @@ function parseDocx(data) {
18006
18315
  customProps
18007
18316
  };
18008
18317
  }
18318
+ /**
18319
+ * Parse w:comments element into CommentOptions array.
18320
+ */
18321
+ function parseComments(el, ctx) {
18322
+ const comments = [];
18323
+ for (const child of el.elements ?? []) {
18324
+ if (child.name !== "w:comment") continue;
18325
+ const id = attrNum(child, "w:id");
18326
+ if (id === void 0) continue;
18327
+ const author = attr(child, "w:author");
18328
+ const initials = attr(child, "w:initials");
18329
+ const date = attr(child, "w:date");
18330
+ const children = [];
18331
+ for (const sub of child.elements ?? []) if (sub.name === "w:p") children.push(parseParagraph(sub, ctx));
18332
+ comments.push({
18333
+ id,
18334
+ author: author || void 0,
18335
+ initials: initials || void 0,
18336
+ date: date || void 0,
18337
+ children
18338
+ });
18339
+ }
18340
+ return comments;
18341
+ }
18342
+ /**
18343
+ * Parse footnotes or endnotes content into {id, children} array.
18344
+ * Skips system notes (id=-1 for separator, id=0 for continuation separator).
18345
+ */
18346
+ function parseNotesContent(el, tagName, ctx) {
18347
+ const notes = [];
18348
+ for (const child of el.elements ?? []) {
18349
+ if (child.name !== tagName) continue;
18350
+ const id = attrNum(child, "w:id");
18351
+ if (id === void 0) continue;
18352
+ if (id < 1) continue;
18353
+ const type = attr(child, "w:type");
18354
+ const children = [];
18355
+ for (const sub of child.elements ?? []) if (sub.name === "w:p") children.push(parseParagraph(sub, ctx));
18356
+ notes.push({
18357
+ id,
18358
+ type: type || void 0,
18359
+ children
18360
+ });
18361
+ }
18362
+ return notes;
18363
+ }
18009
18364
  //#endregion
18010
18365
  //#region src/index.ts
18011
18366
  var src_exports = /* @__PURE__ */ __exportAll({