@cj-tech-master/excelts 9.5.0 → 9.5.1

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 (68) hide show
  1. package/dist/browser/modules/pdf/excel-bridge.js +27 -1
  2. package/dist/browser/modules/pdf/render/layout-engine.js +74 -9
  3. package/dist/browser/modules/pdf/render/style-converter.d.ts +1 -1
  4. package/dist/browser/modules/pdf/render/style-converter.js +98 -1
  5. package/dist/browser/modules/pdf/types.d.ts +1 -0
  6. package/dist/browser/modules/word/color-utils.d.ts +18 -0
  7. package/dist/browser/modules/word/color-utils.js +94 -0
  8. package/dist/browser/modules/word/content-types.d.ts +15 -15
  9. package/dist/browser/modules/word/content-types.js +39 -43
  10. package/dist/browser/modules/word/crypto.d.ts +17 -0
  11. package/dist/browser/modules/word/crypto.js +18 -0
  12. package/dist/browser/modules/word/document-io.d.ts +58 -0
  13. package/dist/browser/modules/word/document-io.js +239 -0
  14. package/dist/browser/modules/word/document.d.ts +64 -135
  15. package/dist/browser/modules/word/document.js +207 -469
  16. package/dist/browser/modules/word/docx-packager.js +90 -90
  17. package/dist/browser/modules/word/html-renderer.js +1 -1
  18. package/dist/browser/modules/word/html.d.ts +13 -0
  19. package/dist/browser/modules/word/html.js +12 -0
  20. package/dist/browser/modules/word/index.base.d.ts +6 -9
  21. package/dist/browser/modules/word/index.base.js +7 -10
  22. package/dist/browser/modules/word/namespaces.d.ts +159 -0
  23. package/dist/browser/modules/word/namespaces.js +189 -0
  24. package/dist/browser/modules/word/relationships.d.ts +15 -16
  25. package/dist/browser/modules/word/relationships.js +37 -45
  26. package/dist/cjs/modules/pdf/excel-bridge.js +27 -1
  27. package/dist/cjs/modules/pdf/render/layout-engine.js +74 -9
  28. package/dist/cjs/modules/pdf/render/style-converter.js +98 -1
  29. package/dist/cjs/modules/word/color-utils.js +97 -0
  30. package/dist/cjs/modules/word/content-types.js +44 -45
  31. package/dist/cjs/modules/word/crypto.js +34 -0
  32. package/dist/cjs/modules/word/document-io.js +244 -0
  33. package/dist/cjs/modules/word/document.js +209 -473
  34. package/dist/cjs/modules/word/docx-packager.js +88 -88
  35. package/dist/cjs/modules/word/html-renderer.js +2 -2
  36. package/dist/cjs/modules/word/html.js +16 -0
  37. package/dist/cjs/modules/word/index.base.js +17 -27
  38. package/dist/cjs/modules/word/namespaces.js +192 -0
  39. package/dist/cjs/modules/word/relationships.js +42 -47
  40. package/dist/esm/modules/pdf/excel-bridge.js +27 -1
  41. package/dist/esm/modules/pdf/render/layout-engine.js +74 -9
  42. package/dist/esm/modules/pdf/render/style-converter.js +98 -1
  43. package/dist/esm/modules/word/color-utils.js +94 -0
  44. package/dist/esm/modules/word/content-types.js +39 -43
  45. package/dist/esm/modules/word/crypto.js +18 -0
  46. package/dist/esm/modules/word/document-io.js +239 -0
  47. package/dist/esm/modules/word/document.js +207 -469
  48. package/dist/esm/modules/word/docx-packager.js +90 -90
  49. package/dist/esm/modules/word/html-renderer.js +1 -1
  50. package/dist/esm/modules/word/html.js +12 -0
  51. package/dist/esm/modules/word/index.base.js +7 -10
  52. package/dist/esm/modules/word/namespaces.js +189 -0
  53. package/dist/esm/modules/word/relationships.js +37 -45
  54. package/dist/iife/excelts.iife.js +153 -11
  55. package/dist/iife/excelts.iife.js.map +1 -1
  56. package/dist/iife/excelts.iife.min.js +4 -4
  57. package/dist/types/modules/pdf/render/style-converter.d.ts +1 -1
  58. package/dist/types/modules/pdf/types.d.ts +1 -0
  59. package/dist/types/modules/word/color-utils.d.ts +18 -0
  60. package/dist/types/modules/word/content-types.d.ts +15 -15
  61. package/dist/types/modules/word/crypto.d.ts +17 -0
  62. package/dist/types/modules/word/document-io.d.ts +58 -0
  63. package/dist/types/modules/word/document.d.ts +64 -135
  64. package/dist/types/modules/word/html.d.ts +13 -0
  65. package/dist/types/modules/word/index.base.d.ts +6 -9
  66. package/dist/types/modules/word/namespaces.d.ts +159 -0
  67. package/dist/types/modules/word/relationships.d.ts +15 -16
  68. package/package.json +1 -1
@@ -9,8 +9,8 @@
9
9
  import { zip } from "../archive/create-archive.js";
10
10
  import { XmlWriter } from "../xml/writer.js";
11
11
  import { ContentType, RelType, PartPath, STD_DOC_ATTRIBUTES } from "./constants.js";
12
- import { ContentTypesManager } from "./content-types.js";
13
- import { RelationshipManager } from "./relationships.js";
12
+ import { createContentTypes, addContentTypeDefault, addContentTypeOverride, addImageContentTypeDefaults, renderContentTypes } from "./content-types.js";
13
+ import { createRelationships, addRelationship, addRelationshipWithId, getRelationshipCount, renderRelationships } from "./relationships.js";
14
14
  import { renderChartPart } from "./writers/chart-writer.js";
15
15
  import { renderComments, renderCommentsExtended } from "./writers/comment-writer.js";
16
16
  import { renderDocument, CHART_RID_REGISTRY } from "./writers/document-writer.js";
