@office-open/docx 0.14.2 → 0.14.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
@@ -1,4 +1,4 @@
1
- import { DOCX_NS, DOCX_PARTS, EmbeddingCollection, IMAGE_MEDIA_CONTENT_TYPES, Media, OoxmlMimeType, ParsedArchive, Relationships, TargetModeType, addBinaryFile, addSmartArtRelationships, appPropertiesDesc, appendContentType, appendOverride, appendRelationship, applyCorePropertiesOverride, assertEncryptedExclusive, blipDesc, buildCorePropertiesXmlString, buildRootRelationships, collectPassthroughParts, compileMapping, contentTypesDesc, convertEmuToPixels, convertInchesToTwip, convertToEmu, convertToPt, convertToTwip, createPacker, createReplacer, createThemeXml, createTraverser, customGeometryDesc, customPropertiesDesc, decimalNumber, deriveContentTypes, derivePasswordHash, dropDanglingPassthroughRels, effectListDesc, eighthPointMeasureValue, encodeBase64, encryptedContainerOutput, encryptedContainerStream, fillDesc, findAndReplaceImagePlaceholders, formatId, getNextRelationshipIndex, getReferencedMedia, hasPlaceholders, hexColorValue, hpsMeasureValue, imageTypeFromPath, isEncryptedContainer, mapOptional, nextNumericId, nextVmlShapeId, optionalRelsPart, outlineDesc, parseAngle, parseArchive, parseColorChoice, parseCorePropsElement, parseNonVisualDrawingProperties, parseOnOff, parseVmlImageData, parseVmlShapeChild, parseVmlShapeDefaults, parseVmlShapeLayout, parseVmlShapeStyle, parseVmlShapetype, parseVmlStyle, partPathToRelsPath, pictureLockingDesc, pointMeasureValue, presetGeometryDesc, replaceAllPlaceholders, replaceImagePlaceholders, replaceNumberingPlaceholders, resolveRelationshipTarget, resolverFromRegistry, shapePropertiesDesc, strFromU8, stringifyVmlBackground, stringifyVmlShape, stringifyVmlShapeChild, stringifyVmlShapeDefaults, stringifyVmlShapeLayout, stringifyVmlShapetype, toJson, toUint8Array, toUint8ArrayAsync, uCharHexNumber, uniqueId, uniqueNumericIdCreator, uniqueUuid, unzipSync, xsdJcAlignment, xsdMathStyle, xsdShadingPattern, xsdTableWidthType, xsdVerticalMergeRev, zipAndConvert } from "@office-open/core";
1
+ import { DOCX_NS, DOCX_PARTS, EmbeddingCollection, IMAGE_MEDIA_CONTENT_TYPES, Media, OoxmlMimeType, ParsedArchive, RELATIONSHIP_TYPES, Relationships, TargetModeType, addModelBinaries, addSmartArtRelationships, appPropertiesDesc, appendContentType, appendOverride, appendRelationship, applyCorePropertiesOverride, assertEncryptedExclusive, blipDesc, buildCorePropertiesXmlString, buildRootRelationships, collectPassthroughParts, compileMapping, contentTypesDesc, convertEmuToPixels, convertInchesToTwip, convertToEmu, convertToPt, convertToTwip, createPacker, createReplacer, createThemeXml, createTraverser, customGeometryDesc, customPropertiesDesc, decimalNumber, derivePasswordHash, dropDanglingPassthroughRels, effectListDesc, eighthPointMeasureValue, encodeBase64, encryptedContainerOutput, encryptedContainerStream, fillDesc, finalizeContentTypes, findAndReplaceImagePlaceholders, formatId, getNextRelationshipIndex, getReferencedMedia, hasPlaceholders, hexColorValue, hpsMeasureValue, imageTypeFromPath, isEncryptedContainer, mapOptional, nextNumericId, nextVmlShapeId, optionalRelsPart, outlineDesc, parseAngle, parseArchive, parseColorChoice, parseCorePropsElement, parseNonVisualDrawingProperties, parseOnOff, parseVmlImageData, parseVmlShapeChild, parseVmlShapeDefaults, parseVmlShapeLayout, parseVmlShapeStyle, parseVmlShapetype, parseVmlStyle, partPathToRelsPath, pictureLockingDesc, pointMeasureValue, presetGeometryDesc, replaceAllPlaceholders, replaceImagePlaceholders, replaceNumberingPlaceholders, resolveRelationshipTarget, resolverFromRegistry, shapePropertiesDesc, strFromU8, stringifyVmlBackground, stringifyVmlShape, stringifyVmlShapeChild, stringifyVmlShapeDefaults, stringifyVmlShapeLayout, stringifyVmlShapetype, toJson, toUint8Array, toUint8ArrayAsync, uCharHexNumber, uniqueId, uniqueNumericIdCreator, uniqueUuid, unzipSync, xsdJcAlignment, xsdMathStyle, xsdShadingPattern, xsdTableWidthType, xsdVerticalMergeRev, zipAndConvert } from "@office-open/core";
2
2
  import { bodyPropertiesDesc, calculateEffectExtent, connectorLockingDesc, createBodyProperties as createBodyProperties$1, createColorElement, groupShapePropertiesDesc, parseBodyProperties, parseNonVisualContentPartProperties, pictureLockingDesc as pictureLockingDesc$1, scene3DDesc, shape3DDesc, shapeLockingDesc, shapePropertiesDesc as shapePropertiesDesc$1, stringifyBlipEffects, stringifyNonVisualContentPartProperties, stringifyNonVisualDrawingProperties } from "@office-open/core/drawing";
3
3
  import { OOXML_XML_DECLARATION, attr, attrBool, attrMeasure, attrNum, attrsRaw, children, colorAttr, element, escapeXml, findChild, findDeep, findFirst, parse, stringify, stringifyElement, textOf } from "@office-open/xml";
4
4
  import { ChartCollection, buildUserShapesData, chartSpaceDesc, userShapesDesc } from "@office-open/core/chart";
@@ -2713,18 +2713,20 @@ function stringifyParagraphProperties(options) {
2713
2713
  if (bParts.length) s += `<w:pBdr>${bParts.join("")}</w:pBdr>`;
2714
2714
  }
2715
2715
  if (options.shading) s += shadingStr(options.shading);
2716
- const tabDefs = [
2717
- ...options.rightTabStop !== void 0 ? [{
2718
- position: options.rightTabStop,
2719
- type: "right"
2720
- }] : [],
2721
- ...options.tabStops ? options.tabStops : [],
2722
- ...options.leftTabStop !== void 0 ? [{
2723
- position: options.leftTabStop,
2724
- type: "left"
2725
- }] : []
2726
- ];
2727
- if (tabDefs.length > 0) s += tabStopsStr(tabDefs);
2716
+ if (options.rightTabStop !== void 0 || options.leftTabStop !== void 0 || options.tabStops !== void 0) {
2717
+ const tabDefs = [
2718
+ ...options.rightTabStop !== void 0 ? [{
2719
+ position: options.rightTabStop,
2720
+ type: "right"
2721
+ }] : [],
2722
+ ...options.tabStops ? options.tabStops : [],
2723
+ ...options.leftTabStop !== void 0 ? [{
2724
+ position: options.leftTabStop,
2725
+ type: "left"
2726
+ }] : []
2727
+ ];
2728
+ if (tabDefs.length > 0) s += tabStopsStr(tabDefs);
2729
+ }
2728
2730
  if (options.suppressAutoHyphens !== void 0) s += onOff$2("w:suppressAutoHyphens", options.suppressAutoHyphens);
2729
2731
  if (options.kinsoku !== void 0) s += onOff$2("w:kinsoku", options.kinsoku);
2730
2732
  if (options.wordWrap !== void 0) s += onOff$2("w:wordWrap", options.wordWrap);
