docxmlater 10.3.5 → 10.4.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.
- package/README.md +158 -7
- package/dist/core/Document.d.ts +102 -3
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +775 -50
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentContent.d.ts.map +1 -1
- package/dist/core/DocumentContent.js +0 -8
- package/dist/core/DocumentContent.js.map +1 -1
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +9 -5
- package/dist/core/DocumentGenerator.js.map +1 -1
- package/dist/core/DocumentParser.d.ts.map +1 -1
- package/dist/core/DocumentParser.js +588 -102
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +4 -3
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/Bookmark.d.ts +7 -0
- package/dist/elements/Bookmark.d.ts.map +1 -1
- package/dist/elements/Bookmark.js +24 -4
- package/dist/elements/Bookmark.js.map +1 -1
- package/dist/elements/BookmarkManager.d.ts.map +1 -1
- package/dist/elements/BookmarkManager.js +4 -3
- package/dist/elements/BookmarkManager.js.map +1 -1
- package/dist/elements/CommonTypes.d.ts +2 -2
- package/dist/elements/CommonTypes.d.ts.map +1 -1
- package/dist/elements/CommonTypes.js +14 -1
- package/dist/elements/CommonTypes.js.map +1 -1
- package/dist/elements/Field.d.ts +1 -1
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +1 -1
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/Footer.d.ts +2 -0
- package/dist/elements/Footer.d.ts.map +1 -1
- package/dist/elements/Footer.js +6 -0
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/Header.d.ts +2 -0
- package/dist/elements/Header.d.ts.map +1 -1
- package/dist/elements/Header.js +6 -0
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/Image.d.ts +1 -0
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +17 -2
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/Paragraph.d.ts +81 -1
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +515 -21
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/Revision.d.ts +0 -1
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +0 -12
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/RevisionManager.d.ts +0 -1
- package/dist/elements/RevisionManager.d.ts.map +1 -1
- package/dist/elements/RevisionManager.js +0 -2
- package/dist/elements/RevisionManager.js.map +1 -1
- package/dist/elements/Run.d.ts +16 -4
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +114 -22
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts +7 -1
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +185 -4
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/Table.d.ts +30 -1
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +357 -40
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +3 -0
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +30 -3
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableGridChange.d.ts +0 -1
- package/dist/elements/TableGridChange.d.ts.map +1 -1
- package/dist/elements/TableGridChange.js +0 -10
- package/dist/elements/TableGridChange.js.map +1 -1
- package/dist/elements/TableRow.d.ts +4 -0
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +31 -3
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/formatting/AbstractNumbering.d.ts +5 -0
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +22 -0
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +3 -3
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/Style.d.ts +1 -0
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +25 -59
- package/dist/formatting/Style.js.map +1 -1
- package/dist/formatting/StylesManager.d.ts +1 -0
- package/dist/formatting/StylesManager.d.ts.map +1 -1
- package/dist/formatting/StylesManager.js +12 -0
- package/dist/formatting/StylesManager.js.map +1 -1
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/images/ImageOptimizer.d.ts.map +1 -1
- package/dist/images/ImageOptimizer.js +0 -1
- package/dist/images/ImageOptimizer.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/managers/DrawingManager.d.ts.map +1 -1
- package/dist/managers/DrawingManager.js +4 -2
- package/dist/managers/DrawingManager.js.map +1 -1
- package/dist/types/formatting.d.ts +2 -2
- package/dist/types/formatting.d.ts.map +1 -1
- package/dist/types/formatting.js.map +1 -1
- package/dist/utils/ChangelogGenerator.d.ts +2 -2
- package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
- package/dist/utils/ChangelogGenerator.js +4 -5
- package/dist/utils/ChangelogGenerator.js.map +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.d.ts.map +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.js +0 -1
- package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/utils/RevisionAwareProcessor.d.ts +2 -2
- package/dist/utils/RevisionAwareProcessor.d.ts.map +1 -1
- package/dist/utils/RevisionAwareProcessor.js +2 -2
- package/dist/utils/RevisionAwareProcessor.js.map +1 -1
- package/dist/utils/SelectiveRevisionAcceptor.d.ts +0 -2
- package/dist/utils/SelectiveRevisionAcceptor.d.ts.map +1 -1
- package/dist/utils/SelectiveRevisionAcceptor.js +0 -26
- package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/utils/ShadingResolver.d.ts.map +1 -1
- package/dist/utils/ShadingResolver.js.map +1 -1
- package/dist/utils/acceptRevisions.js +1 -1
- package/dist/utils/acceptRevisions.js.map +1 -1
- package/dist/utils/stripTrackedChanges.js +1 -1
- package/dist/utils/stripTrackedChanges.js.map +1 -1
- package/dist/utils/units.d.ts.map +1 -1
- package/dist/utils/units.js +1 -1
- package/dist/utils/units.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.d.ts +2 -1
- package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/package.json +10 -1
- package/src/constants/CLAUDE.md +28 -0
- package/src/core/CLAUDE.md +4 -0
- package/src/core/Document.ts +1888 -137
- package/src/core/DocumentContent.ts +0 -11
- package/src/core/DocumentGenerator.ts +11 -12
- package/src/core/DocumentParser.ts +620 -139
- package/src/core/RelationshipManager.ts +6 -3
- package/src/elements/Bookmark.ts +39 -4
- package/src/elements/BookmarkManager.ts +4 -3
- package/src/elements/CLAUDE.md +18 -2
- package/src/elements/CommonTypes.ts +35 -8
- package/src/elements/Field.ts +1 -1
- package/src/elements/Footer.ts +23 -0
- package/src/elements/Header.ts +25 -0
- package/src/elements/Image.ts +28 -5
- package/src/elements/Paragraph.ts +1069 -41
- package/src/elements/Revision.ts +0 -19
- package/src/elements/RevisionManager.ts +1 -3
- package/src/elements/Run.ts +265 -35
- package/src/elements/Section.ts +214 -8
- package/src/elements/Shape.ts +1 -1
- package/src/elements/Table.ts +850 -61
- package/src/elements/TableCell.ts +84 -10
- package/src/elements/TableGridChange.ts +2 -16
- package/src/elements/TableRow.ts +94 -9
- package/src/formatting/AbstractNumbering.ts +42 -1
- package/src/formatting/CLAUDE.md +4 -0
- package/src/formatting/NumberingLevel.ts +11 -7
- package/src/formatting/Style.ts +39 -71
- package/src/formatting/StylesManager.ts +36 -0
- package/src/helpers/CleanupHelper.ts +1 -1
- package/src/images/ImageOptimizer.ts +0 -3
- package/src/index.ts +1 -1
- package/src/managers/DrawingManager.ts +5 -3
- package/src/tracking/CLAUDE.md +30 -0
- package/src/types/CLAUDE.md +39 -0
- package/src/types/formatting.ts +2 -2
- package/src/utils/CLAUDE.md +15 -0
- package/src/utils/ChangelogGenerator.ts +4 -5
- package/src/utils/InMemoryRevisionAcceptor.ts +0 -9
- package/src/utils/RevisionAwareProcessor.ts +2 -3
- package/src/utils/SelectiveRevisionAcceptor.ts +0 -39
- package/src/utils/ShadingResolver.ts +0 -1
- package/src/utils/acceptRevisions.ts +1 -1
- package/src/utils/stripTrackedChanges.ts +1 -1
- package/src/utils/units.ts +2 -1
- package/src/validation/CLAUDE.md +40 -0
- package/src/validation/RevisionAutoFixer.ts +2 -1
package/dist/core/Document.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.Document = void 0;
|
|
37
37
|
const Bookmark_1 = require("../elements/Bookmark");
|
|
38
38
|
const BookmarkManager_1 = require("../elements/BookmarkManager");
|
|
39
|
+
const PreservedElement_1 = require("../elements/PreservedElement");
|
|
39
40
|
const CommentManager_1 = require("../elements/CommentManager");
|
|
40
41
|
const EndnoteManager_1 = require("../elements/EndnoteManager");
|
|
41
42
|
const Field_1 = require("../elements/Field");
|
|
@@ -155,7 +156,6 @@ class Document {
|
|
|
155
156
|
showInkAnnotations: true,
|
|
156
157
|
};
|
|
157
158
|
autoPopulateTOCs = false;
|
|
158
|
-
autoSyncTOCStyles = false;
|
|
159
159
|
skipDocumentXmlRegeneration = false;
|
|
160
160
|
acceptRevisionsBeforeSave = false;
|
|
161
161
|
_originalContentTypes;
|
|
@@ -243,6 +243,128 @@ class Document {
|
|
|
243
243
|
doc.initializeRequiredFiles();
|
|
244
244
|
return doc;
|
|
245
245
|
}
|
|
246
|
+
static fromMarkdown(markdown, options) {
|
|
247
|
+
const doc = Document.create(options);
|
|
248
|
+
const lines = markdown.split('\n');
|
|
249
|
+
let i = 0;
|
|
250
|
+
while (i < lines.length) {
|
|
251
|
+
const line = lines[i];
|
|
252
|
+
if (line.trim() === '') {
|
|
253
|
+
i++;
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (/^\s{0,3}([-]{3,}|[*]{3,}|[_]{3,})\s*$/.test(line)) {
|
|
257
|
+
doc.addHorizontalRule();
|
|
258
|
+
i++;
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const headingMatch = /^(#{1,6})\s+(.+)$/.exec(line);
|
|
262
|
+
if (headingMatch) {
|
|
263
|
+
const level = headingMatch[1].length;
|
|
264
|
+
const text = headingMatch[2];
|
|
265
|
+
const para = doc.addHeading('', level);
|
|
266
|
+
Document.applyInlineMarkdown(para, text);
|
|
267
|
+
i++;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (line.trimStart().startsWith('|')) {
|
|
271
|
+
const tableLines = [];
|
|
272
|
+
while (i < lines.length && lines[i].trimStart().startsWith('|')) {
|
|
273
|
+
tableLines.push(lines[i]);
|
|
274
|
+
i++;
|
|
275
|
+
}
|
|
276
|
+
const table = Document.parseMarkdownTable(tableLines);
|
|
277
|
+
if (table) {
|
|
278
|
+
doc.addTable(table);
|
|
279
|
+
}
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
const bulletMatch = /^(\s*)[-*+]\s+(.+)$/.exec(line);
|
|
283
|
+
if (bulletMatch) {
|
|
284
|
+
const text = bulletMatch[2];
|
|
285
|
+
const para = doc.createParagraph();
|
|
286
|
+
Document.applyInlineMarkdown(para, text);
|
|
287
|
+
para.setStyle('ListBullet');
|
|
288
|
+
i++;
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const numberMatch = /^(\s*)\d+[.)]\s+(.+)$/.exec(line);
|
|
292
|
+
if (numberMatch) {
|
|
293
|
+
const text = numberMatch[2];
|
|
294
|
+
const para = doc.createParagraph();
|
|
295
|
+
Document.applyInlineMarkdown(para, text);
|
|
296
|
+
para.setStyle('ListNumber');
|
|
297
|
+
i++;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const paraLines = [line];
|
|
301
|
+
i++;
|
|
302
|
+
while (i < lines.length &&
|
|
303
|
+
lines[i].trim() !== '' &&
|
|
304
|
+
!lines[i].trim().startsWith('#') &&
|
|
305
|
+
!lines[i].trim().startsWith('|') &&
|
|
306
|
+
!/^\s{0,3}([-]{3,}|[*]{3,}|[_]{3,})\s*$/.test(lines[i]) &&
|
|
307
|
+
!/^(\s*)[-*+]\s+/.test(lines[i]) &&
|
|
308
|
+
!/^(\s*)\d+[.)]\s+/.test(lines[i])) {
|
|
309
|
+
paraLines.push(lines[i]);
|
|
310
|
+
i++;
|
|
311
|
+
}
|
|
312
|
+
const para = doc.createParagraph();
|
|
313
|
+
Document.applyInlineMarkdown(para, paraLines.join(' '));
|
|
314
|
+
}
|
|
315
|
+
return doc;
|
|
316
|
+
}
|
|
317
|
+
static applyInlineMarkdown(para, text) {
|
|
318
|
+
const inlinePattern = /(\*\*\*(.+?)\*\*\*|\*\*(.+?)\*\*|\*(.+?)\*|~~(.+?)~~|`([^`]+)`|\[([^\]]+)\]\(([^)]+)\))/g;
|
|
319
|
+
let lastIndex = 0;
|
|
320
|
+
let match;
|
|
321
|
+
while ((match = inlinePattern.exec(text)) !== null) {
|
|
322
|
+
if (match.index > lastIndex) {
|
|
323
|
+
para.addText(text.slice(lastIndex, match.index));
|
|
324
|
+
}
|
|
325
|
+
if (match[2] !== undefined) {
|
|
326
|
+
para.addText(match[2], { bold: true, italic: true });
|
|
327
|
+
}
|
|
328
|
+
else if (match[3] !== undefined) {
|
|
329
|
+
para.addText(match[3], { bold: true });
|
|
330
|
+
}
|
|
331
|
+
else if (match[4] !== undefined) {
|
|
332
|
+
para.addText(match[4], { italic: true });
|
|
333
|
+
}
|
|
334
|
+
else if (match[5] !== undefined) {
|
|
335
|
+
para.addText(match[5], { strike: true });
|
|
336
|
+
}
|
|
337
|
+
else if (match[6] !== undefined) {
|
|
338
|
+
para.addText(match[6], { font: 'Courier New' });
|
|
339
|
+
}
|
|
340
|
+
else if (match[7] !== undefined && match[8] !== undefined) {
|
|
341
|
+
para.addHyperlink(new Hyperlink_1.Hyperlink({ url: match[8], text: match[7] }));
|
|
342
|
+
}
|
|
343
|
+
lastIndex = match.index + match[0].length;
|
|
344
|
+
}
|
|
345
|
+
if (lastIndex < text.length) {
|
|
346
|
+
para.addText(text.slice(lastIndex));
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
static parseMarkdownTable(lines) {
|
|
350
|
+
if (lines.length < 2)
|
|
351
|
+
return null;
|
|
352
|
+
const parseRow = (line) => line
|
|
353
|
+
.replace(/^\|/, '')
|
|
354
|
+
.replace(/\|$/, '')
|
|
355
|
+
.split('|')
|
|
356
|
+
.map((cell) => cell.trim());
|
|
357
|
+
const rows = [];
|
|
358
|
+
for (let i = 0; i < lines.length; i++) {
|
|
359
|
+
const cells = parseRow(lines[i]);
|
|
360
|
+
if (cells.every((c) => /^:?-+:?$/.test(c)))
|
|
361
|
+
continue;
|
|
362
|
+
rows.push(cells);
|
|
363
|
+
}
|
|
364
|
+
if (rows.length === 0)
|
|
365
|
+
return null;
|
|
366
|
+
return Table_1.Table.fromArray(rows);
|
|
367
|
+
}
|
|
246
368
|
static async load(filePath, options) {
|
|
247
369
|
const logger = getLogger();
|
|
248
370
|
logger.info('Loading document from file', { path: filePath });
|
|
@@ -732,6 +854,21 @@ class Document {
|
|
|
732
854
|
this.bodyElements.push(para);
|
|
733
855
|
return para;
|
|
734
856
|
}
|
|
857
|
+
addHeading(text, level = 1) {
|
|
858
|
+
return this.createParagraph(text).setStyle(`Heading${level}`);
|
|
859
|
+
}
|
|
860
|
+
addPageBreak() {
|
|
861
|
+
const para = this.createParagraph();
|
|
862
|
+
const run = new Run_1.Run('');
|
|
863
|
+
run.addBreak('page');
|
|
864
|
+
para.addRun(run);
|
|
865
|
+
return para;
|
|
866
|
+
}
|
|
867
|
+
addHorizontalRule(color = 'auto', size = 4) {
|
|
868
|
+
const para = this.createParagraph();
|
|
869
|
+
para.setBorder({ bottom: { style: 'single', size, color, space: 1 } });
|
|
870
|
+
return para;
|
|
871
|
+
}
|
|
735
872
|
addTable(table) {
|
|
736
873
|
table._setStylesManager(this.stylesManager);
|
|
737
874
|
if (this.trackChangesEnabled && this.trackingContext.isEnabled()) {
|
|
@@ -750,6 +887,12 @@ class Document {
|
|
|
750
887
|
this.bodyElements.push(table);
|
|
751
888
|
return table;
|
|
752
889
|
}
|
|
890
|
+
createTableFromCSV(csv, delimiter = ',') {
|
|
891
|
+
const table = Table_1.Table.fromCSV(csv, delimiter);
|
|
892
|
+
table._setStylesManager(this.stylesManager);
|
|
893
|
+
this.bodyElements.push(table);
|
|
894
|
+
return table;
|
|
895
|
+
}
|
|
753
896
|
getTables() {
|
|
754
897
|
return this.bodyElements.filter((el) => el instanceof Table_1.Table);
|
|
755
898
|
}
|
|
@@ -1007,7 +1150,7 @@ class Document {
|
|
|
1007
1150
|
await fs.unlink(tempPath);
|
|
1008
1151
|
}
|
|
1009
1152
|
catch (cleanupErr) {
|
|
1010
|
-
logger.
|
|
1153
|
+
logger.warn('Failed to clean up temp file', { tempPath, error: String(cleanupErr) });
|
|
1011
1154
|
}
|
|
1012
1155
|
throw error;
|
|
1013
1156
|
}
|
|
@@ -1049,6 +1192,22 @@ class Document {
|
|
|
1049
1192
|
}
|
|
1050
1193
|
}
|
|
1051
1194
|
}
|
|
1195
|
+
async toBase64() {
|
|
1196
|
+
const buffer = await this.toBuffer();
|
|
1197
|
+
return buffer.toString('base64');
|
|
1198
|
+
}
|
|
1199
|
+
async toDataUri() {
|
|
1200
|
+
const base64 = await this.toBase64();
|
|
1201
|
+
return `data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,${base64}`;
|
|
1202
|
+
}
|
|
1203
|
+
static async loadFromBase64(base64, options) {
|
|
1204
|
+
const buffer = Buffer.from(base64, 'base64');
|
|
1205
|
+
return Document.loadFromBuffer(buffer, options);
|
|
1206
|
+
}
|
|
1207
|
+
async clone() {
|
|
1208
|
+
const buffer = await this.toBuffer();
|
|
1209
|
+
return Document.loadFromBuffer(buffer);
|
|
1210
|
+
}
|
|
1052
1211
|
updateDocumentXml() {
|
|
1053
1212
|
let xml = this.generator.generateDocumentXml(this.bodyElements, this.section, this.namespaces, this._documentBackground);
|
|
1054
1213
|
xml = this.syncTOCFieldInstructions(xml);
|
|
@@ -2181,7 +2340,6 @@ class Document {
|
|
|
2181
2340
|
left: options?.cellMargins?.left ?? 115,
|
|
2182
2341
|
right: options?.cellMargins?.right ?? 115,
|
|
2183
2342
|
};
|
|
2184
|
-
const skipSingleCellTables = options?.skipSingleCellTables !== false && !singleCellShading;
|
|
2185
2343
|
let tablesProcessed = 0;
|
|
2186
2344
|
let headerRowsFormatted = 0;
|
|
2187
2345
|
let cellsRecolored = 0;
|
|
@@ -2584,6 +2742,19 @@ class Document {
|
|
|
2584
2742
|
}
|
|
2585
2743
|
const registeredSet = new Set(existingRevisions);
|
|
2586
2744
|
let docPrId = 1;
|
|
2745
|
+
const existingParaIds = new Set();
|
|
2746
|
+
const paragraphsNeedingIds = [];
|
|
2747
|
+
const generateUniqueParaId = () => {
|
|
2748
|
+
let id;
|
|
2749
|
+
do {
|
|
2750
|
+
id = Math.floor(Math.random() * 0x7fffffff + 1)
|
|
2751
|
+
.toString(16)
|
|
2752
|
+
.toUpperCase()
|
|
2753
|
+
.padStart(8, '0');
|
|
2754
|
+
} while (existingParaIds.has(id));
|
|
2755
|
+
existingParaIds.add(id);
|
|
2756
|
+
return id;
|
|
2757
|
+
};
|
|
2587
2758
|
const processParagraph = (para) => {
|
|
2588
2759
|
for (const rev of para.getRevisions()) {
|
|
2589
2760
|
if (!registeredSet.has(rev)) {
|
|
@@ -2603,6 +2774,12 @@ class Document {
|
|
|
2603
2774
|
item.getImageElement().setDocPrId(docPrId++);
|
|
2604
2775
|
}
|
|
2605
2776
|
}
|
|
2777
|
+
if (para.formatting.paraId) {
|
|
2778
|
+
existingParaIds.add(para.formatting.paraId);
|
|
2779
|
+
}
|
|
2780
|
+
else {
|
|
2781
|
+
paragraphsNeedingIds.push(para);
|
|
2782
|
+
}
|
|
2606
2783
|
};
|
|
2607
2784
|
for (const element of this.bodyElements) {
|
|
2608
2785
|
if (element instanceof Paragraph_1.Paragraph) {
|
|
@@ -2618,6 +2795,12 @@ class Document {
|
|
|
2618
2795
|
}
|
|
2619
2796
|
}
|
|
2620
2797
|
}
|
|
2798
|
+
for (const para of paragraphsNeedingIds) {
|
|
2799
|
+
para.formatting.paraId = generateUniqueParaId();
|
|
2800
|
+
if (!para.formatting.textId) {
|
|
2801
|
+
para.formatting.textId = generateUniqueParaId();
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2621
2804
|
}
|
|
2622
2805
|
getLastParagraph() {
|
|
2623
2806
|
for (let i = this.bodyElements.length - 1; i >= 0; i--) {
|
|
@@ -2820,6 +3003,30 @@ class Document {
|
|
|
2820
3003
|
createMultiLevelList() {
|
|
2821
3004
|
return this.numberingManager.createMultiLevelList();
|
|
2822
3005
|
}
|
|
3006
|
+
addBulletListFromArray(items, formatting) {
|
|
3007
|
+
if (items.length === 0)
|
|
3008
|
+
return [];
|
|
3009
|
+
const numId = this.createBulletList();
|
|
3010
|
+
return this.addListItems(numId, items, formatting);
|
|
3011
|
+
}
|
|
3012
|
+
addNumberedListFromArray(items, formatting) {
|
|
3013
|
+
if (items.length === 0)
|
|
3014
|
+
return [];
|
|
3015
|
+
const numId = this.createNumberedList();
|
|
3016
|
+
return this.addListItems(numId, items, formatting);
|
|
3017
|
+
}
|
|
3018
|
+
addListItems(numId, items, formatting) {
|
|
3019
|
+
const paragraphs = [];
|
|
3020
|
+
for (const item of items) {
|
|
3021
|
+
const text = typeof item === 'string' ? item : item.text;
|
|
3022
|
+
const level = typeof item === 'string' ? 0 : (item.level ?? 0);
|
|
3023
|
+
const para = this.createParagraph();
|
|
3024
|
+
para.addText(text, formatting);
|
|
3025
|
+
para.setNumbering(numId, level);
|
|
3026
|
+
paragraphs.push(para);
|
|
3027
|
+
}
|
|
3028
|
+
return paragraphs;
|
|
3029
|
+
}
|
|
2823
3030
|
restartNumbering(numId, level, startValue) {
|
|
2824
3031
|
return this.numberingManager.restartNumbering(numId, level, startValue);
|
|
2825
3032
|
}
|
|
@@ -3773,12 +3980,12 @@ class Document {
|
|
|
3773
3980
|
}
|
|
3774
3981
|
let updateCount = 0;
|
|
3775
3982
|
const fillPattern = new RegExp(`(w:fill=["'])${normalizedOld}(["'])`, 'gi');
|
|
3776
|
-
stylesXml = stylesXml.replace(fillPattern, (
|
|
3983
|
+
stylesXml = stylesXml.replace(fillPattern, (_match, prefix, suffix) => {
|
|
3777
3984
|
updateCount++;
|
|
3778
3985
|
return `${prefix}${normalizedNew}${suffix}`;
|
|
3779
3986
|
});
|
|
3780
3987
|
const colorPattern = new RegExp(`(<w:shd[^>]*w:color=["'])${normalizedOld}(["'])`, 'gi');
|
|
3781
|
-
stylesXml = stylesXml.replace(colorPattern, (
|
|
3988
|
+
stylesXml = stylesXml.replace(colorPattern, (_match, prefix, suffix) => {
|
|
3782
3989
|
updateCount++;
|
|
3783
3990
|
return `${prefix}${normalizedNew}${suffix}`;
|
|
3784
3991
|
});
|
|
@@ -3804,21 +4011,6 @@ class Document {
|
|
|
3804
4011
|
}
|
|
3805
4012
|
return totalUpdated;
|
|
3806
4013
|
}
|
|
3807
|
-
processConsecutiveBlanks(blanks, keepOne, toRemove) {
|
|
3808
|
-
if (blanks.length === 0)
|
|
3809
|
-
return;
|
|
3810
|
-
if (keepOne && blanks.length > 1) {
|
|
3811
|
-
for (let i = 1; i < blanks.length; i++) {
|
|
3812
|
-
const blank = blanks[i];
|
|
3813
|
-
if (blank) {
|
|
3814
|
-
toRemove.push(blank);
|
|
3815
|
-
}
|
|
3816
|
-
}
|
|
3817
|
-
}
|
|
3818
|
-
else if (!keepOne) {
|
|
3819
|
-
toRemove.push(...blanks);
|
|
3820
|
-
}
|
|
3821
|
-
}
|
|
3822
4014
|
standardizeBulletSymbols(options) {
|
|
3823
4015
|
const { bold = false, fontSize = 24, color = '000000', font = 'Arial', } = options || {};
|
|
3824
4016
|
let listsUpdated = 0;
|
|
@@ -4108,7 +4300,6 @@ class Document {
|
|
|
4108
4300
|
parseTOCFieldInstruction(instrText) {
|
|
4109
4301
|
const levels = new Set();
|
|
4110
4302
|
let hasOutlineSwitch = false;
|
|
4111
|
-
let hasTableSwitch = false;
|
|
4112
4303
|
const normalizedText = instrText.trim().replace(/"/g, '"');
|
|
4113
4304
|
const outlineMatch = /\\o\s+(?:"(\d+)-(\d+)"|'(\d+)-(\d+)'|(\d+)-(\d+))/.exec(normalizedText);
|
|
4114
4305
|
if (outlineMatch) {
|
|
@@ -4132,7 +4323,6 @@ class Document {
|
|
|
4132
4323
|
const tSwitchRegex = /\\t\s+"([^"]*)"/g;
|
|
4133
4324
|
const tMatches = [...normalizedText.matchAll(tSwitchRegex)];
|
|
4134
4325
|
for (const match of tMatches) {
|
|
4135
|
-
hasTableSwitch = true;
|
|
4136
4326
|
const content = (match[1] || '').trim();
|
|
4137
4327
|
if (!content)
|
|
4138
4328
|
continue;
|
|
@@ -4479,34 +4669,6 @@ class Document {
|
|
|
4479
4669
|
}
|
|
4480
4670
|
return headings;
|
|
4481
4671
|
}
|
|
4482
|
-
findHeadingsForTOC(levels) {
|
|
4483
|
-
const headings = [];
|
|
4484
|
-
const levelSet = new Set(levels);
|
|
4485
|
-
for (const element of this.bodyElements) {
|
|
4486
|
-
if (element instanceof Paragraph_1.Paragraph) {
|
|
4487
|
-
const para = element;
|
|
4488
|
-
const formatting = para.getFormatting();
|
|
4489
|
-
if (formatting.style) {
|
|
4490
|
-
const styleMatch = /Heading\s*(\d+)/i.exec(formatting.style);
|
|
4491
|
-
if (styleMatch?.[1]) {
|
|
4492
|
-
const headingLevel = parseInt(styleMatch[1], 10);
|
|
4493
|
-
if (levelSet.has(headingLevel)) {
|
|
4494
|
-
const text = para.getText().trim();
|
|
4495
|
-
if (text) {
|
|
4496
|
-
const bookmark = this.bookmarkManager.createHeadingBookmark(text);
|
|
4497
|
-
headings.push({
|
|
4498
|
-
level: headingLevel,
|
|
4499
|
-
text: text,
|
|
4500
|
-
bookmark: bookmark.getName(),
|
|
4501
|
-
});
|
|
4502
|
-
}
|
|
4503
|
-
}
|
|
4504
|
-
}
|
|
4505
|
-
}
|
|
4506
|
-
}
|
|
4507
|
-
}
|
|
4508
|
-
return headings;
|
|
4509
|
-
}
|
|
4510
4672
|
generateTOCXML(headings, originalInstrText) {
|
|
4511
4673
|
const sdtId = Math.floor(Math.random() * 2000000000) - 1000000000;
|
|
4512
4674
|
let tocXml = '<w:sdt>';
|
|
@@ -5218,6 +5380,57 @@ class Document {
|
|
|
5218
5380
|
},
|
|
5219
5381
|
};
|
|
5220
5382
|
}
|
|
5383
|
+
ensureTopLinksAbove1x1Tables(options) {
|
|
5384
|
+
const linkText = options?.text || 'Top of the Document';
|
|
5385
|
+
const formatting = options?.formatting;
|
|
5386
|
+
this.addTopBookmark();
|
|
5387
|
+
let insertedCount = 0;
|
|
5388
|
+
let oneByOneCount = 0;
|
|
5389
|
+
let i = 0;
|
|
5390
|
+
while (i < this.bodyElements.length) {
|
|
5391
|
+
const element = this.bodyElements[i];
|
|
5392
|
+
if (element instanceof Table_1.Table &&
|
|
5393
|
+
element.getRowCount() === 1 &&
|
|
5394
|
+
element.getColumnCount() === 1) {
|
|
5395
|
+
oneByOneCount++;
|
|
5396
|
+
if (oneByOneCount > 1) {
|
|
5397
|
+
const prevElement = i > 0 ? this.bodyElements[i - 1] : undefined;
|
|
5398
|
+
const hasLink = prevElement instanceof Paragraph_1.Paragraph && this._paragraphHasTopLink(prevElement);
|
|
5399
|
+
if (!hasLink) {
|
|
5400
|
+
const para = new Paragraph_1.Paragraph();
|
|
5401
|
+
const link = Hyperlink_1.Hyperlink.createInternal('_top', linkText, {
|
|
5402
|
+
color: '0000FF',
|
|
5403
|
+
underline: 'single',
|
|
5404
|
+
...formatting,
|
|
5405
|
+
});
|
|
5406
|
+
para.addHyperlink(link);
|
|
5407
|
+
this.bodyElements.splice(i, 0, para);
|
|
5408
|
+
insertedCount++;
|
|
5409
|
+
i++;
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
i++;
|
|
5414
|
+
}
|
|
5415
|
+
return insertedCount;
|
|
5416
|
+
}
|
|
5417
|
+
_paragraphHasTopLink(paragraph) {
|
|
5418
|
+
for (const item of paragraph.getContent()) {
|
|
5419
|
+
if (item instanceof Hyperlink_1.Hyperlink && item.getAnchor() === '_top') {
|
|
5420
|
+
return true;
|
|
5421
|
+
}
|
|
5422
|
+
if (item instanceof Field_1.ComplexField && item.isHyperlinkField()) {
|
|
5423
|
+
const parsed = item.getParsedHyperlink();
|
|
5424
|
+
if (parsed?.anchor === '_top') {
|
|
5425
|
+
return true;
|
|
5426
|
+
}
|
|
5427
|
+
}
|
|
5428
|
+
if (item instanceof PreservedElement_1.PreservedElement && item.getRawXml().includes('w:anchor="_top"')) {
|
|
5429
|
+
return true;
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5432
|
+
return false;
|
|
5433
|
+
}
|
|
5221
5434
|
getRevisionManager() {
|
|
5222
5435
|
return this.revisionManager;
|
|
5223
5436
|
}
|
|
@@ -5582,6 +5795,40 @@ class Document {
|
|
|
5582
5795
|
this._settingsModified = true;
|
|
5583
5796
|
this._modifiedBooleanSettings.add('defaultTabStop');
|
|
5584
5797
|
}
|
|
5798
|
+
setDefaultFont(fontName, sizeInPoints) {
|
|
5799
|
+
let normalStyle = this.stylesManager.getStyle('Normal');
|
|
5800
|
+
if (!normalStyle) {
|
|
5801
|
+
normalStyle = new Style_1.Style({
|
|
5802
|
+
styleId: 'Normal',
|
|
5803
|
+
name: 'Normal',
|
|
5804
|
+
type: 'paragraph',
|
|
5805
|
+
isDefault: true,
|
|
5806
|
+
});
|
|
5807
|
+
this.stylesManager.addStyle(normalStyle);
|
|
5808
|
+
}
|
|
5809
|
+
const existing = normalStyle.getRunFormatting() ?? {};
|
|
5810
|
+
const updated = { ...existing, font: fontName };
|
|
5811
|
+
if (sizeInPoints !== undefined) {
|
|
5812
|
+
updated.size = sizeInPoints;
|
|
5813
|
+
}
|
|
5814
|
+
normalStyle.setRunFormatting(updated);
|
|
5815
|
+
return this;
|
|
5816
|
+
}
|
|
5817
|
+
setDefaultFontSize(sizeInPoints) {
|
|
5818
|
+
let normalStyle = this.stylesManager.getStyle('Normal');
|
|
5819
|
+
if (!normalStyle) {
|
|
5820
|
+
normalStyle = new Style_1.Style({
|
|
5821
|
+
styleId: 'Normal',
|
|
5822
|
+
name: 'Normal',
|
|
5823
|
+
type: 'paragraph',
|
|
5824
|
+
isDefault: true,
|
|
5825
|
+
});
|
|
5826
|
+
this.stylesManager.addStyle(normalStyle);
|
|
5827
|
+
}
|
|
5828
|
+
const existing = normalStyle.getRunFormatting() ?? {};
|
|
5829
|
+
normalStyle.setRunFormatting({ ...existing, size: sizeInPoints });
|
|
5830
|
+
return this;
|
|
5831
|
+
}
|
|
5585
5832
|
getUpdateFields() {
|
|
5586
5833
|
return this._updateFields ?? false;
|
|
5587
5834
|
}
|
|
@@ -6021,6 +6268,10 @@ class Document {
|
|
|
6021
6268
|
}
|
|
6022
6269
|
return count;
|
|
6023
6270
|
}
|
|
6271
|
+
clear() {
|
|
6272
|
+
this.bodyElements = [];
|
|
6273
|
+
return this;
|
|
6274
|
+
}
|
|
6024
6275
|
dispose() {
|
|
6025
6276
|
this.bodyElements = [];
|
|
6026
6277
|
this.parser.clearParseErrors();
|
|
@@ -6703,6 +6954,33 @@ class Document {
|
|
|
6703
6954
|
}
|
|
6704
6955
|
return trackChanges ? { count, revisions } : { count };
|
|
6705
6956
|
}
|
|
6957
|
+
fillTemplate(data, options) {
|
|
6958
|
+
const [open, close] = options?.delimiters ?? ['{{', '}}'];
|
|
6959
|
+
let totalCount = 0;
|
|
6960
|
+
const allParagraphs = this.getAllParagraphs();
|
|
6961
|
+
for (const [key, value] of Object.entries(data)) {
|
|
6962
|
+
const placeholder = `${open}${key}${close}`;
|
|
6963
|
+
for (const para of allParagraphs) {
|
|
6964
|
+
totalCount += para.replaceTextCrossRun(placeholder, value);
|
|
6965
|
+
}
|
|
6966
|
+
}
|
|
6967
|
+
return totalCount;
|
|
6968
|
+
}
|
|
6969
|
+
findAndHighlight(text, color = 'yellow', options) {
|
|
6970
|
+
return this.findAndFormat(text, { highlight: color }, options);
|
|
6971
|
+
}
|
|
6972
|
+
findAndFormat(text, formatting, options) {
|
|
6973
|
+
let totalMatches = 0;
|
|
6974
|
+
for (const para of this.getAllParagraphs()) {
|
|
6975
|
+
const matches = para.findTextCrossRun(text, options);
|
|
6976
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
6977
|
+
const match = matches[i];
|
|
6978
|
+
para.applyFormattingToRange(match.offset, match.offset + match.text.length, formatting);
|
|
6979
|
+
}
|
|
6980
|
+
totalMatches += matches.length;
|
|
6981
|
+
}
|
|
6982
|
+
return totalMatches;
|
|
6983
|
+
}
|
|
6706
6984
|
getWordCount() {
|
|
6707
6985
|
let totalWords = 0;
|
|
6708
6986
|
const countedParagraphs = new Set();
|
|
@@ -6777,6 +7055,425 @@ class Document {
|
|
|
6777
7055
|
}
|
|
6778
7056
|
return totalChars;
|
|
6779
7057
|
}
|
|
7058
|
+
getStatistics() {
|
|
7059
|
+
const allParagraphs = this.getAllParagraphs();
|
|
7060
|
+
const tables = this.getTables();
|
|
7061
|
+
let words = 0;
|
|
7062
|
+
let characters = 0;
|
|
7063
|
+
let charactersNoSpaces = 0;
|
|
7064
|
+
let headings = 0;
|
|
7065
|
+
let lists = 0;
|
|
7066
|
+
const counted = new Set();
|
|
7067
|
+
for (const para of allParagraphs) {
|
|
7068
|
+
if (counted.has(para))
|
|
7069
|
+
continue;
|
|
7070
|
+
counted.add(para);
|
|
7071
|
+
const text = para.getText();
|
|
7072
|
+
characters += text.length;
|
|
7073
|
+
charactersNoSpaces += text.replace(/\s/g, '').length;
|
|
7074
|
+
const trimmed = text.trim();
|
|
7075
|
+
if (trimmed) {
|
|
7076
|
+
words += trimmed.split(/\s+/).filter((w) => w.length > 0).length;
|
|
7077
|
+
}
|
|
7078
|
+
if (para.detectHeadingLevel() !== null)
|
|
7079
|
+
headings++;
|
|
7080
|
+
if (para.hasNumbering())
|
|
7081
|
+
lists++;
|
|
7082
|
+
}
|
|
7083
|
+
for (const table of tables) {
|
|
7084
|
+
for (const row of table.getRows()) {
|
|
7085
|
+
for (const cell of row.getCells()) {
|
|
7086
|
+
for (const para of cell.getParagraphs()) {
|
|
7087
|
+
if (counted.has(para))
|
|
7088
|
+
continue;
|
|
7089
|
+
counted.add(para);
|
|
7090
|
+
const text = para.getText();
|
|
7091
|
+
characters += text.length;
|
|
7092
|
+
charactersNoSpaces += text.replace(/\s/g, '').length;
|
|
7093
|
+
const trimmed = text.trim();
|
|
7094
|
+
if (trimmed) {
|
|
7095
|
+
words += trimmed.split(/\s+/).filter((w) => w.length > 0).length;
|
|
7096
|
+
}
|
|
7097
|
+
}
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
}
|
|
7101
|
+
return {
|
|
7102
|
+
words,
|
|
7103
|
+
characters,
|
|
7104
|
+
charactersNoSpaces,
|
|
7105
|
+
paragraphs: allParagraphs.length,
|
|
7106
|
+
tables: tables.length,
|
|
7107
|
+
images: this.imageManager.getAllImages().length,
|
|
7108
|
+
headings,
|
|
7109
|
+
lists,
|
|
7110
|
+
hyperlinks: this.getHyperlinks().length,
|
|
7111
|
+
bookmarks: this.bookmarkManager.getAllBookmarks().length,
|
|
7112
|
+
footnotes: this.footnoteManager.getAllFootnotes().length,
|
|
7113
|
+
endnotes: this.endnoteManager.getAllEndnotes().length,
|
|
7114
|
+
comments: this.commentManager.getAllComments().length,
|
|
7115
|
+
sections: 1,
|
|
7116
|
+
};
|
|
7117
|
+
}
|
|
7118
|
+
forEachParagraph(callback) {
|
|
7119
|
+
let count = 0;
|
|
7120
|
+
let paraIndex = 0;
|
|
7121
|
+
for (const element of this.bodyElements) {
|
|
7122
|
+
if (element instanceof Paragraph_1.Paragraph) {
|
|
7123
|
+
const result = callback(element, paraIndex);
|
|
7124
|
+
count++;
|
|
7125
|
+
paraIndex++;
|
|
7126
|
+
if (result === false)
|
|
7127
|
+
break;
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7130
|
+
return count;
|
|
7131
|
+
}
|
|
7132
|
+
forEachTable(callback) {
|
|
7133
|
+
let count = 0;
|
|
7134
|
+
let tableIndex = 0;
|
|
7135
|
+
for (const element of this.bodyElements) {
|
|
7136
|
+
if (element instanceof Table_1.Table) {
|
|
7137
|
+
const result = callback(element, tableIndex);
|
|
7138
|
+
count++;
|
|
7139
|
+
tableIndex++;
|
|
7140
|
+
if (result === false)
|
|
7141
|
+
break;
|
|
7142
|
+
}
|
|
7143
|
+
}
|
|
7144
|
+
return count;
|
|
7145
|
+
}
|
|
7146
|
+
toPlainText(separator = '\n') {
|
|
7147
|
+
const paragraphs = this.getAllParagraphs();
|
|
7148
|
+
return paragraphs.map((p) => p.getText()).join(separator);
|
|
7149
|
+
}
|
|
7150
|
+
toMarkdown() {
|
|
7151
|
+
const lines = [];
|
|
7152
|
+
for (const element of this.bodyElements) {
|
|
7153
|
+
if (element instanceof Paragraph_1.Paragraph) {
|
|
7154
|
+
const mdLine = this.paragraphToMarkdown(element);
|
|
7155
|
+
if (mdLine !== null) {
|
|
7156
|
+
lines.push(mdLine);
|
|
7157
|
+
lines.push('');
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7160
|
+
else if (element instanceof Table_1.Table) {
|
|
7161
|
+
lines.push(...this.tableToMarkdown(element));
|
|
7162
|
+
lines.push('');
|
|
7163
|
+
}
|
|
7164
|
+
}
|
|
7165
|
+
while (lines.length > 0 && lines[lines.length - 1] === '') {
|
|
7166
|
+
lines.pop();
|
|
7167
|
+
}
|
|
7168
|
+
return lines.join('\n');
|
|
7169
|
+
}
|
|
7170
|
+
paragraphToMarkdown(para) {
|
|
7171
|
+
const text = this.paragraphContentToMarkdown(para);
|
|
7172
|
+
if (!text && !para.hasNumbering())
|
|
7173
|
+
return null;
|
|
7174
|
+
const headingLevel = para.detectHeadingLevel();
|
|
7175
|
+
if (headingLevel !== null && headingLevel >= 1 && headingLevel <= 6) {
|
|
7176
|
+
return '#'.repeat(headingLevel) + ' ' + text;
|
|
7177
|
+
}
|
|
7178
|
+
if (para.hasNumbering()) {
|
|
7179
|
+
const style = para.getStyle();
|
|
7180
|
+
const isBullet = style?.toLowerCase().includes('bullet') || style?.toLowerCase().includes('list bullet');
|
|
7181
|
+
return isBullet ? `- ${text}` : `1. ${text}`;
|
|
7182
|
+
}
|
|
7183
|
+
return text;
|
|
7184
|
+
}
|
|
7185
|
+
paragraphContentToMarkdown(para) {
|
|
7186
|
+
const parts = [];
|
|
7187
|
+
for (const item of para.getContent()) {
|
|
7188
|
+
if (item instanceof Run_1.Run) {
|
|
7189
|
+
const runText = item.getText();
|
|
7190
|
+
if (!runText)
|
|
7191
|
+
continue;
|
|
7192
|
+
const fmt = item.getFormatting();
|
|
7193
|
+
let md = runText;
|
|
7194
|
+
if (fmt.bold && fmt.italic) {
|
|
7195
|
+
md = `***${md}***`;
|
|
7196
|
+
}
|
|
7197
|
+
else if (fmt.bold) {
|
|
7198
|
+
md = `**${md}**`;
|
|
7199
|
+
}
|
|
7200
|
+
else if (fmt.italic) {
|
|
7201
|
+
md = `*${md}*`;
|
|
7202
|
+
}
|
|
7203
|
+
if (fmt.strike) {
|
|
7204
|
+
md = `~~${md}~~`;
|
|
7205
|
+
}
|
|
7206
|
+
if (fmt.font &&
|
|
7207
|
+
/^(courier|consolas|monaco|menlo|source code|fira code|jetbrains mono)/i.test(fmt.font)) {
|
|
7208
|
+
md = `\`${runText}\``;
|
|
7209
|
+
}
|
|
7210
|
+
parts.push(md);
|
|
7211
|
+
}
|
|
7212
|
+
else if (item instanceof Hyperlink_1.Hyperlink) {
|
|
7213
|
+
const url = item.getUrl() || '';
|
|
7214
|
+
const linkText = item.getText() || url;
|
|
7215
|
+
parts.push(`[${linkText}](${url})`);
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
return parts.join('');
|
|
7219
|
+
}
|
|
7220
|
+
tableToMarkdown(table) {
|
|
7221
|
+
const data = table.toArray();
|
|
7222
|
+
if (data.length === 0)
|
|
7223
|
+
return [];
|
|
7224
|
+
const colCount = Math.max(...data.map((row) => row.length));
|
|
7225
|
+
if (colCount === 0)
|
|
7226
|
+
return [];
|
|
7227
|
+
const normalized = data.map((row) => {
|
|
7228
|
+
const padded = [...row];
|
|
7229
|
+
while (padded.length < colCount)
|
|
7230
|
+
padded.push('');
|
|
7231
|
+
return padded.map((cell) => cell.replace(/\|/g, '\\|').replace(/\n/g, ' ').trim());
|
|
7232
|
+
});
|
|
7233
|
+
const lines = [];
|
|
7234
|
+
lines.push('| ' + normalized[0].join(' | ') + ' |');
|
|
7235
|
+
lines.push('| ' + normalized[0].map(() => '---').join(' | ') + ' |');
|
|
7236
|
+
for (let i = 1; i < normalized.length; i++) {
|
|
7237
|
+
lines.push('| ' + normalized[i].join(' | ') + ' |');
|
|
7238
|
+
}
|
|
7239
|
+
return lines;
|
|
7240
|
+
}
|
|
7241
|
+
toHTML(options) {
|
|
7242
|
+
const parts = [];
|
|
7243
|
+
let inList = null;
|
|
7244
|
+
const closeList = () => {
|
|
7245
|
+
if (inList) {
|
|
7246
|
+
parts.push(`</${inList}>`);
|
|
7247
|
+
inList = null;
|
|
7248
|
+
}
|
|
7249
|
+
};
|
|
7250
|
+
for (const element of this.bodyElements) {
|
|
7251
|
+
if (element instanceof Paragraph_1.Paragraph) {
|
|
7252
|
+
const headingLevel = element.detectHeadingLevel();
|
|
7253
|
+
const style = element.getStyle();
|
|
7254
|
+
const isBullet = style?.toLowerCase().includes('bullet') || style === 'ListBullet';
|
|
7255
|
+
const isNumber = style?.toLowerCase().includes('listnumber') ||
|
|
7256
|
+
style?.toLowerCase().includes('list number') ||
|
|
7257
|
+
style === 'ListNumber';
|
|
7258
|
+
if (isBullet || isNumber) {
|
|
7259
|
+
const listType = isBullet ? 'ul' : 'ol';
|
|
7260
|
+
if (inList !== listType) {
|
|
7261
|
+
closeList();
|
|
7262
|
+
inList = listType;
|
|
7263
|
+
parts.push(`<${listType}>`);
|
|
7264
|
+
}
|
|
7265
|
+
parts.push(`<li>${this.paragraphContentToHTML(element)}</li>`);
|
|
7266
|
+
continue;
|
|
7267
|
+
}
|
|
7268
|
+
closeList();
|
|
7269
|
+
if (headingLevel !== null && headingLevel >= 1 && headingLevel <= 6) {
|
|
7270
|
+
parts.push(`<h${headingLevel}>${this.paragraphContentToHTML(element)}</h${headingLevel}>`);
|
|
7271
|
+
}
|
|
7272
|
+
else {
|
|
7273
|
+
const content = this.paragraphContentToHTML(element);
|
|
7274
|
+
if (content) {
|
|
7275
|
+
parts.push(`<p>${content}</p>`);
|
|
7276
|
+
}
|
|
7277
|
+
}
|
|
7278
|
+
}
|
|
7279
|
+
else if (element instanceof Table_1.Table) {
|
|
7280
|
+
closeList();
|
|
7281
|
+
parts.push(this.tableToHTML(element));
|
|
7282
|
+
}
|
|
7283
|
+
}
|
|
7284
|
+
closeList();
|
|
7285
|
+
const body = parts.join('\n');
|
|
7286
|
+
if (options?.wrapInDocument) {
|
|
7287
|
+
const title = options.title ? this.escapeHTML(options.title) : 'Document';
|
|
7288
|
+
return [
|
|
7289
|
+
'<!DOCTYPE html>',
|
|
7290
|
+
'<html>',
|
|
7291
|
+
'<head>',
|
|
7292
|
+
`<meta charset="utf-8">`,
|
|
7293
|
+
`<title>${title}</title>`,
|
|
7294
|
+
'</head>',
|
|
7295
|
+
'<body>',
|
|
7296
|
+
body,
|
|
7297
|
+
'</body>',
|
|
7298
|
+
'</html>',
|
|
7299
|
+
].join('\n');
|
|
7300
|
+
}
|
|
7301
|
+
return body;
|
|
7302
|
+
}
|
|
7303
|
+
paragraphContentToHTML(para) {
|
|
7304
|
+
const parts = [];
|
|
7305
|
+
for (const item of para.getContent()) {
|
|
7306
|
+
if (item instanceof Run_1.Run) {
|
|
7307
|
+
const text = item.getText();
|
|
7308
|
+
if (!text)
|
|
7309
|
+
continue;
|
|
7310
|
+
const escaped = this.escapeHTML(text);
|
|
7311
|
+
const fmt = item.getFormatting();
|
|
7312
|
+
const isMono = fmt.font &&
|
|
7313
|
+
/^(courier|consolas|monaco|menlo|source code|fira code|jetbrains mono)/i.test(fmt.font);
|
|
7314
|
+
if (isMono) {
|
|
7315
|
+
parts.push(`<code>${escaped}</code>`);
|
|
7316
|
+
continue;
|
|
7317
|
+
}
|
|
7318
|
+
let html = escaped;
|
|
7319
|
+
if (fmt.bold)
|
|
7320
|
+
html = `<strong>${html}</strong>`;
|
|
7321
|
+
if (fmt.italic)
|
|
7322
|
+
html = `<em>${html}</em>`;
|
|
7323
|
+
if (fmt.strike)
|
|
7324
|
+
html = `<s>${html}</s>`;
|
|
7325
|
+
if (fmt.underline && fmt.underline !== 'none') {
|
|
7326
|
+
html = `<u>${html}</u>`;
|
|
7327
|
+
}
|
|
7328
|
+
parts.push(html);
|
|
7329
|
+
}
|
|
7330
|
+
else if (item instanceof Hyperlink_1.Hyperlink) {
|
|
7331
|
+
const url = this.escapeHTML(item.getUrl() || '');
|
|
7332
|
+
const linkText = this.escapeHTML(item.getText() || url);
|
|
7333
|
+
parts.push(`<a href="${url}">${linkText}</a>`);
|
|
7334
|
+
}
|
|
7335
|
+
}
|
|
7336
|
+
return parts.join('');
|
|
7337
|
+
}
|
|
7338
|
+
tableToHTML(table) {
|
|
7339
|
+
const rows = table.getRows();
|
|
7340
|
+
if (rows.length === 0)
|
|
7341
|
+
return '';
|
|
7342
|
+
const lines = ['<table>'];
|
|
7343
|
+
const headerCells = rows[0].getCells();
|
|
7344
|
+
lines.push('<thead>');
|
|
7345
|
+
lines.push('<tr>');
|
|
7346
|
+
for (const cell of headerCells) {
|
|
7347
|
+
lines.push(`<th>${this.escapeHTML(cell.getText())}</th>`);
|
|
7348
|
+
}
|
|
7349
|
+
lines.push('</tr>');
|
|
7350
|
+
lines.push('</thead>');
|
|
7351
|
+
if (rows.length > 1) {
|
|
7352
|
+
lines.push('<tbody>');
|
|
7353
|
+
for (let r = 1; r < rows.length; r++) {
|
|
7354
|
+
lines.push('<tr>');
|
|
7355
|
+
for (const cell of rows[r].getCells()) {
|
|
7356
|
+
lines.push(`<td>${this.escapeHTML(cell.getText())}</td>`);
|
|
7357
|
+
}
|
|
7358
|
+
lines.push('</tr>');
|
|
7359
|
+
}
|
|
7360
|
+
lines.push('</tbody>');
|
|
7361
|
+
}
|
|
7362
|
+
lines.push('</table>');
|
|
7363
|
+
return lines.join('\n');
|
|
7364
|
+
}
|
|
7365
|
+
escapeHTML(text) {
|
|
7366
|
+
return text
|
|
7367
|
+
.replace(/&/g, '&')
|
|
7368
|
+
.replace(/</g, '<')
|
|
7369
|
+
.replace(/>/g, '>')
|
|
7370
|
+
.replace(/"/g, '"');
|
|
7371
|
+
}
|
|
7372
|
+
toJSON() {
|
|
7373
|
+
const paragraphs = this.getAllParagraphs();
|
|
7374
|
+
const tables = this.getTables();
|
|
7375
|
+
const headings = this.getHeadingHierarchy();
|
|
7376
|
+
return {
|
|
7377
|
+
properties: this.getProperties(),
|
|
7378
|
+
stats: {
|
|
7379
|
+
paragraphs: paragraphs.length,
|
|
7380
|
+
tables: tables.length,
|
|
7381
|
+
images: this.imageManager.getImageCount(),
|
|
7382
|
+
headings: headings.length,
|
|
7383
|
+
sections: this.bodyElements.filter((el) => el instanceof Section_1.Section).length || 1,
|
|
7384
|
+
},
|
|
7385
|
+
headings: headings.map((h) => ({ level: h.level, text: h.text })),
|
|
7386
|
+
body: this.bodyElements.map((el) => {
|
|
7387
|
+
if (el instanceof Paragraph_1.Paragraph) {
|
|
7388
|
+
return {
|
|
7389
|
+
type: 'paragraph',
|
|
7390
|
+
text: el.getText(),
|
|
7391
|
+
style: el.getStyle(),
|
|
7392
|
+
};
|
|
7393
|
+
}
|
|
7394
|
+
if (el instanceof Table_1.Table) {
|
|
7395
|
+
return {
|
|
7396
|
+
type: 'table',
|
|
7397
|
+
text: `${el.getRows().length} rows x ${el.getRows()[0]?.getCells().length ?? 0} cols`,
|
|
7398
|
+
};
|
|
7399
|
+
}
|
|
7400
|
+
return { type: el.constructor.name };
|
|
7401
|
+
}),
|
|
7402
|
+
};
|
|
7403
|
+
}
|
|
7404
|
+
findImagesWithoutAltText() {
|
|
7405
|
+
const results = [];
|
|
7406
|
+
for (const para of this.getAllParagraphs()) {
|
|
7407
|
+
for (const item of para.getContent()) {
|
|
7408
|
+
if (item instanceof ImageRun_1.ImageRun) {
|
|
7409
|
+
const image = item.getImageElement();
|
|
7410
|
+
const altText = image.getAltText();
|
|
7411
|
+
if (!altText || altText === 'Image') {
|
|
7412
|
+
results.push(image);
|
|
7413
|
+
}
|
|
7414
|
+
}
|
|
7415
|
+
if (item instanceof Revision_1.Revision) {
|
|
7416
|
+
for (const revContent of item.getContent()) {
|
|
7417
|
+
if (revContent instanceof ImageRun_1.ImageRun) {
|
|
7418
|
+
const image = revContent.getImageElement();
|
|
7419
|
+
const altText = image.getAltText();
|
|
7420
|
+
if (!altText || altText === 'Image') {
|
|
7421
|
+
results.push(image);
|
|
7422
|
+
}
|
|
7423
|
+
}
|
|
7424
|
+
}
|
|
7425
|
+
}
|
|
7426
|
+
}
|
|
7427
|
+
}
|
|
7428
|
+
return results;
|
|
7429
|
+
}
|
|
7430
|
+
getHeadingHierarchy() {
|
|
7431
|
+
const results = [];
|
|
7432
|
+
for (const para of this.getAllParagraphs()) {
|
|
7433
|
+
const level = para.detectHeadingLevel();
|
|
7434
|
+
if (level !== null) {
|
|
7435
|
+
results.push({
|
|
7436
|
+
level,
|
|
7437
|
+
text: para.getText(),
|
|
7438
|
+
paragraph: para,
|
|
7439
|
+
});
|
|
7440
|
+
}
|
|
7441
|
+
}
|
|
7442
|
+
return results;
|
|
7443
|
+
}
|
|
7444
|
+
extractByHeading(maxLevel = 1) {
|
|
7445
|
+
const sections = [];
|
|
7446
|
+
let current = {
|
|
7447
|
+
heading: undefined,
|
|
7448
|
+
level: 0,
|
|
7449
|
+
content: [],
|
|
7450
|
+
};
|
|
7451
|
+
for (const element of this.bodyElements) {
|
|
7452
|
+
if (element instanceof Paragraph_1.Paragraph) {
|
|
7453
|
+
const headingLevel = element.detectHeadingLevel();
|
|
7454
|
+
if (headingLevel !== null && headingLevel <= maxLevel) {
|
|
7455
|
+
if (current.heading || current.content.length > 0) {
|
|
7456
|
+
sections.push(current);
|
|
7457
|
+
}
|
|
7458
|
+
current = { heading: element, level: headingLevel, content: [] };
|
|
7459
|
+
continue;
|
|
7460
|
+
}
|
|
7461
|
+
}
|
|
7462
|
+
current.content.push(element);
|
|
7463
|
+
}
|
|
7464
|
+
if (current.heading || current.content.length > 0) {
|
|
7465
|
+
sections.push(current);
|
|
7466
|
+
}
|
|
7467
|
+
return sections;
|
|
7468
|
+
}
|
|
7469
|
+
getElementsBetween(startElement, endElement) {
|
|
7470
|
+
const startIndex = this.bodyElements.indexOf(startElement);
|
|
7471
|
+
const endIndex = this.bodyElements.indexOf(endElement);
|
|
7472
|
+
if (startIndex === -1 || endIndex === -1 || startIndex >= endIndex) {
|
|
7473
|
+
return [];
|
|
7474
|
+
}
|
|
7475
|
+
return this.bodyElements.slice(startIndex + 1, endIndex);
|
|
7476
|
+
}
|
|
6780
7477
|
removeParagraph(paragraphOrIndex) {
|
|
6781
7478
|
let index;
|
|
6782
7479
|
if (typeof paragraphOrIndex === 'number') {
|
|
@@ -6984,6 +7681,34 @@ class Document {
|
|
|
6984
7681
|
}
|
|
6985
7682
|
return false;
|
|
6986
7683
|
}
|
|
7684
|
+
removeElement(element) {
|
|
7685
|
+
const index = this.bodyElements.indexOf(element);
|
|
7686
|
+
if (index === -1)
|
|
7687
|
+
return false;
|
|
7688
|
+
this.bodyElements.splice(index, 1);
|
|
7689
|
+
return true;
|
|
7690
|
+
}
|
|
7691
|
+
insertAfter(reference, element) {
|
|
7692
|
+
const index = this.bodyElements.indexOf(reference);
|
|
7693
|
+
if (index === -1)
|
|
7694
|
+
return false;
|
|
7695
|
+
this.bodyElements.splice(index + 1, 0, element);
|
|
7696
|
+
return true;
|
|
7697
|
+
}
|
|
7698
|
+
insertBefore(reference, element) {
|
|
7699
|
+
const index = this.bodyElements.indexOf(reference);
|
|
7700
|
+
if (index === -1)
|
|
7701
|
+
return false;
|
|
7702
|
+
this.bodyElements.splice(index, 0, element);
|
|
7703
|
+
return true;
|
|
7704
|
+
}
|
|
7705
|
+
replaceElement(oldElement, newElement) {
|
|
7706
|
+
const index = this.bodyElements.indexOf(oldElement);
|
|
7707
|
+
if (index === -1)
|
|
7708
|
+
return false;
|
|
7709
|
+
this.bodyElements[index] = newElement;
|
|
7710
|
+
return true;
|
|
7711
|
+
}
|
|
6987
7712
|
insertBodyElementAt(index, element) {
|
|
6988
7713
|
const clampedIndex = Math.max(0, Math.min(index, this.bodyElements.length));
|
|
6989
7714
|
this.bodyElements.splice(clampedIndex, 0, element);
|