@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.
- package/dist/browser/modules/pdf/excel-bridge.js +27 -1
- package/dist/browser/modules/pdf/render/layout-engine.js +74 -9
- package/dist/browser/modules/pdf/render/style-converter.d.ts +1 -1
- package/dist/browser/modules/pdf/render/style-converter.js +98 -1
- package/dist/browser/modules/pdf/types.d.ts +1 -0
- package/dist/browser/modules/word/color-utils.d.ts +18 -0
- package/dist/browser/modules/word/color-utils.js +94 -0
- package/dist/browser/modules/word/content-types.d.ts +15 -15
- package/dist/browser/modules/word/content-types.js +39 -43
- package/dist/browser/modules/word/crypto.d.ts +17 -0
- package/dist/browser/modules/word/crypto.js +18 -0
- package/dist/browser/modules/word/document-io.d.ts +58 -0
- package/dist/browser/modules/word/document-io.js +239 -0
- package/dist/browser/modules/word/document.d.ts +64 -135
- package/dist/browser/modules/word/document.js +207 -469
- package/dist/browser/modules/word/docx-packager.js +90 -90
- package/dist/browser/modules/word/html-renderer.js +1 -1
- package/dist/browser/modules/word/html.d.ts +13 -0
- package/dist/browser/modules/word/html.js +12 -0
- package/dist/browser/modules/word/index.base.d.ts +6 -9
- package/dist/browser/modules/word/index.base.js +7 -10
- package/dist/browser/modules/word/namespaces.d.ts +159 -0
- package/dist/browser/modules/word/namespaces.js +189 -0
- package/dist/browser/modules/word/relationships.d.ts +15 -16
- package/dist/browser/modules/word/relationships.js +37 -45
- package/dist/cjs/modules/pdf/excel-bridge.js +27 -1
- package/dist/cjs/modules/pdf/render/layout-engine.js +74 -9
- package/dist/cjs/modules/pdf/render/style-converter.js +98 -1
- package/dist/cjs/modules/word/color-utils.js +97 -0
- package/dist/cjs/modules/word/content-types.js +44 -45
- package/dist/cjs/modules/word/crypto.js +34 -0
- package/dist/cjs/modules/word/document-io.js +244 -0
- package/dist/cjs/modules/word/document.js +209 -473
- package/dist/cjs/modules/word/docx-packager.js +88 -88
- package/dist/cjs/modules/word/html-renderer.js +2 -2
- package/dist/cjs/modules/word/html.js +16 -0
- package/dist/cjs/modules/word/index.base.js +17 -27
- package/dist/cjs/modules/word/namespaces.js +192 -0
- package/dist/cjs/modules/word/relationships.js +42 -47
- package/dist/esm/modules/pdf/excel-bridge.js +27 -1
- package/dist/esm/modules/pdf/render/layout-engine.js +74 -9
- package/dist/esm/modules/pdf/render/style-converter.js +98 -1
- package/dist/esm/modules/word/color-utils.js +94 -0
- package/dist/esm/modules/word/content-types.js +39 -43
- package/dist/esm/modules/word/crypto.js +18 -0
- package/dist/esm/modules/word/document-io.js +239 -0
- package/dist/esm/modules/word/document.js +207 -469
- package/dist/esm/modules/word/docx-packager.js +90 -90
- package/dist/esm/modules/word/html-renderer.js +1 -1
- package/dist/esm/modules/word/html.js +12 -0
- package/dist/esm/modules/word/index.base.js +7 -10
- package/dist/esm/modules/word/namespaces.js +189 -0
- package/dist/esm/modules/word/relationships.js +37 -45
- package/dist/iife/excelts.iife.js +153 -11
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +4 -4
- package/dist/types/modules/pdf/render/style-converter.d.ts +1 -1
- package/dist/types/modules/pdf/types.d.ts +1 -0
- package/dist/types/modules/word/color-utils.d.ts +18 -0
- package/dist/types/modules/word/content-types.d.ts +15 -15
- package/dist/types/modules/word/crypto.d.ts +17 -0
- package/dist/types/modules/word/document-io.d.ts +58 -0
- package/dist/types/modules/word/document.d.ts +64 -135
- package/dist/types/modules/word/html.d.ts +13 -0
- package/dist/types/modules/word/index.base.d.ts +6 -9
- package/dist/types/modules/word/namespaces.d.ts +159 -0
- package/dist/types/modules/word/relationships.d.ts +15 -16
- 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 {
|
|
13
|
-
import {
|
|
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 =
|
|
206
|
-
const packageRels =
|
|
207
|
-
const documentRels =
|
|
205
|
+
const contentTypes = createContentTypes();
|
|
206
|
+
const packageRels = createRelationships();
|
|
207
|
+
const documentRels = createRelationships();
|
|
208
208
|
// --- Package relationships ---
|
|
209
|
-
packageRels
|
|
210
|
-
packageRels
|
|
211
|
-
packageRels
|
|
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
|
|
215
|
+
addRelationship(packageRels, RelType.CustomProperties, "docProps/custom.xml");
|
|
216
216
|
}
|
|
217
217
|
// --- Document relationships ---
|
|
218
|
-
documentRels
|
|
219
|
-
documentRels
|
|
220
|
-
documentRels
|
|
221
|
-
documentRels
|
|
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
|
|
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
|
|
232
|
+
addRelationship(documentRels, RelType.Footnotes, "footnotes.xml");
|
|
233
233
|
}
|
|
234
234
|
if (hasEndnotes) {
|
|
235
|
-
documentRels
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
370
|
+
const rId = addRelationship(documentRels, RelType.Header, `header${headerIndex}.xml`);
|
|
371
371
|
headerDef.rId = rId;
|
|
372
|
-
// Create per-header relationship
|
|
373
|
-
const hRels =
|
|
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
|
|
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
|
|
388
|
+
const linkRId = addRelationship(hRels, RelType.Hyperlink, link.url, "External");
|
|
389
389
|
link.rId = linkRId;
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
|
-
if (hRels
|
|
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
|
|
403
|
+
const rId = addRelationship(documentRels, RelType.Footer, `footer${footerIndex}.xml`);
|
|
404
404
|
footerDef.rId = rId;
|
|
405
|
-
// Create per-footer relationship
|
|
406
|
-
const fRels =
|
|
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
|
|
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
|
|
420
|
+
const linkRId = addRelationship(fRels, RelType.Hyperlink, link.url, "External");
|
|
421
421
|
link.rId = linkRId;
|
|
422
422
|
}
|
|
423
423
|
}
|
|
424
|
-
if (fRels
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
453
|
-
contentTypes
|
|
454
|
-
contentTypes
|
|
455
|
-
contentTypes
|
|
456
|
-
contentTypes
|
|
457
|
-
contentTypes
|
|
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
|
|
459
|
+
addContentTypeOverride(contentTypes, PartPath.Numbering, ContentType.Numbering);
|
|
460
460
|
}
|
|
461
461
|
if (hasFootnotes) {
|
|
462
|
-
contentTypes
|
|
462
|
+
addContentTypeOverride(contentTypes, PartPath.Footnotes, ContentType.Footnotes);
|
|
463
463
|
}
|
|
464
464
|
if (hasEndnotes) {
|
|
465
|
-
contentTypes
|
|
465
|
+
addContentTypeOverride(contentTypes, PartPath.Endnotes, ContentType.Endnotes);
|
|
466
466
|
}
|
|
467
467
|
if (hasComments) {
|
|
468
|
-
contentTypes
|
|
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
|
|
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
|
|
480
|
+
addContentTypeOverride(contentTypes, PartPath.footer(footerIndex), ContentType.Footer);
|
|
481
481
|
footerIndex++;
|
|
482
482
|
}
|
|
483
483
|
}
|
|
484
484
|
if (watermarkHeaderIndex !== undefined) {
|
|
485
|
-
contentTypes
|
|
485
|
+
addContentTypeOverride(contentTypes, PartPath.header(watermarkHeaderIndex), ContentType.Header);
|
|
486
486
|
}
|
|
487
|
-
contentTypes
|
|
488
|
-
contentTypes
|
|
487
|
+
addContentTypeOverride(contentTypes, PartPath.CoreProps, ContentType.CoreProperties);
|
|
488
|
+
addContentTypeOverride(contentTypes, PartPath.AppProps, ContentType.ExtendedProperties);
|
|
489
489
|
if (hasCustomProps) {
|
|
490
|
-
contentTypes
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
581
|
+
addContentTypeDefault(contentTypes, "odttf", ContentType.ObfuscatedFont);
|
|
582
582
|
}
|
|
583
583
|
else if (ext === "ttf") {
|
|
584
|
-
contentTypes
|
|
584
|
+
addContentTypeDefault(contentTypes, "ttf", "application/x-font-ttf");
|
|
585
585
|
}
|
|
586
586
|
else if (ext === "otf") {
|
|
587
|
-
contentTypes
|
|
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
|
|
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 =
|
|
623
|
-
itemRels
|
|
624
|
-
archive.add(`word/customXml/_rels/item${num}.xml.rels`, renderXml(xml => itemRels
|
|
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
|
|
626
|
+
addContentTypeOverride(contentTypes, `/word/customXml/itemProps${num}.xml`, "application/vnd.openxmlformats-officedocument.customXmlProperties+xml");
|
|
627
627
|
// Add to document rels
|
|
628
|
-
documentRels
|
|
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
|
|
654
|
-
contentTypes
|
|
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
|
|
668
|
-
archive.add(`word/_rels/header${headerIndex}.xml.rels`, renderXml(xml => hRels
|
|
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
|
|
685
|
-
archive.add(`word/_rels/footer${footerIndex}.xml.rels`, renderXml(xml => fRels
|
|
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
|
|
695
|
-
archive.add(`word/_rels/header${watermarkHeaderIndex}.xml.rels`, renderXml(xml => watermarkHeaderRels
|
|
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
|
|
720
|
-
contentTypes
|
|
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
|
|
726
|
-
contentTypes
|
|
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
|
|
739
|
-
contentTypes
|
|
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
|
|
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
|
|
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 =
|
|
759
|
+
const partRels = createRelationships();
|
|
760
760
|
for (const rel of part.relationships) {
|
|
761
|
-
partRels
|
|
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
|
|
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
|
|
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
|
|
780
|
-
archive.add(PartPath.PackageRels, renderXml(xml => packageRels
|
|
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 "./
|
|
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,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";
|
|
@@ -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 {
|
|
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,
|
|
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
|
-
//
|
|
45
|
-
export {
|
|
46
|
-
//
|
|
47
|
-
export {
|
|
48
|
-
|
|
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";
|