docxmlater 10.0.2 → 10.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 -2
- package/dist/constants/legacyCompatFlags.d.ts.map +1 -1
- package/dist/constants/legacyCompatFlags.js.map +1 -1
- package/dist/constants/limits.d.ts +0 -27
- package/dist/constants/limits.d.ts.map +1 -1
- package/dist/constants/limits.js +13 -13
- package/dist/constants/limits.js.map +1 -1
- package/dist/core/Document.d.ts +23 -19
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +197 -63
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentContent.d.ts.map +1 -1
- package/dist/core/DocumentContent.js.map +1 -1
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +59 -24
- package/dist/core/DocumentGenerator.js.map +1 -1
- package/dist/core/DocumentIdManager.d.ts.map +1 -1
- package/dist/core/DocumentIdManager.js.map +1 -1
- package/dist/core/DocumentParser.d.ts +6 -6
- package/dist/core/DocumentParser.d.ts.map +1 -1
- package/dist/core/DocumentParser.js +86 -55
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/DocumentValidator.d.ts.map +1 -1
- package/dist/core/DocumentValidator.js.map +1 -1
- package/dist/core/Relationship.d.ts.map +1 -1
- package/dist/core/Relationship.js +1 -1
- package/dist/core/Relationship.js.map +1 -1
- package/dist/core/RelationshipManager.js +3 -3
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/AlternateContent.js.map +1 -1
- package/dist/elements/Bookmark.d.ts.map +1 -1
- package/dist/elements/Bookmark.js.map +1 -1
- package/dist/elements/BookmarkManager.d.ts.map +1 -1
- package/dist/elements/BookmarkManager.js.map +1 -1
- package/dist/elements/Comment.js +1 -1
- package/dist/elements/Comment.js.map +1 -1
- package/dist/elements/CommentManager.d.ts.map +1 -1
- package/dist/elements/CommentManager.js +8 -2
- package/dist/elements/CommentManager.js.map +1 -1
- package/dist/elements/CommonTypes.d.ts.map +1 -1
- package/dist/elements/CommonTypes.js +1 -2
- package/dist/elements/CommonTypes.js.map +1 -1
- package/dist/elements/CustomXml.js.map +1 -1
- package/dist/elements/Endnote.d.ts.map +1 -1
- package/dist/elements/Endnote.js.map +1 -1
- package/dist/elements/EndnoteManager.d.ts.map +1 -1
- package/dist/elements/EndnoteManager.js.map +1 -1
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +31 -28
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/FieldHelpers.d.ts.map +1 -1
- package/dist/elements/FieldHelpers.js +6 -6
- package/dist/elements/FieldHelpers.js.map +1 -1
- package/dist/elements/FontManager.d.ts.map +1 -1
- package/dist/elements/FontManager.js.map +1 -1
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/Footnote.d.ts.map +1 -1
- package/dist/elements/Footnote.js.map +1 -1
- package/dist/elements/FootnoteManager.d.ts.map +1 -1
- package/dist/elements/FootnoteManager.js.map +1 -1
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/HeaderFooterManager.js.map +1 -1
- package/dist/elements/Hyperlink.d.ts.map +1 -1
- package/dist/elements/Hyperlink.js +5 -5
- package/dist/elements/Hyperlink.js.map +1 -1
- package/dist/elements/Image.d.ts +2 -2
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +21 -5
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/ImageManager.d.ts.map +1 -1
- package/dist/elements/ImageManager.js +2 -2
- package/dist/elements/ImageManager.js.map +1 -1
- package/dist/elements/ImageRun.js.map +1 -1
- package/dist/elements/MathElement.js.map +1 -1
- package/dist/elements/Paragraph.d.ts +8 -0
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +153 -118
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/PreservedElement.js.map +1 -1
- package/dist/elements/PropertyChangeTypes.js.map +1 -1
- package/dist/elements/RangeMarker.js.map +1 -1
- package/dist/elements/Revision.d.ts +1 -0
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +44 -5
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/RevisionContent.js.map +1 -1
- package/dist/elements/RevisionManager.d.ts.map +1 -1
- package/dist/elements/RevisionManager.js.map +1 -1
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +1 -3
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +127 -118
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.d.ts.map +1 -1
- package/dist/elements/Shape.js +21 -0
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
- package/dist/elements/StructuredDocumentTag.js +20 -8
- package/dist/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/elements/Table.d.ts +2 -2
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +29 -35
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +2 -2
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +63 -67
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableGridChange.js.map +1 -1
- package/dist/elements/TableOfContents.d.ts +6 -6
- package/dist/elements/TableOfContents.d.ts.map +1 -1
- package/dist/elements/TableOfContents.js.map +1 -1
- package/dist/elements/TableOfContentsElement.js.map +1 -1
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +65 -47
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/elements/TextBox.d.ts.map +1 -1
- package/dist/elements/TextBox.js +1 -1
- package/dist/elements/TextBox.js.map +1 -1
- package/dist/formatting/AbstractNumbering.d.ts +1 -1
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +11 -11
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingInstance.d.ts.map +1 -1
- package/dist/formatting/NumberingInstance.js +4 -4
- package/dist/formatting/NumberingInstance.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +26 -26
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/NumberingManager.d.ts +1 -1
- package/dist/formatting/NumberingManager.d.ts.map +1 -1
- package/dist/formatting/NumberingManager.js.map +1 -1
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +87 -95
- package/dist/formatting/Style.js.map +1 -1
- package/dist/formatting/StylesManager.d.ts +3 -3
- package/dist/formatting/StylesManager.d.ts.map +1 -1
- package/dist/formatting/StylesManager.js.map +1 -1
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/images/ImageOptimizer.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/managers/DrawingManager.d.ts.map +1 -1
- package/dist/managers/DrawingManager.js.map +1 -1
- package/dist/tracking/DocumentTrackingContext.js.map +1 -1
- package/dist/tracking/TrackingContext.js.map +1 -1
- package/dist/types/compatibility-types.js.map +1 -1
- package/dist/types/formatting.js.map +1 -1
- package/dist/types/list-types.d.ts +4 -4
- package/dist/types/list-types.d.ts.map +1 -1
- package/dist/types/list-types.js.map +1 -1
- package/dist/types/settings-types.js.map +1 -1
- package/dist/types/styleConfig.js.map +1 -1
- package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
- package/dist/utils/ChangelogGenerator.js.map +1 -1
- package/dist/utils/CompatibilityUpgrader.d.ts.map +1 -1
- package/dist/utils/CompatibilityUpgrader.js +7 -7
- package/dist/utils/CompatibilityUpgrader.js.map +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.d.ts.map +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.js +23 -2
- package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/utils/MoveOperationHelper.js.map +1 -1
- package/dist/utils/RevisionAwareProcessor.js.map +1 -1
- package/dist/utils/RevisionWalker.js.map +1 -1
- package/dist/utils/SelectiveRevisionAcceptor.d.ts +1 -0
- package/dist/utils/SelectiveRevisionAcceptor.d.ts.map +1 -1
- package/dist/utils/SelectiveRevisionAcceptor.js +46 -0
- package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/utils/ShadingResolver.js +1 -1
- package/dist/utils/ShadingResolver.js.map +1 -1
- package/dist/utils/acceptRevisions.d.ts +0 -28
- package/dist/utils/acceptRevisions.d.ts.map +1 -1
- package/dist/utils/acceptRevisions.js +5 -7
- package/dist/utils/acceptRevisions.js.map +1 -1
- package/dist/utils/cnfStyleDecoder.js +1 -1
- package/dist/utils/cnfStyleDecoder.js.map +1 -1
- package/dist/utils/corruptionDetection.js.map +1 -1
- package/dist/utils/dateFormatting.js.map +1 -1
- package/dist/utils/deepClone.d.ts +0 -1
- package/dist/utils/deepClone.d.ts.map +1 -1
- package/dist/utils/deepClone.js +0 -7
- package/dist/utils/deepClone.js.map +1 -1
- package/dist/utils/diagnostics.d.ts +2 -2
- package/dist/utils/diagnostics.d.ts.map +1 -1
- package/dist/utils/diagnostics.js.map +1 -1
- package/dist/utils/errorHandling.js.map +1 -1
- package/dist/utils/formatting.js.map +1 -1
- package/dist/utils/list-detection.d.ts +2 -2
- package/dist/utils/list-detection.d.ts.map +1 -1
- package/dist/utils/list-detection.js +3 -3
- package/dist/utils/list-detection.js.map +1 -1
- package/dist/utils/logger.d.ts +2 -4
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +0 -2
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/parsingHelpers.js.map +1 -1
- package/dist/utils/stripTrackedChanges.d.ts +0 -19
- package/dist/utils/stripTrackedChanges.d.ts.map +1 -1
- package/dist/utils/stripTrackedChanges.js +0 -2
- package/dist/utils/stripTrackedChanges.js.map +1 -1
- package/dist/utils/textDiff.js.map +1 -1
- package/dist/utils/units.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/xmlSanitization.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/validation/RevisionValidator.js.map +1 -1
- package/dist/validation/ValidationRules.js.map +1 -1
- package/dist/validation/index.js.map +1 -1
- package/dist/xml/XMLBuilder.d.ts.map +1 -1
- package/dist/xml/XMLBuilder.js +10 -0
- package/dist/xml/XMLBuilder.js.map +1 -1
- package/dist/xml/XMLParser.d.ts.map +1 -1
- package/dist/xml/XMLParser.js +4 -5
- package/dist/xml/XMLParser.js.map +1 -1
- package/dist/zip/ZipHandler.js.map +1 -1
- package/dist/zip/ZipReader.js.map +1 -1
- package/dist/zip/ZipWriter.js.map +1 -1
- package/dist/zip/errors.js.map +1 -1
- package/dist/zip/types.js.map +1 -1
- package/package.json +34 -4
- package/src/__tests__/helper-methods.test.ts +512 -0
- package/src/constants/legacyCompatFlags.ts +138 -0
- package/src/constants/limits.ts +50 -0
- package/src/core/CLAUDE.md +109 -0
- package/src/core/Document.ts +15569 -0
- package/src/core/DocumentContent.ts +467 -0
- package/src/core/DocumentGenerator.ts +1104 -0
- package/src/core/DocumentIdManager.ts +158 -0
- package/src/core/DocumentParser.ts +10140 -0
- package/src/core/DocumentValidator.ts +372 -0
- package/src/core/Relationship.ts +367 -0
- package/src/core/RelationshipManager.ts +428 -0
- package/src/elements/AlternateContent.ts +42 -0
- package/src/elements/Bookmark.ts +210 -0
- package/src/elements/BookmarkManager.ts +250 -0
- package/src/elements/CLAUDE.md +126 -0
- package/src/elements/Comment.ts +359 -0
- package/src/elements/CommentManager.ts +502 -0
- package/src/elements/CommonTypes.ts +549 -0
- package/src/elements/CustomXml.ts +36 -0
- package/src/elements/Endnote.ts +217 -0
- package/src/elements/EndnoteManager.ts +249 -0
- package/src/elements/Field.ts +1233 -0
- package/src/elements/FieldHelpers.ts +333 -0
- package/src/elements/FontManager.ts +339 -0
- package/src/elements/Footer.ts +269 -0
- package/src/elements/Footnote.ts +217 -0
- package/src/elements/FootnoteManager.ts +249 -0
- package/src/elements/Header.ts +269 -0
- package/src/elements/HeaderFooterManager.ts +219 -0
- package/src/elements/Hyperlink.ts +1146 -0
- package/src/elements/Image.ts +1756 -0
- package/src/elements/ImageManager.ts +432 -0
- package/src/elements/ImageRun.ts +59 -0
- package/src/elements/MathElement.ts +65 -0
- package/src/elements/Paragraph.ts +4287 -0
- package/src/elements/PreservedElement.ts +53 -0
- package/src/elements/PropertyChangeTypes.ts +442 -0
- package/src/elements/RangeMarker.ts +400 -0
- package/src/elements/Revision.ts +1217 -0
- package/src/elements/RevisionContent.ts +73 -0
- package/src/elements/RevisionManager.ts +1070 -0
- package/src/elements/Run.ts +3068 -0
- package/src/elements/Section.ts +1421 -0
- package/src/elements/Shape.ts +873 -0
- package/src/elements/StructuredDocumentTag.ts +978 -0
- package/src/elements/Table.ts +2524 -0
- package/src/elements/TableCell.ts +1586 -0
- package/src/elements/TableGridChange.ts +151 -0
- package/src/elements/TableOfContents.ts +691 -0
- package/src/elements/TableOfContentsElement.ts +89 -0
- package/src/elements/TableRow.ts +906 -0
- package/src/elements/TextBox.ts +768 -0
- package/src/formatting/AbstractNumbering.ts +548 -0
- package/src/formatting/CLAUDE.md +74 -0
- package/src/formatting/NumberingInstance.ts +212 -0
- package/src/formatting/NumberingLevel.ts +1006 -0
- package/src/formatting/NumberingManager.ts +827 -0
- package/src/formatting/Style.ts +1833 -0
- package/src/formatting/StylesManager.ts +1005 -0
- package/src/helpers/CleanupHelper.ts +524 -0
- package/src/images/ImageOptimizer.ts +274 -0
- package/src/index.ts +554 -0
- package/src/managers/CLAUDE.md +47 -0
- package/src/managers/DrawingManager.ts +319 -0
- package/src/tracking/DocumentTrackingContext.ts +643 -0
- package/src/tracking/TrackingContext.ts +173 -0
- package/src/types/compatibility-types.ts +49 -0
- package/src/types/formatting.ts +210 -0
- package/src/types/list-types.ts +152 -0
- package/src/types/settings-types.ts +59 -0
- package/src/types/styleConfig.ts +189 -0
- package/src/utils/CLAUDE.md +153 -0
- package/src/utils/ChangelogGenerator.ts +1581 -0
- package/src/utils/CompatibilityUpgrader.ts +237 -0
- package/src/utils/InMemoryRevisionAcceptor.ts +696 -0
- package/src/utils/MoveOperationHelper.ts +238 -0
- package/src/utils/RevisionAwareProcessor.ts +526 -0
- package/src/utils/RevisionWalker.ts +457 -0
- package/src/utils/SelectiveRevisionAcceptor.ts +683 -0
- package/src/utils/ShadingResolver.ts +107 -0
- package/src/utils/acceptRevisions.ts +714 -0
- package/src/utils/cnfStyleDecoder.ts +217 -0
- package/src/utils/corruptionDetection.ts +345 -0
- package/src/utils/dateFormatting.ts +20 -0
- package/src/utils/deepClone.ts +78 -0
- package/src/utils/diagnostics.ts +129 -0
- package/src/utils/errorHandling.ts +80 -0
- package/src/utils/formatting.ts +213 -0
- package/src/utils/list-detection.ts +274 -0
- package/src/utils/logger.ts +404 -0
- package/src/utils/parsingHelpers.ts +190 -0
- package/src/utils/stripTrackedChanges.ts +353 -0
- package/src/utils/textDiff.ts +100 -0
- package/src/utils/units.ts +421 -0
- package/src/utils/validation.ts +542 -0
- package/src/utils/xmlSanitization.ts +182 -0
- package/src/validation/RevisionAutoFixer.ts +542 -0
- package/src/validation/RevisionValidator.ts +460 -0
- package/src/validation/ValidationRules.ts +338 -0
- package/src/validation/index.ts +30 -0
- package/src/xml/CLAUDE.md +65 -0
- package/src/xml/XMLBuilder.ts +871 -0
- package/src/xml/XMLParser.ts +919 -0
- package/src/zip/CLAUDE.md +55 -0
- package/src/zip/ZipHandler.ts +637 -0
- package/src/zip/ZipReader.ts +299 -0
- package/src/zip/ZipWriter.ts +390 -0
- package/src/zip/errors.ts +69 -0
- package/src/zip/types.ts +116 -0
- package/dist/core/ListNormalizer.d.ts +0 -23
- package/dist/core/ListNormalizer.d.ts.map +0 -1
- package/dist/core/ListNormalizer.js +0 -624
- package/dist/core/ListNormalizer.js.map +0 -1
- package/dist/images/index.d.ts +0 -2
- package/dist/images/index.d.ts.map +0 -1
- package/dist/images/index.js +0 -8
- package/dist/images/index.js.map +0 -1
- package/dist/ms-doc/cfb/CFBReader.d.ts +0 -35
- package/dist/ms-doc/cfb/CFBReader.d.ts.map +0 -1
- package/dist/ms-doc/cfb/CFBReader.js +0 -360
- package/dist/ms-doc/cfb/CFBReader.js.map +0 -1
- package/dist/ms-doc/converter/DocToDocxConverter.d.ts +0 -55
- package/dist/ms-doc/converter/DocToDocxConverter.d.ts.map +0 -1
- package/dist/ms-doc/converter/DocToDocxConverter.js +0 -324
- package/dist/ms-doc/converter/DocToDocxConverter.js.map +0 -1
- package/dist/ms-doc/fib/FIB.d.ts +0 -18
- package/dist/ms-doc/fib/FIB.d.ts.map +0 -1
- package/dist/ms-doc/fib/FIB.js +0 -342
- package/dist/ms-doc/fib/FIB.js.map +0 -1
- package/dist/ms-doc/fields/FieldParser.d.ts +0 -31
- package/dist/ms-doc/fields/FieldParser.d.ts.map +0 -1
- package/dist/ms-doc/fields/FieldParser.js +0 -266
- package/dist/ms-doc/fields/FieldParser.js.map +0 -1
- package/dist/ms-doc/images/PictureExtractor.d.ts +0 -22
- package/dist/ms-doc/images/PictureExtractor.d.ts.map +0 -1
- package/dist/ms-doc/images/PictureExtractor.js +0 -233
- package/dist/ms-doc/images/PictureExtractor.js.map +0 -1
- package/dist/ms-doc/index.d.ts +0 -20
- package/dist/ms-doc/index.d.ts.map +0 -1
- package/dist/ms-doc/index.js +0 -59
- package/dist/ms-doc/index.js.map +0 -1
- package/dist/ms-doc/properties/SPRM.d.ts +0 -210
- package/dist/ms-doc/properties/SPRM.d.ts.map +0 -1
- package/dist/ms-doc/properties/SPRM.js +0 -633
- package/dist/ms-doc/properties/SPRM.js.map +0 -1
- package/dist/ms-doc/sections/SectionParser.d.ts +0 -25
- package/dist/ms-doc/sections/SectionParser.d.ts.map +0 -1
- package/dist/ms-doc/sections/SectionParser.js +0 -214
- package/dist/ms-doc/sections/SectionParser.js.map +0 -1
- package/dist/ms-doc/styles/StyleSheet.d.ts +0 -23
- package/dist/ms-doc/styles/StyleSheet.d.ts.map +0 -1
- package/dist/ms-doc/styles/StyleSheet.js +0 -268
- package/dist/ms-doc/styles/StyleSheet.js.map +0 -1
- package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts +0 -61
- package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts.map +0 -1
- package/dist/ms-doc/subdocuments/SubdocumentParser.js +0 -208
- package/dist/ms-doc/subdocuments/SubdocumentParser.js.map +0 -1
- package/dist/ms-doc/tables/TableParser.d.ts +0 -29
- package/dist/ms-doc/tables/TableParser.d.ts.map +0 -1
- package/dist/ms-doc/tables/TableParser.js +0 -176
- package/dist/ms-doc/tables/TableParser.js.map +0 -1
- package/dist/ms-doc/text/PieceTable.d.ts +0 -21
- package/dist/ms-doc/text/PieceTable.d.ts.map +0 -1
- package/dist/ms-doc/text/PieceTable.js +0 -171
- package/dist/ms-doc/text/PieceTable.js.map +0 -1
- package/dist/ms-doc/types/Constants.d.ts +0 -99
- package/dist/ms-doc/types/Constants.d.ts.map +0 -1
- package/dist/ms-doc/types/Constants.js +0 -102
- package/dist/ms-doc/types/Constants.js.map +0 -1
- package/dist/ms-doc/types/DocTypes.d.ts +0 -368
- package/dist/ms-doc/types/DocTypes.d.ts.map +0 -1
- package/dist/ms-doc/types/DocTypes.js +0 -3
- package/dist/ms-doc/types/DocTypes.js.map +0 -1
- package/dist/tracking/index.d.ts +0 -3
- package/dist/tracking/index.d.ts.map +0 -1
- package/dist/tracking/index.js +0 -6
- package/dist/tracking/index.js.map +0 -1
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging interface for docXMLater
|
|
3
|
+
* Allows library consumers to control logging behavior
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Log severity levels
|
|
8
|
+
*/
|
|
9
|
+
export enum LogLevel {
|
|
10
|
+
/** Debugging information (most verbose) */
|
|
11
|
+
DEBUG = 'debug',
|
|
12
|
+
/** Informational messages */
|
|
13
|
+
INFO = 'info',
|
|
14
|
+
/** Warning messages - potential issues that don't prevent operation */
|
|
15
|
+
WARN = 'warn',
|
|
16
|
+
/** Error messages - serious issues that may cause failures */
|
|
17
|
+
ERROR = 'error',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Log entry structure
|
|
22
|
+
*/
|
|
23
|
+
export interface LogEntry {
|
|
24
|
+
/** Timestamp when log was created */
|
|
25
|
+
timestamp: Date;
|
|
26
|
+
/** Severity level */
|
|
27
|
+
level: LogLevel;
|
|
28
|
+
/** Log message */
|
|
29
|
+
message: string;
|
|
30
|
+
/** Optional context data */
|
|
31
|
+
context?: Record<string, any>;
|
|
32
|
+
/** Source component that generated the log */
|
|
33
|
+
source?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Logger interface that consumers can implement
|
|
38
|
+
* Provides full control over how logs are handled
|
|
39
|
+
*/
|
|
40
|
+
export interface ILogger {
|
|
41
|
+
/**
|
|
42
|
+
* Log a debug message
|
|
43
|
+
* @param message - Debug message
|
|
44
|
+
* @param context - Optional context data
|
|
45
|
+
*/
|
|
46
|
+
debug(message: string, context?: Record<string, any>): void;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Log an informational message
|
|
50
|
+
* @param message - Info message
|
|
51
|
+
* @param context - Optional context data
|
|
52
|
+
*/
|
|
53
|
+
info(message: string, context?: Record<string, any>): void;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Log a warning message
|
|
57
|
+
* @param message - Warning message
|
|
58
|
+
* @param context - Optional context data
|
|
59
|
+
*/
|
|
60
|
+
warn(message: string, context?: Record<string, any>): void;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Log an error message
|
|
64
|
+
* @param message - Error message
|
|
65
|
+
* @param context - Optional context data
|
|
66
|
+
*/
|
|
67
|
+
error(message: string, context?: Record<string, any>): void;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Console-based logger implementation
|
|
72
|
+
* Uses standard console methods for output with timestamps and source prefixes
|
|
73
|
+
*/
|
|
74
|
+
export class ConsoleLogger implements ILogger {
|
|
75
|
+
private showTimestamp: boolean;
|
|
76
|
+
|
|
77
|
+
constructor(private minLevel: LogLevel = LogLevel.WARN, options?: { showTimestamp?: boolean }) {
|
|
78
|
+
this.showTimestamp = options?.showTimestamp ?? true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
debug(message: string, context?: Record<string, any>): void {
|
|
82
|
+
if (this.shouldLog(LogLevel.DEBUG)) {
|
|
83
|
+
console.debug(this.formatMessage(LogLevel.DEBUG, message, context));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
info(message: string, context?: Record<string, any>): void {
|
|
88
|
+
if (this.shouldLog(LogLevel.INFO)) {
|
|
89
|
+
console.info(this.formatMessage(LogLevel.INFO, message, context));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
warn(message: string, context?: Record<string, any>): void {
|
|
94
|
+
if (this.shouldLog(LogLevel.WARN)) {
|
|
95
|
+
console.warn(this.formatMessage(LogLevel.WARN, message, context));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
error(message: string, context?: Record<string, any>): void {
|
|
100
|
+
if (this.shouldLog(LogLevel.ERROR)) {
|
|
101
|
+
console.error(this.formatMessage(LogLevel.ERROR, message, context));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private shouldLog(level: LogLevel): boolean {
|
|
106
|
+
const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR];
|
|
107
|
+
const minIndex = levels.indexOf(this.minLevel);
|
|
108
|
+
const currentIndex = levels.indexOf(level);
|
|
109
|
+
return currentIndex >= minIndex;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private formatMessage(level: LogLevel, message: string, context?: Record<string, any>): string {
|
|
113
|
+
const parts: string[] = [];
|
|
114
|
+
|
|
115
|
+
// Add timestamp if enabled
|
|
116
|
+
if (this.showTimestamp) {
|
|
117
|
+
const timestamp = new Date().toISOString().slice(11, 23); // HH:mm:ss.SSS
|
|
118
|
+
parts.push(timestamp);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Add level tag
|
|
122
|
+
parts.push(`[${level.toUpperCase().padEnd(5)}]`);
|
|
123
|
+
|
|
124
|
+
// Add source if present
|
|
125
|
+
if (context?.source) {
|
|
126
|
+
parts.push(`[${context.source}]`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Add message
|
|
130
|
+
parts.push(message);
|
|
131
|
+
|
|
132
|
+
// Add context (excluding source which is already shown)
|
|
133
|
+
if (context && Object.keys(context).length > 0) {
|
|
134
|
+
const contextWithoutSource = { ...context };
|
|
135
|
+
delete contextWithoutSource.source;
|
|
136
|
+
if (Object.keys(contextWithoutSource).length > 0) {
|
|
137
|
+
// Format context as key=value pairs for readability
|
|
138
|
+
const contextStr = this.formatContext(contextWithoutSource);
|
|
139
|
+
if (contextStr) {
|
|
140
|
+
parts.push(contextStr);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return parts.join(' ');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private formatContext(context: Record<string, any>): string {
|
|
149
|
+
const pairs: string[] = [];
|
|
150
|
+
for (const [key, value] of Object.entries(context)) {
|
|
151
|
+
if (value === undefined || value === null) continue;
|
|
152
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
153
|
+
// Nested object - use compact JSON
|
|
154
|
+
pairs.push(`${key}=${JSON.stringify(value)}`);
|
|
155
|
+
} else if (Array.isArray(value)) {
|
|
156
|
+
pairs.push(`${key}=[${value.length}]`);
|
|
157
|
+
} else {
|
|
158
|
+
pairs.push(`${key}=${value}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return pairs.length > 0 ? pairs.join(' ') : '';
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Silent logger that discards all log messages
|
|
167
|
+
* Useful for testing or when logging is not desired
|
|
168
|
+
*/
|
|
169
|
+
export class SilentLogger implements ILogger {
|
|
170
|
+
debug(): void {
|
|
171
|
+
// No-op
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
info(): void {
|
|
175
|
+
// No-op
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
warn(): void {
|
|
179
|
+
// No-op
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
error(): void {
|
|
183
|
+
// No-op
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Collecting logger that stores log entries in memory
|
|
189
|
+
* Useful for testing and diagnostics
|
|
190
|
+
*/
|
|
191
|
+
export class CollectingLogger implements ILogger {
|
|
192
|
+
private logs: LogEntry[] = [];
|
|
193
|
+
|
|
194
|
+
debug(message: string, context?: Record<string, any>): void {
|
|
195
|
+
this.addLog(LogLevel.DEBUG, message, context);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
info(message: string, context?: Record<string, any>): void {
|
|
199
|
+
this.addLog(LogLevel.INFO, message, context);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
warn(message: string, context?: Record<string, any>): void {
|
|
203
|
+
this.addLog(LogLevel.WARN, message, context);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
error(message: string, context?: Record<string, any>): void {
|
|
207
|
+
this.addLog(LogLevel.ERROR, message, context);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private addLog(level: LogLevel, message: string, context?: Record<string, any>): void {
|
|
211
|
+
this.logs.push({
|
|
212
|
+
timestamp: new Date(),
|
|
213
|
+
level,
|
|
214
|
+
message,
|
|
215
|
+
context,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get all collected log entries
|
|
221
|
+
*/
|
|
222
|
+
getLogs(): readonly LogEntry[] {
|
|
223
|
+
return [...this.logs];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get logs filtered by level
|
|
228
|
+
*/
|
|
229
|
+
getLogsByLevel(level: LogLevel): readonly LogEntry[] {
|
|
230
|
+
return this.logs.filter(log => log.level === level);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Clear all collected logs
|
|
235
|
+
*/
|
|
236
|
+
clear(): void {
|
|
237
|
+
this.logs = [];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Get count of logs by level
|
|
242
|
+
*/
|
|
243
|
+
getCount(level?: LogLevel): number {
|
|
244
|
+
if (level) {
|
|
245
|
+
return this.logs.filter(log => log.level === level).length;
|
|
246
|
+
}
|
|
247
|
+
return this.logs.length;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Default logger instance
|
|
253
|
+
* Delegates to the global logger, respecting setGlobalLogger() and environment variables
|
|
254
|
+
*/
|
|
255
|
+
export const defaultLogger: ILogger = {
|
|
256
|
+
debug(message: string, context?: Record<string, any>): void {
|
|
257
|
+
getGlobalLogger().debug(message, context);
|
|
258
|
+
},
|
|
259
|
+
info(message: string, context?: Record<string, any>): void {
|
|
260
|
+
getGlobalLogger().info(message, context);
|
|
261
|
+
},
|
|
262
|
+
warn(message: string, context?: Record<string, any>): void {
|
|
263
|
+
getGlobalLogger().warn(message, context);
|
|
264
|
+
},
|
|
265
|
+
error(message: string, context?: Record<string, any>): void {
|
|
266
|
+
getGlobalLogger().error(message, context);
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Creates a scoped logger that adds source information
|
|
272
|
+
* @param logger - Base logger
|
|
273
|
+
* @param source - Source component name
|
|
274
|
+
* @returns Scoped logger with source context
|
|
275
|
+
*/
|
|
276
|
+
export function createScopedLogger(logger: ILogger, source: string): ILogger {
|
|
277
|
+
return {
|
|
278
|
+
debug(message: string, context?: Record<string, any>): void {
|
|
279
|
+
logger.debug(message, { ...context, source });
|
|
280
|
+
},
|
|
281
|
+
info(message: string, context?: Record<string, any>): void {
|
|
282
|
+
logger.info(message, { ...context, source });
|
|
283
|
+
},
|
|
284
|
+
warn(message: string, context?: Record<string, any>): void {
|
|
285
|
+
logger.warn(message, { ...context, source });
|
|
286
|
+
},
|
|
287
|
+
error(message: string, context?: Record<string, any>): void {
|
|
288
|
+
logger.error(message, { ...context, source });
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Parse log level from string
|
|
295
|
+
* @param level - Log level string (case-insensitive)
|
|
296
|
+
* @returns LogLevel or undefined if invalid
|
|
297
|
+
*/
|
|
298
|
+
function parseLogLevel(level: string | undefined): LogLevel | undefined {
|
|
299
|
+
if (!level) return undefined;
|
|
300
|
+
const normalized = level.toLowerCase();
|
|
301
|
+
switch (normalized) {
|
|
302
|
+
case 'debug': return LogLevel.DEBUG;
|
|
303
|
+
case 'info': return LogLevel.INFO;
|
|
304
|
+
case 'warn': return LogLevel.WARN;
|
|
305
|
+
case 'error': return LogLevel.ERROR;
|
|
306
|
+
default: return undefined;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Create a logger based on environment variables
|
|
312
|
+
*
|
|
313
|
+
* Environment variables (in order of precedence):
|
|
314
|
+
* - DEBUG=docxmlater or DEBUG=docxmlater:* - Enables DEBUG level
|
|
315
|
+
* - DOCXMLATER_LOG_LEVEL=debug|info|warn|error|silent - Sets specific level
|
|
316
|
+
*
|
|
317
|
+
* @returns Logger configured from environment, or SilentLogger if not configured
|
|
318
|
+
*/
|
|
319
|
+
function createLoggerFromEnv(): ILogger {
|
|
320
|
+
// Check DEBUG environment variable first (highest precedence for debug mode)
|
|
321
|
+
const debugEnv = process.env.DEBUG || '';
|
|
322
|
+
if (debugEnv.includes('docxmlater')) {
|
|
323
|
+
return new ConsoleLogger(LogLevel.DEBUG);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Check DOCXMLATER_LOG_LEVEL environment variable
|
|
327
|
+
const envLevel = process.env.DOCXMLATER_LOG_LEVEL?.toLowerCase();
|
|
328
|
+
if (envLevel === 'silent') {
|
|
329
|
+
return new SilentLogger();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const parsedLevel = parseLogLevel(envLevel);
|
|
333
|
+
if (parsedLevel) {
|
|
334
|
+
return new ConsoleLogger(parsedLevel);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Default: silent (no logging unless explicitly enabled)
|
|
338
|
+
return new SilentLogger();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Global logger instance - initialized from environment
|
|
342
|
+
let globalLogger: ILogger = createLoggerFromEnv();
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Set the global logger instance
|
|
346
|
+
* Use this to configure logging programmatically
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```typescript
|
|
350
|
+
* import { setGlobalLogger, ConsoleLogger, LogLevel } from 'docxmlater';
|
|
351
|
+
*
|
|
352
|
+
* // Enable info-level logging
|
|
353
|
+
* setGlobalLogger(new ConsoleLogger(LogLevel.INFO));
|
|
354
|
+
* ```
|
|
355
|
+
*
|
|
356
|
+
* @param logger - Logger instance to use globally
|
|
357
|
+
*/
|
|
358
|
+
export function setGlobalLogger(logger: ILogger): void {
|
|
359
|
+
globalLogger = logger;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Get the global logger instance
|
|
364
|
+
* Used internally by framework components
|
|
365
|
+
*
|
|
366
|
+
* @returns Current global logger
|
|
367
|
+
*/
|
|
368
|
+
export function getGlobalLogger(): ILogger {
|
|
369
|
+
return globalLogger;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Reset the global logger to its default (environment-based) configuration
|
|
374
|
+
* Useful for testing cleanup
|
|
375
|
+
*/
|
|
376
|
+
export function resetGlobalLogger(): void {
|
|
377
|
+
globalLogger = createLoggerFromEnv();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Creates a component-scoped logger using the global logger.
|
|
382
|
+
* This is a convenience function that combines getGlobalLogger() and createScopedLogger()
|
|
383
|
+
* into a single call, reducing boilerplate in component files.
|
|
384
|
+
*
|
|
385
|
+
* @param componentName - Name of the component (appears in log output)
|
|
386
|
+
* @returns Scoped logger instance
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```typescript
|
|
390
|
+
* // Instead of:
|
|
391
|
+
* function getLogger(): ILogger {
|
|
392
|
+
* return createScopedLogger(getGlobalLogger(), 'MyComponent');
|
|
393
|
+
* }
|
|
394
|
+
*
|
|
395
|
+
* // You can use:
|
|
396
|
+
* const logger = createComponentLogger('MyComponent');
|
|
397
|
+
*
|
|
398
|
+
* // Or for lazy initialization:
|
|
399
|
+
* const getLogger = () => createComponentLogger('MyComponent');
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
export function createComponentLogger(componentName: string): ILogger {
|
|
403
|
+
return createScopedLogger(getGlobalLogger(), componentName);
|
|
404
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsing Helper Functions
|
|
3
|
+
*
|
|
4
|
+
* Utility functions for safely parsing OOXML values from XML attributes.
|
|
5
|
+
* These helpers address common parsing issues:
|
|
6
|
+
* - Zero-value handling (0 should not be treated as falsy)
|
|
7
|
+
* - NaN validation (malformed values should fall back to defaults)
|
|
8
|
+
* - ECMA-376 boolean parsing (self-closing tags, val="1", val="true")
|
|
9
|
+
*
|
|
10
|
+
* @see https://ecma-international.org/publications-and-standards/standards/ecma-376/
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Safely parse an integer value with NaN handling.
|
|
15
|
+
*
|
|
16
|
+
* Addresses the issue where parseInt() can return NaN for malformed input,
|
|
17
|
+
* which then propagates through the document model causing issues.
|
|
18
|
+
*
|
|
19
|
+
* @param value - The value to parse (string, number, or any)
|
|
20
|
+
* @param defaultValue - Default value if parsing fails (default: 0)
|
|
21
|
+
* @returns Parsed integer or default value
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* safeParseInt("42") // 42
|
|
25
|
+
* safeParseInt("invalid") // 0
|
|
26
|
+
* safeParseInt(undefined) // 0
|
|
27
|
+
* safeParseInt("", 100) // 100
|
|
28
|
+
*/
|
|
29
|
+
export function safeParseInt(value: unknown, defaultValue = 0): number {
|
|
30
|
+
if (value === undefined || value === null) {
|
|
31
|
+
return defaultValue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// If already a number, return it (handle NaN case)
|
|
35
|
+
if (typeof value === 'number') {
|
|
36
|
+
return isNaN(value) ? defaultValue : Math.floor(value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const parsed = parseInt(String(value), 10);
|
|
40
|
+
return isNaN(parsed) ? defaultValue : parsed;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Parse OOXML boolean value per ECMA-376 specification.
|
|
45
|
+
*
|
|
46
|
+
* OOXML boolean properties follow these rules:
|
|
47
|
+
* - Self-closing tag `<w:bold/>` (no w:val attribute) = true
|
|
48
|
+
* - `<w:bold w:val="1"/>` = true
|
|
49
|
+
* - `<w:bold w:val="true"/>` = true
|
|
50
|
+
* - `<w:bold w:val="on"/>` = true
|
|
51
|
+
* - `<w:bold w:val="0"/>` = false
|
|
52
|
+
* - `<w:bold w:val="false"/>` = false
|
|
53
|
+
* - `<w:bold w:val="off"/>` = false
|
|
54
|
+
* - Absent element = false (handled by caller checking for property existence)
|
|
55
|
+
*
|
|
56
|
+
* @param prop - The parsed XML property object (e.g., pPrObj["w:bold"])
|
|
57
|
+
* @returns Boolean value
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* // For XML: <w:bold/>
|
|
61
|
+
* parseOoxmlBoolean({}) // true (self-closing, no @_w:val)
|
|
62
|
+
*
|
|
63
|
+
* // For XML: <w:bold w:val="1"/>
|
|
64
|
+
* parseOoxmlBoolean({ "@_w:val": "1" }) // true
|
|
65
|
+
*
|
|
66
|
+
* // For XML: <w:bold w:val="0"/>
|
|
67
|
+
* parseOoxmlBoolean({ "@_w:val": "0" }) // false
|
|
68
|
+
*
|
|
69
|
+
* // For absent element
|
|
70
|
+
* parseOoxmlBoolean(undefined) // false
|
|
71
|
+
*/
|
|
72
|
+
export function parseOoxmlBoolean(prop: unknown): boolean {
|
|
73
|
+
// Absent element = false
|
|
74
|
+
if (!prop) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Get the w:val attribute value
|
|
79
|
+
const val = (prop as Record<string, unknown>)['@_w:val'];
|
|
80
|
+
|
|
81
|
+
// Self-closing tag without w:val attribute = true
|
|
82
|
+
// Per ECMA-376, presence of element without val means "on"
|
|
83
|
+
if (val === undefined) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Handle string values
|
|
88
|
+
if (typeof val === 'string') {
|
|
89
|
+
const lowerVal = val.toLowerCase();
|
|
90
|
+
return lowerVal === '1' || lowerVal === 'true' || lowerVal === 'on';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Handle numeric values
|
|
94
|
+
if (typeof val === 'number') {
|
|
95
|
+
return val === 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Handle boolean values (already parsed by XML parser)
|
|
99
|
+
if (typeof val === 'boolean') {
|
|
100
|
+
return val;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Unknown type - default to false
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Check if a value is explicitly set (not undefined or null).
|
|
109
|
+
*
|
|
110
|
+
* This helper addresses the zero-value handling bug where truthy checks
|
|
111
|
+
* incorrectly treat 0 as falsy:
|
|
112
|
+
*
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // WRONG - treats 0 as falsy
|
|
115
|
+
* const width = val ? parseInt(val) : defaultWidth;
|
|
116
|
+
*
|
|
117
|
+
* // CORRECT - only checks for undefined/null
|
|
118
|
+
* const width = isExplicitlySet(val) ? parseInt(val) : defaultWidth;
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @param value - The value to check
|
|
122
|
+
* @returns true if value is not undefined and not null
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* isExplicitlySet(0) // true
|
|
126
|
+
* isExplicitlySet("") // true
|
|
127
|
+
* isExplicitlySet(false) // true
|
|
128
|
+
* isExplicitlySet(undefined) // false
|
|
129
|
+
* isExplicitlySet(null) // false
|
|
130
|
+
*/
|
|
131
|
+
export function isExplicitlySet(value: unknown): boolean {
|
|
132
|
+
return value !== undefined && value !== null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Parse an OOXML numeric attribute with proper handling of zero values.
|
|
137
|
+
*
|
|
138
|
+
* Combines isExplicitlySet() and safeParseInt() for common use case
|
|
139
|
+
* of parsing numeric attributes from XML.
|
|
140
|
+
*
|
|
141
|
+
* @param value - The attribute value to parse
|
|
142
|
+
* @param defaultValue - Default value if attribute is not set
|
|
143
|
+
* @returns Parsed integer or default value
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* parseNumericAttribute("100", 50) // 100
|
|
147
|
+
* parseNumericAttribute("0", 50) // 0 (not 50!)
|
|
148
|
+
* parseNumericAttribute(undefined, 50) // 50
|
|
149
|
+
* parseNumericAttribute("invalid", 50) // 50
|
|
150
|
+
*/
|
|
151
|
+
export function parseNumericAttribute(value: unknown, defaultValue: number): number {
|
|
152
|
+
if (!isExplicitlySet(value)) {
|
|
153
|
+
return defaultValue;
|
|
154
|
+
}
|
|
155
|
+
return safeParseInt(value, defaultValue);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Parse OOXML "on/off" attribute (ST_OnOff type).
|
|
160
|
+
*
|
|
161
|
+
* Some OOXML attributes use the ST_OnOff simple type which can be:
|
|
162
|
+
* - "on", "1", "true" = true
|
|
163
|
+
* - "off", "0", "false" = false
|
|
164
|
+
*
|
|
165
|
+
* This is similar to parseOoxmlBoolean but works on attribute values directly.
|
|
166
|
+
*
|
|
167
|
+
* @param value - The attribute value
|
|
168
|
+
* @param defaultValue - Default if value is not set
|
|
169
|
+
* @returns Boolean value
|
|
170
|
+
*/
|
|
171
|
+
export function parseOnOffAttribute(value: unknown, defaultValue = false): boolean {
|
|
172
|
+
if (!isExplicitlySet(value)) {
|
|
173
|
+
return defaultValue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (typeof value === 'string') {
|
|
177
|
+
const lowerVal = value.toLowerCase();
|
|
178
|
+
return lowerVal === '1' || lowerVal === 'true' || lowerVal === 'on';
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (typeof value === 'number') {
|
|
182
|
+
return value === 1;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (typeof value === 'boolean') {
|
|
186
|
+
return value;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return defaultValue;
|
|
190
|
+
}
|