docxmlater 11.0.10 → 12.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -13
- package/dist/core/Document.d.ts +28 -2
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +725 -170
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentGenerator.d.ts +1 -0
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +77 -25
- package/dist/core/DocumentGenerator.js.map +1 -1
- package/dist/core/DocumentParser.d.ts +7 -3
- package/dist/core/DocumentParser.d.ts.map +1 -1
- package/dist/core/DocumentParser.js +427 -81
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +2 -2
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/Comment.d.ts +15 -1
- package/dist/elements/Comment.d.ts.map +1 -1
- package/dist/elements/Comment.js +67 -12
- package/dist/elements/Comment.js.map +1 -1
- package/dist/elements/CommentManager.d.ts +4 -0
- package/dist/elements/CommentManager.d.ts.map +1 -1
- package/dist/elements/CommentManager.js +74 -16
- package/dist/elements/CommentManager.js.map +1 -1
- package/dist/elements/EndnoteManager.d.ts.map +1 -1
- package/dist/elements/EndnoteManager.js.map +1 -1
- package/dist/elements/Field.d.ts +10 -1
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +76 -34
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/FieldHelpers.d.ts +1 -0
- package/dist/elements/FieldHelpers.d.ts.map +1 -1
- package/dist/elements/FieldHelpers.js +8 -4
- package/dist/elements/FieldHelpers.js.map +1 -1
- package/dist/elements/Footer.d.ts +3 -1
- package/dist/elements/Footer.d.ts.map +1 -1
- package/dist/elements/Footer.js +39 -53
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/FootnoteManager.d.ts.map +1 -1
- package/dist/elements/FootnoteManager.js.map +1 -1
- package/dist/elements/Header.d.ts +3 -1
- package/dist/elements/Header.d.ts.map +1 -1
- package/dist/elements/Header.js +39 -53
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/HeaderFooterManager.d.ts +4 -2
- package/dist/elements/HeaderFooterManager.d.ts.map +1 -1
- package/dist/elements/HeaderFooterManager.js +36 -6
- package/dist/elements/HeaderFooterManager.js.map +1 -1
- package/dist/elements/Hyperlink.d.ts +6 -1
- package/dist/elements/Hyperlink.d.ts.map +1 -1
- package/dist/elements/Hyperlink.js +69 -44
- package/dist/elements/Hyperlink.js.map +1 -1
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +33 -6
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/ImageManager.d.ts +1 -0
- package/dist/elements/ImageManager.d.ts.map +1 -1
- package/dist/elements/ImageManager.js +11 -0
- package/dist/elements/ImageManager.js.map +1 -1
- package/dist/elements/Paragraph.d.ts +3 -0
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +91 -26
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/Revision.d.ts +4 -0
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +369 -29
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/Run.d.ts +1 -0
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +24 -4
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +17 -7
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.d.ts.map +1 -1
- package/dist/elements/Shape.js +50 -42
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/StructuredDocumentTag.d.ts +9 -1
- package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
- package/dist/elements/StructuredDocumentTag.js +46 -6
- package/dist/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/elements/Table.d.ts +2 -0
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +90 -42
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +1 -0
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +32 -13
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableOfContents.d.ts.map +1 -1
- package/dist/elements/TableOfContents.js +5 -7
- package/dist/elements/TableOfContents.js.map +1 -1
- package/dist/elements/TableRow.d.ts +1 -0
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +16 -1
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/elements/TextBox.d.ts.map +1 -1
- package/dist/elements/TextBox.js +55 -42
- package/dist/elements/TextBox.js.map +1 -1
- package/dist/esm/core/Document.js +726 -171
- package/dist/esm/core/Document.js.map +1 -1
- package/dist/esm/core/DocumentGenerator.js +77 -25
- package/dist/esm/core/DocumentGenerator.js.map +1 -1
- package/dist/esm/core/DocumentParser.js +427 -81
- package/dist/esm/core/DocumentParser.js.map +1 -1
- package/dist/esm/core/RelationshipManager.js +2 -2
- package/dist/esm/core/RelationshipManager.js.map +1 -1
- package/dist/esm/elements/Comment.js +67 -12
- package/dist/esm/elements/Comment.js.map +1 -1
- package/dist/esm/elements/CommentManager.js +74 -16
- package/dist/esm/elements/CommentManager.js.map +1 -1
- package/dist/esm/elements/EndnoteManager.js.map +1 -1
- package/dist/esm/elements/Field.js +77 -35
- package/dist/esm/elements/Field.js.map +1 -1
- package/dist/esm/elements/FieldHelpers.js +7 -4
- package/dist/esm/elements/FieldHelpers.js.map +1 -1
- package/dist/esm/elements/Footer.js +39 -53
- package/dist/esm/elements/Footer.js.map +1 -1
- package/dist/esm/elements/FootnoteManager.js.map +1 -1
- package/dist/esm/elements/Header.js +39 -53
- package/dist/esm/elements/Header.js.map +1 -1
- package/dist/esm/elements/HeaderFooterManager.js +36 -6
- package/dist/esm/elements/HeaderFooterManager.js.map +1 -1
- package/dist/esm/elements/Hyperlink.js +69 -44
- package/dist/esm/elements/Hyperlink.js.map +1 -1
- package/dist/esm/elements/Image.js +33 -6
- package/dist/esm/elements/Image.js.map +1 -1
- package/dist/esm/elements/ImageManager.js +11 -0
- package/dist/esm/elements/ImageManager.js.map +1 -1
- package/dist/esm/elements/Paragraph.js +91 -26
- package/dist/esm/elements/Paragraph.js.map +1 -1
- package/dist/esm/elements/Revision.js +369 -29
- package/dist/esm/elements/Revision.js.map +1 -1
- package/dist/esm/elements/Run.js +24 -4
- package/dist/esm/elements/Run.js.map +1 -1
- package/dist/esm/elements/Section.js +17 -7
- package/dist/esm/elements/Section.js.map +1 -1
- package/dist/esm/elements/Shape.js +50 -42
- package/dist/esm/elements/Shape.js.map +1 -1
- package/dist/esm/elements/StructuredDocumentTag.js +46 -6
- package/dist/esm/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/esm/elements/Table.js +90 -42
- package/dist/esm/elements/Table.js.map +1 -1
- package/dist/esm/elements/TableCell.js +32 -13
- package/dist/esm/elements/TableCell.js.map +1 -1
- package/dist/esm/elements/TableOfContents.js +5 -7
- package/dist/esm/elements/TableOfContents.js.map +1 -1
- package/dist/esm/elements/TableRow.js +16 -1
- package/dist/esm/elements/TableRow.js.map +1 -1
- package/dist/esm/elements/TextBox.js +55 -42
- package/dist/esm/elements/TextBox.js.map +1 -1
- package/dist/esm/formatting/AbstractNumbering.js +1 -1
- package/dist/esm/formatting/AbstractNumbering.js.map +1 -1
- package/dist/esm/formatting/NumberingLevel.js +8 -6
- package/dist/esm/formatting/NumberingLevel.js.map +1 -1
- package/dist/esm/formatting/NumberingManager.js +16 -1
- package/dist/esm/formatting/NumberingManager.js.map +1 -1
- package/dist/esm/formatting/Style.js +14 -0
- package/dist/esm/formatting/Style.js.map +1 -1
- package/dist/esm/formatting/StylesManager.js +14 -2
- package/dist/esm/formatting/StylesManager.js.map +1 -1
- package/dist/esm/helpers/CleanupHelper.js +103 -26
- package/dist/esm/helpers/CleanupHelper.js.map +1 -1
- package/dist/esm/images/ImageOptimizer.js +52 -4
- package/dist/esm/images/ImageOptimizer.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal.js +1 -1
- package/dist/esm/internal.js.map +1 -1
- package/dist/esm/processors/CompatibilityUpgrader.js +7 -1
- package/dist/esm/processors/CompatibilityUpgrader.js.map +1 -1
- package/dist/esm/processors/InMemoryRevisionAcceptor.js +134 -13
- package/dist/esm/processors/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/esm/processors/RevisionWalker.js +58 -8
- package/dist/esm/processors/RevisionWalker.js.map +1 -1
- package/dist/esm/processors/SelectiveRevisionAcceptor.js +116 -17
- package/dist/esm/processors/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/esm/processors/cnfStyleDecoder.js +7 -7
- package/dist/esm/processors/cnfStyleDecoder.js.map +1 -1
- package/dist/esm/processors/stripTrackedChanges.js +16 -5
- package/dist/esm/processors/stripTrackedChanges.js.map +1 -1
- package/dist/esm/utils/deepClone.js +24 -11
- package/dist/esm/utils/deepClone.js.map +1 -1
- package/dist/esm/utils/units.js +1 -1
- package/dist/esm/utils/units.js.map +1 -1
- package/dist/esm/utils/validation.js +11 -23
- package/dist/esm/utils/validation.js.map +1 -1
- package/dist/esm/utils/xmlSanitization.js +131 -7
- package/dist/esm/utils/xmlSanitization.js.map +1 -1
- package/dist/esm/validation/RevisionAutoFixer.js +69 -55
- package/dist/esm/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/esm/validation/RevisionValidator.js +24 -20
- package/dist/esm/validation/RevisionValidator.js.map +1 -1
- package/dist/esm/xml/XMLBuilder.js +52 -20
- package/dist/esm/xml/XMLBuilder.js.map +1 -1
- package/dist/esm/xml/XMLParser.js +55 -13
- package/dist/esm/xml/XMLParser.js.map +1 -1
- package/dist/esm/zip/ZipHandler.js +37 -13
- package/dist/esm/zip/ZipHandler.js.map +1 -1
- package/dist/esm/zip/ZipReader.js +53 -6
- package/dist/esm/zip/ZipReader.js.map +1 -1
- package/dist/esm/zip/errors.js +7 -0
- package/dist/esm/zip/errors.js.map +1 -1
- package/dist/esm/zip/types.js +4 -0
- package/dist/esm/zip/types.js.map +1 -1
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +1 -1
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts +1 -1
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +8 -6
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/NumberingManager.d.ts.map +1 -1
- package/dist/formatting/NumberingManager.js +16 -1
- package/dist/formatting/NumberingManager.js.map +1 -1
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +14 -0
- package/dist/formatting/Style.js.map +1 -1
- package/dist/formatting/StylesManager.d.ts +2 -0
- package/dist/formatting/StylesManager.d.ts.map +1 -1
- package/dist/formatting/StylesManager.js +14 -2
- package/dist/formatting/StylesManager.js.map +1 -1
- package/dist/helpers/CleanupHelper.d.ts.map +1 -1
- package/dist/helpers/CleanupHelper.js +103 -26
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/images/ImageOptimizer.d.ts.map +1 -1
- package/dist/images/ImageOptimizer.js +52 -4
- package/dist/images/ImageOptimizer.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -1
- package/dist/internal.js.map +1 -1
- package/dist/processors/CompatibilityUpgrader.d.ts.map +1 -1
- package/dist/processors/CompatibilityUpgrader.js +7 -1
- package/dist/processors/CompatibilityUpgrader.js.map +1 -1
- package/dist/processors/InMemoryRevisionAcceptor.d.ts +1 -0
- package/dist/processors/InMemoryRevisionAcceptor.d.ts.map +1 -1
- package/dist/processors/InMemoryRevisionAcceptor.js +135 -13
- package/dist/processors/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/processors/RevisionWalker.d.ts +2 -0
- package/dist/processors/RevisionWalker.d.ts.map +1 -1
- package/dist/processors/RevisionWalker.js +58 -8
- package/dist/processors/RevisionWalker.js.map +1 -1
- package/dist/processors/SelectiveRevisionAcceptor.d.ts.map +1 -1
- package/dist/processors/SelectiveRevisionAcceptor.js +116 -17
- package/dist/processors/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/processors/cnfStyleDecoder.d.ts.map +1 -1
- package/dist/processors/cnfStyleDecoder.js +7 -7
- package/dist/processors/cnfStyleDecoder.js.map +1 -1
- package/dist/processors/stripTrackedChanges.d.ts.map +1 -1
- package/dist/processors/stripTrackedChanges.js +16 -5
- package/dist/processors/stripTrackedChanges.js.map +1 -1
- package/dist/utils/deepClone.d.ts.map +1 -1
- package/dist/utils/deepClone.js +24 -11
- package/dist/utils/deepClone.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/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +11 -23
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/xmlSanitization.d.ts +2 -0
- package/dist/utils/xmlSanitization.d.ts.map +1 -1
- package/dist/utils/xmlSanitization.js +133 -7
- package/dist/utils/xmlSanitization.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.d.ts +6 -2
- package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
- package/dist/validation/RevisionAutoFixer.js +68 -54
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/validation/RevisionValidator.d.ts +2 -0
- package/dist/validation/RevisionValidator.d.ts.map +1 -1
- package/dist/validation/RevisionValidator.js +26 -21
- package/dist/validation/RevisionValidator.js.map +1 -1
- package/dist/xml/XMLBuilder.d.ts +1 -0
- package/dist/xml/XMLBuilder.d.ts.map +1 -1
- package/dist/xml/XMLBuilder.js +52 -20
- package/dist/xml/XMLBuilder.js.map +1 -1
- package/dist/xml/XMLParser.d.ts +1 -0
- package/dist/xml/XMLParser.d.ts.map +1 -1
- package/dist/xml/XMLParser.js +55 -13
- package/dist/xml/XMLParser.js.map +1 -1
- package/dist/zip/ZipHandler.d.ts.map +1 -1
- package/dist/zip/ZipHandler.js +37 -13
- package/dist/zip/ZipHandler.js.map +1 -1
- package/dist/zip/ZipReader.d.ts.map +1 -1
- package/dist/zip/ZipReader.js +52 -5
- package/dist/zip/ZipReader.js.map +1 -1
- package/dist/zip/errors.d.ts +3 -0
- package/dist/zip/errors.d.ts.map +1 -1
- package/dist/zip/errors.js +9 -1
- package/dist/zip/errors.js.map +1 -1
- package/dist/zip/types.d.ts +4 -0
- package/dist/zip/types.d.ts.map +1 -1
- package/dist/zip/types.js +4 -0
- package/dist/zip/types.js.map +1 -1
- package/package.json +2 -2
- package/src/core/Document.ts +1159 -240
- package/src/core/DocumentGenerator.ts +106 -26
- package/src/core/DocumentParser.ts +681 -114
- package/src/core/RelationshipManager.ts +446 -442
- package/src/elements/Comment.ts +123 -18
- package/src/elements/CommentManager.ts +121 -22
- package/src/elements/EndnoteManager.ts +4 -1
- package/src/elements/Field.ts +134 -43
- package/src/elements/FieldHelpers.ts +20 -4
- package/src/elements/Footer.ts +62 -67
- package/src/elements/FootnoteManager.ts +4 -1
- package/src/elements/Header.ts +62 -67
- package/src/elements/HeaderFooterManager.ts +56 -8
- package/src/elements/Hyperlink.ts +150 -55
- package/src/elements/Image.ts +51 -7
- package/src/elements/ImageManager.ts +24 -0
- package/src/elements/Paragraph.ts +161 -40
- package/src/elements/Revision.ts +446 -47
- package/src/elements/Run.ts +44 -6
- package/src/elements/Section.ts +25 -9
- package/src/elements/Shape.ts +52 -44
- package/src/elements/StructuredDocumentTag.ts +83 -8
- package/src/elements/Table.ts +151 -50
- package/src/elements/TableCell.ts +57 -17
- package/src/elements/TableOfContents.ts +10 -9
- package/src/elements/TableRow.ts +35 -3
- package/src/elements/TextBox.ts +58 -43
- package/src/formatting/AbstractNumbering.ts +4 -2
- package/src/formatting/NumberingLevel.ts +50 -12
- package/src/formatting/NumberingManager.ts +32 -3
- package/src/formatting/Style.ts +14 -0
- package/src/formatting/StylesManager.ts +29 -2
- package/src/helpers/CleanupHelper.ts +122 -30
- package/src/images/ImageOptimizer.ts +64 -5
- package/src/index.ts +7 -0
- package/src/internal.ts +1 -0
- package/src/processors/CompatibilityUpgrader.ts +15 -2
- package/src/processors/InMemoryRevisionAcceptor.ts +276 -17
- package/src/processors/RevisionWalker.ts +83 -7
- package/src/processors/SelectiveRevisionAcceptor.ts +164 -28
- package/src/processors/cnfStyleDecoder.ts +18 -12
- package/src/processors/stripTrackedChanges.ts +47 -10
- package/src/utils/deepClone.ts +48 -14
- package/src/utils/units.ts +3 -1
- package/src/utils/validation.ts +30 -32
- package/src/utils/xmlSanitization.ts +218 -22
- package/src/validation/RevisionAutoFixer.ts +109 -65
- package/src/validation/RevisionValidator.ts +48 -23
- package/src/xml/XMLBuilder.ts +82 -22
- package/src/xml/XMLParser.ts +87 -20
- package/src/zip/ZipHandler.ts +61 -21
- package/src/zip/ZipReader.ts +135 -13
- package/src/zip/errors.ts +15 -0
- package/src/zip/types.ts +44 -2
|
@@ -4,29 +4,46 @@ exports.XML_CONTROL_CHARS = void 0;
|
|
|
4
4
|
exports.removeInvalidXmlChars = removeInvalidXmlChars;
|
|
5
5
|
exports.findInvalidXmlChars = findInvalidXmlChars;
|
|
6
6
|
exports.hasInvalidXmlChars = hasInvalidXmlChars;
|
|
7
|
+
exports.reorderRunPropertyChildren = reorderRunPropertyChildren;
|
|
8
|
+
exports.normalizeAnchorSizeRel = normalizeAnchorSizeRel;
|
|
7
9
|
const logger_js_1 = require("./logger.js");
|
|
8
|
-
const INVALID_XML_CHAR_REGEX = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
|
|
10
|
+
const INVALID_XML_CHAR_REGEX = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
|
|
11
|
+
const UNPAIRED_SURROGATE_REGEX = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
|
|
9
12
|
function removeInvalidXmlChars(text, logWarning = true) {
|
|
10
13
|
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
11
|
-
|
|
14
|
+
UNPAIRED_SURROGATE_REGEX.lastIndex = 0;
|
|
15
|
+
if (logWarning && (INVALID_XML_CHAR_REGEX.test(text) || UNPAIRED_SURROGATE_REGEX.test(text))) {
|
|
12
16
|
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
17
|
+
UNPAIRED_SURROGATE_REGEX.lastIndex = 0;
|
|
13
18
|
const invalidChars = findInvalidXmlChars(text);
|
|
14
19
|
const hexCodes = invalidChars
|
|
15
20
|
.map((c) => `0x${c.toString(16).toUpperCase().padStart(2, '0')}`)
|
|
16
21
|
.join(', ');
|
|
17
|
-
(0, logger_js_1.getGlobalLogger)().warn(`[XMLSanitization] Removing invalid XML
|
|
22
|
+
(0, logger_js_1.getGlobalLogger)().warn(`[XMLSanitization] Removing invalid XML characters: ${hexCodes}`);
|
|
18
23
|
}
|
|
19
24
|
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
20
|
-
|
|
25
|
+
UNPAIRED_SURROGATE_REGEX.lastIndex = 0;
|
|
26
|
+
return text.replace(INVALID_XML_CHAR_REGEX, '').replace(UNPAIRED_SURROGATE_REGEX, '');
|
|
21
27
|
}
|
|
22
28
|
function findInvalidXmlChars(text) {
|
|
23
29
|
const invalid = [];
|
|
24
30
|
for (let i = 0; i < text.length; i++) {
|
|
25
31
|
const code = text.charCodeAt(i);
|
|
26
|
-
|
|
32
|
+
let isInvalid = (code >= 0x00 && code <= 0x08) ||
|
|
27
33
|
(code >= 0x0b && code <= 0x0c) ||
|
|
28
34
|
(code >= 0x0e && code <= 0x1f) ||
|
|
29
|
-
code === 0x7f
|
|
35
|
+
code === 0x7f ||
|
|
36
|
+
code === 0xfffe ||
|
|
37
|
+
code === 0xffff;
|
|
38
|
+
if (!isInvalid && code >= 0xd800 && code <= 0xdbff) {
|
|
39
|
+
const next = text.charCodeAt(i + 1);
|
|
40
|
+
isInvalid = !(next >= 0xdc00 && next <= 0xdfff);
|
|
41
|
+
}
|
|
42
|
+
else if (!isInvalid && code >= 0xdc00 && code <= 0xdfff) {
|
|
43
|
+
const prev = text.charCodeAt(i - 1);
|
|
44
|
+
isInvalid = !(prev >= 0xd800 && prev <= 0xdbff);
|
|
45
|
+
}
|
|
46
|
+
if (isInvalid) {
|
|
30
47
|
if (!invalid.includes(code)) {
|
|
31
48
|
invalid.push(code);
|
|
32
49
|
}
|
|
@@ -36,7 +53,116 @@ function findInvalidXmlChars(text) {
|
|
|
36
53
|
}
|
|
37
54
|
function hasInvalidXmlChars(text) {
|
|
38
55
|
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
39
|
-
|
|
56
|
+
UNPAIRED_SURROGATE_REGEX.lastIndex = 0;
|
|
57
|
+
return INVALID_XML_CHAR_REGEX.test(text) || UNPAIRED_SURROGATE_REGEX.test(text);
|
|
58
|
+
}
|
|
59
|
+
const CT_RPR_CHILD_ORDER = [
|
|
60
|
+
'rStyle',
|
|
61
|
+
'rFonts',
|
|
62
|
+
'b',
|
|
63
|
+
'bCs',
|
|
64
|
+
'i',
|
|
65
|
+
'iCs',
|
|
66
|
+
'caps',
|
|
67
|
+
'smallCaps',
|
|
68
|
+
'strike',
|
|
69
|
+
'dstrike',
|
|
70
|
+
'outline',
|
|
71
|
+
'shadow',
|
|
72
|
+
'emboss',
|
|
73
|
+
'imprint',
|
|
74
|
+
'noProof',
|
|
75
|
+
'snapToGrid',
|
|
76
|
+
'vanish',
|
|
77
|
+
'webHidden',
|
|
78
|
+
'color',
|
|
79
|
+
'spacing',
|
|
80
|
+
'w',
|
|
81
|
+
'kern',
|
|
82
|
+
'position',
|
|
83
|
+
'sz',
|
|
84
|
+
'szCs',
|
|
85
|
+
'highlight',
|
|
86
|
+
'u',
|
|
87
|
+
'effect',
|
|
88
|
+
'bdr',
|
|
89
|
+
'shd',
|
|
90
|
+
'fitText',
|
|
91
|
+
'vertAlign',
|
|
92
|
+
'rtl',
|
|
93
|
+
'cs',
|
|
94
|
+
'em',
|
|
95
|
+
'lang',
|
|
96
|
+
'eastAsianLayout',
|
|
97
|
+
'specVanish',
|
|
98
|
+
'oMath',
|
|
99
|
+
];
|
|
100
|
+
function splitTopLevelElements(inner) {
|
|
101
|
+
const children = [];
|
|
102
|
+
const tagRegex = /<([A-Za-z][\w:.-]*)([^>]*?)(\/?)>|<\/([A-Za-z][\w:.-]*)\s*>/g;
|
|
103
|
+
let depth = 0;
|
|
104
|
+
let start = -1;
|
|
105
|
+
let match;
|
|
106
|
+
while ((match = tagRegex.exec(inner)) !== null) {
|
|
107
|
+
const isClosing = match[4] !== undefined;
|
|
108
|
+
const isSelfClosing = match[3] === '/';
|
|
109
|
+
if (isClosing) {
|
|
110
|
+
if (depth > 0) {
|
|
111
|
+
depth--;
|
|
112
|
+
if (depth === 0 && start !== -1) {
|
|
113
|
+
children.push(inner.slice(start, tagRegex.lastIndex));
|
|
114
|
+
start = -1;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (isSelfClosing) {
|
|
120
|
+
if (depth === 0) {
|
|
121
|
+
children.push(inner.slice(match.index, tagRegex.lastIndex));
|
|
122
|
+
}
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (depth === 0)
|
|
126
|
+
start = match.index;
|
|
127
|
+
depth++;
|
|
128
|
+
}
|
|
129
|
+
return children;
|
|
130
|
+
}
|
|
131
|
+
function reorderRunPropertyChildren(xml) {
|
|
132
|
+
if (!xml || !xml.includes('<w:rPr'))
|
|
133
|
+
return xml;
|
|
134
|
+
const orderIndex = (fragment) => {
|
|
135
|
+
const nameMatch = /^<w:(\w+)/.exec(fragment);
|
|
136
|
+
const name = nameMatch?.[1];
|
|
137
|
+
if (!name)
|
|
138
|
+
return CT_RPR_CHILD_ORDER.length;
|
|
139
|
+
const idx = CT_RPR_CHILD_ORDER.indexOf(name);
|
|
140
|
+
return idx === -1 ? CT_RPR_CHILD_ORDER.length : idx;
|
|
141
|
+
};
|
|
142
|
+
return xml.replace(/<w:rPr(\s[^>]*)?>([\s\S]*?)<\/w:rPr>/g, (full, attrs, inner) => {
|
|
143
|
+
if (!inner || !inner.includes('<'))
|
|
144
|
+
return full;
|
|
145
|
+
const children = splitTopLevelElements(inner);
|
|
146
|
+
if (children.length < 2)
|
|
147
|
+
return full;
|
|
148
|
+
const ordered = children
|
|
149
|
+
.map((frag, i) => ({ frag, i, order: orderIndex(frag) }))
|
|
150
|
+
.sort((a, b) => a.order - b.order || a.i - b.i);
|
|
151
|
+
if (ordered.every((c, i) => c.i === i))
|
|
152
|
+
return full;
|
|
153
|
+
return `<w:rPr${attrs ?? ''}>${ordered.map((c) => c.frag).join('')}</w:rPr>`;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function normalizeAnchorSizeRel(xml) {
|
|
157
|
+
if (!xml)
|
|
158
|
+
return xml;
|
|
159
|
+
return xml
|
|
160
|
+
.replace(/(<wp14:sizeRelH\b[^>]*>)([^<]+)(<\/wp14:sizeRelH>)/g, (_m, open, text, close) => text.trim() === ''
|
|
161
|
+
? `${open}${text}${close}`
|
|
162
|
+
: `${open}<wp14:pctWidth>${text.trim()}</wp14:pctWidth>${close}`)
|
|
163
|
+
.replace(/(<wp14:sizeRelV\b[^>]*>)([^<]+)(<\/wp14:sizeRelV>)/g, (_m, open, text, close) => text.trim() === ''
|
|
164
|
+
? `${open}${text}${close}`
|
|
165
|
+
: `${open}<wp14:pctHeight>${text.trim()}</wp14:pctHeight>${close}`);
|
|
40
166
|
}
|
|
41
167
|
exports.XML_CONTROL_CHARS = {
|
|
42
168
|
NULL: 0x00,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xmlSanitization.js","sourceRoot":"","sources":["../../src/utils/xmlSanitization.ts"],"names":[],"mappings":";;;AAuDA,sDAoBC;AAoBD,kDAqBC;AAkBD,gDAIC;AAtHD,2CAA8C;AAO9C,MAAM,sBAAsB,GAAG,mCAAmC,CAAC;AA4BnE,SAAgB,qBAAqB,CAAC,IAAY,EAAE,UAAU,GAAG,IAAI;IAEnE,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;IAErC,IAAI,UAAU,IAAI,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAEpD,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;QAErC,MAAM,YAAY,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,YAAY;aAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;aAChE,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,IAAA,2BAAe,GAAE,CAAC,IAAI,CACpB,8DAA8D,QAAQ,EAAE,CACzE,CAAC;IACJ,CAAC;IAGD,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;IACrC,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;AAClD,CAAC;AAoBD,SAAgB,mBAAmB,CAAC,IAAY;IAC9C,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAGhC,IACE,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;YAC9B,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;YAC9B,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;YAC9B,IAAI,KAAK,IAAI,EACb,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAkBD,SAAgB,kBAAkB,CAAC,IAAY;IAE7C,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;IACrC,OAAO,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC;AAKY,QAAA,iBAAiB,GAAG;IAE/B,IAAI,EAAE,IAAI;IAEV,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,EAAE,EAAE,IAAI;IAER,GAAG,EAAE,IAAI;IAET,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,GAAG,EAAE,IAAI;CACD,CAAC","sourcesContent":["/**\n * XML Sanitization Utilities\n *\n * Provides functions for validating and sanitizing text content per XML 1.0 specification.\n * Per XML 1.0, certain control characters are invalid and must be removed before\n * including text in XML documents.\n *\n * Valid characters in XML 1.0:\n * - 0x09 (tab), 0x0A (newline), 0x0D (carriage return)\n * - 0x20-0xD7FF, 0xE000-0xFFFD, 0x10000-0x10FFFF\n *\n * Invalid characters (control characters that must be removed):\n * - 0x00-0x08 (NULL through BACKSPACE)\n * - 0x0B-0x0C (VERTICAL TAB and FORM FEED)\n * - 0x0E-0x1F (SHIFT OUT through UNIT SEPARATOR)\n * - 0x7F (DELETE)\n *\n * @module xmlSanitization\n */\n\nimport { getGlobalLogger } from './logger.js';\n\n/**\n * Regular expression matching invalid XML 1.0 control characters.\n * Matches: 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F\n * Does NOT match valid chars: 0x09 (tab), 0x0A (newline), 0x0D (CR)\n */\nconst INVALID_XML_CHAR_REGEX = /[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g;\n\n/**\n * Removes invalid XML 1.0 control characters from text.\n *\n * Per XML 1.0 spec, characters 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid\n * and cannot appear in XML documents. This function removes them.\n *\n * Valid control characters are preserved:\n * - Tab (0x09)\n * - Line Feed / Newline (0x0A)\n * - Carriage Return (0x0D)\n *\n * @param text - Input text to sanitize\n * @param logWarning - If true, logs a warning when invalid chars are found (default: true)\n * @returns Sanitized text with invalid control characters removed\n *\n * @example\n * ```typescript\n * // Remove NULL byte from text\n * const clean = removeInvalidXmlChars(\"Hello\\x00World\");\n * // Returns: \"HelloWorld\"\n *\n * // Tab and newline are preserved\n * const preserved = removeInvalidXmlChars(\"Hello\\tWorld\\n\");\n * // Returns: \"Hello\\tWorld\\n\"\n * ```\n */\nexport function removeInvalidXmlChars(text: string, logWarning = true): string {\n // Reset regex lastIndex for global regex\n INVALID_XML_CHAR_REGEX.lastIndex = 0;\n\n if (logWarning && INVALID_XML_CHAR_REGEX.test(text)) {\n // Reset regex lastIndex after test\n INVALID_XML_CHAR_REGEX.lastIndex = 0;\n\n const invalidChars = findInvalidXmlChars(text);\n const hexCodes = invalidChars\n .map((c) => `0x${c.toString(16).toUpperCase().padStart(2, '0')}`)\n .join(', ');\n getGlobalLogger().warn(\n `[XMLSanitization] Removing invalid XML control characters: ${hexCodes}`\n );\n }\n\n // Reset regex lastIndex before replace\n INVALID_XML_CHAR_REGEX.lastIndex = 0;\n return text.replace(INVALID_XML_CHAR_REGEX, '');\n}\n\n/**\n * Finds all invalid XML 1.0 control characters in text.\n *\n * Returns an array of unique character codes that are invalid per XML 1.0 spec.\n * This is useful for diagnostics and error reporting.\n *\n * @param text - Text to scan for invalid characters\n * @returns Array of unique invalid character codes found, or empty array if text is valid\n *\n * @example\n * ```typescript\n * const invalid = findInvalidXmlChars(\"Hello\\x00\\x08World\");\n * // Returns: [0, 8] - NULL and BACKSPACE codes\n *\n * const valid = findInvalidXmlChars(\"Hello\\tWorld\");\n * // Returns: [] - tab is valid\n * ```\n */\nexport function findInvalidXmlChars(text: string): number[] {\n const invalid: number[] = [];\n\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n\n // Check if character is in invalid ranges\n if (\n (code >= 0x00 && code <= 0x08) || // NULL through BACKSPACE\n (code >= 0x0b && code <= 0x0c) || // VERTICAL TAB and FORM FEED\n (code >= 0x0e && code <= 0x1f) || // SHIFT OUT through UNIT SEPARATOR\n code === 0x7f // DELETE\n ) {\n // Only add unique codes\n if (!invalid.includes(code)) {\n invalid.push(code);\n }\n }\n }\n\n return invalid;\n}\n\n/**\n * Checks if text contains any invalid XML 1.0 control characters.\n *\n * This is a fast check that returns true/false without identifying specific characters.\n * Use `findInvalidXmlChars()` if you need to know which characters are invalid.\n *\n * @param text - Text to check\n * @returns true if text contains invalid characters, false otherwise\n *\n * @example\n * ```typescript\n * hasInvalidXmlChars(\"Hello\\x00World\"); // true - NULL byte\n * hasInvalidXmlChars(\"Hello\\tWorld\"); // false - tab is valid\n * hasInvalidXmlChars(\"Normal text\"); // false\n * ```\n */\nexport function hasInvalidXmlChars(text: string): boolean {\n // Reset regex lastIndex for global regex\n INVALID_XML_CHAR_REGEX.lastIndex = 0;\n return INVALID_XML_CHAR_REGEX.test(text);\n}\n\n/**\n * Character code constants for documentation and testing.\n */\nexport const XML_CONTROL_CHARS = {\n /** NULL (0x00) - Invalid */\n NULL: 0x00,\n /** Start of Heading (0x01) - Invalid */\n SOH: 0x01,\n /** Start of Text (0x02) - Invalid */\n STX: 0x02,\n /** End of Text (0x03) - Invalid */\n ETX: 0x03,\n /** End of Transmission (0x04) - Invalid */\n EOT: 0x04,\n /** Enquiry (0x05) - Invalid */\n ENQ: 0x05,\n /** Acknowledge (0x06) - Invalid */\n ACK: 0x06,\n /** Bell (0x07) - Invalid */\n BEL: 0x07,\n /** Backspace (0x08) - Invalid */\n BS: 0x08,\n /** Horizontal Tab (0x09) - VALID */\n TAB: 0x09,\n /** Line Feed / Newline (0x0A) - VALID */\n LF: 0x0a,\n /** Vertical Tab (0x0B) - Invalid */\n VT: 0x0b,\n /** Form Feed (0x0C) - Invalid */\n FF: 0x0c,\n /** Carriage Return (0x0D) - VALID */\n CR: 0x0d,\n /** Shift Out (0x0E) - Invalid */\n SO: 0x0e,\n /** Unit Separator (0x1F) - Invalid */\n US: 0x1f,\n /** Delete (0x7F) - Invalid */\n DEL: 0x7f,\n} as const;\n"]}
|
|
1
|
+
{"version":3,"file":"xmlSanitization.js","sourceRoot":"","sources":["../../src/utils/xmlSanitization.ts"],"names":[],"mappings":";;;AAuEA,sDAqBC;AAqBD,kDAkCC;AAkBD,gDAKC;AAyGD,gEA2BC;AAeD,wDAiBC;AAxTD,2CAA8C;AAO9C,MAAM,sBAAsB,GAAG,qCAAqC,CAAC;AASrE,MAAM,wBAAwB,GAC5B,yEAAyE,CAAC;AAgC5E,SAAgB,qBAAqB,CAAC,IAAY,EAAE,UAAU,GAAG,IAAI;IAEnE,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;IACrC,wBAAwB,CAAC,SAAS,GAAG,CAAC,CAAC;IAEvC,IAAI,UAAU,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAE7F,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;QACrC,wBAAwB,CAAC,SAAS,GAAG,CAAC,CAAC;QAEvC,MAAM,YAAY,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,YAAY;aAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;aAChE,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,IAAA,2BAAe,GAAE,CAAC,IAAI,CAAC,sDAAsD,QAAQ,EAAE,CAAC,CAAC;IAC3F,CAAC;IAGD,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;IACrC,wBAAwB,CAAC,SAAS,GAAG,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAC;AACxF,CAAC;AAqBD,SAAgB,mBAAmB,CAAC,IAAY;IAC9C,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAGhC,IAAI,SAAS,GACX,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;YAC9B,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;YAC9B,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;YAC9B,IAAI,KAAK,IAAI;YACb,IAAI,KAAK,MAAM;YACf,IAAI,KAAK,MAAM,CAAC;QAElB,IAAI,CAAC,SAAS,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;YAEnD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACpC,SAAS,GAAG,CAAC,CAAC,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC;QAClD,CAAC;aAAM,IAAI,CAAC,SAAS,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;YAE1D,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACpC,SAAS,GAAG,CAAC,CAAC,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YAEd,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAkBD,SAAgB,kBAAkB,CAAC,IAAY;IAE7C,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;IACrC,wBAAwB,CAAC,SAAS,GAAG,CAAC,CAAC;IACvC,OAAO,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClF,CAAC;AAQD,MAAM,kBAAkB,GAAsB;IAC5C,QAAQ;IACR,QAAQ;IACR,GAAG;IACH,KAAK;IACL,GAAG;IACH,KAAK;IACL,MAAM;IACN,WAAW;IACX,QAAQ;IACR,SAAS;IACT,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,SAAS;IACT,YAAY;IACZ,QAAQ;IACR,WAAW;IACX,OAAO;IACP,SAAS;IACT,GAAG;IACH,MAAM;IACN,UAAU;IACV,IAAI;IACJ,MAAM;IACN,WAAW;IACX,GAAG;IACH,QAAQ;IACR,KAAK;IACL,KAAK;IACL,SAAS;IACT,WAAW;IACX,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,MAAM;IACN,iBAAiB;IACjB,YAAY;IACZ,OAAO;CACR,CAAC;AASF,SAAS,qBAAqB,CAAC,KAAa;IAC1C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,8DAA8D,CAAC;IAChF,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;IACf,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;QACzC,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;QACvC,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACd,KAAK,EAAE,CAAC;gBACR,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;oBAChC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;oBACtD,KAAK,GAAG,CAAC,CAAC,CAAC;gBACb,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,aAAa,EAAE,CAAC;YAClB,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;YAC9D,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,CAAC;YAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QACrC,KAAK,EAAE,CAAC;IACV,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAkBD,SAAgB,0BAA0B,CAAC,GAAW;IACpD,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,GAAG,CAAC;IAEhD,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAU,EAAE;QAC9C,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI;YAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC;QAC5C,MAAM,GAAG,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7C,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;IACtD,CAAC,CAAC;IAIF,OAAO,GAAG,CAAC,OAAO,CAAC,uCAAuC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QACjF,IAAI,CAAC,KAAK,IAAI,CAAE,KAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5D,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAErC,MAAM,OAAO,GAAG,QAAQ;aACrB,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aAExD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAElD,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAEpD,OAAO,SAAS,KAAK,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC;IAC/E,CAAC,CAAC,CAAC;AACL,CAAC;AAeD,SAAgB,sBAAsB,CAAC,GAAW;IAChD,IAAI,CAAC,GAAG;QAAE,OAAO,GAAG,CAAC;IACrB,OAAO,GAAG;SACP,OAAO,CACN,qDAAqD,EACrD,CAAC,EAAE,EAAE,IAAY,EAAE,IAAY,EAAE,KAAa,EAAE,EAAE,CAChD,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAChB,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE;QAC1B,CAAC,CAAC,GAAG,IAAI,kBAAkB,IAAI,CAAC,IAAI,EAAE,mBAAmB,KAAK,EAAE,CACrE;SACA,OAAO,CACN,qDAAqD,EACrD,CAAC,EAAE,EAAE,IAAY,EAAE,IAAY,EAAE,KAAa,EAAE,EAAE,CAChD,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAChB,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE;QAC1B,CAAC,CAAC,GAAG,IAAI,mBAAmB,IAAI,CAAC,IAAI,EAAE,oBAAoB,KAAK,EAAE,CACvE,CAAC;AACN,CAAC;AAKY,QAAA,iBAAiB,GAAG;IAE/B,IAAI,EAAE,IAAI;IAEV,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,GAAG,EAAE,IAAI;IAET,EAAE,EAAE,IAAI;IAER,GAAG,EAAE,IAAI;IAET,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,EAAE,EAAE,IAAI;IAER,GAAG,EAAE,IAAI;CACD,CAAC","sourcesContent":["/**\n * XML Sanitization Utilities\n *\n * Provides functions for validating and sanitizing text content per XML 1.0 specification.\n * Per XML 1.0, certain control characters are invalid and must be removed before\n * including text in XML documents.\n *\n * Valid characters in XML 1.0:\n * - 0x09 (tab), 0x0A (newline), 0x0D (carriage return)\n * - 0x20-0xD7FF, 0xE000-0xFFFD, 0x10000-0x10FFFF\n *\n * Invalid characters that must be removed:\n * - 0x00-0x08 (NULL through BACKSPACE)\n * - 0x0B-0x0C (VERTICAL TAB and FORM FEED)\n * - 0x0E-0x1F (SHIFT OUT through UNIT SEPARATOR)\n * - 0x7F (DELETE)\n * - 0xFFFE-0xFFFF (Unicode noncharacters excluded by the Char production)\n * - Unpaired surrogates (0xD800-0xDFFF outside a valid high/low pair)\n *\n * @module xmlSanitization\n */\n\nimport { getGlobalLogger } from './logger.js';\n\n/**\n * Regular expression matching invalid XML 1.0 characters.\n * Matches: 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F, 0xFFFE, 0xFFFF\n * Does NOT match valid chars: 0x09 (tab), 0x0A (newline), 0x0D (CR)\n */\nconst INVALID_XML_CHAR_REGEX = /[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g;\n\n/**\n * Matches surrogate code units that do not form a valid high/low pair.\n * XML 1.0 Char excludes 0xD800-0xDFFF entirely; only properly paired\n * surrogates (which decode to a single 0x10000-0x10FFFF character) are\n * legal, so lone halves must be stripped or they corrupt the part at\n * UTF-8 encode time.\n */\nconst UNPAIRED_SURROGATE_REGEX =\n /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/g;\n\n/**\n * Removes invalid XML 1.0 characters from text.\n *\n * Per XML 1.0 spec, characters 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F,\n * 0xFFFE, 0xFFFF, and unpaired surrogates are invalid and cannot appear\n * in XML documents. This function removes them.\n *\n * Valid control characters are preserved:\n * - Tab (0x09)\n * - Line Feed / Newline (0x0A)\n * - Carriage Return (0x0D)\n *\n * Properly paired surrogates (astral-plane characters such as emoji)\n * are preserved.\n *\n * @param text - Input text to sanitize\n * @param logWarning - If true, logs a warning when invalid chars are found (default: true)\n * @returns Sanitized text with invalid characters removed\n *\n * @example\n * ```typescript\n * // Remove NULL byte from text\n * const clean = removeInvalidXmlChars(\"Hello\\x00World\");\n * // Returns: \"HelloWorld\"\n *\n * // Tab and newline are preserved\n * const preserved = removeInvalidXmlChars(\"Hello\\tWorld\\n\");\n * // Returns: \"Hello\\tWorld\\n\"\n * ```\n */\nexport function removeInvalidXmlChars(text: string, logWarning = true): string {\n // Reset regex lastIndex for global regexes\n INVALID_XML_CHAR_REGEX.lastIndex = 0;\n UNPAIRED_SURROGATE_REGEX.lastIndex = 0;\n\n if (logWarning && (INVALID_XML_CHAR_REGEX.test(text) || UNPAIRED_SURROGATE_REGEX.test(text))) {\n // Reset regex lastIndex after test\n INVALID_XML_CHAR_REGEX.lastIndex = 0;\n UNPAIRED_SURROGATE_REGEX.lastIndex = 0;\n\n const invalidChars = findInvalidXmlChars(text);\n const hexCodes = invalidChars\n .map((c) => `0x${c.toString(16).toUpperCase().padStart(2, '0')}`)\n .join(', ');\n getGlobalLogger().warn(`[XMLSanitization] Removing invalid XML characters: ${hexCodes}`);\n }\n\n // Reset regex lastIndex before replace\n INVALID_XML_CHAR_REGEX.lastIndex = 0;\n UNPAIRED_SURROGATE_REGEX.lastIndex = 0;\n return text.replace(INVALID_XML_CHAR_REGEX, '').replace(UNPAIRED_SURROGATE_REGEX, '');\n}\n\n/**\n * Finds all invalid XML 1.0 characters in text.\n *\n * Returns an array of unique character codes that are invalid per XML 1.0 spec,\n * including 0xFFFE/0xFFFF noncharacters and unpaired surrogate code units.\n * This is useful for diagnostics and error reporting.\n *\n * @param text - Text to scan for invalid characters\n * @returns Array of unique invalid character codes found, or empty array if text is valid\n *\n * @example\n * ```typescript\n * const invalid = findInvalidXmlChars(\"Hello\\x00\\x08World\");\n * // Returns: [0, 8] - NULL and BACKSPACE codes\n *\n * const valid = findInvalidXmlChars(\"Hello\\tWorld\");\n * // Returns: [] - tab is valid\n * ```\n */\nexport function findInvalidXmlChars(text: string): number[] {\n const invalid: number[] = [];\n\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n\n // Check if character is in invalid ranges\n let isInvalid =\n (code >= 0x00 && code <= 0x08) || // NULL through BACKSPACE\n (code >= 0x0b && code <= 0x0c) || // VERTICAL TAB and FORM FEED\n (code >= 0x0e && code <= 0x1f) || // SHIFT OUT through UNIT SEPARATOR\n code === 0x7f || // DELETE\n code === 0xfffe || // Noncharacter excluded by XML 1.0 Char\n code === 0xffff; // Noncharacter excluded by XML 1.0 Char\n\n if (!isInvalid && code >= 0xd800 && code <= 0xdbff) {\n // High surrogate is only valid when followed by a low surrogate\n const next = text.charCodeAt(i + 1); // NaN at end of string fails the range check\n isInvalid = !(next >= 0xdc00 && next <= 0xdfff);\n } else if (!isInvalid && code >= 0xdc00 && code <= 0xdfff) {\n // Low surrogate is only valid when preceded by a high surrogate\n const prev = text.charCodeAt(i - 1); // NaN at start of string fails the range check\n isInvalid = !(prev >= 0xd800 && prev <= 0xdbff);\n }\n\n if (isInvalid) {\n // Only add unique codes\n if (!invalid.includes(code)) {\n invalid.push(code);\n }\n }\n }\n\n return invalid;\n}\n\n/**\n * Checks if text contains any invalid XML 1.0 characters.\n *\n * This is a fast check that returns true/false without identifying specific characters.\n * Use `findInvalidXmlChars()` if you need to know which characters are invalid.\n *\n * @param text - Text to check\n * @returns true if text contains invalid characters, false otherwise\n *\n * @example\n * ```typescript\n * hasInvalidXmlChars(\"Hello\\x00World\"); // true - NULL byte\n * hasInvalidXmlChars(\"Hello\\tWorld\"); // false - tab is valid\n * hasInvalidXmlChars(\"Normal text\"); // false\n * ```\n */\nexport function hasInvalidXmlChars(text: string): boolean {\n // Reset regex lastIndex for global regexes\n INVALID_XML_CHAR_REGEX.lastIndex = 0;\n UNPAIRED_SURROGATE_REGEX.lastIndex = 0;\n return INVALID_XML_CHAR_REGEX.test(text) || UNPAIRED_SURROGATE_REGEX.test(text);\n}\n\n/**\n * CT_RPr child element order per ECMA-376 Part 1 §17.3.2.28 (local names,\n * `w:` namespace). Used to repair raw-preserved run-property blocks whose\n * children are out of schema order — Word rejects, for example, a `w:b`\n * that appears after `w:color`/`w:sz` and reports the document as corrupt.\n */\nconst CT_RPR_CHILD_ORDER: readonly string[] = [\n 'rStyle',\n 'rFonts',\n 'b',\n 'bCs',\n 'i',\n 'iCs',\n 'caps',\n 'smallCaps',\n 'strike',\n 'dstrike',\n 'outline',\n 'shadow',\n 'emboss',\n 'imprint',\n 'noProof',\n 'snapToGrid',\n 'vanish',\n 'webHidden',\n 'color',\n 'spacing',\n 'w',\n 'kern',\n 'position',\n 'sz',\n 'szCs',\n 'highlight',\n 'u',\n 'effect',\n 'bdr',\n 'shd',\n 'fitText',\n 'vertAlign',\n 'rtl',\n 'cs',\n 'em',\n 'lang',\n 'eastAsianLayout',\n 'specVanish',\n 'oMath',\n];\n\n/**\n * Splits the inner content of an element into its top-level child elements,\n * respecting nesting so that a child's descendants are kept with it. Returns\n * the raw XML fragment for each direct child in document order. Non-element\n * text between children (whitespace) is dropped, which is safe for the\n * element-only content models this helper targets (e.g. `w:rPr`).\n */\nfunction splitTopLevelElements(inner: string): string[] {\n const children: string[] = [];\n const tagRegex = /<([A-Za-z][\\w:.-]*)([^>]*?)(\\/?)>|<\\/([A-Za-z][\\w:.-]*)\\s*>/g;\n let depth = 0;\n let start = -1;\n let match: RegExpExecArray | null;\n while ((match = tagRegex.exec(inner)) !== null) {\n const isClosing = match[4] !== undefined;\n const isSelfClosing = match[3] === '/';\n if (isClosing) {\n if (depth > 0) {\n depth--;\n if (depth === 0 && start !== -1) {\n children.push(inner.slice(start, tagRegex.lastIndex));\n start = -1;\n }\n }\n continue;\n }\n if (isSelfClosing) {\n if (depth === 0) {\n children.push(inner.slice(match.index, tagRegex.lastIndex));\n }\n continue;\n }\n // Opening tag of a paired element\n if (depth === 0) start = match.index;\n depth++;\n }\n return children;\n}\n\n/**\n * Reorders the direct children of every `<w:rPr>` block in a raw XML part to\n * the ECMA-376 CT_RPr sequence. Unknown/unmodeled children retain their\n * relative position at the end of the block. The transform is idempotent:\n * already-ordered run properties are returned unchanged.\n *\n * Some producers (and older versions of this framework) appended boolean\n * toggles such as `w:b`/`w:bCs` to the end of an existing `w:rPr`, leaving\n * them after `w:color`/`w:sz`. Word treats the out-of-order child as an\n * unexpected element and flags the whole document as corrupt. Numbering\n * definitions are written back verbatim for fidelity, so this repair runs on\n * the preserved part before it is saved.\n *\n * @param xml - Raw XML for a part containing `w:rPr` blocks (e.g. numbering.xml)\n * @returns XML with every `w:rPr` child sequence normalized to schema order\n */\nexport function reorderRunPropertyChildren(xml: string): string {\n if (!xml || !xml.includes('<w:rPr')) return xml;\n\n const orderIndex = (fragment: string): number => {\n const nameMatch = /^<w:(\\w+)/.exec(fragment);\n const name = nameMatch?.[1];\n if (!name) return CT_RPR_CHILD_ORDER.length;\n const idx = CT_RPR_CHILD_ORDER.indexOf(name);\n return idx === -1 ? CT_RPR_CHILD_ORDER.length : idx;\n };\n\n // Only match non-empty <w:rPr>...</w:rPr> blocks; self-closing <w:rPr/> has\n // no children to reorder.\n return xml.replace(/<w:rPr(\\s[^>]*)?>([\\s\\S]*?)<\\/w:rPr>/g, (full, attrs, inner) => {\n if (!inner || !(inner as string).includes('<')) return full;\n const children = splitTopLevelElements(inner);\n if (children.length < 2) return full;\n\n const ordered = children\n .map((frag, i) => ({ frag, i, order: orderIndex(frag) }))\n // Stable sort: ties (including unknown children) keep original order.\n .sort((a, b) => a.order - b.order || a.i - b.i);\n\n if (ordered.every((c, i) => c.i === i)) return full; // already in order\n\n return `<w:rPr${attrs ?? ''}>${ordered.map((c) => c.frag).join('')}</w:rPr>`;\n });\n}\n\n/**\n * Normalizes malformed floating-drawing relative-size elements in a raw anchor\n * fragment. Per ECMA-376 (DrawingML wordprocessing 2010 extensions),\n * `wp14:sizeRelH` must contain a `wp14:pctWidth` child and `wp14:sizeRelV` a\n * `wp14:pctHeight` child. Some producers emit the percentage as bare text\n * content (`<wp14:sizeRelH relativeFrom=\"margin\">0</wp14:sizeRelH>`), which\n * Word rejects as incomplete content. This wraps such text in the required\n * child element. Already-valid nested forms are left untouched because the\n * text-content pattern (`[^<]`) cannot match an element child.\n *\n * @param xml - Raw anchor-extras fragment captured during parsing\n * @returns Fragment with sizeRelH/sizeRelV normalized to schema-valid form\n */\nexport function normalizeAnchorSizeRel(xml: string): string {\n if (!xml) return xml;\n return xml\n .replace(\n /(<wp14:sizeRelH\\b[^>]*>)([^<]+)(<\\/wp14:sizeRelH>)/g,\n (_m, open: string, text: string, close: string) =>\n text.trim() === ''\n ? `${open}${text}${close}`\n : `${open}<wp14:pctWidth>${text.trim()}</wp14:pctWidth>${close}`\n )\n .replace(\n /(<wp14:sizeRelV\\b[^>]*>)([^<]+)(<\\/wp14:sizeRelV>)/g,\n (_m, open: string, text: string, close: string) =>\n text.trim() === ''\n ? `${open}${text}${close}`\n : `${open}<wp14:pctHeight>${text.trim()}</wp14:pctHeight>${close}`\n );\n}\n\n/**\n * Character code constants for documentation and testing.\n */\nexport const XML_CONTROL_CHARS = {\n /** NULL (0x00) - Invalid */\n NULL: 0x00,\n /** Start of Heading (0x01) - Invalid */\n SOH: 0x01,\n /** Start of Text (0x02) - Invalid */\n STX: 0x02,\n /** End of Text (0x03) - Invalid */\n ETX: 0x03,\n /** End of Transmission (0x04) - Invalid */\n EOT: 0x04,\n /** Enquiry (0x05) - Invalid */\n ENQ: 0x05,\n /** Acknowledge (0x06) - Invalid */\n ACK: 0x06,\n /** Bell (0x07) - Invalid */\n BEL: 0x07,\n /** Backspace (0x08) - Invalid */\n BS: 0x08,\n /** Horizontal Tab (0x09) - VALID */\n TAB: 0x09,\n /** Line Feed / Newline (0x0A) - VALID */\n LF: 0x0a,\n /** Vertical Tab (0x0B) - Invalid */\n VT: 0x0b,\n /** Form Feed (0x0C) - Invalid */\n FF: 0x0c,\n /** Carriage Return (0x0D) - VALID */\n CR: 0x0d,\n /** Shift Out (0x0E) - Invalid */\n SO: 0x0e,\n /** Unit Separator (0x1F) - Invalid */\n US: 0x1f,\n /** Delete (0x7F) - Invalid */\n DEL: 0x7f,\n} as const;\n"]}
|
|
@@ -8,10 +8,14 @@ export declare class RevisionAutoFixer {
|
|
|
8
8
|
static fixMissingAuthors(revisions: Revision[], defaultAuthor: string, dryRun?: boolean): FixAction[];
|
|
9
9
|
static fixMissingDates(revisions: Revision[], dryRun?: boolean): FixAction[];
|
|
10
10
|
static fixInvalidDates(revisions: Revision[], dryRun?: boolean): FixAction[];
|
|
11
|
+
private static removeRevisionFromContent;
|
|
11
12
|
static fixOrphanedMoveMarkers(revisionManager: {
|
|
12
13
|
removeById(id: number): boolean;
|
|
13
|
-
}, revisions: Revision[], dryRun?: boolean
|
|
14
|
-
|
|
14
|
+
}, revisions: Revision[], dryRun?: boolean, doc?: Document, ruleFilter?: {
|
|
15
|
+
moveFrom?: boolean;
|
|
16
|
+
moveTo?: boolean;
|
|
17
|
+
}): FixAction[];
|
|
18
|
+
static fixEmptyRevisions(revisionManager: RevisionManager, revisions: Revision[], dryRun?: boolean, doc?: Document): FixAction[];
|
|
15
19
|
static fixNonSequentialIds(revisions: Revision[], dryRun?: boolean): FixAction[];
|
|
16
20
|
static preview(doc: Document, options?: Omit<AutoFixOptions, 'dryRun'>): AutoFixResult;
|
|
17
21
|
static formatResult(result: AutoFixResult): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevisionAutoFixer.d.ts","sourceRoot":"","sources":["../../src/validation/RevisionAutoFixer.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAEL,cAAc,EACd,aAAa,EACb,SAAS,EAEV,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"RevisionAutoFixer.d.ts","sourceRoot":"","sources":["../../src/validation/RevisionAutoFixer.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAEL,cAAc,EACd,aAAa,EACb,SAAS,EAEV,MAAM,sBAAsB,CAAC;AAuB9B,qBAAa,iBAAiB;IAQ5B,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa;IAqGlE,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE;IA4C5E,MAAM,CAAC,iBAAiB,CACtB,SAAS,EAAE,QAAQ,EAAE,EACrB,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,OAAO,GACf,SAAS,EAAE;IAuCd,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE;IAwC5E,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE;IA4C5E,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAwBxC,MAAM,CAAC,sBAAsB,CAC3B,eAAe,EAAE;QAAE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,EACpD,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,CAAC,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,QAAQ,EACd,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GACpD,SAAS,EAAE;IA4Fd,MAAM,CAAC,iBAAiB,CACtB,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,CAAC,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,QAAQ,GACb,SAAS,EAAE;IA+Cd,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE;IAyDhF,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,GAAG,aAAa;IAUtF,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;CAuBnD"}
|
|
@@ -36,7 +36,10 @@ class RevisionAutoFixer {
|
|
|
36
36
|
actions.push(...this.fixMissingAuthors(revisions, defaultAuthor, options?.dryRun));
|
|
37
37
|
}
|
|
38
38
|
if (shouldProcess('REV003') || shouldProcess('REV004')) {
|
|
39
|
-
actions.push(...this.fixOrphanedMoveMarkers(revisionManager, revisions, options?.dryRun
|
|
39
|
+
actions.push(...this.fixOrphanedMoveMarkers(revisionManager, revisions, options?.dryRun, doc, {
|
|
40
|
+
moveFrom: shouldProcess('REV003'),
|
|
41
|
+
moveTo: shouldProcess('REV004'),
|
|
42
|
+
}));
|
|
40
43
|
}
|
|
41
44
|
if (shouldProcess('REV101')) {
|
|
42
45
|
actions.push(...this.fixMissingDates(revisions, options?.dryRun));
|
|
@@ -45,7 +48,7 @@ class RevisionAutoFixer {
|
|
|
45
48
|
actions.push(...this.fixInvalidDates(revisions, options?.dryRun));
|
|
46
49
|
}
|
|
47
50
|
if (shouldProcess('REV103')) {
|
|
48
|
-
actions.push(...this.fixEmptyRevisions(revisionManager, revisions, options?.dryRun));
|
|
51
|
+
actions.push(...this.fixEmptyRevisions(revisionManager, revisions, options?.dryRun, doc));
|
|
49
52
|
}
|
|
50
53
|
if (shouldProcess('REV104')) {
|
|
51
54
|
actions.push(...this.fixNonSequentialIds(revisions, options?.dryRun));
|
|
@@ -178,8 +181,18 @@ class RevisionAutoFixer {
|
|
|
178
181
|
}
|
|
179
182
|
return actions;
|
|
180
183
|
}
|
|
181
|
-
static
|
|
184
|
+
static removeRevisionFromContent(doc, revision) {
|
|
185
|
+
for (const paragraph of doc.getAllParagraphs()) {
|
|
186
|
+
if (paragraph.replaceContent(revision, [])) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
static fixOrphanedMoveMarkers(revisionManager, revisions, dryRun, doc, ruleFilter) {
|
|
182
193
|
const actions = [];
|
|
194
|
+
const fixMoveFrom = ruleFilter?.moveFrom ?? true;
|
|
195
|
+
const fixMoveTo = ruleFilter?.moveTo ?? true;
|
|
183
196
|
const moveFromIds = new Map();
|
|
184
197
|
const moveToIds = new Map();
|
|
185
198
|
for (const rev of revisions) {
|
|
@@ -193,70 +206,68 @@ class RevisionAutoFixer {
|
|
|
193
206
|
moveToIds.set(moveId, rev);
|
|
194
207
|
}
|
|
195
208
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
209
|
+
if (fixMoveFrom) {
|
|
210
|
+
for (const [moveId, rev] of moveFromIds) {
|
|
211
|
+
if (!moveToIds.has(moveId)) {
|
|
212
|
+
const issue = {
|
|
213
|
+
code: ValidationRules_js_1.REVISION_RULES.ORPHANED_MOVE_FROM.code,
|
|
214
|
+
severity: 'error',
|
|
215
|
+
message: `Orphaned moveFrom with moveId="${moveId}"`,
|
|
216
|
+
location: { revisionId: rev.getId() },
|
|
217
|
+
autoFixable: true,
|
|
218
|
+
};
|
|
219
|
+
actions.push({
|
|
220
|
+
issue,
|
|
221
|
+
action: `Removed orphaned moveFrom (ID: ${rev.getId()}, moveId: ${moveId})`,
|
|
222
|
+
before: { type: 'moveFrom', moveId },
|
|
223
|
+
after: null,
|
|
224
|
+
success: true,
|
|
225
|
+
});
|
|
226
|
+
if (!dryRun) {
|
|
227
|
+
revisionManager.removeById(rev.getId());
|
|
228
|
+
if (doc) {
|
|
229
|
+
this.removeRevisionFromContent(doc, rev);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
214
232
|
}
|
|
215
233
|
}
|
|
216
234
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
+
if (fixMoveTo) {
|
|
236
|
+
for (const [moveId, rev] of moveToIds) {
|
|
237
|
+
if (!moveFromIds.has(moveId)) {
|
|
238
|
+
const issue = {
|
|
239
|
+
code: ValidationRules_js_1.REVISION_RULES.ORPHANED_MOVE_TO.code,
|
|
240
|
+
severity: 'error',
|
|
241
|
+
message: `Orphaned moveTo with moveId="${moveId}"`,
|
|
242
|
+
location: { revisionId: rev.getId() },
|
|
243
|
+
autoFixable: true,
|
|
244
|
+
};
|
|
245
|
+
actions.push({
|
|
246
|
+
issue,
|
|
247
|
+
action: `Removed orphaned moveTo (ID: ${rev.getId()}, moveId: ${moveId})`,
|
|
248
|
+
before: { type: 'moveTo', moveId },
|
|
249
|
+
after: null,
|
|
250
|
+
success: true,
|
|
251
|
+
});
|
|
252
|
+
if (!dryRun) {
|
|
253
|
+
revisionManager.removeById(rev.getId());
|
|
254
|
+
if (doc) {
|
|
255
|
+
this.removeRevisionFromContent(doc, rev);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
235
258
|
}
|
|
236
259
|
}
|
|
237
260
|
}
|
|
238
261
|
return actions;
|
|
239
262
|
}
|
|
240
|
-
static fixEmptyRevisions(revisionManager, revisions, dryRun) {
|
|
263
|
+
static fixEmptyRevisions(revisionManager, revisions, dryRun, doc) {
|
|
241
264
|
const actions = [];
|
|
242
|
-
const propertyChangeTypes = [
|
|
243
|
-
'runPropertiesChange',
|
|
244
|
-
'paragraphPropertiesChange',
|
|
245
|
-
'tablePropertiesChange',
|
|
246
|
-
'tableExceptionPropertiesChange',
|
|
247
|
-
'tableRowPropertiesChange',
|
|
248
|
-
'tableCellPropertiesChange',
|
|
249
|
-
'sectionPropertiesChange',
|
|
250
|
-
'numberingChange',
|
|
251
|
-
];
|
|
252
265
|
for (const rev of revisions) {
|
|
253
266
|
const type = rev.getType();
|
|
254
|
-
if (
|
|
267
|
+
if (RevisionValidator_js_1.CONTENTLESS_REVISION_TYPES.has(type)) {
|
|
255
268
|
continue;
|
|
256
269
|
}
|
|
257
|
-
|
|
258
|
-
const hasContent = runs.length > 0 && runs.some((r) => r.getText().length > 0);
|
|
259
|
-
if (!hasContent) {
|
|
270
|
+
if (!(0, RevisionValidator_js_1.revisionHasContent)(rev)) {
|
|
260
271
|
const issue = {
|
|
261
272
|
code: ValidationRules_js_1.REVISION_RULES.EMPTY_REVISION.code,
|
|
262
273
|
severity: 'warning',
|
|
@@ -273,6 +284,9 @@ class RevisionAutoFixer {
|
|
|
273
284
|
});
|
|
274
285
|
if (!dryRun) {
|
|
275
286
|
revisionManager.removeById(rev.getId());
|
|
287
|
+
if (doc) {
|
|
288
|
+
this.removeRevisionFromContent(doc, rev);
|
|
289
|
+
}
|
|
276
290
|
}
|
|
277
291
|
}
|
|
278
292
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevisionAutoFixer.js","sourceRoot":"","sources":["../../src/validation/RevisionAutoFixer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RevisionAutoFixer - Automatically fixes revision validation issues\n *\n * Provides auto-fix capabilities for common revision compliance issues,\n * helping to prevent document corruption while preserving user intent.\n *\n * @module RevisionAutoFixer\n */\n\nimport type { Document } from '../core/Document.js';\nimport type { Revision } from '../elements/Revision.js';\nimport type { RevisionManager } from '../elements/RevisionManager.js';\nimport {\n REVISION_RULES,\n AutoFixOptions,\n AutoFixResult,\n FixAction,\n ValidationIssue,\n} from './ValidationRules.js';\nimport { RevisionValidator } from './RevisionValidator.js';\n\n/**\n * Automatically fixes revision validation issues.\n *\n * @example\n * ```typescript\n * // Auto-fix all issues\n * const result = RevisionAutoFixer.fix(doc);\n * console.log(`Fixed ${result.issuesFixed} issues`);\n *\n * // Dry run (preview fixes without applying)\n * const preview = RevisionAutoFixer.fix(doc, { dryRun: true });\n * for (const action of preview.actions) {\n * console.log(`Would fix: ${action.action}`);\n * }\n * ```\n */\nexport class RevisionAutoFixer {\n /**\n * Auto-fix all fixable issues in a document.\n *\n * @param doc - Document to fix\n * @param options - Fix options\n * @returns Result with details of all fixes applied\n */\n static fix(doc: Document, options?: AutoFixOptions): AutoFixResult {\n const actions: FixAction[] = [];\n const errors: string[] = [];\n const revisionManager = doc.getRevisionManager();\n\n if (!revisionManager) {\n return {\n allFixed: true,\n issuesFixed: 0,\n issuesRemaining: 0,\n actions: [],\n errors: [],\n };\n }\n\n const revisions = revisionManager.getAllRevisions();\n const skipRules = new Set(options?.skipRules || []);\n const onlyRules = options?.onlyRules ? new Set(options.onlyRules) : null;\n\n // Helper to check if a rule should be processed\n const shouldProcess = (ruleCode: string) => {\n if (skipRules.has(ruleCode)) return false;\n if (onlyRules && !onlyRules.has(ruleCode)) return false;\n return true;\n };\n\n try {\n // Fix duplicate IDs (REV001)\n if (shouldProcess('REV001')) {\n actions.push(...this.fixDuplicateIds(revisions, options?.dryRun));\n }\n\n // Fix missing authors (REV002)\n if (shouldProcess('REV002')) {\n const defaultAuthor = options?.defaultAuthor || 'Unknown Author';\n actions.push(...this.fixMissingAuthors(revisions, defaultAuthor, options?.dryRun));\n }\n\n // Fix orphaned move markers (REV003, REV004)\n if (shouldProcess('REV003') || shouldProcess('REV004')) {\n actions.push(...this.fixOrphanedMoveMarkers(revisionManager, revisions, options?.dryRun));\n }\n\n // Fix missing dates (REV101)\n if (shouldProcess('REV101')) {\n actions.push(...this.fixMissingDates(revisions, options?.dryRun));\n }\n\n // Fix invalid dates (REV102)\n if (shouldProcess('REV102')) {\n actions.push(...this.fixInvalidDates(revisions, options?.dryRun));\n }\n\n // Fix empty revisions (REV103)\n if (shouldProcess('REV103')) {\n actions.push(...this.fixEmptyRevisions(revisionManager, revisions, options?.dryRun));\n }\n\n // Fix non-sequential IDs (REV104)\n if (shouldProcess('REV104')) {\n actions.push(...this.fixNonSequentialIds(revisions, options?.dryRun));\n }\n } catch (error: unknown) {\n errors.push(`Fix error: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Validate after fixes\n const postValidation = RevisionValidator.validate(doc);\n\n // Log actions if verbose\n if (options?.verbose) {\n for (const action of actions) {\n console.log(`[AutoFix] ${action.action}: ${action.issue.code}`);\n }\n }\n\n return {\n allFixed: postValidation.valid,\n issuesFixed: actions.filter((a) => a.success).length,\n issuesRemaining: postValidation.summary.errorCount + postValidation.summary.warningCount,\n actions,\n errors,\n };\n }\n\n /**\n * Fix duplicate revision IDs by reassigning.\n *\n * Assigns new unique IDs to revisions with duplicate IDs.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixDuplicateIds(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const usedIds = new Set<number>();\n let nextId = Math.max(...revisions.map((r) => r.getId()), 0) + 1;\n\n for (const rev of revisions) {\n const id = rev.getId();\n\n if (usedIds.has(id)) {\n const newId = nextId++;\n const issue: ValidationIssue = {\n code: REVISION_RULES.DUPLICATE_ID.code,\n severity: 'error',\n message: `Duplicate ID ${id}`,\n location: { revisionId: id },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Reassigned duplicate ID ${id} to ${newId}`,\n before: id,\n after: newId,\n success: true,\n });\n\n if (!dryRun) {\n rev.setId(newId);\n }\n }\n usedIds.add(rev.getId());\n }\n\n return actions;\n }\n\n /**\n * Fix missing authors by setting a default value.\n *\n * @param revisions - Array of revisions\n * @param defaultAuthor - Default author name to use\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixMissingAuthors(\n revisions: Revision[],\n defaultAuthor: string,\n dryRun?: boolean\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n for (const rev of revisions) {\n const author = rev.getAuthor();\n\n if (!author || author.trim() === '') {\n const issue: ValidationIssue = {\n code: REVISION_RULES.MISSING_AUTHOR.code,\n severity: 'error',\n message: `Missing author for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Set author to \"${defaultAuthor}\" for revision ${rev.getId()}`,\n before: author,\n after: defaultAuthor,\n success: true,\n });\n\n if (!dryRun) {\n rev.setAuthor(defaultAuthor);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix missing dates by setting current date.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixMissingDates(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const now = new Date();\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (!date) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.MISSING_DATE.code,\n severity: 'warning',\n message: `Missing date for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Set date to ${now.toISOString()} for revision ${rev.getId()}`,\n before: null,\n after: now,\n success: true,\n });\n\n if (!dryRun) {\n rev.setDate(now);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix invalid dates by replacing with current date.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixInvalidDates(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const now = new Date();\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (date && isNaN(date.getTime())) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.INVALID_DATE_FORMAT.code,\n severity: 'warning',\n message: `Invalid date for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Replaced invalid date with ${now.toISOString()} for revision ${rev.getId()}`,\n before: date,\n after: now,\n success: true,\n });\n\n if (!dryRun) {\n rev.setDate(now);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix orphaned move markers by removing them.\n *\n * @param revisionManager - RevisionManager instance\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixOrphanedMoveMarkers(\n revisionManager: { removeById(id: number): boolean },\n revisions: Revision[],\n dryRun?: boolean\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n const moveFromIds = new Map<string, Revision>();\n const moveToIds = new Map<string, Revision>();\n\n for (const rev of revisions) {\n const moveId = rev.getMoveId();\n if (!moveId) continue;\n\n if (rev.getType() === 'moveFrom') {\n moveFromIds.set(moveId, rev);\n } else if (rev.getType() === 'moveTo') {\n moveToIds.set(moveId, rev);\n }\n }\n\n // Remove orphaned moveFrom\n for (const [moveId, rev] of moveFromIds) {\n if (!moveToIds.has(moveId)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.ORPHANED_MOVE_FROM.code,\n severity: 'error',\n message: `Orphaned moveFrom with moveId=\"${moveId}\"`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed orphaned moveFrom (ID: ${rev.getId()}, moveId: ${moveId})`,\n before: { type: 'moveFrom', moveId },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n }\n }\n }\n\n // Remove orphaned moveTo\n for (const [moveId, rev] of moveToIds) {\n if (!moveFromIds.has(moveId)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.ORPHANED_MOVE_TO.code,\n severity: 'error',\n message: `Orphaned moveTo with moveId=\"${moveId}\"`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed orphaned moveTo (ID: ${rev.getId()}, moveId: ${moveId})`,\n before: { type: 'moveTo', moveId },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix empty revisions by removing them.\n *\n * @param revisionManager - RevisionManager instance\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixEmptyRevisions(\n revisionManager: RevisionManager,\n revisions: Revision[],\n dryRun?: boolean\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n const propertyChangeTypes = [\n 'runPropertiesChange',\n 'paragraphPropertiesChange',\n 'tablePropertiesChange',\n 'tableExceptionPropertiesChange',\n 'tableRowPropertiesChange',\n 'tableCellPropertiesChange',\n 'sectionPropertiesChange',\n 'numberingChange',\n ];\n\n for (const rev of revisions) {\n const type = rev.getType();\n\n // Skip property changes\n if (propertyChangeTypes.includes(type)) {\n continue;\n }\n\n const runs = rev.getRuns();\n const hasContent = runs.length > 0 && runs.some((r) => r.getText().length > 0);\n\n if (!hasContent) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.EMPTY_REVISION.code,\n severity: 'warning',\n message: `Empty revision ${rev.getId()} (type: ${type})`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed empty revision (ID: ${rev.getId()}, type: ${type})`,\n before: { id: rev.getId(), type },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix non-sequential IDs by reassigning.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixNonSequentialIds(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n\n if (revisions.length === 0) return actions;\n\n // Check if IDs are already sequential\n const ids = revisions.map((r) => r.getId()).sort((a, b) => a - b);\n let isSequential = true;\n\n for (let i = 1; i < ids.length; i++) {\n const currentId = ids[i]!;\n const prevId = ids[i - 1]!;\n if (currentId !== prevId + 1) {\n isSequential = false;\n break;\n }\n }\n\n if (!isSequential) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.NON_SEQUENTIAL_IDS.code,\n severity: 'warning',\n message: 'Revision IDs are not sequential',\n autoFixable: true,\n };\n\n const oldIds = revisions.map((r) => r.getId());\n const newIds: number[] = [];\n\n revisions.forEach((rev, index) => {\n newIds.push(index);\n if (!dryRun) {\n rev.setId(index);\n }\n });\n\n actions.push({\n issue,\n action: `Reassigned ${revisions.length} revision IDs to be sequential (0 to ${revisions.length - 1})`,\n before: oldIds,\n after: newIds,\n success: true,\n });\n }\n\n return actions;\n }\n\n /**\n * Preview fixes without applying them.\n *\n * Convenience method that calls fix() with dryRun: true.\n *\n * @param doc - Document to preview fixes for\n * @param options - Fix options (dryRun is forced to true)\n * @returns Result showing what would be fixed\n */\n static preview(doc: Document, options?: Omit<AutoFixOptions, 'dryRun'>): AutoFixResult {\n return this.fix(doc, { ...options, dryRun: true });\n }\n\n /**\n * Format fix result as a human-readable string.\n *\n * @param result - AutoFixResult to format\n * @returns Formatted string\n */\n static formatResult(result: AutoFixResult): string {\n const lines: string[] = [];\n\n lines.push(`Auto-Fix ${result.allFixed ? 'COMPLETE' : 'PARTIAL'}`);\n lines.push(`Fixed: ${result.issuesFixed}, Remaining: ${result.issuesRemaining}`);\n\n if (result.actions.length > 0) {\n lines.push('\\nActions taken:');\n for (const action of result.actions) {\n const status = action.success ? 'OK' : 'FAILED';\n lines.push(` [${status}] ${action.action}`);\n }\n }\n\n if (result.errors.length > 0) {\n lines.push('\\nErrors:');\n for (const error of result.errors) {\n lines.push(` - ${error}`);\n }\n }\n\n return lines.join('\\n');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"RevisionAutoFixer.js","sourceRoot":"","sources":["../../src/validation/RevisionAutoFixer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RevisionAutoFixer - Automatically fixes revision validation issues\n *\n * Provides auto-fix capabilities for common revision compliance issues,\n * helping to prevent document corruption while preserving user intent.\n *\n * @module RevisionAutoFixer\n */\n\nimport type { Document } from '../core/Document.js';\nimport type { Revision } from '../elements/Revision.js';\nimport type { RevisionManager } from '../elements/RevisionManager.js';\nimport {\n REVISION_RULES,\n AutoFixOptions,\n AutoFixResult,\n FixAction,\n ValidationIssue,\n} from './ValidationRules.js';\nimport {\n CONTENTLESS_REVISION_TYPES,\n RevisionValidator,\n revisionHasContent,\n} from './RevisionValidator.js';\n\n/**\n * Automatically fixes revision validation issues.\n *\n * @example\n * ```typescript\n * // Auto-fix all issues\n * const result = RevisionAutoFixer.fix(doc);\n * console.log(`Fixed ${result.issuesFixed} issues`);\n *\n * // Dry run (preview fixes without applying)\n * const preview = RevisionAutoFixer.fix(doc, { dryRun: true });\n * for (const action of preview.actions) {\n * console.log(`Would fix: ${action.action}`);\n * }\n * ```\n */\nexport class RevisionAutoFixer {\n /**\n * Auto-fix all fixable issues in a document.\n *\n * @param doc - Document to fix\n * @param options - Fix options\n * @returns Result with details of all fixes applied\n */\n static fix(doc: Document, options?: AutoFixOptions): AutoFixResult {\n const actions: FixAction[] = [];\n const errors: string[] = [];\n const revisionManager = doc.getRevisionManager();\n\n if (!revisionManager) {\n return {\n allFixed: true,\n issuesFixed: 0,\n issuesRemaining: 0,\n actions: [],\n errors: [],\n };\n }\n\n const revisions = revisionManager.getAllRevisions();\n const skipRules = new Set(options?.skipRules || []);\n const onlyRules = options?.onlyRules ? new Set(options.onlyRules) : null;\n\n // Helper to check if a rule should be processed\n const shouldProcess = (ruleCode: string) => {\n if (skipRules.has(ruleCode)) return false;\n if (onlyRules && !onlyRules.has(ruleCode)) return false;\n return true;\n };\n\n try {\n // Fix duplicate IDs (REV001)\n if (shouldProcess('REV001')) {\n actions.push(...this.fixDuplicateIds(revisions, options?.dryRun));\n }\n\n // Fix missing authors (REV002)\n if (shouldProcess('REV002')) {\n const defaultAuthor = options?.defaultAuthor || 'Unknown Author';\n actions.push(...this.fixMissingAuthors(revisions, defaultAuthor, options?.dryRun));\n }\n\n // Fix orphaned move markers (REV003, REV004) — one pairing pass\n // produces both rules, so gate each side individually to honor\n // onlyRules/skipRules without mutating revisions the caller excluded.\n if (shouldProcess('REV003') || shouldProcess('REV004')) {\n actions.push(\n ...this.fixOrphanedMoveMarkers(revisionManager, revisions, options?.dryRun, doc, {\n moveFrom: shouldProcess('REV003'),\n moveTo: shouldProcess('REV004'),\n })\n );\n }\n\n // Fix missing dates (REV101)\n if (shouldProcess('REV101')) {\n actions.push(...this.fixMissingDates(revisions, options?.dryRun));\n }\n\n // Fix invalid dates (REV102)\n if (shouldProcess('REV102')) {\n actions.push(...this.fixInvalidDates(revisions, options?.dryRun));\n }\n\n // Fix empty revisions (REV103)\n if (shouldProcess('REV103')) {\n actions.push(...this.fixEmptyRevisions(revisionManager, revisions, options?.dryRun, doc));\n }\n\n // Fix non-sequential IDs (REV104)\n if (shouldProcess('REV104')) {\n actions.push(...this.fixNonSequentialIds(revisions, options?.dryRun));\n }\n } catch (error: unknown) {\n errors.push(`Fix error: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Validate after fixes\n const postValidation = RevisionValidator.validate(doc);\n\n // Log actions if verbose\n if (options?.verbose) {\n for (const action of actions) {\n console.log(`[AutoFix] ${action.action}: ${action.issue.code}`);\n }\n }\n\n return {\n allFixed: postValidation.valid,\n issuesFixed: actions.filter((a) => a.success).length,\n issuesRemaining: postValidation.summary.errorCount + postValidation.summary.warningCount,\n actions,\n errors,\n };\n }\n\n /**\n * Fix duplicate revision IDs by reassigning.\n *\n * Assigns new unique IDs to revisions with duplicate IDs.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixDuplicateIds(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const usedIds = new Set<number>();\n let nextId = Math.max(...revisions.map((r) => r.getId()), 0) + 1;\n\n for (const rev of revisions) {\n const id = rev.getId();\n\n if (usedIds.has(id)) {\n const newId = nextId++;\n const issue: ValidationIssue = {\n code: REVISION_RULES.DUPLICATE_ID.code,\n severity: 'error',\n message: `Duplicate ID ${id}`,\n location: { revisionId: id },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Reassigned duplicate ID ${id} to ${newId}`,\n before: id,\n after: newId,\n success: true,\n });\n\n if (!dryRun) {\n rev.setId(newId);\n }\n }\n usedIds.add(rev.getId());\n }\n\n return actions;\n }\n\n /**\n * Fix missing authors by setting a default value.\n *\n * @param revisions - Array of revisions\n * @param defaultAuthor - Default author name to use\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixMissingAuthors(\n revisions: Revision[],\n defaultAuthor: string,\n dryRun?: boolean\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n for (const rev of revisions) {\n const author = rev.getAuthor();\n\n if (!author || author.trim() === '') {\n const issue: ValidationIssue = {\n code: REVISION_RULES.MISSING_AUTHOR.code,\n severity: 'error',\n message: `Missing author for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Set author to \"${defaultAuthor}\" for revision ${rev.getId()}`,\n before: author,\n after: defaultAuthor,\n success: true,\n });\n\n if (!dryRun) {\n rev.setAuthor(defaultAuthor);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix missing dates by setting current date.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixMissingDates(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const now = new Date();\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (!date) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.MISSING_DATE.code,\n severity: 'warning',\n message: `Missing date for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Set date to ${now.toISOString()} for revision ${rev.getId()}`,\n before: null,\n after: now,\n success: true,\n });\n\n if (!dryRun) {\n rev.setDate(now);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix invalid dates by replacing with current date.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixInvalidDates(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const now = new Date();\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (date && isNaN(date.getTime())) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.INVALID_DATE_FORMAT.code,\n severity: 'warning',\n message: `Invalid date for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Replaced invalid date with ${now.toISOString()} for revision ${rev.getId()}`,\n before: date,\n after: now,\n success: true,\n });\n\n if (!dryRun) {\n rev.setDate(now);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Removes a revision from the paragraph content that owns it.\n *\n * RevisionManager.removeById() only deregisters the revision from the\n * manager registry, but serialization reads Paragraph.content directly —\n * without this step the removed markup would still be written on save.\n *\n * @param doc - Document whose paragraphs are searched\n * @param revision - Revision instance to remove\n * @returns True if the revision was found and removed from a paragraph\n */\n private static removeRevisionFromContent(doc: Document, revision: Revision): boolean {\n for (const paragraph of doc.getAllParagraphs()) {\n // replaceContent matches by identity and splices without tracking side effects\n if (paragraph.replaceContent(revision, [])) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Fix orphaned move markers by removing them.\n *\n * @param revisionManager - RevisionManager instance\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @param doc - Document to remove the revision content from; without it\n * only the manager registry is pruned and saved XML keeps the markup\n * @param ruleFilter - Which sides of the pairing to fix; REV003 (moveFrom)\n * and REV004 (moveTo) are separate rules, so callers honoring\n * onlyRules/skipRules must be able to fix one without the other.\n * Defaults to both.\n * @returns Array of fix actions\n */\n static fixOrphanedMoveMarkers(\n revisionManager: { removeById(id: number): boolean },\n revisions: Revision[],\n dryRun?: boolean,\n doc?: Document,\n ruleFilter?: { moveFrom?: boolean; moveTo?: boolean }\n ): FixAction[] {\n const actions: FixAction[] = [];\n const fixMoveFrom = ruleFilter?.moveFrom ?? true;\n const fixMoveTo = ruleFilter?.moveTo ?? true;\n\n const moveFromIds = new Map<string, Revision>();\n const moveToIds = new Map<string, Revision>();\n\n for (const rev of revisions) {\n const moveId = rev.getMoveId();\n if (!moveId) continue;\n\n if (rev.getType() === 'moveFrom') {\n moveFromIds.set(moveId, rev);\n } else if (rev.getType() === 'moveTo') {\n moveToIds.set(moveId, rev);\n }\n }\n\n // Remove orphaned moveFrom (REV003)\n if (fixMoveFrom) {\n for (const [moveId, rev] of moveFromIds) {\n if (!moveToIds.has(moveId)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.ORPHANED_MOVE_FROM.code,\n severity: 'error',\n message: `Orphaned moveFrom with moveId=\"${moveId}\"`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed orphaned moveFrom (ID: ${rev.getId()}, moveId: ${moveId})`,\n before: { type: 'moveFrom', moveId },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n if (doc) {\n this.removeRevisionFromContent(doc, rev);\n }\n }\n }\n }\n }\n\n // Remove orphaned moveTo (REV004)\n if (fixMoveTo) {\n for (const [moveId, rev] of moveToIds) {\n if (!moveFromIds.has(moveId)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.ORPHANED_MOVE_TO.code,\n severity: 'error',\n message: `Orphaned moveTo with moveId=\"${moveId}\"`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed orphaned moveTo (ID: ${rev.getId()}, moveId: ${moveId})`,\n before: { type: 'moveTo', moveId },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n if (doc) {\n this.removeRevisionFromContent(doc, rev);\n }\n }\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix empty revisions by removing them.\n *\n * @param revisionManager - RevisionManager instance\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @param doc - Document to remove the revision content from; without it\n * only the manager registry is pruned and saved XML keeps the markup\n * @returns Array of fix actions\n */\n static fixEmptyRevisions(\n revisionManager: RevisionManager,\n revisions: Revision[],\n dryRun?: boolean,\n doc?: Document\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n for (const rev of revisions) {\n const type = rev.getType();\n\n // Property changes and cell markers are contentless by design\n if (CONTENTLESS_REVISION_TYPES.has(type)) {\n continue;\n }\n\n if (!revisionHasContent(rev)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.EMPTY_REVISION.code,\n severity: 'warning',\n message: `Empty revision ${rev.getId()} (type: ${type})`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed empty revision (ID: ${rev.getId()}, type: ${type})`,\n before: { id: rev.getId(), type },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n if (doc) {\n this.removeRevisionFromContent(doc, rev);\n }\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix non-sequential IDs by reassigning.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixNonSequentialIds(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n\n if (revisions.length === 0) return actions;\n\n // Check if IDs are already sequential\n const ids = revisions.map((r) => r.getId()).sort((a, b) => a - b);\n let isSequential = true;\n\n for (let i = 1; i < ids.length; i++) {\n const currentId = ids[i]!;\n const prevId = ids[i - 1]!;\n if (currentId !== prevId + 1) {\n isSequential = false;\n break;\n }\n }\n\n if (!isSequential) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.NON_SEQUENTIAL_IDS.code,\n severity: 'warning',\n message: 'Revision IDs are not sequential',\n autoFixable: true,\n };\n\n const oldIds = revisions.map((r) => r.getId());\n const newIds: number[] = [];\n\n revisions.forEach((rev, index) => {\n newIds.push(index);\n if (!dryRun) {\n rev.setId(index);\n }\n });\n\n actions.push({\n issue,\n action: `Reassigned ${revisions.length} revision IDs to be sequential (0 to ${revisions.length - 1})`,\n before: oldIds,\n after: newIds,\n success: true,\n });\n }\n\n return actions;\n }\n\n /**\n * Preview fixes without applying them.\n *\n * Convenience method that calls fix() with dryRun: true.\n *\n * @param doc - Document to preview fixes for\n * @param options - Fix options (dryRun is forced to true)\n * @returns Result showing what would be fixed\n */\n static preview(doc: Document, options?: Omit<AutoFixOptions, 'dryRun'>): AutoFixResult {\n return this.fix(doc, { ...options, dryRun: true });\n }\n\n /**\n * Format fix result as a human-readable string.\n *\n * @param result - AutoFixResult to format\n * @returns Formatted string\n */\n static formatResult(result: AutoFixResult): string {\n const lines: string[] = [];\n\n lines.push(`Auto-Fix ${result.allFixed ? 'COMPLETE' : 'PARTIAL'}`);\n lines.push(`Fixed: ${result.issuesFixed}, Remaining: ${result.issuesRemaining}`);\n\n if (result.actions.length > 0) {\n lines.push('\\nActions taken:');\n for (const action of result.actions) {\n const status = action.success ? 'OK' : 'FAILED';\n lines.push(` [${status}] ${action.action}`);\n }\n }\n\n if (result.errors.length > 0) {\n lines.push('\\nErrors:');\n for (const error of result.errors) {\n lines.push(` - ${error}`);\n }\n }\n\n return lines.join('\\n');\n }\n}\n"]}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Document } from '../core/Document.js';
|
|
2
2
|
import type { Revision } from '../elements/Revision.js';
|
|
3
3
|
import { ValidationIssue, ValidationOptions, ValidationResult } from './ValidationRules.js';
|
|
4
|
+
export declare const CONTENTLESS_REVISION_TYPES: ReadonlySet<string>;
|
|
5
|
+
export declare function revisionHasContent(rev: Revision): boolean;
|
|
4
6
|
export declare class RevisionValidator {
|
|
5
7
|
static validate(doc: Document, options?: ValidationOptions): ValidationResult;
|
|
6
8
|
private static runCustomRules;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevisionValidator.d.ts","sourceRoot":"","sources":["../../src/validation/RevisionValidator.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"RevisionValidator.d.ts","sourceRoot":"","sources":["../../src/validation/RevisionValidator.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,EAEL,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,sBAAsB,CAAC;AAY9B,eAAO,MAAM,0BAA0B,EAAE,WAAW,CAAC,MAAM,CAYzD,CAAC;AAQH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAOzD;AAgBD,qBAAa,iBAAiB;IAQ5B,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,gBAAgB;IAyD7E,OAAO,CAAC,MAAM,CAAC,cAAc;IAe7B,OAAO,CAAC,MAAM,CAAC,QAAQ;IAyCvB,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE;IAuCpE,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE;IAsDlE,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE;IAuBhE,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE;IA8B9D,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE;IAiChE,MAAM,CAAC,qBAAqB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE;IA2CtE,MAAM,CAAC,qBAAqB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE;IAwBtE,MAAM,CAAC,qBAAqB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE;IAgCtE,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO;IAWtC,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM;CAsBvD"}
|