docxmlater 10.0.1 → 10.0.3
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 +24 -19
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +272 -71
- 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 +60 -54
- 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.map +1 -1
- package/dist/elements/Paragraph.js +128 -117
- 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.d.ts.map +1 -1
- package/dist/helpers/CleanupHelper.js +1 -7
- 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.js +1 -1
- 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.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 +10107 -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 +4227 -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 +668 -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 +613 -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,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnostic logging utilities for debugging document processing
|
|
3
|
+
* @module diagnostics
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface DiagnosticConfig {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
logParsing: boolean;
|
|
9
|
+
logSerialization: boolean;
|
|
10
|
+
logTextDirection: boolean;
|
|
11
|
+
verbose: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const defaultConfig: DiagnosticConfig = {
|
|
15
|
+
enabled: false,
|
|
16
|
+
logParsing: false,
|
|
17
|
+
logSerialization: false,
|
|
18
|
+
logTextDirection: false,
|
|
19
|
+
verbose: false,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
let config: DiagnosticConfig = { ...defaultConfig };
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Enable diagnostic logging
|
|
26
|
+
*/
|
|
27
|
+
export function enableDiagnostics(options: Partial<DiagnosticConfig> = {}): void {
|
|
28
|
+
config = {
|
|
29
|
+
...defaultConfig,
|
|
30
|
+
enabled: true,
|
|
31
|
+
...options,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Disable diagnostic logging
|
|
37
|
+
*/
|
|
38
|
+
export function disableDiagnostics(): void {
|
|
39
|
+
config = { ...defaultConfig };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get current diagnostic configuration
|
|
44
|
+
*/
|
|
45
|
+
export function getDiagnosticConfig(): DiagnosticConfig {
|
|
46
|
+
return { ...config };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Log parsing activity
|
|
51
|
+
*/
|
|
52
|
+
export function logParsing(message: string, data?: unknown): void {
|
|
53
|
+
if (config.enabled && config.logParsing) {
|
|
54
|
+
console.log(`[PARSE] ${message}`, data !== undefined ? data : '');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Log serialization activity
|
|
60
|
+
*/
|
|
61
|
+
export function logSerialization(message: string, data?: unknown): void {
|
|
62
|
+
if (config.enabled && config.logSerialization) {
|
|
63
|
+
console.log(`[SERIALIZE] ${message}`, data !== undefined ? data : '');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Log text direction properties
|
|
69
|
+
*/
|
|
70
|
+
export function logTextDirection(message: string, data?: unknown): void {
|
|
71
|
+
if (config.enabled && config.logTextDirection) {
|
|
72
|
+
console.log(`[TEXT-DIR] ${message}`, data !== undefined ? data : '');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Log verbose details
|
|
78
|
+
*/
|
|
79
|
+
export function logVerbose(message: string, data?: unknown): void {
|
|
80
|
+
if (config.enabled && config.verbose) {
|
|
81
|
+
console.log(`[VERBOSE] ${message}`, data !== undefined ? data : '');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Log paragraph content summary
|
|
87
|
+
*/
|
|
88
|
+
export function logParagraphContent(
|
|
89
|
+
source: 'parsing' | 'serialization',
|
|
90
|
+
paraIndex: number,
|
|
91
|
+
runs: { text: string; rtl?: boolean }[],
|
|
92
|
+
bidi?: boolean
|
|
93
|
+
): void {
|
|
94
|
+
if (!config.enabled) return;
|
|
95
|
+
|
|
96
|
+
const logger = source === 'parsing' ? logParsing : logSerialization;
|
|
97
|
+
|
|
98
|
+
logger(`Paragraph ${paraIndex}:`);
|
|
99
|
+
logger(` BiDi: ${bidi !== undefined ? bidi : 'not set'}`);
|
|
100
|
+
logger(` Runs (${runs.length}):`);
|
|
101
|
+
|
|
102
|
+
runs.forEach((run, idx) => {
|
|
103
|
+
const rtlStatus = run.rtl ? ' [RTL]' : '';
|
|
104
|
+
logger(` ${idx + 1}. "${run.text}"${rtlStatus}`);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const fullText = runs.map(r => r.text).join('');
|
|
108
|
+
logger(` Combined text: "${fullText}"`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Compare text before and after processing
|
|
113
|
+
*/
|
|
114
|
+
export function logTextComparison(
|
|
115
|
+
label: string,
|
|
116
|
+
before: string,
|
|
117
|
+
after: string
|
|
118
|
+
): void {
|
|
119
|
+
if (!config.enabled) return;
|
|
120
|
+
|
|
121
|
+
if (before !== after) {
|
|
122
|
+
console.log(`[TEXT-CHANGE] ${label}:`);
|
|
123
|
+
console.log(` Before: "${before}"`);
|
|
124
|
+
console.log(` After: "${after}"`);
|
|
125
|
+
console.log(` MISMATCH DETECTED!`);
|
|
126
|
+
} else if (config.verbose) {
|
|
127
|
+
logVerbose(`${label}: Text preserved correctly`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error handling utilities for consistent error processing
|
|
3
|
+
* Ensures all caught errors are properly typed and handled
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Type guard to check if a value is an Error object
|
|
8
|
+
* @param error - The value to check
|
|
9
|
+
* @returns True if the value is an Error instance
|
|
10
|
+
*/
|
|
11
|
+
export function isError(error: unknown): error is Error {
|
|
12
|
+
return error instanceof Error;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Converts unknown error to Error object
|
|
17
|
+
* Ensures we always have a proper Error with message property
|
|
18
|
+
* @param error - The error to normalize (can be anything)
|
|
19
|
+
* @returns Normalized Error object
|
|
20
|
+
*/
|
|
21
|
+
export function toError(error: unknown): Error {
|
|
22
|
+
if (isError(error)) {
|
|
23
|
+
return error;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Handle string errors
|
|
27
|
+
if (typeof error === 'string') {
|
|
28
|
+
return new Error(error);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle objects with message property
|
|
32
|
+
if (error && typeof error === 'object' && 'message' in error) {
|
|
33
|
+
return new Error(String(error.message));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Fallback for any other type
|
|
37
|
+
return new Error(String(error));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Wraps an error with additional context
|
|
42
|
+
* Useful for adding file paths, operation names, etc.
|
|
43
|
+
* @param error - The original error
|
|
44
|
+
* @param context - Additional context to prepend to error message
|
|
45
|
+
* @returns New Error with combined message and original stack
|
|
46
|
+
*/
|
|
47
|
+
export function wrapError(error: unknown, context: string): Error {
|
|
48
|
+
const originalError = toError(error);
|
|
49
|
+
const wrappedError = new Error(`${context}: ${originalError.message}`);
|
|
50
|
+
|
|
51
|
+
// Preserve original stack trace if available
|
|
52
|
+
if (originalError.stack) {
|
|
53
|
+
wrappedError.stack = `${wrappedError.message}\nCaused by: ${originalError.stack}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return wrappedError;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Safe error message extraction
|
|
61
|
+
* Returns error message or generic fallback
|
|
62
|
+
* @param error - The error to extract message from
|
|
63
|
+
* @param fallback - Fallback message if extraction fails
|
|
64
|
+
* @returns Error message string
|
|
65
|
+
*/
|
|
66
|
+
export function getErrorMessage(error: unknown, fallback = 'Unknown error occurred'): string {
|
|
67
|
+
if (isError(error)) {
|
|
68
|
+
return error.message;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (typeof error === 'string') {
|
|
72
|
+
return error;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (error && typeof error === 'object' && 'message' in error) {
|
|
76
|
+
return String(error.message);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return fallback;
|
|
80
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting utilities for deep merging and cloning formatting objects
|
|
3
|
+
* Used for style inheritance and applying formatting
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Deep merges two formatting objects, with override taking precedence
|
|
8
|
+
* Used for style inheritance and applying formatting
|
|
9
|
+
*
|
|
10
|
+
* @param base - Base formatting object
|
|
11
|
+
* @param override - Override formatting object (takes precedence)
|
|
12
|
+
* @returns Merged formatting object
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const baseFormat = { bold: true, fontSize: 24 };
|
|
17
|
+
* const overrideFormat = { fontSize: 28, italic: true };
|
|
18
|
+
* const result = mergeFormatting(baseFormat, overrideFormat);
|
|
19
|
+
* // Result: { bold: true, fontSize: 28, italic: true }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function mergeFormatting<T extends Record<string, any>>(
|
|
23
|
+
base: T,
|
|
24
|
+
override: Partial<T>
|
|
25
|
+
): T {
|
|
26
|
+
const result = { ...base };
|
|
27
|
+
|
|
28
|
+
for (const [key, value] of Object.entries(override)) {
|
|
29
|
+
if (value === undefined) continue;
|
|
30
|
+
|
|
31
|
+
if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
|
|
32
|
+
// Deep merge nested objects
|
|
33
|
+
result[key as keyof T] = mergeFormatting(
|
|
34
|
+
result[key as keyof T] || ({} as any),
|
|
35
|
+
value
|
|
36
|
+
);
|
|
37
|
+
} else {
|
|
38
|
+
// Direct assignment for primitives
|
|
39
|
+
result[key as keyof T] = value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Deep clones a formatting object
|
|
48
|
+
* Creates a completely independent copy with no shared references
|
|
49
|
+
*
|
|
50
|
+
* @param formatting - Formatting object to clone
|
|
51
|
+
* @returns Cloned formatting object
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const original = { bold: true, indentation: { left: 100 } };
|
|
56
|
+
* const cloned = cloneFormatting(original);
|
|
57
|
+
* cloned.indentation.left = 200; // Doesn't affect original
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function cloneFormatting<T>(formatting: T): T {
|
|
61
|
+
return JSON.parse(JSON.stringify(formatting));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Checks if a formatting object has any defined properties
|
|
66
|
+
*
|
|
67
|
+
* @param formatting - Formatting object to check
|
|
68
|
+
* @returns True if the object has at least one defined property
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* hasFormatting({}) // false
|
|
73
|
+
* hasFormatting({ bold: true }) // true
|
|
74
|
+
* hasFormatting({ bold: undefined }) // false
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function hasFormatting(formatting: Record<string, unknown>): boolean {
|
|
78
|
+
for (const value of Object.values(formatting)) {
|
|
79
|
+
if (value !== undefined && value !== null) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Removes undefined and null properties from a formatting object
|
|
88
|
+
* Useful for cleaning up formatting before comparison or serialization
|
|
89
|
+
*
|
|
90
|
+
* @param formatting - Formatting object to clean
|
|
91
|
+
* @returns Cleaned formatting object with no undefined/null values
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const dirty = { bold: true, italic: undefined, fontSize: null, underline: false };
|
|
96
|
+
* const clean = cleanFormatting(dirty);
|
|
97
|
+
* // Result: { bold: true, underline: false }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export function cleanFormatting<T extends Record<string, any>>(formatting: T): Partial<T> {
|
|
101
|
+
const cleaned: Partial<T> = {};
|
|
102
|
+
|
|
103
|
+
for (const [key, value] of Object.entries(formatting)) {
|
|
104
|
+
if (value !== undefined && value !== null) {
|
|
105
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
106
|
+
// Recursively clean nested objects
|
|
107
|
+
const cleanedNested = cleanFormatting(value);
|
|
108
|
+
if (Object.keys(cleanedNested).length > 0) {
|
|
109
|
+
cleaned[key as keyof T] = cleanedNested as any;
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
cleaned[key as keyof T] = value;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return cleaned;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Compares two formatting objects for equality
|
|
122
|
+
* Performs deep comparison of all properties
|
|
123
|
+
*
|
|
124
|
+
* @param format1 - First formatting object
|
|
125
|
+
* @param format2 - Second formatting object
|
|
126
|
+
* @returns True if the formatting objects are equal
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* const a = { bold: true, fontSize: 24 };
|
|
131
|
+
* const b = { bold: true, fontSize: 24 };
|
|
132
|
+
* const c = { bold: true, fontSize: 28 };
|
|
133
|
+
* isEqualFormatting(a, b) // true
|
|
134
|
+
* isEqualFormatting(a, c) // false
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export function isEqualFormatting(
|
|
138
|
+
format1: Record<string, unknown>,
|
|
139
|
+
format2: Record<string, unknown>
|
|
140
|
+
): boolean {
|
|
141
|
+
// Quick reference check
|
|
142
|
+
if (format1 === format2) return true;
|
|
143
|
+
|
|
144
|
+
// Null/undefined checks
|
|
145
|
+
if (!format1 || !format2) return false;
|
|
146
|
+
|
|
147
|
+
// Get all keys from both objects
|
|
148
|
+
const keys1 = Object.keys(format1);
|
|
149
|
+
const keys2 = Object.keys(format2);
|
|
150
|
+
|
|
151
|
+
// Check if they have the same number of properties
|
|
152
|
+
if (keys1.length !== keys2.length) return false;
|
|
153
|
+
|
|
154
|
+
// Check all properties
|
|
155
|
+
for (const key of keys1) {
|
|
156
|
+
const val1 = format1[key];
|
|
157
|
+
const val2 = format2[key];
|
|
158
|
+
|
|
159
|
+
// Both undefined/null - considered equal
|
|
160
|
+
if ((val1 === undefined || val1 === null) && (val2 === undefined || val2 === null)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// One is undefined/null and the other isn't
|
|
165
|
+
if ((val1 === undefined || val1 === null) !== (val2 === undefined || val2 === null)) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Check nested objects
|
|
170
|
+
if (typeof val1 === 'object' && val1 !== null && typeof val2 === 'object' && val2 !== null && !Array.isArray(val1) && !Array.isArray(val2)) {
|
|
171
|
+
if (!isEqualFormatting(val1 as Record<string, unknown>, val2 as Record<string, unknown>)) return false;
|
|
172
|
+
} else if (val1 !== val2) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Applies default values to a formatting object for any undefined properties
|
|
182
|
+
*
|
|
183
|
+
* @param formatting - Formatting object to apply defaults to
|
|
184
|
+
* @param defaults - Default values
|
|
185
|
+
* @returns Formatting object with defaults applied
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* const format = { bold: true };
|
|
190
|
+
* const defaults = { bold: false, italic: false, fontSize: 24 };
|
|
191
|
+
* const result = applyDefaults(format, defaults);
|
|
192
|
+
* // Result: { bold: true, italic: false, fontSize: 24 }
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
export function applyDefaults<T extends Record<string, any>>(
|
|
196
|
+
formatting: Partial<T>,
|
|
197
|
+
defaults: T
|
|
198
|
+
): T {
|
|
199
|
+
const result = { ...defaults };
|
|
200
|
+
|
|
201
|
+
for (const [key, value] of Object.entries(formatting)) {
|
|
202
|
+
if (value !== undefined) {
|
|
203
|
+
if (typeof value === 'object' && !Array.isArray(value) && value !== null && typeof defaults[key] === 'object') {
|
|
204
|
+
// Deep merge nested objects
|
|
205
|
+
result[key as keyof T] = applyDefaults(value, defaults[key]);
|
|
206
|
+
} else {
|
|
207
|
+
result[key as keyof T] = value;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List Detection Utilities for docxmlater
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to detect typed list prefixes and analyze
|
|
5
|
+
* paragraph list properties.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Paragraph } from "../elements/Paragraph";
|
|
9
|
+
import type {
|
|
10
|
+
ListCategory,
|
|
11
|
+
ListDetectionResult,
|
|
12
|
+
NumberFormat,
|
|
13
|
+
BulletFormat,
|
|
14
|
+
} from "../types/list-types";
|
|
15
|
+
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// CONSTANTS
|
|
18
|
+
// =============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Regex patterns for typed list prefixes.
|
|
22
|
+
* Order matters: more specific patterns first.
|
|
23
|
+
*/
|
|
24
|
+
export const TYPED_LIST_PATTERNS: Record<string, RegExp> = {
|
|
25
|
+
// Numbered patterns (capture the marker for validation)
|
|
26
|
+
decimal: /^(\d+)[.)]\s+/,
|
|
27
|
+
lowerLetter: /^([a-z])[.)]\s+/,
|
|
28
|
+
upperLetter: /^([A-Z])[.)]\s+/,
|
|
29
|
+
lowerRoman: /^((?:i{1,3}|iv|vi{0,3}|ix|x{1,3}))[.)]\s+/i,
|
|
30
|
+
|
|
31
|
+
// Bullet patterns
|
|
32
|
+
bullet: /^[•●○◦▪■□]\s+/,
|
|
33
|
+
dash: /^[-–—]\s+/,
|
|
34
|
+
arrow: /^[►▸▶→]\s+/,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Map pattern names to categories */
|
|
38
|
+
export const PATTERN_TO_CATEGORY: Record<string, ListCategory> = {
|
|
39
|
+
decimal: "numbered",
|
|
40
|
+
lowerLetter: "numbered",
|
|
41
|
+
upperLetter: "numbered",
|
|
42
|
+
lowerRoman: "numbered",
|
|
43
|
+
bullet: "bullet",
|
|
44
|
+
dash: "bullet",
|
|
45
|
+
arrow: "bullet",
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Map typed prefix format to Word numbering level.
|
|
50
|
+
* Word's default multilevel list uses:
|
|
51
|
+
* Level 0: 1., 2., 3. (decimal)
|
|
52
|
+
* Level 1: a., b., c. (lowerLetter)
|
|
53
|
+
* Level 2: i., ii., iii. (lowerRoman)
|
|
54
|
+
*/
|
|
55
|
+
export const FORMAT_TO_LEVEL: Record<string, number> = {
|
|
56
|
+
decimal: 0, // 1., 2., 3.
|
|
57
|
+
lowerLetter: 1, // a., b., c.
|
|
58
|
+
upperLetter: 1, // A., B., C.
|
|
59
|
+
lowerRoman: 2, // i., ii., iii.
|
|
60
|
+
upperRoman: 2, // I., II., III.
|
|
61
|
+
bullet: 0, // Top-level bullet (filled circle)
|
|
62
|
+
dash: 0, // Top-level dash marker
|
|
63
|
+
arrow: 0, // Top-level arrow marker
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get the Word numbering level for a given format.
|
|
68
|
+
* Returns 0 (top level) for decimal or unknown formats.
|
|
69
|
+
*/
|
|
70
|
+
export function getLevelFromFormat(format: string | null): number {
|
|
71
|
+
if (!format) return 0;
|
|
72
|
+
return FORMAT_TO_LEVEL[format] ?? 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Word standard indentation values in twips.
|
|
77
|
+
* Level 0: 720 twips (0.5 inch) left indent
|
|
78
|
+
* Level 1: 1080 twips (0.75 inch) left indent
|
|
79
|
+
* Level 2: 1440 twips (1 inch) left indent
|
|
80
|
+
* Each subsequent level adds 360 twips.
|
|
81
|
+
*/
|
|
82
|
+
const WORD_BASE_INDENT = 720;
|
|
83
|
+
const INDENT_PER_LEVEL = 360;
|
|
84
|
+
|
|
85
|
+
// =============================================================================
|
|
86
|
+
// CORE DETECTION FUNCTIONS
|
|
87
|
+
// =============================================================================
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Infer list level from indentation.
|
|
91
|
+
* Uses standard Word indentation: 720 twips for level 0, +360 per level.
|
|
92
|
+
*/
|
|
93
|
+
export function inferLevelFromIndentation(indentTwips: number): number {
|
|
94
|
+
if (indentTwips < WORD_BASE_INDENT) return 0;
|
|
95
|
+
return Math.floor((indentTwips - WORD_BASE_INDENT) / INDENT_PER_LEVEL);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Infer list level from relative indentation (baseline already subtracted).
|
|
100
|
+
* Used when normalizing lists within a table cell where the baseline
|
|
101
|
+
* indentation varies per cell.
|
|
102
|
+
*/
|
|
103
|
+
export function inferLevelFromRelativeIndentation(relativeIndentTwips: number): number {
|
|
104
|
+
if (relativeIndentTwips <= 0) return 0;
|
|
105
|
+
return Math.min(8, Math.floor(relativeIndentTwips / INDENT_PER_LEVEL));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Detect typed list prefix in text.
|
|
110
|
+
* Returns the matched prefix and format type.
|
|
111
|
+
*
|
|
112
|
+
* Special handling for abbreviations:
|
|
113
|
+
* - Single letter prefixes (A., B., P.) are NOT treated as list markers
|
|
114
|
+
* if the remaining text also starts with a letter+period pattern,
|
|
115
|
+
* indicating an abbreviation like "P.O. Box", "U.S. Army", etc.
|
|
116
|
+
*/
|
|
117
|
+
export function detectTypedPrefix(text: string): {
|
|
118
|
+
prefix: string | null;
|
|
119
|
+
format: NumberFormat | BulletFormat | null;
|
|
120
|
+
category: ListCategory;
|
|
121
|
+
} {
|
|
122
|
+
for (const [format, regex] of Object.entries(TYPED_LIST_PATTERNS)) {
|
|
123
|
+
const match = text.match(regex);
|
|
124
|
+
if (match) {
|
|
125
|
+
// Special check for single-letter patterns (lowerLetter, upperLetter)
|
|
126
|
+
// to avoid false positives on abbreviations like "P.O. Box", "U.S.", "A.M."
|
|
127
|
+
if (format === "lowerLetter" || format === "upperLetter") {
|
|
128
|
+
const remaining = text.substring(match[0].length);
|
|
129
|
+
// If remaining text starts with another letter followed by period,
|
|
130
|
+
// this is likely an abbreviation, not a list marker
|
|
131
|
+
if (/^[A-Za-z]\./.test(remaining)) {
|
|
132
|
+
continue; // Skip this pattern, try others
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
prefix: match[0],
|
|
138
|
+
format: format as NumberFormat | BulletFormat,
|
|
139
|
+
category: PATTERN_TO_CATEGORY[format] ?? "none",
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return { prefix: null, format: null, category: "none" };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get the left indentation from a paragraph in twips.
|
|
149
|
+
*/
|
|
150
|
+
export function getParagraphIndentation(paragraph: Paragraph): number {
|
|
151
|
+
const formatting = paragraph.getFormatting();
|
|
152
|
+
return formatting?.indentation?.left ?? 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Main detection function: analyze a single paragraph for list properties.
|
|
157
|
+
*/
|
|
158
|
+
export function detectListType(paragraph: Paragraph): ListDetectionResult {
|
|
159
|
+
const text = paragraph.getText();
|
|
160
|
+
const indentation = getParagraphIndentation(paragraph);
|
|
161
|
+
const numbering = paragraph.getNumbering();
|
|
162
|
+
|
|
163
|
+
// Priority 1: Real Word list with <w:numPr>
|
|
164
|
+
if (numbering?.numId !== undefined && numbering.numId !== 0) {
|
|
165
|
+
return {
|
|
166
|
+
category: "numbered", // Default, caller can refine with NumberingManager lookup
|
|
167
|
+
isWordList: true,
|
|
168
|
+
typedPrefix: null,
|
|
169
|
+
inferredLevel: numbering.level ?? 0,
|
|
170
|
+
format: null, // Would need numbering.xml lookup
|
|
171
|
+
numId: numbering.numId,
|
|
172
|
+
ilvl: numbering.level ?? 0,
|
|
173
|
+
indentationTwips: indentation,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Priority 2: Typed prefix detection
|
|
178
|
+
const typed = detectTypedPrefix(text);
|
|
179
|
+
if (typed.prefix) {
|
|
180
|
+
return {
|
|
181
|
+
category: typed.category,
|
|
182
|
+
isWordList: false,
|
|
183
|
+
typedPrefix: typed.prefix,
|
|
184
|
+
// Use FORMAT to determine level, not indentation!
|
|
185
|
+
// decimal=0, lowerLetter=1, lowerRoman=2
|
|
186
|
+
inferredLevel: getLevelFromFormat(typed.format),
|
|
187
|
+
format: typed.format,
|
|
188
|
+
numId: null,
|
|
189
|
+
ilvl: null,
|
|
190
|
+
indentationTwips: indentation,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Priority 3: Not a list
|
|
195
|
+
return {
|
|
196
|
+
category: "none",
|
|
197
|
+
isWordList: false,
|
|
198
|
+
typedPrefix: null,
|
|
199
|
+
inferredLevel: 0,
|
|
200
|
+
format: null,
|
|
201
|
+
numId: null,
|
|
202
|
+
ilvl: null,
|
|
203
|
+
indentationTwips: indentation,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Validate that a typed prefix sequence is reasonable.
|
|
209
|
+
* E.g., "1. 2. 3." is valid, "1. 5. 2." is suspicious.
|
|
210
|
+
*/
|
|
211
|
+
export function validateListSequence(
|
|
212
|
+
paragraphs: { detection: ListDetectionResult; text: string }[]
|
|
213
|
+
): { valid: boolean; warnings: string[] } {
|
|
214
|
+
const warnings: string[] = [];
|
|
215
|
+
let lastDecimal = 0;
|
|
216
|
+
let lastLetter = "";
|
|
217
|
+
|
|
218
|
+
for (const { detection } of paragraphs) {
|
|
219
|
+
if (!detection.typedPrefix || detection.category !== "numbered") continue;
|
|
220
|
+
|
|
221
|
+
const match = /^(\d+|[a-zA-Z]+)/.exec(detection.typedPrefix);
|
|
222
|
+
if (!match?.[1]) continue;
|
|
223
|
+
|
|
224
|
+
const marker = match[1];
|
|
225
|
+
|
|
226
|
+
// Check decimal sequence
|
|
227
|
+
if (/^\d+$/.test(marker)) {
|
|
228
|
+
const num = parseInt(marker, 10);
|
|
229
|
+
if (lastDecimal > 0 && num !== lastDecimal + 1 && num !== 1) {
|
|
230
|
+
warnings.push(`Unexpected number sequence: ${lastDecimal} → ${num}`);
|
|
231
|
+
}
|
|
232
|
+
lastDecimal = num;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Check letter sequence
|
|
236
|
+
if (/^[a-z]$/i.test(marker)) {
|
|
237
|
+
const letter = marker.toLowerCase();
|
|
238
|
+
if (
|
|
239
|
+
lastLetter &&
|
|
240
|
+
letter.charCodeAt(0) !== lastLetter.charCodeAt(0) + 1 &&
|
|
241
|
+
letter !== "a"
|
|
242
|
+
) {
|
|
243
|
+
warnings.push(`Unexpected letter sequence: ${lastLetter} → ${letter}`);
|
|
244
|
+
}
|
|
245
|
+
lastLetter = letter;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return { valid: warnings.length === 0, warnings };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Determine the list category for a given numId by checking the abstractNum.
|
|
254
|
+
* This requires access to the NumberingManager.
|
|
255
|
+
*/
|
|
256
|
+
export function getListCategoryFromFormat(
|
|
257
|
+
format: string | undefined
|
|
258
|
+
): ListCategory {
|
|
259
|
+
if (!format) return "none";
|
|
260
|
+
|
|
261
|
+
if (["bullet", "dash", "arrow"].includes(format)) {
|
|
262
|
+
return "bullet";
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (
|
|
266
|
+
["decimal", "lowerLetter", "upperLetter", "lowerRoman", "upperRoman"].includes(
|
|
267
|
+
format
|
|
268
|
+
)
|
|
269
|
+
) {
|
|
270
|
+
return "numbered";
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return "none";
|
|
274
|
+
}
|