docxmlater 11.0.10 → 12.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -13
- package/dist/core/Document.d.ts +28 -2
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +725 -170
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentGenerator.d.ts +1 -0
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +77 -25
- package/dist/core/DocumentGenerator.js.map +1 -1
- package/dist/core/DocumentParser.d.ts +7 -3
- package/dist/core/DocumentParser.d.ts.map +1 -1
- package/dist/core/DocumentParser.js +427 -81
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +2 -2
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/Comment.d.ts +15 -1
- package/dist/elements/Comment.d.ts.map +1 -1
- package/dist/elements/Comment.js +67 -12
- package/dist/elements/Comment.js.map +1 -1
- package/dist/elements/CommentManager.d.ts +4 -0
- package/dist/elements/CommentManager.d.ts.map +1 -1
- package/dist/elements/CommentManager.js +74 -16
- package/dist/elements/CommentManager.js.map +1 -1
- package/dist/elements/EndnoteManager.d.ts.map +1 -1
- package/dist/elements/EndnoteManager.js.map +1 -1
- package/dist/elements/Field.d.ts +10 -1
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +76 -34
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/FieldHelpers.d.ts +1 -0
- package/dist/elements/FieldHelpers.d.ts.map +1 -1
- package/dist/elements/FieldHelpers.js +8 -4
- package/dist/elements/FieldHelpers.js.map +1 -1
- package/dist/elements/Footer.d.ts +3 -1
- package/dist/elements/Footer.d.ts.map +1 -1
- package/dist/elements/Footer.js +39 -53
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/FootnoteManager.d.ts.map +1 -1
- package/dist/elements/FootnoteManager.js.map +1 -1
- package/dist/elements/Header.d.ts +3 -1
- package/dist/elements/Header.d.ts.map +1 -1
- package/dist/elements/Header.js +39 -53
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/HeaderFooterManager.d.ts +4 -2
- package/dist/elements/HeaderFooterManager.d.ts.map +1 -1
- package/dist/elements/HeaderFooterManager.js +36 -6
- package/dist/elements/HeaderFooterManager.js.map +1 -1
- package/dist/elements/Hyperlink.d.ts +6 -1
- package/dist/elements/Hyperlink.d.ts.map +1 -1
- package/dist/elements/Hyperlink.js +69 -44
- package/dist/elements/Hyperlink.js.map +1 -1
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +33 -6
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/ImageManager.d.ts +1 -0
- package/dist/elements/ImageManager.d.ts.map +1 -1
- package/dist/elements/ImageManager.js +11 -0
- package/dist/elements/ImageManager.js.map +1 -1
- package/dist/elements/Paragraph.d.ts +3 -0
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +91 -26
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/Revision.d.ts +4 -0
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +369 -29
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/Run.d.ts +1 -0
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +24 -4
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +17 -7
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.d.ts.map +1 -1
- package/dist/elements/Shape.js +50 -42
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/StructuredDocumentTag.d.ts +9 -1
- package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
- package/dist/elements/StructuredDocumentTag.js +46 -6
- package/dist/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/elements/Table.d.ts +2 -0
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +90 -42
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +1 -0
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +32 -13
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableOfContents.d.ts.map +1 -1
- package/dist/elements/TableOfContents.js +5 -7
- package/dist/elements/TableOfContents.js.map +1 -1
- package/dist/elements/TableRow.d.ts +1 -0
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +16 -1
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/elements/TextBox.d.ts.map +1 -1
- package/dist/elements/TextBox.js +55 -42
- package/dist/elements/TextBox.js.map +1 -1
- package/dist/esm/core/Document.js +726 -171
- package/dist/esm/core/Document.js.map +1 -1
- package/dist/esm/core/DocumentGenerator.js +77 -25
- package/dist/esm/core/DocumentGenerator.js.map +1 -1
- package/dist/esm/core/DocumentParser.js +427 -81
- package/dist/esm/core/DocumentParser.js.map +1 -1
- package/dist/esm/core/RelationshipManager.js +2 -2
- package/dist/esm/core/RelationshipManager.js.map +1 -1
- package/dist/esm/elements/Comment.js +67 -12
- package/dist/esm/elements/Comment.js.map +1 -1
- package/dist/esm/elements/CommentManager.js +74 -16
- package/dist/esm/elements/CommentManager.js.map +1 -1
- package/dist/esm/elements/EndnoteManager.js.map +1 -1
- package/dist/esm/elements/Field.js +77 -35
- package/dist/esm/elements/Field.js.map +1 -1
- package/dist/esm/elements/FieldHelpers.js +7 -4
- package/dist/esm/elements/FieldHelpers.js.map +1 -1
- package/dist/esm/elements/Footer.js +39 -53
- package/dist/esm/elements/Footer.js.map +1 -1
- package/dist/esm/elements/FootnoteManager.js.map +1 -1
- package/dist/esm/elements/Header.js +39 -53
- package/dist/esm/elements/Header.js.map +1 -1
- package/dist/esm/elements/HeaderFooterManager.js +36 -6
- package/dist/esm/elements/HeaderFooterManager.js.map +1 -1
- package/dist/esm/elements/Hyperlink.js +69 -44
- package/dist/esm/elements/Hyperlink.js.map +1 -1
- package/dist/esm/elements/Image.js +33 -6
- package/dist/esm/elements/Image.js.map +1 -1
- package/dist/esm/elements/ImageManager.js +11 -0
- package/dist/esm/elements/ImageManager.js.map +1 -1
- package/dist/esm/elements/Paragraph.js +91 -26
- package/dist/esm/elements/Paragraph.js.map +1 -1
- package/dist/esm/elements/Revision.js +369 -29
- package/dist/esm/elements/Revision.js.map +1 -1
- package/dist/esm/elements/Run.js +24 -4
- package/dist/esm/elements/Run.js.map +1 -1
- package/dist/esm/elements/Section.js +17 -7
- package/dist/esm/elements/Section.js.map +1 -1
- package/dist/esm/elements/Shape.js +50 -42
- package/dist/esm/elements/Shape.js.map +1 -1
- package/dist/esm/elements/StructuredDocumentTag.js +46 -6
- package/dist/esm/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/esm/elements/Table.js +90 -42
- package/dist/esm/elements/Table.js.map +1 -1
- package/dist/esm/elements/TableCell.js +32 -13
- package/dist/esm/elements/TableCell.js.map +1 -1
- package/dist/esm/elements/TableOfContents.js +5 -7
- package/dist/esm/elements/TableOfContents.js.map +1 -1
- package/dist/esm/elements/TableRow.js +16 -1
- package/dist/esm/elements/TableRow.js.map +1 -1
- package/dist/esm/elements/TextBox.js +55 -42
- package/dist/esm/elements/TextBox.js.map +1 -1
- package/dist/esm/formatting/AbstractNumbering.js +1 -1
- package/dist/esm/formatting/AbstractNumbering.js.map +1 -1
- package/dist/esm/formatting/NumberingLevel.js +8 -6
- package/dist/esm/formatting/NumberingLevel.js.map +1 -1
- package/dist/esm/formatting/NumberingManager.js +16 -1
- package/dist/esm/formatting/NumberingManager.js.map +1 -1
- package/dist/esm/formatting/Style.js +14 -0
- package/dist/esm/formatting/Style.js.map +1 -1
- package/dist/esm/formatting/StylesManager.js +14 -2
- package/dist/esm/formatting/StylesManager.js.map +1 -1
- package/dist/esm/helpers/CleanupHelper.js +103 -26
- package/dist/esm/helpers/CleanupHelper.js.map +1 -1
- package/dist/esm/images/ImageOptimizer.js +52 -4
- package/dist/esm/images/ImageOptimizer.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal.js +1 -1
- package/dist/esm/internal.js.map +1 -1
- package/dist/esm/processors/CompatibilityUpgrader.js +7 -1
- package/dist/esm/processors/CompatibilityUpgrader.js.map +1 -1
- package/dist/esm/processors/InMemoryRevisionAcceptor.js +134 -13
- package/dist/esm/processors/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/esm/processors/RevisionWalker.js +58 -8
- package/dist/esm/processors/RevisionWalker.js.map +1 -1
- package/dist/esm/processors/SelectiveRevisionAcceptor.js +116 -17
- package/dist/esm/processors/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/esm/processors/cnfStyleDecoder.js +7 -7
- package/dist/esm/processors/cnfStyleDecoder.js.map +1 -1
- package/dist/esm/processors/stripTrackedChanges.js +16 -5
- package/dist/esm/processors/stripTrackedChanges.js.map +1 -1
- package/dist/esm/utils/deepClone.js +24 -11
- package/dist/esm/utils/deepClone.js.map +1 -1
- package/dist/esm/utils/units.js +1 -1
- package/dist/esm/utils/units.js.map +1 -1
- package/dist/esm/utils/validation.js +11 -23
- package/dist/esm/utils/validation.js.map +1 -1
- package/dist/esm/utils/xmlSanitization.js +131 -7
- package/dist/esm/utils/xmlSanitization.js.map +1 -1
- package/dist/esm/validation/RevisionAutoFixer.js +69 -55
- package/dist/esm/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/esm/validation/RevisionValidator.js +24 -20
- package/dist/esm/validation/RevisionValidator.js.map +1 -1
- package/dist/esm/xml/XMLBuilder.js +52 -20
- package/dist/esm/xml/XMLBuilder.js.map +1 -1
- package/dist/esm/xml/XMLParser.js +55 -13
- package/dist/esm/xml/XMLParser.js.map +1 -1
- package/dist/esm/zip/ZipHandler.js +37 -13
- package/dist/esm/zip/ZipHandler.js.map +1 -1
- package/dist/esm/zip/ZipReader.js +53 -6
- package/dist/esm/zip/ZipReader.js.map +1 -1
- package/dist/esm/zip/errors.js +7 -0
- package/dist/esm/zip/errors.js.map +1 -1
- package/dist/esm/zip/types.js +4 -0
- package/dist/esm/zip/types.js.map +1 -1
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +1 -1
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts +1 -1
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +8 -6
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/NumberingManager.d.ts.map +1 -1
- package/dist/formatting/NumberingManager.js +16 -1
- package/dist/formatting/NumberingManager.js.map +1 -1
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +14 -0
- package/dist/formatting/Style.js.map +1 -1
- package/dist/formatting/StylesManager.d.ts +2 -0
- package/dist/formatting/StylesManager.d.ts.map +1 -1
- package/dist/formatting/StylesManager.js +14 -2
- package/dist/formatting/StylesManager.js.map +1 -1
- package/dist/helpers/CleanupHelper.d.ts.map +1 -1
- package/dist/helpers/CleanupHelper.js +103 -26
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/images/ImageOptimizer.d.ts.map +1 -1
- package/dist/images/ImageOptimizer.js +52 -4
- package/dist/images/ImageOptimizer.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -1
- package/dist/internal.js.map +1 -1
- package/dist/processors/CompatibilityUpgrader.d.ts.map +1 -1
- package/dist/processors/CompatibilityUpgrader.js +7 -1
- package/dist/processors/CompatibilityUpgrader.js.map +1 -1
- package/dist/processors/InMemoryRevisionAcceptor.d.ts +1 -0
- package/dist/processors/InMemoryRevisionAcceptor.d.ts.map +1 -1
- package/dist/processors/InMemoryRevisionAcceptor.js +135 -13
- package/dist/processors/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/processors/RevisionWalker.d.ts +2 -0
- package/dist/processors/RevisionWalker.d.ts.map +1 -1
- package/dist/processors/RevisionWalker.js +58 -8
- package/dist/processors/RevisionWalker.js.map +1 -1
- package/dist/processors/SelectiveRevisionAcceptor.d.ts.map +1 -1
- package/dist/processors/SelectiveRevisionAcceptor.js +116 -17
- package/dist/processors/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/processors/cnfStyleDecoder.d.ts.map +1 -1
- package/dist/processors/cnfStyleDecoder.js +7 -7
- package/dist/processors/cnfStyleDecoder.js.map +1 -1
- package/dist/processors/stripTrackedChanges.d.ts.map +1 -1
- package/dist/processors/stripTrackedChanges.js +16 -5
- package/dist/processors/stripTrackedChanges.js.map +1 -1
- package/dist/utils/deepClone.d.ts.map +1 -1
- package/dist/utils/deepClone.js +24 -11
- package/dist/utils/deepClone.js.map +1 -1
- package/dist/utils/units.d.ts.map +1 -1
- package/dist/utils/units.js +1 -1
- package/dist/utils/units.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +11 -23
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/xmlSanitization.d.ts +2 -0
- package/dist/utils/xmlSanitization.d.ts.map +1 -1
- package/dist/utils/xmlSanitization.js +133 -7
- package/dist/utils/xmlSanitization.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.d.ts +6 -2
- package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
- package/dist/validation/RevisionAutoFixer.js +68 -54
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/validation/RevisionValidator.d.ts +2 -0
- package/dist/validation/RevisionValidator.d.ts.map +1 -1
- package/dist/validation/RevisionValidator.js +26 -21
- package/dist/validation/RevisionValidator.js.map +1 -1
- package/dist/xml/XMLBuilder.d.ts +1 -0
- package/dist/xml/XMLBuilder.d.ts.map +1 -1
- package/dist/xml/XMLBuilder.js +52 -20
- package/dist/xml/XMLBuilder.js.map +1 -1
- package/dist/xml/XMLParser.d.ts +1 -0
- package/dist/xml/XMLParser.d.ts.map +1 -1
- package/dist/xml/XMLParser.js +55 -13
- package/dist/xml/XMLParser.js.map +1 -1
- package/dist/zip/ZipHandler.d.ts.map +1 -1
- package/dist/zip/ZipHandler.js +37 -13
- package/dist/zip/ZipHandler.js.map +1 -1
- package/dist/zip/ZipReader.d.ts.map +1 -1
- package/dist/zip/ZipReader.js +52 -5
- package/dist/zip/ZipReader.js.map +1 -1
- package/dist/zip/errors.d.ts +3 -0
- package/dist/zip/errors.d.ts.map +1 -1
- package/dist/zip/errors.js +9 -1
- package/dist/zip/errors.js.map +1 -1
- package/dist/zip/types.d.ts +4 -0
- package/dist/zip/types.d.ts.map +1 -1
- package/dist/zip/types.js +4 -0
- package/dist/zip/types.js.map +1 -1
- package/package.json +2 -2
- package/src/core/Document.ts +1159 -240
- package/src/core/DocumentGenerator.ts +106 -26
- package/src/core/DocumentParser.ts +681 -114
- package/src/core/RelationshipManager.ts +446 -442
- package/src/elements/Comment.ts +123 -18
- package/src/elements/CommentManager.ts +121 -22
- package/src/elements/EndnoteManager.ts +4 -1
- package/src/elements/Field.ts +134 -43
- package/src/elements/FieldHelpers.ts +20 -4
- package/src/elements/Footer.ts +62 -67
- package/src/elements/FootnoteManager.ts +4 -1
- package/src/elements/Header.ts +62 -67
- package/src/elements/HeaderFooterManager.ts +56 -8
- package/src/elements/Hyperlink.ts +150 -55
- package/src/elements/Image.ts +51 -7
- package/src/elements/ImageManager.ts +24 -0
- package/src/elements/Paragraph.ts +161 -40
- package/src/elements/Revision.ts +446 -47
- package/src/elements/Run.ts +44 -6
- package/src/elements/Section.ts +25 -9
- package/src/elements/Shape.ts +52 -44
- package/src/elements/StructuredDocumentTag.ts +83 -8
- package/src/elements/Table.ts +151 -50
- package/src/elements/TableCell.ts +57 -17
- package/src/elements/TableOfContents.ts +10 -9
- package/src/elements/TableRow.ts +35 -3
- package/src/elements/TextBox.ts +58 -43
- package/src/formatting/AbstractNumbering.ts +4 -2
- package/src/formatting/NumberingLevel.ts +50 -12
- package/src/formatting/NumberingManager.ts +32 -3
- package/src/formatting/Style.ts +14 -0
- package/src/formatting/StylesManager.ts +29 -2
- package/src/helpers/CleanupHelper.ts +122 -30
- package/src/images/ImageOptimizer.ts +64 -5
- package/src/index.ts +7 -0
- package/src/internal.ts +1 -0
- package/src/processors/CompatibilityUpgrader.ts +15 -2
- package/src/processors/InMemoryRevisionAcceptor.ts +276 -17
- package/src/processors/RevisionWalker.ts +83 -7
- package/src/processors/SelectiveRevisionAcceptor.ts +164 -28
- package/src/processors/cnfStyleDecoder.ts +18 -12
- package/src/processors/stripTrackedChanges.ts +47 -10
- package/src/utils/deepClone.ts +48 -14
- package/src/utils/units.ts +3 -1
- package/src/utils/validation.ts +30 -32
- package/src/utils/xmlSanitization.ts +218 -22
- package/src/validation/RevisionAutoFixer.ts +109 -65
- package/src/validation/RevisionValidator.ts +48 -23
- package/src/xml/XMLBuilder.ts +82 -22
- package/src/xml/XMLParser.ts +87 -20
- package/src/zip/ZipHandler.ts +61 -21
- package/src/zip/ZipReader.ts +135 -13
- package/src/zip/errors.ts +15 -0
- package/src/zip/types.ts +44 -2
|
@@ -171,12 +171,28 @@ export class NumberingLevel {
|
|
|
171
171
|
private properties: Required<
|
|
172
172
|
Omit<
|
|
173
173
|
NumberingLevelProperties,
|
|
174
|
-
|
|
174
|
+
| 'fontSize'
|
|
175
|
+
| 'color'
|
|
176
|
+
| 'lvlRestart'
|
|
177
|
+
| 'underline'
|
|
178
|
+
| 'pStyle'
|
|
179
|
+
| 'tentative'
|
|
180
|
+
| 'tplc'
|
|
181
|
+
| 'lvlPicBulletId'
|
|
182
|
+
| 'legacy'
|
|
175
183
|
>
|
|
176
184
|
> &
|
|
177
185
|
Pick<
|
|
178
186
|
NumberingLevelProperties,
|
|
179
|
-
|
|
187
|
+
| 'fontSize'
|
|
188
|
+
| 'color'
|
|
189
|
+
| 'lvlRestart'
|
|
190
|
+
| 'underline'
|
|
191
|
+
| 'pStyle'
|
|
192
|
+
| 'tentative'
|
|
193
|
+
| 'tplc'
|
|
194
|
+
| 'lvlPicBulletId'
|
|
195
|
+
| 'legacy'
|
|
180
196
|
>;
|
|
181
197
|
|
|
182
198
|
/**
|
|
@@ -195,11 +211,14 @@ export class NumberingLevel {
|
|
|
195
211
|
properties.leftIndent !== undefined ? properties.leftIndent : 720 + properties.level * 360,
|
|
196
212
|
hangingIndent: properties.hangingIndent !== undefined ? properties.hangingIndent : 360,
|
|
197
213
|
font: properties.font || 'Calibri',
|
|
198
|
-
|
|
214
|
+
// undefined = inherit per ECMA-376 (absent w:sz/w:color rPr child);
|
|
215
|
+
// forcing defaults here would inject explicit size/color into
|
|
216
|
+
// re-serialized levels that the source document never specified
|
|
217
|
+
fontSize: properties.fontSize,
|
|
199
218
|
isLegalNumberingStyle:
|
|
200
219
|
properties.isLegalNumberingStyle !== undefined ? properties.isLegalNumberingStyle : false,
|
|
201
220
|
suffix: properties.suffix || 'tab',
|
|
202
|
-
color: properties.color
|
|
221
|
+
color: properties.color,
|
|
203
222
|
bold: properties.bold !== undefined ? properties.bold : false,
|
|
204
223
|
italic: properties.italic !== undefined ? properties.italic : false,
|
|
205
224
|
underline: properties.underline,
|
|
@@ -310,12 +329,28 @@ export class NumberingLevel {
|
|
|
310
329
|
getProperties(): Required<
|
|
311
330
|
Omit<
|
|
312
331
|
NumberingLevelProperties,
|
|
313
|
-
|
|
332
|
+
| 'fontSize'
|
|
333
|
+
| 'color'
|
|
334
|
+
| 'lvlRestart'
|
|
335
|
+
| 'underline'
|
|
336
|
+
| 'pStyle'
|
|
337
|
+
| 'tentative'
|
|
338
|
+
| 'tplc'
|
|
339
|
+
| 'lvlPicBulletId'
|
|
340
|
+
| 'legacy'
|
|
314
341
|
>
|
|
315
342
|
> &
|
|
316
343
|
Pick<
|
|
317
344
|
NumberingLevelProperties,
|
|
318
|
-
|
|
345
|
+
| 'fontSize'
|
|
346
|
+
| 'color'
|
|
347
|
+
| 'lvlRestart'
|
|
348
|
+
| 'underline'
|
|
349
|
+
| 'pStyle'
|
|
350
|
+
| 'tentative'
|
|
351
|
+
| 'tplc'
|
|
352
|
+
| 'lvlPicBulletId'
|
|
353
|
+
| 'legacy'
|
|
319
354
|
> {
|
|
320
355
|
return { ...this.properties };
|
|
321
356
|
}
|
|
@@ -616,13 +651,15 @@ export class NumberingLevel {
|
|
|
616
651
|
// ... b, bCs, i, iCs, ... color (#19), ... sz (#24), szCs (#25), ... u (#27)
|
|
617
652
|
|
|
618
653
|
// Color (#19)
|
|
619
|
-
if (this.properties.color) {
|
|
654
|
+
if (this.properties.color !== undefined) {
|
|
620
655
|
rPrChildren.push(XMLBuilder.wSelf('color', { 'w:val': this.properties.color }));
|
|
621
656
|
}
|
|
622
657
|
|
|
623
|
-
// Font size (#24, #25)
|
|
624
|
-
|
|
625
|
-
|
|
658
|
+
// Font size (#24, #25) — omit when unset so the level inherits size
|
|
659
|
+
if (this.properties.fontSize !== undefined) {
|
|
660
|
+
rPrChildren.push(XMLBuilder.wSelf('sz', { 'w:val': this.properties.fontSize.toString() }));
|
|
661
|
+
rPrChildren.push(XMLBuilder.wSelf('szCs', { 'w:val': this.properties.fontSize.toString() }));
|
|
662
|
+
}
|
|
626
663
|
|
|
627
664
|
// Underline (#27)
|
|
628
665
|
if (this.properties.underline) {
|
|
@@ -1123,9 +1160,10 @@ export class NumberingLevel {
|
|
|
1123
1160
|
if (hangingMatch?.[1]) hangingIndent = parseInt(hangingMatch[1], 10);
|
|
1124
1161
|
}
|
|
1125
1162
|
|
|
1126
|
-
// Extract font and size from <w:rPr
|
|
1163
|
+
// Extract font and size from <w:rPr>. An absent w:sz means the level
|
|
1164
|
+
// inherits its size — keep it undefined so toXML doesn't fabricate one.
|
|
1127
1165
|
let font = 'Calibri';
|
|
1128
|
-
let fontSize
|
|
1166
|
+
let fontSize: number | undefined;
|
|
1129
1167
|
|
|
1130
1168
|
const rFontsMatch = /<w:rFonts[^>]*\/>/.exec(xml);
|
|
1131
1169
|
if (rFontsMatch) {
|
|
@@ -542,6 +542,10 @@ export class NumberingManager {
|
|
|
542
542
|
numLevel.setLeftIndent(leftIndent);
|
|
543
543
|
numLevel.setHangingIndent(hangingIndent);
|
|
544
544
|
|
|
545
|
+
// NumberingLevel setters don't notify the manager; without this flag the
|
|
546
|
+
// save pipeline preserves the original numbering.xml and drops the change
|
|
547
|
+
this.markAbstractNumberingModified(instance.getAbstractNumId());
|
|
548
|
+
|
|
545
549
|
return true;
|
|
546
550
|
}
|
|
547
551
|
|
|
@@ -585,6 +589,10 @@ export class NumberingManager {
|
|
|
585
589
|
level.setHangingIndent(standardIndent.hangingIndent);
|
|
586
590
|
}
|
|
587
591
|
|
|
592
|
+
// NumberingLevel setters don't notify the manager; without this flag the
|
|
593
|
+
// save pipeline preserves the original numbering.xml and drops the change
|
|
594
|
+
this.markAbstractNumberingModified(instance.getAbstractNumId());
|
|
595
|
+
|
|
588
596
|
return true;
|
|
589
597
|
}
|
|
590
598
|
|
|
@@ -708,8 +716,10 @@ export class NumberingManager {
|
|
|
708
716
|
* For each group with >1 member, picks the lowest abstractNumId as canonical,
|
|
709
717
|
* remaps all instances pointing to non-canonical IDs, and removes duplicates.
|
|
710
718
|
*
|
|
711
|
-
*
|
|
712
|
-
*
|
|
719
|
+
* Numbering counters belong to the abstract numbering definition: instances
|
|
720
|
+
* sharing an abstractNum continue one sequence in document order unless a
|
|
721
|
+
* startOverride restarts them (ECMA-376 §17.9.27). Remapped instances get a
|
|
722
|
+
* startOverride per counted level so each list keeps its independent restart.
|
|
713
723
|
*
|
|
714
724
|
* @param options Optional configuration (e.g., protected IDs to skip)
|
|
715
725
|
* @returns Summary of what was consolidated
|
|
@@ -748,9 +758,23 @@ export class NumberingManager {
|
|
|
748
758
|
groupsConsolidated++;
|
|
749
759
|
|
|
750
760
|
// Remap instances pointing to duplicate abstractNums
|
|
761
|
+
const canonicalAbstract = this.abstractNumberings.get(canonicalId);
|
|
751
762
|
for (const instance of this.instances.values()) {
|
|
752
763
|
if (duplicateIds.has(instance.getAbstractNumId())) {
|
|
753
764
|
instance.setAbstractNumId(canonicalId);
|
|
765
|
+
|
|
766
|
+
// Counters live on the abstractNum, so without a startOverride the
|
|
767
|
+
// remapped list would continue the canonical sequence instead of
|
|
768
|
+
// restarting — bullets carry no counter and are skipped
|
|
769
|
+
if (canonicalAbstract) {
|
|
770
|
+
for (const level of canonicalAbstract.getAllLevels()) {
|
|
771
|
+
const levelIndex = level.getLevel();
|
|
772
|
+
if (level.getFormat() === 'bullet') continue;
|
|
773
|
+
if (instance.getLevelOverride(levelIndex) !== undefined) continue;
|
|
774
|
+
instance.setLevelOverride(levelIndex, level.getProperties().start);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
754
778
|
this._modifiedNumIds.add(instance.getNumId());
|
|
755
779
|
instancesRemapped++;
|
|
756
780
|
}
|
|
@@ -785,11 +809,16 @@ export class NumberingManager {
|
|
|
785
809
|
|
|
786
810
|
for (const level of abstractNum.getAllLevels()) {
|
|
787
811
|
const props = level.getProperties();
|
|
812
|
+
// pStyle, lvlPicBulletId, and legacy all affect rendering (style-to-level
|
|
813
|
+
// linkage, picture bullet image, legacy indentation), so definitions
|
|
814
|
+
// differing on any of them must not be treated as duplicates
|
|
788
815
|
parts.push(
|
|
789
816
|
`${props.level}|${props.format}|${props.text}|${props.font}|${props.fontSize}|` +
|
|
790
817
|
`${props.color}|${props.leftIndent}|${props.hangingIndent}|${props.alignment}|` +
|
|
791
818
|
`${props.start}|${props.bold}|${props.italic}|${props.underline ?? ''}|` +
|
|
792
|
-
`${props.suffix}|${props.isLegalNumberingStyle}|${props.lvlRestart ?? ''}
|
|
819
|
+
`${props.suffix}|${props.isLegalNumberingStyle}|${props.lvlRestart ?? ''}|` +
|
|
820
|
+
`${props.pStyle ?? ''}|${props.lvlPicBulletId ?? ''}|` +
|
|
821
|
+
`${JSON.stringify(props.legacy ?? null)}`
|
|
793
822
|
);
|
|
794
823
|
}
|
|
795
824
|
|
package/src/formatting/Style.ts
CHANGED
|
@@ -1636,6 +1636,8 @@ export class Style {
|
|
|
1636
1636
|
},
|
|
1637
1637
|
runFormatting: {
|
|
1638
1638
|
font: 'Verdana',
|
|
1639
|
+
fontHAnsi: 'Verdana',
|
|
1640
|
+
fontCs: 'Verdana',
|
|
1639
1641
|
size: 12,
|
|
1640
1642
|
color: '000000',
|
|
1641
1643
|
},
|
|
@@ -1684,6 +1686,8 @@ export class Style {
|
|
|
1684
1686
|
},
|
|
1685
1687
|
runFormatting: {
|
|
1686
1688
|
font: 'Verdana',
|
|
1689
|
+
fontHAnsi: 'Verdana',
|
|
1690
|
+
fontCs: 'Verdana',
|
|
1687
1691
|
size: sizes[level - 1],
|
|
1688
1692
|
bold: true,
|
|
1689
1693
|
color: '000000',
|
|
@@ -1713,6 +1717,8 @@ export class Style {
|
|
|
1713
1717
|
uiPriority: 9,
|
|
1714
1718
|
runFormatting: {
|
|
1715
1719
|
font: 'Verdana',
|
|
1720
|
+
fontHAnsi: 'Verdana',
|
|
1721
|
+
fontCs: 'Verdana',
|
|
1716
1722
|
size: sizes[level - 1],
|
|
1717
1723
|
bold: true,
|
|
1718
1724
|
color: '000000',
|
|
@@ -1738,6 +1744,8 @@ export class Style {
|
|
|
1738
1744
|
},
|
|
1739
1745
|
runFormatting: {
|
|
1740
1746
|
font: 'Verdana',
|
|
1747
|
+
fontHAnsi: 'Verdana',
|
|
1748
|
+
fontCs: 'Verdana',
|
|
1741
1749
|
size: 28,
|
|
1742
1750
|
color: '000000',
|
|
1743
1751
|
},
|
|
@@ -1762,6 +1770,8 @@ export class Style {
|
|
|
1762
1770
|
},
|
|
1763
1771
|
runFormatting: {
|
|
1764
1772
|
font: 'Verdana',
|
|
1773
|
+
fontHAnsi: 'Verdana',
|
|
1774
|
+
fontCs: 'Verdana',
|
|
1765
1775
|
size: 14,
|
|
1766
1776
|
color: '000000',
|
|
1767
1777
|
italic: true,
|
|
@@ -1798,6 +1808,8 @@ export class Style {
|
|
|
1798
1808
|
},
|
|
1799
1809
|
runFormatting: {
|
|
1800
1810
|
font: 'Verdana',
|
|
1811
|
+
fontHAnsi: 'Verdana',
|
|
1812
|
+
fontCs: 'Verdana',
|
|
1801
1813
|
size: 12,
|
|
1802
1814
|
color: '000000',
|
|
1803
1815
|
},
|
|
@@ -1818,6 +1830,8 @@ export class Style {
|
|
|
1818
1830
|
runFormatting: {
|
|
1819
1831
|
bold: true,
|
|
1820
1832
|
font: 'Verdana',
|
|
1833
|
+
fontHAnsi: 'Verdana',
|
|
1834
|
+
fontCs: 'Verdana',
|
|
1821
1835
|
size: 14,
|
|
1822
1836
|
color: '000000', // Black
|
|
1823
1837
|
},
|
|
@@ -74,6 +74,9 @@ export class StylesManager {
|
|
|
74
74
|
// Track which specific styles have been modified (for selective merging)
|
|
75
75
|
private _modifiedStyleIds = new Set<string>();
|
|
76
76
|
|
|
77
|
+
// Track which styles have been removed (for removal from original XML during merge)
|
|
78
|
+
private _removedStyleIds = new Set<string>();
|
|
79
|
+
|
|
77
80
|
// Latent styles configuration
|
|
78
81
|
private latentStyles?: LatentStylesConfig;
|
|
79
82
|
private latentStyleExceptions: LatentStyleException[] = [];
|
|
@@ -176,6 +179,9 @@ export class StylesManager {
|
|
|
176
179
|
}
|
|
177
180
|
this.styles.set(style.getStyleId(), style);
|
|
178
181
|
this._modifiedStyleIds.add(style.getStyleId());
|
|
182
|
+
// Re-adding a previously removed style cancels the pending removal —
|
|
183
|
+
// otherwise the merge would strip the style right after appending it
|
|
184
|
+
this._removedStyleIds.delete(style.getStyleId());
|
|
179
185
|
this._modified = true;
|
|
180
186
|
return this;
|
|
181
187
|
}
|
|
@@ -218,7 +224,10 @@ export class StylesManager {
|
|
|
218
224
|
const source = this.getStyle(sourceId);
|
|
219
225
|
if (!source) return undefined;
|
|
220
226
|
|
|
221
|
-
|
|
227
|
+
// Use Style.clone()'s deepClone path so nested formatting (runFormatting,
|
|
228
|
+
// paragraphFormatting, tableStyle) is fully copied — not reference-shared
|
|
229
|
+
// with the source — matching this method's documented deep-copy guarantee.
|
|
230
|
+
const props = source.clone().getProperties();
|
|
222
231
|
props.styleId = newId;
|
|
223
232
|
props.name = newName ?? newId;
|
|
224
233
|
props.isDefault = false; // Clones should never be default
|
|
@@ -249,7 +258,15 @@ export class StylesManager {
|
|
|
249
258
|
* @returns True if the style was removed
|
|
250
259
|
*/
|
|
251
260
|
removeStyle(styleId: string): boolean {
|
|
252
|
-
|
|
261
|
+
const deleted = this.styles.delete(styleId);
|
|
262
|
+
if (deleted) {
|
|
263
|
+
// Drop from the modified set so the merge cannot resurrect the style
|
|
264
|
+
// (getStyle lazily re-creates built-ins, which would re-append it)
|
|
265
|
+
this._modifiedStyleIds.delete(styleId);
|
|
266
|
+
this._removedStyleIds.add(styleId);
|
|
267
|
+
this._modified = true;
|
|
268
|
+
}
|
|
269
|
+
return deleted;
|
|
253
270
|
}
|
|
254
271
|
|
|
255
272
|
/**
|
|
@@ -276,6 +293,7 @@ export class StylesManager {
|
|
|
276
293
|
resetModified(): void {
|
|
277
294
|
this._modified = false;
|
|
278
295
|
this._modifiedStyleIds.clear();
|
|
296
|
+
this._removedStyleIds.clear();
|
|
279
297
|
}
|
|
280
298
|
|
|
281
299
|
/**
|
|
@@ -287,6 +305,15 @@ export class StylesManager {
|
|
|
287
305
|
return new Set(this._modifiedStyleIds);
|
|
288
306
|
}
|
|
289
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Gets the IDs of styles that have been removed since loading
|
|
310
|
+
* Used for removal from original styles.xml during merge
|
|
311
|
+
* @returns Set of removed style IDs
|
|
312
|
+
*/
|
|
313
|
+
getRemovedStyleIds(): Set<string> {
|
|
314
|
+
return new Set(this._removedStyleIds);
|
|
315
|
+
}
|
|
316
|
+
|
|
290
317
|
/**
|
|
291
318
|
* Gets styles by type
|
|
292
319
|
* @param type - Style type to filter by
|
|
@@ -21,6 +21,7 @@ import { Hyperlink } from '../elements/Hyperlink.js';
|
|
|
21
21
|
import { Paragraph } from '../elements/Paragraph.js';
|
|
22
22
|
import { Table } from '../elements/Table.js';
|
|
23
23
|
import { StructuredDocumentTag } from '../elements/StructuredDocumentTag.js';
|
|
24
|
+
import { StylesManager } from '../formatting/StylesManager.js';
|
|
24
25
|
|
|
25
26
|
export interface CleanupOptions {
|
|
26
27
|
/** Unlock all SDTs to enable editing */
|
|
@@ -264,24 +265,98 @@ export class CleanupHelper {
|
|
|
264
265
|
}
|
|
265
266
|
|
|
266
267
|
private cleanupStyles(): number {
|
|
267
|
-
|
|
268
|
-
// Scan all paragraphs and runs for used styles
|
|
268
|
+
const stylesManager = this.doc.getStylesManager();
|
|
269
269
|
const usedStyles = new Set<string>();
|
|
270
|
-
|
|
270
|
+
|
|
271
|
+
const collectParagraph = (para: Paragraph): void => {
|
|
271
272
|
const paraStyle = para.getFormatting().style;
|
|
272
273
|
if (paraStyle) usedStyles.add(paraStyle);
|
|
273
274
|
for (const run of para.getRuns()) {
|
|
274
275
|
const runStyle = run.getFormatting().characterStyle;
|
|
275
276
|
if (runStyle) usedStyles.add(runStyle);
|
|
276
277
|
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Body paragraphs (getAllParagraphs walks table cells and nested SDTs)
|
|
281
|
+
for (const para of this.doc.getAllParagraphs()) {
|
|
282
|
+
collectParagraph(para);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Table styles (w:tblStyle) — tables reference styles without any
|
|
286
|
+
// paragraph carrying the ID, so a paragraph-only scan misses them
|
|
287
|
+
for (const table of this.doc.getAllTables()) {
|
|
288
|
+
const tableStyle = table.getFormatting().style;
|
|
289
|
+
if (tableStyle) usedStyles.add(tableStyle);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Headers and footers live outside the body walk
|
|
293
|
+
const headerFooterManager = this.doc.getHeaderFooterManager();
|
|
294
|
+
const headerFooterElements = [
|
|
295
|
+
...headerFooterManager.getAllHeaders().flatMap((entry) => entry.header.getElements()),
|
|
296
|
+
...headerFooterManager.getAllFooters().flatMap((entry) => entry.footer.getElements()),
|
|
297
|
+
];
|
|
298
|
+
for (const element of headerFooterElements) {
|
|
299
|
+
if (element instanceof Paragraph) {
|
|
300
|
+
collectParagraph(element);
|
|
301
|
+
} else if (element instanceof Table) {
|
|
302
|
+
const tableStyle = element.getFormatting().style;
|
|
303
|
+
if (tableStyle) usedStyles.add(tableStyle);
|
|
304
|
+
for (const row of element.getRows()) {
|
|
305
|
+
for (const cell of row.getCells()) {
|
|
306
|
+
for (const para of cell.getParagraphs()) {
|
|
307
|
+
collectParagraph(para);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Footnotes and endnotes also live outside the body walk
|
|
315
|
+
for (const footnote of this.doc.getFootnoteManager().getAllFootnotes()) {
|
|
316
|
+
for (const para of footnote.getParagraphs()) {
|
|
317
|
+
collectParagraph(para);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
for (const endnote of this.doc.getEndnoteManager().getAllEndnotes()) {
|
|
321
|
+
for (const para of endnote.getParagraphs()) {
|
|
322
|
+
collectParagraph(para);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Numbering levels can bind a paragraph style (w:pStyle, ECMA-376 §17.9.23)
|
|
327
|
+
for (const abstractNum of this.doc.getNumberingManager().getAllAbstractNumberings()) {
|
|
328
|
+
for (const level of abstractNum.getAllLevels()) {
|
|
329
|
+
const pStyle = level.getParagraphStyle();
|
|
330
|
+
if (pStyle) usedStyles.add(pStyle);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Expand to basedOn/link/next ancestors transitively — removing a chain
|
|
335
|
+
// member leaves dangling references that break style resolution in Word
|
|
336
|
+
const allStyles = stylesManager.getAllStyles();
|
|
337
|
+
const stylesById = new Map(allStyles.map((style) => [style.getStyleId(), style]));
|
|
338
|
+
const pending = [...usedStyles];
|
|
339
|
+
while (pending.length > 0) {
|
|
340
|
+
const style = stylesById.get(pending.pop()!);
|
|
341
|
+
if (!style) continue;
|
|
342
|
+
const props = style.getProperties();
|
|
343
|
+
for (const ref of [props.basedOn, props.link, props.next]) {
|
|
344
|
+
if (ref && !usedStyles.has(ref)) {
|
|
345
|
+
usedStyles.add(ref);
|
|
346
|
+
pending.push(ref);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
277
349
|
}
|
|
278
350
|
|
|
279
|
-
// Remove unused styles
|
|
351
|
+
// Remove unused styles — but never built-ins or part defaults, which
|
|
352
|
+
// apply without being referenced (mirrors StylesManager.cleanupUnusedStyles)
|
|
280
353
|
let removed = 0;
|
|
281
|
-
const allStyles = this.doc.getStylesManager().getAllStyles();
|
|
282
354
|
for (const style of allStyles) {
|
|
283
|
-
|
|
284
|
-
|
|
355
|
+
const styleId = style.getStyleId();
|
|
356
|
+
if (usedStyles.has(styleId)) continue;
|
|
357
|
+
if (StylesManager.isBuiltInStyle(styleId)) continue;
|
|
358
|
+
if (style.getProperties().isDefault) continue;
|
|
359
|
+
if (stylesManager.removeStyle(styleId)) {
|
|
285
360
|
removed++;
|
|
286
361
|
}
|
|
287
362
|
}
|
|
@@ -330,38 +405,55 @@ export class CleanupHelper {
|
|
|
330
405
|
return removed;
|
|
331
406
|
}
|
|
332
407
|
|
|
408
|
+
// Lock state must be cleared on the in-memory model, not the ZIP copy of
|
|
409
|
+
// word/document.xml: prepareSave() regenerates document.xml from the model,
|
|
410
|
+
// so raw-XML edits here would be overwritten and the locks re-emitted.
|
|
333
411
|
private unlockFields(): number {
|
|
334
|
-
|
|
335
|
-
const docXml = zipHandler.getFileAsString('word/document.xml');
|
|
336
|
-
if (!docXml) return 0;
|
|
412
|
+
let count = 0;
|
|
337
413
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
414
|
+
for (const para of this.doc.getAllParagraphs()) {
|
|
415
|
+
// w:fldChar w:fldLock on complex-field runs (ECMA-376 §17.16.18).
|
|
416
|
+
// getRuns() includes runs inside revisions and hyperlinks; the
|
|
417
|
+
// returned content elements are live references, so clearing the
|
|
418
|
+
// flag mutates the run itself.
|
|
419
|
+
for (const run of para.getRuns()) {
|
|
420
|
+
for (const item of run.getContent()) {
|
|
421
|
+
if (item.type === 'fieldChar' && item.fieldCharLocked === true) {
|
|
422
|
+
item.fieldCharLocked = undefined;
|
|
423
|
+
count++;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
342
427
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
428
|
+
// w:fldLock on simple fields (w:fldSimple, ECMA-376 §17.16.16).
|
|
429
|
+
// Field keeps the flag private with no mutator, so clear it
|
|
430
|
+
// structurally — the regenerated fldSimple then omits the attribute.
|
|
431
|
+
for (const item of para.getContent()) {
|
|
432
|
+
if (item instanceof Field) {
|
|
433
|
+
const lockable = item as unknown as { fldLock?: boolean };
|
|
434
|
+
if (lockable.fldLock === true) {
|
|
435
|
+
lockable.fldLock = undefined;
|
|
436
|
+
count++;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
346
441
|
|
|
347
|
-
return
|
|
442
|
+
return count;
|
|
348
443
|
}
|
|
349
444
|
|
|
350
445
|
private unlockFrames(): number {
|
|
351
|
-
|
|
352
|
-
const docXml = zipHandler.getFileAsString('word/document.xml');
|
|
353
|
-
if (!docXml) return 0;
|
|
354
|
-
|
|
355
|
-
// Count matches first, then replace (avoid regex re-execution)
|
|
356
|
-
const pattern = /w:anchorLock="(1|true)"/g;
|
|
357
|
-
const matches = docXml.match(pattern) || [];
|
|
358
|
-
if (matches.length === 0) return 0;
|
|
446
|
+
let count = 0;
|
|
359
447
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
448
|
+
for (const para of this.doc.getAllParagraphs()) {
|
|
449
|
+
const framePr = para.getFormatting().framePr;
|
|
450
|
+
if (framePr?.anchorLock === true) {
|
|
451
|
+
para.setFrameProperties({ ...framePr, anchorLock: undefined });
|
|
452
|
+
count++;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
363
455
|
|
|
364
|
-
return
|
|
456
|
+
return count;
|
|
365
457
|
}
|
|
366
458
|
|
|
367
459
|
private sanitizeTables(): number {
|
|
@@ -144,6 +144,26 @@ export function optimizePng(buffer: Buffer): Buffer | null {
|
|
|
144
144
|
// BMP → PNG Conversion
|
|
145
145
|
// =============================================================================
|
|
146
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Maps a 32-bit BI_BITFIELDS channel mask to its byte index within a
|
|
149
|
+
* little-endian pixel. Only byte-aligned 8-bit masks map losslessly onto
|
|
150
|
+
* PNG's 8-bit channels; anything else returns null.
|
|
151
|
+
*/
|
|
152
|
+
function maskToByteIndex(mask: number): number | null {
|
|
153
|
+
switch (mask) {
|
|
154
|
+
case 0x000000ff:
|
|
155
|
+
return 0;
|
|
156
|
+
case 0x0000ff00:
|
|
157
|
+
return 1;
|
|
158
|
+
case 0x00ff0000:
|
|
159
|
+
return 2;
|
|
160
|
+
case 0xff000000:
|
|
161
|
+
return 3;
|
|
162
|
+
default:
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
147
167
|
/**
|
|
148
168
|
* Converts a BMP buffer to PNG format. Lossless conversion.
|
|
149
169
|
* Supports 24-bit (RGB) and 32-bit (RGBA) uncompressed BMPs.
|
|
@@ -186,6 +206,45 @@ export function convertBmpToPng(buffer: Buffer): Buffer | null {
|
|
|
186
206
|
// Validate buffer has enough pixel data
|
|
187
207
|
if (pixelDataOffset + absHeight * rowSize > buffer.length) return null;
|
|
188
208
|
|
|
209
|
+
// Channel byte offsets within a pixel; defaults match the standard BGR(A) layout
|
|
210
|
+
let rOff = 2;
|
|
211
|
+
let gOff = 1;
|
|
212
|
+
let bOff = 0;
|
|
213
|
+
let aOff = 3;
|
|
214
|
+
let forceOpaqueAlpha = false;
|
|
215
|
+
|
|
216
|
+
if (bitsPerPixel === 32) {
|
|
217
|
+
if (compression === 3) {
|
|
218
|
+
// BI_BITFIELDS: channel masks follow BITMAPINFOHEADER (the same file
|
|
219
|
+
// offsets hold the masks inside V4/V5 headers), so they must be honored
|
|
220
|
+
// to keep the conversion lossless
|
|
221
|
+
if (buffer.length < 66) return null;
|
|
222
|
+
const rIdx = maskToByteIndex(buffer.readUInt32LE(54));
|
|
223
|
+
const gIdx = maskToByteIndex(buffer.readUInt32LE(58));
|
|
224
|
+
const bIdx = maskToByteIndex(buffer.readUInt32LE(62));
|
|
225
|
+
if (rIdx === null || gIdx === null || bIdx === null) return null;
|
|
226
|
+
if (rIdx === gIdx || rIdx === bIdx || gIdx === bIdx) return null;
|
|
227
|
+
rOff = rIdx;
|
|
228
|
+
gOff = gIdx;
|
|
229
|
+
bOff = bIdx;
|
|
230
|
+
aOff = 6 - rIdx - gIdx - bIdx; // the byte not claimed by R/G/B carries alpha
|
|
231
|
+
} else {
|
|
232
|
+
// BI_RGB: the 4th byte is reserved and writers commonly zero it, so
|
|
233
|
+
// copying it as alpha would render the whole image transparent. Treat it
|
|
234
|
+
// as alpha only when at least one pixel carries a non-zero value.
|
|
235
|
+
forceOpaqueAlpha = true;
|
|
236
|
+
for (let y = 0; forceOpaqueAlpha && y < absHeight; y++) {
|
|
237
|
+
const rowOffset = pixelDataOffset + y * rowSize;
|
|
238
|
+
for (let x = 0; x < width; x++) {
|
|
239
|
+
if (buffer[rowOffset + x * 4 + 3] !== 0) {
|
|
240
|
+
forceOpaqueAlpha = false;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
189
248
|
// PNG color type: 2 = RGB (24-bit), 6 = RGBA (32-bit)
|
|
190
249
|
const colorType = bitsPerPixel === 32 ? 6 : 2;
|
|
191
250
|
const pngBytesPerPixel = bitsPerPixel === 32 ? 4 : 3;
|
|
@@ -216,13 +275,13 @@ export function convertBmpToPng(buffer: Buffer): Buffer | null {
|
|
|
216
275
|
const bmpPixelOffset = bmpRowOffset + x * bytesPerPixel;
|
|
217
276
|
const pngPixelOffset = pngRowOffset + 1 + x * pngBytesPerPixel;
|
|
218
277
|
|
|
219
|
-
//
|
|
220
|
-
rawData[pngPixelOffset] = buffer[bmpPixelOffset +
|
|
221
|
-
rawData[pngPixelOffset + 1] = buffer[bmpPixelOffset +
|
|
222
|
-
rawData[pngPixelOffset + 2] = buffer[bmpPixelOffset]!; // B
|
|
278
|
+
// Route channels by resolved byte offsets (BGR(A) unless masks say otherwise)
|
|
279
|
+
rawData[pngPixelOffset] = buffer[bmpPixelOffset + rOff]!; // R
|
|
280
|
+
rawData[pngPixelOffset + 1] = buffer[bmpPixelOffset + gOff]!; // G
|
|
281
|
+
rawData[pngPixelOffset + 2] = buffer[bmpPixelOffset + bOff]!; // B
|
|
223
282
|
|
|
224
283
|
if (bitsPerPixel === 32) {
|
|
225
|
-
rawData[pngPixelOffset + 3] = buffer[bmpPixelOffset +
|
|
284
|
+
rawData[pngPixelOffset + 3] = forceOpaqueAlpha ? 0xff : buffer[bmpPixelOffset + aOff]!; // A
|
|
226
285
|
}
|
|
227
286
|
}
|
|
228
287
|
}
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export {
|
|
|
13
13
|
DocumentOptions,
|
|
14
14
|
DocumentLoadOptions,
|
|
15
15
|
DocumentPart,
|
|
16
|
+
MarkdownConversionOptions,
|
|
16
17
|
} from './core/Document.js';
|
|
17
18
|
|
|
18
19
|
// =============================================================================
|
|
@@ -411,6 +412,12 @@ export {
|
|
|
411
412
|
CorruptionType,
|
|
412
413
|
} from './utils/corruptionDetection.js';
|
|
413
414
|
export { isError, toError, wrapError, getErrorMessage } from './utils/errorHandling.js';
|
|
415
|
+
// Deliberately on the stable path: ResourceLimitError is the security-relevant,
|
|
416
|
+
// catchable error thrown by Document.load/loadFromBuffer for oversized/zip-bomb
|
|
417
|
+
// untrusted input, and SizeLimitOptions is its tuning type. The rest of the
|
|
418
|
+
// DocxError hierarchy stays on the `docxmlater/internal` subpath.
|
|
419
|
+
export { ResourceLimitError } from './zip/errors.js';
|
|
420
|
+
export type { SizeLimitOptions } from './zip/types.js';
|
|
414
421
|
export {
|
|
415
422
|
REVISION_RULES,
|
|
416
423
|
ValidationSeverity,
|
package/src/internal.ts
CHANGED
|
@@ -67,9 +67,22 @@ export class CompatibilityUpgrader {
|
|
|
67
67
|
const selfClosingCompat = /<w:compat\s*\/>/.exec(settingsXml);
|
|
68
68
|
|
|
69
69
|
if (!compatBlockMatch && !selfClosingCompat) {
|
|
70
|
-
// No w:compat block — insert a full modern block
|
|
70
|
+
// No w:compat block — insert a full modern block. CT_Settings is an
|
|
71
|
+
// xsd:sequence where w:compat must precede rsids, mathPr, themeFontLang,
|
|
72
|
+
// clrSchemeMapping, shapeDefaults, decimalSymbol, and listSeparator, so
|
|
73
|
+
// anchor before the earliest of those; append before </w:settings> only
|
|
74
|
+
// when none are present.
|
|
71
75
|
const modernBlock = CompatibilityUpgrader.buildModernCompatBlock(MODERN_COMPAT_SETTINGS);
|
|
72
|
-
const
|
|
76
|
+
const followingSibling =
|
|
77
|
+
/<(?:w:rsids|m:mathPr|w:themeFontLang|w:clrSchemeMapping|w:shapeDefaults|w:decimalSymbol|w:listSeparator)[\s/>]/.exec(
|
|
78
|
+
settingsXml
|
|
79
|
+
);
|
|
80
|
+
const xml = followingSibling
|
|
81
|
+
? settingsXml.slice(0, followingSibling.index) +
|
|
82
|
+
modernBlock +
|
|
83
|
+
'\n ' +
|
|
84
|
+
settingsXml.slice(followingSibling.index)
|
|
85
|
+
: settingsXml.replace(/<\/w:settings>/, modernBlock + '\n</w:settings>');
|
|
73
86
|
|
|
74
87
|
for (const s of MODERN_COMPAT_SETTINGS) {
|
|
75
88
|
addedSettings.push(s.name);
|