@@ -202,42 +202,42 @@ function collectHyperlinksFromHeaderFooter(content) {
202
202
  export async function packageDocx(doc, compressionLevel) {
203
203
  const archive = zip({ level: compressionLevel ?? 6 });
204
204
  // Managers
205
- const contentTypes = new ContentTypesManager();
206
- const packageRels = new RelationshipManager();
207
- const documentRels = new RelationshipManager();
205
+ const contentTypes = createContentTypes();
206
+ const packageRels = createRelationships();
207
+ const documentRels = createRelationships();
208
208
  // --- Package relationships ---
209
- packageRels.add(RelType.OfficeDocument, "word/document.xml");
210
- packageRels.add(RelType.CoreProperties, "docProps/core.xml");
211
- packageRels.add(RelType.ExtendedProperties, "docProps/app.xml");
209
+ addRelationship(packageRels, RelType.OfficeDocument, "word/document.xml");
210
+ addRelationship(packageRels, RelType.CoreProperties, "docProps/core.xml");
211
+ addRelationship(packageRels, RelType.ExtendedProperties, "docProps/app.xml");
212
212
  // Custom properties
213
213
  const hasCustomProps = doc.customProperties && doc.customProperties.length > 0;
214
214
  if (hasCustomProps) {
215
- packageRels.add(RelType.CustomProperties, "docProps/custom.xml");
215
+ addRelationship(packageRels, RelType.CustomProperties, "docProps/custom.xml");
216
216
  }
217
217
  // --- Document relationships ---
218
- documentRels.add(RelType.Styles, "styles.xml");
219
- documentRels.add(RelType.Settings, "settings.xml");
220
- documentRels.add(RelType.FontTable, "fontTable.xml");
221
- documentRels.add(RelType.Theme, "theme/theme1.xml");
218
+ addRelationship(documentRels, RelType.Styles, "styles.xml");
219
+ addRelationship(documentRels, RelType.Settings, "settings.xml");
220
+ addRelationship(documentRels, RelType.FontTable, "fontTable.xml");
221
+ addRelationship(documentRels, RelType.Theme, "theme/theme1.xml");
222
222
  // Numbering
223
223
  const hasNumbering = (doc.abstractNumberings && doc.abstractNumberings.length > 0) ||
224
224
  (doc.numberingInstances && doc.numberingInstances.length > 0);
225
225
  if (hasNumbering) {
226
- documentRels.add(RelType.Numbering, "numbering.xml");
226
+ addRelationship(documentRels, RelType.Numbering, "numbering.xml");
227
227
  }
228
228
  // Footnotes & Endnotes
229
229
  const hasFootnotes = doc.footnotes && doc.footnotes.length > 0;
230
230
  const hasEndnotes = doc.endnotes && doc.endnotes.length > 0;
231
231
  if (hasFootnotes) {
232
- documentRels.add(RelType.Footnotes, "footnotes.xml");
232
+ addRelationship(documentRels, RelType.Footnotes, "footnotes.xml");
233
233
  }
234
234
  if (hasEndnotes) {
235
- documentRels.add(RelType.Endnotes, "endnotes.xml");
235
+ addRelationship(documentRels, RelType.Endnotes, "endnotes.xml");
236
236
  }
237
237
  // Comments
238
238
  const hasComments = doc.comments && doc.comments.length > 0;
239
239
  if (hasComments) {
240
- documentRels.add(RelType.Comments, "comments.xml");
240
+ addRelationship(documentRels, RelType.Comments, "comments.xml");
241
241
  }
242
242
  // Images
243
243
  const imageExtensions = new Set();
@@ -259,14 +259,14 @@ export async function packageDocx(doc, compressionLevel) {
259
259
  const baseName = img.fileName.replace(/\.[^.]+$/, "");
260
260
  const fallbackFileName = `${baseName}_fallback.png`;
261
261
  // Register PNG fallback as the main rId
262
- const fbRId = documentRels.add(RelType.Image, `media/${fallbackFileName}`);
262
+ const fbRId = addRelationship(documentRels, RelType.Image, `media/${fallbackFileName}`);
263
263
  img.rId = fbRId;
264
264
  if (oldRid) {
265
265
  imageRidMap.set(oldRid, fbRId);
266
266
  }
267
267
  imageExtensions.add("png");
268
268
  // Register SVG as separate image
269
- const svgRId = documentRels.add(RelType.Image, `media/${img.fileName}`);
269
+ const svgRId = addRelationship(documentRels, RelType.Image, `media/${img.fileName}`);
270
270
  svgRidMap.set(img.fileName, svgRId);
271
271
  const ext = img.fileName.split(".").pop()?.toLowerCase();
272
272
  if (ext) {
@@ -275,7 +275,7 @@ export async function packageDocx(doc, compressionLevel) {
275
275
  svgFallbacks.push({ fallbackFileName, data: img.fallbackData });
276
276
  }
277
277
  else {
278
- const rId = documentRels.add(RelType.Image, `media/${img.fileName}`);
278
+ const rId = addRelationship(documentRels, RelType.Image, `media/${img.fileName}`);
279
279
  img.rId = rId;
280
280
  if (oldRid) {
281
281
  imageRidMap.set(oldRid, rId);
@@ -342,7 +342,7 @@ export async function packageDocx(doc, compressionLevel) {
342
342
  const hyperlinks = collectHyperlinks(doc.body);
343
343
  for (const link of hyperlinks) {
344
344
  if (link.url) {
345
- const rId = documentRels.add(RelType.Hyperlink, link.url, "External");
345
+ const rId = addRelationship(documentRels, RelType.Hyperlink, link.url, "External");
346
346
  link.rId = rId;
347
347
  }
348
348
  }
@@ -352,11 +352,11 @@ export async function packageDocx(doc, compressionLevel) {
352
352
  altChunks.forEach((chunk, i) => {
353
353
  const fileName = chunk.fileName ?? `afchunk${i + 1}.html`;
354
354
  // Register relationship for the alt chunk
355
- const rId = documentRels.add("http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk", fileName);
355
+ const rId = addRelationship(documentRels, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk", fileName);
356
356
  chunk.rId = rId;
357
357
  // Register content type
358
358
  const ct = chunk.contentType ?? "text/html";
359
- contentTypes.addOverride(`/word/${fileName}`, ct);
359
+ addContentTypeOverride(contentTypes, `/word/${fileName}`, ct);
360
360
  // Write data to archive
361
361
  if (chunk.data) {
362
362
  archive.add(`word/${fileName}`, chunk.data);
@@ -367,17 +367,17 @@ export async function packageDocx(doc, compressionLevel) {
367
367
  const headerRelManagers = new Map();
368
368
  if (doc.headers) {
369
369
  for (const [key, headerDef] of doc.headers) {
370
- const rId = documentRels.add(RelType.Header, `header${headerIndex}.xml`);
370
+ const rId = addRelationship(documentRels, RelType.Header, `header${headerIndex}.xml`);
371
371
  headerDef.rId = rId;
372
- // Create per-header relationship manager for images and hyperlinks
373
- const hRels = new RelationshipManager();
372
+ // Create per-header relationship state for images and hyperlinks
373
+ const hRels = createRelationships();
374
374
  const imgRids = collectImageRidsFromContent(headerDef.content);
375
375
  if (imgRids.size > 0 && doc.images) {
376
376
  for (const oldRid of imgRids) {
377
377
  // O(1) lookup: direct or via remap
378
378
  const img = imageByRid.get(oldRid) ?? imageByRid.get(imageRidMap.get(oldRid) ?? "");
379
379
  if (img) {
380
- hRels.addWithId(oldRid, RelType.Image, `media/${img.fileName}`);
380
+ addRelationshipWithId(hRels, oldRid, RelType.Image, `media/${img.fileName}`);
381
381
  }
382
382
  }
383
383
  }
@@ -385,11 +385,11 @@ export async function packageDocx(doc, compressionLevel) {
385
385
  const hLinks = collectHyperlinksFromHeaderFooter(headerDef.content);
386
386
  for (const link of hLinks) {
387
387
  if (link.url) {
388
- const linkRId = hRels.add(RelType.Hyperlink, link.url, "External");
388
+ const linkRId = addRelationship(hRels, RelType.Hyperlink, link.url, "External");
389
389
  link.rId = linkRId;
390
390
  }
391
391
  }
392
- if (hRels.count > 0) {
392
+ if (getRelationshipCount(hRels) > 0) {
393
393
  headerRelManagers.set(key, hRels);
394
394
  }
395
395
  headerIndex++;
@@ -400,16 +400,16 @@ export async function packageDocx(doc, compressionLevel) {
400
400
  const footerRelManagers = new Map();
401
401
  if (doc.footers) {
402
402
  for (const [key, footerDef] of doc.footers) {
403
- const rId = documentRels.add(RelType.Footer, `footer${footerIndex}.xml`);
403
+ const rId = addRelationship(documentRels, RelType.Footer, `footer${footerIndex}.xml`);
404
404
  footerDef.rId = rId;
405
- // Create per-footer relationship manager for images and hyperlinks
406
- const fRels = new RelationshipManager();
405
+ // Create per-footer relationship state for images and hyperlinks
406
+ const fRels = createRelationships();
407
407
  const imgRids = collectImageRidsFromContent(footerDef.content);
408
408
  if (imgRids.size > 0 && doc.images) {
409
409
  for (const oldRid of imgRids) {
410
410
  const img = imageByRid.get(oldRid) ?? imageByRid.get(imageRidMap.get(oldRid) ?? "");
411
411
  if (img) {
412
- fRels.addWithId(oldRid, RelType.Image, `media/${img.fileName}`);
412
+ addRelationshipWithId(fRels, oldRid, RelType.Image, `media/${img.fileName}`);
413
413
  }
414
414
  }
415
415
  }
@@ -417,11 +417,11 @@ export async function packageDocx(doc, compressionLevel) {
417
417
  const fLinks = collectHyperlinksFromHeaderFooter(footerDef.content);
418
418
  for (const link of fLinks) {
419
419
  if (link.url) {
420
- const linkRId = fRels.add(RelType.Hyperlink, link.url, "External");
420
+ const linkRId = addRelationship(fRels, RelType.Hyperlink, link.url, "External");
421
421
  link.rId = linkRId;
422
422
  }
423
423
  }
424
- if (fRels.count > 0) {
424
+ if (getRelationshipCount(fRels) > 0) {
425
425
  footerRelManagers.set(key, fRels);
426
426
  }
427
427
  footerIndex++;
@@ -434,67 +434,67 @@ export async function packageDocx(doc, compressionLevel) {
434
434
  if (doc.watermark) {
435
435
  // Use next header index
436
436
  const wmHdrIdx = headerIndex;
437
- watermarkHeaderRId = documentRels.add(RelType.Header, `header${wmHdrIdx}.xml`);
437
+ watermarkHeaderRId = addRelationship(documentRels, RelType.Header, `header${wmHdrIdx}.xml`);
438
438
  watermarkHeaderIndex = wmHdrIdx;
439
439
  // If image watermark, add image relationship in header .rels
440
440
  if (doc.watermark.type === "image") {
441
- const wmRels = new RelationshipManager();
441
+ const wmRels = createRelationships();
442
442
  const wmRId = doc.watermark.rId;
443
443
  const img = imageByRid.get(wmRId) ?? imageByRid.get(imageRidMap.get(wmRId) ?? "");
444
444
  if (img) {
445
- wmRels.addWithId(wmRId, RelType.Image, `media/${img.fileName}`);
445
+ addRelationshipWithId(wmRels, wmRId, RelType.Image, `media/${img.fileName}`);
446
446
  }
447
447
  watermarkHeaderRels = wmRels;
448
448
  }
449
449
  headerIndex++;
450
450
  }
451
451
  // --- Content Types ---
452
- contentTypes.addImageDefaults(imageExtensions);
453
- contentTypes.addOverride(PartPath.Document, ContentType.Document);
454
- contentTypes.addOverride(PartPath.Styles, ContentType.Styles);
455
- contentTypes.addOverride(PartPath.Settings, ContentType.Settings);
456
- contentTypes.addOverride(PartPath.FontTable, ContentType.FontTable);
457
- contentTypes.addOverride(PartPath.Theme, ContentType.Theme);
452
+ addImageContentTypeDefaults(contentTypes, imageExtensions);
453
+ addContentTypeOverride(contentTypes, PartPath.Document, ContentType.Document);
454
+ addContentTypeOverride(contentTypes, PartPath.Styles, ContentType.Styles);
455
+ addContentTypeOverride(contentTypes, PartPath.Settings, ContentType.Settings);
456
+ addContentTypeOverride(contentTypes, PartPath.FontTable, ContentType.FontTable);
457
+ addContentTypeOverride(contentTypes, PartPath.Theme, ContentType.Theme);
458
458
  if (hasNumbering) {
459
- contentTypes.addOverride(PartPath.Numbering, ContentType.Numbering);
459
+ addContentTypeOverride(contentTypes, PartPath.Numbering, ContentType.Numbering);
460
460
  }
461
461
  if (hasFootnotes) {
462
- contentTypes.addOverride(PartPath.Footnotes, ContentType.Footnotes);
462
+ addContentTypeOverride(contentTypes, PartPath.Footnotes, ContentType.Footnotes);
463
463
  }
464
464
  if (hasEndnotes) {
465
- contentTypes.addOverride(PartPath.Endnotes, ContentType.Endnotes);
465
+ addContentTypeOverride(contentTypes, PartPath.Endnotes, ContentType.Endnotes);
466
466
  }
467
467
  if (hasComments) {
468
- contentTypes.addOverride(PartPath.Comments, ContentType.Comments);
468
+ addContentTypeOverride(contentTypes, PartPath.Comments, ContentType.Comments);
469
469
  }
470
470
  headerIndex = 1;
471
471
  if (doc.headers) {
472
472
  for (const [,] of doc.headers) {
473
- contentTypes.addOverride(PartPath.header(headerIndex), ContentType.Header);
473
+ addContentTypeOverride(contentTypes, PartPath.header(headerIndex), ContentType.Header);
474
474
  headerIndex++;
475
475
  }
476
476
  }
477
477
  footerIndex = 1;
478
478
  if (doc.footers) {
479
479
  for (const [,] of doc.footers) {
480
- contentTypes.addOverride(PartPath.footer(footerIndex), ContentType.Footer);
480
+ addContentTypeOverride(contentTypes, PartPath.footer(footerIndex), ContentType.Footer);
481
481
  footerIndex++;
482
482
  }
483
483
  }
484
484
  if (watermarkHeaderIndex !== undefined) {
485
- contentTypes.addOverride(PartPath.header(watermarkHeaderIndex), ContentType.Header);
485
+ addContentTypeOverride(contentTypes, PartPath.header(watermarkHeaderIndex), ContentType.Header);
486
486
  }
487
- contentTypes.addOverride(PartPath.CoreProps, ContentType.CoreProperties);
488
- contentTypes.addOverride(PartPath.AppProps, ContentType.ExtendedProperties);
487
+ addContentTypeOverride(contentTypes, PartPath.CoreProps, ContentType.CoreProperties);
488
+ addContentTypeOverride(contentTypes, PartPath.AppProps, ContentType.ExtendedProperties);
489
489
  if (hasCustomProps) {
490
- contentTypes.addOverride(PartPath.CustomProps, ContentType.CustomProperties);
490
+ addContentTypeOverride(contentTypes, PartPath.CustomProps, ContentType.CustomProperties);
491
491
  }
492
492
  // --- Generate & add parts to archive ---
493
493
  // Note: [Content_Types].xml and _rels/.rels are serialized LAST so that any
494
494
  // relationships/content types registered during content rendering (e.g.
495
495
  // thumbnails, chart parts, alt chunks) are included.
496
496
  // word/_rels/document.xml.rels
497
- archive.add(PartPath.DocumentRels, renderXml(xml => documentRels.render(xml)));
497
+ archive.add(PartPath.DocumentRels, renderXml(xml => renderRelationships(documentRels, xml)));
498
498
  // Build an effective doc that includes the auto-generated watermark header
499
499
  // reference in section properties (without mutating the caller's doc).
500
500
  let effectiveDoc = doc;
@@ -530,7 +530,7 @@ export async function packageDocx(doc, compressionLevel) {
530
530
  const chartRIds = [];
531
531
  charts.forEach(chartContent => {
532
532
  const num = chartRIds.length + 1;
533
- const rId = documentRels.add(RelType.Chart, `charts/chart${num}.xml`);
533
+ const rId = addRelationship(documentRels, RelType.Chart, `charts/chart${num}.xml`);
534
534
  chartRIds.push(rId);
535
535
  // Store rId in registry so renderChartDrawing can look it up
536
536
  CHART_RID_REGISTRY.set(chartContent, rId);
@@ -545,7 +545,7 @@ export async function packageDocx(doc, compressionLevel) {
545
545
  archive.add(PartPath.FontTable, renderXml(xml => renderFontTable(xml, doc.fonts)));
546
546
  // word/fonts/*.odttf (embedded fonts)
547
547
  if (doc.embeddedFonts && doc.embeddedFonts.length > 0) {
548
- const fontTableRels = new RelationshipManager();
548
+ const fontTableRels = createRelationships();
549
549
  const usedRIds = new Set();
550
550
  // Collect rIds referenced in fontTable
551
551
  if (doc.fonts) {
@@ -569,26 +569,26 @@ export async function packageDocx(doc, compressionLevel) {
569
569
  archive.add(partPath, ef.data);
570
570
  // Register relationship from fontTable.xml
571
571
  if (usedRIds.has(ef.rId)) {
572
- fontTableRels.addWithId(ef.rId, RelType.Font, `fonts/${ef.fileName}`);
572
+ addRelationshipWithId(fontTableRels, ef.rId, RelType.Font, `fonts/${ef.fileName}`);
573
573
  }
574
574
  else {
575
575
  // Add anyway so the embedded font isn't orphaned
576
- fontTableRels.addWithId(ef.rId, RelType.Font, `fonts/${ef.fileName}`);
576
+ addRelationshipWithId(fontTableRels, ef.rId, RelType.Font, `fonts/${ef.fileName}`);
577
577
  }
578
578
  // Register content type for .odttf / .ttf
579
579
  const ext = ef.fileName.split(".").pop()?.toLowerCase();
580
580
  if (ext === "odttf") {
581
- contentTypes.addDefault("odttf", ContentType.ObfuscatedFont);
581
+ addContentTypeDefault(contentTypes, "odttf", ContentType.ObfuscatedFont);
582
582
  }
583
583
  else if (ext === "ttf") {
584
- contentTypes.addDefault("ttf", "application/x-font-ttf");
584
+ addContentTypeDefault(contentTypes, "ttf", "application/x-font-ttf");
585
585
  }
586
586
  else if (ext === "otf") {
587
- contentTypes.addDefault("otf", "application/x-font-otf");
587
+ addContentTypeDefault(contentTypes, "otf", "application/x-font-otf");
588
588
  }
589
589
  }
590
590
  // Write fontTable.xml.rels
591
- archive.add("word/_rels/fontTable.xml.rels", renderXml(xml => fontTableRels.render(xml)));
591
+ archive.add("word/_rels/fontTable.xml.rels", renderXml(xml => renderRelationships(fontTableRels, xml)));
592
592
  }
593
593
  // Custom XML parts (for SDT data binding)
594
594
  if (doc.customXmlParts && doc.customXmlParts.length > 0) {
@@ -619,13 +619,13 @@ export async function packageDocx(doc, compressionLevel) {
619
619
  });
620
620
  archive.add(propsPath, propsXml);
621
621
  // Write item rels (links itemN.xml → itemPropsN.xml)
622
- const itemRels = new RelationshipManager();
623
- itemRels.add(RelType.CustomXmlProps, `itemProps${num}.xml`);
624
- archive.add(`word/customXml/_rels/item${num}.xml.rels`, renderXml(xml => itemRels.render(xml)));
622
+ const itemRels = createRelationships();
623
+ addRelationship(itemRels, RelType.CustomXmlProps, `itemProps${num}.xml`);
624
+ archive.add(`word/customXml/_rels/item${num}.xml.rels`, renderXml(xml => renderRelationships(itemRels, xml)));
625
625
  // Register content types
626
- contentTypes.addOverride(`/word/customXml/itemProps${num}.xml`, "application/vnd.openxmlformats-officedocument.customXmlProperties+xml");
626
+ addContentTypeOverride(contentTypes, `/word/customXml/itemProps${num}.xml`, "application/vnd.openxmlformats-officedocument.customXmlProperties+xml");
627
627
  // Add to document rels
628
- documentRels.add(RelType.CustomXml, `customXml/item${num}.xml`);
628
+ addRelationship(documentRels, RelType.CustomXml, `customXml/item${num}.xml`);
629
629
  });
630
630
  }
631
631
  // word/theme/theme1.xml
@@ -650,8 +650,8 @@ export async function packageDocx(doc, compressionLevel) {
650
650
  if (hasExtended) {
651
651
  const extXml = renderXml(xml => renderCommentsExtended(xml, doc.comments));
652
652
  archive.add(PartPath.CommentsExtended, extXml);
653
- documentRels.add(RelType.CommentsExtended, "commentsExtended.xml");
654
- contentTypes.addOverride(`/${PartPath.CommentsExtended}`, ContentType.CommentsExtended);
653
+ addRelationship(documentRels, RelType.CommentsExtended, "commentsExtended.xml");
654
+ addContentTypeOverride(contentTypes, `/${PartPath.CommentsExtended}`, ContentType.CommentsExtended);
655
655
  }
656
656
  }
657
657
  // Headers
@@ -664,8 +664,8 @@ export async function packageDocx(doc, compressionLevel) {
664
664
  // Header .rels file
665
665
  const hKey = keys[hIdx];
666
666
  const hRels = headerRelManagers.get(hKey);
667
- if (hRels && hRels.count > 0) {
668
- archive.add(`word/_rels/header${headerIndex}.xml.rels`, renderXml(xml => hRels.render(xml)));
667
+ if (hRels && getRelationshipCount(hRels) > 0) {
668
+ archive.add(`word/_rels/header${headerIndex}.xml.rels`, renderXml(xml => renderRelationships(hRels, xml)));
669
669
  }
670
670
  headerIndex++;
671
671
  hIdx++;
@@ -681,8 +681,8 @@ export async function packageDocx(doc, compressionLevel) {
681
681
  // Footer .rels file
682
682
  const fKey = keys[fIdx];
683
683
  const fRels = footerRelManagers.get(fKey);
684
- if (fRels && fRels.count > 0) {
685
- archive.add(`word/_rels/footer${footerIndex}.xml.rels`, renderXml(xml => fRels.render(xml)));
684
+ if (fRels && getRelationshipCount(fRels) > 0) {
685
+ archive.add(`word/_rels/footer${footerIndex}.xml.rels`, renderXml(xml => renderRelationships(fRels, xml)));
686
686
  }
687
687
  footerIndex++;
688
688
  fIdx++;
@@ -691,8 +691,8 @@ export async function packageDocx(doc, compressionLevel) {
691
691
  // Watermark header
692
692
  if (watermarkHeaderIndex !== undefined && doc.watermark) {
693
693
  archive.add(PartPath.header(watermarkHeaderIndex), renderXml(xml => renderWatermarkHeader(xml, doc.watermark)));
694
- if (watermarkHeaderRels && watermarkHeaderRels.count > 0) {
695
- archive.add(`word/_rels/header${watermarkHeaderIndex}.xml.rels`, renderXml(xml => watermarkHeaderRels.render(xml)));
694
+ if (watermarkHeaderRels && getRelationshipCount(watermarkHeaderRels) > 0) {
695
+ archive.add(`word/_rels/header${watermarkHeaderIndex}.xml.rels`, renderXml(xml => renderRelationships(watermarkHeaderRels, xml)));
696
696
  }
697
697
  }
698
698
  // Media / images
@@ -716,14 +716,14 @@ export async function packageDocx(doc, compressionLevel) {
716
716
  // word/webSettings.xml
717
717
  if (doc.webSettings) {
718
718
  archive.add(PartPath.WebSettings, renderXml(xml => renderWebSettings(xml, doc.webSettings)));
719
- documentRels.add(RelType.WebSettings, "webSettings.xml");
720
- contentTypes.addOverride(`/${PartPath.WebSettings}`, ContentType.WebSettings);
719
+ addRelationship(documentRels, RelType.WebSettings, "webSettings.xml");
720
+ addContentTypeOverride(contentTypes, `/${PartPath.WebSettings}`, ContentType.WebSettings);
721
721
  }
722
722
  // word/people.xml
723
723
  if (doc.people && doc.people.length > 0) {
724
724
  archive.add(PartPath.People, renderXml(xml => renderPeople(xml, doc.people)));
725
- documentRels.add(RelType.People, "people.xml");
726
- contentTypes.addOverride(`/${PartPath.People}`, ContentType.People);
725
+ addRelationship(documentRels, RelType.People, "people.xml");
726
+ addContentTypeOverride(contentTypes, `/${PartPath.People}`, ContentType.People);
727
727
  }
728
728
  // docProps/thumbnail
729
729
  if (doc.thumbnail) {
@@ -735,8 +735,8 @@ export async function packageDocx(doc, compressionLevel) {
735
735
  const thumbPath = `docProps/thumbnail.${ext}`;
736
736
  archive.add(thumbPath, doc.thumbnail.data);
737
737
  // Package rels: target is relative to package root (docProps/thumbnail.jpeg)
738
- packageRels.add("http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail", thumbPath);
739
- contentTypes.addDefault(ext, doc.thumbnail.contentType);
738
+ addRelationship(packageRels, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail", thumbPath);
739
+ addContentTypeDefault(contentTypes, ext, doc.thumbnail.contentType);
740
740
  }
741
741
  // Write opaque (unrecognized) parts for round-trip preservation
742
742
  if (doc.opaqueParts) {
@@ -745,23 +745,23 @@ export async function packageDocx(doc, compressionLevel) {
745
745
  // Register content type: explicit > inferred by extension > skip
746
746
  const ext = part.path.split(".").pop()?.toLowerCase();
747
747
  if (part.contentType) {
748
- contentTypes.addOverride(`/${part.path}`, part.contentType);
748
+ addContentTypeOverride(contentTypes, `/${part.path}`, part.contentType);
749
749
  }
750
750
  else if (ext) {
751
751
  // Infer from common extensions so [Content_Types].xml isn't incomplete
752
752
  const inferred = inferContentType(ext);
753
753
  if (inferred) {
754
- contentTypes.addOverride(`/${part.path}`, inferred);
754
+ addContentTypeOverride(contentTypes, `/${part.path}`, inferred);
755
755
  }
756
756
  }
757
757
  // Write part relationships if any
758
758
  if (part.relationships && part.relationships.length > 0) {
759
- const partRels = new RelationshipManager();
759
+ const partRels = createRelationships();
760
760
  for (const rel of part.relationships) {
761
- partRels.addWithId(rel.id, rel.type, rel.target, rel.targetMode);
761
+ addRelationshipWithId(partRels, rel.id, rel.type, rel.target, rel.targetMode);
762
762
  }
763
763
  const relsPath = getPartRelsPath(part.path);
764
- archive.add(relsPath, renderXml(xml => partRels.render(xml)));
764
+ archive.add(relsPath, renderXml(xml => renderRelationships(partRels, xml)));
765
765
  }
766
766
  }
767
767
  }
@@ -772,12 +772,12 @@ export async function packageDocx(doc, compressionLevel) {
772
772
  // Register chart part
773
773
  archive.add(chartPath, renderXml(xml => renderChartPart(xml, chartContent.chart)));
774
774
  // Register content type
775
- contentTypes.addOverride(`/word/charts/chart${num}.xml`, ContentType.Chart);
775
+ addContentTypeOverride(contentTypes, `/word/charts/chart${num}.xml`, ContentType.Chart);
776
776
  });
777
777
  // LAST: Write [Content_Types].xml and _rels/.rels after all parts have registered
778
778
  // their content types and relationships.
779
- archive.add(PartPath.ContentTypes, renderXml(xml => contentTypes.render(xml)));
780
- archive.add(PartPath.PackageRels, renderXml(xml => packageRels.render(xml)));
779
+ archive.add(PartPath.ContentTypes, renderXml(xml => renderContentTypes(contentTypes, xml)));
780
+ archive.add(PartPath.PackageRels, renderXml(xml => renderRelationships(packageRels, xml)));
781
781
  return archive.bytes();
782
782
  }
783
783
  /** Recursively collect altChunks from body content. */
@@ -5,7 +5,7 @@
5
5
  * Supports paragraphs, runs with formatting, tables, lists, images, hyperlinks,
6
6
  * headings, comments, footnotes/endnotes, and more.
7
7
  */
8
- import { resolveThemeColor } from "./document.js";
8
+ import { resolveThemeColor } from "./color-utils.js";
9
9
  import { bytesToBase64 } from "./internal-utils.js";
10
10
  /**
11
11
  * Convert a DocxDocument to HTML.
@@ -0,0 +1,13 @@
1
+ /**
2
+ * DOCX Module - HTML Renderer (Subpath Export)
3
+ *
4
+ * Import separately to avoid pulling html-renderer into the bundle
5
+ * when only core document building is needed.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { renderToHtml } from "excelts/word/html";
10
+ * ```
11
+ */
12
+ export { renderToHtml } from "./html-renderer.js";
13
+ export type { HtmlRenderOptions, HtmlRenderResult } from "./html-renderer.js";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * DOCX Module - HTML Renderer (Subpath Export)
3
+ *
4
+ * Import separately to avoid pulling html-renderer into the bundle
5
+ * when only core document building is needed.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { renderToHtml } from "excelts/word/html";
10
+ * ```
11
+ */
12
+ export { renderToHtml } from "./html-renderer.js";
@@ -6,14 +6,11 @@
6
6
  export type { HalfPoint, Twips, Emu, EighthPoint, HexColor, ShadingType, BorderStyle, PageOrientation, PageSize, PageMargins, ColumnDef, SectionColumns, SectionBreakType, PageNumberFormat, HeaderFooterType, HeaderFooterRef, PageVerticalAlign, DocumentGridType, PageTextDirection, Border, ArtBorderType, PageBorders, SectionProperties, UnderlineStyle, VerticalAlign, HighlightColor, FontSpec, Shading, UnderlineSpec, TextEffect, EmphasisMarkType, ColorSpec, RunProperties, RunContent, TextContent, BreakContent, TabContent, PositionalTabContent, RubyContent, RubyAlign, RubyProperties, SymbolContent, FootnoteRefContent, EndnoteRefContent, FieldContent, InlineImageContent, CarriageReturnContent, NoBreakHyphenContent, SoftHyphenContent, LastRenderedPageBreakContent, AnnotationReferenceContent, PageNumberType, DateFieldContent, Run, RevisionInfo, InsertedRun, DeletedRun, MovedFromRun, MovedToRun, MoveRangeMarker, CustomXmlTrackingMarker, ParagraphPropertyChange, RunPropertyChange, SectionPropertyChange, TableRowRevision, CommentDef, CommentRangeStart, CommentRangeEnd, CommentReference, Alignment, LineSpacingRule, LineSpacing, Indentation, TabStopType, TabStopLeader, TabStop, PositionalTabAlignment, PositionalTabRelativeTo, PositionalTabLeader, ParagraphBorders, NumberingRef, FrameAnchorType, DropCapType, ParagraphFrame, ParagraphProperties, Paragraph, Hyperlink, BookmarkStart, BookmarkEnd, ParagraphChild, TableWidth, TableBorders, TableCellMargins, TableLayout, TableLook, TableFloat, TableProperties, RowHeightRule, TableRowProperties, VerticalCellAlign, TextDirection, VerticalMerge, TableCellProperties, TableCell, TableRow, Table, HorizontalPositionRelative, VerticalPositionRelative, WrapStyle, WrapTextSide, WrapMargins, FloatingImage, DrawingShape, PresetShapeType, Chart, ChartType, ChartSeries, ChartLegendPosition, ChartAxis, ChartContent, AltChunk, WebSettings, PersonInfo, NoteType, TablePropertyChange, TableRowPropertyChange, TableCellPropertyChange, CellMergeRevision, OpaquePart, OpaqueRelationship, OpaqueDrawing, TableOfContents, MathRun, MathFraction, MathSuperScript, MathSubScript, MathSubSuperScript, MathPreSubSuperScript, MathPhantom, MathGroupChar, MathBorderBox, MathRadical, MathDelimiter, MathNary, MathFunction, MathLimit, MathMatrix, MathAccent, MathBar, MathBox, MathEquationArray, MathContent, MathBlock, TextBox, CheckBox, SdtListItem, SdtDateProperties, SdtProperties, SdtDataBinding, SdtCheckboxProperties, SdtRepeatingSectionProperties, StructuredDocumentTag, CustomXmlPart, BodyContent, StyleType, TableStyleConditionType, TableStyleConditionalFormat, StyleDef, DocDefaults, NumberFormat, LevelJustification, LevelSuffix, NumberingLevel, MultiLevelType, AbstractNumbering, LevelOverride, NumberingInstance, NumPicBullet, HeaderFooterContent, HeaderDef, FooterDef, FootnoteDef, EndnoteDef, ImageMediaType, ImageDef, FontFamily, FontPitch, FontDef, EmbeddedFont, ProtectionType, HyphenationSettings, DocumentSettings, CompatSetting, CompatFlag, DocumentBackground, DocumentTheme, ThemeColorScheme, ThemeFontScheme, ThemeFont, ThemeFormatScheme, ThemeColorName, CustomPropertyValue, CustomProperty, CoreProperties, AppProperties, DocxDocument, DocxOptions } from "./types.js";
7
7
  export { DocxError, DocxParseError, DocxWriteError, DocxMissingPartError, DocxInvalidStructureError, DocxUnsupportedFeatureError, isDocxError } from "./errors.js";
8
8
  export { inchesToTwips, twipsToInches, cmToTwips, twipsToCm, ptToTwips, twipsToPt, mmToTwips, inchesToEmu, emuToInches, cmToEmu, emuToCm, ptToEmu, pxToEmu, emuToPx, ptToHalfPoint, halfPointToPt, ptToEighthPoint, eighthPointToPt, lineMultiplierToSpacing, spacingToLineMultiplier, percentToTablePct, tablePctToPercent } from "./units.js";
9
- export { DocumentBuilder, text, bold, italic, pageBreak, lineBreak, columnBreak, tab, positionalTab, ruby, carriageReturn, noBreakHyphen, softHyphen, field, pageNumberField, totalPagesField, sectionPagesField, sectionField, dateField, sequenceField, timeField, authorField, titleField, subjectField, keywordsField, fileNameField, fileSizeField, styleRefField, refField, pageRefField, noteRefField, hyperlinkField, quoteField, tocField, tcField, indexEntryField, indexField, ifField, includeTextField, includePictureField, formTextField, formCheckboxField, formDropdownField, paragraph, textParagraph, heading, hyperlink, bookmarkStart, bookmarkEnd, commentRangeStart, commentRangeEnd, commentReference, insertedRun, deletedRun, movedFromRun, movedToRun, moveFromRangeStart, moveFromRangeEnd, moveToRangeStart, moveToRangeEnd, checkBox, mathBlock, mathRun, mathFraction, mathSqrt, mathRoot, mathSum, mathIntegral, mathProduct, mathSuperScript, mathSubScript, mathSubSuperScript, mathPreSubSuperScript, mathPhantom, mathGroupChar, mathBorderBox, mathDelimiter, mathNary, mathFunction, mathLimit, mathMatrix, mathAccent, mathBar, mathBox, mathEquationArray, symbol, floatingImage, drawingShape, chart, structuredDocumentTag, border, gridBorders, cell, row, table, simpleTable, searchText, replaceText, resolveThemeColor, patchDocument, mailMerge, paragraphCount, countWords, getHeadings, findBookmark, findComment, listImages, listTables, listHyperlinks, tableCount, extractText } from "./document.js";
10
- export type { SearchResult, PatchContent, PatchOperation, PatchOptions, DocumentHeading } from "./document.js";
9
+ export { Document, text, bold, italic, pageBreak, lineBreak, columnBreak, tab, positionalTab, ruby, carriageReturn, noBreakHyphen, softHyphen, field, pageNumberField, totalPagesField, sectionPagesField, sectionField, dateField, sequenceField, timeField, authorField, titleField, subjectField, keywordsField, fileNameField, fileSizeField, styleRefField, refField, pageRefField, noteRefField, hyperlinkField, quoteField, tocField, tcField, indexEntryField, indexField, ifField, includeTextField, includePictureField, formTextField, formCheckboxField, formDropdownField, paragraph, textParagraph, heading, hyperlink, bookmarkStart, bookmarkEnd, commentRangeStart, commentRangeEnd, commentReference, insertedRun, deletedRun, movedFromRun, movedToRun, moveFromRangeStart, moveFromRangeEnd, moveToRangeStart, moveToRangeEnd, checkBox, mathBlock, mathRun, mathFraction, mathSqrt, mathRoot, mathSum, mathIntegral, mathProduct, mathSuperScript, mathSubScript, mathSubSuperScript, mathPreSubSuperScript, mathPhantom, mathGroupChar, mathBorderBox, mathDelimiter, mathNary, mathFunction, mathLimit, mathMatrix, mathAccent, mathBar, mathBox, mathEquationArray, symbol, floatingImage, drawingShape, chart, structuredDocumentTag, border, gridBorders, cell, row, table, simpleTable, searchText, replaceText, resolveThemeColor, mailMerge, paragraphCount, countWords, getHeadings, findBookmark, findComment, listImages, listTables, listHyperlinks, tableCount, extractText } from "./document.js";
10
+ export type { DocumentHandle, SearchResult, DocumentHeading } from "./document.js";
11
+ export type { PatchContent, PatchOperation, PatchOptions } from "./document-io.js";
11
12
  export { packageDocx } from "./docx-packager.js";
12
13
  export { readDocx } from "./docx-reader.js";
13
- export { deobfuscateFont, obfuscateFont, generateFontKey } from "./font-obfuscation.js";
14
- export { isEncryptedDocx, verifyPassword, decryptPackage, parseEncryptionInfoXml, deriveEncryptionKey, AGILE_BLOCK_KEYS } from "./encryption.js";
15
- export type { AgileEncryptionInfo } from "./encryption.js";
16
- export { hasDigitalSignatures, parseSignatureXml, extractSignatures, isWellFormedSignature } from "./digital-signatures.js";
17
- export type { DigitalSignatureInfo } from "./digital-signatures.js";
18
- export { renderToHtml } from "./html-renderer.js";
19
- export type { HtmlRenderOptions, HtmlRenderResult } from "./html-renderer.js";
14
+ export { toBuffer, toBase64, patchDocument } from "./document-io.js";
15
+ export { Field, Drawing, TrackChanges, Sdt, Query } from "./namespaces.js";
16
+ export { Math as MathML } from "./namespaces.js";
@@ -8,7 +8,7 @@ export { DocxError, DocxParseError, DocxWriteError, DocxMissingPartError, DocxIn
8
8
  // Units
9
9
  export { inchesToTwips, twipsToInches, cmToTwips, twipsToCm, ptToTwips, twipsToPt, mmToTwips, inchesToEmu, emuToInches, cmToEmu, emuToCm, ptToEmu, pxToEmu, emuToPx, ptToHalfPoint, halfPointToPt, ptToEighthPoint, eighthPointToPt, lineMultiplierToSpacing, spacingToLineMultiplier, percentToTablePct, tablePctToPercent } from "./units.js";
10
10
  // Builder helpers
11
- export { DocumentBuilder,
11
+ export { Document,
12
12
  // Run helpers
13
13
  text, bold, italic, pageBreak, lineBreak, columnBreak, tab, positionalTab, ruby, carriageReturn, noBreakHyphen, softHyphen, field, pageNumberField, totalPagesField, sectionPagesField, sectionField, dateField, sequenceField, timeField, authorField, titleField, subjectField, keywordsField, fileNameField, fileSizeField, styleRefField, refField, pageRefField, noteRefField, hyperlinkField, quoteField, tocField, tcField, indexEntryField, indexField, ifField, includeTextField, includePictureField, formTextField, formCheckboxField, formDropdownField,
14
14
  // Paragraph helpers
@@ -34,18 +34,15 @@ chart,
34
34
  // SDT helper
35
35
  structuredDocumentTag,
36
36
  // Table helpers
37
- border, gridBorders, cell, row, table, simpleTable, searchText, replaceText, resolveThemeColor, patchDocument, mailMerge,
37
+ border, gridBorders, cell, row, table, simpleTable, searchText, replaceText, resolveThemeColor, mailMerge,
38
38
  // Query API
39
39
  paragraphCount, countWords, getHeadings, findBookmark, findComment, listImages, listTables, listHyperlinks, tableCount, extractText } from "./document.js";
40
40
  // Packager
41
41
  export { packageDocx } from "./docx-packager.js";
42
42
  // Reader
43
43
  export { readDocx } from "./docx-reader.js";
44
- // Font obfuscation utilities
45
- export { deobfuscateFont, obfuscateFont, generateFontKey } from "./font-obfuscation.js";
46
- // Encryption utilities
47
- export { isEncryptedDocx, verifyPassword, decryptPackage, parseEncryptionInfoXml, deriveEncryptionKey, AGILE_BLOCK_KEYS } from "./encryption.js";
48
- // Digital signature utilities
49
- export { hasDigitalSignatures, parseSignatureXml, extractSignatures, isWellFormedSignature } from "./digital-signatures.js";
50
- // HTML Renderer
51
- export { renderToHtml } from "./html-renderer.js";
44
+ // Document IO (toBuffer, toBase64, patchDocument)
45
+ export { toBuffer, toBase64, patchDocument } from "./document-io.js";
46
+ // Sub-namespaces for grouped API ergonomics (no name conflicts with types)
47
+ export { Field, Drawing, TrackChanges, Sdt, Query } from "./namespaces.js";
48
+ export { Math as MathML } from "./namespaces.js";