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,827 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NumberingManager - Manages numbering definitions and generates numbering.xml
|
|
3
|
+
*
|
|
4
|
+
* The NumberingManager is responsible for managing all abstract numbering definitions
|
|
5
|
+
* and numbering instances in a document, and generating the numbering.xml file.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { XMLBuilder, XMLElement } from '../xml/XMLBuilder';
|
|
9
|
+
import { AbstractNumbering } from './AbstractNumbering';
|
|
10
|
+
import { NumberingInstance } from './NumberingInstance';
|
|
11
|
+
import { NumberingLevel } from './NumberingLevel';
|
|
12
|
+
import { defaultLogger } from '../utils/logger';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Options for numbering consolidation
|
|
16
|
+
*/
|
|
17
|
+
export interface NumberingConsolidationOptions {
|
|
18
|
+
/** AbstractNumIds to exclude from consolidation (e.g., HLP/row-number lists) */
|
|
19
|
+
protectedAbstractNumIds?: Set<number>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Result of numbering consolidation
|
|
24
|
+
*/
|
|
25
|
+
export interface NumberingConsolidationResult {
|
|
26
|
+
abstractNumsRemoved: number;
|
|
27
|
+
instancesRemapped: number;
|
|
28
|
+
groupsConsolidated: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Manages numbering definitions and instances for a document
|
|
33
|
+
*/
|
|
34
|
+
export class NumberingManager {
|
|
35
|
+
private abstractNumberings: Map<number, AbstractNumbering>;
|
|
36
|
+
private instances: Map<number, NumberingInstance>;
|
|
37
|
+
private nextAbstractNumId: number;
|
|
38
|
+
private nextNumId: number;
|
|
39
|
+
|
|
40
|
+
// Track if numbering has been modified (for XML preservation)
|
|
41
|
+
private _modified = false;
|
|
42
|
+
|
|
43
|
+
// Track which specific definitions have been modified (for selective merging)
|
|
44
|
+
private _modifiedAbstractNumIds = new Set<number>();
|
|
45
|
+
private _modifiedNumIds = new Set<number>();
|
|
46
|
+
|
|
47
|
+
// Track which definitions have been removed (for removal from original XML during merge)
|
|
48
|
+
private _removedAbstractNumIds = new Set<number>();
|
|
49
|
+
private _removedNumIds = new Set<number>();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new numbering manager
|
|
53
|
+
* @param initializeDefaults Whether to initialize with default numbering definitions
|
|
54
|
+
*/
|
|
55
|
+
constructor(initializeDefaults = false) {
|
|
56
|
+
this.abstractNumberings = new Map();
|
|
57
|
+
this.instances = new Map();
|
|
58
|
+
this.nextAbstractNumId = 0;
|
|
59
|
+
this.nextNumId = 1;
|
|
60
|
+
|
|
61
|
+
if (initializeDefaults) {
|
|
62
|
+
this.initializeDefaultNumberings();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Initializes default numbering definitions (bullet and numbered lists)
|
|
68
|
+
*/
|
|
69
|
+
private initializeDefaultNumberings(): void {
|
|
70
|
+
// Create default bullet list
|
|
71
|
+
const bulletAbstract = AbstractNumbering.createBulletList(this.nextAbstractNumId++);
|
|
72
|
+
this.addAbstractNumbering(bulletAbstract);
|
|
73
|
+
|
|
74
|
+
// Create default numbered list
|
|
75
|
+
const numberedAbstract = AbstractNumbering.createNumberedList(this.nextAbstractNumId++);
|
|
76
|
+
this.addAbstractNumbering(numberedAbstract);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Adds an abstract numbering definition
|
|
81
|
+
* @param abstractNumbering The abstract numbering to add
|
|
82
|
+
*/
|
|
83
|
+
addAbstractNumbering(abstractNumbering: AbstractNumbering): this {
|
|
84
|
+
const id = abstractNumbering.getAbstractNumId();
|
|
85
|
+
this.abstractNumberings.set(id, abstractNumbering);
|
|
86
|
+
|
|
87
|
+
// Update next ID if necessary
|
|
88
|
+
if (id >= this.nextAbstractNumId) {
|
|
89
|
+
this.nextAbstractNumId = id + 1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this._modified = true;
|
|
93
|
+
this._modifiedAbstractNumIds.add(id);
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Gets an abstract numbering by ID
|
|
99
|
+
* @param abstractNumId The abstract numbering ID
|
|
100
|
+
*/
|
|
101
|
+
getAbstractNumbering(abstractNumId: number): AbstractNumbering | undefined {
|
|
102
|
+
return this.abstractNumberings.get(abstractNumId);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Gets all abstract numberings
|
|
107
|
+
*/
|
|
108
|
+
getAllAbstractNumberings(): AbstractNumbering[] {
|
|
109
|
+
return Array.from(this.abstractNumberings.values()).sort(
|
|
110
|
+
(a, b) => a.getAbstractNumId() - b.getAbstractNumId()
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Checks if an abstract numbering exists
|
|
116
|
+
* @param abstractNumId The abstract numbering ID
|
|
117
|
+
*/
|
|
118
|
+
hasAbstractNumbering(abstractNumId: number): boolean {
|
|
119
|
+
return this.abstractNumberings.has(abstractNumId);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Removes an abstract numbering
|
|
124
|
+
* @param abstractNumId The abstract numbering ID
|
|
125
|
+
*/
|
|
126
|
+
removeAbstractNumbering(abstractNumId: number): boolean {
|
|
127
|
+
// Also remove all instances referencing this abstract numbering
|
|
128
|
+
const instancesToRemove: number[] = [];
|
|
129
|
+
this.instances.forEach((instance, numId) => {
|
|
130
|
+
if (instance.getAbstractNumId() === abstractNumId) {
|
|
131
|
+
instancesToRemove.push(numId);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
instancesToRemove.forEach(numId => {
|
|
136
|
+
this.instances.delete(numId);
|
|
137
|
+
this._removedNumIds.add(numId);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const deleted = this.abstractNumberings.delete(abstractNumId);
|
|
141
|
+
if (deleted) {
|
|
142
|
+
this._modified = true;
|
|
143
|
+
this._removedAbstractNumIds.add(abstractNumId);
|
|
144
|
+
}
|
|
145
|
+
return deleted;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Adds a numbering instance
|
|
150
|
+
* @param instance The numbering instance to add
|
|
151
|
+
*/
|
|
152
|
+
addInstance(instance: NumberingInstance): this {
|
|
153
|
+
const numId = instance.getNumId();
|
|
154
|
+
const abstractNumId = instance.getAbstractNumId();
|
|
155
|
+
|
|
156
|
+
// Verify that the abstract numbering exists
|
|
157
|
+
if (!this.hasAbstractNumbering(abstractNumId)) {
|
|
158
|
+
throw new Error(`Abstract numbering ${abstractNumId} does not exist`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.instances.set(numId, instance);
|
|
162
|
+
this._modified = true;
|
|
163
|
+
this._modifiedNumIds.add(numId);
|
|
164
|
+
|
|
165
|
+
// Update next ID if necessary
|
|
166
|
+
if (numId >= this.nextNumId) {
|
|
167
|
+
this.nextNumId = numId + 1;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return this;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Alias for addInstance for backward compatibility
|
|
175
|
+
* @param instance The numbering instance to add
|
|
176
|
+
*/
|
|
177
|
+
addNumberingInstance(instance: NumberingInstance): this {
|
|
178
|
+
return this.addInstance(instance);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Gets a numbering instance by ID
|
|
183
|
+
* @param numId The numbering instance ID
|
|
184
|
+
*/
|
|
185
|
+
getInstance(numId: number): NumberingInstance | undefined {
|
|
186
|
+
return this.instances.get(numId);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Alias for getInstance for backward compatibility
|
|
191
|
+
* @param numId The numbering instance ID
|
|
192
|
+
*/
|
|
193
|
+
getNumberingInstance(numId: number): NumberingInstance | undefined {
|
|
194
|
+
return this.getInstance(numId);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Gets all numbering instances
|
|
199
|
+
*/
|
|
200
|
+
getAllInstances(): NumberingInstance[] {
|
|
201
|
+
return Array.from(this.instances.values()).sort(
|
|
202
|
+
(a, b) => a.getNumId() - b.getNumId()
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Checks if numbering has been modified since loading
|
|
208
|
+
* Used for XML preservation optimization
|
|
209
|
+
* @returns True if numbering was added or modified
|
|
210
|
+
*/
|
|
211
|
+
isModified(): boolean {
|
|
212
|
+
return this._modified;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Marks an abstract numbering as modified for XML regeneration.
|
|
217
|
+
* Use when modifying NumberingLevel properties directly (setLeftIndent, etc.)
|
|
218
|
+
* which don't automatically trigger the modified flag.
|
|
219
|
+
* @param abstractNumId The abstract numbering ID to mark as modified
|
|
220
|
+
*/
|
|
221
|
+
markAbstractNumberingModified(abstractNumId: number): void {
|
|
222
|
+
if (this.abstractNumberings.has(abstractNumId)) {
|
|
223
|
+
this._modified = true;
|
|
224
|
+
this._modifiedAbstractNumIds.add(abstractNumId);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Resets the modified flag
|
|
230
|
+
* Called after parsing to indicate that loaded numbering doesn't count as modifications
|
|
231
|
+
*/
|
|
232
|
+
resetModified(): void {
|
|
233
|
+
this._modified = false;
|
|
234
|
+
this._modifiedAbstractNumIds.clear();
|
|
235
|
+
this._modifiedNumIds.clear();
|
|
236
|
+
this._removedAbstractNumIds.clear();
|
|
237
|
+
this._removedNumIds.clear();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Gets the IDs of abstract numberings that have been modified since loading
|
|
242
|
+
* Used for selective merging with original numbering.xml
|
|
243
|
+
*/
|
|
244
|
+
getModifiedAbstractNumIds(): Set<number> {
|
|
245
|
+
return new Set(this._modifiedAbstractNumIds);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Gets the IDs of numbering instances that have been modified since loading
|
|
250
|
+
* Used for selective merging with original numbering.xml
|
|
251
|
+
*/
|
|
252
|
+
getModifiedNumIds(): Set<number> {
|
|
253
|
+
return new Set(this._modifiedNumIds);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Gets the IDs of abstract numberings that have been removed since loading
|
|
258
|
+
* Used for removal from original numbering.xml during merge
|
|
259
|
+
*/
|
|
260
|
+
getRemovedAbstractNumIds(): Set<number> {
|
|
261
|
+
return new Set(this._removedAbstractNumIds);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Gets the IDs of numbering instances that have been removed since loading
|
|
266
|
+
* Used for removal from original numbering.xml during merge
|
|
267
|
+
*/
|
|
268
|
+
getRemovedNumIds(): Set<number> {
|
|
269
|
+
return new Set(this._removedNumIds);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Alias for getAllInstances for backward compatibility
|
|
274
|
+
*/
|
|
275
|
+
getAllNumberingInstances(): NumberingInstance[] {
|
|
276
|
+
return this.getAllInstances();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Checks if a numbering instance exists
|
|
281
|
+
* @param numId The numbering instance ID
|
|
282
|
+
*/
|
|
283
|
+
hasInstance(numId: number): boolean {
|
|
284
|
+
return this.instances.has(numId);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Removes a numbering instance
|
|
289
|
+
* @param numId The numbering instance ID
|
|
290
|
+
*/
|
|
291
|
+
removeInstance(numId: number): boolean {
|
|
292
|
+
const deleted = this.instances.delete(numId);
|
|
293
|
+
if (deleted) {
|
|
294
|
+
this._modified = true;
|
|
295
|
+
this._removedNumIds.add(numId);
|
|
296
|
+
}
|
|
297
|
+
return deleted;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Creates a new bullet list and returns its numId
|
|
302
|
+
* @param levels Number of levels (default: 9)
|
|
303
|
+
* @param bullets Array of bullet characters
|
|
304
|
+
*/
|
|
305
|
+
createBulletList(levels = 9, bullets?: string[]): number {
|
|
306
|
+
// Create abstract numbering
|
|
307
|
+
const abstractNumId = this.nextAbstractNumId++;
|
|
308
|
+
// Only pass bullets if it's defined, so defaults are used otherwise
|
|
309
|
+
const abstractNumbering = bullets
|
|
310
|
+
? AbstractNumbering.createBulletList(abstractNumId, levels, bullets)
|
|
311
|
+
: AbstractNumbering.createBulletList(abstractNumId, levels);
|
|
312
|
+
this.addAbstractNumbering(abstractNumbering);
|
|
313
|
+
|
|
314
|
+
// Create instance
|
|
315
|
+
const numId = this.nextNumId++;
|
|
316
|
+
const instance = NumberingInstance.create({ numId, abstractNumId });
|
|
317
|
+
this.addInstance(instance);
|
|
318
|
+
|
|
319
|
+
return numId;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Creates a new numbered list and returns its numId
|
|
324
|
+
* @param levels Number of levels (default: 9)
|
|
325
|
+
* @param formats Array of formats for each level
|
|
326
|
+
*/
|
|
327
|
+
createNumberedList(
|
|
328
|
+
levels = 9,
|
|
329
|
+
formats?: ('decimal' | 'lowerLetter' | 'lowerRoman')[]
|
|
330
|
+
): number {
|
|
331
|
+
// Create abstract numbering
|
|
332
|
+
const abstractNumId = this.nextAbstractNumId++;
|
|
333
|
+
// Only pass formats if it's defined, so defaults are used otherwise
|
|
334
|
+
const abstractNumbering = formats
|
|
335
|
+
? AbstractNumbering.createNumberedList(abstractNumId, levels, formats)
|
|
336
|
+
: AbstractNumbering.createNumberedList(abstractNumId, levels);
|
|
337
|
+
this.addAbstractNumbering(abstractNumbering);
|
|
338
|
+
|
|
339
|
+
// Create instance
|
|
340
|
+
const numId = this.nextNumId++;
|
|
341
|
+
const instance = NumberingInstance.create({ numId, abstractNumId });
|
|
342
|
+
this.addInstance(instance);
|
|
343
|
+
|
|
344
|
+
return numId;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Creates a new multi-level list and returns its numId
|
|
349
|
+
*/
|
|
350
|
+
createMultiLevelList(): number {
|
|
351
|
+
// Create abstract numbering
|
|
352
|
+
const abstractNumId = this.nextAbstractNumId++;
|
|
353
|
+
const abstractNumbering = AbstractNumbering.createMultiLevelList(abstractNumId);
|
|
354
|
+
this.addAbstractNumbering(abstractNumbering);
|
|
355
|
+
|
|
356
|
+
// Create instance
|
|
357
|
+
const numId = this.nextNumId++;
|
|
358
|
+
const instance = NumberingInstance.create({ numId, abstractNumId });
|
|
359
|
+
this.addInstance(instance);
|
|
360
|
+
|
|
361
|
+
return numId;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Creates a new outline list and returns its numId
|
|
366
|
+
*/
|
|
367
|
+
createOutlineList(): number {
|
|
368
|
+
// Create abstract numbering
|
|
369
|
+
const abstractNumId = this.nextAbstractNumId++;
|
|
370
|
+
const abstractNumbering = AbstractNumbering.createOutlineList(abstractNumId);
|
|
371
|
+
this.addAbstractNumbering(abstractNumbering);
|
|
372
|
+
|
|
373
|
+
// Create instance
|
|
374
|
+
const numId = this.nextNumId++;
|
|
375
|
+
const instance = NumberingInstance.create({ numId, abstractNumId });
|
|
376
|
+
this.addInstance(instance);
|
|
377
|
+
|
|
378
|
+
return numId;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Creates a custom list with specified levels and returns its numId
|
|
383
|
+
* @param levels Array of numbering levels
|
|
384
|
+
* @param name Optional name for the list
|
|
385
|
+
*/
|
|
386
|
+
createCustomList(levels: NumberingLevel[], name?: string): number {
|
|
387
|
+
// Create abstract numbering
|
|
388
|
+
const abstractNumId = this.nextAbstractNumId++;
|
|
389
|
+
const abstractNumbering = AbstractNumbering.create({
|
|
390
|
+
abstractNumId,
|
|
391
|
+
name,
|
|
392
|
+
levels,
|
|
393
|
+
});
|
|
394
|
+
this.addAbstractNumbering(abstractNumbering);
|
|
395
|
+
|
|
396
|
+
// Create instance
|
|
397
|
+
const numId = this.nextNumId++;
|
|
398
|
+
const instance = NumberingInstance.create({ numId, abstractNumId });
|
|
399
|
+
this.addInstance(instance);
|
|
400
|
+
|
|
401
|
+
return numId;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Creates a new instance of an existing abstract numbering
|
|
406
|
+
* @param abstractNumId The abstract numbering ID to create an instance of
|
|
407
|
+
*/
|
|
408
|
+
createInstance(abstractNumId: number): number {
|
|
409
|
+
if (!this.hasAbstractNumbering(abstractNumId)) {
|
|
410
|
+
throw new Error(`Abstract numbering ${abstractNumId} does not exist`);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const numId = this.nextNumId++;
|
|
414
|
+
const instance = NumberingInstance.create({ numId, abstractNumId });
|
|
415
|
+
this.addInstance(instance);
|
|
416
|
+
|
|
417
|
+
return numId;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Gets the framework's standard indentation for a list level
|
|
422
|
+
*
|
|
423
|
+
* The framework uses a consistent indentation scheme:
|
|
424
|
+
* - leftIndent: 720 + (level * 360) twips
|
|
425
|
+
* - hangingIndent: 360 twips
|
|
426
|
+
*
|
|
427
|
+
* Examples:
|
|
428
|
+
* - Level 0: 720 twips (0.5 inch) left, 360 twips hanging
|
|
429
|
+
* - Level 1: 1080 twips (0.75 inch) left, 360 twips hanging
|
|
430
|
+
* - Level 2: 1440 twips (1.0 inch) left, 360 twips hanging
|
|
431
|
+
*
|
|
432
|
+
* @param level The level (0-8)
|
|
433
|
+
* @returns Object with leftIndent and hangingIndent in twips
|
|
434
|
+
* @example
|
|
435
|
+
* ```typescript
|
|
436
|
+
* const indent = manager.getStandardIndentation(0);
|
|
437
|
+
* // Returns: { leftIndent: 720, hangingIndent: 360 }
|
|
438
|
+
* ```
|
|
439
|
+
*/
|
|
440
|
+
getStandardIndentation(level: number): { leftIndent: number; hangingIndent: number } {
|
|
441
|
+
if (level < 0 || level > 8) {
|
|
442
|
+
throw new Error(`Invalid level ${level}. Level must be between 0 and 8.`);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return {
|
|
446
|
+
leftIndent: 720 + (level * 360),
|
|
447
|
+
hangingIndent: 360,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Sets custom indentation for a specific level in a numbering definition
|
|
453
|
+
*
|
|
454
|
+
* This updates the indentation for a specific level across ALL paragraphs
|
|
455
|
+
* that use this numId and level combination.
|
|
456
|
+
*
|
|
457
|
+
* @param numId The numbering instance ID
|
|
458
|
+
* @param level The level to modify (0-8)
|
|
459
|
+
* @param leftIndent Left indentation in twips
|
|
460
|
+
* @param hangingIndent Hanging indentation in twips (optional, defaults to 360)
|
|
461
|
+
* @returns true if successful, false if numId doesn't exist
|
|
462
|
+
* @example
|
|
463
|
+
* ```typescript
|
|
464
|
+
* // Set level 0 to 0.5 inch left, 0.25 inch hanging
|
|
465
|
+
* manager.setListIndentation(1, 0, 720, 360);
|
|
466
|
+
* ```
|
|
467
|
+
*/
|
|
468
|
+
setListIndentation(
|
|
469
|
+
numId: number,
|
|
470
|
+
level: number,
|
|
471
|
+
leftIndent: number,
|
|
472
|
+
hangingIndent = 360
|
|
473
|
+
): boolean {
|
|
474
|
+
// Validate level
|
|
475
|
+
if (level < 0 || level > 8) {
|
|
476
|
+
throw new Error(`Invalid level ${level}. Level must be between 0 and 8.`);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Validate indents (clamp negatives to 0)
|
|
480
|
+
leftIndent = Math.max(0, leftIndent);
|
|
481
|
+
hangingIndent = Math.max(0, hangingIndent);
|
|
482
|
+
|
|
483
|
+
// Get the numbering instance
|
|
484
|
+
const instance = this.getInstance(numId);
|
|
485
|
+
if (!instance) {
|
|
486
|
+
defaultLogger.warn(`Numbering instance ${numId} does not exist`);
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Get the abstract numbering
|
|
491
|
+
const abstractNum = this.getAbstractNumbering(instance.getAbstractNumId());
|
|
492
|
+
if (!abstractNum) {
|
|
493
|
+
defaultLogger.warn(`Abstract numbering for instance ${numId} does not exist`);
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Get the level from the abstract numbering
|
|
498
|
+
const numLevel = abstractNum.getLevel(level);
|
|
499
|
+
if (!numLevel) {
|
|
500
|
+
defaultLogger.warn(`Level ${level} does not exist in abstract numbering`);
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Update the level's indentation
|
|
505
|
+
numLevel.setLeftIndent(leftIndent);
|
|
506
|
+
numLevel.setHangingIndent(hangingIndent);
|
|
507
|
+
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Resets all levels in a numbering definition to standard indentation
|
|
513
|
+
*
|
|
514
|
+
* This applies the framework's standard indentation formula to all levels:
|
|
515
|
+
* - leftIndent: 720 + (level * 360) twips
|
|
516
|
+
* - hangingIndent: 360 twips
|
|
517
|
+
*
|
|
518
|
+
* @param numId The numbering instance ID
|
|
519
|
+
* @returns true if successful, false if numId doesn't exist
|
|
520
|
+
* @example
|
|
521
|
+
* ```typescript
|
|
522
|
+
* // Reset list 1 to standard indentation
|
|
523
|
+
* manager.normalizeListIndentation(1);
|
|
524
|
+
* ```
|
|
525
|
+
*/
|
|
526
|
+
normalizeListIndentation(numId: number): boolean {
|
|
527
|
+
// Get the numbering instance
|
|
528
|
+
const instance = this.getInstance(numId);
|
|
529
|
+
if (!instance) {
|
|
530
|
+
defaultLogger.warn(`Numbering instance ${numId} does not exist`);
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Get the abstract numbering
|
|
535
|
+
const abstractNum = this.getAbstractNumbering(instance.getAbstractNumId());
|
|
536
|
+
if (!abstractNum) {
|
|
537
|
+
defaultLogger.warn(`Abstract numbering for instance ${numId} does not exist`);
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Get all levels
|
|
542
|
+
const levels = abstractNum.getAllLevels();
|
|
543
|
+
|
|
544
|
+
// Apply standard indentation to each level
|
|
545
|
+
for (const level of levels) {
|
|
546
|
+
const standardIndent = this.getStandardIndentation(level.getLevel());
|
|
547
|
+
level.setLeftIndent(standardIndent.leftIndent);
|
|
548
|
+
level.setHangingIndent(standardIndent.hangingIndent);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return true;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Normalizes indentation for all lists in the document
|
|
556
|
+
*
|
|
557
|
+
* Applies standard indentation to every numbering instance:
|
|
558
|
+
* - leftIndent: 720 + (level * 360) twips
|
|
559
|
+
* - hangingIndent: 360 twips
|
|
560
|
+
*
|
|
561
|
+
* This ensures consistent spacing across all lists in the document.
|
|
562
|
+
*
|
|
563
|
+
* @returns Number of numbering instances updated
|
|
564
|
+
* @example
|
|
565
|
+
* ```typescript
|
|
566
|
+
* const count = manager.normalizeAllListIndentation();
|
|
567
|
+
* console.log(`Normalized ${count} lists`);
|
|
568
|
+
* ```
|
|
569
|
+
*/
|
|
570
|
+
normalizeAllListIndentation(): number {
|
|
571
|
+
let count = 0;
|
|
572
|
+
|
|
573
|
+
// Iterate over all instances
|
|
574
|
+
for (const instance of this.getAllInstances()) {
|
|
575
|
+
const success = this.normalizeListIndentation(instance.getNumId());
|
|
576
|
+
if (success) {
|
|
577
|
+
count++;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return count;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Gets the total number of abstract numberings
|
|
586
|
+
*/
|
|
587
|
+
getAbstractNumberingCount(): number {
|
|
588
|
+
return this.abstractNumberings.size;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Gets the total number of numbering instances
|
|
593
|
+
*/
|
|
594
|
+
getInstanceCount(): number {
|
|
595
|
+
return this.instances.size;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Clears all numbering definitions and instances
|
|
600
|
+
*/
|
|
601
|
+
clear(): this {
|
|
602
|
+
this.abstractNumberings.clear();
|
|
603
|
+
this.instances.clear();
|
|
604
|
+
this.nextAbstractNumId = 0;
|
|
605
|
+
this.nextNumId = 1;
|
|
606
|
+
return this;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Removes unused numbering instances and abstract numberings
|
|
611
|
+
*
|
|
612
|
+
* This method cleans up numbering definitions that are no longer referenced
|
|
613
|
+
* by any paragraphs in the document. It removes:
|
|
614
|
+
* 1. Instances not in the usedNumIds set
|
|
615
|
+
* 2. Abstract numberings not referenced by any remaining instance
|
|
616
|
+
*
|
|
617
|
+
* @param usedNumIds Set of numIds currently used by paragraphs
|
|
618
|
+
* @returns Object with counts of removed instances and abstract numberings
|
|
619
|
+
*/
|
|
620
|
+
cleanupUnusedNumbering(usedNumIds: Set<number>): { instancesRemoved: number; abstractsRemoved: number } {
|
|
621
|
+
let instancesRemoved = 0;
|
|
622
|
+
let abstractsRemoved = 0;
|
|
623
|
+
|
|
624
|
+
// Step 1: Remove unused instances
|
|
625
|
+
const instancesToRemove: number[] = [];
|
|
626
|
+
this.instances.forEach((_instance, numId) => {
|
|
627
|
+
if (!usedNumIds.has(numId)) {
|
|
628
|
+
instancesToRemove.push(numId);
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
for (const numId of instancesToRemove) {
|
|
633
|
+
this.instances.delete(numId);
|
|
634
|
+
this._modified = true;
|
|
635
|
+
this._removedNumIds.add(numId);
|
|
636
|
+
instancesRemoved++;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Step 2: Find abstract numberings still referenced by remaining instances
|
|
640
|
+
const referencedAbstractNumIds = new Set<number>();
|
|
641
|
+
this.instances.forEach(instance => {
|
|
642
|
+
referencedAbstractNumIds.add(instance.getAbstractNumId());
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
// Step 3: Remove unreferenced abstract numberings
|
|
646
|
+
const abstractsToRemove: number[] = [];
|
|
647
|
+
this.abstractNumberings.forEach((_abstractNum, abstractNumId) => {
|
|
648
|
+
if (!referencedAbstractNumIds.has(abstractNumId)) {
|
|
649
|
+
abstractsToRemove.push(abstractNumId);
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
for (const abstractNumId of abstractsToRemove) {
|
|
654
|
+
this.abstractNumberings.delete(abstractNumId);
|
|
655
|
+
this._modified = true;
|
|
656
|
+
this._removedAbstractNumIds.add(abstractNumId);
|
|
657
|
+
abstractsRemoved++;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
return { instancesRemoved, abstractsRemoved };
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Consolidates duplicate abstract numbering definitions
|
|
665
|
+
*
|
|
666
|
+
* Groups abstractNums by a deterministic fingerprint of their level properties
|
|
667
|
+
* (format, text, font, fontSize, color, indentation, alignment, etc.).
|
|
668
|
+
* For each group with >1 member, picks the lowest abstractNumId as canonical,
|
|
669
|
+
* remaps all instances pointing to non-canonical IDs, and removes duplicates.
|
|
670
|
+
*
|
|
671
|
+
* This is safe because multiple num instances can reference the same abstractNum —
|
|
672
|
+
* each instance maintains its own independent counter via level overrides.
|
|
673
|
+
*
|
|
674
|
+
* @param options Optional configuration (e.g., protected IDs to skip)
|
|
675
|
+
* @returns Summary of what was consolidated
|
|
676
|
+
*/
|
|
677
|
+
consolidateNumbering(options?: NumberingConsolidationOptions): NumberingConsolidationResult {
|
|
678
|
+
const protectedIds = options?.protectedAbstractNumIds ?? new Set<number>();
|
|
679
|
+
|
|
680
|
+
// 1. Compute fingerprint for each non-protected abstractNum
|
|
681
|
+
const fingerprintGroups = new Map<string, number[]>();
|
|
682
|
+
for (const abstractNum of this.abstractNumberings.values()) {
|
|
683
|
+
const id = abstractNum.getAbstractNumId();
|
|
684
|
+
if (protectedIds.has(id)) continue;
|
|
685
|
+
|
|
686
|
+
const fingerprint = this._fingerprintAbstractNum(abstractNum);
|
|
687
|
+
const group = fingerprintGroups.get(fingerprint);
|
|
688
|
+
if (group) {
|
|
689
|
+
group.push(id);
|
|
690
|
+
} else {
|
|
691
|
+
fingerprintGroups.set(fingerprint, [id]);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// 2. For each group with >1 member, consolidate
|
|
696
|
+
let abstractNumsRemoved = 0;
|
|
697
|
+
let instancesRemapped = 0;
|
|
698
|
+
let groupsConsolidated = 0;
|
|
699
|
+
|
|
700
|
+
for (const [, ids] of fingerprintGroups) {
|
|
701
|
+
if (ids.length <= 1) continue;
|
|
702
|
+
|
|
703
|
+
// Sort to pick lowest ID as canonical
|
|
704
|
+
ids.sort((a, b) => a - b);
|
|
705
|
+
const canonicalId = ids[0]!;
|
|
706
|
+
const duplicateIds = new Set(ids.slice(1));
|
|
707
|
+
|
|
708
|
+
groupsConsolidated++;
|
|
709
|
+
|
|
710
|
+
// Remap instances pointing to duplicate abstractNums
|
|
711
|
+
for (const instance of this.instances.values()) {
|
|
712
|
+
if (duplicateIds.has(instance.getAbstractNumId())) {
|
|
713
|
+
instance.setAbstractNumId(canonicalId);
|
|
714
|
+
this._modifiedNumIds.add(instance.getNumId());
|
|
715
|
+
instancesRemapped++;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Remove duplicate abstractNums
|
|
720
|
+
for (const dupId of duplicateIds) {
|
|
721
|
+
this.abstractNumberings.delete(dupId);
|
|
722
|
+
this._removedAbstractNumIds.add(dupId);
|
|
723
|
+
abstractNumsRemoved++;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
if (abstractNumsRemoved > 0) {
|
|
728
|
+
this._modified = true;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
return { abstractNumsRemoved, instancesRemapped, groupsConsolidated };
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Computes a deterministic fingerprint for an abstract numbering definition
|
|
736
|
+
* based on its multiLevelType and all level properties. Name and abstractNumId
|
|
737
|
+
* are excluded since they don't affect rendering.
|
|
738
|
+
*/
|
|
739
|
+
private _fingerprintAbstractNum(abstractNum: AbstractNumbering): string {
|
|
740
|
+
const parts: string[] = [
|
|
741
|
+
abstractNum.getNumStyleLink() ?? '',
|
|
742
|
+
abstractNum.getStyleLink() ?? '',
|
|
743
|
+
abstractNum.getMultiLevelType(),
|
|
744
|
+
];
|
|
745
|
+
|
|
746
|
+
for (const level of abstractNum.getAllLevels()) {
|
|
747
|
+
const props = level.getProperties();
|
|
748
|
+
parts.push(
|
|
749
|
+
`${props.level}|${props.format}|${props.text}|${props.font}|${props.fontSize}|` +
|
|
750
|
+
`${props.color}|${props.leftIndent}|${props.hangingIndent}|${props.alignment}|` +
|
|
751
|
+
`${props.start}|${props.bold}|${props.italic}|${props.underline ?? ''}|` +
|
|
752
|
+
`${props.suffix}|${props.isLegalNumberingStyle}|${props.lvlRestart ?? ''}`
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return parts.join('::');
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Generates the complete numbering.xml content
|
|
761
|
+
*/
|
|
762
|
+
generateNumberingXml(): string {
|
|
763
|
+
const builder = new XMLBuilder();
|
|
764
|
+
|
|
765
|
+
const children: XMLElement[] = [];
|
|
766
|
+
|
|
767
|
+
// Add all abstract numberings
|
|
768
|
+
const abstractNumberings = this.getAllAbstractNumberings();
|
|
769
|
+
abstractNumberings.forEach(abstractNum => {
|
|
770
|
+
children.push(abstractNum.toXML());
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
// Add all numbering instances
|
|
774
|
+
const instances = this.getAllInstances();
|
|
775
|
+
instances.forEach(instance => {
|
|
776
|
+
children.push(instance.toXML());
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
const numbering = XMLBuilder.w('numbering', {
|
|
780
|
+
'xmlns:w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
|
|
781
|
+
'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
|
|
782
|
+
}, children);
|
|
783
|
+
|
|
784
|
+
builder.element(numbering.name, numbering.attributes, numbering.children);
|
|
785
|
+
|
|
786
|
+
// Generate XML with declaration
|
|
787
|
+
return builder.build(true);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Generates the numbering.xml as XMLElement (for API compatibility)
|
|
792
|
+
*/
|
|
793
|
+
toXML(): XMLElement {
|
|
794
|
+
const children: XMLElement[] = [];
|
|
795
|
+
|
|
796
|
+
// Add all abstract numberings
|
|
797
|
+
const abstractNumberings = this.getAllAbstractNumberings();
|
|
798
|
+
abstractNumberings.forEach(abstractNum => {
|
|
799
|
+
children.push(abstractNum.toXML());
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
// Add all numbering instances
|
|
803
|
+
const instances = this.getAllInstances();
|
|
804
|
+
instances.forEach(instance => {
|
|
805
|
+
children.push(instance.toXML());
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
return XMLBuilder.w('numbering', {
|
|
809
|
+
'xmlns:w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
|
|
810
|
+
'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
|
|
811
|
+
}, children);
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Creates a numbering manager with default numbering definitions
|
|
816
|
+
*/
|
|
817
|
+
static create(): NumberingManager {
|
|
818
|
+
return new NumberingManager(false);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Creates an empty numbering manager
|
|
823
|
+
*/
|
|
824
|
+
static createEmpty(): NumberingManager {
|
|
825
|
+
return new NumberingManager(false);
|
|
826
|
+
}
|
|
827
|
+
}
|