docxmlater 10.1.3 → 10.1.5
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 +759 -754
- package/dist/constants/legacyCompatFlags.js +1 -1
- package/dist/constants/legacyCompatFlags.js.map +1 -1
- package/dist/constants/limits.js.map +1 -1
- package/dist/core/Document.d.ts +50 -50
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +483 -471
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentContent.d.ts +9 -9
- package/dist/core/DocumentContent.d.ts.map +1 -1
- package/dist/core/DocumentContent.js +1 -1
- package/dist/core/DocumentContent.js.map +1 -1
- package/dist/core/DocumentGenerator.d.ts +11 -11
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +251 -251
- package/dist/core/DocumentGenerator.js.map +1 -1
- package/dist/core/DocumentIdManager.js.map +1 -1
- package/dist/core/DocumentParser.d.ts +15 -15
- package/dist/core/DocumentParser.d.ts.map +1 -1
- package/dist/core/DocumentParser.js +2123 -2155
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/DocumentValidator.d.ts.map +1 -1
- package/dist/core/DocumentValidator.js +2 -5
- package/dist/core/DocumentValidator.js.map +1 -1
- package/dist/core/Relationship.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +3 -3
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/AlternateContent.js.map +1 -1
- package/dist/elements/Bookmark.d.ts.map +1 -1
- package/dist/elements/Bookmark.js +3 -1
- package/dist/elements/Bookmark.js.map +1 -1
- package/dist/elements/BookmarkManager.d.ts.map +1 -1
- package/dist/elements/BookmarkManager.js.map +1 -1
- package/dist/elements/Comment.d.ts.map +1 -1
- package/dist/elements/Comment.js +9 -6
- package/dist/elements/Comment.js.map +1 -1
- package/dist/elements/CommentManager.d.ts.map +1 -1
- package/dist/elements/CommentManager.js +18 -17
- package/dist/elements/CommentManager.js.map +1 -1
- package/dist/elements/CommonTypes.d.ts +21 -21
- package/dist/elements/CommonTypes.d.ts.map +1 -1
- package/dist/elements/CommonTypes.js +56 -56
- package/dist/elements/CommonTypes.js.map +1 -1
- package/dist/elements/CustomXml.js.map +1 -1
- package/dist/elements/Endnote.d.ts.map +1 -1
- package/dist/elements/Endnote.js +6 -6
- package/dist/elements/Endnote.js.map +1 -1
- package/dist/elements/EndnoteManager.d.ts.map +1 -1
- package/dist/elements/EndnoteManager.js +6 -7
- package/dist/elements/EndnoteManager.js.map +1 -1
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +82 -25
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/FieldHelpers.d.ts.map +1 -1
- package/dist/elements/FieldHelpers.js.map +1 -1
- package/dist/elements/FontManager.d.ts.map +1 -1
- package/dist/elements/FontManager.js +1 -1
- package/dist/elements/FontManager.js.map +1 -1
- package/dist/elements/Footer.js +2 -2
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/Footnote.d.ts.map +1 -1
- package/dist/elements/Footnote.js +6 -6
- package/dist/elements/Footnote.js.map +1 -1
- package/dist/elements/FootnoteManager.d.ts.map +1 -1
- package/dist/elements/FootnoteManager.js +6 -7
- package/dist/elements/FootnoteManager.js.map +1 -1
- package/dist/elements/Header.js +2 -2
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/HeaderFooterManager.js.map +1 -1
- package/dist/elements/Hyperlink.d.ts +5 -3
- package/dist/elements/Hyperlink.d.ts.map +1 -1
- package/dist/elements/Hyperlink.js +134 -76
- package/dist/elements/Hyperlink.js.map +1 -1
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +238 -106
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/ImageManager.d.ts.map +1 -1
- package/dist/elements/ImageManager.js +1 -1
- package/dist/elements/ImageManager.js.map +1 -1
- package/dist/elements/ImageRun.js +1 -1
- package/dist/elements/ImageRun.js.map +1 -1
- package/dist/elements/MathElement.js.map +1 -1
- package/dist/elements/Paragraph.d.ts +24 -24
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +181 -188
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/PreservedElement.js.map +1 -1
- package/dist/elements/PropertyChangeTypes.d.ts.map +1 -1
- package/dist/elements/PropertyChangeTypes.js +6 -6
- package/dist/elements/PropertyChangeTypes.js.map +1 -1
- package/dist/elements/RangeMarker.d.ts.map +1 -1
- package/dist/elements/RangeMarker.js.map +1 -1
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +4 -5
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/RevisionContent.js.map +1 -1
- package/dist/elements/RevisionManager.d.ts.map +1 -1
- package/dist/elements/RevisionManager.js +40 -48
- package/dist/elements/RevisionManager.js.map +1 -1
- package/dist/elements/Run.d.ts +16 -16
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +256 -238
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +36 -11
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.d.ts.map +1 -1
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/StructuredDocumentTag.d.ts +6 -6
- package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
- package/dist/elements/StructuredDocumentTag.js +99 -104
- package/dist/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/elements/Table.d.ts +11 -11
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +102 -107
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +10 -10
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +105 -106
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableGridChange.d.ts.map +1 -1
- package/dist/elements/TableGridChange.js.map +1 -1
- package/dist/elements/TableOfContents.d.ts.map +1 -1
- package/dist/elements/TableOfContents.js +4 -4
- package/dist/elements/TableOfContents.js.map +1 -1
- package/dist/elements/TableOfContentsElement.js.map +1 -1
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +13 -6
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/elements/TextBox.d.ts.map +1 -1
- package/dist/elements/TextBox.js +3 -5
- package/dist/elements/TextBox.js.map +1 -1
- package/dist/formatting/AbstractNumbering.d.ts +4 -4
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +54 -49
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingInstance.d.ts.map +1 -1
- package/dist/formatting/NumberingInstance.js +1 -3
- package/dist/formatting/NumberingInstance.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts +5 -5
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +119 -125
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/NumberingManager.d.ts.map +1 -1
- package/dist/formatting/NumberingManager.js +9 -9
- package/dist/formatting/NumberingManager.js.map +1 -1
- package/dist/formatting/Style.d.ts +11 -11
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +219 -247
- package/dist/formatting/Style.js.map +1 -1
- package/dist/formatting/StylesManager.d.ts +2 -2
- package/dist/formatting/StylesManager.d.ts.map +1 -1
- package/dist/formatting/StylesManager.js +96 -102
- package/dist/formatting/StylesManager.js.map +1 -1
- package/dist/helpers/CleanupHelper.d.ts +1 -1
- package/dist/helpers/CleanupHelper.d.ts.map +1 -1
- package/dist/helpers/CleanupHelper.js +6 -6
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/images/ImageOptimizer.js +7 -7
- package/dist/images/ImageOptimizer.js.map +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/managers/DrawingManager.js.map +1 -1
- package/dist/tracking/DocumentTrackingContext.d.ts.map +1 -1
- package/dist/tracking/DocumentTrackingContext.js +23 -7
- package/dist/tracking/DocumentTrackingContext.js.map +1 -1
- package/dist/tracking/TrackingContext.d.ts.map +1 -1
- package/dist/tracking/TrackingContext.js.map +1 -1
- package/dist/types/compatibility-types.js.map +1 -1
- package/dist/types/formatting.js.map +1 -1
- package/dist/types/list-types.d.ts +6 -6
- package/dist/types/list-types.js.map +1 -1
- package/dist/types/settings-types.js.map +1 -1
- package/dist/types/styleConfig.d.ts +2 -2
- package/dist/types/styleConfig.js.map +1 -1
- package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
- package/dist/utils/ChangelogGenerator.js +97 -101
- package/dist/utils/ChangelogGenerator.js.map +1 -1
- package/dist/utils/CompatibilityUpgrader.d.ts.map +1 -1
- package/dist/utils/CompatibilityUpgrader.js +1 -1
- package/dist/utils/CompatibilityUpgrader.js.map +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.d.ts.map +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.js +1 -6
- package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/utils/MoveOperationHelper.d.ts.map +1 -1
- package/dist/utils/MoveOperationHelper.js +1 -1
- package/dist/utils/MoveOperationHelper.js.map +1 -1
- package/dist/utils/RevisionAwareProcessor.d.ts.map +1 -1
- package/dist/utils/RevisionAwareProcessor.js +2 -4
- package/dist/utils/RevisionAwareProcessor.js.map +1 -1
- package/dist/utils/RevisionWalker.d.ts.map +1 -1
- package/dist/utils/RevisionWalker.js +4 -12
- package/dist/utils/RevisionWalker.js.map +1 -1
- package/dist/utils/SelectiveRevisionAcceptor.d.ts.map +1 -1
- package/dist/utils/SelectiveRevisionAcceptor.js +2 -6
- package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/utils/ShadingResolver.d.ts.map +1 -1
- package/dist/utils/ShadingResolver.js +1 -1
- package/dist/utils/ShadingResolver.js.map +1 -1
- package/dist/utils/acceptRevisions.d.ts.map +1 -1
- package/dist/utils/acceptRevisions.js +23 -12
- package/dist/utils/acceptRevisions.js.map +1 -1
- package/dist/utils/cnfStyleDecoder.d.ts +1 -1
- package/dist/utils/cnfStyleDecoder.d.ts.map +1 -1
- package/dist/utils/cnfStyleDecoder.js +40 -40
- package/dist/utils/cnfStyleDecoder.js.map +1 -1
- package/dist/utils/corruptionDetection.d.ts.map +1 -1
- package/dist/utils/corruptionDetection.js.map +1 -1
- package/dist/utils/dateFormatting.js.map +1 -1
- package/dist/utils/deepClone.js +1 -1
- package/dist/utils/deepClone.js.map +1 -1
- package/dist/utils/diagnostics.d.ts.map +1 -1
- package/dist/utils/diagnostics.js +1 -1
- package/dist/utils/diagnostics.js.map +1 -1
- package/dist/utils/errorHandling.js.map +1 -1
- package/dist/utils/formatting.d.ts.map +1 -1
- package/dist/utils/formatting.js +10 -2
- package/dist/utils/formatting.js.map +1 -1
- package/dist/utils/list-detection.d.ts +2 -2
- package/dist/utils/list-detection.d.ts.map +1 -1
- package/dist/utils/list-detection.js +21 -23
- package/dist/utils/list-detection.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +12 -7
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/parsingHelpers.js.map +1 -1
- package/dist/utils/stripTrackedChanges.d.ts.map +1 -1
- package/dist/utils/stripTrackedChanges.js +3 -3
- package/dist/utils/stripTrackedChanges.js.map +1 -1
- package/dist/utils/textDiff.d.ts +1 -1
- package/dist/utils/textDiff.js +8 -8
- package/dist/utils/textDiff.js.map +1 -1
- package/dist/utils/units.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +24 -7
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/xmlSanitization.d.ts.map +1 -1
- package/dist/utils/xmlSanitization.js +3 -3
- package/dist/utils/xmlSanitization.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
- package/dist/validation/RevisionAutoFixer.js +5 -5
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/validation/RevisionValidator.d.ts.map +1 -1
- package/dist/validation/RevisionValidator.js +7 -9
- package/dist/validation/RevisionValidator.js.map +1 -1
- package/dist/validation/ValidationRules.js +3 -3
- package/dist/validation/ValidationRules.js.map +1 -1
- package/dist/validation/index.js.map +1 -1
- package/dist/xml/XMLBuilder.d.ts +1 -1
- package/dist/xml/XMLBuilder.d.ts.map +1 -1
- package/dist/xml/XMLBuilder.js +98 -100
- package/dist/xml/XMLBuilder.js.map +1 -1
- package/dist/xml/XMLParser.d.ts.map +1 -1
- package/dist/xml/XMLParser.js +61 -66
- package/dist/xml/XMLParser.js.map +1 -1
- package/dist/zip/ZipHandler.d.ts.map +1 -1
- package/dist/zip/ZipHandler.js.map +1 -1
- package/dist/zip/ZipReader.d.ts.map +1 -1
- package/dist/zip/ZipReader.js +1 -3
- package/dist/zip/ZipReader.js.map +1 -1
- package/dist/zip/ZipWriter.d.ts +1 -1
- package/dist/zip/ZipWriter.d.ts.map +1 -1
- package/dist/zip/ZipWriter.js +28 -36
- package/dist/zip/ZipWriter.js.map +1 -1
- package/dist/zip/types.js +1 -1
- package/dist/zip/types.js.map +1 -1
- package/package.json +92 -92
- package/src/__tests__/helper-methods.test.ts +512 -512
- package/src/constants/legacyCompatFlags.ts +138 -138
- package/src/constants/limits.ts +50 -50
- package/src/core/Document.ts +985 -1145
- package/src/core/DocumentContent.ts +461 -467
- package/src/core/DocumentGenerator.ts +1133 -1104
- package/src/core/DocumentIdManager.ts +158 -158
- package/src/core/DocumentParser.ts +2347 -2716
- package/src/core/DocumentValidator.ts +363 -372
- package/src/core/Relationship.ts +367 -367
- package/src/core/RelationshipManager.ts +429 -428
- package/src/elements/AlternateContent.ts +42 -42
- package/src/elements/Bookmark.ts +212 -210
- package/src/elements/BookmarkManager.ts +247 -250
- package/src/elements/Comment.ts +356 -359
- package/src/elements/CommentManager.ts +499 -502
- package/src/elements/CommonTypes.ts +524 -549
- package/src/elements/CustomXml.ts +36 -36
- package/src/elements/Endnote.ts +221 -217
- package/src/elements/EndnoteManager.ts +246 -249
- package/src/elements/Field.ts +1292 -1233
- package/src/elements/FieldHelpers.ts +329 -333
- package/src/elements/FontManager.ts +336 -339
- package/src/elements/Footer.ts +269 -269
- package/src/elements/Footnote.ts +221 -217
- package/src/elements/FootnoteManager.ts +246 -249
- package/src/elements/Header.ts +269 -269
- package/src/elements/HeaderFooterManager.ts +219 -219
- package/src/elements/Hyperlink.ts +1288 -1193
- package/src/elements/Image.ts +1982 -1756
- package/src/elements/ImageManager.ts +437 -432
- package/src/elements/ImageRun.ts +59 -59
- package/src/elements/MathElement.ts +65 -65
- package/src/elements/Paragraph.ts +4347 -4287
- package/src/elements/PreservedElement.ts +53 -53
- package/src/elements/PropertyChangeTypes.ts +458 -442
- package/src/elements/RangeMarker.ts +382 -400
- package/src/elements/Revision.ts +1198 -1217
- package/src/elements/RevisionContent.ts +73 -73
- package/src/elements/RevisionManager.ts +1070 -1070
- package/src/elements/Run.ts +3103 -3073
- package/src/elements/Section.ts +1521 -1421
- package/src/elements/Shape.ts +884 -873
- package/src/elements/StructuredDocumentTag.ts +1176 -1207
- package/src/elements/Table.ts +2468 -2524
- package/src/elements/TableCell.ts +1617 -1621
- package/src/elements/TableGridChange.ts +149 -151
- package/src/elements/TableOfContents.ts +701 -691
- package/src/elements/TableOfContentsElement.ts +89 -89
- package/src/elements/TableRow.ts +960 -929
- package/src/elements/TextBox.ts +766 -768
- package/src/formatting/AbstractNumbering.ts +580 -579
- package/src/formatting/NumberingInstance.ts +295 -299
- package/src/formatting/NumberingLevel.ts +981 -1040
- package/src/formatting/NumberingManager.ts +833 -827
- package/src/formatting/Style.ts +1785 -1879
- package/src/formatting/StylesManager.ts +1090 -1130
- package/src/helpers/CleanupHelper.ts +524 -524
- package/src/images/ImageOptimizer.ts +274 -274
- package/src/index.ts +559 -554
- package/src/managers/DrawingManager.ts +319 -319
- package/src/tracking/DocumentTrackingContext.ts +687 -674
- package/src/tracking/TrackingContext.ts +175 -173
- package/src/types/compatibility-types.ts +49 -49
- package/src/types/formatting.ts +210 -210
- package/src/types/list-types.ts +14 -14
- package/src/types/settings-types.ts +59 -59
- package/src/types/styleConfig.ts +189 -189
- package/src/utils/ChangelogGenerator.ts +1583 -1581
- package/src/utils/CompatibilityUpgrader.ts +235 -237
- package/src/utils/InMemoryRevisionAcceptor.ts +691 -696
- package/src/utils/MoveOperationHelper.ts +233 -238
- package/src/utils/RevisionAwareProcessor.ts +518 -526
- package/src/utils/RevisionWalker.ts +427 -457
- package/src/utils/SelectiveRevisionAcceptor.ts +662 -683
- package/src/utils/ShadingResolver.ts +105 -107
- package/src/utils/acceptRevisions.ts +723 -714
- package/src/utils/cnfStyleDecoder.ts +212 -217
- package/src/utils/corruptionDetection.ts +346 -345
- package/src/utils/dateFormatting.ts +20 -20
- package/src/utils/deepClone.ts +77 -78
- package/src/utils/diagnostics.ts +125 -129
- package/src/utils/errorHandling.ts +80 -80
- package/src/utils/formatting.ts +220 -213
- package/src/utils/list-detection.ts +32 -42
- package/src/utils/logger.ts +412 -404
- package/src/utils/parsingHelpers.ts +190 -190
- package/src/utils/stripTrackedChanges.ts +356 -353
- package/src/utils/textDiff.ts +100 -100
- package/src/utils/units.ts +421 -421
- package/src/utils/validation.ts +553 -542
- package/src/utils/xmlSanitization.ts +179 -182
- package/src/validation/RevisionAutoFixer.ts +541 -542
- package/src/validation/RevisionValidator.ts +470 -460
- package/src/validation/ValidationRules.ts +338 -338
- package/src/validation/index.ts +30 -30
- package/src/xml/XMLBuilder.ts +857 -871
- package/src/xml/XMLParser.ts +877 -919
- package/src/zip/ZipHandler.ts +629 -637
- package/src/zip/ZipReader.ts +295 -299
- package/src/zip/ZipWriter.ts +374 -390
- package/src/zip/types.ts +116 -116
|
@@ -1,353 +1,356 @@
|
|
|
1
|
-
import { ZipHandler } from '../zip/ZipHandler';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Strips all tracked changes markup from a Word document
|
|
5
|
-
* This includes insertions, deletions, move operations, and property changes
|
|
6
|
-
* Also cleans up related metadata in people.xml, settings.xml, and core.xml
|
|
7
|
-
*/
|
|
8
|
-
class TrackedChangesStripper {
|
|
9
|
-
private zipHandler: ZipHandler;
|
|
10
|
-
|
|
11
|
-
constructor(zipHandler: ZipHandler) {
|
|
12
|
-
this.zipHandler = zipHandler;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Main method to strip all tracked changes from the document
|
|
17
|
-
*/
|
|
18
|
-
public async stripTrackedChanges(): Promise<void> {
|
|
19
|
-
// Strip revision elements from document.xml
|
|
20
|
-
await this.stripDocumentRevisions();
|
|
21
|
-
|
|
22
|
-
// Clean up metadata files
|
|
23
|
-
await this.cleanupPeopleXml();
|
|
24
|
-
await this.cleanupSettingsXml();
|
|
25
|
-
await this.cleanupCorePropsXml();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Strip ALL revision elements from word/document.xml
|
|
30
|
-
*/
|
|
31
|
-
private async stripDocumentRevisions(): Promise<void> {
|
|
32
|
-
const documentXml = this.zipHandler.getFileAsString('word/document.xml');
|
|
33
|
-
if (!documentXml) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let content = documentXml;
|
|
38
|
-
|
|
39
|
-
// STEP 1: Remove all range markers (boundary markers for tracked changes)
|
|
40
|
-
content = this.removeRangeMarkers(content);
|
|
41
|
-
|
|
42
|
-
// STEP 2: Process insertions - keep content, remove wrapper
|
|
43
|
-
content = this.processInsertions(content);
|
|
44
|
-
|
|
45
|
-
// STEP 3: Process deletions - remove entirely
|
|
46
|
-
content = this.processDeletions(content);
|
|
47
|
-
|
|
48
|
-
// STEP 4: Process move operations
|
|
49
|
-
content = this.processMoveFrom(content);
|
|
50
|
-
content = this.processMoveTo(content);
|
|
51
|
-
|
|
52
|
-
// STEP 5: Remove all property change tracking elements
|
|
53
|
-
content = this.removePropertyChanges(content);
|
|
54
|
-
|
|
55
|
-
// STEP 6: Remove any remaining self-closing revision tags
|
|
56
|
-
content = this.removeSelfClosingRevisionTags(content);
|
|
57
|
-
|
|
58
|
-
// Update the file in the zip
|
|
59
|
-
this.zipHandler.updateFile('word/document.xml', content);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Remove all range marker elements
|
|
64
|
-
*/
|
|
65
|
-
private removeRangeMarkers(xml: string): string {
|
|
66
|
-
const patterns = [
|
|
67
|
-
/<w:moveFromRangeStart[^>]*\/>/g,
|
|
68
|
-
/<w:moveFromRangeEnd[^>]*\/>/g,
|
|
69
|
-
/<w:moveToRangeStart[^>]*\/>/g,
|
|
70
|
-
/<w:moveToRangeEnd[^>]*\/>/g,
|
|
71
|
-
/<w:customXmlInsRangeStart[^>]*\/>/g,
|
|
72
|
-
/<w:customXmlInsRangeEnd[^>]*\/>/g,
|
|
73
|
-
/<w:customXmlDelRangeStart[^>]*\/>/g,
|
|
74
|
-
/<w:customXmlDelRangeEnd[^>]*\/>/g,
|
|
75
|
-
/<w:customXmlMoveFromRangeStart[^>]*\/>/g,
|
|
76
|
-
/<w:customXmlMoveFromRangeEnd[^>]*\/>/g,
|
|
77
|
-
/<w:customXmlMoveToRangeStart[^>]*\/>/g,
|
|
78
|
-
/<w:customXmlMoveToRangeEnd[^>]*\/>/g
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
let result = xml;
|
|
82
|
-
for (const pattern of patterns) {
|
|
83
|
-
result = result.replace(pattern, '');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return result;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Process <w:ins> elements - keep inner content, remove wrapper
|
|
91
|
-
* Handles orphaned tags by removing opening and closing tags separately
|
|
92
|
-
*
|
|
93
|
-
* IMPORTANT: This method now handles relationship ID remapping for images inside insertions.
|
|
94
|
-
* When Word tracks changes with images, it can reuse relationship IDs (like rId5) because
|
|
95
|
-
* they're in separate tracked change contexts. But when we unwrap them, duplicate IDs
|
|
96
|
-
* cause corruption. This method assigns new unique IDs to images inside insertions.
|
|
97
|
-
*/
|
|
98
|
-
private processInsertions(xml: string): string {
|
|
99
|
-
let result = xml;
|
|
100
|
-
|
|
101
|
-
// Parse existing relationships
|
|
102
|
-
const relationships = this.parseRelationships();
|
|
103
|
-
const existingIds = new Set(relationships.keys());
|
|
104
|
-
|
|
105
|
-
// Process each w:ins element and remap images one by one
|
|
106
|
-
const insRegex = /<w:ins\b[^>]*>[\s\S]*?<\/w:ins>/g;
|
|
107
|
-
|
|
108
|
-
result = result.replace(insRegex, (insMatch) => {
|
|
109
|
-
// For each image reference inside this insertion, generate a unique new ID
|
|
110
|
-
return insMatch.replace(/r:embed="(rId\d+)"/g, (embedMatch, oldId) => {
|
|
111
|
-
// Generate new unique ID for THIS occurrence
|
|
112
|
-
const newId = this.getNextRelationshipId(existingIds);
|
|
113
|
-
existingIds.add(newId);
|
|
114
|
-
|
|
115
|
-
// Add relationship with same target as original
|
|
116
|
-
const target = relationships.get(oldId);
|
|
117
|
-
if (target) {
|
|
118
|
-
this.addRelationship(
|
|
119
|
-
newId,
|
|
120
|
-
target,
|
|
121
|
-
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image'
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return `r:embed="${newId}"`;
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// First, remove all closing tags
|
|
130
|
-
result = result.replace(/<\/w:ins>/g, '');
|
|
131
|
-
|
|
132
|
-
// Then, remove all opening tags (keeping any content that follows)
|
|
133
|
-
result = result.replace(/<w:ins[\s>][^>]*>/g, '');
|
|
134
|
-
|
|
135
|
-
return result;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Process <w:del> elements - remove entire element
|
|
140
|
-
* Uses iterative replacement to handle nested deletions
|
|
141
|
-
*/
|
|
142
|
-
private processDeletions(xml: string): string {
|
|
143
|
-
let result = xml;
|
|
144
|
-
let previousLength = 0;
|
|
145
|
-
|
|
146
|
-
// Keep replacing until no more changes (handles nested revisions)
|
|
147
|
-
while (result.length !== previousLength) {
|
|
148
|
-
previousLength = result.length;
|
|
149
|
-
|
|
150
|
-
// Match entire deletion element and remove it
|
|
151
|
-
// Use [\s>] to match either space or closing bracket
|
|
152
|
-
result = result.replace(/<w:del[\s>][^>]*>.*?<\/w:del>/gs, '');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return result;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Process <w:moveFrom> elements - remove entire element (source of move)
|
|
160
|
-
* Uses iterative replacement to handle nested moves
|
|
161
|
-
*/
|
|
162
|
-
private processMoveFrom(xml: string): string {
|
|
163
|
-
let result = xml;
|
|
164
|
-
let previousLength = 0;
|
|
165
|
-
|
|
166
|
-
// Keep replacing until no more changes
|
|
167
|
-
while (result.length !== previousLength) {
|
|
168
|
-
previousLength = result.length;
|
|
169
|
-
|
|
170
|
-
// Use [\s>] to match either space or closing bracket
|
|
171
|
-
result = result.replace(/<w:moveFrom[\s>][^>]*>.*?<\/w:moveFrom>/gs, '');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return result;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Process <w:moveTo> elements - keep inner content (destination of move)
|
|
179
|
-
* Handles orphaned tags by removing opening and closing tags separately
|
|
180
|
-
*/
|
|
181
|
-
private processMoveTo(xml: string): string {
|
|
182
|
-
let result = xml;
|
|
183
|
-
|
|
184
|
-
// First, remove all closing tags
|
|
185
|
-
result = result.replace(/<\/w:moveTo>/g, '');
|
|
186
|
-
|
|
187
|
-
// Then, remove all opening tags (keeping any content that follows)
|
|
188
|
-
result = result.replace(/<w:moveTo[\s>][^>]*>/g, '');
|
|
189
|
-
|
|
190
|
-
return result;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Remove all property change tracking elements
|
|
195
|
-
*/
|
|
196
|
-
private removePropertyChanges(xml: string): string {
|
|
197
|
-
const patterns = [
|
|
198
|
-
/<w:rPrChange[^>]*>.*?<\/w:rPrChange>/gs,
|
|
199
|
-
/<w:pPrChange[^>]*>.*?<\/w:pPrChange>/gs,
|
|
200
|
-
/<w:tblPrChange[^>]*>.*?<\/w:tblPrChange>/gs,
|
|
201
|
-
/<w:tblPrExChange[^>]*>.*?<\/w:tblPrExChange>/gs, // Table property exception changes
|
|
202
|
-
/<w:tcPrChange[^>]*>.*?<\/w:tcPrChange>/gs,
|
|
203
|
-
/<w:trPrChange[^>]*>.*?<\/w:trPrChange>/gs,
|
|
204
|
-
/<w:sectPrChange[^>]*>.*?<\/w:sectPrChange>/gs, // Section property changes
|
|
205
|
-
/<w:tblGridChange[^>]*>.*?<\/w:tblGridChange>/gs, // Table grid changes
|
|
206
|
-
/<w:numberingChange[^>]*>.*?<\/w:numberingChange>/gs // Numbering changes
|
|
207
|
-
];
|
|
208
|
-
|
|
209
|
-
let result = xml;
|
|
210
|
-
for (const pattern of patterns) {
|
|
211
|
-
result = result.replace(pattern, '');
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return result;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Remove self-closing revision tags
|
|
219
|
-
*/
|
|
220
|
-
private removeSelfClosingRevisionTags(xml: string): string {
|
|
221
|
-
const patterns = [
|
|
222
|
-
/<w:ins\s+[^>]*\/>/g,
|
|
223
|
-
/<w:del\s+[^>]*\/>/g,
|
|
224
|
-
/<w:moveFrom\s+[^>]*\/>/g,
|
|
225
|
-
/<w:moveTo\s+[^>]*\/>/g
|
|
226
|
-
];
|
|
227
|
-
|
|
228
|
-
let result = xml;
|
|
229
|
-
for (const pattern of patterns) {
|
|
230
|
-
result = result.replace(pattern, '');
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return result;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Parse relationship IDs from word/_rels/document.xml.rels
|
|
238
|
-
* Returns a map of relationship ID to target path
|
|
239
|
-
*/
|
|
240
|
-
private parseRelationships(): Map<string, string> {
|
|
241
|
-
const relsXml = this.zipHandler.getFileAsString('word/_rels/document.xml.rels');
|
|
242
|
-
if (!relsXml) return new Map();
|
|
243
|
-
|
|
244
|
-
const map = new Map<string, string>();
|
|
245
|
-
const relationshipRegex = /<Relationship[^>]*Id="([^"]+)"[^>]*Target="([^"]+)"[^>]*\/>/g;
|
|
246
|
-
let match;
|
|
247
|
-
|
|
248
|
-
while ((match = relationshipRegex.exec(relsXml)) !== null) {
|
|
249
|
-
if (match[1] && match[2]) {
|
|
250
|
-
map.set(match[1], match[2]); // rId -> target path
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return map;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Get the next available relationship ID
|
|
259
|
-
* Finds the highest numeric ID and increments it
|
|
260
|
-
*/
|
|
261
|
-
private getNextRelationshipId(existingIds: Set<string>): string {
|
|
262
|
-
let maxId = 0;
|
|
263
|
-
for (const id of existingIds) {
|
|
264
|
-
const num = parseInt(id.replace('rId', ''));
|
|
265
|
-
if (!isNaN(num) && num > maxId) {
|
|
266
|
-
maxId = num;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
return `rId${maxId + 1}`;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Add a new relationship to word/_rels/document.xml.rels
|
|
274
|
-
*/
|
|
275
|
-
private addRelationship(rId: string, target: string, type: string): void {
|
|
276
|
-
const relsXml = this.zipHandler.getFileAsString('word/_rels/document.xml.rels');
|
|
277
|
-
if (!relsXml) return;
|
|
278
|
-
|
|
279
|
-
// Insert new relationship before closing tag
|
|
280
|
-
const newRel = `<Relationship Id="${rId}" Type="${type}" Target="${target}"/>`;
|
|
281
|
-
const updated = relsXml.replace('</Relationships>', `${newRel}\n</Relationships>`);
|
|
282
|
-
|
|
283
|
-
this.zipHandler.updateFile('word/_rels/document.xml.rels', updated);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Clean up word/people.xml - remove revision authors
|
|
288
|
-
*/
|
|
289
|
-
private async cleanupPeopleXml(): Promise<void> {
|
|
290
|
-
const peopleXml = this.zipHandler.getFileAsString('word/people.xml');
|
|
291
|
-
if (!peopleXml) {
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
let content = peopleXml;
|
|
296
|
-
|
|
297
|
-
// Remove all <w:person> elements (standard namespace)
|
|
298
|
-
content = content.replace(/<w:person[^>]*>.*?<\/w:person>/gs, '');
|
|
299
|
-
|
|
300
|
-
// Remove all <w15:person> elements (Word 2013+ namespace)
|
|
301
|
-
content = content.replace(/<w15:person[^>]*>.*?<\/w15:person>/gs, '');
|
|
302
|
-
|
|
303
|
-
// Remove any other namespace variants of person elements
|
|
304
|
-
content = content.replace(/<w\d*:person[^>]*>.*?<\/w\d*:person>/gs, '');
|
|
305
|
-
|
|
306
|
-
this.zipHandler.updateFile('word/people.xml', content);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Clean up word/settings.xml - disable track changes
|
|
311
|
-
*/
|
|
312
|
-
private async cleanupSettingsXml(): Promise<void> {
|
|
313
|
-
const settingsXml = this.zipHandler.getFileAsString('word/settings.xml');
|
|
314
|
-
if (!settingsXml) {
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
let content = settingsXml;
|
|
319
|
-
|
|
320
|
-
// Remove track changes settings
|
|
321
|
-
content = content.replace(/<w:trackRevisions[^>]*\/>/g, '');
|
|
322
|
-
content = content.replace(/<w:trackRevisions[^>]*>.*?<\/w:trackRevisions>/gs, '');
|
|
323
|
-
|
|
324
|
-
// Remove revision view settings
|
|
325
|
-
content = content.replace(/<w:revisionView[^>]*\/>/g, '');
|
|
326
|
-
content = content.replace(/<w:revisionView[^>]*>.*?<\/w:revisionView>/gs, '');
|
|
327
|
-
|
|
328
|
-
this.zipHandler.updateFile('word/settings.xml', content);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Clean up docProps/core.xml - reset revision count
|
|
333
|
-
*/
|
|
334
|
-
private async cleanupCorePropsXml(): Promise<void> {
|
|
335
|
-
const coreXml = this.zipHandler.getFileAsString('docProps/core.xml');
|
|
336
|
-
if (!coreXml) {
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Reset revision count to 1
|
|
341
|
-
const content = coreXml.replace(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
1
|
+
import { ZipHandler } from '../zip/ZipHandler';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Strips all tracked changes markup from a Word document
|
|
5
|
+
* This includes insertions, deletions, move operations, and property changes
|
|
6
|
+
* Also cleans up related metadata in people.xml, settings.xml, and core.xml
|
|
7
|
+
*/
|
|
8
|
+
class TrackedChangesStripper {
|
|
9
|
+
private zipHandler: ZipHandler;
|
|
10
|
+
|
|
11
|
+
constructor(zipHandler: ZipHandler) {
|
|
12
|
+
this.zipHandler = zipHandler;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Main method to strip all tracked changes from the document
|
|
17
|
+
*/
|
|
18
|
+
public async stripTrackedChanges(): Promise<void> {
|
|
19
|
+
// Strip revision elements from document.xml
|
|
20
|
+
await this.stripDocumentRevisions();
|
|
21
|
+
|
|
22
|
+
// Clean up metadata files
|
|
23
|
+
await this.cleanupPeopleXml();
|
|
24
|
+
await this.cleanupSettingsXml();
|
|
25
|
+
await this.cleanupCorePropsXml();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Strip ALL revision elements from word/document.xml
|
|
30
|
+
*/
|
|
31
|
+
private async stripDocumentRevisions(): Promise<void> {
|
|
32
|
+
const documentXml = this.zipHandler.getFileAsString('word/document.xml');
|
|
33
|
+
if (!documentXml) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let content = documentXml;
|
|
38
|
+
|
|
39
|
+
// STEP 1: Remove all range markers (boundary markers for tracked changes)
|
|
40
|
+
content = this.removeRangeMarkers(content);
|
|
41
|
+
|
|
42
|
+
// STEP 2: Process insertions - keep content, remove wrapper
|
|
43
|
+
content = this.processInsertions(content);
|
|
44
|
+
|
|
45
|
+
// STEP 3: Process deletions - remove entirely
|
|
46
|
+
content = this.processDeletions(content);
|
|
47
|
+
|
|
48
|
+
// STEP 4: Process move operations
|
|
49
|
+
content = this.processMoveFrom(content);
|
|
50
|
+
content = this.processMoveTo(content);
|
|
51
|
+
|
|
52
|
+
// STEP 5: Remove all property change tracking elements
|
|
53
|
+
content = this.removePropertyChanges(content);
|
|
54
|
+
|
|
55
|
+
// STEP 6: Remove any remaining self-closing revision tags
|
|
56
|
+
content = this.removeSelfClosingRevisionTags(content);
|
|
57
|
+
|
|
58
|
+
// Update the file in the zip
|
|
59
|
+
this.zipHandler.updateFile('word/document.xml', content);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Remove all range marker elements
|
|
64
|
+
*/
|
|
65
|
+
private removeRangeMarkers(xml: string): string {
|
|
66
|
+
const patterns = [
|
|
67
|
+
/<w:moveFromRangeStart[^>]*\/>/g,
|
|
68
|
+
/<w:moveFromRangeEnd[^>]*\/>/g,
|
|
69
|
+
/<w:moveToRangeStart[^>]*\/>/g,
|
|
70
|
+
/<w:moveToRangeEnd[^>]*\/>/g,
|
|
71
|
+
/<w:customXmlInsRangeStart[^>]*\/>/g,
|
|
72
|
+
/<w:customXmlInsRangeEnd[^>]*\/>/g,
|
|
73
|
+
/<w:customXmlDelRangeStart[^>]*\/>/g,
|
|
74
|
+
/<w:customXmlDelRangeEnd[^>]*\/>/g,
|
|
75
|
+
/<w:customXmlMoveFromRangeStart[^>]*\/>/g,
|
|
76
|
+
/<w:customXmlMoveFromRangeEnd[^>]*\/>/g,
|
|
77
|
+
/<w:customXmlMoveToRangeStart[^>]*\/>/g,
|
|
78
|
+
/<w:customXmlMoveToRangeEnd[^>]*\/>/g,
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
let result = xml;
|
|
82
|
+
for (const pattern of patterns) {
|
|
83
|
+
result = result.replace(pattern, '');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Process <w:ins> elements - keep inner content, remove wrapper
|
|
91
|
+
* Handles orphaned tags by removing opening and closing tags separately
|
|
92
|
+
*
|
|
93
|
+
* IMPORTANT: This method now handles relationship ID remapping for images inside insertions.
|
|
94
|
+
* When Word tracks changes with images, it can reuse relationship IDs (like rId5) because
|
|
95
|
+
* they're in separate tracked change contexts. But when we unwrap them, duplicate IDs
|
|
96
|
+
* cause corruption. This method assigns new unique IDs to images inside insertions.
|
|
97
|
+
*/
|
|
98
|
+
private processInsertions(xml: string): string {
|
|
99
|
+
let result = xml;
|
|
100
|
+
|
|
101
|
+
// Parse existing relationships
|
|
102
|
+
const relationships = this.parseRelationships();
|
|
103
|
+
const existingIds = new Set(relationships.keys());
|
|
104
|
+
|
|
105
|
+
// Process each w:ins element and remap images one by one
|
|
106
|
+
const insRegex = /<w:ins\b[^>]*>[\s\S]*?<\/w:ins>/g;
|
|
107
|
+
|
|
108
|
+
result = result.replace(insRegex, (insMatch) => {
|
|
109
|
+
// For each image reference inside this insertion, generate a unique new ID
|
|
110
|
+
return insMatch.replace(/r:embed="(rId\d+)"/g, (embedMatch, oldId) => {
|
|
111
|
+
// Generate new unique ID for THIS occurrence
|
|
112
|
+
const newId = this.getNextRelationshipId(existingIds);
|
|
113
|
+
existingIds.add(newId);
|
|
114
|
+
|
|
115
|
+
// Add relationship with same target as original
|
|
116
|
+
const target = relationships.get(oldId);
|
|
117
|
+
if (target) {
|
|
118
|
+
this.addRelationship(
|
|
119
|
+
newId,
|
|
120
|
+
target,
|
|
121
|
+
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image'
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return `r:embed="${newId}"`;
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// First, remove all closing tags
|
|
130
|
+
result = result.replace(/<\/w:ins>/g, '');
|
|
131
|
+
|
|
132
|
+
// Then, remove all opening tags (keeping any content that follows)
|
|
133
|
+
result = result.replace(/<w:ins[\s>][^>]*>/g, '');
|
|
134
|
+
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Process <w:del> elements - remove entire element
|
|
140
|
+
* Uses iterative replacement to handle nested deletions
|
|
141
|
+
*/
|
|
142
|
+
private processDeletions(xml: string): string {
|
|
143
|
+
let result = xml;
|
|
144
|
+
let previousLength = 0;
|
|
145
|
+
|
|
146
|
+
// Keep replacing until no more changes (handles nested revisions)
|
|
147
|
+
while (result.length !== previousLength) {
|
|
148
|
+
previousLength = result.length;
|
|
149
|
+
|
|
150
|
+
// Match entire deletion element and remove it
|
|
151
|
+
// Use [\s>] to match either space or closing bracket
|
|
152
|
+
result = result.replace(/<w:del[\s>][^>]*>.*?<\/w:del>/gs, '');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Process <w:moveFrom> elements - remove entire element (source of move)
|
|
160
|
+
* Uses iterative replacement to handle nested moves
|
|
161
|
+
*/
|
|
162
|
+
private processMoveFrom(xml: string): string {
|
|
163
|
+
let result = xml;
|
|
164
|
+
let previousLength = 0;
|
|
165
|
+
|
|
166
|
+
// Keep replacing until no more changes
|
|
167
|
+
while (result.length !== previousLength) {
|
|
168
|
+
previousLength = result.length;
|
|
169
|
+
|
|
170
|
+
// Use [\s>] to match either space or closing bracket
|
|
171
|
+
result = result.replace(/<w:moveFrom[\s>][^>]*>.*?<\/w:moveFrom>/gs, '');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Process <w:moveTo> elements - keep inner content (destination of move)
|
|
179
|
+
* Handles orphaned tags by removing opening and closing tags separately
|
|
180
|
+
*/
|
|
181
|
+
private processMoveTo(xml: string): string {
|
|
182
|
+
let result = xml;
|
|
183
|
+
|
|
184
|
+
// First, remove all closing tags
|
|
185
|
+
result = result.replace(/<\/w:moveTo>/g, '');
|
|
186
|
+
|
|
187
|
+
// Then, remove all opening tags (keeping any content that follows)
|
|
188
|
+
result = result.replace(/<w:moveTo[\s>][^>]*>/g, '');
|
|
189
|
+
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Remove all property change tracking elements
|
|
195
|
+
*/
|
|
196
|
+
private removePropertyChanges(xml: string): string {
|
|
197
|
+
const patterns = [
|
|
198
|
+
/<w:rPrChange[^>]*>.*?<\/w:rPrChange>/gs, // Run property changes
|
|
199
|
+
/<w:pPrChange[^>]*>.*?<\/w:pPrChange>/gs, // Paragraph property changes
|
|
200
|
+
/<w:tblPrChange[^>]*>.*?<\/w:tblPrChange>/gs, // Table property changes
|
|
201
|
+
/<w:tblPrExChange[^>]*>.*?<\/w:tblPrExChange>/gs, // Table property exception changes
|
|
202
|
+
/<w:tcPrChange[^>]*>.*?<\/w:tcPrChange>/gs, // Table cell property changes
|
|
203
|
+
/<w:trPrChange[^>]*>.*?<\/w:trPrChange>/gs, // Table row property changes
|
|
204
|
+
/<w:sectPrChange[^>]*>.*?<\/w:sectPrChange>/gs, // Section property changes
|
|
205
|
+
/<w:tblGridChange[^>]*>.*?<\/w:tblGridChange>/gs, // Table grid changes
|
|
206
|
+
/<w:numberingChange[^>]*>.*?<\/w:numberingChange>/gs, // Numbering changes
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
let result = xml;
|
|
210
|
+
for (const pattern of patterns) {
|
|
211
|
+
result = result.replace(pattern, '');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Remove self-closing revision tags
|
|
219
|
+
*/
|
|
220
|
+
private removeSelfClosingRevisionTags(xml: string): string {
|
|
221
|
+
const patterns = [
|
|
222
|
+
/<w:ins\s+[^>]*\/>/g,
|
|
223
|
+
/<w:del\s+[^>]*\/>/g,
|
|
224
|
+
/<w:moveFrom\s+[^>]*\/>/g,
|
|
225
|
+
/<w:moveTo\s+[^>]*\/>/g,
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
let result = xml;
|
|
229
|
+
for (const pattern of patterns) {
|
|
230
|
+
result = result.replace(pattern, '');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Parse relationship IDs from word/_rels/document.xml.rels
|
|
238
|
+
* Returns a map of relationship ID to target path
|
|
239
|
+
*/
|
|
240
|
+
private parseRelationships(): Map<string, string> {
|
|
241
|
+
const relsXml = this.zipHandler.getFileAsString('word/_rels/document.xml.rels');
|
|
242
|
+
if (!relsXml) return new Map();
|
|
243
|
+
|
|
244
|
+
const map = new Map<string, string>();
|
|
245
|
+
const relationshipRegex = /<Relationship[^>]*Id="([^"]+)"[^>]*Target="([^"]+)"[^>]*\/>/g;
|
|
246
|
+
let match;
|
|
247
|
+
|
|
248
|
+
while ((match = relationshipRegex.exec(relsXml)) !== null) {
|
|
249
|
+
if (match[1] && match[2]) {
|
|
250
|
+
map.set(match[1], match[2]); // rId -> target path
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return map;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Get the next available relationship ID
|
|
259
|
+
* Finds the highest numeric ID and increments it
|
|
260
|
+
*/
|
|
261
|
+
private getNextRelationshipId(existingIds: Set<string>): string {
|
|
262
|
+
let maxId = 0;
|
|
263
|
+
for (const id of existingIds) {
|
|
264
|
+
const num = parseInt(id.replace('rId', ''));
|
|
265
|
+
if (!isNaN(num) && num > maxId) {
|
|
266
|
+
maxId = num;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return `rId${maxId + 1}`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Add a new relationship to word/_rels/document.xml.rels
|
|
274
|
+
*/
|
|
275
|
+
private addRelationship(rId: string, target: string, type: string): void {
|
|
276
|
+
const relsXml = this.zipHandler.getFileAsString('word/_rels/document.xml.rels');
|
|
277
|
+
if (!relsXml) return;
|
|
278
|
+
|
|
279
|
+
// Insert new relationship before closing tag
|
|
280
|
+
const newRel = `<Relationship Id="${rId}" Type="${type}" Target="${target}"/>`;
|
|
281
|
+
const updated = relsXml.replace('</Relationships>', `${newRel}\n</Relationships>`);
|
|
282
|
+
|
|
283
|
+
this.zipHandler.updateFile('word/_rels/document.xml.rels', updated);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Clean up word/people.xml - remove revision authors
|
|
288
|
+
*/
|
|
289
|
+
private async cleanupPeopleXml(): Promise<void> {
|
|
290
|
+
const peopleXml = this.zipHandler.getFileAsString('word/people.xml');
|
|
291
|
+
if (!peopleXml) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let content = peopleXml;
|
|
296
|
+
|
|
297
|
+
// Remove all <w:person> elements (standard namespace)
|
|
298
|
+
content = content.replace(/<w:person[^>]*>.*?<\/w:person>/gs, '');
|
|
299
|
+
|
|
300
|
+
// Remove all <w15:person> elements (Word 2013+ namespace)
|
|
301
|
+
content = content.replace(/<w15:person[^>]*>.*?<\/w15:person>/gs, '');
|
|
302
|
+
|
|
303
|
+
// Remove any other namespace variants of person elements
|
|
304
|
+
content = content.replace(/<w\d*:person[^>]*>.*?<\/w\d*:person>/gs, '');
|
|
305
|
+
|
|
306
|
+
this.zipHandler.updateFile('word/people.xml', content);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Clean up word/settings.xml - disable track changes
|
|
311
|
+
*/
|
|
312
|
+
private async cleanupSettingsXml(): Promise<void> {
|
|
313
|
+
const settingsXml = this.zipHandler.getFileAsString('word/settings.xml');
|
|
314
|
+
if (!settingsXml) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let content = settingsXml;
|
|
319
|
+
|
|
320
|
+
// Remove track changes settings
|
|
321
|
+
content = content.replace(/<w:trackRevisions[^>]*\/>/g, '');
|
|
322
|
+
content = content.replace(/<w:trackRevisions[^>]*>.*?<\/w:trackRevisions>/gs, '');
|
|
323
|
+
|
|
324
|
+
// Remove revision view settings
|
|
325
|
+
content = content.replace(/<w:revisionView[^>]*\/>/g, '');
|
|
326
|
+
content = content.replace(/<w:revisionView[^>]*>.*?<\/w:revisionView>/gs, '');
|
|
327
|
+
|
|
328
|
+
this.zipHandler.updateFile('word/settings.xml', content);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Clean up docProps/core.xml - reset revision count
|
|
333
|
+
*/
|
|
334
|
+
private async cleanupCorePropsXml(): Promise<void> {
|
|
335
|
+
const coreXml = this.zipHandler.getFileAsString('docProps/core.xml');
|
|
336
|
+
if (!coreXml) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Reset revision count to 1
|
|
341
|
+
const content = coreXml.replace(
|
|
342
|
+
/<cp:revision>\d+<\/cp:revision>/g,
|
|
343
|
+
'<cp:revision>1</cp:revision>'
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
this.zipHandler.updateFile('docProps/core.xml', content);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Convenience function to strip tracked changes from a ZipHandler
|
|
352
|
+
*/
|
|
353
|
+
export async function stripTrackedChanges(zipHandler: ZipHandler): Promise<void> {
|
|
354
|
+
const stripper = new TrackedChangesStripper(zipHandler);
|
|
355
|
+
await stripper.stripTrackedChanges();
|
|
356
|
+
}
|