@cj-tech-master/excelts 9.6.1 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/README.md +18 -3
  2. package/README_zh.md +18 -3
  3. package/dist/browser/modules/excel/cell.d.ts +4 -0
  4. package/dist/browser/modules/excel/note.js +5 -1
  5. package/dist/browser/modules/excel/row.js +35 -2
  6. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +8 -1
  7. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +22 -2
  8. package/dist/browser/modules/excel/types.d.ts +81 -0
  9. package/dist/browser/modules/excel/utils/drawing-utils.d.ts +8 -0
  10. package/dist/browser/modules/excel/utils/drawing-utils.js +19 -2
  11. package/dist/browser/modules/excel/workbook.browser.d.ts +16 -0
  12. package/dist/browser/modules/excel/workbook.browser.js +32 -2
  13. package/dist/browser/modules/excel/worksheet.d.ts +31 -1
  14. package/dist/browser/modules/excel/worksheet.js +83 -0
  15. package/dist/browser/modules/excel/xlsx/xform/comment/vml-shape-xform.d.ts +7 -0
  16. package/dist/browser/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
  17. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
  18. package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
  19. package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
  20. package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +6 -0
  21. package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
  22. package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -0
  23. package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
  24. package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +2 -0
  25. package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
  26. package/dist/browser/modules/excel/xlsx/xform/drawing/shape-xform.d.ts +47 -0
  27. package/dist/browser/modules/excel/xlsx/xform/drawing/shape-xform.js +109 -0
  28. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
  29. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
  30. package/dist/browser/modules/pdf/builder/document-builder.js +22 -49
  31. package/dist/browser/modules/pdf/builder/pdf-editor.js +1 -1
  32. package/dist/browser/modules/pdf/core/pdf-stream.d.ts +28 -1
  33. package/dist/browser/modules/pdf/core/pdf-stream.js +38 -2
  34. package/dist/browser/modules/pdf/font/font-manager.d.ts +26 -0
  35. package/dist/browser/modules/pdf/font/font-manager.js +35 -18
  36. package/dist/browser/modules/pdf/render/page-renderer.d.ts +51 -3
  37. package/dist/browser/modules/pdf/render/page-renderer.js +111 -18
  38. package/dist/browser/modules/word/advanced/field-engine.js +45 -20
  39. package/dist/browser/modules/word/advanced/glossary.d.ts +10 -36
  40. package/dist/browser/modules/word/advanced/glossary.js +8 -9
  41. package/dist/browser/modules/word/advanced/math-convert.js +94 -12
  42. package/dist/browser/modules/word/advanced/ole-objects.d.ts +28 -0
  43. package/dist/browser/modules/word/advanced/ole-objects.js +122 -19
  44. package/dist/browser/modules/word/advanced/style-map.js +31 -10
  45. package/dist/browser/modules/word/builder/run-builders.d.ts +7 -1
  46. package/dist/browser/modules/word/builder/run-builders.js +7 -1
  47. package/dist/browser/modules/word/constants.d.ts +4 -0
  48. package/dist/browser/modules/word/constants.js +5 -1
  49. package/dist/browser/modules/word/convert/docx-to-semantic.d.ts +2 -1
  50. package/dist/browser/modules/word/convert/docx-to-semantic.js +135 -1
  51. package/dist/browser/modules/word/convert/html/html-import.d.ts +32 -1
  52. package/dist/browser/modules/word/convert/html/html-import.js +167 -14
  53. package/dist/browser/modules/word/convert/html/html.d.ts +2 -2
  54. package/dist/browser/modules/word/convert/html/html.js +1 -1
  55. package/dist/browser/modules/word/convert/markdown/markdown-import.d.ts +48 -18
  56. package/dist/browser/modules/word/convert/markdown/markdown-import.js +279 -69
  57. package/dist/browser/modules/word/convert/markdown/markdown.d.ts +1 -1
  58. package/dist/browser/modules/word/convert/odt/odt.js +407 -56
  59. package/dist/browser/modules/word/html.d.ts +2 -2
  60. package/dist/browser/modules/word/html.js +1 -1
  61. package/dist/browser/modules/word/index.base.d.ts +3 -3
  62. package/dist/browser/modules/word/index.base.js +1 -1
  63. package/dist/browser/modules/word/layout/layout-full.js +326 -19
  64. package/dist/browser/modules/word/layout/render-page.js +35 -8
  65. package/dist/browser/modules/word/markdown.d.ts +1 -1
  66. package/dist/browser/modules/word/query/compat.d.ts +10 -2
  67. package/dist/browser/modules/word/query/compat.js +29 -21
  68. package/dist/browser/modules/word/reader/docx-reader.js +105 -2
  69. package/dist/browser/modules/word/reader/math-parser.js +8 -2
  70. package/dist/browser/modules/word/security/cfb-reader.js +5 -5
  71. package/dist/browser/modules/word/types.d.ts +96 -1
  72. package/dist/browser/modules/word/writer/docx-packager.js +108 -2
  73. package/dist/browser/modules/word/writer/glossary-writer.d.ts +28 -0
  74. package/dist/browser/modules/word/writer/glossary-writer.js +121 -0
  75. package/dist/browser/modules/word/writer/header-footer-writer.js +105 -20
  76. package/dist/browser/modules/word/writer/math-writer.js +7 -2
  77. package/dist/browser/utils/font-metrics.d.ts +8 -0
  78. package/dist/browser/utils/font-metrics.js +43 -0
  79. package/dist/browser/utils/theme-colors.js +4 -1
  80. package/dist/cjs/modules/excel/note.js +5 -1
  81. package/dist/cjs/modules/excel/row.js +35 -2
  82. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +22 -2
  83. package/dist/cjs/modules/excel/utils/drawing-utils.js +19 -2
  84. package/dist/cjs/modules/excel/workbook.browser.js +31 -1
  85. package/dist/cjs/modules/excel/worksheet.js +83 -0
  86. package/dist/cjs/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
  87. package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
  88. package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
  89. package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
  90. package/dist/cjs/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
  91. package/dist/cjs/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
  92. package/dist/cjs/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
  93. package/dist/cjs/modules/excel/xlsx/xform/drawing/shape-xform.js +112 -0
  94. package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
  95. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
  96. package/dist/cjs/modules/pdf/builder/document-builder.js +21 -48
  97. package/dist/cjs/modules/pdf/builder/pdf-editor.js +1 -1
  98. package/dist/cjs/modules/pdf/core/pdf-stream.js +38 -2
  99. package/dist/cjs/modules/pdf/font/font-manager.js +35 -18
  100. package/dist/cjs/modules/pdf/render/page-renderer.js +112 -18
  101. package/dist/cjs/modules/word/advanced/field-engine.js +45 -20
  102. package/dist/cjs/modules/word/advanced/glossary.js +8 -9
  103. package/dist/cjs/modules/word/advanced/math-convert.js +94 -12
  104. package/dist/cjs/modules/word/advanced/ole-objects.js +123 -19
  105. package/dist/cjs/modules/word/advanced/style-map.js +31 -10
  106. package/dist/cjs/modules/word/builder/run-builders.js +7 -1
  107. package/dist/cjs/modules/word/constants.js +5 -1
  108. package/dist/cjs/modules/word/convert/docx-to-semantic.js +135 -1
  109. package/dist/cjs/modules/word/convert/html/html-import.js +168 -14
  110. package/dist/cjs/modules/word/convert/html/html.js +2 -1
  111. package/dist/cjs/modules/word/convert/markdown/markdown-import.js +279 -69
  112. package/dist/cjs/modules/word/convert/odt/odt.js +407 -56
  113. package/dist/cjs/modules/word/html.js +2 -1
  114. package/dist/cjs/modules/word/index.base.js +4 -3
  115. package/dist/cjs/modules/word/layout/layout-full.js +325 -18
  116. package/dist/cjs/modules/word/layout/render-page.js +35 -8
  117. package/dist/cjs/modules/word/query/compat.js +29 -21
  118. package/dist/cjs/modules/word/reader/docx-reader.js +104 -1
  119. package/dist/cjs/modules/word/reader/math-parser.js +8 -2
  120. package/dist/cjs/modules/word/security/cfb-reader.js +5 -5
  121. package/dist/cjs/modules/word/writer/docx-packager.js +108 -2
  122. package/dist/cjs/modules/word/writer/glossary-writer.js +124 -0
  123. package/dist/cjs/modules/word/writer/header-footer-writer.js +105 -20
  124. package/dist/cjs/modules/word/writer/math-writer.js +7 -2
  125. package/dist/cjs/utils/font-metrics.js +44 -0
  126. package/dist/cjs/utils/theme-colors.js +4 -1
  127. package/dist/esm/modules/excel/note.js +5 -1
  128. package/dist/esm/modules/excel/row.js +35 -2
  129. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +22 -2
  130. package/dist/esm/modules/excel/utils/drawing-utils.js +19 -2
  131. package/dist/esm/modules/excel/workbook.browser.js +32 -2
  132. package/dist/esm/modules/excel/worksheet.js +83 -0
  133. package/dist/esm/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
  134. package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
  135. package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
  136. package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
  137. package/dist/esm/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
  138. package/dist/esm/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
  139. package/dist/esm/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
  140. package/dist/esm/modules/excel/xlsx/xform/drawing/shape-xform.js +109 -0
  141. package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
  142. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
  143. package/dist/esm/modules/pdf/builder/document-builder.js +22 -49
  144. package/dist/esm/modules/pdf/builder/pdf-editor.js +1 -1
  145. package/dist/esm/modules/pdf/core/pdf-stream.js +38 -2
  146. package/dist/esm/modules/pdf/font/font-manager.js +35 -18
  147. package/dist/esm/modules/pdf/render/page-renderer.js +111 -18
  148. package/dist/esm/modules/word/advanced/field-engine.js +45 -20
  149. package/dist/esm/modules/word/advanced/glossary.js +8 -9
  150. package/dist/esm/modules/word/advanced/math-convert.js +94 -12
  151. package/dist/esm/modules/word/advanced/ole-objects.js +122 -19
  152. package/dist/esm/modules/word/advanced/style-map.js +31 -10
  153. package/dist/esm/modules/word/builder/run-builders.js +7 -1
  154. package/dist/esm/modules/word/constants.js +5 -1
  155. package/dist/esm/modules/word/convert/docx-to-semantic.js +135 -1
  156. package/dist/esm/modules/word/convert/html/html-import.js +167 -14
  157. package/dist/esm/modules/word/convert/html/html.js +1 -1
  158. package/dist/esm/modules/word/convert/markdown/markdown-import.js +279 -69
  159. package/dist/esm/modules/word/convert/odt/odt.js +407 -56
  160. package/dist/esm/modules/word/html.js +1 -1
  161. package/dist/esm/modules/word/index.base.js +1 -1
  162. package/dist/esm/modules/word/layout/layout-full.js +326 -19
  163. package/dist/esm/modules/word/layout/render-page.js +35 -8
  164. package/dist/esm/modules/word/query/compat.js +29 -21
  165. package/dist/esm/modules/word/reader/docx-reader.js +105 -2
  166. package/dist/esm/modules/word/reader/math-parser.js +8 -2
  167. package/dist/esm/modules/word/security/cfb-reader.js +5 -5
  168. package/dist/esm/modules/word/writer/docx-packager.js +108 -2
  169. package/dist/esm/modules/word/writer/glossary-writer.js +121 -0
  170. package/dist/esm/modules/word/writer/header-footer-writer.js +105 -20
  171. package/dist/esm/modules/word/writer/math-writer.js +7 -2
  172. package/dist/esm/utils/font-metrics.js +43 -0
  173. package/dist/esm/utils/theme-colors.js +4 -1
  174. package/dist/iife/excelts.iife.js +496 -59
  175. package/dist/iife/excelts.iife.js.map +1 -1
  176. package/dist/iife/excelts.iife.min.js +39 -39
  177. package/dist/types/modules/excel/cell.d.ts +4 -0
  178. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +8 -1
  179. package/dist/types/modules/excel/types.d.ts +81 -0
  180. package/dist/types/modules/excel/utils/drawing-utils.d.ts +8 -0
  181. package/dist/types/modules/excel/workbook.browser.d.ts +16 -0
  182. package/dist/types/modules/excel/worksheet.d.ts +31 -1
  183. package/dist/types/modules/excel/xlsx/xform/comment/vml-shape-xform.d.ts +7 -0
  184. package/dist/types/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +6 -0
  185. package/dist/types/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -0
  186. package/dist/types/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +2 -0
  187. package/dist/types/modules/excel/xlsx/xform/drawing/shape-xform.d.ts +47 -0
  188. package/dist/types/modules/pdf/core/pdf-stream.d.ts +28 -1
  189. package/dist/types/modules/pdf/font/font-manager.d.ts +26 -0
  190. package/dist/types/modules/pdf/render/page-renderer.d.ts +51 -3
  191. package/dist/types/modules/word/advanced/glossary.d.ts +10 -36
  192. package/dist/types/modules/word/advanced/ole-objects.d.ts +28 -0
  193. package/dist/types/modules/word/builder/run-builders.d.ts +7 -1
  194. package/dist/types/modules/word/constants.d.ts +4 -0
  195. package/dist/types/modules/word/convert/docx-to-semantic.d.ts +2 -1
  196. package/dist/types/modules/word/convert/html/html-import.d.ts +32 -1
  197. package/dist/types/modules/word/convert/html/html.d.ts +2 -2
  198. package/dist/types/modules/word/convert/markdown/markdown-import.d.ts +48 -18
  199. package/dist/types/modules/word/convert/markdown/markdown.d.ts +1 -1
  200. package/dist/types/modules/word/html.d.ts +2 -2
  201. package/dist/types/modules/word/index.base.d.ts +3 -3
  202. package/dist/types/modules/word/markdown.d.ts +1 -1
  203. package/dist/types/modules/word/query/compat.d.ts +10 -2
  204. package/dist/types/modules/word/types.d.ts +96 -1
  205. package/dist/types/modules/word/writer/glossary-writer.d.ts +28 -0
  206. package/dist/types/utils/font-metrics.d.ts +8 -0
  207. package/package.json +3 -1