@@ -3037,7 +3039,7 @@ function parseSdtBlock(el, ctx, parseChildren) {
3037
3039
  *
3038
3040
  * @module
3039
3041
  */
3040
- const ALTCHUNK_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk";
3042
+ const ALTCHUNK_REL_TYPE = RELATIONSHIP_TYPES.aFChunk;
3041
3043
  function wrapHtmlDocument(fragment) {
3042
3044
  if (/<(!DOCTYPE|html|HTML)/i.test(fragment)) return fragment;
3043
3045
  return `<!DOCTYPE html>\n<html><head><meta charset="utf-8"></head>\n<body>${fragment}</body></html>`;
@@ -3093,7 +3095,7 @@ const altChunkDesc = {
3093
3095
  return opts;
3094
3096
  }
3095
3097
  };
3096
- const SUBDOC_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/subDocument";
3098
+ const SUBDOC_REL_TYPE = RELATIONSHIP_TYPES.subDocument;
3097
3099
  const subDocDesc = {
3098
3100
  kind: "custom",
3099
3101
  stringify(opts, ctx) {
@@ -3400,138 +3402,6 @@ const TextWrappingSide = {
3400
3402
  LARGEST: "largest"
3401
3403
  };
3402
3404
  //#endregion
3403
- //#region src/parts/drawing/text-wrap/wrap-tight.ts
3404
- /**
3405
- * Wrap Tight module for DrawingML text wrapping.
3406
- *
3407
- * This module provides tight text wrapping for floating drawings
3408
- * where text wraps closely around the image shape.
3409
- *
3410
- * Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
3411
- *
3412
- * @module
3413
- */
3414
- /**
3415
- * Creates a default rectangular wrap polygon matching the image extent.
3416
- *
3417
- * Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
3418
- *
3419
- * ## XSD Schema
3420
- * ```xml
3421
- * <xsd:complexType name="CT_WrapPath">
3422
- * <xsd:sequence>
3423
- * <xsd:element name="start" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/>
3424
- * <xsd:element name="lineTo" type="a:CT_Point2D" minOccurs="2" maxOccurs="unbounded"/>
3425
- * </xsd:sequence>
3426
- * <xsd:attribute name="edited" type="xsd:boolean" use="optional"/>
3427
- * </xsd:complexType>
3428
- * ```
3429
- */
3430
- const createWrapPolygon$1 = (cx, cy) => element("wp:wrapPolygon", { edited: "0" }, [
3431
- `<wp:start x="0" y="0"/>`,
3432
- `<wp:lineTo x="0" y="${-cy}"/>`,
3433
- `<wp:lineTo x="${cx}" y="${-cy}"/>`,
3434
- `<wp:lineTo x="${cx}" y="0"/>`,
3435
- `<wp:lineTo x="0" y="0"/>`
3436
- ]);
3437
- /**
3438
- * Creates tight text wrapping for a floating drawing.
3439
- *
3440
- * WrapTight causes text to wrap closely around the contours
3441
- * of the drawing rather than its rectangular bounding box.
3442
- * A default rectangular wrap polygon matching the image extent is generated.
3443
- *
3444
- * Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
3445
- *
3446
- * ## XSD Schema
3447
- * ```xml
3448
- * <xsd:complexType name="CT_WrapTight">
3449
- * <xsd:sequence>
3450
- * <xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
3451
- * </xsd:sequence>
3452
- * <xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
3453
- * <xsd:attribute name="distL" type="ST_WrapDistance"/>
3454
- * <xsd:attribute name="distR" type="ST_WrapDistance"/>
3455
- * </xsd:complexType>
3456
- * ```
3457
- */
3458
- const createWrapTight = (textWrapping, margins = {
3459
- bottom: 0,
3460
- left: 0,
3461
- right: 0,
3462
- top: 0
3463
- }, extent) => element("wp:wrapTight", {
3464
- distL: margins.left,
3465
- distR: margins.right,
3466
- wrapText: textWrapping.side || TextWrappingSide.BOTH_SIDES
3467
- }, [createWrapPolygon$1(extent.x, extent.y)]);
3468
- //#endregion
3469
- //#region src/parts/drawing/text-wrap/wrap-through.ts
3470
- /**
3471
- * Wrap Through module for DrawingML text wrapping.
3472
- *
3473
- * This module provides "through" text wrapping for floating drawings
3474
- * where text wraps through the image contours, filling any concave areas.
3475
- *
3476
- * Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
3477
- *
3478
- * @module
3479
- */
3480
- /**
3481
- * Creates a default rectangular wrap polygon matching the image extent.
3482
- *
3483
- * Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
3484
- *
3485
- * ## XSD Schema
3486
- * ```xml
3487
- * <xsd:complexType name="CT_WrapPath">
3488
- * <xsd:sequence>
3489
- * <xsd:element name="start" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/>
3490
- * <xsd:element name="lineTo" type="a:CT_Point2D" minOccurs="2" maxOccurs="unbounded"/>
3491
- * </xsd:sequence>
3492
- * <xsd:attribute name="edited" type="xsd:boolean" use="optional"/>
3493
- * </xsd:complexType>
3494
- * ```
3495
- */
3496
- const createWrapPolygon = (cx, cy) => element("wp:wrapPolygon", { edited: "0" }, [
3497
- `<wp:start x="0" y="0"/>`,
3498
- `<wp:lineTo x="0" y="${-cy}"/>`,
3499
- `<wp:lineTo x="${cx}" y="${-cy}"/>`,
3500
- `<wp:lineTo x="${cx}" y="0"/>`,
3501
- `<wp:lineTo x="0" y="0"/>`
3502
- ]);
3503
- /**
3504
- * Creates "through" text wrapping for a floating drawing.
3505
- *
3506
- * WrapThrough is similar to WrapTight but allows text to wrap through
3507
- * the concave portions of the drawing shape (e.g., the inside of the letter "O").
3508
- * A default rectangular wrap polygon matching the image extent is generated.
3509
- *
3510
- * Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
3511
- *
3512
- * ## XSD Schema
3513
- * ```xml
3514
- * <xsd:complexType name="CT_WrapThrough">
3515
- * <xsd:sequence>
3516
- * <xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
3517
- * </xsd:sequence>
3518
- * <xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
3519
- * <xsd:attribute name="distL" type="ST_WrapDistance"/>
3520
- * <xsd:attribute name="distR" type="ST_WrapDistance"/>
3521
- * </xsd:complexType>
3522
- * ```
3523
- */
3524
- const createWrapThrough = (textWrapping, margins = {
3525
- bottom: 0,
3526
- left: 0,
3527
- right: 0,
3528
- top: 0
3529
- }, extent) => element("wp:wrapThrough", {
3530
- distL: margins.left,
3531
- distR: margins.right,
3532
- wrapText: textWrapping.side || TextWrappingSide.BOTH_SIDES
3533
- }, [createWrapPolygon(extent.x, extent.y)]);
3534
- //#endregion
3535
3405
  //#region src/shared/constants.ts
3536
3406
  /**
3537
3407
  * Shared constants for WordprocessingML documents.
@@ -3640,15 +3510,6 @@ const NumberFormat = {
3640
3510
  UPPER_ROMAN: "upperRoman",
3641
3511
  VIETNAMESE_COUNTING: "vietnameseCounting"
3642
3512
  };
3643
- /**
3644
- * XML space handling modes.
3645
- *
3646
- * @publicApi
3647
- */
3648
- const SpaceType = {
3649
- DEFAULT: "default",
3650
- PRESERVE: "preserve"
3651
- };
3652
3513
  //#endregion
3653
3514
  //#region src/parts/drawing/floating/floating-position.ts
3654
3515
  /**
@@ -4559,7 +4420,7 @@ var FontWrapper = class {
4559
4420
  relIdx++;
4560
4421
  font.embedRid = `rId${relIdx}`;
4561
4422
  const target = font.odttfPath ? font.odttfPath.startsWith("word/") ? font.odttfPath.slice(5) : font.odttfPath : `fonts/${font.name}.odttf`;
4562
- this.relationships.addRelationship(relIdx, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/font", target);
4423
+ this.relationships.addRelationship(relIdx, RELATIONSHIP_TYPES.font, target);
4563
4424
  }
4564
4425
  }
4565
4426
  };
@@ -7923,9 +7784,9 @@ const CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
7923
7784
  const DGM_URI = "http://schemas.openxmlformats.org/drawingml/2006/diagram";
7924
7785
  const WPS_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape";
7925
7786
  const WPG_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup";
7926
- const HYPERLINK_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
7927
- const IMAGE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
7928
- const TEXT_BOX_REL = "http://schemas.microsoft.com/office/2006/relationships/txbx";
7787
+ const HYPERLINK_REL = RELATIONSHIP_TYPES.hyperlink;
7788
+ const IMAGE_REL = RELATIONSHIP_TYPES.image;
7789
+ const TEXT_BOX_REL = RELATIONSHIP_TYPES.txbxMs;
7929
7790
  const SVG_BLIP_EXT_URI = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}";
7930
7791
  const USE_LOCAL_DPI_EXT_URI = "{28A0092B-C50C-407E-A947-70E740481C1C}";
7931
7792
  const A14_NS = "http://schemas.microsoft.com/office/drawing/2010/main";
@@ -8444,347 +8305,637 @@ const drawingDesc = {
8444
8305
  }
8445
8306
  };
8446
8307
  //#endregion
8447
- //#region src/parts/paragraph/run/field.ts
8448
- /**
8449
- * Field module for WordprocessingML documents.
8450
- *
8451
- * This module provides support for complex fields, which are regions of text
8452
- * that can contain dynamic content such as page numbers, dates, or mail merge fields.
8453
- * Fields are delimited by field character elements (begin, separate, end).
8454
- *
8455
- * Reference: http://officeopenxml.com/WPrun.php
8456
- *
8457
- * @module
8458
- */
8459
- /**
8460
- * Field character types that delimit field regions.
8461
- *
8462
- * @internal
8463
- */
8464
- const FieldCharacterType = {
8465
- BEGIN: "begin",
8466
- END: "end",
8467
- SEPARATE: "separate"
8468
- };
8469
- /**
8470
- * Creates a field character element.
8471
- *
8472
- * ## XSD Schema
8473
- * ```xml
8474
- * <xsd:complexType name="CT_FldChar">
8475
- * <xsd:sequence>
8476
- * <xsd:element name="fldData" type="CT_Text" minOccurs="0"/>
8477
- * <xsd:element name="ffData" type="CT_FFData" minOccurs="0"/>
8478
- * <xsd:element name="numberingChange" type="CT_TrackChangeNumbering" minOccurs="0"/>
8479
- * </xsd:sequence>
8480
- * <xsd:attribute name="fldCharType" type="ST_FldCharType" use="required"/>
8481
- * <xsd:attribute name="fldLock" type="s:ST_OnOff"/>
8482
- * <xsd:attribute name="dirty" type="s:ST_OnOff"/>
8483
- * </xsd:complexType>
8484
- * ```
8485
- * @internal
8486
- */
8487
- const createFieldChar = (type, dirty, ffData, fldData, fieldLock) => {
8488
- const children = [];
8489
- if (fldData !== void 0) children.push(element("w:fldData", { "xml:space": "preserve" }, [fldData]));
8490
- if (ffData) children.push(ffData);
8491
- return element("w:fldChar", {
8492
- "w:dirty": dirty,
8493
- "w:fldLock": fieldLock,
8494
- "w:fldCharType": type
8495
- }, children.length > 0 ? children : void 0);
8496
- };
8308
+ //#region src/parts/inline-drawings.ts
8309
+ let nextChartId = 1;
8497
8310
  /**
8498
- * Creates the beginning of a complex field.
8499
- *
8500
- * The Begin element marks the start of a field. A field consists of a begin character,
8501
- * field instructions, an optional separate character, field result, and an end character.
8502
- *
8503
- * For form fields, pass `formField` to embed `w:ffData` within the begin `w:fldChar`.
8504
- *
8505
- * @param dirty - Whether the field should be recalculated
8506
- * @param formField - Optional form field data to embed in the begin character
8507
- *
8508
- * @example
8509
- * ```typescript
8510
- * // Simple field begin
8511
- * createBegin();
8512
- *
8513
- * // Form field (checkbox)
8514
- * createBegin(false, {
8515
- * name: "Check1",
8516
- * checkBox: { checked: true, sizeAuto: true },
8517
- * });
8518
- * ```
8311
+ * Wrap a `<w:drawing>` run, rebuilding an mc:AlternateContent wrapper when a
8312
+ * VML fallback was carried from parse (Choice stays structured/editable,
8313
+ * Fallback round-trips as raw XML for fidelity).
8519
8314
  */
8520
- const createBegin = (dirty, formField, fieldLock) => createFieldChar(FieldCharacterType.BEGIN, dirty, formField ? createFormFieldData(formField) : void 0, void 0, fieldLock);
8315
+ function wrapDrawingRun(drawingXml, opts) {
8316
+ const xml = drawingXml ?? "";
8317
+ const rPr = stringifyRunProperties(opts.runProperties) ?? "";
8318
+ const lrpb = opts.lastRenderedPageBreak ? "<w:lastRenderedPageBreak/>" : "";
8319
+ if (opts.vmlFallback) return `<w:r>${rPr}${lrpb}<mc:AlternateContent><mc:Choice Requires="${opts.mcChoiceRequires ?? "wps"}">${xml}</mc:Choice>${opts.vmlFallback}</mc:AlternateContent></w:r>`;
8320
+ return `<w:r>${rPr}${lrpb}${xml}</w:r>`;
8321
+ }
8521
8322
  /**
8522
- * Creates the separator between field code and field result in a complex field.
8323
+ * Register media carried by a VML fallback (mc:AlternateContent Fallback) so the
8324
+ * compiler resolves the fallback's `{fileName}` placeholders into rIds.
8523
8325
  *
8524
- * The Separate element divides the field code (instructions) from the field result
8525
- * (the computed value).
8326
+ * A VML fallback image mirrors its Choice blip (same source bytes). When the
8327
+ * blip is already registered, reuse it and remap the fallback's `{fileName}`
8328
+ * placeholder to the shared media — matching Office, which emits one
8329
+ * relationship/file per image rather than a duplicate for the VML branch.
8526
8330
  */
8527
- const createSeparate = (dirty) => createFieldChar(FieldCharacterType.SEPARATE, dirty);
8331
+ function registerVmlFallbackMedia(opts, ctx) {
8332
+ if (!opts.vmlFallbackMedia) return;
8333
+ for (const m of opts.vmlFallbackMedia) {
8334
+ const data = toUint8Array(m.data);
8335
+ const entry = ctx.file.media.addMedia(data, m.type, (fileName) => ({
8336
+ type: m.type,
8337
+ data,
8338
+ fileName,
8339
+ transformation: {
8340
+ emus: {
8341
+ x: 0,
8342
+ y: 0
8343
+ },
8344
+ pixels: {
8345
+ x: 0,
8346
+ y: 0
8347
+ }
8348
+ }
8349
+ }), m.fileName);
8350
+ if (entry.fileName !== m.fileName && opts.vmlFallback) opts.vmlFallback = opts.vmlFallback.split(`{${m.fileName}}`).join(`{${entry.fileName}}`);
8351
+ }
8352
+ }
8353
+ /** Rewrite ../media targets inside verbatim data rels after the media
8354
+ * collection re-allocated pinned names. All renames apply in one pass over
8355
+ * the original text, each match bounded by its closing quote, so a name
8356
+ * that prefixes another cannot collide and chained renames cannot re-hit
8357
+ * an already-rewritten target. Preserves the input form (string stays
8358
+ * string, bytes stay bytes). */
8359
+ function remapDataRelsTargets(rels, renames) {
8360
+ const isText = typeof rels === "string";
8361
+ const text = isText ? rels : new TextDecoder().decode(toUint8Array(rels));
8362
+ let out = "";
8363
+ let last = 0;
8364
+ for (const m of text.matchAll(/\.\.\/media\/([^"']*)["']/g)) {
8365
+ const name = m[1] ?? "";
8366
+ const to = renames.get(name);
8367
+ if (to === void 0) continue;
8368
+ const start = (m.index ?? 0) + 9;
8369
+ out += text.slice(last, start) + to;
8370
+ last = start + name.length;
8371
+ }
8372
+ out += text.slice(last);
8373
+ return isText ? out : new TextEncoder().encode(out);
8374
+ }
8375
+ /** Content fingerprint of the raw source parts: every field participates so
8376
+ * two instances that differ in any raw part (or in their companion rels or
8377
+ * media names) never merge into one diagram part set. */
8378
+ function rawSmartArtFingerprint(raw) {
8379
+ if (!raw) return void 0;
8380
+ const b64 = (v) => v === void 0 ? void 0 : encodeBase64(toUint8Array(v));
8381
+ return JSON.stringify({
8382
+ data: b64(raw.data),
8383
+ layout: b64(raw.layout),
8384
+ style: b64(raw.style),
8385
+ color: b64(raw.color),
8386
+ dataRels: b64(raw.dataRels),
8387
+ media: raw.media?.map((m) => m.fileName)
8388
+ });
8389
+ }
8390
+ /** Hash SmartArt data for unique key generation (duplicated from SmartArtRun). */
8391
+ function hashSmartArtData(options) {
8392
+ const data = JSON.stringify({
8393
+ nodes: options.nodes,
8394
+ layout: options.layout,
8395
+ style: options.style,
8396
+ color: options.color,
8397
+ raw: rawSmartArtFingerprint(options.raw)
8398
+ });
8399
+ let hash = 0;
8400
+ for (let i = 0; i < data.length; i++) {
8401
+ const char = data.charCodeAt(i);
8402
+ hash = (hash << 5) - hash + char | 0;
8403
+ }
8404
+ return Math.abs(hash);
8405
+ }
8528
8406
  /**
8529
- * Creates the end of a complex field.
8407
+ * Stringify the drawing-family children of the JSON dispatch: picture, chart,
8408
+ * SmartArt, WPS shape, content part, and WPG group. Each registers its media
8409
+ * or part side effects, then emits the `<w:drawing>` run.
8530
8410
  *
8531
- * The End element marks the end of a field. Every field that begins with a Begin
8532
- * element must be terminated with an End element.
8411
+ * Returns `undefined` when the child is not a drawing-family wrapper.
8533
8412
  */
8534
- const createEnd = (dirty) => createFieldChar(FieldCharacterType.END, dirty);
8535
- //#endregion
8536
- //#region src/parts/inline.ts
8537
- /**
8538
- * Shared inline run/paragraph stringification for DOCX descriptors.
8539
- *
8540
- * Used by table.ts, comments.ts, body.ts, and other descriptors that need to
8541
- * serialize paragraph/run content. Includes JSON child dispatch for all
8542
- * ParagraphChild variants (picture, chart, hyperlink, etc.).
8543
- *
8544
- * Pure string concatenation — no intermediate object tree.
8545
- *
8546
- * @module
8547
- */
8548
- function stringifySymbolRunInner(opts) {
8549
- return `<${opts.kind === "office2016" ? "w16se:sym" : "w:sym"} w:char="${escapeXml(opts.char)}" w:font="${escapeXml(opts.symbolFont ?? "Wingdings")}"/>`;
8550
- }
8551
- /** Serialize a complex field's run chain. Inside a w:del wrapper the
8552
- * instruction is spelled w:delInstrText and the cached result w:delText. */
8553
- function stringifyComplexFieldRuns(cf, isDelete = false) {
8554
- const instrTag = isDelete ? "w:delInstrText" : "w:instrText";
8555
- const textTag = isDelete ? "w:delText" : "w:t";
8556
- const ctrl = cf.rPrXml ?? "";
8557
- const res = cf.resultRPrXml ?? ctrl;
8558
- const instrXml = cf.instrRunsXml ?? (cf.instruction !== "" ? `<w:r>${ctrl}<${instrTag} xml:space="preserve">${escapeXml(cf.instruction)}</${instrTag}></w:r>` : "");
8559
- const resultXml = cf.resultRunsXml !== void 0 ? `<w:r>${ctrl}<w:fldChar w:fldCharType="separate"/></w:r>` + cf.resultRunsXml : cf.result !== void 0 ? `<w:r>${ctrl}<w:fldChar w:fldCharType="separate"/></w:r><w:r>${res}<${textTag} xml:space="preserve">${escapeXml(cf.result)}</${textTag}></w:r>` : "";
8560
- return `<w:r>${ctrl}${cf.lastRenderedPageBreak ? "<w:lastRenderedPageBreak/>" : ""}<w:fldChar w:fldCharType="begin"/></w:r>` + instrXml + resultXml + `<w:r>${cf.endRPrXml ?? ctrl}<w:fldChar w:fldCharType="end"/></w:r>`;
8561
- }
8562
- /** Serialize a deleted run: rPr + delText (or field delInstrText). */
8563
- function stringifyDeletedRun(c) {
8564
- const opts = typeof c === "string" ? { text: c } : c;
8565
- const parts = [];
8566
- const rPr = stringifyRunProperties(opts);
8567
- if (rPr) parts.push(rPr);
8568
- if (opts.break) parts.push(breakXml(opts.break));
8569
- let attr = "";
8570
- if (opts.additionRsid) attr += ` w:rsidR="${opts.additionRsid}"`;
8571
- if (opts.runPropertiesRsid) attr += ` w:rsidRPr="${opts.runPropertiesRsid}"`;
8572
- if (opts.deletionRsid) attr += ` w:rsidDel="${opts.deletionRsid}"`;
8573
- const openTag = attr ? `<w:r${attr}>` : "<w:r>";
8574
- if (opts.children) {
8575
- for (const cc of opts.children) if (typeof cc === "string") parts.push(`<w:delText xml:space="preserve">${escapeXml(cc)}</w:delText>`);
8576
- else if (typeof cc === "object" && cc !== null && "commentReference" in cc) parts.push(`<w:commentReference w:id="${Number(cc.commentReference)}"/>`);
8577
- else if (typeof cc === "object" && cc !== null && "break" in cc) parts.push(breakXml(cc.break));
8578
- } else if (opts.text) parts.push(`<w:delText xml:space="preserve">${escapeXml(String(opts.text))}</w:delText>`);
8579
- return `${openTag}${parts.join("")}</w:r>`;
8580
- }
8581
- function stringifyRubyContent(opts, ctx) {
8582
- return opts.children?.map((child) => stringifyRunInline(typeof child === "string" ? { text: child } : child, ctx)).join("") ?? "";
8583
- }
8584
- function stringifyRuby(opts, ctx) {
8585
- const properties = opts.properties;
8586
- const dirty = properties.dirty !== void 0 ? onOff$2("w:dirty", properties.dirty) : "";
8587
- return `<w:ruby><w:rubyPr><w:rubyAlign w:val="${properties.alignment}"/><w:hps w:val="${hpsMeasureValue(properties.fontSize * 2)}"/><w:hpsRaise w:val="${hpsMeasureValue(properties.raise * 2)}"/><w:hpsBaseText w:val="${hpsMeasureValue(properties.baseFontSize * 2)}"/><w:lid w:val="${escapeXml(properties.languageId)}"/>${dirty}</w:rubyPr><w:rt>${stringifyRubyContent(opts.text, ctx)}</w:rt><w:rubyBase>${stringifyRubyContent(opts.base, ctx)}</w:rubyBase></w:ruby>`;
8588
- }
8589
- function stringifyRunInline(opts, ctx) {
8590
- let body = "";
8591
- let commentRefStyle = false;
8592
- if (opts.children) {
8593
- for (const child of opts.children) if (typeof child === "object" && child !== null && "commentReference" in child) {
8594
- commentRefStyle = true;
8595
- break;
8413
+ function stringifyDrawingChild(child, ctx) {
8414
+ if ("picture" in child) {
8415
+ const opts = child.picture;
8416
+ if (opts.type !== "svg" && opts.data === void 0 && opts.sourceUrl !== void 0) return wrapDrawingRun(drawingDesc.stringify({
8417
+ mediaData: {
8418
+ type: opts.type,
8419
+ sourceUrl: opts.sourceUrl,
8420
+ transformation: createTransformation(opts.transformation),
8421
+ sourceRectangle: opts.sourceRectangle,
8422
+ nonVisualProperties: opts.nonVisualProperties,
8423
+ useLocalDpi: opts.useLocalDpi,
8424
+ compression: opts.compression
8425
+ },
8426
+ docProperties: opts.altText,
8427
+ floating: opts.floating,
8428
+ outline: opts.outline,
8429
+ fill: opts.fill,
8430
+ effects: opts.effects,
8431
+ scene3d: opts.scene3d,
8432
+ shape3d: opts.shape3d,
8433
+ blipEffects: opts.blipEffects,
8434
+ tile: opts.tile,
8435
+ graphicFrameLocks: opts.graphicFrameLocks
8436
+ }, ctx), opts);
8437
+ const rawData = toUint8Array(opts.data, { encoding: "base64" });
8438
+ let mediaData;
8439
+ if (opts.type === "svg") {
8440
+ const fallbackData = toUint8Array(opts.fallback.data, { encoding: "base64" });
8441
+ const fallbackType = opts.fallback.type;
8442
+ const fallback = ctx.file.media.addMedia(fallbackData, fallbackType, (fileName) => ({
8443
+ type: fallbackType,
8444
+ ...createPictureData(fallbackData, opts.transformation, fileName)
8445
+ }), opts.fallback.fileName);
8446
+ mediaData = ctx.file.media.addMedia(rawData, "svg", (fileName) => ({
8447
+ type: "svg",
8448
+ ...createPictureData(rawData, opts.transformation, fileName, opts.sourceRectangle, opts.nonVisualProperties),
8449
+ useLocalDpi: opts.useLocalDpi,
8450
+ compression: opts.compression,
8451
+ fallback
8452
+ }), opts.fileName);
8453
+ } else {
8454
+ const type = opts.type;
8455
+ mediaData = ctx.file.media.addMedia(rawData, type, (fileName) => ({
8456
+ type,
8457
+ ...createPictureData(rawData, opts.transformation, fileName, opts.sourceRectangle, opts.nonVisualProperties),
8458
+ useLocalDpi: opts.useLocalDpi,
8459
+ compression: opts.compression,
8460
+ sourceUrl: opts.sourceUrl
8461
+ }), opts.fileName);
8596
8462
  }
8463
+ return wrapDrawingRun(drawingDesc.stringify({
8464
+ mediaData,
8465
+ docProperties: opts.altText,
8466
+ floating: opts.floating,
8467
+ outline: opts.outline,
8468
+ fill: opts.fill,
8469
+ effects: opts.effects,
8470
+ scene3d: opts.scene3d,
8471
+ shape3d: opts.shape3d,
8472
+ blipEffects: opts.blipEffects,
8473
+ tile: opts.tile,
8474
+ graphicFrameLocks: opts.graphicFrameLocks
8475
+ }, ctx), opts);
8597
8476
  }
8598
- const rPr = stringifyRunProperties(commentRefStyle && !opts.style ? {
8599
- ...opts,
8600
- style: "CommentReference"
8601
- } : opts);
8602
- if (rPr) body += rPr;
8603
- if (opts.break) body += breakXml(opts.break);
8604
- const fnRef = opts.footnoteReference;
8605
- const enRef = opts.endnoteReference;
8606
- if (fnRef !== void 0) {
8607
- const id = typeof fnRef === "number" ? fnRef : fnRef.id;
8608
- const cmf = typeof fnRef === "object" && fnRef.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8609
- body += `<w:footnoteReference w:id="${id}"${cmf}/>`;
8610
- } else if (enRef !== void 0) {
8611
- const id = typeof enRef === "number" ? enRef : enRef.id;
8612
- const cmf = typeof enRef === "object" && enRef.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8613
- body += `<w:endnoteReference w:id="${id}"${cmf}/>`;
8477
+ if ("chart" in child) {
8478
+ const opts = child.chart;
8479
+ const chartKey = `chart_${nextChartId++}`;
8480
+ const mediaData = {
8481
+ chartKey,
8482
+ transformation: createTransformation(opts.transformation),
8483
+ type: "chart"
8484
+ };
8485
+ const { transformation: _t, floating: _f, altText: _a, graphicFrameLocks: _g, runProperties: _r, lastRenderedPageBreak: _l, ...chartSpace } = opts;
8486
+ const chartXml = chartSpaceDesc.stringify(chartSpace, ctx.file);
8487
+ const externalData = chartSpace.externalData;
8488
+ ctx.file.charts.addChart(chartKey, {
8489
+ key: chartKey,
8490
+ chartSpaceXml: chartXml ?? "",
8491
+ ...externalData?.data !== void 0 && externalData.fileName ? { embedding: {
8492
+ relationshipId: externalData.relationshipId,
8493
+ fileName: externalData.fileName,
8494
+ data: externalData.data
8495
+ } } : {},
8496
+ ...chartSpace.userShapes ? { userShapes: buildUserShapesData(chartSpace.userShapes) } : {}
8497
+ });
8498
+ return wrapDrawingRun(drawingDesc.stringify({
8499
+ mediaData,
8500
+ docProperties: opts.altText,
8501
+ floating: opts.floating,
8502
+ graphicFrameLocks: opts.graphicFrameLocks
8503
+ }, ctx), opts);
8614
8504
  }
8615
- if (opts.children) {
8616
- for (const child of opts.children) if (typeof child === "string") body += `<w:t xml:space="preserve">${escapeXml(child)}</w:t>`;
8617
- else if (typeof child === "object" && child !== null) {
8618
- if ("tab" in child) {
8619
- body += "<w:tab/>";
8620
- continue;
8621
- }
8622
- if ("pageBreak" in child) {
8623
- body += "<w:br w:type=\"page\"/>";
8624
- continue;
8625
- }
8626
- if ("columnBreak" in child) {
8627
- body += "<w:br w:type=\"column\"/>";
8628
- continue;
8629
- }
8630
- if ("break" in child) {
8631
- body += breakXml(child.break);
8632
- continue;
8633
- }
8634
- if ("commentReference" in child) {
8635
- body += `<w:commentReference w:id="${Number(child.commentReference)}"/>`;
8636
- continue;
8637
- }
8638
- if ("symbolRun" in child) {
8639
- const sym = child.symbolRun;
8640
- body += `${stringifyRunProperties(sym) ?? ""}${stringifySymbolRunInner(sym)}`;
8641
- continue;
8642
- }
8643
- const bareFnRef = child.footnoteReference;
8644
- if (bareFnRef !== void 0) {
8645
- const id = typeof bareFnRef === "number" ? bareFnRef : bareFnRef.id;
8646
- const cmf = typeof bareFnRef === "object" && bareFnRef.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8647
- body += `<w:footnoteReference w:id="${id}"${cmf}/>`;
8648
- continue;
8649
- }
8650
- const bareEnRef = child.endnoteReference;
8651
- if (bareEnRef !== void 0) {
8652
- const id = typeof bareEnRef === "number" ? bareEnRef : bareEnRef.id;
8653
- const cmf = typeof bareEnRef === "object" && bareEnRef.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8654
- body += `<w:endnoteReference w:id="${id}"${cmf}/>`;
8655
- continue;
8656
- }
8657
- let firstKey;
8658
- for (const key in child) {
8659
- firstKey = key;
8660
- break;
8661
- }
8662
- const emptyXml = firstKey !== void 0 ? EMPTY_RUN_ELEMENTS[firstKey] : void 0;
8663
- if (emptyXml) {
8664
- body += emptyXml;
8665
- continue;
8666
- }
8667
- if ("ruby" in child) {
8668
- body += stringifyRuby(child.ruby, ctx);
8669
- continue;
8670
- }
8671
- if ("object" in child) {
8672
- body += objectDesc.stringify(child.object, ctx) ?? "";
8673
- continue;
8674
- }
8675
- if ("pict" in child) {
8676
- body += stringifyPict(child.pict, ctx);
8677
- continue;
8505
+ if ("smartArt" in child) {
8506
+ const opts = child.smartArt;
8507
+ const smartArtKey = `smartart_${hashSmartArtData(opts)}`;
8508
+ const mediaData = {
8509
+ smartArtKey,
8510
+ transformation: createTransformation(opts.transformation),
8511
+ type: "smartart"
8512
+ };
8513
+ const layoutId = typeof opts.layout === "object" ? definitionId(opts.layout) : opts.layout ?? "default";
8514
+ const styleId = typeof opts.style === "object" ? definitionId(opts.style) : opts.style ?? "simple1";
8515
+ const colorId = typeof opts.color === "object" ? definitionId(opts.color) : opts.color ?? "accent1_2";
8516
+ const dataModelXml = createDataModel(opts.nodes, layoutId, styleId, colorId);
8517
+ let remappedDataRels = opts.raw?.dataRels;
8518
+ if (opts.raw?.media) {
8519
+ const renames = /* @__PURE__ */ new Map();
8520
+ for (const m of opts.raw.media) {
8521
+ const data = toUint8Array(m.data);
8522
+ const type = imageTypeFromPath(m.fileName);
8523
+ const entry = ctx.file.media.addMedia(data, type, (fileName) => ({
8524
+ type,
8525
+ data,
8526
+ fileName,
8527
+ transformation: {
8528
+ emus: {
8529
+ x: 0,
8530
+ y: 0
8531
+ },
8532
+ pixels: {
8533
+ x: 0,
8534
+ y: 0
8535
+ }
8536
+ }
8537
+ }), m.fileName);
8538
+ if (entry.fileName !== m.fileName) renames.set(m.fileName, entry.fileName);
8678
8539
  }
8679
- const jsonResult = stringifyChildDispatch(child, ctx);
8680
- if (jsonResult !== void 0) body += Array.isArray(jsonResult) ? jsonResult.join("") : jsonResult;
8681
- else if ("text" in child || "children" in child || "break" in child) body += stringifyRunInline(child, ctx);
8540
+ if (renames.size > 0 && remappedDataRels !== void 0) remappedDataRels = remapDataRelsTargets(remappedDataRels, renames);
8682
8541
  }
8683
- } else if (opts.text !== void 0) body += `<w:t xml:space="preserve">${escapeXml(String(opts.text))}</w:t>`;
8684
- let attr = "";
8685
- if (opts.additionRsid) attr += ` w:rsidR="${opts.additionRsid}"`;
8686
- if (opts.runPropertiesRsid) attr += ` w:rsidRPr="${opts.runPropertiesRsid}"`;
8687
- if (opts.deletionRsid) attr += ` w:rsidDel="${opts.deletionRsid}"`;
8688
- return body.length === 0 ? attr ? `<w:r${attr}/>` : "<w:r/>" : `<w:r${attr}>${body}</w:r>`;
8542
+ ctx.file.smartArts.addSmartArt(smartArtKey, {
8543
+ dataModelXml,
8544
+ key: smartArtKey,
8545
+ layout: opts.layout ?? "default",
8546
+ style: opts.style ?? "simple1",
8547
+ color: opts.color ?? "accent1_2",
8548
+ ...opts.raw || remappedDataRels !== void 0 ? { raw: {
8549
+ ...opts.raw,
8550
+ dataRels: remappedDataRels
8551
+ } } : {}
8552
+ });
8553
+ return wrapDrawingRun(drawingDesc.stringify({
8554
+ mediaData,
8555
+ docProperties: opts.altText,
8556
+ floating: opts.floating,
8557
+ graphicFrameLocks: opts.graphicFrameLocks
8558
+ }, ctx), {
8559
+ runProperties: opts.runProperties,
8560
+ lastRenderedPageBreak: opts.lastRenderedPageBreak
8561
+ });
8562
+ }
8563
+ if ("wpsShape" in child) {
8564
+ const opts = child.wpsShape;
8565
+ const mediaData = {
8566
+ data: opts,
8567
+ transformation: createTransformation(opts.transformation),
8568
+ type: "wps"
8569
+ };
8570
+ const drawingXml = drawingDesc.stringify({
8571
+ mediaData,
8572
+ docProperties: opts.altText,
8573
+ floating: opts.floating,
8574
+ outline: opts.outline,
8575
+ fill: opts.fill,
8576
+ graphicFrameLocks: opts.graphicFrameLocks
8577
+ }, ctx);
8578
+ registerVmlFallbackMedia(opts, ctx);
8579
+ return wrapDrawingRun(drawingXml, opts);
8580
+ }
8581
+ if ("contentPart" in child) return `<w:r><w:contentPart r:id="${child.contentPart.referenceId}"/></w:r>`;
8582
+ if ("wpgGroup" in child) {
8583
+ const opts = child.wpgGroup;
8584
+ const mediaData = {
8585
+ children: opts.children,
8586
+ transformation: createTransformation(opts.transformation),
8587
+ childOffsetX: opts.childOffsetX,
8588
+ childOffsetY: opts.childOffsetY,
8589
+ childExtentWidth: opts.childExtentWidth,
8590
+ childExtentHeight: opts.childExtentHeight,
8591
+ fill: opts.fill,
8592
+ effects: opts.effects,
8593
+ groupShapeLocks: opts.groupShapeLocks,
8594
+ type: "wpg"
8595
+ };
8596
+ const registerMedia = (children) => {
8597
+ for (const c of children) {
8598
+ if (c.type === "wps") continue;
8599
+ if (c.type === "wpg") {
8600
+ registerMedia(c.children);
8601
+ continue;
8602
+ }
8603
+ if (c.type === "chart") {
8604
+ if (c.chartOptions && !c.chartKey) {
8605
+ c.chartKey = `chart_${nextChartId++}`;
8606
+ const externalData = c.chartOptions.externalData;
8607
+ ctx.file.charts.addChart(c.chartKey, {
8608
+ key: c.chartKey,
8609
+ chartSpaceXml: chartSpaceDesc.stringify(c.chartOptions, ctx.file) ?? "",
8610
+ ...externalData?.data !== void 0 && externalData.fileName ? { embedding: {
8611
+ relationshipId: externalData.relationshipId,
8612
+ fileName: externalData.fileName,
8613
+ data: externalData.data
8614
+ } } : {},
8615
+ ...c.chartOptions.userShapes ? { userShapes: buildUserShapesData(c.chartOptions.userShapes) } : {}
8616
+ });
8617
+ }
8618
+ continue;
8619
+ }
8620
+ if (c.type === "contentPart") continue;
8621
+ if (c.type === "svg") {
8622
+ const fb = c.fallback;
8623
+ fb.fileName = ctx.file.media.addMedia(fb.data, fb.type, () => fb, fb.fileName).fileName;
8624
+ c.fileName = ctx.file.media.addMedia(c.data, "svg", () => c, c.fileName).fileName;
8625
+ continue;
8626
+ }
8627
+ c.fileName = ctx.file.media.addMedia(c.data, c.type, () => c, c.fileName).fileName;
8628
+ }
8629
+ };
8630
+ registerMedia(opts.children);
8631
+ const drawingXml = drawingDesc.stringify({
8632
+ mediaData,
8633
+ docProperties: opts.altText,
8634
+ floating: opts.floating,
8635
+ graphicFrameLocks: opts.graphicFrameLocks
8636
+ }, ctx);
8637
+ registerVmlFallbackMedia(opts, ctx);
8638
+ return wrapDrawingRun(drawingXml, opts);
8639
+ }
8689
8640
  }
8690
- let nextChartId = 1;
8641
+ //#endregion
8642
+ //#region src/parts/paragraph/run/field.ts
8691
8643
  /**
8692
- * Stringify a ParagraphChild into one or more XML strings.
8644
+ * Field module for WordprocessingML documents.
8693
8645
  *
8694
- * Handles side effects (media, chart, smartArt, relationship registration)
8695
- * directly without creating temporary class instances.
8646
+ * This module provides support for complex fields, which are regions of text
8647
+ * that can contain dynamic content such as page numbers, dates, or mail merge fields.
8648
+ * Fields are delimited by field character elements (begin, separate, end).
8696
8649
  *
8697
- * Returns `undefined` if the child is not a recognized JSON wrapper.
8650
+ * Reference: http://officeopenxml.com/WPrun.php
8651
+ *
8652
+ * @module
8698
8653
  */
8699
8654
  /**
8700
- * Wrap a `<w:drawing>` run, rebuilding an mc:AlternateContent wrapper when a
8701
- * VML fallback was carried from parse (Choice stays structured/editable,
8702
- * Fallback round-trips as raw XML for fidelity).
8655
+ * Field character types that delimit field regions.
8656
+ *
8657
+ * @internal
8703
8658
  */
8704
- function wrapDrawingRun(drawingXml, opts) {
8705
- const xml = drawingXml ?? "";
8706
- const rPr = stringifyRunProperties(opts.runProperties) ?? "";
8707
- const lrpb = opts.lastRenderedPageBreak ? "<w:lastRenderedPageBreak/>" : "";
8708
- if (opts.vmlFallback) return `<w:r>${rPr}${lrpb}<mc:AlternateContent><mc:Choice Requires="${opts.mcChoiceRequires ?? "wps"}">${xml}</mc:Choice>${opts.vmlFallback}</mc:AlternateContent></w:r>`;
8709
- return `<w:r>${rPr}${lrpb}${xml}</w:r>`;
8710
- }
8659
+ const FieldCharacterType = {
8660
+ BEGIN: "begin",
8661
+ END: "end",
8662
+ SEPARATE: "separate"
8663
+ };
8711
8664
  /**
8712
- * Register media carried by a VML fallback (mc:AlternateContent Fallback) so the
8713
- * compiler resolves the fallback's `{fileName}` placeholders into rIds.
8665
+ * Creates a field character element.
8714
8666
  *
8715
- * A VML fallback image mirrors its Choice blip (same source bytes). When the
8716
- * blip is already registered, reuse it and remap the fallback's `{fileName}`
8717
- * placeholder to the shared media — matching Office, which emits one
8718
- * relationship/file per image rather than a duplicate for the VML branch.
8667
+ * ## XSD Schema
8668
+ * ```xml
8669
+ * <xsd:complexType name="CT_FldChar">
8670
+ * <xsd:sequence>
8671
+ * <xsd:element name="fldData" type="CT_Text" minOccurs="0"/>
8672
+ * <xsd:element name="ffData" type="CT_FFData" minOccurs="0"/>
8673
+ * <xsd:element name="numberingChange" type="CT_TrackChangeNumbering" minOccurs="0"/>
8674
+ * </xsd:sequence>
8675
+ * <xsd:attribute name="fldCharType" type="ST_FldCharType" use="required"/>
8676
+ * <xsd:attribute name="fldLock" type="s:ST_OnOff"/>
8677
+ * <xsd:attribute name="dirty" type="s:ST_OnOff"/>
8678
+ * </xsd:complexType>
8679
+ * ```
8680
+ * @internal
8719
8681
  */
8720
- function registerVmlFallbackMedia(opts, ctx) {
8721
- if (!opts.vmlFallbackMedia) return;
8722
- for (const m of opts.vmlFallbackMedia) {
8723
- const data = toUint8Array(m.data);
8724
- const entry = ctx.file.media.addMedia(data, m.type, (fileName) => ({
8725
- type: m.type,
8726
- data,
8727
- fileName,
8728
- transformation: {
8729
- emus: {
8730
- x: 0,
8731
- y: 0
8732
- },
8733
- pixels: {
8734
- x: 0,
8735
- y: 0
8736
- }
8737
- }
8738
- }), m.fileName);
8739
- if (entry.fileName !== m.fileName && opts.vmlFallback) opts.vmlFallback = opts.vmlFallback.split(`{${m.fileName}}`).join(`{${entry.fileName}}`);
8740
- }
8741
- }
8682
+ const createFieldChar = (type, dirty, ffData, fldData, fieldLock) => {
8683
+ const children = [];
8684
+ if (fldData !== void 0) children.push(element("w:fldData", { "xml:space": "preserve" }, [fldData]));
8685
+ if (ffData) children.push(ffData);
8686
+ return element("w:fldChar", {
8687
+ "w:dirty": dirty,
8688
+ "w:fldLock": fieldLock,
8689
+ "w:fldCharType": type
8690
+ }, children.length > 0 ? children : void 0);
8691
+ };
8742
8692
  /**
8743
- * Build the rPr XML for a break/tab run from its structured run properties.
8693
+ * Creates the beginning of a complex field.
8694
+ *
8695
+ * The Begin element marks the start of a field. A field consists of a begin character,
8696
+ * field instructions, an optional separate character, field result, and an end character.
8697
+ *
8698
+ * For form fields, pass `formField` to embed `w:ffData` within the begin `w:fldChar`.
8699
+ *
8700
+ * @param dirty - Whether the field should be recalculated
8701
+ * @param formField - Optional form field data to embed in the begin character
8702
+ *
8703
+ * @example
8704
+ * ```typescript
8705
+ * // Simple field begin
8706
+ * createBegin();
8707
+ *
8708
+ * // Form field (checkbox)
8709
+ * createBegin(false, {
8710
+ * name: "Check1",
8711
+ * checkBox: { checked: true, sizeAuto: true },
8712
+ * });
8713
+ * ```
8744
8714
  */
8745
- /** Shared attribute string for CT_MarkupRange end markers (commentRange, move range end). */
8746
- function buildMarkupRangeAttrs(m) {
8747
- const a = [`w:id="${m.id}"`];
8748
- if (m.displacedByCustomXml) a.push(`w:displacedByCustomXml="${m.displacedByCustomXml}"`);
8749
- return a.join(" ");
8750
- }
8751
- /** Shared attribute string for w:bookmarkStart (CT_Bookmark). */
8752
- function buildBookmarkStartAttrs(bs) {
8753
- const a = [`w:id="${bs.id}"`, `w:name="${escapeXml(bs.name)}"`];
8754
- if (bs.displacedByCustomXml) a.push(`w:displacedByCustomXml="${bs.displacedByCustomXml}"`);
8755
- if (bs.colFirst !== void 0) a.push(`w:colFirst="${bs.colFirst}"`);
8756
- if (bs.colLast !== void 0) a.push(`w:colLast="${bs.colLast}"`);
8757
- return a.join(" ");
8758
- }
8759
- /** Shared attribute string for w:moveFromRangeStart / w:moveToRangeStart (CT_MoveBookmark). */
8760
- function buildMoveRangeStartAttrs(m) {
8761
- const a = [`w:id="${m.id}"`];
8762
- if (m.name) a.push(`w:name="${escapeXml(m.name)}"`);
8763
- if (m.author) a.push(`w:author="${escapeXml(m.author)}"`);
8764
- if (m.date) a.push(`w:date="${m.date}"`);
8765
- if (m.displacedByCustomXml) a.push(`w:displacedByCustomXml="${m.displacedByCustomXml}"`);
8766
- if (m.colFirst !== void 0) a.push(`w:colFirst="${m.colFirst}"`);
8767
- if (m.colLast !== void 0) a.push(`w:colLast="${m.colLast}"`);
8768
- return a.join(" ");
8769
- }
8770
- /** Stringify inline run/text content — the `wrap` shared by every sugar child. */
8771
- function stringifyInlineWrap(wrap, ctx) {
8772
- const parts = [];
8773
- for (const item of wrap ?? []) parts.push(typeof item === "string" ? stringifyRunInline({ text: item }, ctx) : stringifyRunInline(item, ctx));
8774
- return parts.join("");
8775
- }
8715
+ const createBegin = (dirty, formField, fieldLock) => createFieldChar(FieldCharacterType.BEGIN, dirty, formField ? createFormFieldData(formField) : void 0, void 0, fieldLock);
8776
8716
  /**
8777
- * Serialize a break run inside a track-change wrapper. A parsed break run
8778
- * keeps its run properties and rsid attributes — the same flat-props shape
8779
- * the paragraph-level break variants carry.
8717
+ * Creates the separator between field code and field result in a complex field.
8718
+ *
8719
+ * The Separate element divides the field code (instructions) from the field result
8720
+ * (the computed value).
8780
8721
  */
8781
- function stringifyTrackChangeBreak(opts, type) {
8782
- const rPr = stringifyRunProperties(opts) ?? "";
8783
- let attr = "";
8784
- if (opts.additionRsid) attr += ` w:rsidR="${opts.additionRsid}"`;
8785
- if (opts.runPropertiesRsid) attr += ` w:rsidRPr="${opts.runPropertiesRsid}"`;
8786
- if (opts.deletionRsid) attr += ` w:rsidDel="${opts.deletionRsid}"`;
8787
- return `<w:r${attr}>${rPr}<w:br w:type="${type}"/></w:r>`;
8722
+ const createSeparate = (dirty) => createFieldChar(FieldCharacterType.SEPARATE, dirty);
8723
+ /**
8724
+ * Creates the end of a complex field.
8725
+ *
8726
+ * The End element marks the end of a field. Every field that begins with a Begin
8727
+ * element must be terminated with an End element.
8728
+ */
8729
+ const createEnd = (dirty) => createFieldChar(FieldCharacterType.END, dirty);
8730
+ //#endregion
8731
+ //#region src/parts/inline.ts
8732
+ /**
8733
+ * Shared inline run/paragraph stringification for DOCX descriptors.
8734
+ *
8735
+ * Used by table.ts, comments.ts, body.ts, and other descriptors that need to
8736
+ * serialize paragraph/run content. Includes JSON child dispatch for all
8737
+ * ParagraphChild variants (picture, chart, hyperlink, etc.).
8738
+ *
8739
+ * Pure string concatenation — no intermediate object tree.
8740
+ *
8741
+ * @module
8742
+ */
8743
+ function stringifySymbolRunInner(opts) {
8744
+ return `<${opts.kind === "office2016" ? "w16se:sym" : "w:sym"} w:char="${escapeXml(opts.char)}" w:font="${escapeXml(opts.symbolFont ?? "Wingdings")}"/>`;
8745
+ }
8746
+ /** Serialize a complex field's run chain. Inside a w:del wrapper the
8747
+ * instruction is spelled w:delInstrText and the cached result w:delText. */
8748
+ function stringifyComplexFieldRuns(cf, isDelete = false) {
8749
+ const instrTag = isDelete ? "w:delInstrText" : "w:instrText";
8750
+ const textTag = isDelete ? "w:delText" : "w:t";
8751
+ const ctrl = cf.rPrXml ?? "";
8752
+ const res = cf.resultRPrXml ?? ctrl;
8753
+ const instrXml = cf.instrRunsXml ?? (cf.instruction !== "" ? `<w:r>${ctrl}<${instrTag} xml:space="preserve">${escapeXml(cf.instruction)}</${instrTag}></w:r>` : "");
8754
+ const resultXml = cf.resultRunsXml !== void 0 ? `<w:r>${ctrl}<w:fldChar w:fldCharType="separate"/></w:r>` + cf.resultRunsXml : cf.result !== void 0 ? `<w:r>${ctrl}<w:fldChar w:fldCharType="separate"/></w:r><w:r>${res}<${textTag} xml:space="preserve">${escapeXml(cf.result)}</${textTag}></w:r>` : "";
8755
+ return `<w:r>${ctrl}${cf.lastRenderedPageBreak ? "<w:lastRenderedPageBreak/>" : ""}<w:fldChar w:fldCharType="begin"/></w:r>` + instrXml + resultXml + `<w:r>${cf.endRPrXml ?? ctrl}<w:fldChar w:fldCharType="end"/></w:r>`;
8756
+ }
8757
+ /** Serialize a deleted run: rPr + delText (or field delInstrText). */
8758
+ function stringifyDeletedRun(c) {
8759
+ const opts = typeof c === "string" ? { text: c } : c;
8760
+ const parts = [];
8761
+ const rPr = stringifyRunProperties(opts);
8762
+ if (rPr) parts.push(rPr);
8763
+ if (opts.break) parts.push(breakXml(opts.break));
8764
+ let attr = "";
8765
+ if (opts.additionRsid) attr += ` w:rsidR="${opts.additionRsid}"`;
8766
+ if (opts.runPropertiesRsid) attr += ` w:rsidRPr="${opts.runPropertiesRsid}"`;
8767
+ if (opts.deletionRsid) attr += ` w:rsidDel="${opts.deletionRsid}"`;
8768
+ const openTag = attr ? `<w:r${attr}>` : "<w:r>";
8769
+ if (opts.children) {
8770
+ for (const cc of opts.children) if (typeof cc === "string") parts.push(`<w:delText xml:space="preserve">${escapeXml(cc)}</w:delText>`);
8771
+ else if (typeof cc === "object" && cc !== null && "commentReference" in cc) parts.push(`<w:commentReference w:id="${Number(cc.commentReference)}"/>`);
8772
+ else if (typeof cc === "object" && cc !== null && "break" in cc) parts.push(breakXml(cc.break));
8773
+ } else if (opts.text) parts.push(`<w:delText xml:space="preserve">${escapeXml(String(opts.text))}</w:delText>`);
8774
+ return `${openTag}${parts.join("")}</w:r>`;
8775
+ }
8776
+ function stringifyRubyContent(opts, ctx) {
8777
+ return opts.children?.map((child) => stringifyRunInline(typeof child === "string" ? { text: child } : child, ctx)).join("") ?? "";
8778
+ }
8779
+ function stringifyRuby(opts, ctx) {
8780
+ const properties = opts.properties;
8781
+ const dirty = properties.dirty !== void 0 ? onOff$2("w:dirty", properties.dirty) : "";
8782
+ return `<w:ruby><w:rubyPr><w:rubyAlign w:val="${properties.alignment}"/><w:hps w:val="${hpsMeasureValue(properties.fontSize * 2)}"/><w:hpsRaise w:val="${hpsMeasureValue(properties.raise * 2)}"/><w:hpsBaseText w:val="${hpsMeasureValue(properties.baseFontSize * 2)}"/><w:lid w:val="${escapeXml(properties.languageId)}"/>${dirty}</w:rubyPr><w:rt>${stringifyRubyContent(opts.text, ctx)}</w:rt><w:rubyBase>${stringifyRubyContent(opts.base, ctx)}</w:rubyBase></w:ruby>`;
8783
+ }
8784
+ function stringifyRunInline(opts, ctx) {
8785
+ let body = "";
8786
+ let commentRefStyle = false;
8787
+ if (opts.children && !opts.style) {
8788
+ for (const child of opts.children) if (typeof child === "object" && child !== null && "commentReference" in child) {
8789
+ commentRefStyle = true;
8790
+ break;
8791
+ }
8792
+ }
8793
+ const rPr = stringifyRunProperties(commentRefStyle && !opts.style ? {
8794
+ ...opts,
8795
+ style: "CommentReference"
8796
+ } : opts);
8797
+ if (rPr) body += rPr;
8798
+ if (opts.break) body += breakXml(opts.break);
8799
+ const fnRef = opts.footnoteReference;
8800
+ const enRef = opts.endnoteReference;
8801
+ if (fnRef !== void 0) {
8802
+ const id = typeof fnRef === "number" ? fnRef : fnRef.id;
8803
+ const cmf = typeof fnRef === "object" && fnRef.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8804
+ body += `<w:footnoteReference w:id="${id}"${cmf}/>`;
8805
+ } else if (enRef !== void 0) {
8806
+ const id = typeof enRef === "number" ? enRef : enRef.id;
8807
+ const cmf = typeof enRef === "object" && enRef.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8808
+ body += `<w:endnoteReference w:id="${id}"${cmf}/>`;
8809
+ }
8810
+ if (opts.children) {
8811
+ for (const child of opts.children) if (typeof child === "string") body += `<w:t xml:space="preserve">${escapeXml(child)}</w:t>`;
8812
+ else if (typeof child === "object" && child !== null) {
8813
+ if ("tab" in child) {
8814
+ body += "<w:tab/>";
8815
+ continue;
8816
+ }
8817
+ if ("pageBreak" in child) {
8818
+ body += "<w:br w:type=\"page\"/>";
8819
+ continue;
8820
+ }
8821
+ if ("columnBreak" in child) {
8822
+ body += "<w:br w:type=\"column\"/>";
8823
+ continue;
8824
+ }
8825
+ if ("break" in child) {
8826
+ body += breakXml(child.break);
8827
+ continue;
8828
+ }
8829
+ if ("commentReference" in child) {
8830
+ body += `<w:commentReference w:id="${Number(child.commentReference)}"/>`;
8831
+ continue;
8832
+ }
8833
+ if ("symbolRun" in child) {
8834
+ const sym = child.symbolRun;
8835
+ body += `${stringifyRunProperties(sym) ?? ""}${stringifySymbolRunInner(sym)}`;
8836
+ continue;
8837
+ }
8838
+ const bareFnRef = child.footnoteReference;
8839
+ if (bareFnRef !== void 0) {
8840
+ const id = typeof bareFnRef === "number" ? bareFnRef : bareFnRef.id;
8841
+ const cmf = typeof bareFnRef === "object" && bareFnRef.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8842
+ body += `<w:footnoteReference w:id="${id}"${cmf}/>`;
8843
+ continue;
8844
+ }
8845
+ const bareEnRef = child.endnoteReference;
8846
+ if (bareEnRef !== void 0) {
8847
+ const id = typeof bareEnRef === "number" ? bareEnRef : bareEnRef.id;
8848
+ const cmf = typeof bareEnRef === "object" && bareEnRef.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8849
+ body += `<w:endnoteReference w:id="${id}"${cmf}/>`;
8850
+ continue;
8851
+ }
8852
+ let firstKey;
8853
+ for (const key in child) {
8854
+ firstKey = key;
8855
+ break;
8856
+ }
8857
+ const emptyXml = firstKey !== void 0 ? EMPTY_RUN_ELEMENTS[firstKey] : void 0;
8858
+ if (emptyXml) {
8859
+ body += emptyXml;
8860
+ continue;
8861
+ }
8862
+ if ("ruby" in child) {
8863
+ body += stringifyRuby(child.ruby, ctx);
8864
+ continue;
8865
+ }
8866
+ if ("object" in child) {
8867
+ body += objectDesc.stringify(child.object, ctx) ?? "";
8868
+ continue;
8869
+ }
8870
+ if ("pict" in child) {
8871
+ body += stringifyPict(child.pict, ctx);
8872
+ continue;
8873
+ }
8874
+ const jsonResult = stringifyChildDispatch(child, ctx);
8875
+ if (jsonResult !== void 0) body += Array.isArray(jsonResult) ? jsonResult.join("") : jsonResult;
8876
+ else if ("text" in child || "children" in child || "break" in child) body += stringifyRunInline(child, ctx);
8877
+ }
8878
+ } else if (opts.text !== void 0) body += `<w:t xml:space="preserve">${escapeXml(String(opts.text))}</w:t>`;
8879
+ let attr = "";
8880
+ if (opts.additionRsid) attr += ` w:rsidR="${opts.additionRsid}"`;
8881
+ if (opts.runPropertiesRsid) attr += ` w:rsidRPr="${opts.runPropertiesRsid}"`;
8882
+ if (opts.deletionRsid) attr += ` w:rsidDel="${opts.deletionRsid}"`;
8883
+ return body.length === 0 ? attr ? `<w:r${attr}/>` : "<w:r/>" : `<w:r${attr}>${body}</w:r>`;
8884
+ }
8885
+ /**
8886
+ * Stringify a ParagraphChild into one or more XML strings.
8887
+ *
8888
+ * Handles side effects (media, chart, smartArt, relationship registration)
8889
+ * directly without creating temporary class instances.
8890
+ *
8891
+ * Returns `undefined` if the child is not a recognized JSON wrapper.
8892
+ */
8893
+ /**
8894
+ * Build the rPr XML for a break/tab run from its structured run properties.
8895
+ */
8896
+ /** Shared attribute string for CT_MarkupRange end markers (commentRange, move range end). */
8897
+ function buildMarkupRangeAttrs(m) {
8898
+ const a = [`w:id="${m.id}"`];
8899
+ if (m.displacedByCustomXml) a.push(`w:displacedByCustomXml="${m.displacedByCustomXml}"`);
8900
+ return a.join(" ");
8901
+ }
8902
+ /** Shared attribute string for w:bookmarkStart (CT_Bookmark). */
8903
+ function buildBookmarkStartAttrs(bs) {
8904
+ const a = [`w:id="${bs.id}"`, `w:name="${escapeXml(bs.name)}"`];
8905
+ if (bs.displacedByCustomXml) a.push(`w:displacedByCustomXml="${bs.displacedByCustomXml}"`);
8906
+ if (bs.colFirst !== void 0) a.push(`w:colFirst="${bs.colFirst}"`);
8907
+ if (bs.colLast !== void 0) a.push(`w:colLast="${bs.colLast}"`);
8908
+ return a.join(" ");
8909
+ }
8910
+ /** Shared attribute string for w:moveFromRangeStart / w:moveToRangeStart (CT_MoveBookmark). */
8911
+ function buildMoveRangeStartAttrs(m) {
8912
+ const a = [`w:id="${m.id}"`];
8913
+ if (m.name) a.push(`w:name="${escapeXml(m.name)}"`);
8914
+ if (m.author) a.push(`w:author="${escapeXml(m.author)}"`);
8915
+ if (m.date) a.push(`w:date="${m.date}"`);
8916
+ if (m.displacedByCustomXml) a.push(`w:displacedByCustomXml="${m.displacedByCustomXml}"`);
8917
+ if (m.colFirst !== void 0) a.push(`w:colFirst="${m.colFirst}"`);
8918
+ if (m.colLast !== void 0) a.push(`w:colLast="${m.colLast}"`);
8919
+ return a.join(" ");
8920
+ }
8921
+ /** Stringify inline run/text content — the `wrap` shared by every sugar child. */
8922
+ function stringifyInlineWrap(wrap, ctx) {
8923
+ const parts = [];
8924
+ for (const item of wrap ?? []) parts.push(typeof item === "string" ? stringifyRunInline({ text: item }, ctx) : stringifyRunInline(item, ctx));
8925
+ return parts.join("");
8926
+ }
8927
+ /**
8928
+ * Serialize a break run inside a track-change wrapper. A parsed break run
8929
+ * keeps its run properties and rsid attributes — the same flat-props shape
8930
+ * the paragraph-level break variants carry.
8931
+ */
8932
+ function stringifyTrackChangeBreak(opts, type) {
8933
+ const rPr = stringifyRunProperties(opts) ?? "";
8934
+ let attr = "";
8935
+ if (opts.additionRsid) attr += ` w:rsidR="${opts.additionRsid}"`;
8936
+ if (opts.runPropertiesRsid) attr += ` w:rsidRPr="${opts.runPropertiesRsid}"`;
8937
+ if (opts.deletionRsid) attr += ` w:rsidDel="${opts.deletionRsid}"`;
8938
+ return `<w:r${attr}>${rPr}<w:br w:type="${type}"/></w:r>`;
8788
8939
  }
8789
8940
  /**
8790
8941
  * Serialize the children of a track-change wrapper: runs (delText inside
@@ -8882,301 +9033,77 @@ function stringifyMoveRangeChild(kind, opts, ctx) {
8882
9033
  displacedByCustomXml: opts.displacedByCustomXml
8883
9034
  });
8884
9035
  return `<${startTag} ${rangeStartAttrs}/><${runTag} w:id="${runId}" w:author="${escapeXml(opts.author)}" w:date="${opts.date}">${stringifyInlineWrap(opts.wrap, ctx)}</${runTag}><${endTag} ${endAttrs}/>`;
8885
- }
8886
- function runPropertiesXml(child) {
8887
- return stringifyRunProperties(child) ?? "";
8888
- }
8889
- /**
8890
- * The plain-run shape the dispatch text fast path claims: text set, with none
8891
- * of the variants that legally coexist with text and have their own dispatch
8892
- * branch (references, the { text, hyperlink } shorthand). Callers that need
8893
- * context-specific text spelling (w:delText inside a deletion wrapper) use
8894
- * this to claim the shape before dispatch does.
8895
- */
8896
- function isPlainTextRun(child) {
8897
- const run = child;
8898
- return "text" in child && run.text !== void 0 && run.footnoteReference === void 0 && run.endnoteReference === void 0 && !("commentReference" in child) && !("hyperlink" in child);
8899
- }
8900
- function stringifyChildDispatch(child, ctx) {
8901
- if ("rawXml" in child) return child.rawXml;
8902
- if (isPlainTextRun(child)) return stringifyRunInline(child, ctx);
8903
- if ("pageBreak" in child) return `<w:r>${runPropertiesXml(child)}<w:br w:type="page"/></w:r>`;
8904
- if ("columnBreak" in child) return `<w:r>${runPropertiesXml(child)}<w:br w:type="column"/></w:r>`;
8905
- if ("tab" in child) return `<w:r>${runPropertiesXml(child)}<w:tab/></w:r>`;
8906
- if ("subDoc" in child) return subDocDesc.stringify(child.subDoc, ctx) ?? "";
8907
- const fnRefChild = child.footnoteReference;
8908
- if (fnRefChild !== void 0) {
8909
- const id = typeof fnRefChild === "number" ? fnRefChild : fnRefChild.id;
8910
- const cmf = typeof fnRefChild === "object" && fnRefChild.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8911
- const props = "properties" in child ? child.properties : void 0;
8912
- return `<w:r>${props ? stringifyRunProperties(props) ?? "" : "<w:rPr><w:rStyle w:val=\"FootnoteReference\"/></w:rPr>"}<w:footnoteReference w:id="${id}"${cmf}/></w:r>`;
8913
- }
8914
- const enRefChild = child.endnoteReference;
8915
- if (enRefChild !== void 0) {
8916
- const id = typeof enRefChild === "number" ? enRefChild : enRefChild.id;
8917
- const cmf = typeof enRefChild === "object" && enRefChild.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
8918
- const props = "properties" in child ? child.properties : void 0;
8919
- return `<w:r>${props ? stringifyRunProperties(props) ?? "" : "<w:rPr><w:rStyle w:val=\"EndnoteReference\"/></w:rPr>"}<w:endnoteReference w:id="${id}"${cmf}/></w:r>`;
8920
- }
8921
- if ("comment" in child) return stringifyCommentChild(child.comment, ctx);
8922
- if ("commentRangeStart" in child) return `<w:commentRangeStart ${buildMarkupRangeAttrs(child.commentRangeStart)}/>`;
8923
- if ("commentRangeEnd" in child) return `<w:commentRangeEnd ${buildMarkupRangeAttrs(child.commentRangeEnd)}/>`;
8924
- if ("commentReference" in child) return `<w:r>${child.properties ? stringifyRunProperties(child.properties) ?? "" : ""}<w:commentReference w:id="${child.commentReference}"/></w:r>`;
8925
- if ("bookmarkStart" in child) return `<w:bookmarkStart ${buildBookmarkStartAttrs(child.bookmarkStart)}/>`;
8926
- if ("bookmarkEnd" in child) return `<w:bookmarkEnd ${buildMarkupRangeAttrs(child.bookmarkEnd)}/>`;
8927
- if ("bookmark" in child) return stringifyBookmarkChild(child.bookmark, ctx);
8928
- if ("symbolRun" in child) {
8929
- const opts = child.symbolRun;
8930
- return `<w:r>${stringifyRunProperties(opts) ?? ""}${stringifySymbolRunInner(opts)}</w:r>`;
8931
- }
8932
- if ("object" in child) return `<w:r>${stringifyRunProperties(child) ?? ""}${objectDesc.stringify(child.object, ctx)}</w:r>`;
8933
- if ("pict" in child) return `<w:r>${stringifyRunProperties(child) ?? ""}${stringifyPict(child.pict, ctx)}</w:r>`;
8934
- if ("formField" in child) {
8935
- const ff = child.formField;
8936
- let result = "";
8937
- let instrCode = "";
8938
- let symbolFont = false;
8939
- if (ff.checkBox) {
8940
- result = ff.checkBox.checked ? "☒" : "☐";
8941
- instrCode = "FORMCHECKBOX";
8942
- symbolFont = true;
8943
- } else if (ff.dropDownList) {
8944
- const idx = ff.dropDownList.result ?? ff.dropDownList.default;
8945
- result = idx !== void 0 ? ff.dropDownList.entries[idx] ?? "" : "";
8946
- instrCode = "FORMDROPDOWN";
8947
- } else if (ff.textInput) {
8948
- result = ff.textInput.value ?? ff.textInput.default ?? "";
8949
- instrCode = "FORMTEXT";
8950
- }
8951
- const rPr = symbolFont ? "<w:rPr><w:rFonts w:ascii=\"MS Gothic\" w:hAnsi=\"MS Gothic\"/></w:rPr>" : "";
8952
- return `<w:r>${createBegin(false, ff)}</w:r><w:r><w:instrText xml:space="preserve"> ${instrCode} </w:instrText></w:r><w:r>${createSeparate()}</w:r><w:r>${rPr}<w:t xml:space="preserve">${escapeXml(result)}</w:t></w:r><w:r>${createEnd()}</w:r>`;
8953
- }
8954
- if ("picture" in child) {
8955
- const opts = child.picture;
8956
- if (opts.type !== "svg" && opts.data === void 0 && opts.sourceUrl !== void 0) return wrapDrawingRun(drawingDesc.stringify({
8957
- mediaData: {
8958
- type: opts.type,
8959
- sourceUrl: opts.sourceUrl,
8960
- transformation: createTransformation(opts.transformation),
8961
- sourceRectangle: opts.sourceRectangle,
8962
- nonVisualProperties: opts.nonVisualProperties,
8963
- useLocalDpi: opts.useLocalDpi,
8964
- compression: opts.compression
8965
- },
8966
- docProperties: opts.altText,
8967
- floating: opts.floating,
8968
- outline: opts.outline,
8969
- fill: opts.fill,
8970
- effects: opts.effects,
8971
- scene3d: opts.scene3d,
8972
- shape3d: opts.shape3d,
8973
- blipEffects: opts.blipEffects,
8974
- tile: opts.tile,
8975
- graphicFrameLocks: opts.graphicFrameLocks
8976
- }, ctx), opts);
8977
- const rawData = toUint8Array(opts.data, { encoding: "base64" });
8978
- let mediaData;
8979
- if (opts.type === "svg") {
8980
- const fallbackData = toUint8Array(opts.fallback.data, { encoding: "base64" });
8981
- const fallbackType = opts.fallback.type;
8982
- const fallback = ctx.file.media.addMedia(fallbackData, fallbackType, (fileName) => ({
8983
- type: fallbackType,
8984
- ...createPictureData(fallbackData, opts.transformation, fileName)
8985
- }), opts.fallback.fileName);
8986
- mediaData = ctx.file.media.addMedia(rawData, "svg", (fileName) => ({
8987
- type: "svg",
8988
- ...createPictureData(rawData, opts.transformation, fileName, opts.sourceRectangle, opts.nonVisualProperties),
8989
- useLocalDpi: opts.useLocalDpi,
8990
- compression: opts.compression,
8991
- fallback
8992
- }), opts.fileName);
8993
- } else {
8994
- const type = opts.type;
8995
- mediaData = ctx.file.media.addMedia(rawData, type, (fileName) => ({
8996
- type,
8997
- ...createPictureData(rawData, opts.transformation, fileName, opts.sourceRectangle, opts.nonVisualProperties),
8998
- useLocalDpi: opts.useLocalDpi,
8999
- compression: opts.compression,
9000
- sourceUrl: opts.sourceUrl
9001
- }), opts.fileName);
9002
- }
9003
- return wrapDrawingRun(drawingDesc.stringify({
9004
- mediaData,
9005
- docProperties: opts.altText,
9006
- floating: opts.floating,
9007
- outline: opts.outline,
9008
- fill: opts.fill,
9009
- effects: opts.effects,
9010
- scene3d: opts.scene3d,
9011
- shape3d: opts.shape3d,
9012
- blipEffects: opts.blipEffects,
9013
- tile: opts.tile,
9014
- graphicFrameLocks: opts.graphicFrameLocks
9015
- }, ctx), opts);
9016
- }
9017
- if ("chart" in child) {
9018
- const opts = child.chart;
9019
- const chartKey = `chart_${nextChartId++}`;
9020
- const mediaData = {
9021
- chartKey,
9022
- transformation: createTransformation(opts.transformation),
9023
- type: "chart"
9024
- };
9025
- const { transformation: _t, floating: _f, altText: _a, graphicFrameLocks: _g, runProperties: _r, lastRenderedPageBreak: _l, ...chartSpace } = opts;
9026
- const chartXml = chartSpaceDesc.stringify(chartSpace, ctx.file);
9027
- const externalData = chartSpace.externalData;
9028
- ctx.file.charts.addChart(chartKey, {
9029
- key: chartKey,
9030
- chartSpaceXml: chartXml ?? "",
9031
- ...externalData?.data !== void 0 && externalData.fileName ? { embedding: {
9032
- relationshipId: externalData.relationshipId,
9033
- fileName: externalData.fileName,
9034
- data: externalData.data
9035
- } } : {},
9036
- ...chartSpace.userShapes ? { userShapes: buildUserShapesData(chartSpace.userShapes) } : {}
9037
- });
9038
- return wrapDrawingRun(drawingDesc.stringify({
9039
- mediaData,
9040
- docProperties: opts.altText,
9041
- floating: opts.floating,
9042
- graphicFrameLocks: opts.graphicFrameLocks
9043
- }, ctx), opts);
9044
- }
9045
- if ("smartArt" in child) {
9046
- const opts = child.smartArt;
9047
- const smartArtKey = `smartart_${hashSmartArtData(opts)}`;
9048
- const mediaData = {
9049
- smartArtKey,
9050
- transformation: createTransformation(opts.transformation),
9051
- type: "smartart"
9052
- };
9053
- const layoutId = typeof opts.layout === "object" ? definitionId(opts.layout) : opts.layout ?? "default";
9054
- const styleId = typeof opts.style === "object" ? definitionId(opts.style) : opts.style ?? "simple1";
9055
- const colorId = typeof opts.color === "object" ? definitionId(opts.color) : opts.color ?? "accent1_2";
9056
- const dataModelXml = createDataModel(opts.nodes, layoutId, styleId, colorId);
9057
- let remappedDataRels = opts.raw?.dataRels;
9058
- if (opts.raw?.media) {
9059
- const renames = /* @__PURE__ */ new Map();
9060
- for (const m of opts.raw.media) {
9061
- const data = toUint8Array(m.data);
9062
- const type = imageTypeFromPath(m.fileName);
9063
- const entry = ctx.file.media.addMedia(data, type, (fileName) => ({
9064
- type,
9065
- data,
9066
- fileName,
9067
- transformation: {
9068
- emus: {
9069
- x: 0,
9070
- y: 0
9071
- },
9072
- pixels: {
9073
- x: 0,
9074
- y: 0
9075
- }
9076
- }
9077
- }), m.fileName);
9078
- if (entry.fileName !== m.fileName) renames.set(m.fileName, entry.fileName);
9079
- }
9080
- if (renames.size > 0 && remappedDataRels !== void 0) remappedDataRels = remapDataRelsTargets(remappedDataRels, renames);
9081
- }
9082
- ctx.file.smartArts.addSmartArt(smartArtKey, {
9083
- dataModelXml,
9084
- key: smartArtKey,
9085
- layout: opts.layout ?? "default",
9086
- style: opts.style ?? "simple1",
9087
- color: opts.color ?? "accent1_2",
9088
- ...opts.raw || remappedDataRels !== void 0 ? { raw: {
9089
- ...opts.raw,
9090
- dataRels: remappedDataRels
9091
- } } : {}
9092
- });
9093
- return wrapDrawingRun(drawingDesc.stringify({
9094
- mediaData,
9095
- docProperties: opts.altText,
9096
- floating: opts.floating,
9097
- graphicFrameLocks: opts.graphicFrameLocks
9098
- }, ctx), {
9099
- runProperties: opts.runProperties,
9100
- lastRenderedPageBreak: opts.lastRenderedPageBreak
9101
- });
9102
- }
9103
- if ("wpsShape" in child) {
9104
- const opts = child.wpsShape;
9105
- const mediaData = {
9106
- data: opts,
9107
- transformation: createTransformation(opts.transformation),
9108
- type: "wps"
9109
- };
9110
- const drawingXml = drawingDesc.stringify({
9111
- mediaData,
9112
- docProperties: opts.altText,
9113
- floating: opts.floating,
9114
- outline: opts.outline,
9115
- fill: opts.fill,
9116
- graphicFrameLocks: opts.graphicFrameLocks
9117
- }, ctx);
9118
- registerVmlFallbackMedia(opts, ctx);
9119
- return wrapDrawingRun(drawingXml, opts);
9120
- }
9121
- if ("contentPart" in child) return `<w:r><w:contentPart r:id="${child.contentPart.referenceId}"/></w:r>`;
9122
- if ("wpgGroup" in child) {
9123
- const opts = child.wpgGroup;
9124
- const mediaData = {
9125
- children: opts.children,
9126
- transformation: createTransformation(opts.transformation),
9127
- childOffsetX: opts.childOffsetX,
9128
- childOffsetY: opts.childOffsetY,
9129
- childExtentWidth: opts.childExtentWidth,
9130
- childExtentHeight: opts.childExtentHeight,
9131
- fill: opts.fill,
9132
- effects: opts.effects,
9133
- groupShapeLocks: opts.groupShapeLocks,
9134
- type: "wpg"
9135
- };
9136
- const registerMedia = (children) => {
9137
- for (const c of children) {
9138
- if (c.type === "wps") continue;
9139
- if (c.type === "wpg") {
9140
- registerMedia(c.children);
9141
- continue;
9142
- }
9143
- if (c.type === "chart") {
9144
- if (c.chartOptions && !c.chartKey) {
9145
- c.chartKey = `chart_${nextChartId++}`;
9146
- const externalData = c.chartOptions.externalData;
9147
- ctx.file.charts.addChart(c.chartKey, {
9148
- key: c.chartKey,
9149
- chartSpaceXml: chartSpaceDesc.stringify(c.chartOptions, ctx.file) ?? "",
9150
- ...externalData?.data !== void 0 && externalData.fileName ? { embedding: {
9151
- relationshipId: externalData.relationshipId,
9152
- fileName: externalData.fileName,
9153
- data: externalData.data
9154
- } } : {},
9155
- ...c.chartOptions.userShapes ? { userShapes: buildUserShapesData(c.chartOptions.userShapes) } : {}
9156
- });
9157
- }
9158
- continue;
9159
- }
9160
- if (c.type === "contentPart") continue;
9161
- if (c.type === "svg") {
9162
- const fb = c.fallback;
9163
- fb.fileName = ctx.file.media.addMedia(fb.data, fb.type, () => fb, fb.fileName).fileName;
9164
- c.fileName = ctx.file.media.addMedia(c.data, "svg", () => c, c.fileName).fileName;
9165
- continue;
9166
- }
9167
- c.fileName = ctx.file.media.addMedia(c.data, c.type, () => c, c.fileName).fileName;
9168
- }
9169
- };
9170
- registerMedia(opts.children);
9171
- const drawingXml = drawingDesc.stringify({
9172
- mediaData,
9173
- docProperties: opts.altText,
9174
- floating: opts.floating,
9175
- graphicFrameLocks: opts.graphicFrameLocks
9176
- }, ctx);
9177
- registerVmlFallbackMedia(opts, ctx);
9178
- return wrapDrawingRun(drawingXml, opts);
9036
+ }
9037
+ function runPropertiesXml(child) {
9038
+ return stringifyRunProperties(child) ?? "";
9039
+ }
9040
+ /**
9041
+ * The plain-run shape the dispatch text fast path claims: text set, with none
9042
+ * of the variants that legally coexist with text and have their own dispatch
9043
+ * branch (references, the { text, hyperlink } shorthand). Callers that need
9044
+ * context-specific text spelling (w:delText inside a deletion wrapper) use
9045
+ * this to claim the shape before dispatch does.
9046
+ */
9047
+ function isPlainTextRun(child) {
9048
+ const run = child;
9049
+ return "text" in child && run.text !== void 0 && run.footnoteReference === void 0 && run.endnoteReference === void 0 && !("commentReference" in child) && !("hyperlink" in child);
9050
+ }
9051
+ function stringifyChildDispatch(child, ctx) {
9052
+ if ("rawXml" in child) return child.rawXml;
9053
+ if (isPlainTextRun(child)) return stringifyRunInline(child, ctx);
9054
+ if ("pageBreak" in child) return `<w:r>${runPropertiesXml(child)}<w:br w:type="page"/></w:r>`;
9055
+ if ("columnBreak" in child) return `<w:r>${runPropertiesXml(child)}<w:br w:type="column"/></w:r>`;
9056
+ if ("tab" in child) return `<w:r>${runPropertiesXml(child)}<w:tab/></w:r>`;
9057
+ if ("subDoc" in child) return subDocDesc.stringify(child.subDoc, ctx) ?? "";
9058
+ const fnRefChild = child.footnoteReference;
9059
+ if (fnRefChild !== void 0) {
9060
+ const id = typeof fnRefChild === "number" ? fnRefChild : fnRefChild.id;
9061
+ const cmf = typeof fnRefChild === "object" && fnRefChild.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
9062
+ const props = "properties" in child ? child.properties : void 0;
9063
+ return `<w:r>${props ? stringifyRunProperties(props) ?? "" : "<w:rPr><w:rStyle w:val=\"FootnoteReference\"/></w:rPr>"}<w:footnoteReference w:id="${id}"${cmf}/></w:r>`;
9064
+ }
9065
+ const enRefChild = child.endnoteReference;
9066
+ if (enRefChild !== void 0) {
9067
+ const id = typeof enRefChild === "number" ? enRefChild : enRefChild.id;
9068
+ const cmf = typeof enRefChild === "object" && enRefChild.customMarkFollows ? " w:customMarkFollows=\"1\"" : "";
9069
+ const props = "properties" in child ? child.properties : void 0;
9070
+ return `<w:r>${props ? stringifyRunProperties(props) ?? "" : "<w:rPr><w:rStyle w:val=\"EndnoteReference\"/></w:rPr>"}<w:endnoteReference w:id="${id}"${cmf}/></w:r>`;
9071
+ }
9072
+ if ("comment" in child) return stringifyCommentChild(child.comment, ctx);
9073
+ if ("commentRangeStart" in child) return `<w:commentRangeStart ${buildMarkupRangeAttrs(child.commentRangeStart)}/>`;
9074
+ if ("commentRangeEnd" in child) return `<w:commentRangeEnd ${buildMarkupRangeAttrs(child.commentRangeEnd)}/>`;
9075
+ if ("commentReference" in child) return `<w:r>${child.properties ? stringifyRunProperties(child.properties) ?? "" : ""}<w:commentReference w:id="${child.commentReference}"/></w:r>`;
9076
+ if ("bookmarkStart" in child) return `<w:bookmarkStart ${buildBookmarkStartAttrs(child.bookmarkStart)}/>`;
9077
+ if ("bookmarkEnd" in child) return `<w:bookmarkEnd ${buildMarkupRangeAttrs(child.bookmarkEnd)}/>`;
9078
+ if ("bookmark" in child) return stringifyBookmarkChild(child.bookmark, ctx);
9079
+ if ("symbolRun" in child) {
9080
+ const opts = child.symbolRun;
9081
+ return `<w:r>${stringifyRunProperties(opts) ?? ""}${stringifySymbolRunInner(opts)}</w:r>`;
9082
+ }
9083
+ if ("object" in child) return `<w:r>${stringifyRunProperties(child) ?? ""}${objectDesc.stringify(child.object, ctx)}</w:r>`;
9084
+ if ("pict" in child) return `<w:r>${stringifyRunProperties(child) ?? ""}${stringifyPict(child.pict, ctx)}</w:r>`;
9085
+ if ("formField" in child) {
9086
+ const ff = child.formField;
9087
+ let result = "";
9088
+ let instrCode = "";
9089
+ let symbolFont = false;
9090
+ if (ff.checkBox) {
9091
+ result = ff.checkBox.checked ? "☒" : "☐";
9092
+ instrCode = "FORMCHECKBOX";
9093
+ symbolFont = true;
9094
+ } else if (ff.dropDownList) {
9095
+ const idx = ff.dropDownList.result ?? ff.dropDownList.default;
9096
+ result = idx !== void 0 ? ff.dropDownList.entries[idx] ?? "" : "";
9097
+ instrCode = "FORMDROPDOWN";
9098
+ } else if (ff.textInput) {
9099
+ result = ff.textInput.value ?? ff.textInput.default ?? "";
9100
+ instrCode = "FORMTEXT";
9101
+ }
9102
+ const rPr = symbolFont ? "<w:rPr><w:rFonts w:ascii=\"MS Gothic\" w:hAnsi=\"MS Gothic\"/></w:rPr>" : "";
9103
+ return `<w:r>${createBegin(false, ff)}</w:r><w:r><w:instrText xml:space="preserve"> ${instrCode} </w:instrText></w:r><w:r>${createSeparate()}</w:r><w:r>${rPr}<w:t xml:space="preserve">${escapeXml(result)}</w:t></w:r><w:r>${createEnd()}</w:r>`;
9179
9104
  }
9105
+ const drawingXml = stringifyDrawingChild(child, ctx);
9106
+ if (drawingXml !== void 0) return drawingXml;
9180
9107
  if ("math" in child && typeof child.math === "object" && child.math !== null) {
9181
9108
  const mathOpts = child.math;
9182
9109
  const children = mathOpts.children ?? [];
@@ -9210,7 +9137,8 @@ function stringifyChildDispatch(child, ctx) {
9210
9137
  if (hl.docLocation) attrs.push(`w:docLocation="${escapeXml(hl.docLocation)}"`);
9211
9138
  };
9212
9139
  if (hl.url) {
9213
- const attrs = [`r:id="${`rId${ctx.viewWrapper.relationships.add("http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", hl.url, TargetModeType.EXTERNAL)}`}"`];
9140
+ const relType = RELATIONSHIP_TYPES.hyperlink;
9141
+ const attrs = [`r:id="${`rId${ctx.viewWrapper.relationships.add(relType, hl.url, TargetModeType.EXTERNAL)}`}"`];
9214
9142
  pushHlAttrs(attrs);
9215
9143
  return `<w:hyperlink ${attrs.join(" ")}>${body}</w:hyperlink>`;
9216
9144
  }
@@ -9362,59 +9290,6 @@ function serializeDispatchChildren(children, ctx) {
9362
9290
  }
9363
9291
  return body;
9364
9292
  }
9365
- /** Rewrite ../media targets inside verbatim data rels after the media
9366
- * collection re-allocated pinned names. All renames apply in one pass over
9367
- * the original text, each match bounded by its closing quote, so a name
9368
- * that prefixes another cannot collide and chained renames cannot re-hit
9369
- * an already-rewritten target. Preserves the input form (string stays
9370
- * string, bytes stay bytes). */
9371
- function remapDataRelsTargets(rels, renames) {
9372
- const isText = typeof rels === "string";
9373
- const text = isText ? rels : new TextDecoder().decode(toUint8Array(rels));
9374
- let out = "";
9375
- let last = 0;
9376
- for (const m of text.matchAll(/\.\.\/media\/([^"']*)["']/g)) {
9377
- const name = m[1] ?? "";
9378
- const to = renames.get(name);
9379
- if (to === void 0) continue;
9380
- const start = (m.index ?? 0) + 9;
9381
- out += text.slice(last, start) + to;
9382
- last = start + name.length;
9383
- }
9384
- out += text.slice(last);
9385
- return isText ? out : new TextEncoder().encode(out);
9386
- }
9387
- /** Content fingerprint of the raw source parts: every field participates so
9388
- * two instances that differ in any raw part (or in their companion rels or
9389
- * media names) never merge into one diagram part set. */
9390
- function rawSmartArtFingerprint(raw) {
9391
- if (!raw) return void 0;
9392
- const b64 = (v) => v === void 0 ? void 0 : encodeBase64(toUint8Array(v));
9393
- return JSON.stringify({
9394
- data: b64(raw.data),
9395
- layout: b64(raw.layout),
9396
- style: b64(raw.style),
9397
- color: b64(raw.color),
9398
- dataRels: b64(raw.dataRels),
9399
- media: raw.media?.map((m) => m.fileName)
9400
- });
9401
- }
9402
- /** Hash SmartArt data for unique key generation (duplicated from SmartArtRun). */
9403
- function hashSmartArtData(options) {
9404
- const data = JSON.stringify({
9405
- nodes: options.nodes,
9406
- layout: options.layout,
9407
- style: options.style,
9408
- color: options.color,
9409
- raw: rawSmartArtFingerprint(options.raw)
9410
- });
9411
- let hash = 0;
9412
- for (let i = 0; i < data.length; i++) {
9413
- const char = data.charCodeAt(i);
9414
- hash = (hash << 5) - hash + char | 0;
9415
- }
9416
- return Math.abs(hash);
9417
- }
9418
9293
  function stringifyParagraphInline(opts, ctx) {
9419
9294
  const resolved = typeof opts === "string" ? { text: opts } : opts;
9420
9295
  let body = "";
@@ -11609,11 +11484,14 @@ function headingOverride(options, level) {
11609
11484
  }
11610
11485
  /** Word's default `<w:rPrDefault>` — theme fonts, kern, 11pt, ligatures. Injected
11611
11486
  * for fresh documents (no structured docDefaults provided) to mirror Word's
11612
- * Normal.dotx. On round-trip the structured form is used instead. */
11613
- const WORD_DEFAULT_RPR_DEFAULT = "<w:rPrDefault><w:rPr><w:rFonts w:asciiTheme=\"minorHAnsi\" w:eastAsiaTheme=\"minorEastAsia\" w:hAnsiTheme=\"minorHAnsi\" w:cstheme=\"minorBidi\"/><w:kern w:val=\"2\"/><w:sz w:val=\"22\"/><w:szCs w:val=\"24\"/><w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" w:bidi=\"ar-SA\"/><w14:ligatures w14:val=\"standardContextual\"/></w:rPr></w:rPrDefault>";
11614
- /** Word's default `<w:pPrDefault>` — widow/orphan control + 8pt after / 1.16 line.
11615
- * Injected for fresh documents only. */
11616
- const WORD_DEFAULT_PPR_DEFAULT = "<w:pPrDefault><w:pPr><w:widowControl/><w:spacing w:after=\"160\" w:line=\"278\" w:lineRule=\"auto\"/></w:pPr></w:pPrDefault>";
11487
+ * Normal.dotx; `language` stands in for Word's editing language (default: an
11488
+ * en-US install writes `<w:lang w:val="en-US"/>`). On round-trip the structured
11489
+ * form is used instead. */
11490
+ const wordDefaultRprDefault = (language) => "<w:rPrDefault><w:rPr><w:rFonts w:asciiTheme=\"minorHAnsi\" w:eastAsiaTheme=\"minorEastAsia\" w:hAnsiTheme=\"minorHAnsi\" w:cstheme=\"minorBidi\"/><w:kern w:val=\"2\"/><w:sz w:val=\"22\"/><w:szCs w:val=\"24\"/>" + languageStr(language ?? { value: "en-US" }) + "<w14:ligatures w14:val=\"standardContextual\"/></w:rPr></w:rPrDefault>";
11491
+ /** Word's default `<w:pPrDefault>` — 8pt after / 1.16 line. widowControl is not
11492
+ * written: ECMA-376 defaults it to on, matching Word's template bytes. Injected
11493
+ * for fresh documents only. */
11494
+ const WORD_DEFAULT_PPR_DEFAULT = "<w:pPrDefault><w:pPr><w:spacing w:after=\"160\" w:line=\"278\" w:lineRule=\"auto\"/></w:pPr></w:pPrDefault>";
11617
11495
  /**
11618
11496
  * Build `<w:docDefaults>` XML from a structured {@link DocumentDefaultsOptions}.
11619
11497
  *
@@ -11627,13 +11505,13 @@ const WORD_DEFAULT_PPR_DEFAULT = "<w:pPrDefault><w:pPr><w:widowControl/><w:spaci
11627
11505
  * mirror Word's Normal.dotx; on round-trip we omit the element
11628
11506
  * to preserve the source's "this default category is absent".
11629
11507
  */
11630
- function stringifyDocDefaults(opts, injectDefaults = true) {
11508
+ function stringifyDocDefaults(opts, injectDefaults = true, language) {
11631
11509
  const children = [];
11632
11510
  if (opts.run) {
11633
11511
  const rPr = stringifyRunProperties(opts.run);
11634
11512
  children.push(rPr ? `<w:rPrDefault>${rPr}</w:rPrDefault>` : `<w:rPrDefault/>`);
11635
11513
  } else if (opts.run === null) children.push(`<w:rPrDefault/>`);
11636
- else if (injectDefaults) children.push(WORD_DEFAULT_RPR_DEFAULT);
11514
+ else if (injectDefaults) children.push(wordDefaultRprDefault(language));
11637
11515
  if (opts.paragraph) {
11638
11516
  const pPr = stringifyParagraphProperties(opts.paragraph).xml;
11639
11517
  children.push(pPr ? `<w:pPrDefault>${pPr}</w:pPrDefault>` : `<w:pPrDefault/>`);
@@ -11672,7 +11550,7 @@ var DefaultStylesFactory = class {
11672
11550
  ]),
11673
11551
  "mc:Ignorable": "w14 w15"
11674
11552
  };
11675
- importedStyles.push(stringifyDocDefaults(options.document ?? {}));
11553
+ importedStyles.push(stringifyDocDefaults(options.document ?? {}, true, options.language));
11676
11554
  importedStyles.push("<w:latentStyles w:defLockedState=\"0\" w:defUIPriority=\"99\" w:defSemiHidden=\"0\" w:defUnhideWhenUsed=\"0\" w:defQFormat=\"0\" w:count=\"376\"><w:lsdException w:name=\"Normal\" w:uiPriority=\"0\" w:qFormat=\"1\"/><w:lsdException w:name=\"heading 1\" w:uiPriority=\"9\" w:qFormat=\"1\"/><w:lsdException w:name=\"heading 2\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/><w:lsdException w:name=\"heading 3\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/><w:lsdException w:name=\"heading 4\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/><w:lsdException w:name=\"heading 5\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/><w:lsdException w:name=\"heading 6\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/><w:lsdException w:name=\"heading 7\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/><w:lsdException w:name=\"heading 8\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/><w:lsdException w:name=\"heading 9\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/><w:lsdException w:name=\"Default Paragraph Font\" w:semiHidden=\"1\" w:uiPriority=\"1\" w:unhideWhenUsed=\"1\"/><w:lsdException w:name=\"Normal Table\" w:semiHidden=\"1\" w:uiPriority=\"99\" w:unhideWhenUsed=\"1\"/><w:lsdException w:name=\"No List\" w:semiHidden=\"1\" w:uiPriority=\"99\" w:unhideWhenUsed=\"1\"/><w:lsdException w:name=\"Subtitle\" w:uiPriority=\"11\" w:qFormat=\"1\"/><w:lsdException w:name=\"Strong\" w:uiPriority=\"22\" w:qFormat=\"1\"/><w:lsdException w:name=\"Emphasis\" w:uiPriority=\"20\" w:qFormat=\"1\"/><w:lsdException w:name=\"Hyperlink\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/><w:lsdException w:name=\"FollowedHyperlink\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/><w:lsdException w:name=\"No Spacing\" w:uiPriority=\"1\" w:qFormat=\"1\"/><w:lsdException w:name=\"Revision\" w:semiHidden=\"1\"/></w:latentStyles>");
11677
11555
  paragraphStyles.push({
11678
11556
  id: "Normal",
@@ -11685,7 +11563,7 @@ var DefaultStylesFactory = class {
11685
11563
  id: "Heading1",
11686
11564
  name: "heading 1",
11687
11565
  link: "Heading1Char",
11688
- sz: 48,
11566
+ sz: 24,
11689
11567
  before: 480,
11690
11568
  after: 80,
11691
11569
  outlineLvl: 0
@@ -11694,7 +11572,7 @@ var DefaultStylesFactory = class {
11694
11572
  id: "Heading2",
11695
11573
  name: "heading 2",
11696
11574
  link: "Heading2Char",
11697
- sz: 40,
11575
+ sz: 20,
11698
11576
  before: 160,
11699
11577
  after: 80,
11700
11578
  outlineLvl: 1
@@ -11703,7 +11581,7 @@ var DefaultStylesFactory = class {
11703
11581
  id: "Heading3",
11704
11582
  name: "heading 3",
11705
11583
  link: "Heading3Char",
11706
- sz: 32,
11584
+ sz: 16,
11707
11585
  before: 160,
11708
11586
  after: 80,
11709
11587
  outlineLvl: 2
@@ -11712,7 +11590,7 @@ var DefaultStylesFactory = class {
11712
11590
  id: "Heading4",
11713
11591
  name: "heading 4",
11714
11592
  link: "Heading4Char",
11715
- sz: 28,
11593
+ sz: 14,
11716
11594
  before: 80,
11717
11595
  after: 40,
11718
11596
  outlineLvl: 3
@@ -11721,7 +11599,7 @@ var DefaultStylesFactory = class {
11721
11599
  id: "Heading5",
11722
11600
  name: "heading 5",
11723
11601
  link: "Heading5Char",
11724
- sz: 24,
11602
+ sz: 12,
11725
11603
  before: 80,
11726
11604
  after: 40,
11727
11605
  outlineLvl: 4
@@ -11813,9 +11691,8 @@ var DefaultStylesFactory = class {
11813
11691
  }
11814
11692
  };
11815
11693
  if (h.sz) {
11816
- const sizePt = h.sz / 2;
11817
- runProps.size = sizePt;
11818
- runProps.sizeComplexScript = sizePt;
11694
+ runProps.size = h.sz;
11695
+ runProps.sizeComplexScript = h.sz;
11819
11696
  }
11820
11697
  if (outlineLvl >= 5) {
11821
11698
  runProps.bold = true;
@@ -12202,7 +12079,7 @@ var DefaultStylesFactory = class {
12202
12079
  line: 240,
12203
12080
  lineRule: "auto"
12204
12081
  } },
12205
- run: { size: 20 },
12082
+ run: { size: 10 },
12206
12083
  ...options.footnoteText
12207
12084
  });
12208
12085
  characterStyles.push({
@@ -12211,7 +12088,7 @@ var DefaultStylesFactory = class {
12211
12088
  basedOn: "DefaultParagraphFont",
12212
12089
  link: "FootnoteText",
12213
12090
  semiHidden: true,
12214
- run: { size: 20 },
12091
+ run: { size: 10 },
12215
12092
  ...options.footnoteTextChar
12216
12093
  });
12217
12094
  characterStyles.push({
@@ -12236,7 +12113,7 @@ var DefaultStylesFactory = class {
12236
12113
  line: 240,
12237
12114
  lineRule: "auto"
12238
12115
  } },
12239
- run: { size: 20 },
12116
+ run: { size: 10 },
12240
12117
  ...options.endnoteText
12241
12118
  });
12242
12119
  characterStyles.push({
@@ -12245,7 +12122,7 @@ var DefaultStylesFactory = class {
12245
12122
  basedOn: "DefaultParagraphFont",
12246
12123
  link: "EndnoteText",
12247
12124
  semiHidden: true,
12248
- run: { size: 20 },
12125
+ run: { size: 10 },
12249
12126
  ...options.endnoteTextChar
12250
12127
  });
12251
12128
  characterStyles.push({
@@ -13238,71 +13115,7 @@ const FRESH_COMPATIBILITY = {
13238
13115
  };
13239
13116
  function stringifyCompatibility(opts) {
13240
13117
  const p = [];
13241
- if (opts.useSingleBorderforContiguousCells) p.push(onOff("w:useSingleBorderforContiguousCells", true));
13242
- if (opts.wordPerfectJustification) p.push(onOff("w:wpJustification", true));
13243
- if (opts.noTabStopForHangingIndent) p.push(onOff("w:noTabHangInd", true));
13244
- if (opts.noLeading) p.push(onOff("w:noLeading", true));
13245
- if (opts.spaceForUnderline) p.push(onOff("w:spaceForUL", true));
13246
- if (opts.noColumnBalance) p.push(onOff("w:noColumnBalance", true));
13247
- if (opts.balanceSingleByteDoubleByteWidth) p.push(onOff("w:balanceSingleByteDoubleByteWidth", true));
13248
- if (opts.noExtraLineSpacing) p.push(onOff("w:noExtraLineSpacing", true));
13249
- if (opts.doNotLeaveBackslashAlone) p.push(onOff("w:doNotLeaveBackslashAlone", true));
13250
- if (opts.underlineTrailingSpaces) p.push(onOff("w:ulTrailSpace", true));
13251
- if (opts.doNotExpandShiftReturn) p.push(onOff("w:doNotExpandShiftReturn", true));
13252
- if (opts.spacingInWholePoints) p.push(onOff("w:spacingInWholePoints", true));
13253
- if (opts.lineWrapLikeWord6) p.push(onOff("w:lineWrapLikeWord6", true));
13254
- if (opts.printBodyTextBeforeHeader) p.push(onOff("w:printBodyTextBeforeHeader", true));
13255
- if (opts.printColorsBlack) p.push(onOff("w:printColBlack", true));
13256
- if (opts.spaceWidth) p.push(onOff("w:wpSpaceWidth", true));
13257
- if (opts.showBreaksInFrames) p.push(onOff("w:showBreaksInFrames", true));
13258
- if (opts.subFontBySize) p.push(onOff("w:subFontBySize", true));
13259
- if (opts.suppressBottomSpacing) p.push(onOff("w:suppressBottomSpacing", true));
13260
- if (opts.suppressTopSpacing) p.push(onOff("w:suppressTopSpacing", true));
13261
- if (opts.suppressSpacingAtTopOfPage) p.push(onOff("w:suppressSpacingAtTopOfPage", true));
13262
- if (opts.suppressTopSpacingWP) p.push(onOff("w:suppressTopSpacingWP", true));
13263
- if (opts.suppressSpBfAfterPgBrk) p.push(onOff("w:suppressSpBfAfterPgBrk", true));
13264
- if (opts.swapBordersFacingPages) p.push(onOff("w:swapBordersFacingPages", true));
13265
- if (opts.convertMailMergeEsc) p.push(onOff("w:convMailMergeEsc", true));
13266
- if (opts.truncateFontHeightsLikeWP6) p.push(onOff("w:truncateFontHeightsLikeWP6", true));
13267
- if (opts.macWordSmallCaps) p.push(onOff("w:mwSmallCaps", true));
13268
- if (opts.usePrinterMetrics) p.push(onOff("w:usePrinterMetrics", true));
13269
- if (opts.doNotSuppressParagraphBorders) p.push(onOff("w:doNotSuppressParagraphBorders", true));
13270
- if (opts.wrapTrailSpaces) p.push(onOff("w:wrapTrailSpaces", true));
13271
- if (opts.footnoteLayoutLikeWW8) p.push(onOff("w:footnoteLayoutLikeWW8", true));
13272
- if (opts.shapeLayoutLikeWW8) p.push(onOff("w:shapeLayoutLikeWW8", true));
13273
- if (opts.alignTablesRowByRow) p.push(onOff("w:alignTablesRowByRow", true));
13274
- if (opts.forgetLastTabAlignment) p.push(onOff("w:forgetLastTabAlignment", true));
13275
- if (opts.adjustLineHeightInTable) p.push(onOff("w:adjustLineHeightInTable", true));
13276
- if (opts.autoSpaceLikeWord95) p.push(onOff("w:autoSpaceLikeWord95", true));
13277
- if (opts.noSpaceRaiseLower) p.push(onOff("w:noSpaceRaiseLower", true));
13278
- if (opts.doNotUseHTMLParagraphAutoSpacing) p.push(onOff("w:doNotUseHTMLParagraphAutoSpacing", true));
13279
- if (opts.layoutRawTableWidth) p.push(onOff("w:layoutRawTableWidth", true));
13280
- if (opts.layoutTableRowsApart) p.push(onOff("w:layoutTableRowsApart", true));
13281
- if (opts.useWord97LineBreakRules) p.push(onOff("w:useWord97LineBreakRules", true));
13282
- if (opts.doNotBreakWrappedTables) p.push(onOff("w:doNotBreakWrappedTables", true));
13283
- if (opts.doNotSnapToGridInCell) p.push(onOff("w:doNotSnapToGridInCell", true));
13284
- if (opts.selectFieldWithFirstOrLastCharacter) p.push(onOff("w:selectFldWithFirstOrLastChar", true));
13285
- if (opts.applyBreakingRules) p.push(onOff("w:applyBreakingRules", true));
13286
- if (opts.doNotWrapTextWithPunctuation) p.push(onOff("w:doNotWrapTextWithPunct", true));
13287
- if (opts.doNotUseEastAsianBreakRules) p.push(onOff("w:doNotUseEastAsianBreakRules", true));
13288
- if (opts.useWord2002TableStyleRules) p.push(onOff("w:useWord2002TableStyleRules", true));
13289
- if (opts.growAutofit) p.push(onOff("w:growAutofit", true));
13290
- if (opts.useFELayout) p.push(onOff("w:useFELayout", true));
13291
- if (opts.useNormalStyleForList) p.push(onOff("w:useNormalStyleForList", true));
13292
- if (opts.doNotUseIndentAsNumberingTabStop) p.push(onOff("w:doNotUseIndentAsNumberingTabStop", true));
13293
- if (opts.useAlternateEastAsianLineBreakRules) p.push(onOff("w:useAltKinsokuLineBreakRules", true));
13294
- if (opts.allowSpaceOfSameStyleInTable) p.push(onOff("w:allowSpaceOfSameStyleInTable", true));
13295
- if (opts.doNotSuppressIndentation) p.push(onOff("w:doNotSuppressIndentation", true));
13296
- if (opts.doNotAutofitConstrainedTables) p.push(onOff("w:doNotAutofitConstrainedTables", true));
13297
- if (opts.autofitToFirstFixedWidthCell) p.push(onOff("w:autofitToFirstFixedWidthCell", true));
13298
- if (opts.underlineTabInNumberingList) p.push(onOff("w:underlineTabInNumList", true));
13299
- if (opts.displayHangulFixedWidth) p.push(onOff("w:displayHangulFixedWidth", true));
13300
- if (opts.splitPgBreakAndParaMark) p.push(onOff("w:splitPgBreakAndParaMark", true));
13301
- if (opts.doNotVerticallyAlignCellWithSp) p.push(onOff("w:doNotVertAlignCellWithSp", true));
13302
- if (opts.doNotBreakConstrainedForcedTable) p.push(onOff("w:doNotBreakConstrainedForcedTable", true));
13303
- if (opts.ignoreVerticalAlignmentInTextboxes) p.push(onOff("w:doNotVertAlignInTxbx", true));
13304
- if (opts.useAnsiKerningPairs) p.push(onOff("w:useAnsiKerningPairs", true));
13305
- if (opts.cachedColumnBalance) p.push(onOff("w:cachedColBalance", true));
13118
+ for (const [key, tag] of COMPAT_FLAG_MAP) if (opts[key]) p.push(onOff(tag, true));
13306
13119
  if (opts.enableOpenTypeKerning) p.push("<w14:enableOpenTypeKerning/>");
13307
13120
  if (opts.version) p.push(compatSetting("compatibilityMode", opts.version));
13308
13121
  if (opts.overrideTableStyleFontSizeAndJustification) p.push(compatSetting("overrideTableStyleFontSizeAndJustification", 1));
@@ -14336,8 +14149,8 @@ var DocxWriteContext = class {
14336
14149
  this.fontTable = new FontWrapper(options.fonts ?? []);
14337
14150
  this.glossaryOptions = options.glossary;
14338
14151
  this.webSettings = options.webSettings ?? void 0;
14339
- if (options.glossary) this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument", "glossary/document.xml");
14340
- if (this.webSettings) this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings", "webSettings.xml");
14152
+ if (options.glossary) this.registerDocumentRel(RELATIONSHIP_TYPES.glossaryDocument, "glossary/document.xml");
14153
+ if (this.webSettings) this.registerDocumentRel(RELATIONSHIP_TYPES.webSettings, "webSettings.xml");
14341
14154
  }
14342
14155
  get headers() {
14343
14156
  return this._headers;
@@ -14389,12 +14202,12 @@ var DocxWriteContext = class {
14389
14202
  addHeaderToDocument(header, partName) {
14390
14203
  this._headers.push(header);
14391
14204
  header.partName = this.nextPartName(this._headers, partName, "header");
14392
- this.document.relationships.addRelationship(header.referenceId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header", header.partName);
14205
+ this.document.relationships.addRelationship(header.referenceId, RELATIONSHIP_TYPES.header, header.partName);
14393
14206
  }
14394
14207
  addFooterToDocument(footer, partName) {
14395
14208
  this._footers.push(footer);
14396
14209
  footer.partName = this.nextPartName(this._footers, partName, "footer");
14397
- this.document.relationships.addRelationship(footer.referenceId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer", footer.partName);
14210
+ this.document.relationships.addRelationship(footer.referenceId, RELATIONSHIP_TYPES.footer, footer.partName);
14398
14211
  }
14399
14212
  /** Resolve the part file name: the round-tripped source name when given,
14400
14213
  * else the next free <kind>N.xml slot (pinned names never collide). */
@@ -14410,17 +14223,17 @@ var DocxWriteContext = class {
14410
14223
  return name;
14411
14224
  }
14412
14225
  addDefaultRelationships() {
14413
- this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", "styles.xml");
14414
- if (this._hasNumbering) this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", "numbering.xml");
14415
- if (this._hasFootnotes) this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes", "footnotes.xml");
14416
- if (this._hasEndnotes) this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes", "endnotes.xml");
14417
- this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings", "settings.xml");
14418
- if (this._options.comments?.length || this._hasCommentSugar) this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", "comments.xml");
14419
- if (this._options.people?.length) this.registerDocumentRel("http://schemas.microsoft.com/office/2011/relationships/people", "people.xml");
14420
- if (this._options.commentsExtended?.length) this.registerDocumentRel("http://schemas.microsoft.com/office/2011/relationships/commentsExtended", "commentsExtended.xml");
14421
- if (this._options.bibliography) this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/bibliography", "bibliography.xml");
14226
+ this.registerDocumentRel(RELATIONSHIP_TYPES.styles, "styles.xml");
14227
+ if (this._hasNumbering) this.registerDocumentRel(RELATIONSHIP_TYPES.numbering, "numbering.xml");
14228
+ if (this._hasFootnotes) this.registerDocumentRel(RELATIONSHIP_TYPES.footnotes, "footnotes.xml");
14229
+ if (this._hasEndnotes) this.registerDocumentRel(RELATIONSHIP_TYPES.endnotes, "endnotes.xml");
14230
+ this.registerDocumentRel(RELATIONSHIP_TYPES.settings, "settings.xml");
14231
+ if (this._options.comments?.length || this._hasCommentSugar) this.registerDocumentRel(RELATIONSHIP_TYPES.comments, "comments.xml");
14232
+ if (this._options.people?.length) this.registerDocumentRel(RELATIONSHIP_TYPES.peopleMs, "people.xml");
14233
+ if (this._options.commentsExtended?.length) this.registerDocumentRel(RELATIONSHIP_TYPES.commentsExtendedMs, "commentsExtended.xml");
14234
+ if (this._options.bibliography) this.registerDocumentRel(RELATIONSHIP_TYPES.bibliography, "bibliography.xml");
14422
14235
  const themeRel = (this._options.passthroughRelationships ?? []).find((r) => r.source === "word/document.xml" && r.relationshipType.endsWith("/theme"));
14423
- this.registerDocumentRel("http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", themeRel ? themeRel.target : "theme/theme1.xml");
14236
+ this.registerDocumentRel(RELATIONSHIP_TYPES.theme, themeRel ? themeRel.target : "theme/theme1.xml");
14424
14237
  }
14425
14238
  /**
14426
14239
  * Register a default document relationship. On round-trip, reuse the source
@@ -16503,9 +16316,9 @@ const VerticalAlignSection = {
16503
16316
  //#region src/patch/from-docx.ts
16504
16317
  /** Reusable TextEncoder (stateless, safe to share). */
16505
16318
  const encoder$1 = new TextEncoder();
16506
- const COMMENTS_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
16319
+ const COMMENTS_REL_TYPE = RELATIONSHIP_TYPES.comments;
16507
16320
  const COMMENTS_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml";
16508
- const HYPERLINK_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
16321
+ const HYPERLINK_REL_TYPE = RELATIONSHIP_TYPES.hyperlink;
16509
16322
  /**
16510
16323
  * Rendered hyperlink ids start here so they can never collide with the real
16511
16324
  * rIdN ids of the part's relationships — including the media entries the
@@ -16840,7 +16653,7 @@ const patchDocument = async ({ outputType, data, placeholders, findReplace, core
16840
16653
  map.set(key, JSON.parse(newJson));
16841
16654
  for (const [i, media] of mediaDatas.entries()) {
16842
16655
  const { fileName } = media;
16843
- appendRelationship(relationshipsJson, index + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${fileName}`);
16656
+ appendRelationship(relationshipsJson, index + i, RELATIONSHIP_TYPES.image, `media/${fileName}`);
16844
16657
  }
16845
16658
  }
16846
16659
  const hyperlinksByPart = /* @__PURE__ */ new Map();
@@ -18738,20 +18551,273 @@ const guidSize = 32;
18738
18551
  * const obfuscatedData = obfuscate(fontData, fontKey);
18739
18552
  * ```
18740
18553
  *
18741
- * @internal
18554
+ * @internal
18555
+ */
18556
+ const obfuscate = (buf, fontKey) => {
18557
+ const guid = fontKey.replace(/-/g, "");
18558
+ if (guid.length !== guidSize) throw new Error(`Error: Cannot extract GUID from font filename: ${fontKey}`);
18559
+ const hexNumbers = guid.replace(/(..)/g, "$1 ").trim().split(" ").map((hexString) => parseInt(hexString, 16));
18560
+ hexNumbers.reverse();
18561
+ const obfuscatedBytes = buf.slice(obfuscatedStartOffset, obfuscatedEndOffset).map((byte, i) => byte ^ hexNumbers[i % hexNumbers.length]);
18562
+ const out = new Uint8Array(obfuscatedStartOffset + obfuscatedBytes.length + Math.max(0, buf.length - obfuscatedEndOffset));
18563
+ out.set(buf.slice(0, obfuscatedStartOffset));
18564
+ out.set(obfuscatedBytes, obfuscatedStartOffset);
18565
+ out.set(buf.slice(obfuscatedEndOffset), obfuscatedStartOffset + obfuscatedBytes.length);
18566
+ return out;
18567
+ };
18568
+ //#endregion
18569
+ //#region src/compile/shared.ts
18570
+ /**
18571
+ * Relationship wiring shared by the docx compile phases: the XML declaration,
18572
+ * the OLE/PACKAGE embedding relationship resolution, and the per-part media +
18573
+ * embedding placeholder bridge.
18574
+ *
18575
+ * @module
18576
+ */
18577
+ /** XML declaration prepended to every OOXML part. */
18578
+ const XML_DECL = OOXML_XML_DECLARATION;
18579
+ /** Relationship type for OLE embedding parts (word|ppt/embeddings/*). */
18580
+ const OLE_OBJECT_RELATIONSHIP = RELATIONSHIP_TYPES.oleObject;
18581
+ /** Relationship type for native-format embedding parts (embedded xlsx/docx). */
18582
+ const PACKAGE_RELATIONSHIP = RELATIONSHIP_TYPES.package;
18583
+ /** Re-emit the relationship type the source used for an embedding part — a
18584
+ * native OPC package (xlsx/docx) stays a package rel, an OLE compound binary
18585
+ * stays an oleObject rel. */
18586
+ const embeddingRelationship = (embeddings, fileName) => embeddings.array.find((e) => e.fileName === fileName)?.relationshipType === "package" ? PACKAGE_RELATIONSHIP : OLE_OBJECT_RELATIONSHIP;
18587
+ /**
18588
+ * Resolve a part's {fileName} media placeholders against the package media
18589
+ * store, then its embedding placeholders chained past the media
18590
+ * relationships (same ordering as the document part — headers/footers and
18591
+ * notes can carry w:object runs of their own).
18592
+ */
18593
+ function resolvePartMedia(xml, ctx, relCount) {
18594
+ const media = findAndReplaceImagePlaceholders(xml, ctx.media.array, relCount);
18595
+ const embeddingOffset = relCount + media.referenced.length;
18596
+ const embeddings = findAndReplaceImagePlaceholders(media.xml, ctx.embeddings.array, embeddingOffset);
18597
+ return {
18598
+ xml: embeddings.xml,
18599
+ relCount,
18600
+ embeddingOffset,
18601
+ mediaRefs: media.referenced,
18602
+ embeddingRefs: embeddings.referenced
18603
+ };
18604
+ }
18605
+ /** Register the resolved media + embedding relationships on the part's rels. */
18606
+ function registerPartMedia(rels, ctx, resolved) {
18607
+ for (const [i, ref] of resolved.mediaRefs.entries()) rels.addRelationship(resolved.relCount + i, RELATIONSHIP_TYPES.image, `media/${ref.fileName}`);
18608
+ for (const [i, ref] of resolved.embeddingRefs.entries()) rels.addRelationship(resolved.embeddingOffset + i, embeddingRelationship(ctx.embeddings, ref.fileName), `embeddings/${ref.fileName}`);
18609
+ }
18610
+ //#endregion
18611
+ //#region src/compile/document.ts
18612
+ /**
18613
+ * Document part compile phase: word/document.xml (chart/SmartArt/numbering
18614
+ * placeholder resolution over the stringified body) and
18615
+ * word/_rels/document.xml.rels.
18616
+ *
18617
+ * The document part is the only one whose media/embedding relationships
18618
+ * re-emit the source rIds on round-trip: the body XML references them
18619
+ * verbatim, so registration goes through sourceRidFor before falling back to
18620
+ * the offset-derived id.
18621
+ *
18622
+ * @module
18623
+ */
18624
+ /**
18625
+ * Look up the source rId for a document relationship by kind+target. Returns
18626
+ * the numeric id when the source carried the same rel, undefined otherwise.
18627
+ * The body XML's `r:id` references the source rId verbatim on round-trip, so
18628
+ * the structured compiler must emit the rel at that exact id — otherwise
18629
+ * `r:id="rId4"` would point at a different rel and Word refuses to open.
18630
+ */
18631
+ function sourceRidFor(passthroughRelationships, ownerSource, relationshipType, target) {
18632
+ if (!passthroughRelationships) return void 0;
18633
+ for (const rel of passthroughRelationships) if (rel.source === ownerSource && rel.relationshipType === relationshipType && rel.target === target) {
18634
+ const m = /^rId(\d+)$/.exec(rel.rId);
18635
+ if (m) return Number(m[1]);
18636
+ }
18637
+ }
18638
+ /**
18639
+ * Build a {fileName → rId} map for source rels targeting `media/` or
18640
+ * `embeddings/`. findAndReplaceImagePlaceholders consults this map to
18641
+ * substitute the source rId in body XML (so `<a:blip r:embed="rId5"/>` points
18642
+ * at the rel registered at rId5 — not the rel registered at an
18643
+ * offset-derived id, which dangles against any source body that referenced
18644
+ * the source rId). Placeholder keys use the media-collection fileName; a
18645
+ * dedup-renamed file misses the map and falls through to the offset id on
18646
+ * BOTH the body and the .rels side, keeping them consistent.
18647
+ */
18648
+ function documentSourceRids(ctx, dir) {
18649
+ const map = /* @__PURE__ */ new Map();
18650
+ const prefix = `${dir}/`;
18651
+ for (const rel of ctx._options.passthroughRelationships ?? []) {
18652
+ if (rel.source !== "word/document.xml") continue;
18653
+ if (!rel.target.startsWith(prefix)) continue;
18654
+ map.set(rel.target.slice(prefix.length), rel.rId);
18655
+ }
18656
+ return map;
18657
+ }
18658
+ /** Resolve the document body's media/embedding placeholders, then emit the
18659
+ * document part and its rels. The rels entry registers media, embeddings,
18660
+ * charts, SmartArt, the font table, and the claimed passthrough rels — in
18661
+ * that order, so the source rId ordering is preserved. */
18662
+ function compileDocumentEntries(ctx, documentXmlData, documentRelationshipCount) {
18663
+ const documentMedia = findAndReplaceImagePlaceholders(documentXmlData, ctx.media.array, documentRelationshipCount, "rId", documentSourceRids(ctx, "media"));
18664
+ const documentEmbeddingOffset = documentRelationshipCount + documentMedia.referenced.length;
18665
+ const documentEmbeddings = findAndReplaceImagePlaceholders(documentMedia.xml, ctx.embeddings.array, documentEmbeddingOffset, "rId", documentSourceRids(ctx, "embeddings"));
18666
+ return {
18667
+ Document: {
18668
+ data: (() => {
18669
+ let xmlData = documentEmbeddings.xml;
18670
+ if (hasPlaceholders(xmlData)) {
18671
+ const mediaCount = documentMedia.referenced.length;
18672
+ const embeddingCount = documentEmbeddings.referenced.length;
18673
+ const chartKeys = ctx.charts.array.map((c) => c.key);
18674
+ const smartArtKeys = ctx.smartArts.array.map((s) => s.key);
18675
+ const chartOffset = documentRelationshipCount + mediaCount + embeddingCount;
18676
+ const smartArtOffset = chartOffset + chartKeys.length;
18677
+ const entries = [];
18678
+ for (const [i, key] of chartKeys.entries()) {
18679
+ const chartTarget = `charts/chart${i + 1}.xml`;
18680
+ const sourceRid = sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", RELATIONSHIP_TYPES.chart, chartTarget);
18681
+ entries.push({
18682
+ prefix: "chart:",
18683
+ key,
18684
+ value: sourceRid !== void 0 ? `rId${sourceRid}` : formatId(chartOffset, i, "rId")
18685
+ });
18686
+ }
18687
+ const saPrefixes = [
18688
+ "smartart:",
18689
+ "smartart-lo:",
18690
+ "smartart-qs:",
18691
+ "smartart-cs:"
18692
+ ];
18693
+ for (const [i, key] of smartArtKeys.entries()) for (let p = 0; p < saPrefixes.length; p++) entries.push({
18694
+ prefix: saPrefixes[p],
18695
+ key,
18696
+ value: formatId(smartArtOffset + p * smartArtKeys.length, i, "rId")
18697
+ });
18698
+ for (const { reference, instance, numId } of ctx.numbering.concreteNumbering) entries.push({
18699
+ key: `${reference}-${instance}`,
18700
+ value: numId.toString()
18701
+ });
18702
+ xmlData = replaceAllPlaceholders(xmlData, entries);
18703
+ } else xmlData = replaceNumberingPlaceholders(xmlData, ctx.numbering.concreteNumbering);
18704
+ return xmlData;
18705
+ })(),
18706
+ path: "word/document.xml"
18707
+ },
18708
+ Relationships: {
18709
+ data: (() => {
18710
+ for (const [i, ref] of documentMedia.referenced.entries()) {
18711
+ const target = `media/${ref.fileName}`;
18712
+ const sourceRid = sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", RELATIONSHIP_TYPES.image, target);
18713
+ ctx.document.relationships.addRelationship(sourceRid ?? documentRelationshipCount + i, RELATIONSHIP_TYPES.image, target);
18714
+ }
18715
+ for (const [i, ref] of documentEmbeddings.referenced.entries()) {
18716
+ const target = `embeddings/${ref.fileName}`;
18717
+ const sourceRid = sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", embeddingRelationship(ctx.embeddings, ref.fileName), target);
18718
+ ctx.document.relationships.addRelationship(sourceRid ?? documentEmbeddingOffset + i, embeddingRelationship(ctx.embeddings, ref.fileName), target);
18719
+ }
18720
+ const chartOffset = documentRelationshipCount + documentMedia.referenced.length + documentEmbeddings.referenced.length;
18721
+ for (let i = 0; i < ctx.charts.array.length; i++) {
18722
+ const target = `charts/chart${i + 1}.xml`;
18723
+ const sourceRid = sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", RELATIONSHIP_TYPES.chart, target);
18724
+ ctx.document.relationships.addRelationship(sourceRid ?? chartOffset + i, RELATIONSHIP_TYPES.chart, target);
18725
+ }
18726
+ addSmartArtRelationships(ctx.smartArts.array.map((s) => s.key), (id, type, target) => {
18727
+ ctx.document.relationships.addRelationship(id, type, target);
18728
+ }, documentRelationshipCount + documentMedia.referenced.length + documentEmbeddings.referenced.length + ctx.charts.array.length, 0, {
18729
+ pathPrefix: "",
18730
+ styleRelType: RELATIONSHIP_TYPES.diagramQuickStyle,
18731
+ hasDrawing: (key) => ctx.smartArts.array.find((s) => s.key === key)?.raw?.drawing !== void 0
18732
+ });
18733
+ ctx.document.relationships.addRelationship(sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", RELATIONSHIP_TYPES.fontTable, "fontTable.xml") ?? ctx.document.relationships.nextRelationshipId, RELATIONSHIP_TYPES.fontTable, "fontTable.xml");
18734
+ ctx.addPassthroughDocumentRelationships();
18735
+ return XML_DECL + ctx.document.relationships.serialize();
18736
+ })(),
18737
+ path: "word/_rels/document.xml.rels"
18738
+ }
18739
+ };
18740
+ }
18741
+ //#endregion
18742
+ //#region src/compile/drawings.ts
18743
+ /**
18744
+ * Drawing tail compile phase: the chart parts (chartSpace, userShapes, their
18745
+ * rels and embedded workbooks) and the SmartArt diagram part sets
18746
+ * (data/layout/quickStyle/colors plus the Office render-cache drawing), read
18747
+ * off the collections the document body stringification filled.
18748
+ *
18749
+ * @module
18742
18750
  */
18743
- const obfuscate = (buf, fontKey) => {
18744
- const guid = fontKey.replace(/-/g, "");
18745
- if (guid.length !== guidSize) throw new Error(`Error: Cannot extract GUID from font filename: ${fontKey}`);
18746
- const hexNumbers = guid.replace(/(..)/g, "$1 ").trim().split(" ").map((hexString) => parseInt(hexString, 16));
18747
- hexNumbers.reverse();
18748
- const obfuscatedBytes = buf.slice(obfuscatedStartOffset, obfuscatedEndOffset).map((byte, i) => byte ^ hexNumbers[i % hexNumbers.length]);
18749
- const out = new Uint8Array(obfuscatedStartOffset + obfuscatedBytes.length + Math.max(0, buf.length - obfuscatedEndOffset));
18750
- out.set(buf.slice(0, obfuscatedStartOffset));
18751
- out.set(obfuscatedBytes, obfuscatedStartOffset);
18752
- out.set(buf.slice(obfuscatedEndOffset), obfuscatedStartOffset + obfuscatedBytes.length);
18753
- return out;
18754
- };
18751
+ /** Chart part → user-shapes part relationship (c:userShapes bridge). */
18752
+ const CHART_USER_SHAPES_REL = RELATIONSHIP_TYPES.chartUserShapes;
18753
+ function compileChartParts(ctx) {
18754
+ if (ctx.charts.array.length === 0) return {};
18755
+ return {
18756
+ Charts: ctx.charts.array.flatMap((chartData, i) => {
18757
+ const parts = [{
18758
+ data: XML_DECL + chartData.chartSpaceXml,
18759
+ path: `word/charts/chart${i + 1}.xml`
18760
+ }];
18761
+ if (chartData.userShapes) parts.push({
18762
+ data: XML_DECL + chartData.userShapes.xml,
18763
+ path: `word/charts/userShapes${i + 1}.xml`
18764
+ });
18765
+ const e = chartData.embedding;
18766
+ const rels = [...e ? [`<Relationship Id="${escapeXml(e.relationshipId)}" Type="${PACKAGE_RELATIONSHIP}" Target="../embeddings/${escapeXml(e.fileName)}"/>`] : [], ...chartData.userShapes ? [`<Relationship Id="${escapeXml(chartData.userShapes.relationshipId)}" Type="${CHART_USER_SHAPES_REL}" Target="userShapes${i + 1}.xml"/>`] : []];
18767
+ if (rels.length > 0) parts.push({
18768
+ data: XML_DECL + `<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${rels.join("")}</Relationships>`,
18769
+ path: `word/charts/_rels/chart${i + 1}.xml.rels`
18770
+ });
18771
+ return parts;
18772
+ }),
18773
+ ChartEmbeddings: (() => {
18774
+ const seen = /* @__PURE__ */ new Set();
18775
+ const parts = [];
18776
+ for (const c of ctx.charts.array) {
18777
+ const e = c.embedding;
18778
+ if (!e || seen.has(e.fileName)) continue;
18779
+ seen.add(e.fileName);
18780
+ parts.push({
18781
+ data: toUint8Array(e.data),
18782
+ path: `word/embeddings/${e.fileName}`
18783
+ });
18784
+ }
18785
+ return parts;
18786
+ })()
18787
+ };
18788
+ }
18789
+ function compileSmartArtParts(ctx) {
18790
+ if (ctx.smartArts.array.length === 0) return {};
18791
+ return {
18792
+ DiagramData: ctx.smartArts.array.map((smartArtData, i) => ({
18793
+ data: smartArtData.raw?.data !== void 0 ? toUint8Array(smartArtData.raw.data) : XML_DECL + smartArtData.dataModelXml,
18794
+ path: `word/diagrams/data${i + 1}.xml`
18795
+ })),
18796
+ DiagramLayout: ctx.smartArts.array.map((smartArtData, i) => ({
18797
+ data: smartArtData.raw?.layout !== void 0 ? toUint8Array(smartArtData.raw.layout) : typeof smartArtData.layout === "string" ? getLayoutXml(smartArtData.layout) : stringifyLayoutDefinitionPart(smartArtData.layout),
18798
+ path: `word/diagrams/layout${i + 1}.xml`
18799
+ })),
18800
+ DiagramStyle: ctx.smartArts.array.map((smartArtData, i) => ({
18801
+ data: smartArtData.raw?.style !== void 0 ? toUint8Array(smartArtData.raw.style) : typeof smartArtData.style === "string" ? getStyleXml(smartArtData.style) : stringifyStyleDefinitionPart(smartArtData.style),
18802
+ path: `word/diagrams/quickStyle${i + 1}.xml`
18803
+ })),
18804
+ DiagramColors: ctx.smartArts.array.map((smartArtData, i) => ({
18805
+ data: smartArtData.raw?.color !== void 0 ? toUint8Array(smartArtData.raw.color) : typeof smartArtData.color === "string" ? getColorXml(smartArtData.color) : stringifyColorDefinitionPart(smartArtData.color),
18806
+ path: `word/diagrams/colors${i + 1}.xml`
18807
+ })),
18808
+ DiagramDrawing: ctx.smartArts.array.map((smartArtData, i) => ({
18809
+ smartArtData,
18810
+ i
18811
+ })).filter(({ smartArtData }) => smartArtData.raw?.drawing !== void 0).map(({ smartArtData, i }) => ({
18812
+ data: toUint8Array(smartArtData.raw.drawing),
18813
+ path: `word/diagrams/drawing${i + 1}.xml`
18814
+ })),
18815
+ ...ctx.smartArts.array.some((s) => s.raw?.dataRels !== void 0) ? { SmartArtDataRels: ctx.smartArts.array.flatMap((smartArtData, i) => smartArtData.raw?.dataRels !== void 0 ? [{
18816
+ data: toUint8Array(smartArtData.raw.dataRels),
18817
+ path: `word/diagrams/_rels/data${i + 1}.xml.rels`
18818
+ }] : []) } : {}
18819
+ };
18820
+ }
18755
18821
  //#endregion
18756
18822
  //#region src/parts/header-footer.ts
18757
18823
  /**
@@ -18831,6 +18897,146 @@ function stringifyHeaderFooter(tag, namespaces, children, ctx) {
18831
18897
  return body.length === 0 ? `<${tag} ${attrStr}/>` : `<${tag} ${attrStr}>${body}</${tag}>`;
18832
18898
  }
18833
18899
  //#endregion
18900
+ //#region src/compile/headerfooter.ts
18901
+ /**
18902
+ * Header/footer compile phase: the four mapping arrays (Headers, Footers,
18903
+ * HeaderRelationships, FooterRelationships).
18904
+ *
18905
+ * Headers and footers are structural twins — same stringify → placeholder
18906
+ * resolution → relationship registration pipeline, differing only in element
18907
+ * name, namespaces, and default part name — so one per-part helper serves
18908
+ * both, and each part's body and rels are produced together (no cross-entry
18909
+ * state needed).
18910
+ *
18911
+ * @module
18912
+ */
18913
+ /** Stringify one header/footer part and wire its media/embedding
18914
+ * relationships. Images get per-part relationship IDs starting at
18915
+ * nextRelationshipId, mirroring the document part; the placeholder pass uses
18916
+ * referenced-local positions, so body r:embed and .rels stay aligned. */
18917
+ function compileHeaderFooterPart(kind, entry, index, ctx, mkCtx) {
18918
+ const partName = entry.partName ?? `${kind}${index + 1}.xml`;
18919
+ const partCtx = mkCtx({
18920
+ relationships: entry.relationships,
18921
+ partName: `word/${partName}`
18922
+ });
18923
+ const xmlData = XML_DECL + stringifyHeaderFooter(kind === "footer" ? "w:ftr" : "w:hdr", kind === "footer" ? FOOTER_NAMESPACES : HEADER_NAMESPACES, entry.children, partCtx);
18924
+ const relCount = entry.relationships.nextRelationshipId;
18925
+ const resolved = resolvePartMedia(xmlData, ctx, relCount);
18926
+ registerPartMedia(entry.relationships, ctx, resolved);
18927
+ return {
18928
+ part: {
18929
+ data: replaceNumberingPlaceholders(resolved.xml, ctx.numbering.concreteNumbering),
18930
+ path: `word/${partName}`
18931
+ },
18932
+ rels: optionalRelsPart(entry.relationships, XML_DECL, `word/_rels/${partName}.rels`)
18933
+ };
18934
+ }
18935
+ function mapParts(entries, kind, ctx, mkCtx) {
18936
+ const parts = [];
18937
+ const rels = [];
18938
+ entries.forEach((entry, index) => {
18939
+ const compiled = compileHeaderFooterPart(kind, entry, index, ctx, mkCtx);
18940
+ parts.push(compiled.part);
18941
+ if (compiled.rels) rels.push(compiled.rels);
18942
+ });
18943
+ return {
18944
+ parts,
18945
+ rels
18946
+ };
18947
+ }
18948
+ function compileHeaderFooterParts(ctx, mkCtx) {
18949
+ const headers = mapParts(ctx.headers, "header", ctx, mkCtx);
18950
+ const footers = mapParts(ctx.footers, "footer", ctx, mkCtx);
18951
+ return {
18952
+ Headers: headers.parts,
18953
+ HeaderRelationships: headers.rels,
18954
+ Footers: footers.parts,
18955
+ FooterRelationships: footers.rels
18956
+ };
18957
+ }
18958
+ //#endregion
18959
+ //#region src/compile/notes.ts
18960
+ /**
18961
+ * Notes compile phase: comments, footnotes, and endnotes parts.
18962
+ *
18963
+ * All three share the same wiring shape — stringify the part, resolve its
18964
+ * {fileName} media and {oleObjectN.bin} embedding placeholders, register the
18965
+ * matching relationships on the part's own rels, and replace numbering
18966
+ * placeholders. Collected here so the three stay symmetric.
18967
+ *
18968
+ * @module
18969
+ */
18970
+ /**
18971
+ * Comments carried by the document: those the caller listed explicitly
18972
+ * (`options.comments`) plus entries registered by `{ comment }` sugar children
18973
+ * during body stringification. Drives both word/comments.xml generation and the
18974
+ * [Content_Types] comments Override, which must stay in sync (OPC consistency).
18975
+ */
18976
+ function mergedCommentChildren(ctx) {
18977
+ return [...ctx._options.comments ?? [], ...ctx.comments.entries];
18978
+ }
18979
+ /** The three notes parts, present only when the document carries content for
18980
+ * them (an empty part with a dangling relationship is the OPC violation Word
18981
+ * rejects on open). */
18982
+ function compileNotesParts(ctx, mkCtx) {
18983
+ const result = {};
18984
+ const comments = mergedCommentChildren(ctx);
18985
+ if (comments.length > 0) {
18986
+ const commentCtx = mkCtx({ relationships: ctx.comments.relationships });
18987
+ const commentXmlData = XML_DECL + (commentsDesc.stringify(comments, commentCtx) ?? "");
18988
+ const commentRelCount = ctx.comments.relationships.nextRelationshipId;
18989
+ const resolved = resolvePartMedia(commentXmlData, ctx, commentRelCount);
18990
+ registerPartMedia(ctx.comments.relationships, ctx, resolved);
18991
+ result.Comments = {
18992
+ data: replaceNumberingPlaceholders(resolved.xml, ctx.numbering.concreteNumbering),
18993
+ path: "word/comments.xml"
18994
+ };
18995
+ result.CommentsRelationships = optionalRelsPart(ctx.comments.relationships, XML_DECL, "word/_rels/comments.xml.rels");
18996
+ }
18997
+ const footnoteCtx = mkCtx({ relationships: ctx.footNotes.relationships });
18998
+ const footnoteXmlData = XML_DECL + (footnotesDesc.stringify({
18999
+ notes: ctx.footNotes.notes,
19000
+ separator: ctx.footNotes.separator,
19001
+ continuationSeparator: ctx.footNotes.continuationSeparator,
19002
+ continuationNotice: ctx.footNotes.continuationNotice
19003
+ }, footnoteCtx) ?? "");
19004
+ const footnoteRelCount = ctx.footNotes.relationships.nextRelationshipId;
19005
+ const footnoteResolved = resolvePartMedia(footnoteXmlData, ctx, footnoteRelCount);
19006
+ registerPartMedia(ctx.footNotes.relationships, ctx, footnoteResolved);
19007
+ if (ctx.hasFootnotes) {
19008
+ result.FootNotes = {
19009
+ data: replaceNumberingPlaceholders(footnoteResolved.xml, ctx.numbering.concreteNumbering),
19010
+ path: "word/footnotes.xml"
19011
+ };
19012
+ if (ctx.footNotes.relationships.relationshipCount > 0) result.FootNotesRelationships = {
19013
+ data: XML_DECL + ctx.footNotes.relationships.serialize(),
19014
+ path: "word/_rels/footnotes.xml.rels"
19015
+ };
19016
+ }
19017
+ if (ctx.hasEndnotes) {
19018
+ const endnoteCtx = mkCtx({ relationships: ctx.endnotes.relationships });
19019
+ const endnoteXmlData = XML_DECL + (endnotesDesc.stringify({
19020
+ notes: ctx.endnotes.notes,
19021
+ separator: ctx.endnotes.separator,
19022
+ continuationSeparator: ctx.endnotes.continuationSeparator,
19023
+ continuationNotice: ctx.endnotes.continuationNotice
19024
+ }, endnoteCtx) ?? "");
19025
+ const endnoteRelCount = ctx.endnotes.relationships.nextRelationshipId;
19026
+ const resolved = resolvePartMedia(endnoteXmlData, ctx, endnoteRelCount);
19027
+ registerPartMedia(ctx.endnotes.relationships, ctx, resolved);
19028
+ result.Endnotes = {
19029
+ data: replaceNumberingPlaceholders(resolved.xml, ctx.numbering.concreteNumbering),
19030
+ path: "word/endnotes.xml"
19031
+ };
19032
+ if (ctx.endnotes.relationships.relationshipCount > 0) result.EndnotesRelationships = {
19033
+ data: XML_DECL + ctx.endnotes.relationships.serialize(),
19034
+ path: "word/_rels/endnotes.xml.rels"
19035
+ };
19036
+ }
19037
+ return result;
19038
+ }
19039
+ //#endregion
18834
19040
  //#region src/compiler.ts
18835
19041
  /**
18836
19042
  * DOCX document compiler — pure function entry point.
@@ -18840,58 +19046,19 @@ function stringifyHeaderFooter(tag, namespaces, children, ctx) {
18840
19046
  * All XML parts are produced via descriptors or serialize() —
18841
19047
  * no Formatter dependency.
18842
19048
  *
19049
+ * The part wiring runs in phases owned by the compile/ folder: the document
19050
+ * body and its rels (compile/document), the notes parts (compile/notes),
19051
+ * headers/footers (compile/headerfooter), and the chart/SmartArt tail
19052
+ * (compile/drawings), with the placeholder bridge and embedding rel
19053
+ * resolution they share in compile/shared. This module keeps the
19054
+ * part-mapping orchestration.
19055
+ *
18843
19056
  * @module
18844
19057
  */
18845
19058
  /** Reusable TextEncoder (stateless, safe to share). */
18846
19059
  const encoder = new TextEncoder();
18847
- /** Relationship type for OLE embedding parts (word|ppt/embeddings/*). */
18848
- const OLE_OBJECT_RELATIONSHIP = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
18849
- /** Relationship type for native-format embedding parts (embedded xlsx/docx). */
18850
- const PACKAGE_RELATIONSHIP = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
18851
- /** Re-emit the relationship type the source used for an embedding part — a
18852
- * native OPC package (xlsx/docx) stays a package rel, an OLE compound binary
18853
- * stays an oleObject rel. */
18854
- const embeddingRelationship = (embeddings, fileName) => embeddings.array.find((e) => e.fileName === fileName)?.relationshipType === "package" ? PACKAGE_RELATIONSHIP : OLE_OBJECT_RELATIONSHIP;
18855
- /** XML declaration prepended to every OOXML part. */
18856
- const XML_DECL = OOXML_XML_DECLARATION;
18857
- /**
18858
- * Look up the source rId for a document relationship by kind+target. Returns
18859
- * the numeric id when the source carried the same rel, undefined otherwise.
18860
- * The body XML's `r:id` references the source rId verbatim on round-trip, so
18861
- * the structured compiler must emit the rel at that exact id — otherwise
18862
- * `r:id="rId4"` would point at a different rel and Word refuses to open.
18863
- */
18864
- function sourceRidFor(passthroughRelationships, ownerSource, relationshipType, target) {
18865
- if (!passthroughRelationships) return void 0;
18866
- for (const rel of passthroughRelationships) if (rel.source === ownerSource && rel.relationshipType === relationshipType && rel.target === target) {
18867
- const m = /^rId(\d+)$/.exec(rel.rId);
18868
- if (m) return Number(m[1]);
18869
- }
18870
- }
18871
- /**
18872
- * Build a {fileName → rId} map for source rels targeting `media/` or
18873
- * `embeddings/`. findAndReplaceImagePlaceholders consults this map to
18874
- * substitute the source rId in body XML (so `<a:blip r:embed="rId5"/>` points
18875
- * at the rel registered at rId5 — not the rel registered at an
18876
- * offset-derived id, which dangles against any source body that referenced
18877
- * the source rId). Placeholder keys use the media-collection fileName; a
18878
- * dedup-renamed file misses the map and falls through to the offset id on
18879
- * BOTH the body and the .rels side, keeping them consistent.
18880
- */
18881
- function documentSourceRids(ctx, dir) {
18882
- const map = /* @__PURE__ */ new Map();
18883
- const prefix = `${dir}/`;
18884
- for (const rel of ctx._options.passthroughRelationships ?? []) {
18885
- if (rel.source !== "word/document.xml") continue;
18886
- if (!rel.target.startsWith(prefix)) continue;
18887
- map.set(rel.target.slice(prefix.length), rel.rId);
18888
- }
18889
- return map;
18890
- }
18891
19060
  /** DOCX part path → content type, derived from the part registry. */
18892
19061
  const DOCX_CONTENT_TYPE_RESOLVER = resolverFromRegistry(DOCX_PARTS);
18893
- /** Chart part → user-shapes part relationship (c:userShapes bridge). */
18894
- const CHART_USER_SHAPES_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartUserShapes";
18895
19062
  /** Extension → MIME for media/font/embedding Default entries. Declared only
18896
19063
  * for extensions actually present in the package. */
18897
19064
  const DOCX_MEDIA_CONTENT_TYPES = {
@@ -18912,87 +19079,28 @@ function compileDocument(options, overrides = [], mediaLevel = 0) {
18912
19079
  const ctx = new DocxWriteContext(options);
18913
19080
  const xmlifiedFileMapping = xmlifyContext(ctx);
18914
19081
  const files = compileMapping(xmlifiedFileMapping, overrides);
18915
- const mediaArray = ctx.media.array;
18916
- for (const mediaData of mediaArray) {
18917
- addBinaryFile(files, `word/media/${mediaData.fileName}`, mediaData.data, mediaLevel);
18918
- if (mediaData.type === "svg") addBinaryFile(files, `word/media/${mediaData.fallback.fileName}`, mediaData.fallback.data, mediaLevel);
18919
- }
18920
- for (const embedding of ctx.embeddings.array) addBinaryFile(files, `word/embeddings/${embedding.fileName}`, embedding.data, mediaLevel);
19082
+ addModelBinaries(files, "word", ctx.media.array, ctx.embeddings.array, mediaLevel);
18921
19083
  for (const font of ctx.fontTable.fontOptionsWithKey) {
18922
19084
  if (font.data === void 0) continue;
18923
19085
  const [nameWithoutExtension] = font.name.split(".");
18924
19086
  const filePath = font.odttfPath ?? `word/fonts/${nameWithoutExtension}.odttf`;
18925
19087
  files[filePath] = font.rawOdttf ? font.data : obfuscate(font.data, font.fontKey);
18926
19088
  }
18927
- const passthroughSkipped = /* @__PURE__ */ new Set();
18928
- for (const part of ctx._options.rawParts ?? []) {
18929
- if (files[part.path] !== void 0) {
18930
- passthroughSkipped.add(part.path);
18931
- continue;
18932
- }
18933
- files[part.path] = toUint8Array(part.data);
18934
- }
18935
- files["[Content_Types].xml"] = encoder.encode(buildContentTypesData(ctx, files, passthroughSkipped));
18936
- dropDanglingPassthroughRels(files, ctx._options.passthroughRelationships);
18937
- return files;
18938
- }
18939
- /**
18940
- * Comments carried by the document: those the caller listed explicitly
18941
- * (`options.comments`) plus entries registered by `{ comment }` sugar children
18942
- * during body stringification. Drives both word/comments.xml generation and the
18943
- * [Content_Types] comments Override, which must stay in sync (OPC consistency).
18944
- */
18945
- function mergedCommentChildren(ctx) {
18946
- return [...ctx._options.comments ?? [], ...ctx.comments.entries];
18947
- }
18948
- /**
18949
- * Serialize [Content_Types].xml from the part registry, then backfill media/
18950
- * font/embedding `<Default>` entries from the parts actually written.
18951
- *
18952
- * Must run after every part has been stringified (parts call `ctx.addMedia`
18953
- * during stringify), so call this once `xmlifyContext` has finished — not from
18954
- * inside its object literal, where ContentTypes would evaluate before the
18955
- * later-defined header/footer/font parts have registered their media.
18956
- */
18957
- /**
18958
- * Derive [Content_Types].xml from the parts actually written to the package.
18959
- *
18960
- * The file set is the single source of truth: every part the resolver knows
18961
- * becomes an Override, every other file falls through to an extension Default,
18962
- * and altChunk/sub-document parts — whose content type is data-driven, not
18963
- * path-determinable — are injected as explicit overrides.
18964
- *
18965
- * Round-trip no longer passes the source [Content_Types] through: the compiler
18966
- * regenerates every part path (altChunks get a fresh uniqueId), so deriving
18967
- * from the written files is what keeps declarations and parts in sync.
18968
- */
18969
- function buildContentTypesData(ctx, files, passthroughSkipped) {
18970
- const overrides = [...ctx.altChunks.array.map((ac) => ({
18971
- path: `word/${ac.path}`,
18972
- contentType: ac.contentType ?? "application/xhtml+xml"
18973
- })), ...ctx.subDocs.array.map((sd) => ({
18974
- path: `word/${sd.path}`,
18975
- contentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
18976
- }))];
18977
- const input = deriveContentTypes(Object.keys(files), {
19089
+ files["[Content_Types].xml"] = encoder.encode(finalizeContentTypes(files, {
18978
19090
  resolve: DOCX_CONTENT_TYPE_RESOLVER,
18979
19091
  mediaContentTypes: DOCX_MEDIA_CONTENT_TYPES,
18980
- overrides,
18981
19092
  source: ctx._options.contentTypes,
18982
- verbatimPaths: new Set((ctx._options.rawParts ?? []).map((p) => p.path))
18983
- });
18984
- const coveredExt = new Set(input.defaults.map((d) => d.extension.toLowerCase()));
18985
- for (const part of ctx._options.rawParts ?? []) {
18986
- if (part.contentType === void 0 || passthroughSkipped.has(part.path)) continue;
18987
- const dot = part.path.lastIndexOf(".");
18988
- const ext = dot > part.path.lastIndexOf("/") ? part.path.slice(dot + 1).toLowerCase() : void 0;
18989
- if (ext && coveredExt.has(ext)) continue;
18990
- input.overrides.push({
18991
- partName: `/${part.path}`,
18992
- contentType: part.contentType
18993
- });
18994
- }
18995
- return XML_DECL + (contentTypesDesc.stringify(input, ctx) ?? "");
19093
+ rawParts: ctx._options.rawParts,
19094
+ overrides: [...ctx.altChunks.array.map((ac) => ({
19095
+ path: `word/${ac.path}`,
19096
+ contentType: ac.contentType ?? "application/xhtml+xml"
19097
+ })), ...ctx.subDocs.array.map((sd) => ({
19098
+ path: `word/${sd.path}`,
19099
+ contentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
19100
+ }))]
19101
+ }, ctx));
19102
+ dropDanglingPassthroughRels(files, ctx._options.passthroughRelationships);
19103
+ return files;
18996
19104
  }
18997
19105
  function xmlifyContext(ctx) {
18998
19106
  const mkCtx = (viewWrapper = ctx.document) => {
@@ -19008,59 +19116,18 @@ function xmlifyContext(ctx) {
19008
19116
  bodyCtx.stringifyChild = (child) => stringifyBodyChild(child, bodyCtx);
19009
19117
  return bodyCtx;
19010
19118
  };
19011
- const footerMediaResults = /* @__PURE__ */ new Map();
19012
- const footerEmbeddingResults = /* @__PURE__ */ new Map();
19013
- const headerMediaResults = /* @__PURE__ */ new Map();
19014
- const headerEmbeddingResults = /* @__PURE__ */ new Map();
19015
19119
  const docCtx = mkCtx(ctx.document);
19016
19120
  const documentXmlData = XML_DECL + stringifyDocumentXml(ctx, docCtx);
19017
19121
  const documentRelationshipCount = ctx.document.relationships.nextRelationshipId;
19018
- const mergedCommentChildrenList = mergedCommentChildren(ctx);
19019
- const hasComments = mergedCommentChildrenList.length > 0;
19020
- const commentCtx = hasComments ? mkCtx({ relationships: ctx.comments.relationships }) : null;
19021
- const commentXmlData = commentCtx ? XML_DECL + commentsDesc.stringify(mergedCommentChildrenList, commentCtx) : "";
19022
- const commentRelationshipCount = hasComments ? ctx.comments.relationships.nextRelationshipId : 0;
19023
- const footnoteCtx = mkCtx({ relationships: ctx.footNotes.relationships });
19024
- const footnoteXmlData = XML_DECL + (footnotesDesc.stringify({
19025
- notes: ctx.footNotes.notes,
19026
- separator: ctx.footNotes.separator,
19027
- continuationSeparator: ctx.footNotes.continuationSeparator,
19028
- continuationNotice: ctx.footNotes.continuationNotice
19029
- }, footnoteCtx) ?? "");
19030
- const footnoteRelationshipCount = ctx.footNotes.relationships.nextRelationshipId;
19031
- const documentMedia = findAndReplaceImagePlaceholders(documentXmlData, ctx.media.array, documentRelationshipCount, "rId", documentSourceRids(ctx, "media"));
19032
- const documentEmbeddingOffset = documentRelationshipCount + documentMedia.referenced.length;
19033
- const documentEmbeddings = findAndReplaceImagePlaceholders(documentMedia.xml, ctx.embeddings.array, documentEmbeddingOffset, "rId", documentSourceRids(ctx, "embeddings"));
19034
- const commentMedia = hasComments ? findAndReplaceImagePlaceholders(commentXmlData, ctx.media.array, commentRelationshipCount) : {
19035
- xml: "",
19036
- referenced: []
19037
- };
19038
- const commentEmbeddingOffset = commentRelationshipCount + commentMedia.referenced.length;
19039
- const commentEmbeddings = hasComments ? findAndReplaceImagePlaceholders(commentMedia.xml, ctx.embeddings.array, commentEmbeddingOffset) : {
19040
- xml: "",
19041
- referenced: []
19042
- };
19043
- const footnoteMedia = findAndReplaceImagePlaceholders(footnoteXmlData, ctx.media.array, footnoteRelationshipCount);
19044
- const footnoteEmbeddingOffset = footnoteRelationshipCount + footnoteMedia.referenced.length;
19045
- const footnoteEmbeddings = findAndReplaceImagePlaceholders(footnoteMedia.xml, ctx.embeddings.array, footnoteEmbeddingOffset);
19046
- for (const [i, ref] of footnoteMedia.referenced.entries()) ctx.footNotes.relationships.addRelationship(footnoteRelationshipCount + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${ref.fileName}`);
19047
- for (const [i, ref] of footnoteEmbeddings.referenced.entries()) ctx.footNotes.relationships.addRelationship(footnoteEmbeddingOffset + i, embeddingRelationship(ctx.embeddings, ref.fileName), `embeddings/${ref.fileName}`);
19122
+ const notesParts = compileNotesParts(ctx, mkCtx);
19123
+ const headerFooterParts = compileHeaderFooterParts(ctx, mkCtx);
19124
+ const documentEntries = compileDocumentEntries(ctx, documentXmlData, documentRelationshipCount);
19048
19125
  return {
19049
19126
  AppProperties: {
19050
19127
  data: XML_DECL + (appPropertiesDesc.stringify(ctx._options.appProperties ?? {}, ctx) ?? ""),
19051
19128
  path: "docProps/app.xml"
19052
19129
  },
19053
- ...hasComments ? {
19054
- Comments: {
19055
- data: replaceNumberingPlaceholders(commentEmbeddings.xml, ctx.numbering.concreteNumbering),
19056
- path: "word/comments.xml"
19057
- },
19058
- CommentsRelationships: (() => {
19059
- for (const [i, ref] of commentMedia.referenced.entries()) ctx.comments.relationships.addRelationship(commentRelationshipCount + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${ref.fileName}`);
19060
- for (const [i, ref] of commentEmbeddings.referenced.entries()) ctx.comments.relationships.addRelationship(commentEmbeddingOffset + i, embeddingRelationship(ctx.embeddings, ref.fileName), `embeddings/${ref.fileName}`);
19061
- return optionalRelsPart(ctx.comments.relationships, XML_DECL, "word/_rels/comments.xml.rels");
19062
- })()
19063
- } : {},
19130
+ ...notesParts,
19064
19131
  ...ctx._options.customProperties !== void 0 ? { CustomProperties: {
19065
19132
  data: XML_DECL + (customPropertiesDesc.stringify({ properties: ctx._options.customProperties }, ctx) ?? ""),
19066
19133
  path: "docProps/custom.xml"
@@ -19073,76 +19140,11 @@ function xmlifyContext(ctx) {
19073
19140
  data: XML_DECL + (commentsExtendedDesc.stringify(ctx._options.commentsExtended, ctx) ?? ""),
19074
19141
  path: "word/commentsExtended.xml"
19075
19142
  } } : {},
19076
- Document: {
19077
- data: (() => {
19078
- let xmlData = documentEmbeddings.xml;
19079
- if (hasPlaceholders(xmlData)) {
19080
- const mediaCount = documentMedia.referenced.length;
19081
- const embeddingCount = documentEmbeddings.referenced.length;
19082
- const chartKeys = ctx.charts.array.map((c) => c.key);
19083
- const smartArtKeys = ctx.smartArts.array.map((s) => s.key);
19084
- const chartOffset = documentRelationshipCount + mediaCount + embeddingCount;
19085
- const smartArtOffset = chartOffset + chartKeys.length;
19086
- const entries = [];
19087
- for (const [i, key] of chartKeys.entries()) {
19088
- const chartTarget = `charts/chart${i + 1}.xml`;
19089
- const sourceRid = sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", chartTarget);
19090
- entries.push({
19091
- prefix: "chart:",
19092
- key,
19093
- value: sourceRid !== void 0 ? `rId${sourceRid}` : formatId(chartOffset, i, "rId")
19094
- });
19095
- }
19096
- const saPrefixes = [
19097
- "smartart:",
19098
- "smartart-lo:",
19099
- "smartart-qs:",
19100
- "smartart-cs:"
19101
- ];
19102
- for (const [i, key] of smartArtKeys.entries()) for (let p = 0; p < saPrefixes.length; p++) entries.push({
19103
- prefix: saPrefixes[p],
19104
- key,
19105
- value: formatId(smartArtOffset + p * smartArtKeys.length, i, "rId")
19106
- });
19107
- for (const { reference, instance, numId } of ctx.numbering.concreteNumbering) entries.push({
19108
- key: `${reference}-${instance}`,
19109
- value: numId.toString()
19110
- });
19111
- xmlData = replaceAllPlaceholders(xmlData, entries);
19112
- } else xmlData = replaceNumberingPlaceholders(xmlData, ctx.numbering.concreteNumbering);
19113
- return xmlData;
19114
- })(),
19115
- path: "word/document.xml"
19116
- },
19143
+ ...documentEntries,
19117
19144
  ...ctx._options.rawParts?.some((part) => part.path.startsWith("word/theme/")) ? {} : { Theme: {
19118
19145
  data: XML_DECL + createThemeXml(),
19119
19146
  path: "word/theme/theme1.xml"
19120
19147
  } },
19121
- ...ctx.hasEndnotes ? {
19122
- Endnotes: {
19123
- data: (() => {
19124
- const endnoteCtx = mkCtx({ relationships: ctx.endnotes.relationships });
19125
- const xmlData = XML_DECL + (endnotesDesc.stringify({
19126
- notes: ctx.endnotes.notes,
19127
- separator: ctx.endnotes.separator,
19128
- continuationSeparator: ctx.endnotes.continuationSeparator,
19129
- continuationNotice: ctx.endnotes.continuationNotice
19130
- }, endnoteCtx) ?? "");
19131
- const endnoteRelCount = ctx.endnotes.relationships.nextRelationshipId;
19132
- const endnoteMedia = findAndReplaceImagePlaceholders(xmlData, ctx.media.array, endnoteRelCount);
19133
- for (const [i, ref] of endnoteMedia.referenced.entries()) ctx.endnotes.relationships.addRelationship(endnoteRelCount + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${ref.fileName}`);
19134
- const endnoteEmbeddingOffset = endnoteRelCount + endnoteMedia.referenced.length;
19135
- const endnoteEmbeddings = findAndReplaceImagePlaceholders(endnoteMedia.xml, ctx.embeddings.array, endnoteEmbeddingOffset);
19136
- for (const [i, ref] of endnoteEmbeddings.referenced.entries()) ctx.endnotes.relationships.addRelationship(endnoteEmbeddingOffset + i, embeddingRelationship(ctx.embeddings, ref.fileName), `embeddings/${ref.fileName}`);
19137
- return replaceNumberingPlaceholders(endnoteEmbeddings.xml, ctx.numbering.concreteNumbering);
19138
- })(),
19139
- path: "word/endnotes.xml"
19140
- },
19141
- EndnotesRelationships: ctx.endnotes.relationships.relationshipCount > 0 ? {
19142
- data: XML_DECL + ctx.endnotes.relationships.serialize(),
19143
- path: "word/_rels/endnotes.xml.rels"
19144
- } : void 0
19145
- } : {},
19146
19148
  FileRelationships: {
19147
19149
  data: XML_DECL + ctx.fileRelationships.serialize(),
19148
19150
  path: "_rels/.rels"
@@ -19152,67 +19154,12 @@ function xmlifyContext(ctx) {
19152
19154
  path: "word/fontTable.xml"
19153
19155
  },
19154
19156
  FontTableRelationships: optionalRelsPart(ctx.fontTable.relationships, XML_DECL, "word/_rels/fontTable.xml.rels"),
19155
- ...ctx.hasFootnotes ? {
19156
- FootNotes: {
19157
- data: replaceNumberingPlaceholders(footnoteEmbeddings.xml, ctx.numbering.concreteNumbering),
19158
- path: "word/footnotes.xml"
19159
- },
19160
- FootNotesRelationships: ctx.footNotes.relationships.relationshipCount > 0 ? {
19161
- data: XML_DECL + ctx.footNotes.relationships.serialize(),
19162
- path: "word/_rels/footnotes.xml.rels"
19163
- } : void 0
19164
- } : {},
19165
- FooterRelationships: ctx.footers.map((entry, index) => {
19166
- const footerCtx = mkCtx({
19167
- relationships: entry.relationships,
19168
- partName: `word/${entry.partName ?? `footer${index + 1}.xml`}`
19169
- });
19170
- const xmlData = XML_DECL + stringifyHeaderFooter("w:ftr", FOOTER_NAMESPACES, entry.children, footerCtx);
19171
- const footerRelCount = entry.relationships.nextRelationshipId;
19172
- const footerMedia = findAndReplaceImagePlaceholders(xmlData, ctx.media.array, footerRelCount);
19173
- footerMediaResults.set(index, footerMedia);
19174
- const footerEmbeddingOffset = footerRelCount + footerMedia.referenced.length;
19175
- const footerEmbeddings = findAndReplaceImagePlaceholders(footerMedia.xml, ctx.embeddings.array, footerEmbeddingOffset);
19176
- footerEmbeddingResults.set(index, footerEmbeddings);
19177
- for (const [i, ref] of footerMedia.referenced.entries()) entry.relationships.addRelationship(footerRelCount + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${ref.fileName}`);
19178
- for (const [i, ref] of footerEmbeddings.referenced.entries()) entry.relationships.addRelationship(footerEmbeddingOffset + i, embeddingRelationship(ctx.embeddings, ref.fileName), `embeddings/${ref.fileName}`);
19179
- return optionalRelsPart(entry.relationships, XML_DECL, `word/_rels/${entry.partName ?? `footer${index + 1}.xml`}.rels`);
19180
- }).filter((r) => r !== void 0),
19181
- Footers: ctx.footers.map((entry, index) => {
19182
- const footerEmbeddings = footerEmbeddingResults.get(index);
19183
- return {
19184
- data: replaceNumberingPlaceholders(footerEmbeddings.xml, ctx.numbering.concreteNumbering),
19185
- path: `word/${entry.partName ?? `footer${index + 1}.xml`}`
19186
- };
19187
- }),
19188
- HeaderRelationships: ctx.headers.map((entry, index) => {
19189
- const headerCtx = mkCtx({
19190
- relationships: entry.relationships,
19191
- partName: `word/${entry.partName ?? `header${index + 1}.xml`}`
19192
- });
19193
- const xmlData = XML_DECL + stringifyHeaderFooter("w:hdr", HEADER_NAMESPACES, entry.children, headerCtx);
19194
- const headerRelCount = entry.relationships.nextRelationshipId;
19195
- const headerMedia = findAndReplaceImagePlaceholders(xmlData, ctx.media.array, headerRelCount);
19196
- headerMediaResults.set(index, headerMedia);
19197
- const headerEmbeddingOffset = headerRelCount + headerMedia.referenced.length;
19198
- const headerEmbeddings = findAndReplaceImagePlaceholders(headerMedia.xml, ctx.embeddings.array, headerEmbeddingOffset);
19199
- headerEmbeddingResults.set(index, headerEmbeddings);
19200
- for (const [i, ref] of headerMedia.referenced.entries()) entry.relationships.addRelationship(headerRelCount + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${ref.fileName}`);
19201
- for (const [i, ref] of headerEmbeddings.referenced.entries()) entry.relationships.addRelationship(headerEmbeddingOffset + i, embeddingRelationship(ctx.embeddings, ref.fileName), `embeddings/${ref.fileName}`);
19202
- return optionalRelsPart(entry.relationships, XML_DECL, `word/_rels/${entry.partName ?? `header${index + 1}.xml`}.rels`);
19203
- }).filter((r) => r !== void 0),
19204
- Headers: ctx.headers.map((entry, index) => {
19205
- const headerEmbeddings = headerEmbeddingResults.get(index);
19206
- return {
19207
- data: replaceNumberingPlaceholders(headerEmbeddings.xml, ctx.numbering.concreteNumbering),
19208
- path: `word/${entry.partName ?? `header${index + 1}.xml`}`
19209
- };
19210
- }),
19157
+ ...headerFooterParts,
19211
19158
  ...ctx.hasNumbering ? (() => {
19212
19159
  const numberingXml = ctx.numbering.serialize(ctx);
19213
19160
  const numberingMedia = findAndReplaceImagePlaceholders(numberingXml, ctx.media.array, 1);
19214
19161
  const numberingRels = new Relationships();
19215
- for (const [i, ref] of numberingMedia.referenced.entries()) numberingRels.addRelationship(1 + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `media/${ref.fileName}`);
19162
+ for (const [i, ref] of numberingMedia.referenced.entries()) numberingRels.addRelationship(1 + i, RELATIONSHIP_TYPES.image, `media/${ref.fileName}`);
19216
19163
  return {
19217
19164
  Numbering: {
19218
19165
  data: numberingMedia.xml,
@@ -19225,44 +19172,13 @@ function xmlifyContext(ctx) {
19225
19172
  data: XML_DECL + (corePropertiesDesc.stringify(ctx._options, ctx) ?? ""),
19226
19173
  path: "docProps/core.xml"
19227
19174
  },
19228
- Relationships: {
19229
- data: (() => {
19230
- for (const [i, ref] of documentMedia.referenced.entries()) {
19231
- const target = `media/${ref.fileName}`;
19232
- const sourceRid = sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", target);
19233
- ctx.document.relationships.addRelationship(sourceRid ?? documentRelationshipCount + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", target);
19234
- }
19235
- for (const [i, ref] of documentEmbeddings.referenced.entries()) {
19236
- const target = `embeddings/${ref.fileName}`;
19237
- const sourceRid = sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", embeddingRelationship(ctx.embeddings, ref.fileName), target);
19238
- ctx.document.relationships.addRelationship(sourceRid ?? documentEmbeddingOffset + i, embeddingRelationship(ctx.embeddings, ref.fileName), target);
19239
- }
19240
- const chartOffset = documentRelationshipCount + documentMedia.referenced.length + documentEmbeddings.referenced.length;
19241
- for (let i = 0; i < ctx.charts.array.length; i++) {
19242
- const target = `charts/chart${i + 1}.xml`;
19243
- const sourceRid = sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", target);
19244
- ctx.document.relationships.addRelationship(sourceRid ?? chartOffset + i, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", target);
19245
- }
19246
- addSmartArtRelationships(ctx.smartArts.array.map((s) => s.key), (id, type, target) => {
19247
- ctx.document.relationships.addRelationship(id, type, target);
19248
- }, documentRelationshipCount + documentMedia.referenced.length + documentEmbeddings.referenced.length + ctx.charts.array.length, 0, {
19249
- pathPrefix: "",
19250
- styleRelType: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/diagramQuickStyle",
19251
- hasDrawing: (key) => ctx.smartArts.array.find((s) => s.key === key)?.raw?.drawing !== void 0
19252
- });
19253
- ctx.document.relationships.addRelationship(sourceRidFor(ctx._options.passthroughRelationships, "word/document.xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable", "fontTable.xml") ?? ctx.document.relationships.nextRelationshipId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable", "fontTable.xml");
19254
- ctx.addPassthroughDocumentRelationships();
19255
- return XML_DECL + ctx.document.relationships.serialize();
19256
- })(),
19257
- path: "word/_rels/document.xml.rels"
19258
- },
19259
19175
  Settings: {
19260
19176
  data: XML_DECL + (settingsDesc.stringify(ctx._settingsOptions, ctx) ?? ""),
19261
19177
  path: "word/settings.xml"
19262
19178
  },
19263
19179
  ...ctx._settingsOptions.attachedTemplate !== void 0 ? (() => {
19264
19180
  const rels = new Relationships();
19265
- rels.addRelationship(1, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate", ctx._settingsOptions.attachedTemplate, TargetModeType.EXTERNAL);
19181
+ rels.addRelationship(1, RELATIONSHIP_TYPES.attachedTemplate, ctx._settingsOptions.attachedTemplate, TargetModeType.EXTERNAL);
19266
19182
  return { SettingsRelationships: {
19267
19183
  data: XML_DECL + rels.serialize(),
19268
19184
  path: "word/_rels/settings.xml.rels"
@@ -19279,68 +19195,8 @@ function xmlifyContext(ctx) {
19279
19195
  data: XML_DECL + (bibliographyDesc.stringify(ctx._options.bibliography, ctx) ?? ""),
19280
19196
  path: "word/bibliography.xml"
19281
19197
  } } : {},
19282
- ...ctx.charts.array.length > 0 ? {
19283
- Charts: ctx.charts.array.flatMap((chartData, i) => {
19284
- const parts = [{
19285
- data: XML_DECL + chartData.chartSpaceXml,
19286
- path: `word/charts/chart${i + 1}.xml`
19287
- }];
19288
- if (chartData.userShapes) parts.push({
19289
- data: XML_DECL + chartData.userShapes.xml,
19290
- path: `word/charts/userShapes${i + 1}.xml`
19291
- });
19292
- const e = chartData.embedding;
19293
- const rels = [...e ? [`<Relationship Id="${escapeXml(e.relationshipId)}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/package" Target="../embeddings/${escapeXml(e.fileName)}"/>`] : [], ...chartData.userShapes ? [`<Relationship Id="${escapeXml(chartData.userShapes.relationshipId)}" Type="${CHART_USER_SHAPES_REL}" Target="userShapes${i + 1}.xml"/>`] : []];
19294
- if (rels.length > 0) parts.push({
19295
- data: XML_DECL + `<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${rels.join("")}</Relationships>`,
19296
- path: `word/charts/_rels/chart${i + 1}.xml.rels`
19297
- });
19298
- return parts;
19299
- }),
19300
- ChartEmbeddings: (() => {
19301
- const seen = /* @__PURE__ */ new Set();
19302
- const parts = [];
19303
- for (const c of ctx.charts.array) {
19304
- const e = c.embedding;
19305
- if (!e || seen.has(e.fileName)) continue;
19306
- seen.add(e.fileName);
19307
- parts.push({
19308
- data: toUint8Array(e.data),
19309
- path: `word/embeddings/${e.fileName}`
19310
- });
19311
- }
19312
- return parts;
19313
- })()
19314
- } : {},
19315
- ...ctx.smartArts.array.length > 0 ? {
19316
- DiagramData: ctx.smartArts.array.map((smartArtData, i) => ({
19317
- data: smartArtData.raw?.data !== void 0 ? toUint8Array(smartArtData.raw.data) : XML_DECL + smartArtData.dataModelXml,
19318
- path: `word/diagrams/data${i + 1}.xml`
19319
- })),
19320
- DiagramLayout: ctx.smartArts.array.map((smartArtData, i) => ({
19321
- data: smartArtData.raw?.layout !== void 0 ? toUint8Array(smartArtData.raw.layout) : typeof smartArtData.layout === "string" ? getLayoutXml(smartArtData.layout) : stringifyLayoutDefinitionPart(smartArtData.layout),
19322
- path: `word/diagrams/layout${i + 1}.xml`
19323
- })),
19324
- DiagramStyle: ctx.smartArts.array.map((smartArtData, i) => ({
19325
- data: smartArtData.raw?.style !== void 0 ? toUint8Array(smartArtData.raw.style) : typeof smartArtData.style === "string" ? getStyleXml(smartArtData.style) : stringifyStyleDefinitionPart(smartArtData.style),
19326
- path: `word/diagrams/quickStyle${i + 1}.xml`
19327
- })),
19328
- DiagramColors: ctx.smartArts.array.map((smartArtData, i) => ({
19329
- data: smartArtData.raw?.color !== void 0 ? toUint8Array(smartArtData.raw.color) : typeof smartArtData.color === "string" ? getColorXml(smartArtData.color) : stringifyColorDefinitionPart(smartArtData.color),
19330
- path: `word/diagrams/colors${i + 1}.xml`
19331
- })),
19332
- DiagramDrawing: ctx.smartArts.array.map((smartArtData, i) => ({
19333
- smartArtData,
19334
- i
19335
- })).filter(({ smartArtData }) => smartArtData.raw?.drawing !== void 0).map(({ smartArtData, i }) => ({
19336
- data: toUint8Array(smartArtData.raw.drawing),
19337
- path: `word/diagrams/drawing${i + 1}.xml`
19338
- })),
19339
- ...ctx.smartArts.array.some((s) => s.raw?.dataRels !== void 0) ? { SmartArtDataRels: ctx.smartArts.array.flatMap((smartArtData, i) => smartArtData.raw?.dataRels !== void 0 ? [{
19340
- data: toUint8Array(smartArtData.raw.dataRels),
19341
- path: `word/diagrams/_rels/data${i + 1}.xml.rels`
19342
- }] : []) } : {}
19343
- } : {},
19198
+ ...compileChartParts(ctx),
19199
+ ...compileSmartArtParts(ctx),
19344
19200
  ...ctx.altChunks.array.length > 0 ? { AltChunks: ctx.altChunks.array.map((altChunkData) => ({
19345
19201
  data: altChunkData.data,
19346
19202
  path: `word/${altChunkData.path}`
@@ -19431,6 +19287,6 @@ function generateDocumentStream(options, packerOptions) {
19431
19287
  return Packer.toStream(options, packerOptions);
19432
19288
  }
19433
19289
  //#endregion
19434
- export { AlignmentType, AltChunkCollection, BorderStyle, BreakType, COMMENTS_NS, CharacterSet, DefaultStylesFactory, DocPartBehavior, DocPartGallery, DocPartType, DocumentAttributeNamespaces, DocumentGridType, DocxReadContext, DocxWriteContext, DropCapType, EMPTY_RUN_ELEMENTS, EditGroupType, EmphasisMarkType, FormFieldTextType, FrameAnchorType, FrameWrap, HIGHLIGHT_PALETTE_RGB, HeadingLevel, HeightRule, HighlightColor, HorizontalPositionAlign, HorizontalPositionRelativeFrom, HyperlinkType, LeaderType, LevelFormat, LevelSuffix, LineNumberRestartFormat, LineRuleType, Media, NumberFormat, Numbering, OverlapType, PageBorderDisplay, PageBorderOffsetFrom, PageBorderZOrder, PageNumber, PageNumberSeparator, PageOrientation, PageTextDirectionType, PositionalTabAlignment, PositionalTabLeader, PositionalTabRelativeTo, ProofErrorType, RelativeHorizontalPosition, RelativeVerticalPosition, RubyAlign, SdtDateMappingType, SdtLock, SectionType, ShadingType, SpaceType, StyleLevel, Styles, SubDocCollection, TABLE_BORDERS_NONE, TabStopPosition, TabStopType, TableAnchorType, TableLayoutType, TargetScreenSize, TextAlignmentType, TextDirection, TextEffect, TextWrappingSide, TextWrappingType, TextboxTightWrapType, UnderlineType, VerticalAlignSection, VerticalAlignTable, VerticalMergeRevisionType, VerticalMergeType, VerticalPositionAlign, VerticalPositionRelativeFrom, WidthType, altChunkDesc, appPropertiesDesc, bibliographyDesc, bodyPropertiesDesc, breakXml, buildBookmarkStartAttrs, buildMarkupRangeAttrs, buildNumIdCache, buildNumberingCache, buildStyleCache, checkboxSymbolRunInner, commentsDesc, commentsExtendedDesc, compileDocument, corePropertiesDesc, createBodyProperties, createDocumentGrid, createFormFieldData, createHorizontalPosition, createLineNumberType, createPageMargin, createPageNumberType, createPictureData, createSectionType, createTransformation, createVerticalPosition, createWrapThrough, createWrapTight, customPropertiesDesc, customXmlBlockDesc, documentNamespaceAttributes, documentNamespaceRecord, drawingDesc, endnotesDesc, extractStyleId, fontTableDesc, footnotesDesc, frameXml, framesetXml, generateDocument, generateDocumentStream, generateDocumentSync, glossaryDesc, keepTocClosingParagraph, objectDesc, parseArchive, parseBodyProperties, parseBorderSide, parseCustomXmlProperties, parseDocument, parseDocumentSync, parseDocx, parseFormFieldData, parseNumberingDefinitions, parsePict, parseRegisteredBodyChild, parseSdtBlock, parseSdtProperties, parseSectionPropertiesEl, parseShading, parseStyleDefinitions, parseTableCellPropertiesEl, parseTablePropertiesEl, parseTableRowPropertiesEl, parseToc, parseTocFieldFromElements, parseTocFieldInstruction, patchDetector, patchDocument, peopleDesc, resetDrawingIdGen, sdtBlockDesc, sectionMarginDefaults, sectionPageSizeDefaults, sectionPropertiesDesc, selectTocEntryElements, setBodyParseChild, setTableParseChild, settingsDesc, stringifyCharacterStyle, stringifyChildDispatch, stringifyConditionalTableStyle, stringifyCustomXmlShell, stringifyDocDefaults, stringifyNumberingStyle, stringifyParagraphInline, stringifyParagraphStyle, stringifyPict, stringifyRunInline, stringifySdtPr, stringifySdtShell, stringifySectionProperties, stringifyTableOfContents, stringifyTableStyle, subDocDesc, tableDesc, webSettingsDesc, widthFiftiethsToPct, widthPctToFiftieths };
19290
+ export { AlignmentType, AltChunkCollection, BorderStyle, BreakType, COMMENTS_NS, CharacterSet, DefaultStylesFactory, DocPartBehavior, DocPartGallery, DocPartType, DocumentAttributeNamespaces, DocumentGridType, DocxReadContext, DocxWriteContext, DropCapType, EMPTY_RUN_ELEMENTS, EditGroupType, EmphasisMarkType, FormFieldTextType, FrameAnchorType, FrameWrap, HIGHLIGHT_PALETTE_RGB, HeadingLevel, HeightRule, HighlightColor, HorizontalPositionAlign, HorizontalPositionRelativeFrom, HyperlinkType, LeaderType, LevelFormat, LevelSuffix, LineNumberRestartFormat, LineRuleType, Media, NumberFormat, Numbering, OverlapType, PageBorderDisplay, PageBorderOffsetFrom, PageBorderZOrder, PageNumber, PageNumberSeparator, PageOrientation, PageTextDirectionType, PositionalTabAlignment, PositionalTabLeader, PositionalTabRelativeTo, ProofErrorType, RelativeHorizontalPosition, RelativeVerticalPosition, RubyAlign, SdtDateMappingType, SdtLock, SectionType, ShadingType, StyleLevel, Styles, SubDocCollection, TABLE_BORDERS_NONE, TabStopPosition, TabStopType, TableAnchorType, TableLayoutType, TargetScreenSize, TextAlignmentType, TextDirection, TextEffect, TextWrappingSide, TextWrappingType, TextboxTightWrapType, UnderlineType, VerticalAlignSection, VerticalAlignTable, VerticalMergeRevisionType, VerticalMergeType, VerticalPositionAlign, VerticalPositionRelativeFrom, WidthType, altChunkDesc, appPropertiesDesc, bibliographyDesc, bodyPropertiesDesc, breakXml, buildBookmarkStartAttrs, buildMarkupRangeAttrs, buildNumIdCache, buildNumberingCache, buildStyleCache, checkboxSymbolRunInner, commentsDesc, commentsExtendedDesc, compileDocument, corePropertiesDesc, createBodyProperties, createDocumentGrid, createFormFieldData, createHorizontalPosition, createLineNumberType, createPageMargin, createPageNumberType, createPictureData, createSectionType, createTransformation, createVerticalPosition, customPropertiesDesc, customXmlBlockDesc, documentNamespaceAttributes, documentNamespaceRecord, drawingDesc, endnotesDesc, extractStyleId, fontTableDesc, footnotesDesc, frameXml, framesetXml, generateDocument, generateDocumentStream, generateDocumentSync, glossaryDesc, keepTocClosingParagraph, objectDesc, parseArchive, parseBodyProperties, parseBorderSide, parseCustomXmlProperties, parseDocument, parseDocumentSync, parseDocx, parseFormFieldData, parseNumberingDefinitions, parsePict, parseRegisteredBodyChild, parseSdtBlock, parseSdtProperties, parseSectionPropertiesEl, parseShading, parseStyleDefinitions, parseTableCellPropertiesEl, parseTablePropertiesEl, parseTableRowPropertiesEl, parseToc, parseTocFieldFromElements, parseTocFieldInstruction, patchDetector, patchDocument, peopleDesc, resetDrawingIdGen, sdtBlockDesc, sectionMarginDefaults, sectionPageSizeDefaults, sectionPropertiesDesc, selectTocEntryElements, setBodyParseChild, setTableParseChild, settingsDesc, stringifyCharacterStyle, stringifyChildDispatch, stringifyConditionalTableStyle, stringifyCustomXmlShell, stringifyDocDefaults, stringifyNumberingStyle, stringifyParagraphInline, stringifyParagraphStyle, stringifyPict, stringifyRunInline, stringifySdtPr, stringifySdtShell, stringifySectionProperties, stringifyTableOfContents, stringifyTableStyle, subDocDesc, tableDesc, webSettingsDesc, widthFiftiethsToPct, widthPctToFiftieths };
19435
19291
 
19436
19292
  //# sourceMappingURL=index.mjs.map