docxmlater 10.4.0 → 11.0.4
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 +3 -3
- package/dist/constants/legacyCompatFlags.d.ts +1 -1
- package/dist/constants/legacyCompatFlags.d.ts.map +1 -1
- package/dist/constants/legacyCompatFlags.js.map +1 -1
- package/dist/core/Document.d.ts +75 -67
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +618 -414
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentContent.d.ts +11 -10
- package/dist/core/DocumentContent.d.ts.map +1 -1
- package/dist/core/DocumentContent.js +19 -19
- package/dist/core/DocumentContent.js.map +1 -1
- package/dist/core/DocumentEvents.d.ts +39 -0
- package/dist/core/DocumentEvents.d.ts.map +1 -0
- package/dist/core/DocumentEvents.js +51 -0
- package/dist/core/DocumentEvents.js.map +1 -0
- package/dist/core/DocumentGenerator.d.ts +11 -11
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +72 -52
- package/dist/core/DocumentGenerator.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 +2100 -1076
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/DocumentValidator.d.ts +3 -3
- package/dist/core/DocumentValidator.d.ts.map +1 -1
- package/dist/core/DocumentValidator.js +31 -31
- package/dist/core/DocumentValidator.js.map +1 -1
- package/dist/core/ElementRegistry.d.ts +22 -0
- package/dist/core/ElementRegistry.d.ts.map +1 -0
- package/dist/core/ElementRegistry.js +27 -0
- package/dist/core/ElementRegistry.js.map +1 -0
- package/dist/core/Relationship.js +4 -4
- package/dist/core/Relationship.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +32 -32
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/AlternateContent.d.ts +1 -1
- package/dist/elements/AlternateContent.d.ts.map +1 -1
- package/dist/elements/AlternateContent.js.map +1 -1
- package/dist/elements/Bookmark.d.ts +6 -1
- package/dist/elements/Bookmark.d.ts.map +1 -1
- package/dist/elements/Bookmark.js +19 -3
- package/dist/elements/Bookmark.js.map +1 -1
- package/dist/elements/BookmarkManager.d.ts +1 -1
- package/dist/elements/BookmarkManager.d.ts.map +1 -1
- package/dist/elements/BookmarkManager.js +7 -7
- package/dist/elements/BookmarkManager.js.map +1 -1
- package/dist/elements/Comment.d.ts +2 -2
- package/dist/elements/Comment.d.ts.map +1 -1
- package/dist/elements/Comment.js +4 -4
- package/dist/elements/Comment.js.map +1 -1
- package/dist/elements/CommentManager.d.ts +2 -2
- package/dist/elements/CommentManager.d.ts.map +1 -1
- package/dist/elements/CommentManager.js +9 -9
- package/dist/elements/CommentManager.js.map +1 -1
- package/dist/elements/CommonTypes.d.ts +9 -4
- package/dist/elements/CommonTypes.d.ts.map +1 -1
- package/dist/elements/CommonTypes.js +1 -0
- package/dist/elements/CommonTypes.js.map +1 -1
- package/dist/elements/CustomXml.d.ts +1 -1
- package/dist/elements/CustomXml.d.ts.map +1 -1
- package/dist/elements/CustomXml.js.map +1 -1
- package/dist/elements/Endnote.d.ts +2 -2
- package/dist/elements/Endnote.d.ts.map +1 -1
- package/dist/elements/Endnote.js +9 -9
- package/dist/elements/Endnote.js.map +1 -1
- package/dist/elements/EndnoteManager.d.ts +1 -1
- package/dist/elements/EndnoteManager.d.ts.map +1 -1
- package/dist/elements/EndnoteManager.js +11 -11
- package/dist/elements/EndnoteManager.js.map +1 -1
- package/dist/elements/Field.d.ts +9 -5
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +21 -9
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/FieldHelpers.d.ts +1 -1
- package/dist/elements/FieldHelpers.d.ts.map +1 -1
- package/dist/elements/FieldHelpers.js +10 -10
- package/dist/elements/FieldHelpers.js.map +1 -1
- package/dist/elements/Footer.d.ts +3 -3
- package/dist/elements/Footer.d.ts.map +1 -1
- package/dist/elements/Footer.js +5 -5
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/Footnote.d.ts +2 -2
- package/dist/elements/Footnote.d.ts.map +1 -1
- package/dist/elements/Footnote.js +9 -9
- package/dist/elements/Footnote.js.map +1 -1
- package/dist/elements/FootnoteManager.d.ts +1 -1
- package/dist/elements/FootnoteManager.d.ts.map +1 -1
- package/dist/elements/FootnoteManager.js +11 -11
- package/dist/elements/FootnoteManager.js.map +1 -1
- package/dist/elements/Header.d.ts +3 -3
- package/dist/elements/Header.d.ts.map +1 -1
- package/dist/elements/Header.js +5 -5
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/HeaderFooterManager.d.ts +2 -2
- package/dist/elements/HeaderFooterManager.d.ts.map +1 -1
- package/dist/elements/HeaderFooterManager.js.map +1 -1
- package/dist/elements/Hyperlink.d.ts +5 -5
- package/dist/elements/Hyperlink.d.ts.map +1 -1
- package/dist/elements/Hyperlink.js +29 -29
- package/dist/elements/Hyperlink.js.map +1 -1
- package/dist/elements/Image.d.ts +1 -1
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +67 -67
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/ImageManager.d.ts +1 -1
- package/dist/elements/ImageManager.d.ts.map +1 -1
- package/dist/elements/ImageManager.js +4 -4
- package/dist/elements/ImageManager.js.map +1 -1
- package/dist/elements/ImageRun.d.ts +3 -3
- package/dist/elements/ImageRun.d.ts.map +1 -1
- package/dist/elements/ImageRun.js +2 -2
- package/dist/elements/ImageRun.js.map +1 -1
- package/dist/elements/MathElement.d.ts +1 -1
- package/dist/elements/MathElement.d.ts.map +1 -1
- package/dist/elements/MathElement.js.map +1 -1
- package/dist/elements/Paragraph.d.ts +34 -19
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +286 -231
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/PreservedElement.d.ts +1 -1
- package/dist/elements/PreservedElement.d.ts.map +1 -1
- package/dist/elements/PreservedElement.js.map +1 -1
- package/dist/elements/PropertyChangeTypes.d.ts +2 -2
- package/dist/elements/PropertyChangeTypes.d.ts.map +1 -1
- package/dist/elements/PropertyChangeTypes.js.map +1 -1
- package/dist/elements/RangeMarker.d.ts +14 -1
- package/dist/elements/RangeMarker.d.ts.map +1 -1
- package/dist/elements/RangeMarker.js +46 -8
- package/dist/elements/RangeMarker.js.map +1 -1
- package/dist/elements/RegisteredBodyElement.d.ts +15 -0
- package/dist/elements/RegisteredBodyElement.d.ts.map +1 -0
- package/dist/elements/RegisteredBodyElement.js +44 -0
- package/dist/elements/RegisteredBodyElement.js.map +1 -0
- package/dist/elements/Revision.d.ts +8 -8
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +12 -12
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/RevisionContent.d.ts +3 -3
- package/dist/elements/RevisionContent.d.ts.map +1 -1
- package/dist/elements/RevisionContent.js.map +1 -1
- package/dist/elements/RevisionManager.d.ts +2 -2
- package/dist/elements/RevisionManager.d.ts.map +1 -1
- package/dist/elements/RevisionManager.js +2 -2
- package/dist/elements/RevisionManager.js.map +1 -1
- package/dist/elements/Run.d.ts +16 -10
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +199 -173
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts +4 -2
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +152 -145
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.d.ts +3 -3
- package/dist/elements/Shape.d.ts.map +1 -1
- package/dist/elements/Shape.js +12 -12
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/StructuredDocumentTag.d.ts +3 -3
- package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
- package/dist/elements/StructuredDocumentTag.js +39 -39
- package/dist/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/elements/Table.d.ts +16 -10
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +118 -89
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +11 -11
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +108 -78
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableGridChange.d.ts +1 -1
- package/dist/elements/TableGridChange.d.ts.map +1 -1
- package/dist/elements/TableGridChange.js +3 -3
- package/dist/elements/TableGridChange.js.map +1 -1
- package/dist/elements/TableOfContents.d.ts +1 -1
- package/dist/elements/TableOfContents.d.ts.map +1 -1
- package/dist/elements/TableOfContents.js +2 -2
- package/dist/elements/TableOfContents.js.map +1 -1
- package/dist/elements/TableOfContentsElement.d.ts +2 -2
- package/dist/elements/TableOfContentsElement.d.ts.map +1 -1
- package/dist/elements/TableOfContentsElement.js +5 -5
- package/dist/elements/TableOfContentsElement.js.map +1 -1
- package/dist/elements/TableRow.d.ts +18 -7
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +127 -74
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/elements/TextBox.d.ts +4 -4
- package/dist/elements/TextBox.d.ts.map +1 -1
- package/dist/elements/TextBox.js +6 -6
- package/dist/elements/TextBox.js.map +1 -1
- package/dist/esm/constants/legacyCompatFlags.js +97 -0
- package/dist/esm/constants/legacyCompatFlags.js.map +1 -0
- package/dist/esm/constants/limits.js +36 -0
- package/dist/esm/constants/limits.js.map +1 -0
- package/dist/esm/core/Document.js +8498 -0
- package/dist/esm/core/Document.js.map +1 -0
- package/dist/esm/core/DocumentContent.js +190 -0
- package/dist/esm/core/DocumentContent.js.map +1 -0
- package/dist/esm/core/DocumentEvents.js +47 -0
- package/dist/esm/core/DocumentEvents.js.map +1 -0
- package/dist/esm/core/DocumentGenerator.js +764 -0
- package/dist/esm/core/DocumentGenerator.js.map +1 -0
- package/dist/esm/core/DocumentIdManager.js +67 -0
- package/dist/esm/core/DocumentIdManager.js.map +1 -0
- package/dist/esm/core/DocumentParser.js +8760 -0
- package/dist/esm/core/DocumentParser.js.map +1 -0
- package/dist/esm/core/DocumentValidator.js +222 -0
- package/dist/esm/core/DocumentValidator.js.map +1 -0
- package/dist/esm/core/ElementRegistry.js +24 -0
- package/dist/esm/core/ElementRegistry.js.map +1 -0
- package/dist/esm/core/Relationship.js +177 -0
- package/dist/esm/core/Relationship.js.map +1 -0
- package/dist/esm/core/RelationshipManager.js +202 -0
- package/dist/esm/core/RelationshipManager.js.map +1 -0
- package/dist/esm/elements/AlternateContent.js +19 -0
- package/dist/esm/elements/AlternateContent.js.map +1 -0
- package/dist/esm/elements/Bookmark.js +115 -0
- package/dist/esm/elements/Bookmark.js.map +1 -0
- package/dist/esm/elements/BookmarkManager.js +99 -0
- package/dist/esm/elements/BookmarkManager.js.map +1 -0
- package/dist/esm/elements/Comment.js +181 -0
- package/dist/esm/elements/Comment.js.map +1 -0
- package/dist/esm/elements/CommentManager.js +233 -0
- package/dist/esm/elements/CommentManager.js.map +1 -0
- package/dist/esm/elements/CommonTypes.js +106 -0
- package/dist/esm/elements/CommonTypes.js.map +1 -0
- package/dist/esm/elements/CustomXml.js +19 -0
- package/dist/esm/elements/CustomXml.js.map +1 -0
- package/dist/esm/elements/Endnote.js +107 -0
- package/dist/esm/elements/Endnote.js.map +1 -0
- package/dist/esm/elements/EndnoteManager.js +119 -0
- package/dist/esm/elements/EndnoteManager.js.map +1 -0
- package/dist/esm/elements/Field.js +856 -0
- package/dist/esm/elements/Field.js.map +1 -0
- package/dist/esm/elements/FieldHelpers.js +134 -0
- package/dist/esm/elements/FieldHelpers.js.map +1 -0
- package/dist/esm/elements/FontManager.js +158 -0
- package/dist/esm/elements/FontManager.js.map +1 -0
- package/dist/esm/elements/Footer.js +141 -0
- package/dist/esm/elements/Footer.js.map +1 -0
- package/dist/esm/elements/Footnote.js +107 -0
- package/dist/esm/elements/Footnote.js.map +1 -0
- package/dist/esm/elements/FootnoteManager.js +119 -0
- package/dist/esm/elements/FootnoteManager.js.map +1 -0
- package/dist/esm/elements/Header.js +141 -0
- package/dist/esm/elements/Header.js.map +1 -0
- package/dist/esm/elements/HeaderFooterManager.js +87 -0
- package/dist/esm/elements/HeaderFooterManager.js.map +1 -0
- package/dist/esm/elements/Hyperlink.js +586 -0
- package/dist/esm/elements/Hyperlink.js.map +1 -0
- package/dist/esm/elements/Image.js +1288 -0
- package/dist/esm/elements/Image.js.map +1 -0
- package/dist/esm/elements/ImageManager.js +223 -0
- package/dist/esm/elements/ImageManager.js.map +1 -0
- package/dist/esm/elements/ImageRun.js +29 -0
- package/dist/esm/elements/ImageRun.js.map +1 -0
- package/dist/esm/elements/MathElement.js +37 -0
- package/dist/esm/elements/MathElement.js.map +1 -0
- package/dist/esm/elements/Paragraph.js +2308 -0
- package/dist/esm/elements/Paragraph.js.map +1 -0
- package/dist/esm/elements/PreservedElement.js +29 -0
- package/dist/esm/elements/PreservedElement.js.map +1 -0
- package/dist/esm/elements/PropertyChangeTypes.js +53 -0
- package/dist/esm/elements/PropertyChangeTypes.js.map +1 -0
- package/dist/esm/elements/RangeMarker.js +219 -0
- package/dist/esm/elements/RangeMarker.js.map +1 -0
- package/dist/esm/elements/RegisteredBodyElement.js +40 -0
- package/dist/esm/elements/RegisteredBodyElement.js.map +1 -0
- package/dist/esm/elements/Revision.js +498 -0
- package/dist/esm/elements/Revision.js.map +1 -0
- package/dist/esm/elements/RevisionContent.js +18 -0
- package/dist/esm/elements/RevisionContent.js.map +1 -0
- package/dist/esm/elements/RevisionManager.js +486 -0
- package/dist/esm/elements/RevisionManager.js.map +1 -0
- package/dist/esm/elements/Run.js +1465 -0
- package/dist/esm/elements/Run.js.map +1 -0
- package/dist/esm/elements/Section.js +978 -0
- package/dist/esm/elements/Section.js.map +1 -0
- package/dist/esm/elements/Shape.js +493 -0
- package/dist/esm/elements/Shape.js.map +1 -0
- package/dist/esm/elements/StructuredDocumentTag.js +471 -0
- package/dist/esm/elements/StructuredDocumentTag.js.map +1 -0
- package/dist/esm/elements/Table.js +1456 -0
- package/dist/esm/elements/Table.js.map +1 -0
- package/dist/esm/elements/TableCell.js +835 -0
- package/dist/esm/elements/TableCell.js.map +1 -0
- package/dist/esm/elements/TableGridChange.js +52 -0
- package/dist/esm/elements/TableGridChange.js.map +1 -0
- package/dist/esm/elements/TableOfContents.js +389 -0
- package/dist/esm/elements/TableOfContents.js.map +1 -0
- package/dist/esm/elements/TableOfContentsElement.js +29 -0
- package/dist/esm/elements/TableOfContentsElement.js.map +1 -0
- package/dist/esm/elements/TableRow.js +555 -0
- package/dist/esm/elements/TableRow.js.map +1 -0
- package/dist/esm/elements/TextBox.js +459 -0
- package/dist/esm/elements/TextBox.js.map +1 -0
- package/dist/esm/formatting/AbstractNumbering.js +325 -0
- package/dist/esm/formatting/AbstractNumbering.js.map +1 -0
- package/dist/esm/formatting/NumberingInstance.js +150 -0
- package/dist/esm/formatting/NumberingInstance.js.map +1 -0
- package/dist/esm/formatting/NumberingLevel.js +608 -0
- package/dist/esm/formatting/NumberingLevel.js.map +1 -0
- package/dist/esm/formatting/NumberingManager.js +423 -0
- package/dist/esm/formatting/NumberingManager.js.map +1 -0
- package/dist/esm/formatting/Style.js +1151 -0
- package/dist/esm/formatting/Style.js.map +1 -0
- package/dist/esm/formatting/StylesManager.js +557 -0
- package/dist/esm/formatting/StylesManager.js.map +1 -0
- package/dist/esm/helpers/CleanupHelper.js +350 -0
- package/dist/esm/helpers/CleanupHelper.js.map +1 -0
- package/dist/esm/images/ImageOptimizer.js +161 -0
- package/dist/esm/images/ImageOptimizer.js.map +1 -0
- package/dist/esm/index.js +75 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal.js +16 -0
- package/dist/esm/internal.js.map +1 -0
- package/dist/esm/managers/DrawingManager.js +163 -0
- package/dist/esm/managers/DrawingManager.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/processors/ChangelogGenerator.js +970 -0
- package/dist/esm/processors/ChangelogGenerator.js.map +1 -0
- package/dist/esm/processors/CompatibilityUpgrader.js +130 -0
- package/dist/esm/processors/CompatibilityUpgrader.js.map +1 -0
- package/dist/esm/processors/InMemoryRevisionAcceptor.js +530 -0
- package/dist/esm/processors/InMemoryRevisionAcceptor.js.map +1 -0
- package/dist/esm/processors/MoveOperationHelper.js +57 -0
- package/dist/esm/processors/MoveOperationHelper.js.map +1 -0
- package/dist/esm/processors/RevisionAwareProcessor.js +232 -0
- package/dist/esm/processors/RevisionAwareProcessor.js.map +1 -0
- package/dist/esm/processors/RevisionWalker.js +278 -0
- package/dist/esm/processors/RevisionWalker.js.map +1 -0
- package/dist/{utils → esm/processors}/SelectiveRevisionAcceptor.js +81 -42
- package/dist/esm/processors/SelectiveRevisionAcceptor.js.map +1 -0
- package/dist/esm/processors/ShadingResolver.js +66 -0
- package/dist/esm/processors/ShadingResolver.js.map +1 -0
- package/dist/esm/processors/acceptRevisions.js +416 -0
- package/dist/esm/processors/acceptRevisions.js.map +1 -0
- package/dist/esm/processors/cnfStyleDecoder.js +89 -0
- package/dist/esm/processors/cnfStyleDecoder.js.map +1 -0
- package/dist/esm/processors/stripTrackedChanges.js +201 -0
- package/dist/esm/processors/stripTrackedChanges.js.map +1 -0
- package/dist/esm/tracking/DocumentTrackingContext.js +531 -0
- package/dist/esm/tracking/DocumentTrackingContext.js.map +1 -0
- package/dist/esm/tracking/TrackingContext.js +2 -0
- package/dist/esm/tracking/TrackingContext.js.map +1 -0
- package/dist/esm/types/compatibility-types.js +8 -0
- package/dist/esm/types/compatibility-types.js.map +1 -0
- package/dist/esm/types/document-types.js +2 -0
- package/dist/esm/types/document-types.js.map +1 -0
- package/dist/esm/types/formatting.js +2 -0
- package/dist/esm/types/formatting.js.map +1 -0
- package/dist/esm/types/list-types.js +2 -0
- package/dist/esm/types/list-types.js.map +1 -0
- package/dist/esm/types/settings-types.js +2 -0
- package/dist/esm/types/settings-types.js.map +1 -0
- package/dist/esm/types/styleConfig.js +2 -0
- package/dist/esm/types/styleConfig.js.map +1 -0
- package/dist/esm/utils/KeyedRegistry.js +32 -0
- package/dist/esm/utils/KeyedRegistry.js.map +1 -0
- package/dist/esm/utils/corruptionDetection.js +155 -0
- package/dist/esm/utils/corruptionDetection.js.map +1 -0
- package/dist/esm/utils/dateFormatting.js +4 -0
- package/dist/esm/utils/dateFormatting.js.map +1 -0
- package/dist/esm/utils/deepClone.js +40 -0
- package/dist/esm/utils/deepClone.js.map +1 -0
- package/dist/esm/utils/deepEqual.js +47 -0
- package/dist/esm/utils/deepEqual.js.map +1 -0
- package/dist/esm/utils/diagnostics.js +69 -0
- package/dist/esm/utils/diagnostics.js.map +1 -0
- package/dist/esm/utils/errorHandling.js +36 -0
- package/dist/esm/utils/errorHandling.js.map +1 -0
- package/dist/esm/utils/formatting.js +93 -0
- package/dist/esm/utils/formatting.js.map +1 -0
- package/dist/esm/utils/list-detection.js +148 -0
- package/dist/esm/utils/list-detection.js.map +1 -0
- package/dist/esm/utils/logger.js +205 -0
- package/dist/esm/utils/logger.js.map +1 -0
- package/dist/esm/utils/parsingHelpers.js +56 -0
- package/dist/esm/utils/parsingHelpers.js.map +1 -0
- package/dist/esm/utils/textDiff.js +42 -0
- package/dist/esm/utils/textDiff.js.map +1 -0
- package/dist/esm/utils/units.js +152 -0
- package/dist/esm/utils/units.js.map +1 -0
- package/dist/esm/utils/validation.js +285 -0
- package/dist/esm/utils/validation.js.map +1 -0
- package/dist/esm/utils/xmlSanitization.js +54 -0
- package/dist/esm/utils/xmlSanitization.js.map +1 -0
- package/dist/esm/validation/RevisionAutoFixer.js +340 -0
- package/dist/esm/validation/RevisionAutoFixer.js.map +1 -0
- package/dist/esm/validation/RevisionValidator.js +240 -0
- package/dist/esm/validation/RevisionValidator.js.map +1 -0
- package/dist/esm/validation/ValidationRuleRegistry.js +40 -0
- package/dist/esm/validation/ValidationRuleRegistry.js.map +1 -0
- package/dist/esm/validation/ValidationRules.js +92 -0
- package/dist/esm/validation/ValidationRules.js.map +1 -0
- package/dist/esm/validation/index.js +4 -0
- package/dist/esm/validation/index.js.map +1 -0
- package/dist/esm/xml/XMLBuilder.js +434 -0
- package/dist/esm/xml/XMLBuilder.js.map +1 -0
- package/dist/esm/xml/XMLParser.js +486 -0
- package/dist/esm/xml/XMLParser.js.map +1 -0
- package/dist/esm/zip/ZipHandler.js +298 -0
- package/dist/esm/zip/ZipHandler.js.map +1 -0
- package/dist/esm/zip/ZipReader.js +147 -0
- package/dist/esm/zip/ZipReader.js.map +1 -0
- package/dist/esm/zip/ZipWriter.js +199 -0
- package/dist/esm/zip/ZipWriter.js.map +1 -0
- package/dist/esm/zip/errors.js +43 -0
- package/dist/esm/zip/errors.js.map +1 -0
- package/dist/esm/zip/types.js +31 -0
- package/dist/esm/zip/types.js.map +1 -0
- package/dist/formatting/AbstractNumbering.d.ts +2 -2
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +33 -33
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingInstance.d.ts +2 -2
- package/dist/formatting/NumberingInstance.d.ts.map +1 -1
- package/dist/formatting/NumberingInstance.js +7 -7
- package/dist/formatting/NumberingInstance.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts +11 -2
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +111 -25
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/NumberingManager.d.ts +4 -4
- package/dist/formatting/NumberingManager.d.ts.map +1 -1
- package/dist/formatting/NumberingManager.js +28 -28
- package/dist/formatting/NumberingManager.js.map +1 -1
- package/dist/formatting/Style.d.ts +14 -7
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +309 -112
- 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 +52 -52
- 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 +15 -15
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/index.d.ts +81 -90
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +286 -317
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +16 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +42 -0
- package/dist/internal.js.map +1 -0
- package/dist/managers/DrawingManager.d.ts +3 -3
- package/dist/managers/DrawingManager.d.ts.map +1 -1
- package/dist/managers/DrawingManager.js +12 -12
- package/dist/managers/DrawingManager.js.map +1 -1
- package/dist/{utils → processors}/ChangelogGenerator.d.ts +2 -2
- package/dist/processors/ChangelogGenerator.d.ts.map +1 -0
- package/dist/{utils → processors}/ChangelogGenerator.js +2 -2
- package/dist/processors/ChangelogGenerator.js.map +1 -0
- package/dist/processors/CompatibilityUpgrader.d.ts.map +1 -0
- package/dist/{utils → processors}/CompatibilityUpgrader.js +10 -10
- package/dist/processors/CompatibilityUpgrader.js.map +1 -0
- package/dist/{utils → processors}/InMemoryRevisionAcceptor.d.ts +3 -3
- package/dist/processors/InMemoryRevisionAcceptor.d.ts.map +1 -0
- package/dist/{utils → processors}/InMemoryRevisionAcceptor.js +84 -27
- package/dist/processors/InMemoryRevisionAcceptor.js.map +1 -0
- package/dist/{utils → processors}/MoveOperationHelper.d.ts +4 -4
- package/dist/processors/MoveOperationHelper.d.ts.map +1 -0
- package/dist/{utils → processors}/MoveOperationHelper.js +10 -10
- package/dist/processors/MoveOperationHelper.js.map +1 -0
- package/dist/{utils → processors}/RevisionAwareProcessor.d.ts +3 -3
- package/dist/processors/RevisionAwareProcessor.d.ts.map +1 -0
- package/dist/{utils → processors}/RevisionAwareProcessor.js +2 -2
- package/dist/processors/RevisionAwareProcessor.js.map +1 -0
- package/dist/{utils → processors}/RevisionWalker.d.ts +2 -1
- package/dist/processors/RevisionWalker.d.ts.map +1 -0
- package/dist/{utils → processors}/RevisionWalker.js +28 -0
- package/dist/processors/RevisionWalker.js.map +1 -0
- package/dist/{utils → processors}/SelectiveRevisionAcceptor.d.ts +4 -3
- package/dist/processors/SelectiveRevisionAcceptor.d.ts.map +1 -0
- package/dist/processors/SelectiveRevisionAcceptor.js +402 -0
- package/dist/processors/SelectiveRevisionAcceptor.js.map +1 -0
- package/dist/processors/ShadingResolver.d.ts +6 -0
- package/dist/processors/ShadingResolver.d.ts.map +1 -0
- package/dist/{utils → processors}/ShadingResolver.js +2 -2
- package/dist/processors/ShadingResolver.js.map +1 -0
- package/dist/{utils → processors}/acceptRevisions.d.ts +1 -1
- package/dist/processors/acceptRevisions.d.ts.map +1 -0
- package/dist/{utils → processors}/acceptRevisions.js +24 -4
- package/dist/processors/acceptRevisions.js.map +1 -0
- package/dist/{utils → processors}/cnfStyleDecoder.d.ts +1 -1
- package/dist/processors/cnfStyleDecoder.d.ts.map +1 -0
- package/dist/processors/cnfStyleDecoder.js.map +1 -0
- package/dist/processors/stripTrackedChanges.d.ts +3 -0
- package/dist/processors/stripTrackedChanges.d.ts.map +1 -0
- package/dist/{utils → processors}/stripTrackedChanges.js +16 -6
- package/dist/processors/stripTrackedChanges.js.map +1 -0
- package/dist/tracking/DocumentTrackingContext.d.ts +4 -4
- package/dist/tracking/DocumentTrackingContext.d.ts.map +1 -1
- package/dist/tracking/DocumentTrackingContext.js +38 -43
- package/dist/tracking/DocumentTrackingContext.js.map +1 -1
- package/dist/tracking/TrackingContext.d.ts +8 -8
- package/dist/tracking/TrackingContext.d.ts.map +1 -1
- package/dist/tracking/TrackingContext.js.map +1 -1
- package/dist/types/document-types.d.ts +28 -0
- package/dist/types/document-types.d.ts.map +1 -0
- package/dist/types/document-types.js +3 -0
- package/dist/types/document-types.js.map +1 -0
- package/dist/types/formatting.d.ts +4 -4
- package/dist/types/formatting.d.ts.map +1 -1
- package/dist/types/formatting.js.map +1 -1
- package/dist/types/settings-types.d.ts +6 -0
- package/dist/types/settings-types.d.ts.map +1 -1
- package/dist/types/settings-types.js.map +1 -1
- package/dist/utils/KeyedRegistry.d.ts +13 -0
- package/dist/utils/KeyedRegistry.d.ts.map +1 -0
- package/dist/utils/KeyedRegistry.js +36 -0
- package/dist/utils/KeyedRegistry.js.map +1 -0
- package/dist/utils/corruptionDetection.d.ts +1 -1
- package/dist/utils/corruptionDetection.d.ts.map +1 -1
- package/dist/utils/corruptionDetection.js +4 -4
- package/dist/utils/corruptionDetection.js.map +1 -1
- package/dist/utils/deepEqual.d.ts +2 -0
- package/dist/utils/deepEqual.d.ts.map +1 -0
- package/dist/utils/deepEqual.js +50 -0
- package/dist/utils/deepEqual.js.map +1 -0
- 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.map +1 -1
- package/dist/utils/parsingHelpers.d.ts +1 -1
- package/dist/utils/parsingHelpers.d.ts.map +1 -1
- package/dist/utils/parsingHelpers.js +2 -2
- package/dist/utils/parsingHelpers.js.map +1 -1
- package/dist/utils/validation.js +7 -7
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/xmlSanitization.js +2 -2
- package/dist/utils/xmlSanitization.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.d.ts +4 -4
- package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
- package/dist/validation/RevisionAutoFixer.js +11 -11
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/validation/RevisionValidator.d.ts +5 -4
- package/dist/validation/RevisionValidator.d.ts.map +1 -1
- package/dist/validation/RevisionValidator.js +29 -30
- package/dist/validation/RevisionValidator.js.map +1 -1
- package/dist/validation/ValidationRuleRegistry.d.ts +27 -0
- package/dist/validation/ValidationRuleRegistry.d.ts.map +1 -0
- package/dist/validation/ValidationRuleRegistry.js +43 -0
- package/dist/validation/ValidationRuleRegistry.js.map +1 -0
- package/dist/validation/index.d.ts +3 -3
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +10 -10
- package/dist/validation/index.js.map +1 -1
- package/dist/xml/XMLBuilder.d.ts +6 -1
- package/dist/xml/XMLBuilder.d.ts.map +1 -1
- package/dist/xml/XMLBuilder.js +11 -6
- package/dist/xml/XMLBuilder.js.map +1 -1
- package/dist/xml/XMLParser.js +6 -6
- package/dist/xml/XMLParser.js.map +1 -1
- package/dist/zip/ZipHandler.d.ts +1 -1
- package/dist/zip/ZipHandler.d.ts.map +1 -1
- package/dist/zip/ZipHandler.js +8 -8
- package/dist/zip/ZipHandler.js.map +1 -1
- package/dist/zip/ZipReader.d.ts +1 -1
- package/dist/zip/ZipReader.d.ts.map +1 -1
- package/dist/zip/ZipReader.js +14 -14
- 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 +10 -10
- package/dist/zip/ZipWriter.js.map +1 -1
- package/package.json +20 -4
- package/src/constants/legacyCompatFlags.ts +1 -1
- package/src/core/Document.ts +478 -167
- package/src/core/DocumentContent.ts +14 -11
- package/src/core/DocumentEvents.ts +90 -0
- package/src/core/DocumentGenerator.ts +49 -22
- package/src/core/DocumentParser.ts +2235 -620
- package/src/core/DocumentValidator.ts +7 -7
- package/src/core/ElementRegistry.ts +69 -0
- package/src/core/Relationship.ts +1 -1
- package/src/core/RelationshipManager.ts +4 -4
- package/src/elements/AlternateContent.ts +1 -1
- package/src/elements/Bookmark.ts +52 -4
- package/src/elements/BookmarkManager.ts +2 -2
- package/src/elements/Comment.ts +3 -3
- package/src/elements/CommentManager.ts +4 -4
- package/src/elements/CommonTypes.ts +45 -7
- package/src/elements/CustomXml.ts +1 -1
- package/src/elements/Endnote.ts +2 -2
- package/src/elements/EndnoteManager.ts +3 -3
- package/src/elements/Field.ts +44 -10
- package/src/elements/FieldHelpers.ts +2 -2
- package/src/elements/Footer.ts +4 -4
- package/src/elements/Footnote.ts +2 -2
- package/src/elements/FootnoteManager.ts +3 -3
- package/src/elements/Header.ts +4 -4
- package/src/elements/HeaderFooterManager.ts +2 -2
- package/src/elements/Hyperlink.ts +16 -12
- package/src/elements/Image.ts +3 -3
- package/src/elements/ImageManager.ts +2 -2
- package/src/elements/ImageRun.ts +3 -3
- package/src/elements/MathElement.ts +1 -1
- package/src/elements/Paragraph.ts +221 -88
- package/src/elements/PreservedElement.ts +1 -1
- package/src/elements/PropertyChangeTypes.ts +2 -2
- package/src/elements/RangeMarker.ts +153 -12
- package/src/elements/RegisteredBodyElement.ts +52 -0
- package/src/elements/Revision.ts +14 -14
- package/src/elements/RevisionContent.ts +3 -3
- package/src/elements/RevisionManager.ts +3 -3
- package/src/elements/Run.ts +221 -94
- package/src/elements/Section.ts +136 -69
- package/src/elements/Shape.ts +4 -4
- package/src/elements/StructuredDocumentTag.ts +3 -3
- package/src/elements/Table.ts +91 -27
- package/src/elements/TableCell.ts +62 -34
- package/src/elements/TableGridChange.ts +1 -1
- package/src/elements/TableOfContents.ts +1 -1
- package/src/elements/TableOfContentsElement.ts +2 -2
- package/src/elements/TableRow.ts +192 -48
- package/src/elements/TextBox.ts +5 -5
- package/src/formatting/AbstractNumbering.ts +3 -3
- package/src/formatting/NumberingInstance.ts +2 -2
- package/src/formatting/NumberingLevel.ts +201 -10
- package/src/formatting/NumberingManager.ts +5 -5
- package/src/formatting/Style.ts +382 -86
- package/src/formatting/StylesManager.ts +4 -4
- package/src/helpers/CleanupHelper.ts +6 -6
- package/src/index.ts +118 -127
- package/src/internal.ts +79 -0
- package/src/managers/DrawingManager.ts +3 -3
- package/src/{utils → processors}/ChangelogGenerator.ts +3 -3
- package/src/{utils → processors}/CompatibilityUpgrader.ts +2 -2
- package/src/{utils → processors}/InMemoryRevisionAcceptor.ts +100 -12
- package/src/{utils → processors}/MoveOperationHelper.ts +5 -5
- package/src/{utils → processors}/RevisionAwareProcessor.ts +3 -3
- package/src/{utils → processors}/RevisionWalker.ts +42 -1
- package/src/{utils → processors}/SelectiveRevisionAcceptor.ts +98 -39
- package/src/{utils → processors}/ShadingResolver.ts +5 -5
- package/src/{utils → processors}/acceptRevisions.ts +77 -9
- package/src/{utils → processors}/cnfStyleDecoder.ts +1 -1
- package/src/{utils → processors}/stripTrackedChanges.ts +35 -10
- package/src/tracking/DocumentTrackingContext.ts +12 -14
- package/src/tracking/TrackingContext.ts +8 -8
- package/src/types/document-types.ts +53 -0
- package/src/types/formatting.ts +4 -4
- package/src/types/settings-types.ts +32 -0
- package/src/utils/KeyedRegistry.ts +41 -0
- package/src/utils/corruptionDetection.ts +2 -2
- package/src/utils/deepEqual.ts +58 -0
- package/src/utils/list-detection.ts +2 -2
- package/src/utils/parsingHelpers.ts +11 -3
- package/src/utils/validation.ts +3 -3
- package/src/utils/xmlSanitization.ts +1 -1
- package/src/validation/RevisionAutoFixer.ts +5 -5
- package/src/validation/RevisionValidator.ts +39 -28
- package/src/validation/ValidationRuleRegistry.ts +86 -0
- package/src/validation/index.ts +3 -3
- package/src/xml/XMLBuilder.ts +13 -3
- package/src/xml/XMLParser.ts +2 -2
- package/src/zip/ZipHandler.ts +4 -4
- package/src/zip/ZipReader.ts +3 -3
- package/src/zip/ZipWriter.ts +3 -3
- package/dist/utils/ChangelogGenerator.d.ts.map +0 -1
- package/dist/utils/ChangelogGenerator.js.map +0 -1
- package/dist/utils/CompatibilityUpgrader.d.ts.map +0 -1
- package/dist/utils/CompatibilityUpgrader.js.map +0 -1
- package/dist/utils/InMemoryRevisionAcceptor.d.ts.map +0 -1
- package/dist/utils/InMemoryRevisionAcceptor.js.map +0 -1
- package/dist/utils/MoveOperationHelper.d.ts.map +0 -1
- package/dist/utils/MoveOperationHelper.js.map +0 -1
- package/dist/utils/RevisionAwareProcessor.d.ts.map +0 -1
- package/dist/utils/RevisionAwareProcessor.js.map +0 -1
- package/dist/utils/RevisionWalker.d.ts.map +0 -1
- package/dist/utils/RevisionWalker.js.map +0 -1
- package/dist/utils/SelectiveRevisionAcceptor.d.ts.map +0 -1
- package/dist/utils/SelectiveRevisionAcceptor.js.map +0 -1
- package/dist/utils/ShadingResolver.d.ts +0 -6
- package/dist/utils/ShadingResolver.d.ts.map +0 -1
- package/dist/utils/ShadingResolver.js.map +0 -1
- package/dist/utils/acceptRevisions.d.ts.map +0 -1
- package/dist/utils/acceptRevisions.js.map +0 -1
- package/dist/utils/cnfStyleDecoder.d.ts.map +0 -1
- package/dist/utils/cnfStyleDecoder.js.map +0 -1
- package/dist/utils/stripTrackedChanges.d.ts +0 -3
- package/dist/utils/stripTrackedChanges.d.ts.map +0 -1
- package/dist/utils/stripTrackedChanges.js.map +0 -1
- package/src/__tests__/helper-methods.test.ts +0 -512
- package/src/constants/CLAUDE.md +0 -28
- package/src/core/CLAUDE.md +0 -113
- package/src/elements/CLAUDE.md +0 -142
- package/src/formatting/CLAUDE.md +0 -78
- package/src/managers/CLAUDE.md +0 -47
- package/src/tracking/CLAUDE.md +0 -30
- package/src/types/CLAUDE.md +0 -39
- package/src/utils/CLAUDE.md +0 -168
- package/src/validation/CLAUDE.md +0 -40
- package/src/xml/CLAUDE.md +0 -65
- package/src/zip/CLAUDE.md +0 -55
- /package/dist/{utils → processors}/CompatibilityUpgrader.d.ts +0 -0
- /package/dist/{utils → processors}/cnfStyleDecoder.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textDiff.js","sourceRoot":"","sources":["../../../src/utils/textDiff.ts"],"names":[],"mappings":"AAkCA,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,OAAe;IAEvD,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,CAAC;IAGD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,CAAC;IAGD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7C,CAAC;IAGD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACxD,OAAO,SAAS,GAAG,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACvE,SAAS,EAAE,CAAC;IACd,CAAC;IAGD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,OACE,SAAS,GAAG,SAAS;QACrB,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,EACnF,CAAC;QACD,SAAS,EAAE,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAkB,EAAE,CAAC;IAGnC,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;IAGD,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEvE,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACrD,CAAC;IAGD,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAMD,MAAM,UAAU,qBAAqB,CAAC,QAAuB;IAC3D,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;AAClD,CAAC","sourcesContent":["/**\n * Text diff utility for character-level granular tracked changes.\n *\n * Uses a prefix/suffix diff algorithm to compute minimal edit operations\n * between two strings. This allows tracked changes to show only the\n * actual differences instead of marking entire runs as deleted/inserted.\n */\n\n/**\n * Represents a segment of a diff result.\n */\nexport interface DiffSegment {\n /** Whether this segment is unchanged, deleted, or inserted */\n type: 'equal' | 'delete' | 'insert';\n /** The text content of this segment */\n text: string;\n}\n\n/**\n * Computes minimal diff segments between two strings.\n *\n * Algorithm: Find common prefix, then common suffix from the remaining text,\n * then the middle portion is a delete (from old) + insert (from new).\n *\n * This handles the most common edit patterns optimally:\n * - Space removal: \"word word\" → \"word word\" → [equal \"word \", delete \" \", equal \"word\"]\n * - Word replacement: \"The quick fox\" → \"The slow fox\" → [equal \"The \", delete \"quick\", insert \"slow\", equal \" fox\"]\n * - Prefix change: \"Hello World\" → \"Goodbye World\" → [delete \"Hello\", insert \"Goodbye\", equal \" World\"]\n * - Suffix change: \"Hello World\" → \"Hello Earth\" → [equal \"Hello \", delete \"World\", insert \"Earth\"]\n *\n * @param oldText - The original text\n * @param newText - The new text\n * @returns Array of diff segments\n */\nexport function diffText(oldText: string, newText: string): DiffSegment[] {\n // Identical strings — no changes\n if (oldText === newText) {\n return oldText.length > 0 ? [{ type: 'equal', text: oldText }] : [];\n }\n\n // Empty old — entire new text is an insertion\n if (oldText.length === 0) {\n return newText.length > 0 ? [{ type: 'insert', text: newText }] : [];\n }\n\n // Empty new — entire old text is a deletion\n if (newText.length === 0) {\n return [{ type: 'delete', text: oldText }];\n }\n\n // Find common prefix length\n let prefixLen = 0;\n const minLen = Math.min(oldText.length, newText.length);\n while (prefixLen < minLen && oldText[prefixLen] === newText[prefixLen]) {\n prefixLen++;\n }\n\n // Find common suffix length (not overlapping with prefix)\n let suffixLen = 0;\n const maxSuffix = minLen - prefixLen;\n while (\n suffixLen < maxSuffix &&\n oldText[oldText.length - 1 - suffixLen] === newText[newText.length - 1 - suffixLen]\n ) {\n suffixLen++;\n }\n\n const segments: DiffSegment[] = [];\n\n // Common prefix\n if (prefixLen > 0) {\n segments.push({ type: 'equal', text: oldText.slice(0, prefixLen) });\n }\n\n // Middle portion — what changed\n const oldMiddle = oldText.slice(prefixLen, oldText.length - suffixLen);\n const newMiddle = newText.slice(prefixLen, newText.length - suffixLen);\n\n if (oldMiddle.length > 0) {\n segments.push({ type: 'delete', text: oldMiddle });\n }\n if (newMiddle.length > 0) {\n segments.push({ type: 'insert', text: newMiddle });\n }\n\n // Common suffix\n if (suffixLen > 0) {\n segments.push({ type: 'equal', text: oldText.slice(oldText.length - suffixLen) });\n }\n\n return segments;\n}\n\n/**\n * Checks whether a diff result has any unchanged (equal) portions.\n * If false, the entire text was replaced (no benefit from granular tracking).\n */\nexport function diffHasUnchangedParts(segments: DiffSegment[]): boolean {\n return segments.some((s) => s.type === 'equal');\n}\n"]}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
export const STANDARD_DPI = 96;
|
|
2
|
+
export const UNITS = {
|
|
3
|
+
EMUS_PER_INCH: 914400,
|
|
4
|
+
TWIPS_PER_INCH: 1440,
|
|
5
|
+
POINTS_PER_INCH: 72,
|
|
6
|
+
TWIPS_PER_POINT: 20,
|
|
7
|
+
EMUS_PER_TWIP: 635,
|
|
8
|
+
EMUS_PER_POINT: 12700,
|
|
9
|
+
EMUS_PER_CM: 360000,
|
|
10
|
+
INCHES_PER_CM: 0.393701,
|
|
11
|
+
CM_PER_INCH: 2.54,
|
|
12
|
+
HALF_POINTS_PER_POINT: 2,
|
|
13
|
+
};
|
|
14
|
+
export function twipsToPoints(twips) {
|
|
15
|
+
return twips / UNITS.TWIPS_PER_POINT;
|
|
16
|
+
}
|
|
17
|
+
export function twipsToInches(twips) {
|
|
18
|
+
return twips / UNITS.TWIPS_PER_INCH;
|
|
19
|
+
}
|
|
20
|
+
export function twipsToCm(twips) {
|
|
21
|
+
return twipsToInches(twips) * UNITS.CM_PER_INCH;
|
|
22
|
+
}
|
|
23
|
+
export function twipsToEmus(twips) {
|
|
24
|
+
return Math.round(twips * UNITS.EMUS_PER_TWIP);
|
|
25
|
+
}
|
|
26
|
+
export function emusToTwips(emus) {
|
|
27
|
+
return Math.round(emus / UNITS.EMUS_PER_TWIP);
|
|
28
|
+
}
|
|
29
|
+
export function emusToInches(emus) {
|
|
30
|
+
return emus / UNITS.EMUS_PER_INCH;
|
|
31
|
+
}
|
|
32
|
+
export function emusToCm(emus) {
|
|
33
|
+
return emus / UNITS.EMUS_PER_CM;
|
|
34
|
+
}
|
|
35
|
+
export function emusToPoints(emus) {
|
|
36
|
+
return emus / UNITS.EMUS_PER_POINT;
|
|
37
|
+
}
|
|
38
|
+
export function emusToPixels(emus, dpi = STANDARD_DPI) {
|
|
39
|
+
return Math.round((emus / UNITS.EMUS_PER_INCH) * dpi);
|
|
40
|
+
}
|
|
41
|
+
export function pointsToTwips(points) {
|
|
42
|
+
return points * UNITS.TWIPS_PER_POINT;
|
|
43
|
+
}
|
|
44
|
+
export function pointsToEmus(points) {
|
|
45
|
+
return Math.round(points * UNITS.EMUS_PER_POINT);
|
|
46
|
+
}
|
|
47
|
+
export function pointsToInches(points) {
|
|
48
|
+
return points / UNITS.POINTS_PER_INCH;
|
|
49
|
+
}
|
|
50
|
+
export function pointsToCm(points) {
|
|
51
|
+
return pointsToInches(points) * UNITS.CM_PER_INCH;
|
|
52
|
+
}
|
|
53
|
+
export function pointsToHalfPoints(points) {
|
|
54
|
+
return Math.round(points * UNITS.HALF_POINTS_PER_POINT);
|
|
55
|
+
}
|
|
56
|
+
export function halfPointsToPoints(halfPoints) {
|
|
57
|
+
return halfPoints / UNITS.HALF_POINTS_PER_POINT;
|
|
58
|
+
}
|
|
59
|
+
export function inchesToTwips(inches) {
|
|
60
|
+
return Math.round(inches * UNITS.TWIPS_PER_INCH);
|
|
61
|
+
}
|
|
62
|
+
export function inchesToEmus(inches) {
|
|
63
|
+
return Math.round(inches * UNITS.EMUS_PER_INCH);
|
|
64
|
+
}
|
|
65
|
+
export function inchesToPoints(inches) {
|
|
66
|
+
return inches * UNITS.POINTS_PER_INCH;
|
|
67
|
+
}
|
|
68
|
+
export function inchesToCm(inches) {
|
|
69
|
+
return inches * UNITS.CM_PER_INCH;
|
|
70
|
+
}
|
|
71
|
+
export function inchesToPixels(inches, dpi = STANDARD_DPI) {
|
|
72
|
+
return Math.round(inches * dpi);
|
|
73
|
+
}
|
|
74
|
+
export function cmToTwips(cm) {
|
|
75
|
+
return inchesToTwips(cm * UNITS.INCHES_PER_CM);
|
|
76
|
+
}
|
|
77
|
+
export function cmToEmus(cm) {
|
|
78
|
+
return Math.round(cm * UNITS.EMUS_PER_CM);
|
|
79
|
+
}
|
|
80
|
+
export function cmToInches(cm) {
|
|
81
|
+
return cm * UNITS.INCHES_PER_CM;
|
|
82
|
+
}
|
|
83
|
+
export function cmToPoints(cm) {
|
|
84
|
+
return inchesToPoints(cmToInches(cm));
|
|
85
|
+
}
|
|
86
|
+
export function cmToPixels(cm, dpi = STANDARD_DPI) {
|
|
87
|
+
return inchesToPixels(cmToInches(cm), dpi);
|
|
88
|
+
}
|
|
89
|
+
export function pixelsToEmus(pixels, dpi = STANDARD_DPI) {
|
|
90
|
+
return Math.round((pixels / dpi) * UNITS.EMUS_PER_INCH);
|
|
91
|
+
}
|
|
92
|
+
export function pixelsToInches(pixels, dpi = STANDARD_DPI) {
|
|
93
|
+
return pixels / dpi;
|
|
94
|
+
}
|
|
95
|
+
export function pixelsToTwips(pixels, dpi = STANDARD_DPI) {
|
|
96
|
+
return inchesToTwips(pixelsToInches(pixels, dpi));
|
|
97
|
+
}
|
|
98
|
+
export function pixelsToCm(pixels, dpi = STANDARD_DPI) {
|
|
99
|
+
return pixelsToInches(pixels, dpi) * UNITS.CM_PER_INCH;
|
|
100
|
+
}
|
|
101
|
+
export function pixelsToPoints(pixels, dpi = STANDARD_DPI) {
|
|
102
|
+
return inchesToPoints(pixelsToInches(pixels, dpi));
|
|
103
|
+
}
|
|
104
|
+
export const PAGE_SIZES = {
|
|
105
|
+
LETTER: {
|
|
106
|
+
width: 12240,
|
|
107
|
+
height: 15840,
|
|
108
|
+
},
|
|
109
|
+
A4: {
|
|
110
|
+
width: 11906,
|
|
111
|
+
height: 16838,
|
|
112
|
+
},
|
|
113
|
+
LEGAL: {
|
|
114
|
+
width: 12240,
|
|
115
|
+
height: 20160,
|
|
116
|
+
},
|
|
117
|
+
TABLOID: {
|
|
118
|
+
width: 15840,
|
|
119
|
+
height: 24480,
|
|
120
|
+
},
|
|
121
|
+
A3: {
|
|
122
|
+
width: 16838,
|
|
123
|
+
height: 23811,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
export const COMMON_MARGINS = {
|
|
127
|
+
NORMAL: {
|
|
128
|
+
top: 1440,
|
|
129
|
+
bottom: 1440,
|
|
130
|
+
left: 1440,
|
|
131
|
+
right: 1440,
|
|
132
|
+
},
|
|
133
|
+
NARROW: {
|
|
134
|
+
top: 720,
|
|
135
|
+
bottom: 720,
|
|
136
|
+
left: 720,
|
|
137
|
+
right: 720,
|
|
138
|
+
},
|
|
139
|
+
WIDE: {
|
|
140
|
+
top: 1440,
|
|
141
|
+
bottom: 1440,
|
|
142
|
+
left: 2880,
|
|
143
|
+
right: 2880,
|
|
144
|
+
},
|
|
145
|
+
MODERATE: {
|
|
146
|
+
top: 1440,
|
|
147
|
+
bottom: 1440,
|
|
148
|
+
left: 1080,
|
|
149
|
+
right: 1080,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
//# sourceMappingURL=units.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"units.js","sourceRoot":"","sources":["../../../src/utils/units.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unit Conversion Utilities\n *\n * Word documents use multiple measurement units:\n * - Twips: 1/20th of a point (used for most measurements like margins, indents)\n * - EMUs: English Metric Units (used for DrawingML, images)\n * - Points: Typography unit (72 points = 1 inch)\n * - Pixels: Screen measurement (depends on DPI)\n * - Inches/Centimeters: Human-readable units\n *\n * Conversion factors:\n * - 1 inch = 72 points = 1440 twips = 914,400 EMUs\n * - 1 cm = 0.393701 inches = 360,000 EMUs\n * - 1 point = 20 twips = 12,700 EMUs\n */\n\n/**\n * Standard DPI (dots per inch) for screen displays\n */\nexport const STANDARD_DPI = 96;\n\n/**\n * Conversion constants\n */\nexport const UNITS = {\n /** EMUs per inch */\n EMUS_PER_INCH: 914400,\n /** Twips per inch */\n TWIPS_PER_INCH: 1440,\n /** Points per inch */\n POINTS_PER_INCH: 72,\n /** Twips per point */\n TWIPS_PER_POINT: 20,\n /** EMUs per twip */\n EMUS_PER_TWIP: 635,\n /** EMUs per point */\n EMUS_PER_POINT: 12700,\n /** EMUs per centimeter */\n EMUS_PER_CM: 360000,\n /** Inches per centimeter */\n INCHES_PER_CM: 0.393701,\n /** Centimeters per inch */\n CM_PER_INCH: 2.54,\n /** Half-points per point (Word uses half-points for font sizes) */\n HALF_POINTS_PER_POINT: 2,\n} as const;\n\n// ============================================================================\n// Twips Conversions\n// ============================================================================\n\n/**\n * Converts twips to points\n * @param twips Value in twips\n * @returns Value in points\n */\nexport function twipsToPoints(twips: number): number {\n return twips / UNITS.TWIPS_PER_POINT;\n}\n\n/**\n * Converts twips to inches\n * @param twips Value in twips\n * @returns Value in inches\n */\nexport function twipsToInches(twips: number): number {\n return twips / UNITS.TWIPS_PER_INCH;\n}\n\n/**\n * Converts twips to centimeters\n * @param twips Value in twips\n * @returns Value in centimeters\n */\nexport function twipsToCm(twips: number): number {\n return twipsToInches(twips) * UNITS.CM_PER_INCH;\n}\n\n/**\n * Converts twips to EMUs\n * @param twips Value in twips\n * @returns Value in EMUs\n */\nexport function twipsToEmus(twips: number): number {\n return Math.round(twips * UNITS.EMUS_PER_TWIP);\n}\n\n// ============================================================================\n// EMUs Conversions\n// ============================================================================\n\n/**\n * Converts EMUs to twips\n * @param emus Value in EMUs\n * @returns Value in twips\n */\nexport function emusToTwips(emus: number): number {\n return Math.round(emus / UNITS.EMUS_PER_TWIP);\n}\n\n/**\n * Converts EMUs to inches\n * @param emus Value in EMUs\n * @returns Value in inches\n */\nexport function emusToInches(emus: number): number {\n return emus / UNITS.EMUS_PER_INCH;\n}\n\n/**\n * Converts EMUs to centimeters\n * @param emus Value in EMUs\n * @returns Value in centimeters\n */\nexport function emusToCm(emus: number): number {\n return emus / UNITS.EMUS_PER_CM;\n}\n\n/**\n * Converts EMUs to points\n * @param emus Value in EMUs\n * @returns Value in points\n */\nexport function emusToPoints(emus: number): number {\n return emus / UNITS.EMUS_PER_POINT;\n}\n\n/**\n * Converts EMUs to pixels\n * @param emus Value in EMUs\n * @param dpi Dots per inch (default: 96)\n * @returns Value in pixels\n */\nexport function emusToPixels(emus: number, dpi: number = STANDARD_DPI): number {\n return Math.round((emus / UNITS.EMUS_PER_INCH) * dpi);\n}\n\n// ============================================================================\n// Points Conversions\n// ============================================================================\n\n/**\n * Converts points to twips\n * @param points Value in points\n * @returns Value in twips\n */\nexport function pointsToTwips(points: number): number {\n return points * UNITS.TWIPS_PER_POINT;\n}\n\n/**\n * Converts points to EMUs\n * @param points Value in points\n * @returns Value in EMUs\n */\nexport function pointsToEmus(points: number): number {\n return Math.round(points * UNITS.EMUS_PER_POINT);\n}\n\n/**\n * Converts points to inches\n * @param points Value in points\n * @returns Value in inches\n */\nexport function pointsToInches(points: number): number {\n return points / UNITS.POINTS_PER_INCH;\n}\n\n/**\n * Converts points to centimeters\n * @param points Value in points\n * @returns Value in centimeters\n */\nexport function pointsToCm(points: number): number {\n return pointsToInches(points) * UNITS.CM_PER_INCH;\n}\n\n// ============================================================================\n// Half-Points Conversions (Word uses half-points for font sizes)\n// ============================================================================\n\n/**\n * Converts points to half-points (for Word font size storage)\n * @param points Value in points\n * @returns Value in half-points\n */\nexport function pointsToHalfPoints(points: number): number {\n // Round to nearest integer — w:sz/w:szCs require ST_HpsMeasure (unsigned integer)\n return Math.round(points * UNITS.HALF_POINTS_PER_POINT);\n}\n\n/**\n * Converts half-points to points (from Word font size storage)\n * @param halfPoints Value in half-points\n * @returns Value in points\n */\nexport function halfPointsToPoints(halfPoints: number): number {\n return halfPoints / UNITS.HALF_POINTS_PER_POINT;\n}\n\n// ============================================================================\n// Inches Conversions\n// ============================================================================\n\n/**\n * Converts inches to twips\n * @param inches Value in inches\n * @returns Value in twips\n */\nexport function inchesToTwips(inches: number): number {\n return Math.round(inches * UNITS.TWIPS_PER_INCH);\n}\n\n/**\n * Converts inches to EMUs\n * @param inches Value in inches\n * @returns Value in EMUs\n */\nexport function inchesToEmus(inches: number): number {\n return Math.round(inches * UNITS.EMUS_PER_INCH);\n}\n\n/**\n * Converts inches to points\n * @param inches Value in inches\n * @returns Value in points\n */\nexport function inchesToPoints(inches: number): number {\n return inches * UNITS.POINTS_PER_INCH;\n}\n\n/**\n * Converts inches to centimeters\n * @param inches Value in inches\n * @returns Value in centimeters\n */\nexport function inchesToCm(inches: number): number {\n return inches * UNITS.CM_PER_INCH;\n}\n\n/**\n * Converts inches to pixels\n * @param inches Value in inches\n * @param dpi Dots per inch (default: 96)\n * @returns Value in pixels\n */\nexport function inchesToPixels(inches: number, dpi: number = STANDARD_DPI): number {\n return Math.round(inches * dpi);\n}\n\n// ============================================================================\n// Centimeters Conversions\n// ============================================================================\n\n/**\n * Converts centimeters to twips\n * @param cm Value in centimeters\n * @returns Value in twips\n */\nexport function cmToTwips(cm: number): number {\n return inchesToTwips(cm * UNITS.INCHES_PER_CM);\n}\n\n/**\n * Converts centimeters to EMUs\n * @param cm Value in centimeters\n * @returns Value in EMUs\n */\nexport function cmToEmus(cm: number): number {\n return Math.round(cm * UNITS.EMUS_PER_CM);\n}\n\n/**\n * Converts centimeters to inches\n * @param cm Value in centimeters\n * @returns Value in inches\n */\nexport function cmToInches(cm: number): number {\n return cm * UNITS.INCHES_PER_CM;\n}\n\n/**\n * Converts centimeters to points\n * @param cm Value in centimeters\n * @returns Value in points\n */\nexport function cmToPoints(cm: number): number {\n return inchesToPoints(cmToInches(cm));\n}\n\n/**\n * Converts centimeters to pixels\n * @param cm Value in centimeters\n * @param dpi Dots per inch (default: 96)\n * @returns Value in pixels\n */\nexport function cmToPixels(cm: number, dpi: number = STANDARD_DPI): number {\n return inchesToPixels(cmToInches(cm), dpi);\n}\n\n// ============================================================================\n// Pixels Conversions\n// ============================================================================\n\n/**\n * Converts pixels to EMUs\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in EMUs\n */\nexport function pixelsToEmus(pixels: number, dpi: number = STANDARD_DPI): number {\n return Math.round((pixels / dpi) * UNITS.EMUS_PER_INCH);\n}\n\n/**\n * Converts pixels to inches\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in inches\n */\nexport function pixelsToInches(pixels: number, dpi: number = STANDARD_DPI): number {\n return pixels / dpi;\n}\n\n/**\n * Converts pixels to twips\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in twips\n */\nexport function pixelsToTwips(pixels: number, dpi: number = STANDARD_DPI): number {\n return inchesToTwips(pixelsToInches(pixels, dpi));\n}\n\n/**\n * Converts pixels to centimeters\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in centimeters\n */\nexport function pixelsToCm(pixels: number, dpi: number = STANDARD_DPI): number {\n return pixelsToInches(pixels, dpi) * UNITS.CM_PER_INCH;\n}\n\n/**\n * Converts pixels to points\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in points\n */\nexport function pixelsToPoints(pixels: number, dpi: number = STANDARD_DPI): number {\n return inchesToPoints(pixelsToInches(pixels, dpi));\n}\n\n// ============================================================================\n// Common Document Sizes (in twips)\n// ============================================================================\n\n/**\n * Common page sizes in twips\n */\nexport const PAGE_SIZES = {\n /** Letter (8.5\" x 11\") */\n LETTER: {\n width: 12240, // 8.5 inches\n height: 15840, // 11 inches\n },\n /** A4 (21cm x 29.7cm) */\n A4: {\n width: 11906, // 21cm\n height: 16838, // 29.7cm\n },\n /** Legal (8.5\" x 14\") */\n LEGAL: {\n width: 12240, // 8.5 inches\n height: 20160, // 14 inches\n },\n /** Tabloid (11\" x 17\") */\n TABLOID: {\n width: 15840, // 11 inches\n height: 24480, // 17 inches\n },\n /** A3 (29.7cm x 42cm) */\n A3: {\n width: 16838, // 29.7cm\n height: 23811, // 42cm\n },\n} as const;\n\n/**\n * Common margin sizes in twips\n */\nexport const COMMON_MARGINS = {\n /** Normal margins (1 inch all around) */\n NORMAL: {\n top: 1440,\n bottom: 1440,\n left: 1440,\n right: 1440,\n },\n /** Narrow margins (0.5 inch all around) */\n NARROW: {\n top: 720,\n bottom: 720,\n left: 720,\n right: 720,\n },\n /** Wide margins (2 inches left/right, 1 inch top/bottom) */\n WIDE: {\n top: 1440,\n bottom: 1440,\n left: 2880,\n right: 2880,\n },\n /** Moderate margins (1 inch top/bottom, 0.75 inch left/right) */\n MODERATE: {\n top: 1440,\n bottom: 1440,\n left: 1080,\n right: 1080,\n },\n} as const;\n"]}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { REQUIRED_DOCX_FILES } from '../zip/types.js';
|
|
2
|
+
import { MissingRequiredFileError } from '../zip/errors.js';
|
|
3
|
+
import { defaultLogger } from './logger.js';
|
|
4
|
+
export function validateDocxStructure(filePaths) {
|
|
5
|
+
const fileSet = new Set(filePaths);
|
|
6
|
+
for (const requiredFile of REQUIRED_DOCX_FILES) {
|
|
7
|
+
if (!fileSet.has(requiredFile)) {
|
|
8
|
+
throw new MissingRequiredFileError(requiredFile);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function isBinaryFile(filePath) {
|
|
13
|
+
const binaryExtensions = [
|
|
14
|
+
'.png',
|
|
15
|
+
'.jpg',
|
|
16
|
+
'.jpeg',
|
|
17
|
+
'.gif',
|
|
18
|
+
'.bmp',
|
|
19
|
+
'.tiff',
|
|
20
|
+
'.ico',
|
|
21
|
+
'.emf',
|
|
22
|
+
'.wmf',
|
|
23
|
+
'.bin',
|
|
24
|
+
'.dat',
|
|
25
|
+
'.ttf',
|
|
26
|
+
'.otf',
|
|
27
|
+
'.woff',
|
|
28
|
+
];
|
|
29
|
+
const extension = filePath.substring(filePath.lastIndexOf('.')).toLowerCase();
|
|
30
|
+
return binaryExtensions.includes(extension);
|
|
31
|
+
}
|
|
32
|
+
export function normalizePath(path) {
|
|
33
|
+
const normalized = path.replace(/\\/g, '/').replace(/^\/+/, '');
|
|
34
|
+
if (/%2[eE]|%2[fF]|%5[cC]/.test(path)) {
|
|
35
|
+
throw new Error(`Invalid file path: "${path}" contains URL-encoded characters (%2E, %2F, %5C). ` +
|
|
36
|
+
`This could be an attempt to bypass path validation. ` +
|
|
37
|
+
`Only plain characters are allowed in DOCX file paths.`);
|
|
38
|
+
}
|
|
39
|
+
if (normalized.includes('../') || normalized.includes('/..') || normalized === '..') {
|
|
40
|
+
throw new Error(`Invalid file path: "${path}" contains path traversal sequence (..). ` +
|
|
41
|
+
`This could be a malicious DOCX file attempting directory traversal. ` +
|
|
42
|
+
`DOCX archives must only contain relative paths within the archive.`);
|
|
43
|
+
}
|
|
44
|
+
if (/^[a-zA-Z]:/.test(normalized)) {
|
|
45
|
+
throw new Error(`Invalid file path: "${path}" appears to be an absolute Windows path. ` +
|
|
46
|
+
`Absolute paths are not allowed in DOCX archives. ` +
|
|
47
|
+
`Only relative paths within the archive are permitted.`);
|
|
48
|
+
}
|
|
49
|
+
if (path.startsWith('/') && normalized.startsWith('/')) {
|
|
50
|
+
throw new Error(`Invalid file path: "${path}" appears to be an absolute Unix path. ` +
|
|
51
|
+
`Only relative paths are allowed in DOCX archives.`);
|
|
52
|
+
}
|
|
53
|
+
return normalized;
|
|
54
|
+
}
|
|
55
|
+
export function isValidZipBuffer(buffer) {
|
|
56
|
+
if (buffer.length < 4) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return (buffer[0] === 0x50 &&
|
|
60
|
+
buffer[1] === 0x4b &&
|
|
61
|
+
((buffer[2] === 0x03 && buffer[3] === 0x04) || (buffer[2] === 0x05 && buffer[3] === 0x06)));
|
|
62
|
+
}
|
|
63
|
+
export function isTextContent(content) {
|
|
64
|
+
if (typeof content === 'string') {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const text = content.toString('utf8');
|
|
69
|
+
return !text.includes('\0');
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function validateTwips(value, fieldName = 'value') {
|
|
76
|
+
if (!Number.isFinite(value)) {
|
|
77
|
+
throw new Error(`${fieldName} must be a finite number, got ${value}`);
|
|
78
|
+
}
|
|
79
|
+
const MIN_TWIPS = -31680;
|
|
80
|
+
const MAX_TWIPS = 31680;
|
|
81
|
+
if (value < MIN_TWIPS || value > MAX_TWIPS) {
|
|
82
|
+
throw new Error(`${fieldName} out of range: ${value} twips (allowed: ${MIN_TWIPS} to ${MAX_TWIPS}, ±22 inches)`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function normalizeColor(color) {
|
|
86
|
+
const hex = color.replace(/^#/, '');
|
|
87
|
+
if (!/^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(hex)) {
|
|
88
|
+
throw new Error(`Invalid color format: "${color}". Expected 3 or 6-character hex ` +
|
|
89
|
+
`(e.g., "FF0000", "#FF0000", "F00", or "#F00")`);
|
|
90
|
+
}
|
|
91
|
+
if (hex.length === 3) {
|
|
92
|
+
return (hex.charAt(0) +
|
|
93
|
+
hex.charAt(0) +
|
|
94
|
+
hex.charAt(1) +
|
|
95
|
+
hex.charAt(1) +
|
|
96
|
+
hex.charAt(2) +
|
|
97
|
+
hex.charAt(2)).toUpperCase();
|
|
98
|
+
}
|
|
99
|
+
return hex.toUpperCase();
|
|
100
|
+
}
|
|
101
|
+
export function validateColor(color, fieldName = 'color') {
|
|
102
|
+
if (typeof color !== 'string') {
|
|
103
|
+
throw new Error(`${fieldName} must be a string, got ${typeof color}`);
|
|
104
|
+
}
|
|
105
|
+
const cleanColor = color.startsWith('#') ? color.substring(1) : color;
|
|
106
|
+
if (!/^[0-9A-Fa-f]{6}$/.test(cleanColor)) {
|
|
107
|
+
throw new Error(`${fieldName} must be a 6-digit hex color (e.g., 'FF0000' or '#FF0000'), got '${color}'`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export const validateHexColor = validateColor;
|
|
111
|
+
export function validateNumberingId(numId, fieldName = 'numbering ID') {
|
|
112
|
+
if (!Number.isInteger(numId)) {
|
|
113
|
+
throw new Error(`${fieldName} must be an integer, got ${numId}`);
|
|
114
|
+
}
|
|
115
|
+
if (numId < 0) {
|
|
116
|
+
throw new Error(`${fieldName} must be non-negative, got ${numId}`);
|
|
117
|
+
}
|
|
118
|
+
const MAX_NUM_ID = 2147483647;
|
|
119
|
+
if (numId > MAX_NUM_ID) {
|
|
120
|
+
throw new Error(`${fieldName} exceeds maximum value ${MAX_NUM_ID}, got ${numId}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export function validateLevel(level, fieldName = 'level', maxLevel = 8) {
|
|
124
|
+
if (!Number.isInteger(level)) {
|
|
125
|
+
throw new Error(`${fieldName} must be an integer, got ${level}`);
|
|
126
|
+
}
|
|
127
|
+
if (level < 0 || level > maxLevel) {
|
|
128
|
+
throw new Error(`${fieldName} must be between 0 and ${maxLevel}, got ${level}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
export function validateAlignment(alignment, allowed, fieldName = 'alignment') {
|
|
132
|
+
if (typeof alignment !== 'string') {
|
|
133
|
+
throw new Error(`${fieldName} must be a string, got ${typeof alignment}`);
|
|
134
|
+
}
|
|
135
|
+
if (!allowed.includes(alignment)) {
|
|
136
|
+
throw new Error(`Invalid ${fieldName}: '${alignment}' (allowed: ${allowed.join(', ')})`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export function validateFontSize(size, fieldName = 'font size') {
|
|
140
|
+
if (!Number.isFinite(size)) {
|
|
141
|
+
throw new Error(`${fieldName} must be a finite number, got ${size}`);
|
|
142
|
+
}
|
|
143
|
+
if (!Number.isInteger(size)) {
|
|
144
|
+
throw new Error(`${fieldName} must be an integer (in half-points), got ${size}`);
|
|
145
|
+
}
|
|
146
|
+
const MIN_SIZE = 2;
|
|
147
|
+
const MAX_SIZE = 1638;
|
|
148
|
+
if (size < MIN_SIZE || size > MAX_SIZE) {
|
|
149
|
+
throw new Error(`${fieldName} out of range: ${size} half-points (allowed: ${MIN_SIZE}-${MAX_SIZE}, or ${MIN_SIZE / 2}-${MAX_SIZE / 2} points)`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export function validateNonEmptyString(value, fieldName = 'value') {
|
|
153
|
+
if (typeof value !== 'string') {
|
|
154
|
+
throw new Error(`${fieldName} must be a string, got ${typeof value}`);
|
|
155
|
+
}
|
|
156
|
+
if (value.trim().length === 0) {
|
|
157
|
+
throw new Error(`${fieldName} cannot be empty`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export function validatePercentage(value, fieldName = 'percentage') {
|
|
161
|
+
if (!Number.isFinite(value)) {
|
|
162
|
+
throw new Error(`${fieldName} must be a finite number, got ${value}`);
|
|
163
|
+
}
|
|
164
|
+
if (value < 0 || value > 100) {
|
|
165
|
+
throw new Error(`${fieldName} must be between 0 and 100, got ${value}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export function validateEmus(value, fieldName = 'EMUs') {
|
|
169
|
+
if (!Number.isFinite(value)) {
|
|
170
|
+
throw new Error(`${fieldName} must be a finite number, got ${value}`);
|
|
171
|
+
}
|
|
172
|
+
if (!Number.isInteger(value)) {
|
|
173
|
+
throw new Error(`${fieldName} must be an integer, got ${value}`);
|
|
174
|
+
}
|
|
175
|
+
if (value < 0) {
|
|
176
|
+
throw new Error(`${fieldName} must be non-negative, got ${value}`);
|
|
177
|
+
}
|
|
178
|
+
const MAX_EMUS = 50000000;
|
|
179
|
+
if (value > MAX_EMUS) {
|
|
180
|
+
throw new Error(`${fieldName} exceeds maximum ${MAX_EMUS} (about 55 inches), got ${value}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
export function detectXmlInText(text, context) {
|
|
184
|
+
const warnings = [];
|
|
185
|
+
let hasXmlPatterns = false;
|
|
186
|
+
const xmlElementPattern = /<\/?w:[^>]+>|<w:[^>]+\/>/g;
|
|
187
|
+
const escapedXmlPattern = /<.*?>|"|'/g;
|
|
188
|
+
const problematicPatterns = [
|
|
189
|
+
/<w:t\s+xml:space="preserve">/,
|
|
190
|
+
/<w:t\s+xml:space=["']preserve["']>/,
|
|
191
|
+
/<\/w:t>/,
|
|
192
|
+
/<w:t\s+xml:space="preserve">/,
|
|
193
|
+
];
|
|
194
|
+
if (xmlElementPattern.test(text)) {
|
|
195
|
+
hasXmlPatterns = true;
|
|
196
|
+
const contextStr = context ? ` in ${context}` : '';
|
|
197
|
+
warnings.push(`Text${contextStr} contains XML-like markup: "${text.substring(0, 100)}${text.length > 100 ? '...' : ''}". ` +
|
|
198
|
+
`This will be displayed as literal text in the document. ` +
|
|
199
|
+
`If you intended to add formatting, use the appropriate API methods instead.`);
|
|
200
|
+
}
|
|
201
|
+
if (escapedXmlPattern.test(text)) {
|
|
202
|
+
hasXmlPatterns = true;
|
|
203
|
+
const contextStr = context ? ` in ${context}` : '';
|
|
204
|
+
warnings.push(`Text${contextStr} contains escaped XML entities (e.g., <, >, "). ` +
|
|
205
|
+
`These will appear as literal characters in the document.`);
|
|
206
|
+
}
|
|
207
|
+
for (const pattern of problematicPatterns) {
|
|
208
|
+
if (pattern.test(text)) {
|
|
209
|
+
hasXmlPatterns = true;
|
|
210
|
+
const contextStr = context ? ` in ${context}` : '';
|
|
211
|
+
warnings.push(`Text${contextStr} contains a known problematic XML pattern that suggests ` +
|
|
212
|
+
`the text may have been corrupted by previous processing.`);
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
isValid: true,
|
|
218
|
+
hasXmlPatterns,
|
|
219
|
+
warnings,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
export function cleanXmlFromText(text, aggressive = false) {
|
|
223
|
+
let cleaned = text;
|
|
224
|
+
cleaned = cleaned
|
|
225
|
+
.replace(/</g, '<')
|
|
226
|
+
.replace(/>/g, '>')
|
|
227
|
+
.replace(/"/g, '"')
|
|
228
|
+
.replace(/'/g, "'")
|
|
229
|
+
.replace(/&/g, '&');
|
|
230
|
+
cleaned = cleaned.replace(/<w:[^>]+>/g, '');
|
|
231
|
+
cleaned = cleaned.replace(/<\/w:[^>]+>/g, '');
|
|
232
|
+
if (aggressive) {
|
|
233
|
+
cleaned = cleaned.replace(/<[^>]+>/g, '');
|
|
234
|
+
}
|
|
235
|
+
cleaned = cleaned.replace(/\s+/g, ' ').trim();
|
|
236
|
+
return cleaned;
|
|
237
|
+
}
|
|
238
|
+
export function validateRunText(text, options = {}) {
|
|
239
|
+
const { context, autoClean = false, aggressive = false, warnToConsole = true } = options;
|
|
240
|
+
const result = detectXmlInText(text, context);
|
|
241
|
+
if (autoClean && result.hasXmlPatterns) {
|
|
242
|
+
result.cleanedText = cleanXmlFromText(text, aggressive);
|
|
243
|
+
result.warnings.push(`Text has been automatically cleaned. ` +
|
|
244
|
+
`Original: "${text.substring(0, 50)}${text.length > 50 ? '...' : ''}" ` +
|
|
245
|
+
`Cleaned: "${result.cleanedText.substring(0, 50)}${result.cleanedText.length > 50 ? '...' : ''}"`);
|
|
246
|
+
}
|
|
247
|
+
if (warnToConsole && result.warnings.length > 0 && typeof console !== 'undefined') {
|
|
248
|
+
const contextStr = context ? ` [${context}]` : '';
|
|
249
|
+
defaultLogger.warn(`DocXML Text Validation Warning${contextStr}:`);
|
|
250
|
+
result.warnings.forEach((warning) => defaultLogger.warn(` - ${warning}`));
|
|
251
|
+
}
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
export function sanitizeHyperlinkUrl(url) {
|
|
255
|
+
if (!url)
|
|
256
|
+
return null;
|
|
257
|
+
const fixes = [];
|
|
258
|
+
let sanitized = url;
|
|
259
|
+
const extensionPrefixes = [
|
|
260
|
+
{ pattern: /^chrome-extension:\/\/[a-z]{32}\//i, name: 'Chrome extension' },
|
|
261
|
+
{
|
|
262
|
+
pattern: /^moz-extension:\/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\//i,
|
|
263
|
+
name: 'Firefox extension',
|
|
264
|
+
},
|
|
265
|
+
{ pattern: /^extension:\/\/[a-z0-9]{32}\//i, name: 'Edge extension' },
|
|
266
|
+
];
|
|
267
|
+
for (const { pattern, name } of extensionPrefixes) {
|
|
268
|
+
const match = pattern.exec(sanitized);
|
|
269
|
+
if (match) {
|
|
270
|
+
sanitized = sanitized.substring(match[0].length);
|
|
271
|
+
fixes.push(`Stripped ${name} URL prefix`);
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const brokenProtocol = /^(https?:\/)([^/])/i.exec(sanitized);
|
|
276
|
+
if (brokenProtocol) {
|
|
277
|
+
sanitized =
|
|
278
|
+
brokenProtocol[1] + '/' + brokenProtocol[2] + sanitized.substring(brokenProtocol[0].length);
|
|
279
|
+
fixes.push('Fixed broken protocol (added missing slash)');
|
|
280
|
+
}
|
|
281
|
+
if (fixes.length === 0)
|
|
282
|
+
return null;
|
|
283
|
+
return { url: sanitized, fixes };
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../src/utils/validation.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validation utilities for DOCX files\n */\n\nimport { REQUIRED_DOCX_FILES } from '../zip/types.js';\nimport { MissingRequiredFileError } from '../zip/errors.js';\nimport { defaultLogger } from './logger.js';\n\n/**\n * Validates that all required DOCX files are present\n * @param filePaths - Array of file paths in the archive\n * @throws {MissingRequiredFileError} If a required file is missing\n */\nexport function validateDocxStructure(filePaths: string[]): void {\n const fileSet = new Set(filePaths);\n\n for (const requiredFile of REQUIRED_DOCX_FILES) {\n if (!fileSet.has(requiredFile)) {\n throw new MissingRequiredFileError(requiredFile);\n }\n }\n}\n\n/**\n * Checks if a file path represents a binary file based on extension\n * @param filePath - The file path to check\n * @returns True if the file is likely binary\n */\nexport function isBinaryFile(filePath: string): boolean {\n const binaryExtensions = [\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.bmp',\n '.tiff',\n '.ico',\n '.emf',\n '.wmf',\n '.bin',\n '.dat',\n '.ttf',\n '.otf',\n '.woff',\n ];\n\n const extension = filePath.substring(filePath.lastIndexOf('.')).toLowerCase();\n return binaryExtensions.includes(extension);\n}\n\n/**\n * Normalizes a file path for consistent comparisons\n * Converts backslashes to forward slashes and removes leading slashes\n * Also validates against path traversal attacks\n *\n * **Security:** This function validates paths to prevent:\n * - Path traversal attacks (../, ..\\, URL-encoded variants)\n * - Absolute paths (C:\\, /etc/, etc.)\n * - Malicious DOCX files attempting directory escape\n *\n * @param path - The path to normalize\n * @returns Normalized path\n * @throws {Error} If path contains path traversal sequences, absolute paths, or URL-encoded attacks\n */\nexport function normalizePath(path: string): string {\n // First convert all backslashes to forward slashes for consistent checking\n const normalized = path.replace(/\\\\/g, '/').replace(/^\\/+/, '');\n\n // Security: Reject URL-encoded path traversal attempts\n // Attackers might try: %2e%2e%2f (%2e = . and %2f = /)\n if (/%2[eE]|%2[fF]|%5[cC]/.test(path)) {\n throw new Error(\n `Invalid file path: \"${path}\" contains URL-encoded characters (%2E, %2F, %5C). ` +\n `This could be an attempt to bypass path validation. ` +\n `Only plain characters are allowed in DOCX file paths.`\n );\n }\n\n // Security: Prevent path traversal attacks\n // Check AFTER normalization when all paths use forward slashes\n // This catches: ../, /.., or standalone \"..\"\n if (normalized.includes('../') || normalized.includes('/..') || normalized === '..') {\n throw new Error(\n `Invalid file path: \"${path}\" contains path traversal sequence (..). ` +\n `This could be a malicious DOCX file attempting directory traversal. ` +\n `DOCX archives must only contain relative paths within the archive.`\n );\n }\n\n // Security: Prevent absolute paths (Windows drive letters)\n // Examples: C:/, C:\\, D:, etc.\n if (/^[a-zA-Z]:/.test(normalized)) {\n throw new Error(\n `Invalid file path: \"${path}\" appears to be an absolute Windows path. ` +\n `Absolute paths are not allowed in DOCX archives. ` +\n `Only relative paths within the archive are permitted.`\n );\n }\n\n // Security: Prevent Unix absolute paths\n // After removing leading slashes, if it starts with / it's suspicious\n if (path.startsWith('/') && normalized.startsWith('/')) {\n throw new Error(\n `Invalid file path: \"${path}\" appears to be an absolute Unix path. ` +\n `Only relative paths are allowed in DOCX archives.`\n );\n }\n\n return normalized;\n}\n\n/**\n * Validates that a buffer contains a valid ZIP file signature\n * ZIP files start with the signature 'PK' (0x50 0x4B)\n * @param buffer - The buffer to validate\n * @returns True if the buffer appears to be a ZIP file\n */\nexport function isValidZipBuffer(buffer: Buffer): boolean {\n if (buffer.length < 4) {\n return false;\n }\n\n // Check for ZIP signature: PK\\x03\\x04 or PK\\x05\\x06 (for empty archives)\n return (\n buffer[0] === 0x50 &&\n buffer[1] === 0x4b &&\n ((buffer[2] === 0x03 && buffer[3] === 0x04) || (buffer[2] === 0x05 && buffer[3] === 0x06))\n );\n}\n\n/**\n * Checks if a string is valid UTF-8 text\n * @param content - The content to check\n * @returns True if the content is valid text\n */\nexport function isTextContent(content: Buffer | string): boolean {\n if (typeof content === 'string') {\n return true;\n }\n\n // Try to decode as UTF-8 and check for null bytes\n try {\n const text = content.toString('utf8');\n // Binary files often contain null bytes\n return !text.includes('\\0');\n } catch {\n return false;\n }\n}\n\n/**\n * Validates a twips value (used for spacing, indentation, margins)\n * Twips: 1/20th of a point, 1440 twips = 1 inch\n * Reasonable range: -31680 to 31680 (±22 inches)\n * @param value - The twips value to validate\n * @param fieldName - Name of the field (for error messages)\n * @throws {Error} If the value is invalid\n */\nexport function validateTwips(value: number, fieldName = 'value'): void {\n if (!Number.isFinite(value)) {\n throw new Error(`${fieldName} must be a finite number, got ${value}`);\n }\n\n // Reasonable range: ±22 inches (31680 twips)\n const MIN_TWIPS = -31680;\n const MAX_TWIPS = 31680;\n\n if (value < MIN_TWIPS || value > MAX_TWIPS) {\n throw new Error(\n `${fieldName} out of range: ${value} twips (allowed: ${MIN_TWIPS} to ${MAX_TWIPS}, ±22 inches)`\n );\n }\n}\n\n/**\n * Normalizes a color to uppercase 6-character hex format\n * Accepts 3-character or 6-character hex colors with or without '#' prefix\n * Follows Microsoft Word convention of uppercase hex colors\n *\n * @param color - Color to normalize (e.g., '#F00', 'FF0000', '#FF0000', 'f00')\n * @returns Normalized color (e.g., 'FF0000')\n * @throws Error if color format is invalid\n *\n * @example\n * ```typescript\n * normalizeColor('#F00') // Returns: 'FF0000'\n * normalizeColor('FF0000') // Returns: 'FF0000'\n * normalizeColor('#ff0000') // Returns: 'FF0000'\n * normalizeColor('f00') // Returns: 'FF0000'\n * ```\n */\nexport function normalizeColor(color: string): string {\n const hex = color.replace(/^#/, '');\n\n // Validate hex format\n if (!/^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(hex)) {\n throw new Error(\n `Invalid color format: \"${color}\". Expected 3 or 6-character hex ` +\n `(e.g., \"FF0000\", \"#FF0000\", \"F00\", or \"#F00\")`\n );\n }\n\n // Expand 3-character to 6-character\n if (hex.length === 3) {\n return (\n hex.charAt(0) +\n hex.charAt(0) +\n hex.charAt(1) +\n hex.charAt(1) +\n hex.charAt(2) +\n hex.charAt(2)\n ).toUpperCase();\n }\n\n return hex.toUpperCase();\n}\n\n/**\n * Validates a hexadecimal color value\n * Must be 6 characters (RRGGBB format)\n * @param color - The color hex string to validate (without #)\n * @param fieldName - Name of the field (for error messages)\n * @throws {Error} If the color is invalid\n */\nexport function validateColor(color: string, fieldName = 'color'): void {\n if (typeof color !== 'string') {\n throw new Error(`${fieldName} must be a string, got ${typeof color}`);\n }\n\n // Allow both with and without # prefix\n const cleanColor = color.startsWith('#') ? color.substring(1) : color;\n\n if (!/^[0-9A-Fa-f]{6}$/.test(cleanColor)) {\n throw new Error(\n `${fieldName} must be a 6-digit hex color (e.g., 'FF0000' or '#FF0000'), got '${color}'`\n );\n }\n}\n\n/**\n * Alias for validateColor for backwards compatibility\n */\nexport const validateHexColor = validateColor;\n\n/**\n * Validates a numbering ID (must be non-negative integer)\n * @param numId - The numbering ID to validate\n * @param fieldName - Name of the field (for error messages)\n * @throws {Error} If the ID is invalid\n */\nexport function validateNumberingId(numId: number, fieldName = 'numbering ID'): void {\n if (!Number.isInteger(numId)) {\n throw new Error(`${fieldName} must be an integer, got ${numId}`);\n }\n\n if (numId < 0) {\n throw new Error(`${fieldName} must be non-negative, got ${numId}`);\n }\n\n // Word supports numbering IDs up to 2147483647\n const MAX_NUM_ID = 2147483647;\n if (numId > MAX_NUM_ID) {\n throw new Error(`${fieldName} exceeds maximum value ${MAX_NUM_ID}, got ${numId}`);\n }\n}\n\n/**\n * Validates a numbering level (0-8 for Word)\n * @param level - The level to validate\n * @param fieldName - Name of the field (for error messages)\n * @param maxLevel - Maximum allowed level (default 8)\n * @throws {Error} If the level is invalid\n */\nexport function validateLevel(level: number, fieldName = 'level', maxLevel = 8): void {\n if (!Number.isInteger(level)) {\n throw new Error(`${fieldName} must be an integer, got ${level}`);\n }\n\n if (level < 0 || level > maxLevel) {\n throw new Error(`${fieldName} must be between 0 and ${maxLevel}, got ${level}`);\n }\n}\n\n/**\n * Validates an alignment value against allowed values\n * @param alignment - The alignment value to validate\n * @param allowed - Array of allowed alignment values\n * @param fieldName - Name of the field (for error messages)\n * @throws {Error} If the alignment is invalid\n */\nexport function validateAlignment(\n alignment: string,\n allowed: readonly string[],\n fieldName = 'alignment'\n): void {\n if (typeof alignment !== 'string') {\n throw new Error(`${fieldName} must be a string, got ${typeof alignment}`);\n }\n\n if (!allowed.includes(alignment)) {\n throw new Error(`Invalid ${fieldName}: '${alignment}' (allowed: ${allowed.join(', ')})`);\n }\n}\n\n/**\n * Validates a font size (in half-points for Word)\n * Reasonable range: 2-1638 (1-819 points)\n * @param size - The font size in half-points to validate\n * @param fieldName - Name of the field (for error messages)\n * @throws {Error} If the size is invalid\n */\nexport function validateFontSize(size: number, fieldName = 'font size'): void {\n if (!Number.isFinite(size)) {\n throw new Error(`${fieldName} must be a finite number, got ${size}`);\n }\n\n if (!Number.isInteger(size)) {\n throw new Error(`${fieldName} must be an integer (in half-points), got ${size}`);\n }\n\n // Reasonable range: 2-1638 half-points (1-819 points)\n const MIN_SIZE = 2;\n const MAX_SIZE = 1638;\n\n if (size < MIN_SIZE || size > MAX_SIZE) {\n throw new Error(\n `${fieldName} out of range: ${size} half-points (allowed: ${MIN_SIZE}-${MAX_SIZE}, or ${MIN_SIZE / 2}-${MAX_SIZE / 2} points)`\n );\n }\n}\n\n/**\n * Validates that a string is not empty\n * @param value - The string to validate\n * @param fieldName - Name of the field (for error messages)\n * @throws {Error} If the string is empty or not a string\n */\nexport function validateNonEmptyString(value: string, fieldName = 'value'): void {\n if (typeof value !== 'string') {\n throw new Error(`${fieldName} must be a string, got ${typeof value}`);\n }\n\n if (value.trim().length === 0) {\n throw new Error(`${fieldName} cannot be empty`);\n }\n}\n\n/**\n * Validates a percentage value (0-100)\n * @param value - The percentage to validate\n * @param fieldName - Name of the field (for error messages)\n * @throws {Error} If the percentage is invalid\n */\nexport function validatePercentage(value: number, fieldName = 'percentage'): void {\n if (!Number.isFinite(value)) {\n throw new Error(`${fieldName} must be a finite number, got ${value}`);\n }\n\n if (value < 0 || value > 100) {\n throw new Error(`${fieldName} must be between 0 and 100, got ${value}`);\n }\n}\n\n/**\n * Validates EMUs (English Metric Units) value\n * Used for image dimensions: 914400 EMUs = 1 inch\n * Reasonable range: 0 to 50 million (about 55 inches)\n * @param value - The EMUs value to validate\n * @param fieldName - Name of the field (for error messages)\n * @throws {Error} If the value is invalid\n */\nexport function validateEmus(value: number, fieldName = 'EMUs'): void {\n if (!Number.isFinite(value)) {\n throw new Error(`${fieldName} must be a finite number, got ${value}`);\n }\n\n if (!Number.isInteger(value)) {\n throw new Error(`${fieldName} must be an integer, got ${value}`);\n }\n\n if (value < 0) {\n throw new Error(`${fieldName} must be non-negative, got ${value}`);\n }\n\n // Reasonable maximum: 50 million EMUs (about 55 inches)\n const MAX_EMUS = 50000000;\n if (value > MAX_EMUS) {\n throw new Error(`${fieldName} exceeds maximum ${MAX_EMUS} (about 55 inches), got ${value}`);\n }\n}\n\n/**\n * Result of text validation for XML-like content\n */\nexport interface TextValidationResult {\n isValid: boolean;\n hasXmlPatterns: boolean;\n warnings: string[];\n cleanedText?: string;\n}\n\n/**\n * Detects XML-like patterns in text that might cause display issues\n *\n * This function checks for patterns that look like XML markup which,\n * when properly escaped in XML output, will display as literal text\n * in Word documents rather than being interpreted as markup.\n *\n * @param text - The text to validate\n * @param context - Optional context for better warning messages (e.g., \"hyperlink text\")\n * @returns Validation result with warnings and optional cleaned text\n */\nexport function detectXmlInText(text: string, context?: string): TextValidationResult {\n const warnings: string[] = [];\n let hasXmlPatterns = false;\n\n // Check for common XML element patterns\n const xmlElementPattern = /<\\/?w:[^>]+>|<w:[^>]+\\/>/g;\n const escapedXmlPattern = /<.*?>|"|'/g;\n\n // Check for specific problematic patterns we've seen\n const problematicPatterns = [\n /<w:t\\s+xml:space=\"preserve\">/,\n /<w:t\\s+xml:space=[\"']preserve[\"']>/,\n /<\\/w:t>/,\n /<w:t\\s+xml:space="preserve">/,\n ];\n\n // Check for any XML-like tags\n if (xmlElementPattern.test(text)) {\n hasXmlPatterns = true;\n const contextStr = context ? ` in ${context}` : '';\n warnings.push(\n `Text${contextStr} contains XML-like markup: \"${text.substring(0, 100)}${text.length > 100 ? '...' : ''}\". ` +\n `This will be displayed as literal text in the document. ` +\n `If you intended to add formatting, use the appropriate API methods instead.`\n );\n }\n\n // Check for already-escaped XML entities\n if (escapedXmlPattern.test(text)) {\n hasXmlPatterns = true;\n const contextStr = context ? ` in ${context}` : '';\n warnings.push(\n `Text${contextStr} contains escaped XML entities (e.g., <, >, "). ` +\n `These will appear as literal characters in the document.`\n );\n }\n\n // Check for specific known problematic patterns\n for (const pattern of problematicPatterns) {\n if (pattern.test(text)) {\n hasXmlPatterns = true;\n const contextStr = context ? ` in ${context}` : '';\n warnings.push(\n `Text${contextStr} contains a known problematic XML pattern that suggests ` +\n `the text may have been corrupted by previous processing.`\n );\n break;\n }\n }\n\n return {\n isValid: true, // Text is always \"valid\" - we just warn about potential issues\n hasXmlPatterns,\n warnings,\n };\n}\n\n/**\n * Cleans XML-like patterns from text\n *\n * This function removes or cleans various XML patterns that might\n * appear in text content, typically from corrupted or improperly\n * processed documents.\n *\n * @param text - The text to clean\n * @param aggressive - If true, removes all angle brackets; if false, only removes clear XML tags\n * @returns Cleaned text with XML patterns removed\n */\nexport function cleanXmlFromText(text: string, aggressive = false): string {\n let cleaned = text;\n\n // First, unescape any HTML/XML entities\n cleaned = cleaned\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/&/g, '&');\n\n // Remove specific Word XML patterns\n // This targets patterns like <w:t xml:space=\"preserve\">\n cleaned = cleaned.replace(/<w:[^>]+>/g, '');\n cleaned = cleaned.replace(/<\\/w:[^>]+>/g, '');\n\n // Remove any remaining XML-like tags if aggressive mode\n if (aggressive) {\n cleaned = cleaned.replace(/<[^>]+>/g, '');\n }\n\n // Clean up any double spaces left behind\n cleaned = cleaned.replace(/\\s+/g, ' ').trim();\n\n return cleaned;\n}\n\n/**\n * Validates text for use in Run or Hyperlink elements\n *\n * This is the main validation function that should be called when\n * setting text content in Run or Hyperlink elements. It provides\n * warnings about problematic content and optionally cleans the text.\n *\n * @param text - The text to validate\n * @param options - Validation options\n * @returns Validation result with warnings and optionally cleaned text\n */\nexport function validateRunText(\n text: string,\n options: {\n context?: string;\n autoClean?: boolean;\n aggressive?: boolean;\n warnToConsole?: boolean;\n } = {}\n): TextValidationResult {\n const { context, autoClean = false, aggressive = false, warnToConsole = true } = options;\n\n // Detect XML patterns\n const result = detectXmlInText(text, context);\n\n // If auto-cleaning is enabled and XML patterns were found\n if (autoClean && result.hasXmlPatterns) {\n result.cleanedText = cleanXmlFromText(text, aggressive);\n\n // Add a note about cleaning\n result.warnings.push(\n `Text has been automatically cleaned. ` +\n `Original: \"${text.substring(0, 50)}${text.length > 50 ? '...' : ''}\" ` +\n `Cleaned: \"${result.cleanedText.substring(0, 50)}${result.cleanedText.length > 50 ? '...' : ''}\"`\n );\n }\n\n // Log warnings to console in development if requested\n if (warnToConsole && result.warnings.length > 0 && typeof console !== 'undefined') {\n const contextStr = context ? ` [${context}]` : '';\n defaultLogger.warn(`DocXML Text Validation Warning${contextStr}:`);\n result.warnings.forEach((warning) => defaultLogger.warn(` - ${warning}`));\n }\n\n return result;\n}\n\n/**\n * Result of URL sanitization\n */\nexport interface SanitizeHyperlinkUrlResult {\n /** The sanitized URL */\n url: string;\n /** List of fixes that were applied */\n fixes: string[];\n}\n\n/**\n * Sanitizes hyperlink URLs by removing browser extension prefixes and fixing\n * broken protocols that result from the stripping.\n *\n * Known corruptions:\n * - Chrome extensions (e.g. Adobe Acrobat) wrap URLs with `chrome-extension://[id]/`\n * - Firefox extensions wrap URLs with `moz-extension://[uuid]/`\n * - Edge extensions wrap URLs with `extension://[id]/`\n * - After stripping, protocol may be broken (`https:/` instead of `https://`)\n *\n * @param url - The URL to sanitize\n * @returns Object with sanitized URL and list of fixes, or null if no changes needed\n */\nexport function sanitizeHyperlinkUrl(url: string): SanitizeHyperlinkUrlResult | null {\n if (!url) return null;\n\n const fixes: string[] = [];\n let sanitized = url;\n\n // Strip known browser extension URL prefixes\n const extensionPrefixes = [\n { pattern: /^chrome-extension:\\/\\/[a-z]{32}\\//i, name: 'Chrome extension' },\n {\n pattern: /^moz-extension:\\/\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\//i,\n name: 'Firefox extension',\n },\n { pattern: /^extension:\\/\\/[a-z0-9]{32}\\//i, name: 'Edge extension' },\n ];\n\n for (const { pattern, name } of extensionPrefixes) {\n const match = pattern.exec(sanitized);\n if (match) {\n sanitized = sanitized.substring(match[0].length);\n fixes.push(`Stripped ${name} URL prefix`);\n break;\n }\n }\n\n // Fix broken protocol after stripping (https:/ -> https://, http:/ -> http://)\n const brokenProtocol = /^(https?:\\/)([^/])/i.exec(sanitized);\n if (brokenProtocol) {\n sanitized =\n brokenProtocol[1] + '/' + brokenProtocol[2] + sanitized.substring(brokenProtocol[0].length);\n fixes.push('Fixed broken protocol (added missing slash)');\n }\n\n if (fixes.length === 0) return null;\n\n return { url: sanitized, fixes };\n}\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getGlobalLogger } from './logger.js';
|
|
2
|
+
const INVALID_XML_CHAR_REGEX = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
|
|
3
|
+
export function removeInvalidXmlChars(text, logWarning = true) {
|
|
4
|
+
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
5
|
+
if (logWarning && INVALID_XML_CHAR_REGEX.test(text)) {
|
|
6
|
+
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
7
|
+
const invalidChars = findInvalidXmlChars(text);
|
|
8
|
+
const hexCodes = invalidChars
|
|
9
|
+
.map((c) => `0x${c.toString(16).toUpperCase().padStart(2, '0')}`)
|
|
10
|
+
.join(', ');
|
|
11
|
+
getGlobalLogger().warn(`[XMLSanitization] Removing invalid XML control characters: ${hexCodes}`);
|
|
12
|
+
}
|
|
13
|
+
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
14
|
+
return text.replace(INVALID_XML_CHAR_REGEX, '');
|
|
15
|
+
}
|
|
16
|
+
export function findInvalidXmlChars(text) {
|
|
17
|
+
const invalid = [];
|
|
18
|
+
for (let i = 0; i < text.length; i++) {
|
|
19
|
+
const code = text.charCodeAt(i);
|
|
20
|
+
if ((code >= 0x00 && code <= 0x08) ||
|
|
21
|
+
(code >= 0x0b && code <= 0x0c) ||
|
|
22
|
+
(code >= 0x0e && code <= 0x1f) ||
|
|
23
|
+
code === 0x7f) {
|
|
24
|
+
if (!invalid.includes(code)) {
|
|
25
|
+
invalid.push(code);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return invalid;
|
|
30
|
+
}
|
|
31
|
+
export function hasInvalidXmlChars(text) {
|
|
32
|
+
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
33
|
+
return INVALID_XML_CHAR_REGEX.test(text);
|
|
34
|
+
}
|
|
35
|
+
export const XML_CONTROL_CHARS = {
|
|
36
|
+
NULL: 0x00,
|
|
37
|
+
SOH: 0x01,
|
|
38
|
+
STX: 0x02,
|
|
39
|
+
ETX: 0x03,
|
|
40
|
+
EOT: 0x04,
|
|
41
|
+
ENQ: 0x05,
|
|
42
|
+
ACK: 0x06,
|
|
43
|
+
BEL: 0x07,
|
|
44
|
+
BS: 0x08,
|
|
45
|
+
TAB: 0x09,
|
|
46
|
+
LF: 0x0a,
|
|
47
|
+
VT: 0x0b,
|
|
48
|
+
FF: 0x0c,
|
|
49
|
+
CR: 0x0d,
|
|
50
|
+
SO: 0x0e,
|
|
51
|
+
US: 0x1f,
|
|
52
|
+
DEL: 0x7f,
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=xmlSanitization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xmlSanitization.js","sourceRoot":"","sources":["../../../src/utils/xmlSanitization.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAO9C,MAAM,sBAAsB,GAAG,mCAAmC,CAAC;AA4BnE,MAAM,UAAU,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,eAAe,EAAE,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,MAAM,UAAU,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,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAE7C,sBAAsB,CAAC,SAAS,GAAG,CAAC,CAAC;IACrC,OAAO,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC;AAKD,MAAM,CAAC,MAAM,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"]}
|