docxmlater 11.0.9 → 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 +431 -85
- 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 +431 -85
- 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 +692 -120
- 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
|
@@ -27,18 +27,18 @@ const BIT_POSITIONS = {
|
|
|
27
27
|
swCell: 11,
|
|
28
28
|
};
|
|
29
29
|
export const CONDITIONAL_PRIORITY_ORDER = [
|
|
30
|
-
'nwCell',
|
|
31
|
-
'neCell',
|
|
32
|
-
'swCell',
|
|
33
30
|
'seCell',
|
|
34
|
-
'
|
|
31
|
+
'swCell',
|
|
32
|
+
'neCell',
|
|
33
|
+
'nwCell',
|
|
35
34
|
'lastRow',
|
|
36
|
-
'
|
|
35
|
+
'firstRow',
|
|
37
36
|
'lastCol',
|
|
38
|
-
'
|
|
37
|
+
'firstCol',
|
|
39
38
|
'band2Horz',
|
|
40
|
-
'
|
|
39
|
+
'band1Horz',
|
|
41
40
|
'band2Vert',
|
|
41
|
+
'band1Vert',
|
|
42
42
|
];
|
|
43
43
|
export function decodeCnfStyle(cnfStyle) {
|
|
44
44
|
const normalized = cnfStyle.padEnd(12, '0');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cnfStyleDecoder.js","sourceRoot":"","sources":["../../../src/processors/cnfStyleDecoder.ts"],"names":[],"mappings":"AA4CA,MAAM,CAAC,MAAM,sBAAsB,GAA2D;IAC5F,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;CACjB,CAAC;AAMF,MAAM,aAAa,GAAwC;IACzD,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,EAAE;CACX,CAAC;
|
|
1
|
+
{"version":3,"file":"cnfStyleDecoder.js","sourceRoot":"","sources":["../../../src/processors/cnfStyleDecoder.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * cnfStyle Decoder - Decodes the conditional formatting style bitmask\n * Per ECMA-376 Part 1 Section 17.4.7 (w:cnfStyle)\n *\n * The cnfStyle is a 12-character string where each character is '0' or '1'\n * representing whether a particular conditional format applies.\n */\n\nimport { ConditionalFormattingType } from '../formatting/Style.js';\n\n/**\n * Decoded cnfStyle flags\n * Each flag corresponds to a conditional formatting type that may apply to a cell\n */\nexport interface CnfStyleFlags {\n /** First row of table (header row) */\n firstRow: boolean;\n /** Last row of table */\n lastRow: boolean;\n /** First column of table */\n firstCol: boolean;\n /** Last column of table */\n lastCol: boolean;\n /** Odd vertical band (column banding) */\n band1Vert: boolean;\n /** Even vertical band (column banding) */\n band2Vert: boolean;\n /** Odd horizontal band (row banding) */\n band1Horz: boolean;\n /** Even horizontal band (row banding) */\n band2Horz: boolean;\n /** Northeast cell (top-right corner) */\n neCell: boolean;\n /** Northwest cell (top-left corner) */\n nwCell: boolean;\n /** Southeast cell (bottom-right corner) */\n seCell: boolean;\n /** Southwest cell (bottom-left corner) */\n swCell: boolean;\n}\n\n/**\n * Maps flag names to ConditionalFormattingType values\n */\nexport const CNF_TO_CONDITIONAL_MAP: Record<keyof CnfStyleFlags, ConditionalFormattingType> = {\n firstRow: 'firstRow',\n lastRow: 'lastRow',\n firstCol: 'firstCol',\n lastCol: 'lastCol',\n band1Vert: 'band1Vert',\n band2Vert: 'band2Vert',\n band1Horz: 'band1Horz',\n band2Horz: 'band2Horz',\n neCell: 'neCell',\n nwCell: 'nwCell',\n seCell: 'seCell',\n swCell: 'swCell',\n};\n\n/**\n * Bit positions in the cnfStyle string (0-indexed from left)\n * Per ECMA-376 Part 1 Section 17.4.7\n */\nconst BIT_POSITIONS: Record<keyof CnfStyleFlags, number> = {\n firstRow: 0,\n lastRow: 1,\n firstCol: 2,\n lastCol: 3,\n band1Vert: 4,\n band2Vert: 5,\n band1Horz: 6,\n band2Horz: 7,\n neCell: 8,\n nwCell: 9,\n seCell: 10,\n swCell: 11,\n};\n\n/**\n * Priority order for conditional formatting resolution\n *\n * ECMA-376 §17.7.6.6 applies conditional formats in sequence (banding, then\n * first/last row, first/last column, then corners top-left through\n * bottom-right) with subsequent formats overriding earlier ones. First-match\n * consumers need the opposite: the last-applied (winning) member of each\n * group listed first, so when two conditionals in the same group co-apply\n * (e.g. firstRow + lastRow in a single-row table) resolution picks the one\n * Word actually renders.\n */\nexport const CONDITIONAL_PRIORITY_ORDER: (keyof CnfStyleFlags)[] = [\n // Corner cells (most specific; spec applies nw, ne, sw, se — se wins)\n 'seCell',\n 'swCell',\n 'neCell',\n 'nwCell',\n // Edge rows/columns (within each pair, last is applied after first)\n 'lastRow',\n 'firstRow',\n 'lastCol',\n 'firstCol',\n // Banding (least specific; even banding is applied after odd)\n 'band2Horz',\n 'band1Horz',\n 'band2Vert',\n 'band1Vert',\n];\n\n/**\n * Decodes a cnfStyle string into individual flags\n *\n * @param cnfStyle - 12-character binary string (e.g., \"100000000000\" for firstRow)\n * @returns Decoded flags object\n *\n * @example\n * ```typescript\n * const flags = decodeCnfStyle('100000000000');\n * console.log(flags.firstRow); // true\n * console.log(flags.lastRow); // false\n * ```\n */\nexport function decodeCnfStyle(cnfStyle: string): CnfStyleFlags {\n // Pad to 12 characters if shorter (handles legacy or truncated values)\n // Use padEnd because the string represents left-to-right bit positions\n const normalized = cnfStyle.padEnd(12, '0');\n\n return {\n firstRow: normalized.startsWith('1'),\n lastRow: normalized[BIT_POSITIONS.lastRow] === '1',\n firstCol: normalized[BIT_POSITIONS.firstCol] === '1',\n lastCol: normalized[BIT_POSITIONS.lastCol] === '1',\n band1Vert: normalized[BIT_POSITIONS.band1Vert] === '1',\n band2Vert: normalized[BIT_POSITIONS.band2Vert] === '1',\n band1Horz: normalized[BIT_POSITIONS.band1Horz] === '1',\n band2Horz: normalized[BIT_POSITIONS.band2Horz] === '1',\n neCell: normalized[BIT_POSITIONS.neCell] === '1',\n nwCell: normalized[BIT_POSITIONS.nwCell] === '1',\n seCell: normalized[BIT_POSITIONS.seCell] === '1',\n swCell: normalized[BIT_POSITIONS.swCell] === '1',\n };\n}\n\n/**\n * Encodes CnfStyleFlags back to a binary string\n *\n * @param flags - Flags to encode\n * @returns 12-character binary string\n *\n * @example\n * ```typescript\n * const cnfStyle = encodeCnfStyle({ firstRow: true, lastCol: true });\n * console.log(cnfStyle); // '100100000000'\n * ```\n */\nexport function encodeCnfStyle(flags: Partial<CnfStyleFlags>): string {\n const bits = new Array(12).fill('0');\n\n for (const [key, position] of Object.entries(BIT_POSITIONS)) {\n if (flags[key as keyof CnfStyleFlags]) {\n bits[position] = '1';\n }\n }\n\n return bits.join('');\n}\n\n/**\n * Gets the active conditional formatting types from a cnfStyle\n *\n * @param cnfStyle - The cnfStyle string to decode\n * @returns Array of active ConditionalFormattingType values\n *\n * @example\n * ```typescript\n * const types = getActiveConditionals('110000000000');\n * console.log(types); // ['firstRow', 'lastRow']\n * ```\n */\nexport function getActiveConditionals(cnfStyle: string): ConditionalFormattingType[] {\n const flags = decodeCnfStyle(cnfStyle);\n const active: ConditionalFormattingType[] = [];\n\n for (const [key, isActive] of Object.entries(flags)) {\n if (isActive) {\n active.push(CNF_TO_CONDITIONAL_MAP[key as keyof CnfStyleFlags]);\n }\n }\n\n return active;\n}\n\n/**\n * Gets the active conditional formatting types in priority order\n * More specific conditions come first (corners before edges before banding)\n *\n * @param cnfStyle - The cnfStyle string to decode\n * @returns Array of active ConditionalFormattingType values in priority order\n *\n * @example\n * ```typescript\n * // Cell is both in first row and is the nwCell (top-left corner)\n * const types = getActiveConditionalsInPriorityOrder('100000000100');\n * console.log(types); // ['nwCell', 'firstRow'] - corner takes priority\n * ```\n */\nexport function getActiveConditionalsInPriorityOrder(\n cnfStyle: string\n): ConditionalFormattingType[] {\n const flags = decodeCnfStyle(cnfStyle);\n const active: ConditionalFormattingType[] = [];\n\n for (const flagName of CONDITIONAL_PRIORITY_ORDER) {\n if (flags[flagName]) {\n active.push(CNF_TO_CONDITIONAL_MAP[flagName]);\n }\n }\n\n return active;\n}\n"]}
|
|
@@ -27,11 +27,12 @@ class TrackedChangesStripper {
|
|
|
27
27
|
let content = xml;
|
|
28
28
|
content = this.removeRangeMarkers(content);
|
|
29
29
|
content = this.processInsertions(content);
|
|
30
|
+
content = this.removeDeletedRows(content);
|
|
31
|
+
content = this.removeSelfClosingRevisionTags(content);
|
|
30
32
|
content = this.processDeletions(content);
|
|
31
33
|
content = this.processMoveFrom(content);
|
|
32
34
|
content = this.processMoveTo(content);
|
|
33
35
|
content = this.removePropertyChanges(content);
|
|
34
|
-
content = this.removeSelfClosingRevisionTags(content);
|
|
35
36
|
this.zipHandler.updateFile(partPath, content);
|
|
36
37
|
}
|
|
37
38
|
removeRangeMarkers(xml) {
|
|
@@ -75,6 +76,16 @@ class TrackedChangesStripper {
|
|
|
75
76
|
result = result.replace(/<w:ins[\s>][^>]*>/g, '');
|
|
76
77
|
return result;
|
|
77
78
|
}
|
|
79
|
+
removeDeletedRows(xml) {
|
|
80
|
+
const rowDelPattern = /<w:tr\b[^>]*>(?:(?!<w:tc\b|<w:tr\b|<\/w:tr>)[\s\S])*?<w:trPr\b(?:\s[^>]*)?>(?:(?!<\/w:trPr>)[\s\S])*?<w:del\b[^>]*\/>(?:(?!<\/w:trPr>)[\s\S])*?<\/w:trPr>(?:(?!<w:tr\b|<\/w:tr>)[\s\S])*?<\/w:tr>/g;
|
|
81
|
+
let result = xml;
|
|
82
|
+
let previousLength = 0;
|
|
83
|
+
while (result.length !== previousLength) {
|
|
84
|
+
previousLength = result.length;
|
|
85
|
+
result = result.replace(rowDelPattern, '');
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
78
89
|
processDeletions(xml) {
|
|
79
90
|
let result = xml;
|
|
80
91
|
let previousLength = 0;
|
|
@@ -119,10 +130,10 @@ class TrackedChangesStripper {
|
|
|
119
130
|
}
|
|
120
131
|
removeSelfClosingRevisionTags(xml) {
|
|
121
132
|
const patterns = [
|
|
122
|
-
/<w:ins\
|
|
123
|
-
/<w:del\
|
|
124
|
-
/<w:moveFrom\
|
|
125
|
-
/<w:moveTo\
|
|
133
|
+
/<w:ins\b[^>]*\/>/g,
|
|
134
|
+
/<w:del\b[^>]*\/>/g,
|
|
135
|
+
/<w:moveFrom\b[^>]*\/>/g,
|
|
136
|
+
/<w:moveTo\b[^>]*\/>/g,
|
|
126
137
|
];
|
|
127
138
|
let result = xml;
|
|
128
139
|
for (const pattern of patterns) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stripTrackedChanges.js","sourceRoot":"","sources":["../../../src/processors/stripTrackedChanges.ts"],"names":[],"mappings":"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","sourcesContent":["import { ZipHandler } from '../zip/ZipHandler.js';\n\n/**\n * Strips all tracked changes markup from a Word document\n * This includes insertions, deletions, move operations, and property changes\n * Also cleans up related metadata in people.xml, settings.xml, and core.xml\n */\nclass TrackedChangesStripper {\n private zipHandler: ZipHandler;\n\n constructor(zipHandler: ZipHandler) {\n this.zipHandler = zipHandler;\n }\n\n /**\n * Main method to strip all tracked changes from the document.\n *\n * Per ECMA-376 Part 1, tracked-change markup can appear in any\n * part that carries block-level content: the body (§17.2 w:body),\n * headers / footers (§17.10.3-4 CT_HdrFtr), footnotes (§17.11.15),\n * endnotes (§17.11.4), and comments (§17.13.4). All of these\n * must be walked — stripping document.xml alone would leave\n * tracked changes visible in Word for every header / footer /\n * note / comment revision.\n */\n public async stripTrackedChanges(): Promise<void> {\n // Always process the body.\n await this.stripPartRevisions('word/document.xml');\n\n // Process every header and footer part present in the ZIP.\n for (const file of this.zipHandler.getFilePaths()) {\n if (/^word\\/header\\d+\\.xml$/.exec(file) || /^word\\/footer\\d+\\.xml$/.exec(file)) {\n await this.stripPartRevisions(file);\n }\n }\n\n // Process singleton notes / comments parts when present.\n for (const path of ['word/footnotes.xml', 'word/endnotes.xml', 'word/comments.xml']) {\n if (this.zipHandler.getFileAsString(path)) {\n await this.stripPartRevisions(path);\n }\n }\n\n // Clean up metadata files\n await this.cleanupPeopleXml();\n await this.cleanupSettingsXml();\n await this.cleanupCorePropsXml();\n }\n\n /**\n * Strip ALL revision elements from a single document part.\n * The per-step pipeline is identical to the historical\n * document.xml implementation; the only difference is the\n * configurable source path.\n */\n private async stripPartRevisions(partPath: string): Promise<void> {\n const xml = this.zipHandler.getFileAsString(partPath);\n if (!xml) {\n return;\n }\n\n let content = xml;\n\n // STEP 1: Remove all range markers (boundary markers for tracked changes)\n content = this.removeRangeMarkers(content);\n\n // STEP 2: Process insertions - keep content, remove wrapper\n content = this.processInsertions(content);\n\n // STEP 3: Process deletions - remove entirely\n content = this.processDeletions(content);\n\n // STEP 4: Process move operations\n content = this.processMoveFrom(content);\n content = this.processMoveTo(content);\n\n // STEP 5: Remove all property change tracking elements\n content = this.removePropertyChanges(content);\n\n // STEP 6: Remove any remaining self-closing revision tags\n content = this.removeSelfClosingRevisionTags(content);\n\n // Update the file in the zip\n this.zipHandler.updateFile(partPath, content);\n }\n\n /**\n * Remove all range marker elements\n */\n private removeRangeMarkers(xml: string): string {\n const patterns = [\n /<w:moveFromRangeStart[^>]*\\/>/g,\n /<w:moveFromRangeEnd[^>]*\\/>/g,\n /<w:moveToRangeStart[^>]*\\/>/g,\n /<w:moveToRangeEnd[^>]*\\/>/g,\n /<w:customXmlInsRangeStart[^>]*\\/>/g,\n /<w:customXmlInsRangeEnd[^>]*\\/>/g,\n /<w:customXmlDelRangeStart[^>]*\\/>/g,\n /<w:customXmlDelRangeEnd[^>]*\\/>/g,\n /<w:customXmlMoveFromRangeStart[^>]*\\/>/g,\n /<w:customXmlMoveFromRangeEnd[^>]*\\/>/g,\n /<w:customXmlMoveToRangeStart[^>]*\\/>/g,\n /<w:customXmlMoveToRangeEnd[^>]*\\/>/g,\n ];\n\n let result = xml;\n for (const pattern of patterns) {\n result = result.replace(pattern, '');\n }\n\n return result;\n }\n\n /**\n * Process <w:ins> elements - keep inner content, remove wrapper\n * Handles orphaned tags by removing opening and closing tags separately\n *\n * IMPORTANT: This method now handles relationship ID remapping for images inside insertions.\n * When Word tracks changes with images, it can reuse relationship IDs (like rId5) because\n * they're in separate tracked change contexts. But when we unwrap them, duplicate IDs\n * cause corruption. This method assigns new unique IDs to images inside insertions.\n */\n private processInsertions(xml: string): string {\n let result = xml;\n\n // Parse existing relationships\n const relationships = this.parseRelationships();\n const existingIds = new Set(relationships.keys());\n\n // Process each w:ins element and remap images one by one\n const insRegex = /<w:ins\\b[^>]*>[\\s\\S]*?<\\/w:ins>/g;\n\n result = result.replace(insRegex, (insMatch) => {\n // For each image reference inside this insertion, generate a unique new ID\n return insMatch.replace(/r:embed=\"(rId\\d+)\"/g, (_embedMatch, oldId) => {\n // Generate new unique ID for THIS occurrence\n const newId = this.getNextRelationshipId(existingIds);\n existingIds.add(newId);\n\n // Add relationship with same target as original\n const target = relationships.get(oldId);\n if (target) {\n this.addRelationship(\n newId,\n target,\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image'\n );\n }\n\n return `r:embed=\"${newId}\"`;\n });\n });\n\n // First, remove all closing tags\n result = result.replace(/<\\/w:ins>/g, '');\n\n // Then, remove all opening tags (keeping any content that follows)\n result = result.replace(/<w:ins[\\s>][^>]*>/g, '');\n\n return result;\n }\n\n /**\n * Process <w:del> elements - remove entire element\n * Uses iterative replacement to handle nested deletions\n */\n private processDeletions(xml: string): string {\n let result = xml;\n let previousLength = 0;\n\n // Keep replacing until no more changes (handles nested revisions)\n while (result.length !== previousLength) {\n previousLength = result.length;\n\n // Match entire deletion element and remove it\n // Use [\\s>] to match either space or closing bracket\n result = result.replace(/<w:del[\\s>][^>]*>.*?<\\/w:del>/gs, '');\n }\n\n return result;\n }\n\n /**\n * Process <w:moveFrom> elements - remove entire element (source of move)\n * Uses iterative replacement to handle nested moves\n */\n private processMoveFrom(xml: string): string {\n let result = xml;\n let previousLength = 0;\n\n // Keep replacing until no more changes\n while (result.length !== previousLength) {\n previousLength = result.length;\n\n // Use [\\s>] to match either space or closing bracket\n result = result.replace(/<w:moveFrom[\\s>][^>]*>.*?<\\/w:moveFrom>/gs, '');\n }\n\n return result;\n }\n\n /**\n * Process <w:moveTo> elements - keep inner content (destination of move)\n * Handles orphaned tags by removing opening and closing tags separately\n */\n private processMoveTo(xml: string): string {\n let result = xml;\n\n // First, remove all closing tags\n result = result.replace(/<\\/w:moveTo>/g, '');\n\n // Then, remove all opening tags (keeping any content that follows)\n result = result.replace(/<w:moveTo[\\s>][^>]*>/g, '');\n\n return result;\n }\n\n /**\n * Remove all property change tracking elements\n */\n private removePropertyChanges(xml: string): string {\n const patterns = [\n /<w:rPrChange[^>]*>.*?<\\/w:rPrChange>/gs, // Run property changes\n /<w:pPrChange[^>]*>.*?<\\/w:pPrChange>/gs, // Paragraph property changes\n /<w:tblPrChange[^>]*>.*?<\\/w:tblPrChange>/gs, // Table property changes\n /<w:tblPrExChange[^>]*>.*?<\\/w:tblPrExChange>/gs, // Table property exception changes\n /<w:tcPrChange[^>]*>.*?<\\/w:tcPrChange>/gs, // Table cell property changes\n /<w:trPrChange[^>]*>.*?<\\/w:trPrChange>/gs, // Table row property changes\n /<w:sectPrChange[^>]*>.*?<\\/w:sectPrChange>/gs, // Section property changes\n /<w:tblGridChange[^>]*>.*?<\\/w:tblGridChange>/gs, // Table grid changes\n /<w:numberingChange[^>]*>.*?<\\/w:numberingChange>/gs, // Numbering changes\n ];\n\n let result = xml;\n for (const pattern of patterns) {\n result = result.replace(pattern, '');\n }\n\n return result;\n }\n\n /**\n * Remove self-closing revision tags\n */\n private removeSelfClosingRevisionTags(xml: string): string {\n const patterns = [\n /<w:ins\\s+[^>]*\\/>/g,\n /<w:del\\s+[^>]*\\/>/g,\n /<w:moveFrom\\s+[^>]*\\/>/g,\n /<w:moveTo\\s+[^>]*\\/>/g,\n ];\n\n let result = xml;\n for (const pattern of patterns) {\n result = result.replace(pattern, '');\n }\n\n return result;\n }\n\n /**\n * Parse relationship IDs from word/_rels/document.xml.rels\n * Returns a map of relationship ID to target path\n */\n private parseRelationships(): Map<string, string> {\n const relsXml = this.zipHandler.getFileAsString('word/_rels/document.xml.rels');\n if (!relsXml) return new Map();\n\n const map = new Map<string, string>();\n const relationshipRegex = /<Relationship[^>]*Id=\"([^\"]+)\"[^>]*Target=\"([^\"]+)\"[^>]*\\/>/g;\n let match;\n\n while ((match = relationshipRegex.exec(relsXml)) !== null) {\n if (match[1] && match[2]) {\n map.set(match[1], match[2]); // rId -> target path\n }\n }\n\n return map;\n }\n\n /**\n * Get the next available relationship ID\n * Finds the highest numeric ID and increments it\n */\n private getNextRelationshipId(existingIds: Set<string>): string {\n let maxId = 0;\n for (const id of existingIds) {\n const num = parseInt(id.replace('rId', ''));\n if (!isNaN(num) && num > maxId) {\n maxId = num;\n }\n }\n return `rId${maxId + 1}`;\n }\n\n /**\n * Add a new relationship to word/_rels/document.xml.rels\n */\n private addRelationship(rId: string, target: string, type: string): void {\n const relsXml = this.zipHandler.getFileAsString('word/_rels/document.xml.rels');\n if (!relsXml) return;\n\n // Insert new relationship before closing tag\n const newRel = `<Relationship Id=\"${rId}\" Type=\"${type}\" Target=\"${target}\"/>`;\n const updated = relsXml.replace('</Relationships>', `${newRel}\\n</Relationships>`);\n\n this.zipHandler.updateFile('word/_rels/document.xml.rels', updated);\n }\n\n /**\n * Clean up word/people.xml - remove revision authors\n */\n private async cleanupPeopleXml(): Promise<void> {\n const peopleXml = this.zipHandler.getFileAsString('word/people.xml');\n if (!peopleXml) {\n return;\n }\n\n let content = peopleXml;\n\n // Remove all <w:person> elements (standard namespace)\n content = content.replace(/<w:person[^>]*>.*?<\\/w:person>/gs, '');\n\n // Remove all <w15:person> elements (Word 2013+ namespace)\n content = content.replace(/<w15:person[^>]*>.*?<\\/w15:person>/gs, '');\n\n // Remove any other namespace variants of person elements\n content = content.replace(/<w\\d*:person[^>]*>.*?<\\/w\\d*:person>/gs, '');\n\n this.zipHandler.updateFile('word/people.xml', content);\n }\n\n /**\n * Clean up word/settings.xml - disable track changes\n */\n private async cleanupSettingsXml(): Promise<void> {\n const settingsXml = this.zipHandler.getFileAsString('word/settings.xml');\n if (!settingsXml) {\n return;\n }\n\n let content = settingsXml;\n\n // Remove track changes settings\n content = content.replace(/<w:trackRevisions[^>]*\\/>/g, '');\n content = content.replace(/<w:trackRevisions[^>]*>.*?<\\/w:trackRevisions>/gs, '');\n\n // Remove revision view settings\n content = content.replace(/<w:revisionView[^>]*\\/>/g, '');\n content = content.replace(/<w:revisionView[^>]*>.*?<\\/w:revisionView>/gs, '');\n\n this.zipHandler.updateFile('word/settings.xml', content);\n }\n\n /**\n * Clean up docProps/core.xml - reset revision count\n */\n private async cleanupCorePropsXml(): Promise<void> {\n const coreXml = this.zipHandler.getFileAsString('docProps/core.xml');\n if (!coreXml) {\n return;\n }\n\n // Reset revision count to 1\n const content = coreXml.replace(\n /<cp:revision>\\d+<\\/cp:revision>/g,\n '<cp:revision>1</cp:revision>'\n );\n\n this.zipHandler.updateFile('docProps/core.xml', content);\n }\n}\n\n/**\n * Convenience function to strip tracked changes from a ZipHandler\n */\nexport async function stripTrackedChanges(zipHandler: ZipHandler): Promise<void> {\n const stripper = new TrackedChangesStripper(zipHandler);\n await stripper.stripTrackedChanges();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stripTrackedChanges.js","sourceRoot":"","sources":["../../../src/processors/stripTrackedChanges.ts"],"names":[],"mappings":"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","sourcesContent":["import { ZipHandler } from '../zip/ZipHandler.js';\n\n/**\n * Strips all tracked changes markup from a Word document\n * This includes insertions, deletions, move operations, and property changes\n * Also cleans up related metadata in people.xml, settings.xml, and core.xml\n */\nclass TrackedChangesStripper {\n private zipHandler: ZipHandler;\n\n constructor(zipHandler: ZipHandler) {\n this.zipHandler = zipHandler;\n }\n\n /**\n * Main method to strip all tracked changes from the document.\n *\n * Per ECMA-376 Part 1, tracked-change markup can appear in any\n * part that carries block-level content: the body (§17.2 w:body),\n * headers / footers (§17.10.3-4 CT_HdrFtr), footnotes (§17.11.15),\n * endnotes (§17.11.4), and comments (§17.13.4). All of these\n * must be walked — stripping document.xml alone would leave\n * tracked changes visible in Word for every header / footer /\n * note / comment revision.\n */\n public async stripTrackedChanges(): Promise<void> {\n // Always process the body.\n await this.stripPartRevisions('word/document.xml');\n\n // Process every header and footer part present in the ZIP.\n for (const file of this.zipHandler.getFilePaths()) {\n if (/^word\\/header\\d+\\.xml$/.exec(file) || /^word\\/footer\\d+\\.xml$/.exec(file)) {\n await this.stripPartRevisions(file);\n }\n }\n\n // Process singleton notes / comments parts when present.\n for (const path of ['word/footnotes.xml', 'word/endnotes.xml', 'word/comments.xml']) {\n if (this.zipHandler.getFileAsString(path)) {\n await this.stripPartRevisions(path);\n }\n }\n\n // Clean up metadata files\n await this.cleanupPeopleXml();\n await this.cleanupSettingsXml();\n await this.cleanupCorePropsXml();\n }\n\n /**\n * Strip ALL revision elements from a single document part.\n * The per-step pipeline is identical to the historical\n * document.xml implementation; the only difference is the\n * configurable source path.\n */\n private async stripPartRevisions(partPath: string): Promise<void> {\n const xml = this.zipHandler.getFileAsString(partPath);\n if (!xml) {\n return;\n }\n\n let content = xml;\n\n // STEP 1: Remove all range markers (boundary markers for tracked changes)\n content = this.removeRangeMarkers(content);\n\n // STEP 2: Process insertions - keep content, remove wrapper\n content = this.processInsertions(content);\n\n // STEP 3: Remove rows whose w:trPr carries a row-deletion marker\n // (self-closing <w:del/> per ECMA-376 §17.13.5.14 marks the ENTIRE\n // row as deleted). Must run before the marker itself is stripped in\n // STEP 4, otherwise the row would silently survive as un-deleted.\n content = this.removeDeletedRows(content);\n\n // STEP 4: Remove self-closing revision markers (paragraph-mark\n // deletions in w:pPr/w:rPr per ECMA-376 §17.13.5.15, etc.). Must run\n // BEFORE the block-removal steps: their [^>]* also matches the\n // trailing '/' of `<w:del .../>`, which would turn the marker into an\n // opening tag and swallow everything up to the next closing tag,\n // corrupting the part.\n content = this.removeSelfClosingRevisionTags(content);\n\n // STEP 5: Process deletions - remove entirely\n content = this.processDeletions(content);\n\n // STEP 6: Process move operations\n content = this.processMoveFrom(content);\n content = this.processMoveTo(content);\n\n // STEP 7: Remove all property change tracking elements\n content = this.removePropertyChanges(content);\n\n // Update the file in the zip\n this.zipHandler.updateFile(partPath, content);\n }\n\n /**\n * Remove all range marker elements\n */\n private removeRangeMarkers(xml: string): string {\n const patterns = [\n /<w:moveFromRangeStart[^>]*\\/>/g,\n /<w:moveFromRangeEnd[^>]*\\/>/g,\n /<w:moveToRangeStart[^>]*\\/>/g,\n /<w:moveToRangeEnd[^>]*\\/>/g,\n /<w:customXmlInsRangeStart[^>]*\\/>/g,\n /<w:customXmlInsRangeEnd[^>]*\\/>/g,\n /<w:customXmlDelRangeStart[^>]*\\/>/g,\n /<w:customXmlDelRangeEnd[^>]*\\/>/g,\n /<w:customXmlMoveFromRangeStart[^>]*\\/>/g,\n /<w:customXmlMoveFromRangeEnd[^>]*\\/>/g,\n /<w:customXmlMoveToRangeStart[^>]*\\/>/g,\n /<w:customXmlMoveToRangeEnd[^>]*\\/>/g,\n ];\n\n let result = xml;\n for (const pattern of patterns) {\n result = result.replace(pattern, '');\n }\n\n return result;\n }\n\n /**\n * Process <w:ins> elements - keep inner content, remove wrapper\n * Handles orphaned tags by removing opening and closing tags separately\n *\n * IMPORTANT: This method now handles relationship ID remapping for images inside insertions.\n * When Word tracks changes with images, it can reuse relationship IDs (like rId5) because\n * they're in separate tracked change contexts. But when we unwrap them, duplicate IDs\n * cause corruption. This method assigns new unique IDs to images inside insertions.\n */\n private processInsertions(xml: string): string {\n let result = xml;\n\n // Parse existing relationships\n const relationships = this.parseRelationships();\n const existingIds = new Set(relationships.keys());\n\n // Process each w:ins element and remap images one by one\n const insRegex = /<w:ins\\b[^>]*>[\\s\\S]*?<\\/w:ins>/g;\n\n result = result.replace(insRegex, (insMatch) => {\n // For each image reference inside this insertion, generate a unique new ID\n return insMatch.replace(/r:embed=\"(rId\\d+)\"/g, (_embedMatch, oldId) => {\n // Generate new unique ID for THIS occurrence\n const newId = this.getNextRelationshipId(existingIds);\n existingIds.add(newId);\n\n // Add relationship with same target as original\n const target = relationships.get(oldId);\n if (target) {\n this.addRelationship(\n newId,\n target,\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image'\n );\n }\n\n return `r:embed=\"${newId}\"`;\n });\n });\n\n // First, remove all closing tags\n result = result.replace(/<\\/w:ins>/g, '');\n\n // Then, remove all opening tags (keeping any content that follows)\n result = result.replace(/<w:ins[\\s>][^>]*>/g, '');\n\n return result;\n }\n\n /**\n * Remove entire <w:tr> rows marked as tracked deletions.\n *\n * Per ECMA-376 Part 1 §17.13.5.14, a self-closing `<w:del/>` inside\n * `<w:trPr>` marks the whole row as deleted — stripping just the marker\n * would resurrect the row instead of removing it. Mirrors the row-level\n * pass in acceptRevisions.ts: the negative lookaheads keep the match\n * anchored to a single row (it cannot slip past a cell boundary or a\n * nested-table row and latch onto a later row's trPr-with-del).\n */\n private removeDeletedRows(xml: string): string {\n const rowDelPattern =\n /<w:tr\\b[^>]*>(?:(?!<w:tc\\b|<w:tr\\b|<\\/w:tr>)[\\s\\S])*?<w:trPr\\b(?:\\s[^>]*)?>(?:(?!<\\/w:trPr>)[\\s\\S])*?<w:del\\b[^>]*\\/>(?:(?!<\\/w:trPr>)[\\s\\S])*?<\\/w:trPr>(?:(?!<w:tr\\b|<\\/w:tr>)[\\s\\S])*?<\\/w:tr>/g;\n\n let result = xml;\n let previousLength = 0;\n while (result.length !== previousLength) {\n previousLength = result.length;\n result = result.replace(rowDelPattern, '');\n }\n\n return result;\n }\n\n /**\n * Process <w:del> elements - remove entire element\n * Uses iterative replacement to handle nested deletions\n */\n private processDeletions(xml: string): string {\n let result = xml;\n let previousLength = 0;\n\n // Keep replacing until no more changes (handles nested revisions)\n while (result.length !== previousLength) {\n previousLength = result.length;\n\n // Match entire deletion element and remove it\n // Use [\\s>] to match either space or closing bracket\n result = result.replace(/<w:del[\\s>][^>]*>.*?<\\/w:del>/gs, '');\n }\n\n return result;\n }\n\n /**\n * Process <w:moveFrom> elements - remove entire element (source of move)\n * Uses iterative replacement to handle nested moves\n */\n private processMoveFrom(xml: string): string {\n let result = xml;\n let previousLength = 0;\n\n // Keep replacing until no more changes\n while (result.length !== previousLength) {\n previousLength = result.length;\n\n // Use [\\s>] to match either space or closing bracket\n result = result.replace(/<w:moveFrom[\\s>][^>]*>.*?<\\/w:moveFrom>/gs, '');\n }\n\n return result;\n }\n\n /**\n * Process <w:moveTo> elements - keep inner content (destination of move)\n * Handles orphaned tags by removing opening and closing tags separately\n */\n private processMoveTo(xml: string): string {\n let result = xml;\n\n // First, remove all closing tags\n result = result.replace(/<\\/w:moveTo>/g, '');\n\n // Then, remove all opening tags (keeping any content that follows)\n result = result.replace(/<w:moveTo[\\s>][^>]*>/g, '');\n\n return result;\n }\n\n /**\n * Remove all property change tracking elements\n */\n private removePropertyChanges(xml: string): string {\n const patterns = [\n /<w:rPrChange[^>]*>.*?<\\/w:rPrChange>/gs, // Run property changes\n /<w:pPrChange[^>]*>.*?<\\/w:pPrChange>/gs, // Paragraph property changes\n /<w:tblPrChange[^>]*>.*?<\\/w:tblPrChange>/gs, // Table property changes\n /<w:tblPrExChange[^>]*>.*?<\\/w:tblPrExChange>/gs, // Table property exception changes\n /<w:tcPrChange[^>]*>.*?<\\/w:tcPrChange>/gs, // Table cell property changes\n /<w:trPrChange[^>]*>.*?<\\/w:trPrChange>/gs, // Table row property changes\n /<w:sectPrChange[^>]*>.*?<\\/w:sectPrChange>/gs, // Section property changes\n /<w:tblGridChange[^>]*>.*?<\\/w:tblGridChange>/gs, // Table grid changes\n /<w:numberingChange[^>]*>.*?<\\/w:numberingChange>/gs, // Numbering changes\n ];\n\n let result = xml;\n for (const pattern of patterns) {\n result = result.replace(pattern, '');\n }\n\n return result;\n }\n\n /**\n * Remove self-closing revision tags\n * `\\b` (not `\\s+`) so attribute-less markers like `<w:del/>` are also\n * caught while `<w:delText>` is not.\n */\n private removeSelfClosingRevisionTags(xml: string): string {\n const patterns = [\n /<w:ins\\b[^>]*\\/>/g,\n /<w:del\\b[^>]*\\/>/g,\n /<w:moveFrom\\b[^>]*\\/>/g,\n /<w:moveTo\\b[^>]*\\/>/g,\n ];\n\n let result = xml;\n for (const pattern of patterns) {\n result = result.replace(pattern, '');\n }\n\n return result;\n }\n\n /**\n * Parse relationship IDs from word/_rels/document.xml.rels\n * Returns a map of relationship ID to target path\n */\n private parseRelationships(): Map<string, string> {\n const relsXml = this.zipHandler.getFileAsString('word/_rels/document.xml.rels');\n if (!relsXml) return new Map();\n\n const map = new Map<string, string>();\n const relationshipRegex = /<Relationship[^>]*Id=\"([^\"]+)\"[^>]*Target=\"([^\"]+)\"[^>]*\\/>/g;\n let match;\n\n while ((match = relationshipRegex.exec(relsXml)) !== null) {\n if (match[1] && match[2]) {\n map.set(match[1], match[2]); // rId -> target path\n }\n }\n\n return map;\n }\n\n /**\n * Get the next available relationship ID\n * Finds the highest numeric ID and increments it\n */\n private getNextRelationshipId(existingIds: Set<string>): string {\n let maxId = 0;\n for (const id of existingIds) {\n const num = parseInt(id.replace('rId', ''));\n if (!isNaN(num) && num > maxId) {\n maxId = num;\n }\n }\n return `rId${maxId + 1}`;\n }\n\n /**\n * Add a new relationship to word/_rels/document.xml.rels\n */\n private addRelationship(rId: string, target: string, type: string): void {\n const relsXml = this.zipHandler.getFileAsString('word/_rels/document.xml.rels');\n if (!relsXml) return;\n\n // Insert new relationship before closing tag\n const newRel = `<Relationship Id=\"${rId}\" Type=\"${type}\" Target=\"${target}\"/>`;\n const updated = relsXml.replace('</Relationships>', `${newRel}\\n</Relationships>`);\n\n this.zipHandler.updateFile('word/_rels/document.xml.rels', updated);\n }\n\n /**\n * Clean up word/people.xml - remove revision authors\n */\n private async cleanupPeopleXml(): Promise<void> {\n const peopleXml = this.zipHandler.getFileAsString('word/people.xml');\n if (!peopleXml) {\n return;\n }\n\n let content = peopleXml;\n\n // Remove all <w:person> elements (standard namespace)\n content = content.replace(/<w:person[^>]*>.*?<\\/w:person>/gs, '');\n\n // Remove all <w15:person> elements (Word 2013+ namespace)\n content = content.replace(/<w15:person[^>]*>.*?<\\/w15:person>/gs, '');\n\n // Remove any other namespace variants of person elements\n content = content.replace(/<w\\d*:person[^>]*>.*?<\\/w\\d*:person>/gs, '');\n\n this.zipHandler.updateFile('word/people.xml', content);\n }\n\n /**\n * Clean up word/settings.xml - disable track changes\n */\n private async cleanupSettingsXml(): Promise<void> {\n const settingsXml = this.zipHandler.getFileAsString('word/settings.xml');\n if (!settingsXml) {\n return;\n }\n\n let content = settingsXml;\n\n // Remove track changes settings\n content = content.replace(/<w:trackRevisions[^>]*\\/>/g, '');\n content = content.replace(/<w:trackRevisions[^>]*>.*?<\\/w:trackRevisions>/gs, '');\n\n // Remove revision view settings\n content = content.replace(/<w:revisionView[^>]*\\/>/g, '');\n content = content.replace(/<w:revisionView[^>]*>.*?<\\/w:revisionView>/gs, '');\n\n this.zipHandler.updateFile('word/settings.xml', content);\n }\n\n /**\n * Clean up docProps/core.xml - reset revision count\n */\n private async cleanupCorePropsXml(): Promise<void> {\n const coreXml = this.zipHandler.getFileAsString('docProps/core.xml');\n if (!coreXml) {\n return;\n }\n\n // Reset revision count to 1\n const content = coreXml.replace(\n /<cp:revision>\\d+<\\/cp:revision>/g,\n '<cp:revision>1</cp:revision>'\n );\n\n this.zipHandler.updateFile('docProps/core.xml', content);\n }\n}\n\n/**\n * Convenience function to strip tracked changes from a ZipHandler\n */\nexport async function stripTrackedChanges(zipHandler: ZipHandler): Promise<void> {\n const stripper = new TrackedChangesStripper(zipHandler);\n await stripper.stripTrackedChanges();\n}\n"]}
|
|
@@ -1,39 +1,52 @@
|
|
|
1
1
|
export function deepClone(obj) {
|
|
2
|
+
return cloneInternal(obj, new WeakMap());
|
|
3
|
+
}
|
|
4
|
+
function cloneInternal(obj, seen) {
|
|
2
5
|
if (obj === null || typeof obj !== 'object') {
|
|
3
6
|
return obj;
|
|
4
7
|
}
|
|
8
|
+
const existing = seen.get(obj);
|
|
9
|
+
if (existing !== undefined) {
|
|
10
|
+
return existing;
|
|
11
|
+
}
|
|
5
12
|
if (obj instanceof Date) {
|
|
6
|
-
|
|
13
|
+
const dateCopy = new Date(obj.getTime());
|
|
14
|
+
seen.set(obj, dateCopy);
|
|
15
|
+
return dateCopy;
|
|
16
|
+
}
|
|
17
|
+
if (obj instanceof RegExp) {
|
|
18
|
+
const regexpCopy = new RegExp(obj.source, obj.flags);
|
|
19
|
+
seen.set(obj, regexpCopy);
|
|
20
|
+
return regexpCopy;
|
|
7
21
|
}
|
|
8
22
|
if (Array.isArray(obj)) {
|
|
9
23
|
const arrCopy = [];
|
|
24
|
+
seen.set(obj, arrCopy);
|
|
10
25
|
for (let i = 0; i < obj.length; i++) {
|
|
11
|
-
arrCopy[i] =
|
|
26
|
+
arrCopy[i] = cloneInternal(obj[i], seen);
|
|
12
27
|
}
|
|
13
28
|
return arrCopy;
|
|
14
29
|
}
|
|
15
30
|
if (obj instanceof Map) {
|
|
16
31
|
const mapCopy = new Map();
|
|
32
|
+
seen.set(obj, mapCopy);
|
|
17
33
|
obj.forEach((value, key) => {
|
|
18
|
-
mapCopy.set(
|
|
34
|
+
mapCopy.set(cloneInternal(key, seen), cloneInternal(value, seen));
|
|
19
35
|
});
|
|
20
36
|
return mapCopy;
|
|
21
37
|
}
|
|
22
38
|
if (obj instanceof Set) {
|
|
23
39
|
const setCopy = new Set();
|
|
40
|
+
seen.set(obj, setCopy);
|
|
24
41
|
obj.forEach((value) => {
|
|
25
|
-
setCopy.add(
|
|
42
|
+
setCopy.add(cloneInternal(value, seen));
|
|
26
43
|
});
|
|
27
44
|
return setCopy;
|
|
28
45
|
}
|
|
29
|
-
if (obj instanceof RegExp) {
|
|
30
|
-
return new RegExp(obj.source, obj.flags);
|
|
31
|
-
}
|
|
32
46
|
const objCopy = Object.create(Object.getPrototypeOf(obj));
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
47
|
+
seen.set(obj, objCopy);
|
|
48
|
+
for (const key of Object.keys(obj)) {
|
|
49
|
+
objCopy[key] = cloneInternal(obj[key], seen);
|
|
37
50
|
}
|
|
38
51
|
return objCopy;
|
|
39
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepClone.js","sourceRoot":"","sources":["../../../src/utils/deepClone.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deepClone.js","sourceRoot":"","sources":["../../../src/utils/deepClone.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Deep clone utility for safely cloning objects\n * More efficient and type-safe than JSON.parse(JSON.stringify())\n */\n\n/**\n * Deep clone an object using structured cloning\n * Preserves most object types including Date, RegExp, Map, Set, etc.\n *\n * For simple objects (like formatting options), this is more efficient\n * than JSON.parse(JSON.stringify()) and doesn't lose non-serializable values.\n *\n * Cyclic and shared references are handled via an internal seen-cache: an\n * object encountered more than once during a single clone is cloned exactly\n * once, so circular graphs cannot overflow the stack and shared sub-objects\n * (including shared Date and RegExp instances) retain a single shared identity\n * in the result.\n *\n * @param obj - Object to clone\n * @returns Deep cloned copy of the object\n *\n * @example\n * ```typescript\n * const original = { bold: true, color: \"FF0000\", date: new Date() };\n * const cloned = deepClone(original);\n * cloned.bold = false;\n * console.log(original.bold); // true (unchanged)\n * console.log(cloned.date instanceof Date); // true (preserved)\n * ```\n */\nexport function deepClone<T>(obj: T): T {\n // Map of already-cloned source objects to their clones, scoped to this call.\n // Guards against infinite recursion on cyclic input and preserves the\n // identity of references shared by multiple parents within the same graph.\n return cloneInternal(obj, new WeakMap<object, unknown>());\n}\n\nfunction cloneInternal<T>(obj: T, seen: WeakMap<object, unknown>): T {\n // Handle primitive types and null\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n // Return the existing clone for any object already seen in this call. Placed\n // before the Date/RegExp branches so a single Date/RegExp instance shared by\n // multiple nodes resolves to one shared clone (the JSDoc shared-identity\n // guarantee), not a fresh copy per reference.\n const existing = seen.get(obj as object);\n if (existing !== undefined) {\n return existing as T;\n }\n\n // Handle Date (immutable value copy; cannot form a cycle). Registered in\n // `seen` so repeat references to the same instance share this clone.\n if (obj instanceof Date) {\n const dateCopy = new Date(obj.getTime());\n seen.set(obj as object, dateCopy);\n return dateCopy as T;\n }\n\n // Handle RegExp (immutable value copy; cannot form a cycle). Registered in\n // `seen` so repeat references to the same instance share this clone.\n if (obj instanceof RegExp) {\n const regexpCopy = new RegExp(obj.source, obj.flags);\n seen.set(obj as object, regexpCopy);\n return regexpCopy as T;\n }\n\n // Handle Array\n if (Array.isArray(obj)) {\n const arrCopy: unknown[] = [];\n // Register before recursing so self/back references resolve to this clone.\n seen.set(obj as object, arrCopy);\n for (let i = 0; i < obj.length; i++) {\n arrCopy[i] = cloneInternal(obj[i], seen);\n }\n return arrCopy as T;\n }\n\n // Handle Map\n if (obj instanceof Map) {\n const mapCopy = new Map();\n seen.set(obj, mapCopy);\n obj.forEach((value, key) => {\n mapCopy.set(cloneInternal(key, seen), cloneInternal(value, seen));\n });\n return mapCopy as T;\n }\n\n // Handle Set\n if (obj instanceof Set) {\n const setCopy = new Set();\n seen.set(obj, setCopy);\n obj.forEach((value) => {\n setCopy.add(cloneInternal(value, seen));\n });\n return setCopy as T;\n }\n\n // Handle plain objects\n const objCopy = Object.create(Object.getPrototypeOf(obj)) as Record<string, unknown>;\n seen.set(obj as object, objCopy);\n // Object.keys avoids the prototype-builtins shadowing risk of\n // obj.hasOwnProperty(key) (matches sibling deepEqual.ts) and yields the same\n // own-enumerable string keys the previous for..in + hasOwnProperty loop did.\n for (const key of Object.keys(obj as object)) {\n objCopy[key] = cloneInternal((obj as Record<string, unknown>)[key], seen);\n }\n\n return objCopy as T;\n}\n"]}
|
package/dist/esm/utils/units.js
CHANGED
|
@@ -39,7 +39,7 @@ export function emusToPixels(emus, dpi = STANDARD_DPI) {
|
|
|
39
39
|
return Math.round((emus / UNITS.EMUS_PER_INCH) * dpi);
|
|
40
40
|
}
|
|
41
41
|
export function pointsToTwips(points) {
|
|
42
|
-
return points * UNITS.TWIPS_PER_POINT;
|
|
42
|
+
return Math.round(points * UNITS.TWIPS_PER_POINT);
|
|
43
43
|
}
|
|
44
44
|
export function pointsToEmus(points) {
|
|
45
45
|
return Math.round(points * UNITS.EMUS_PER_POINT);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"units.js","sourceRoot":"","sources":["../../../src/utils/units.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unit Conversion Utilities\n *\n * Word documents use multiple measurement units:\n * - Twips: 1/20th of a point (used for most measurements like margins, indents)\n * - EMUs: English Metric Units (used for DrawingML, images)\n * - Points: Typography unit (72 points = 1 inch)\n * - Pixels: Screen measurement (depends on DPI)\n * - Inches/Centimeters: Human-readable units\n *\n * Conversion factors:\n * - 1 inch = 72 points = 1440 twips = 914,400 EMUs\n * - 1 cm = 0.393701 inches = 360,000 EMUs\n * - 1 point = 20 twips = 12,700 EMUs\n */\n\n/**\n * Standard DPI (dots per inch) for screen displays\n */\nexport const STANDARD_DPI = 96;\n\n/**\n * Conversion constants\n */\nexport const UNITS = {\n /** EMUs per inch */\n EMUS_PER_INCH: 914400,\n /** Twips per inch */\n TWIPS_PER_INCH: 1440,\n /** Points per inch */\n POINTS_PER_INCH: 72,\n /** Twips per point */\n TWIPS_PER_POINT: 20,\n /** EMUs per twip */\n EMUS_PER_TWIP: 635,\n /** EMUs per point */\n EMUS_PER_POINT: 12700,\n /** EMUs per centimeter */\n EMUS_PER_CM: 360000,\n /** Inches per centimeter */\n INCHES_PER_CM: 0.393701,\n /** Centimeters per inch */\n CM_PER_INCH: 2.54,\n /** Half-points per point (Word uses half-points for font sizes) */\n HALF_POINTS_PER_POINT: 2,\n} as const;\n\n// ============================================================================\n// Twips Conversions\n// ============================================================================\n\n/**\n * Converts twips to points\n * @param twips Value in twips\n * @returns Value in points\n */\nexport function twipsToPoints(twips: number): number {\n return twips / UNITS.TWIPS_PER_POINT;\n}\n\n/**\n * Converts twips to inches\n * @param twips Value in twips\n * @returns Value in inches\n */\nexport function twipsToInches(twips: number): number {\n return twips / UNITS.TWIPS_PER_INCH;\n}\n\n/**\n * Converts twips to centimeters\n * @param twips Value in twips\n * @returns Value in centimeters\n */\nexport function twipsToCm(twips: number): number {\n return twipsToInches(twips) * UNITS.CM_PER_INCH;\n}\n\n/**\n * Converts twips to EMUs\n * @param twips Value in twips\n * @returns Value in EMUs\n */\nexport function twipsToEmus(twips: number): number {\n return Math.round(twips * UNITS.EMUS_PER_TWIP);\n}\n\n// ============================================================================\n// EMUs Conversions\n// ============================================================================\n\n/**\n * Converts EMUs to twips\n * @param emus Value in EMUs\n * @returns Value in twips\n */\nexport function emusToTwips(emus: number): number {\n return Math.round(emus / UNITS.EMUS_PER_TWIP);\n}\n\n/**\n * Converts EMUs to inches\n * @param emus Value in EMUs\n * @returns Value in inches\n */\nexport function emusToInches(emus: number): number {\n return emus / UNITS.EMUS_PER_INCH;\n}\n\n/**\n * Converts EMUs to centimeters\n * @param emus Value in EMUs\n * @returns Value in centimeters\n */\nexport function emusToCm(emus: number): number {\n return emus / UNITS.EMUS_PER_CM;\n}\n\n/**\n * Converts EMUs to points\n * @param emus Value in EMUs\n * @returns Value in points\n */\nexport function emusToPoints(emus: number): number {\n return emus / UNITS.EMUS_PER_POINT;\n}\n\n/**\n * Converts EMUs to pixels\n * @param emus Value in EMUs\n * @param dpi Dots per inch (default: 96)\n * @returns Value in pixels\n */\nexport function emusToPixels(emus: number, dpi: number = STANDARD_DPI): number {\n return Math.round((emus / UNITS.EMUS_PER_INCH) * dpi);\n}\n\n// ============================================================================\n// Points Conversions\n// ============================================================================\n\n/**\n * Converts points to twips\n * @param points Value in points\n * @returns Value in twips\n */\nexport function pointsToTwips(points: number): number {\n return points * UNITS.TWIPS_PER_POINT;\n}\n\n/**\n * Converts points to EMUs\n * @param points Value in points\n * @returns Value in EMUs\n */\nexport function pointsToEmus(points: number): number {\n return Math.round(points * UNITS.EMUS_PER_POINT);\n}\n\n/**\n * Converts points to inches\n * @param points Value in points\n * @returns Value in inches\n */\nexport function pointsToInches(points: number): number {\n return points / UNITS.POINTS_PER_INCH;\n}\n\n/**\n * Converts points to centimeters\n * @param points Value in points\n * @returns Value in centimeters\n */\nexport function pointsToCm(points: number): number {\n return pointsToInches(points) * UNITS.CM_PER_INCH;\n}\n\n// ============================================================================\n// Half-Points Conversions (Word uses half-points for font sizes)\n// ============================================================================\n\n/**\n * Converts points to half-points (for Word font size storage)\n * @param points Value in points\n * @returns Value in half-points\n */\nexport function pointsToHalfPoints(points: number): number {\n // Round to nearest integer — w:sz/w:szCs require ST_HpsMeasure (unsigned integer)\n return Math.round(points * UNITS.HALF_POINTS_PER_POINT);\n}\n\n/**\n * Converts half-points to points (from Word font size storage)\n * @param halfPoints Value in half-points\n * @returns Value in points\n */\nexport function halfPointsToPoints(halfPoints: number): number {\n return halfPoints / UNITS.HALF_POINTS_PER_POINT;\n}\n\n// ============================================================================\n// Inches Conversions\n// ============================================================================\n\n/**\n * Converts inches to twips\n * @param inches Value in inches\n * @returns Value in twips\n */\nexport function inchesToTwips(inches: number): number {\n return Math.round(inches * UNITS.TWIPS_PER_INCH);\n}\n\n/**\n * Converts inches to EMUs\n * @param inches Value in inches\n * @returns Value in EMUs\n */\nexport function inchesToEmus(inches: number): number {\n return Math.round(inches * UNITS.EMUS_PER_INCH);\n}\n\n/**\n * Converts inches to points\n * @param inches Value in inches\n * @returns Value in points\n */\nexport function inchesToPoints(inches: number): number {\n return inches * UNITS.POINTS_PER_INCH;\n}\n\n/**\n * Converts inches to centimeters\n * @param inches Value in inches\n * @returns Value in centimeters\n */\nexport function inchesToCm(inches: number): number {\n return inches * UNITS.CM_PER_INCH;\n}\n\n/**\n * Converts inches to pixels\n * @param inches Value in inches\n * @param dpi Dots per inch (default: 96)\n * @returns Value in pixels\n */\nexport function inchesToPixels(inches: number, dpi: number = STANDARD_DPI): number {\n return Math.round(inches * dpi);\n}\n\n// ============================================================================\n// Centimeters Conversions\n// ============================================================================\n\n/**\n * Converts centimeters to twips\n * @param cm Value in centimeters\n * @returns Value in twips\n */\nexport function cmToTwips(cm: number): number {\n return inchesToTwips(cm * UNITS.INCHES_PER_CM);\n}\n\n/**\n * Converts centimeters to EMUs\n * @param cm Value in centimeters\n * @returns Value in EMUs\n */\nexport function cmToEmus(cm: number): number {\n return Math.round(cm * UNITS.EMUS_PER_CM);\n}\n\n/**\n * Converts centimeters to inches\n * @param cm Value in centimeters\n * @returns Value in inches\n */\nexport function cmToInches(cm: number): number {\n return cm * UNITS.INCHES_PER_CM;\n}\n\n/**\n * Converts centimeters to points\n * @param cm Value in centimeters\n * @returns Value in points\n */\nexport function cmToPoints(cm: number): number {\n return inchesToPoints(cmToInches(cm));\n}\n\n/**\n * Converts centimeters to pixels\n * @param cm Value in centimeters\n * @param dpi Dots per inch (default: 96)\n * @returns Value in pixels\n */\nexport function cmToPixels(cm: number, dpi: number = STANDARD_DPI): number {\n return inchesToPixels(cmToInches(cm), dpi);\n}\n\n// ============================================================================\n// Pixels Conversions\n// ============================================================================\n\n/**\n * Converts pixels to EMUs\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in EMUs\n */\nexport function pixelsToEmus(pixels: number, dpi: number = STANDARD_DPI): number {\n return Math.round((pixels / dpi) * UNITS.EMUS_PER_INCH);\n}\n\n/**\n * Converts pixels to inches\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in inches\n */\nexport function pixelsToInches(pixels: number, dpi: number = STANDARD_DPI): number {\n return pixels / dpi;\n}\n\n/**\n * Converts pixels to twips\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in twips\n */\nexport function pixelsToTwips(pixels: number, dpi: number = STANDARD_DPI): number {\n return inchesToTwips(pixelsToInches(pixels, dpi));\n}\n\n/**\n * Converts pixels to centimeters\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in centimeters\n */\nexport function pixelsToCm(pixels: number, dpi: number = STANDARD_DPI): number {\n return pixelsToInches(pixels, dpi) * UNITS.CM_PER_INCH;\n}\n\n/**\n * Converts pixels to points\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in points\n */\nexport function pixelsToPoints(pixels: number, dpi: number = STANDARD_DPI): number {\n return inchesToPoints(pixelsToInches(pixels, dpi));\n}\n\n// ============================================================================\n// Common Document Sizes (in twips)\n// ============================================================================\n\n/**\n * Common page sizes in twips\n */\nexport const PAGE_SIZES = {\n /** Letter (8.5\" x 11\") */\n LETTER: {\n width: 12240, // 8.5 inches\n height: 15840, // 11 inches\n },\n /** A4 (21cm x 29.7cm) */\n A4: {\n width: 11906, // 21cm\n height: 16838, // 29.7cm\n },\n /** Legal (8.5\" x 14\") */\n LEGAL: {\n width: 12240, // 8.5 inches\n height: 20160, // 14 inches\n },\n /** Tabloid (11\" x 17\") */\n TABLOID: {\n width: 15840, // 11 inches\n height: 24480, // 17 inches\n },\n /** A3 (29.7cm x 42cm) */\n A3: {\n width: 16838, // 29.7cm\n height: 23811, // 42cm\n },\n} as const;\n\n/**\n * Common margin sizes in twips\n */\nexport const COMMON_MARGINS = {\n /** Normal margins (1 inch all around) */\n NORMAL: {\n top: 1440,\n bottom: 1440,\n left: 1440,\n right: 1440,\n },\n /** Narrow margins (0.5 inch all around) */\n NARROW: {\n top: 720,\n bottom: 720,\n left: 720,\n right: 720,\n },\n /** Wide margins (2 inches left/right, 1 inch top/bottom) */\n WIDE: {\n top: 1440,\n bottom: 1440,\n left: 2880,\n right: 2880,\n },\n /** Moderate margins (1 inch top/bottom, 0.75 inch left/right) */\n MODERATE: {\n top: 1440,\n bottom: 1440,\n left: 1080,\n right: 1080,\n },\n} as const;\n"]}
|
|
1
|
+
{"version":3,"file":"units.js","sourceRoot":"","sources":["../../../src/utils/units.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unit Conversion Utilities\n *\n * Word documents use multiple measurement units:\n * - Twips: 1/20th of a point (used for most measurements like margins, indents)\n * - EMUs: English Metric Units (used for DrawingML, images)\n * - Points: Typography unit (72 points = 1 inch)\n * - Pixels: Screen measurement (depends on DPI)\n * - Inches/Centimeters: Human-readable units\n *\n * Conversion factors:\n * - 1 inch = 72 points = 1440 twips = 914,400 EMUs\n * - 1 cm = 0.393701 inches = 360,000 EMUs\n * - 1 point = 20 twips = 12,700 EMUs\n */\n\n/**\n * Standard DPI (dots per inch) for screen displays\n */\nexport const STANDARD_DPI = 96;\n\n/**\n * Conversion constants\n */\nexport const UNITS = {\n /** EMUs per inch */\n EMUS_PER_INCH: 914400,\n /** Twips per inch */\n TWIPS_PER_INCH: 1440,\n /** Points per inch */\n POINTS_PER_INCH: 72,\n /** Twips per point */\n TWIPS_PER_POINT: 20,\n /** EMUs per twip */\n EMUS_PER_TWIP: 635,\n /** EMUs per point */\n EMUS_PER_POINT: 12700,\n /** EMUs per centimeter */\n EMUS_PER_CM: 360000,\n /** Inches per centimeter */\n INCHES_PER_CM: 0.393701,\n /** Centimeters per inch */\n CM_PER_INCH: 2.54,\n /** Half-points per point (Word uses half-points for font sizes) */\n HALF_POINTS_PER_POINT: 2,\n} as const;\n\n// ============================================================================\n// Twips Conversions\n// ============================================================================\n\n/**\n * Converts twips to points\n * @param twips Value in twips\n * @returns Value in points\n */\nexport function twipsToPoints(twips: number): number {\n return twips / UNITS.TWIPS_PER_POINT;\n}\n\n/**\n * Converts twips to inches\n * @param twips Value in twips\n * @returns Value in inches\n */\nexport function twipsToInches(twips: number): number {\n return twips / UNITS.TWIPS_PER_INCH;\n}\n\n/**\n * Converts twips to centimeters\n * @param twips Value in twips\n * @returns Value in centimeters\n */\nexport function twipsToCm(twips: number): number {\n return twipsToInches(twips) * UNITS.CM_PER_INCH;\n}\n\n/**\n * Converts twips to EMUs\n * @param twips Value in twips\n * @returns Value in EMUs\n */\nexport function twipsToEmus(twips: number): number {\n return Math.round(twips * UNITS.EMUS_PER_TWIP);\n}\n\n// ============================================================================\n// EMUs Conversions\n// ============================================================================\n\n/**\n * Converts EMUs to twips\n * @param emus Value in EMUs\n * @returns Value in twips\n */\nexport function emusToTwips(emus: number): number {\n return Math.round(emus / UNITS.EMUS_PER_TWIP);\n}\n\n/**\n * Converts EMUs to inches\n * @param emus Value in EMUs\n * @returns Value in inches\n */\nexport function emusToInches(emus: number): number {\n return emus / UNITS.EMUS_PER_INCH;\n}\n\n/**\n * Converts EMUs to centimeters\n * @param emus Value in EMUs\n * @returns Value in centimeters\n */\nexport function emusToCm(emus: number): number {\n return emus / UNITS.EMUS_PER_CM;\n}\n\n/**\n * Converts EMUs to points\n * @param emus Value in EMUs\n * @returns Value in points\n */\nexport function emusToPoints(emus: number): number {\n return emus / UNITS.EMUS_PER_POINT;\n}\n\n/**\n * Converts EMUs to pixels\n * @param emus Value in EMUs\n * @param dpi Dots per inch (default: 96)\n * @returns Value in pixels\n */\nexport function emusToPixels(emus: number, dpi: number = STANDARD_DPI): number {\n return Math.round((emus / UNITS.EMUS_PER_INCH) * dpi);\n}\n\n// ============================================================================\n// Points Conversions\n// ============================================================================\n\n/**\n * Converts points to twips\n * @param points Value in points\n * @returns Value in twips\n */\nexport function pointsToTwips(points: number): number {\n // Round to nearest integer — twips attributes (w:spacing, w:ind) require\n // ST_DecimalNumber-based integer values\n return Math.round(points * UNITS.TWIPS_PER_POINT);\n}\n\n/**\n * Converts points to EMUs\n * @param points Value in points\n * @returns Value in EMUs\n */\nexport function pointsToEmus(points: number): number {\n return Math.round(points * UNITS.EMUS_PER_POINT);\n}\n\n/**\n * Converts points to inches\n * @param points Value in points\n * @returns Value in inches\n */\nexport function pointsToInches(points: number): number {\n return points / UNITS.POINTS_PER_INCH;\n}\n\n/**\n * Converts points to centimeters\n * @param points Value in points\n * @returns Value in centimeters\n */\nexport function pointsToCm(points: number): number {\n return pointsToInches(points) * UNITS.CM_PER_INCH;\n}\n\n// ============================================================================\n// Half-Points Conversions (Word uses half-points for font sizes)\n// ============================================================================\n\n/**\n * Converts points to half-points (for Word font size storage)\n * @param points Value in points\n * @returns Value in half-points\n */\nexport function pointsToHalfPoints(points: number): number {\n // Round to nearest integer — w:sz/w:szCs require ST_HpsMeasure (unsigned integer)\n return Math.round(points * UNITS.HALF_POINTS_PER_POINT);\n}\n\n/**\n * Converts half-points to points (from Word font size storage)\n * @param halfPoints Value in half-points\n * @returns Value in points\n */\nexport function halfPointsToPoints(halfPoints: number): number {\n return halfPoints / UNITS.HALF_POINTS_PER_POINT;\n}\n\n// ============================================================================\n// Inches Conversions\n// ============================================================================\n\n/**\n * Converts inches to twips\n * @param inches Value in inches\n * @returns Value in twips\n */\nexport function inchesToTwips(inches: number): number {\n return Math.round(inches * UNITS.TWIPS_PER_INCH);\n}\n\n/**\n * Converts inches to EMUs\n * @param inches Value in inches\n * @returns Value in EMUs\n */\nexport function inchesToEmus(inches: number): number {\n return Math.round(inches * UNITS.EMUS_PER_INCH);\n}\n\n/**\n * Converts inches to points\n * @param inches Value in inches\n * @returns Value in points\n */\nexport function inchesToPoints(inches: number): number {\n return inches * UNITS.POINTS_PER_INCH;\n}\n\n/**\n * Converts inches to centimeters\n * @param inches Value in inches\n * @returns Value in centimeters\n */\nexport function inchesToCm(inches: number): number {\n return inches * UNITS.CM_PER_INCH;\n}\n\n/**\n * Converts inches to pixels\n * @param inches Value in inches\n * @param dpi Dots per inch (default: 96)\n * @returns Value in pixels\n */\nexport function inchesToPixels(inches: number, dpi: number = STANDARD_DPI): number {\n return Math.round(inches * dpi);\n}\n\n// ============================================================================\n// Centimeters Conversions\n// ============================================================================\n\n/**\n * Converts centimeters to twips\n * @param cm Value in centimeters\n * @returns Value in twips\n */\nexport function cmToTwips(cm: number): number {\n return inchesToTwips(cm * UNITS.INCHES_PER_CM);\n}\n\n/**\n * Converts centimeters to EMUs\n * @param cm Value in centimeters\n * @returns Value in EMUs\n */\nexport function cmToEmus(cm: number): number {\n return Math.round(cm * UNITS.EMUS_PER_CM);\n}\n\n/**\n * Converts centimeters to inches\n * @param cm Value in centimeters\n * @returns Value in inches\n */\nexport function cmToInches(cm: number): number {\n return cm * UNITS.INCHES_PER_CM;\n}\n\n/**\n * Converts centimeters to points\n * @param cm Value in centimeters\n * @returns Value in points\n */\nexport function cmToPoints(cm: number): number {\n return inchesToPoints(cmToInches(cm));\n}\n\n/**\n * Converts centimeters to pixels\n * @param cm Value in centimeters\n * @param dpi Dots per inch (default: 96)\n * @returns Value in pixels\n */\nexport function cmToPixels(cm: number, dpi: number = STANDARD_DPI): number {\n return inchesToPixels(cmToInches(cm), dpi);\n}\n\n// ============================================================================\n// Pixels Conversions\n// ============================================================================\n\n/**\n * Converts pixels to EMUs\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in EMUs\n */\nexport function pixelsToEmus(pixels: number, dpi: number = STANDARD_DPI): number {\n return Math.round((pixels / dpi) * UNITS.EMUS_PER_INCH);\n}\n\n/**\n * Converts pixels to inches\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in inches\n */\nexport function pixelsToInches(pixels: number, dpi: number = STANDARD_DPI): number {\n return pixels / dpi;\n}\n\n/**\n * Converts pixels to twips\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in twips\n */\nexport function pixelsToTwips(pixels: number, dpi: number = STANDARD_DPI): number {\n return inchesToTwips(pixelsToInches(pixels, dpi));\n}\n\n/**\n * Converts pixels to centimeters\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in centimeters\n */\nexport function pixelsToCm(pixels: number, dpi: number = STANDARD_DPI): number {\n return pixelsToInches(pixels, dpi) * UNITS.CM_PER_INCH;\n}\n\n/**\n * Converts pixels to points\n * @param pixels Value in pixels\n * @param dpi Dots per inch (default: 96)\n * @returns Value in points\n */\nexport function pixelsToPoints(pixels: number, dpi: number = STANDARD_DPI): number {\n return inchesToPoints(pixelsToInches(pixels, dpi));\n}\n\n// ============================================================================\n// Common Document Sizes (in twips)\n// ============================================================================\n\n/**\n * Common page sizes in twips\n */\nexport const PAGE_SIZES = {\n /** Letter (8.5\" x 11\") */\n LETTER: {\n width: 12240, // 8.5 inches\n height: 15840, // 11 inches\n },\n /** A4 (21cm x 29.7cm) */\n A4: {\n width: 11906, // 21cm\n height: 16838, // 29.7cm\n },\n /** Legal (8.5\" x 14\") */\n LEGAL: {\n width: 12240, // 8.5 inches\n height: 20160, // 14 inches\n },\n /** Tabloid (11\" x 17\") */\n TABLOID: {\n width: 15840, // 11 inches\n height: 24480, // 17 inches\n },\n /** A3 (29.7cm x 42cm) */\n A3: {\n width: 16838, // 29.7cm\n height: 23811, // 42cm\n },\n} as const;\n\n/**\n * Common margin sizes in twips\n */\nexport const COMMON_MARGINS = {\n /** Normal margins (1 inch all around) */\n NORMAL: {\n top: 1440,\n bottom: 1440,\n left: 1440,\n right: 1440,\n },\n /** Narrow margins (0.5 inch all around) */\n NARROW: {\n top: 720,\n bottom: 720,\n left: 720,\n right: 720,\n },\n /** Wide margins (2 inches left/right, 1 inch top/bottom) */\n WIDE: {\n top: 1440,\n bottom: 1440,\n left: 2880,\n right: 2880,\n },\n /** Moderate margins (1 inch top/bottom, 0.75 inch left/right) */\n MODERATE: {\n top: 1440,\n bottom: 1440,\n left: 1080,\n right: 1080,\n },\n} as const;\n"]}
|
|
@@ -10,24 +10,13 @@ export function validateDocxStructure(filePaths) {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
export function isBinaryFile(filePath) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
'.ico',
|
|
21
|
-
'.emf',
|
|
22
|
-
'.wmf',
|
|
23
|
-
'.bin',
|
|
24
|
-
'.dat',
|
|
25
|
-
'.ttf',
|
|
26
|
-
'.otf',
|
|
27
|
-
'.woff',
|
|
28
|
-
];
|
|
29
|
-
const extension = filePath.substring(filePath.lastIndexOf('.')).toLowerCase();
|
|
30
|
-
return binaryExtensions.includes(extension);
|
|
13
|
+
const textExtensions = ['.xml', '.rels', '.svg', '.txt', '.html', '.css', '.js'];
|
|
14
|
+
const dotIndex = filePath.lastIndexOf('.');
|
|
15
|
+
if (dotIndex === -1) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
const extension = filePath.substring(dotIndex).toLowerCase();
|
|
19
|
+
return !textExtensions.includes(extension);
|
|
31
20
|
}
|
|
32
21
|
export function normalizePath(path) {
|
|
33
22
|
const normalized = path.replace(/\\/g, '/').replace(/^\/+/, '');
|
|
@@ -46,10 +35,6 @@ export function normalizePath(path) {
|
|
|
46
35
|
`Absolute paths are not allowed in DOCX archives. ` +
|
|
47
36
|
`Only relative paths within the archive are permitted.`);
|
|
48
37
|
}
|
|
49
|
-
if (path.startsWith('/') && normalized.startsWith('/')) {
|
|
50
|
-
throw new Error(`Invalid file path: "${path}" appears to be an absolute Unix path. ` +
|
|
51
|
-
`Only relative paths are allowed in DOCX archives.`);
|
|
52
|
-
}
|
|
53
38
|
return normalized;
|
|
54
39
|
}
|
|
55
40
|
export function isValidZipBuffer(buffer) {
|
|
@@ -76,6 +61,9 @@ export function validateTwips(value, fieldName = 'value') {
|
|
|
76
61
|
if (!Number.isFinite(value)) {
|
|
77
62
|
throw new Error(`${fieldName} must be a finite number, got ${value}`);
|
|
78
63
|
}
|
|
64
|
+
if (!Number.isInteger(value)) {
|
|
65
|
+
throw new Error(`${fieldName} must be an integer (in twips), got ${value}`);
|
|
66
|
+
}
|
|
79
67
|
const MIN_TWIPS = -31680;
|
|
80
68
|
const MAX_TWIPS = 31680;
|
|
81
69
|
if (value < MIN_TWIPS || value > MAX_TWIPS) {
|
|
@@ -144,7 +132,7 @@ export function validateFontSize(size, fieldName = 'font size') {
|
|
|
144
132
|
throw new Error(`${fieldName} must be an integer (in half-points), got ${size}`);
|
|
145
133
|
}
|
|
146
134
|
const MIN_SIZE = 2;
|
|
147
|
-
const MAX_SIZE =
|
|
135
|
+
const MAX_SIZE = 3276;
|
|
148
136
|
if (size < MIN_SIZE || size > MAX_SIZE) {
|
|
149
137
|
throw new Error(`${fieldName} out of range: ${size} half-points (allowed: ${MIN_SIZE}-${MAX_SIZE}, or ${MIN_SIZE / 2}-${MAX_SIZE / 2} points)`);
|
|
150
138
|
}
|