@@ -144,7 +144,7 @@ export class PdfEditorPage {
144
144
  }
145
145
  /** @internal */
146
146
  _hasOverlay() {
147
- return (this._overlay._stream.toString().length > 0 ||
147
+ return (this._overlay._stream.hasContent() ||
148
148
  this._overlay._images.length > 0 ||
149
149
  this._overlay._builderAnnotations.length > 0 ||
150
150
  this._overlay._formFields.length > 0);
@@ -19,12 +19,30 @@ import type { PdfColor } from "../types.js";
19
19
  * and non-stroking (fills/text). We provide methods for both.
20
20
  */
21
21
  export declare class PdfContentStream {
22
+ /**
23
+ * Content stream fragments in draw order. Most entries are plain operator
24
+ * strings produced eagerly. A function entry is a *deferred* fragment:
25
+ * its body is only evaluated at serialization time. This is required for
26
+ * text whose final byte encoding depends on font decisions (embedded
27
+ * CIDFont vs. Type1/WinAnsi vs. Type3 fallback) that are not finalised
28
+ * until `PdfDocumentBuilder.build()`. Deferring keeps the fragment at its
29
+ * exact draw-order position (preserving z-order) while letting the actual
30
+ * encoding run after the font manager's state is settled.
31
+ */
22
32
  private parts;
23
33
  /**
24
34
  * Append a raw PDF operator string to the content stream.
25
35
  * Use this for operators not covered by the typed API (e.g. `d1` for Type3 glyphs).
26
36
  */
27
37
  raw(operator: string): this;
38
+ /**
39
+ * Append a deferred fragment whose body is evaluated only at serialization
40
+ * time. Used by text drawing so the final byte encoding can be chosen after
41
+ * the document's fonts are resolved at build time. The fragment occupies its
42
+ * draw-order slot immediately, so z-order relative to other operators is
43
+ * preserved.
44
+ */
45
+ deferred(produce: () => string): this;
28
46
  /**
29
47
  * Save the current graphics state (push onto state stack).
30
48
  * Must be balanced with a corresponding restore().
@@ -222,7 +240,16 @@ export declare class PdfContentStream {
222
240
  */
223
241
  roundedRect(x: number, y: number, width: number, height: number, r: number): this;
224
242
  /**
225
- * Get the content stream as a string.
243
+ * Whether any fragment has been appended. Unlike `toString().length > 0`,
244
+ * this does NOT evaluate deferred fragments, so it is safe to call before
245
+ * fonts are resolved (e.g. when probing for overlay content during an
246
+ * editor save, prior to `writeFontResources`). A deferred text fragment
247
+ * counts as content even though its bytes are not produced yet.
248
+ */
249
+ hasContent(): boolean;
250
+ /**
251
+ * Get the content stream as a string. Deferred fragments (see `deferred`)
252
+ * are evaluated here, after font resolution has completed at build time.
226
253
  */
227
254
  toString(): string;
228
255
  /**
@@ -23,6 +23,16 @@ import { pdfNumber } from "./pdf-object.js";
23
23
  */
24
24
  export class PdfContentStream {
25
25
  constructor() {
26
+ /**
27
+ * Content stream fragments in draw order. Most entries are plain operator
28
+ * strings produced eagerly. A function entry is a *deferred* fragment:
29
+ * its body is only evaluated at serialization time. This is required for
30
+ * text whose final byte encoding depends on font decisions (embedded
31
+ * CIDFont vs. Type1/WinAnsi vs. Type3 fallback) that are not finalised
32
+ * until `PdfDocumentBuilder.build()`. Deferring keeps the fragment at its
33
+ * exact draw-order position (preserving z-order) while letting the actual
34
+ * encoding run after the font manager's state is settled.
35
+ */
26
36
  this.parts = [];
27
37
  }
28
38
  // ===========================================================================
@@ -36,6 +46,17 @@ export class PdfContentStream {
36
46
  this.parts.push(operator);
37
47
  return this;
38
48
  }
49
+ /**
50
+ * Append a deferred fragment whose body is evaluated only at serialization
51
+ * time. Used by text drawing so the final byte encoding can be chosen after
52
+ * the document's fonts are resolved at build time. The fragment occupies its
53
+ * draw-order slot immediately, so z-order relative to other operators is
54
+ * preserved.
55
+ */
56
+ deferred(produce) {
57
+ this.parts.push(produce);
58
+ return this;
59
+ }
39
60
  // ===========================================================================
40
61
  // Graphics State
41
62
  // ===========================================================================
@@ -435,10 +456,25 @@ export class PdfContentStream {
435
456
  // Serialization
436
457
  // ===========================================================================
437
458
  /**
438
- * Get the content stream as a string.
459
+ * Whether any fragment has been appended. Unlike `toString().length > 0`,
460
+ * this does NOT evaluate deferred fragments, so it is safe to call before
461
+ * fonts are resolved (e.g. when probing for overlay content during an
462
+ * editor save, prior to `writeFontResources`). A deferred text fragment
463
+ * counts as content even though its bytes are not produced yet.
464
+ */
465
+ hasContent() {
466
+ return this.parts.length > 0;
467
+ }
468
+ /**
469
+ * Get the content stream as a string. Deferred fragments (see `deferred`)
470
+ * are evaluated here, after font resolution has completed at build time.
439
471
  */
440
472
  toString() {
441
- return this.parts.join("\n");
473
+ const out = [];
474
+ for (const part of this.parts) {
475
+ out.push(typeof part === "function" ? part() : part);
476
+ }
477
+ return out.join("\n");
442
478
  }
443
479
  /**
444
480
  * Get the content stream as a Uint8Array (UTF-8 encoded).
@@ -76,9 +76,35 @@ export declare class FontManager {
76
76
  * Get the embedded font's resource name (if registered).
77
77
  */
78
78
  getEmbeddedResourceName(): string;
79
+ /**
80
+ * Resolve the resource name a draw-time-resolved Type1 resource should
81
+ * actually render (and be measured) with, given the font manager's
82
+ * *current* state. If an embedded font exists (possibly auto-discovered
83
+ * at build time, after the text was drawn against a Type1 resource), the
84
+ * embedded resource name is returned so both measurement and encoding go
85
+ * through the CIDFont. Otherwise the original Type1 resource name is kept;
86
+ * `measureText` handles Type3-fallback widths internally from that name.
87
+ *
88
+ * Centralises the routing rule shared by the deferred text renderer and
89
+ * any deferred measurement (anchor alignment, word wrapping) so the two
90
+ * never disagree.
91
+ */
92
+ resolveRenderResourceName(type1ResourceName: string): string;
79
93
  /**
80
94
  * Record that a text string will be rendered, tracking its code points.
81
95
  * Must be called for every text string before writing the PDF.
96
+ *
97
+ * Two sets are maintained because font selection may be decided *after*
98
+ * drawing (e.g. `PdfDocumentBuilder.build()` auto-discovers and embeds a
99
+ * system font once it sees the accumulated non-WinAnsi code points):
100
+ *
101
+ * - `usedCodePoints` — every code point seen, always. If an embedded
102
+ * font ends up being used (whether registered up front or
103
+ * auto-discovered at build time), the subset must cover all of these,
104
+ * including plain ASCII, so the CIDFont can encode the full run.
105
+ * - `type3CodePoints` — non-WinAnsi code points only. Drives the
106
+ * build-time decision to auto-embed a system font, and the Type3
107
+ * fallback when none is available.
82
108
  */
83
109
  trackText(text: string): void;
84
110
  /**
@@ -182,30 +182,47 @@ export class FontManager {
182
182
  getEmbeddedResourceName() {
183
183
  return this.embeddedResourceName;
184
184
  }
185
+ /**
186
+ * Resolve the resource name a draw-time-resolved Type1 resource should
187
+ * actually render (and be measured) with, given the font manager's
188
+ * *current* state. If an embedded font exists (possibly auto-discovered
189
+ * at build time, after the text was drawn against a Type1 resource), the
190
+ * embedded resource name is returned so both measurement and encoding go
191
+ * through the CIDFont. Otherwise the original Type1 resource name is kept;
192
+ * `measureText` handles Type3-fallback widths internally from that name.
193
+ *
194
+ * Centralises the routing rule shared by the deferred text renderer and
195
+ * any deferred measurement (anchor alignment, word wrapping) so the two
196
+ * never disagree.
197
+ */
198
+ resolveRenderResourceName(type1ResourceName) {
199
+ return this.embeddedFont ? this.embeddedResourceName : type1ResourceName;
200
+ }
185
201
  /**
186
202
  * Record that a text string will be rendered, tracking its code points.
187
203
  * Must be called for every text string before writing the PDF.
204
+ *
205
+ * Two sets are maintained because font selection may be decided *after*
206
+ * drawing (e.g. `PdfDocumentBuilder.build()` auto-discovers and embeds a
207
+ * system font once it sees the accumulated non-WinAnsi code points):
208
+ *
209
+ * - `usedCodePoints` — every code point seen, always. If an embedded
210
+ * font ends up being used (whether registered up front or
211
+ * auto-discovered at build time), the subset must cover all of these,
212
+ * including plain ASCII, so the CIDFont can encode the full run.
213
+ * - `type3CodePoints` — non-WinAnsi code points only. Drives the
214
+ * build-time decision to auto-embed a system font, and the Type3
215
+ * fallback when none is available.
188
216
  */
189
217
  trackText(text) {
190
- if (this.embeddedFont) {
191
- for (let i = 0; i < text.length; i++) {
192
- const cp = text.codePointAt(i);
193
- this.usedCodePoints.add(cp);
194
- if (cp > 0xffff) {
195
- i++; // skip low surrogate
196
- }
218
+ for (let i = 0; i < text.length; i++) {
219
+ const cp = text.codePointAt(i);
220
+ if (cp > 0xffff) {
221
+ i++; // skip low surrogate
197
222
  }
198
- }
199
- else {
200
- // No embedded font — track non-WinAnsi chars for Type3 fallback
201
- for (let i = 0; i < text.length; i++) {
202
- const cp = text.codePointAt(i);
203
- if (cp > 0xffff) {
204
- i++;
205
- }
206
- if (!isWinAnsiCodePoint(cp)) {
207
- this.type3CodePoints.add(cp);
208
- }
223
+ this.usedCodePoints.add(cp);
224
+ if (!isWinAnsiCodePoint(cp)) {
225
+ this.type3CodePoints.add(cp);
209
226
  }
210
227
  }
211
228
  }
@@ -29,10 +29,58 @@ export declare function renderPage(page: LayoutPage, options: ResolvedPdfOptions
29
29
  * when needed. For each sub-run the matrix origin is advanced along the
30
30
  * text direction (cos, sin) by the rendered width.
31
31
  *
32
- * When `useType3` is false this collapses to a single BT/ET pair — identical
33
- * to the old `emitText()` path but wrapped in begin/end for convenience.
32
+ * The emitted operators are written as a *deferred* fragment (see
33
+ * `PdfContentStream.deferred`). The fragment is only evaluated at
34
+ * serialization time, by which point `PdfDocumentBuilder.build()` has
35
+ * finalised the document's fonts (auto-discovered embedded CIDFont,
36
+ * Type3 fallback, or plain Type1). This is essential: at draw time the
37
+ * font manager has not yet decided whether a non-WinAnsi code point (e.g.
38
+ * U+2192 →) will be served by an embedded font or a Type3 glyph, so eager
39
+ * encoding would irreversibly degrade those characters to spaces via the
40
+ * WinAnsi fallback. Deferring the encode keeps the fragment at its exact
41
+ * draw-order slot (preserving z-order) while choosing the correct bytes
42
+ * once fonts are known.
43
+ *
44
+ * The `useType3` argument is the caller's *draw-time* guess and is ignored;
45
+ * the deferred body recomputes the routing from the now-settled font
46
+ * manager state.
47
+ */
48
+ export declare function emitTextWithMatrix(stream: PdfContentStream, text: string, a: number, b: number, c: number, d: number, tx: number, ty: number, type1ResourceName: string, fontSize: number, fontManager: FontManager, _useType3: boolean): void;
49
+ /** Options for a deferred, font-aware text block (see `emitTextBlock`). */
50
+ export interface TextBlockOptions {
51
+ /** The text to draw (may contain `\n` when `maxWidth` is set). */
52
+ text: string;
53
+ /** Left/anchor x in unrotated page space. */
54
+ x: number;
55
+ /** Baseline y of the first line in unrotated page space. */
56
+ y: number;
57
+ /** Draw-time-resolved Type1 resource name; re-routed at build time. */
58
+ type1ResourceName: string;
59
+ fontSize: number;
60
+ /** Horizontal anchor; applied per line (including each wrapped line). */
61
+ anchor: "start" | "middle" | "end";
62
+ /** Word-wrap width in points; enables multi-line layout when set. */
63
+ maxWidth?: number;
64
+ /** Line-height multiple applied to `fontSize` for wrapped lines. */
65
+ lineHeightFactor: number;
66
+ /** Clockwise rotation in degrees about (x, y); applied to every line. */
67
+ rotation: number;
68
+ }
69
+ /**
70
+ * Emit a text block as a single *deferred* fragment so that anchor
71
+ * alignment, word wrapping, and glyph encoding are all computed at
72
+ * serialization time — after `PdfDocumentBuilder.build()` has finalised the
73
+ * document's fonts.
74
+ *
75
+ * This matters because text measurement (anchor offset, line breaking) must
76
+ * use the *same* font that ultimately renders the glyphs. At draw time the
77
+ * font may still be unresolved (a non-WinAnsi run can trigger a build-time
78
+ * auto-embed of a system CIDFont), so measuring against the provisional
79
+ * Type1/Helvetica metrics would misplace centred/right-aligned text and
80
+ * break lines at the wrong points. Deferring keeps measurement and encoding
81
+ * consistent while preserving the fragment's draw-order slot (z-order).
34
82
  */
35
- export declare function emitTextWithMatrix(stream: PdfContentStream, text: string, a: number, b: number, c: number, d: number, tx: number, ty: number, type1ResourceName: string, fontSize: number, fontManager: FontManager, useType3: boolean): void;
83
+ export declare function emitTextBlock(stream: PdfContentStream, options: TextBlockOptions, fontManager: FontManager): void;
36
84
  /**
37
85
  * Generate a deterministic ExtGState resource name for a given alpha value.
38
86
  * Uses 4 decimal digits to avoid collisions between close alpha values.
@@ -675,7 +675,7 @@ function drawRotatedGeneral(stream, cell, lines, fontManager, resourceName, font
675
675
  emitTextWithMatrix(stream, line, cos, sin, -sin, cos, tx, ty, resourceName, fontSize, fontManager, useType3);
676
676
  }
677
677
  }
678
- /** Emit a text string with hex encoding if available. */
678
+ /** Emit a text string with hex encoding if available, onto a sink stream. */
679
679
  function emitText(stream, fontManager, text, resourceName) {
680
680
  const hex = fontManager.encodeText(text, resourceName);
681
681
  if (hex) {
@@ -690,40 +690,133 @@ function emitText(stream, fontManager, text, resourceName) {
690
690
  * when needed. For each sub-run the matrix origin is advanced along the
691
691
  * text direction (cos, sin) by the rendered width.
692
692
  *
693
- * When `useType3` is false this collapses to a single BT/ET pair — identical
694
- * to the old `emitText()` path but wrapped in begin/end for convenience.
693
+ * The emitted operators are written as a *deferred* fragment (see
694
+ * `PdfContentStream.deferred`). The fragment is only evaluated at
695
+ * serialization time, by which point `PdfDocumentBuilder.build()` has
696
+ * finalised the document's fonts (auto-discovered embedded CIDFont,
697
+ * Type3 fallback, or plain Type1). This is essential: at draw time the
698
+ * font manager has not yet decided whether a non-WinAnsi code point (e.g.
699
+ * U+2192 →) will be served by an embedded font or a Type3 glyph, so eager
700
+ * encoding would irreversibly degrade those characters to spaces via the
701
+ * WinAnsi fallback. Deferring the encode keeps the fragment at its exact
702
+ * draw-order slot (preserving z-order) while choosing the correct bytes
703
+ * once fonts are known.
704
+ *
705
+ * The `useType3` argument is the caller's *draw-time* guess and is ignored;
706
+ * the deferred body recomputes the routing from the now-settled font
707
+ * manager state.
708
+ */
709
+ export function emitTextWithMatrix(stream, text, a, b, c, d, tx, ty, type1ResourceName, fontSize, fontManager, _useType3) {
710
+ stream.deferred(() => renderTextBlock(text, a, b, c, d, tx, ty, type1ResourceName, fontSize, fontManager));
711
+ }
712
+ /**
713
+ * Emit a text block as a single *deferred* fragment so that anchor
714
+ * alignment, word wrapping, and glyph encoding are all computed at
715
+ * serialization time — after `PdfDocumentBuilder.build()` has finalised the
716
+ * document's fonts.
717
+ *
718
+ * This matters because text measurement (anchor offset, line breaking) must
719
+ * use the *same* font that ultimately renders the glyphs. At draw time the
720
+ * font may still be unresolved (a non-WinAnsi run can trigger a build-time
721
+ * auto-embed of a system CIDFont), so measuring against the provisional
722
+ * Type1/Helvetica metrics would misplace centred/right-aligned text and
723
+ * break lines at the wrong points. Deferring keeps measurement and encoding
724
+ * consistent while preserving the fragment's draw-order slot (z-order).
725
+ */
726
+ export function emitTextBlock(stream, options, fontManager) {
727
+ stream.deferred(() => renderTextBlockLayout(options, fontManager));
728
+ }
729
+ /**
730
+ * Lay out and render a text block from the font manager's *current*
731
+ * (build-time) state. Resolves the render resource name once and uses it for
732
+ * both measurement and encoding so the two never disagree.
733
+ *
734
+ * Layout is computed in the text's *local* coordinate frame — x grows along
735
+ * the baseline, y grows upward — then mapped to page space through the
736
+ * rotation matrix. This makes anchor alignment, multi-line word wrapping, and
737
+ * rotation compose correctly together: each line is offset by its anchor
738
+ * shift (along local x) and its line index (down local y), and a single
739
+ * rotation maps the whole block into place. Upright text (rotation 0) reduces
740
+ * to the identity mapping.
741
+ */
742
+ function renderTextBlockLayout(options, fontManager) {
743
+ const { text, x, y, type1ResourceName, fontSize, anchor, maxWidth, lineHeightFactor, rotation } = options;
744
+ // Resolve the resource name once; measurement and rendering share it so a
745
+ // build-time auto-embedded CIDFont (or Type3 fallback) is measured with the
746
+ // metrics that will actually render the glyphs.
747
+ const measureResource = fontManager.resolveRenderResourceName(type1ResourceName);
748
+ const measure = (s) => fontManager.measureText(s, measureResource, fontSize);
749
+ const lines = maxWidth ? wrapTextLines(text, measure, maxWidth) : [text];
750
+ const leading = fontSize * lineHeightFactor;
751
+ // Rotation matrix [a b; c d] = [cos sin; -sin cos]; identity when upright.
752
+ const theta = (rotation * Math.PI) / 180;
753
+ const cos = rotation === 0 ? 1 : Math.cos(theta);
754
+ const sin = rotation === 0 ? 0 : Math.sin(theta);
755
+ const anchorFactor = anchor === "middle" ? 0.5 : anchor === "end" ? 1 : 0;
756
+ const parts = [];
757
+ for (let i = 0; i < lines.length; i++) {
758
+ // Local-frame origin of this line: anchor shift along x, line index down y.
759
+ const localX = anchorFactor === 0 ? 0 : -measure(lines[i]) * anchorFactor;
760
+ const localY = -i * leading;
761
+ // Map local origin into page space through the rotation matrix.
762
+ const tx = x + localX * cos + localY * -sin;
763
+ const ty = y + localX * sin + localY * cos;
764
+ parts.push(renderTextBlock(lines[i], cos, sin, -sin, cos, tx, ty, type1ResourceName, fontSize, fontManager));
765
+ }
766
+ return parts.join("\n");
767
+ }
768
+ /**
769
+ * Produce the PDF operator string for a positioned text run, choosing the
770
+ * encoding from the font manager's *current* (build-time) state:
771
+ * - embedded font → single BT/ET with CIDFont hex encoding
772
+ * - Type3 fallback → split into WinAnsi (Type1) and per-glyph Type3 runs
773
+ * - neither → single BT/ET with Type1/WinAnsi encoding
774
+ *
775
+ * Must only be called after font resolution (i.e. from a deferred fragment).
695
776
  */
696
- export function emitTextWithMatrix(stream, text, a, b, c, d, tx, ty, type1ResourceName, fontSize, fontManager, useType3) {
777
+ function renderTextBlock(text, a, b, c, d, tx, ty, type1ResourceName, fontSize, fontManager) {
778
+ const sink = new PdfContentStream();
779
+ // Type3 splitting only applies when there is no embedded font but Type3
780
+ // fallback glyphs were generated. Otherwise the run renders as a single
781
+ // BT/ET pair, choosing the resource name from the now-settled state:
782
+ // if an embedded font exists (possibly auto-discovered at build time,
783
+ // after this run was drawn against a Type1 resource), the run must use it
784
+ // so `emitText` → `encodeText` produces CIDFont hex; without that switch
785
+ // the stale Type1 resource name would make `encodeText` return null and
786
+ // non-WinAnsi characters would degrade to spaces via the WinAnsi fallback.
787
+ const useType3 = fontManager.hasType3Fonts() && !fontManager.hasEmbeddedFont();
697
788
  if (!useType3) {
698
- stream.beginText();
699
- stream.setFont(type1ResourceName, fontSize);
700
- stream.setTextMatrix(a, b, c, d, tx, ty);
701
- emitText(stream, fontManager, text, type1ResourceName);
702
- stream.endText();
703
- return;
789
+ const resourceName = fontManager.resolveRenderResourceName(type1ResourceName);
790
+ sink.beginText();
791
+ sink.setFont(resourceName, fontSize);
792
+ sink.setTextMatrix(a, b, c, d, tx, ty);
793
+ emitText(sink, fontManager, text, resourceName);
794
+ sink.endText();
795
+ return sink.toString();
704
796
  }
705
797
  // Type3 path: split into runs and advance origin along text direction
706
798
  const runs = splitTextRuns(text, fontManager);
707
799
  let curTx = tx;
708
800
  let curTy = ty;
709
801
  for (const run of runs) {
710
- stream.beginText();
802
+ sink.beginText();
711
803
  if (run.type3) {
712
- stream.setFont(run.type3.resourceName, fontSize);
713
- stream.setTextMatrix(a, b, c, d, curTx, curTy);
714
- stream.showTextHex(run.type3.hex);
804
+ sink.setFont(run.type3.resourceName, fontSize);
805
+ sink.setTextMatrix(a, b, c, d, curTx, curTy);
806
+ sink.showTextHex(run.type3.hex);
715
807
  }
716
808
  else {
717
- stream.setFont(type1ResourceName, fontSize);
718
- stream.setTextMatrix(a, b, c, d, curTx, curTy);
719
- emitText(stream, fontManager, run.text, type1ResourceName);
809
+ sink.setFont(type1ResourceName, fontSize);
810
+ sink.setTextMatrix(a, b, c, d, curTx, curTy);
811
+ emitText(sink, fontManager, run.text, type1ResourceName);
720
812
  }
721
- stream.endText();
813
+ sink.endText();
722
814
  const w = fontManager.measureText(run.text, run.type3?.resourceName ?? type1ResourceName, fontSize);
723
815
  // Advance along the text direction (first column of the matrix)
724
816
  curTx += a * w;
725
817
  curTy += b * w;
726
818
  }
819
+ return sink.toString();
727
820
  }
728
821
  /**
729
822
  * Split a line of text into runs of consecutive WinAnsi and non-WinAnsi
@@ -42,7 +42,7 @@ export function updateFields(doc, options) {
42
42
  // Build style → paragraphs index for STYLEREF
43
43
  const styleIndex = buildStyleIndex(doc);
44
44
  // Collect INDEX entries (XE fields) from all body content
45
- const indexEntries = collectIndexEntries(doc);
45
+ const indexEntries = collectIndexEntries(doc, layout);
46
46
  // Update body content
47
47
  const newBody = updateBody(doc, layout, bookmarkInfo, seqValues, styleIndex, indexEntries, opts);
48
48
  // If TOC was updated, register the TOC1..TOCn paragraph styles so the
@@ -610,23 +610,33 @@ function findStyleRef(styleIndex, styleName, bodyIndex) {
610
610
  // =============================================================================
611
611
  // Index Entry Collection (for INDEX field)
612
612
  // =============================================================================
613
- /** Collect all XE (Index Entry) fields from the document body. */
614
- function collectIndexEntries(doc) {
613
+ /**
614
+ * Collect all XE (Index Entry) fields from the document body, tagging each
615
+ * with the page it falls on. Page numbers come from `layout.contentPages`
616
+ * keyed by the enclosing top-level body index (the same mechanism used for
617
+ * headings/TOC); entries inside nested structures inherit their outer block's
618
+ * page, falling back to 1 when layout produced no page for that block.
619
+ */
620
+ function collectIndexEntries(doc, layout) {
615
621
  const entries = [];
616
- walkBlocks(doc.body, {
617
- visitRunContent(content) {
618
- if (content.type !== "field") {
619
- return;
620
- }
621
- const { type, args } = parseFieldInstruction(content.instruction);
622
- if (type === "XE") {
623
- const term = parseXeTerm(args);
624
- if (term) {
625
- entries.push({ term, page: 1 });
622
+ const { contentPages } = layout;
623
+ for (let i = 0; i < doc.body.length; i++) {
624
+ const page = contentPages[i] ?? 1;
625
+ walkBlocks([doc.body[i]], {
626
+ visitRunContent(content) {
627
+ if (content.type !== "field") {
628
+ return;
629
+ }
630
+ const { type, args } = parseFieldInstruction(content.instruction);
631
+ if (type === "XE") {
632
+ const term = parseXeTerm(args);
633
+ if (term) {
634
+ entries.push({ term, page });
635
+ }
626
636
  }
627
637
  }
628
- }
629
- });
638
+ });
639
+ }
630
640
  return entries;
631
641
  }
632
642
  /** Parse the term from an XE field argument: XE "term" or XE term. */
@@ -643,17 +653,32 @@ function buildIndexContent(entries, args) {
643
653
  if (entries.length === 0) {
644
654
  return "";
645
655
  }
646
- // Sort entries alphabetically by term
647
- const sorted = [...entries].sort((a, b) => a.term.localeCompare(b.term));
656
+ // Merge entries that share the same term: a term marked on several pages
657
+ // produces a single index line listing each distinct page (Word behaviour),
658
+ // e.g. "widget, 1, 4" rather than two separate "widget" rows.
659
+ const byTerm = new Map();
660
+ for (const entry of entries) {
661
+ let pages = byTerm.get(entry.term);
662
+ if (!pages) {
663
+ pages = new Set();
664
+ byTerm.set(entry.term, pages);
665
+ }
666
+ pages.add(entry.page);
667
+ }
668
+ // Sort terms alphabetically; within each term sort pages numerically.
669
+ const merged = [...byTerm.entries()]
670
+ .map(([term, pages]) => ({ term, pages: [...pages].sort((a, b) => a - b) }))
671
+ .sort((a, b) => a.term.localeCompare(b.term));
672
+ const formatEntry = (e) => `${e.term}\t${e.pages.join(", ")}`;
648
673
  // Check for \h switch (group by first letter with headings)
649
674
  const grouped = /\\h\b/i.test(args);
650
675
  if (!grouped) {
651
- return sorted.map(e => `${e.term}\t${e.page}`).join("\n");
676
+ return merged.map(formatEntry).join("\n");
652
677
  }
653
678
  // Group by first letter
654
679
  const lines = [];
655
680
  let currentLetter = "";
656
- for (const entry of sorted) {
681
+ for (const entry of merged) {
657
682
  const letter = entry.term.charAt(0).toUpperCase();
658
683
  if (letter !== currentLetter) {
659
684
  currentLetter = letter;
@@ -662,7 +687,7 @@ function buildIndexContent(entries, args) {
662
687
  }
663
688
  lines.push(currentLetter);
664
689
  }
665
- lines.push(`${entry.term}\t${entry.page}`);
690
+ lines.push(formatEntry(entry));
666
691
  }
667
692
  return lines.join("\n");
668
693
  }
@@ -4,45 +4,19 @@
4
4
  * Provides types and utilities for working with Glossary Document parts,
5
5
  * which contain AutoText entries, Quick Parts, and other Building Blocks.
6
6
  *
7
- * INTEGRATION STATUS: This module provides data structures and query helpers
8
- * for building blocks. The actual reading/writing of glossary parts from/to
9
- * DOCX archives is handled via the opaqueParts round-trip mechanism —
10
- * glossary parts in existing files are preserved as opaque parts during
11
- * read/write. This module is useful for:
7
+ * INTEGRATION STATUS: This module provides the glossary data model and query
8
+ * helpers. To embed a glossary in a document, assign a {@link GlossaryDocument}
9
+ * to `doc.glossary`; the packager then serialises it to
10
+ * `word/glossary/document.xml`, registers the `glossaryDocument` relationship,
11
+ * and adds the `[Content_Types].xml` override (the canonical OOXML location
12
+ * Word reads Quick Parts / AutoText from). Glossary parts in existing files are
13
+ * round-tripped via the same channel. This module is useful for:
12
14
  * - Building glossary data structures programmatically
13
15
  * - Querying/filtering building block collections
14
- * - Preparing data for future direct glossary part writing
15
- *
16
- * To add glossary content to a document currently, include it as an
17
- * OpaquePart with path "word/glossary/document.xml".
16
+ * - Assembling a glossary to attach via `doc.glossary`
18
17
  */
19
- import type { BodyContent, SectionProperties } from "../types.js";
20
- /** Building block gallery category. */
21
- export type BuildingBlockGallery = "autoText" | "quickParts" | "coverPages" | "tableOfContents" | "headers" | "footers" | "pageNumbers" | "tables" | "textBoxes" | "watermarks" | "equations" | "bibliographies" | "custom1" | "custom2" | "custom3" | "custom4" | "custom5";
22
- /** A single building block (AutoText/Quick Part) entry. */
23
- export interface BuildingBlock {
24
- /** Name of the building block (displayed in gallery). */
25
- readonly name: string;
26
- /** Gallery this block belongs to. */
27
- readonly gallery: BuildingBlockGallery;
28
- /** Category within the gallery. */
29
- readonly category?: string;
30
- /** Description/tooltip. */
31
- readonly description?: string;
32
- /** The content of the building block. */
33
- readonly content: readonly BodyContent[];
34
- /** Section properties specific to this building block. */
35
- readonly sectionProperties?: SectionProperties;
36
- /** Unique identifier (GUID). */
37
- readonly guid?: string;
38
- }
39
- /** The glossary document model. */
40
- export interface GlossaryDocument {
41
- /** Building block entries. */
42
- readonly blocks: readonly BuildingBlock[];
43
- /** Raw parts preserved for round-trip (style, settings, fontTable). */
44
- readonly rawParts?: ReadonlyMap<string, Uint8Array>;
45
- }
18
+ import type { BodyContent, BuildingBlock, BuildingBlockGallery, GlossaryDocument, SectionProperties } from "../types.js";
19
+ export type { BuildingBlock, BuildingBlockGallery, GlossaryDocument } from "../types.js";
46
20
  /**
47
21
  * Create a building block entry.
48
22
  *
@@ -4,17 +4,16 @@
4
4
  * Provides types and utilities for working with Glossary Document parts,
5
5
  * which contain AutoText entries, Quick Parts, and other Building Blocks.
6
6
  *
7
- * INTEGRATION STATUS: This module provides data structures and query helpers
8
- * for building blocks. The actual reading/writing of glossary parts from/to
9
- * DOCX archives is handled via the opaqueParts round-trip mechanism —
10
- * glossary parts in existing files are preserved as opaque parts during
11
- * read/write. This module is useful for:
7
+ * INTEGRATION STATUS: This module provides the glossary data model and query
8
+ * helpers. To embed a glossary in a document, assign a {@link GlossaryDocument}
9
+ * to `doc.glossary`; the packager then serialises it to
10
+ * `word/glossary/document.xml`, registers the `glossaryDocument` relationship,
11
+ * and adds the `[Content_Types].xml` override (the canonical OOXML location
12
+ * Word reads Quick Parts / AutoText from). Glossary parts in existing files are
13
+ * round-tripped via the same channel. This module is useful for:
12
14
  * - Building glossary data structures programmatically
13
15
  * - Querying/filtering building block collections
14
- * - Preparing data for future direct glossary part writing
15
- *
16
- * To add glossary content to a document currently, include it as an
17
- * OpaquePart with path "word/glossary/document.xml".
16
+ * - Assembling a glossary to attach via `doc.glossary`
18
17
  */
19
18
  import { generateGuid } from "../core/internal-utils.js";
20
19
  // =============================================================================