docxmlater 11.0.10 → 12.1.0
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 +53 -13
- package/dist/core/Document.d.ts +29 -3
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +733 -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 +735 -172
- 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 +223 -39
- 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/acceptRevisions.js +20 -11
- package/dist/esm/processors/acceptRevisions.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 +9 -3
- package/dist/processors/RevisionWalker.d.ts.map +1 -1
- package/dist/processors/RevisionWalker.js +223 -39
- 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/acceptRevisions.d.ts +1 -0
- package/dist/processors/acceptRevisions.d.ts.map +1 -1
- package/dist/processors/acceptRevisions.js +21 -11
- package/dist/processors/acceptRevisions.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 +1184 -242
- 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 +390 -46
- package/src/processors/SelectiveRevisionAcceptor.ts +164 -28
- package/src/processors/acceptRevisions.ts +67 -17
- 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
package/src/utils/units.ts
CHANGED
|
@@ -145,7 +145,9 @@ export function emusToPixels(emus: number, dpi: number = STANDARD_DPI): number {
|
|
|
145
145
|
* @returns Value in twips
|
|
146
146
|
*/
|
|
147
147
|
export function pointsToTwips(points: number): number {
|
|
148
|
-
|
|
148
|
+
// Round to nearest integer — twips attributes (w:spacing, w:ind) require
|
|
149
|
+
// ST_DecimalNumber-based integer values
|
|
150
|
+
return Math.round(points * UNITS.TWIPS_PER_POINT);
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
/**
|
package/src/utils/validation.ts
CHANGED
|
@@ -23,29 +23,28 @@ export function validateDocxStructure(filePaths: string[]): void {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Checks if a file path represents a binary file based on extension
|
|
26
|
+
*
|
|
27
|
+
* Uses a text-extension whitelist rather than a binary-extension whitelist:
|
|
28
|
+
* misclassifying text as binary only changes its in-memory representation
|
|
29
|
+
* (Buffer instead of string), but misclassifying binary as text corrupts the
|
|
30
|
+
* bytes through a lossy UTF-8 decode. OOXML packages can embed arbitrary
|
|
31
|
+
* binary parts (.xlsx/.pdf OLE packages, .odttf obfuscated fonts, .emz/.wmz
|
|
32
|
+
* compressed metafiles, extensionless parts), so anything not known to be
|
|
33
|
+
* text must be preserved byte-for-byte.
|
|
34
|
+
*
|
|
26
35
|
* @param filePath - The file path to check
|
|
27
36
|
* @returns True if the file is likely binary
|
|
28
37
|
*/
|
|
29
38
|
export function isBinaryFile(filePath: string): boolean {
|
|
30
|
-
const
|
|
31
|
-
'.png',
|
|
32
|
-
'.jpg',
|
|
33
|
-
'.jpeg',
|
|
34
|
-
'.gif',
|
|
35
|
-
'.bmp',
|
|
36
|
-
'.tiff',
|
|
37
|
-
'.ico',
|
|
38
|
-
'.emf',
|
|
39
|
-
'.wmf',
|
|
40
|
-
'.bin',
|
|
41
|
-
'.dat',
|
|
42
|
-
'.ttf',
|
|
43
|
-
'.otf',
|
|
44
|
-
'.woff',
|
|
45
|
-
];
|
|
39
|
+
const textExtensions = ['.xml', '.rels', '.svg', '.txt', '.html', '.css', '.js'];
|
|
46
40
|
|
|
47
|
-
const
|
|
48
|
-
|
|
41
|
+
const dotIndex = filePath.lastIndexOf('.');
|
|
42
|
+
if (dotIndex === -1) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const extension = filePath.substring(dotIndex).toLowerCase();
|
|
47
|
+
return !textExtensions.includes(extension);
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
/**
|
|
@@ -55,12 +54,15 @@ export function isBinaryFile(filePath: string): boolean {
|
|
|
55
54
|
*
|
|
56
55
|
* **Security:** This function validates paths to prevent:
|
|
57
56
|
* - Path traversal attacks (../, ..\, URL-encoded variants)
|
|
58
|
-
* - Absolute paths (C:\,
|
|
57
|
+
* - Absolute Windows paths (C:\, D:, etc.) — rejected
|
|
59
58
|
* - Malicious DOCX files attempting directory escape
|
|
60
59
|
*
|
|
60
|
+
* Unix absolute paths (/etc/...) are sanitized to archive-relative paths
|
|
61
|
+
* by stripping leading slashes, not rejected.
|
|
62
|
+
*
|
|
61
63
|
* @param path - The path to normalize
|
|
62
64
|
* @returns Normalized path
|
|
63
|
-
* @throws {Error} If path contains path traversal sequences, absolute paths, or URL-encoded attacks
|
|
65
|
+
* @throws {Error} If path contains path traversal sequences, absolute Windows paths, or URL-encoded attacks
|
|
64
66
|
*/
|
|
65
67
|
export function normalizePath(path: string): string {
|
|
66
68
|
// First convert all backslashes to forward slashes for consistent checking
|
|
@@ -97,15 +99,6 @@ export function normalizePath(path: string): string {
|
|
|
97
99
|
);
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
// Security: Prevent Unix absolute paths
|
|
101
|
-
// After removing leading slashes, if it starts with / it's suspicious
|
|
102
|
-
if (path.startsWith('/') && normalized.startsWith('/')) {
|
|
103
|
-
throw new Error(
|
|
104
|
-
`Invalid file path: "${path}" appears to be an absolute Unix path. ` +
|
|
105
|
-
`Only relative paths are allowed in DOCX archives.`
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
102
|
return normalized;
|
|
110
103
|
}
|
|
111
104
|
|
|
@@ -161,6 +154,11 @@ export function validateTwips(value: number, fieldName = 'value'): void {
|
|
|
161
154
|
throw new Error(`${fieldName} must be a finite number, got ${value}`);
|
|
162
155
|
}
|
|
163
156
|
|
|
157
|
+
// ST_TwipsMeasure/ST_SignedTwipsMeasure are ST_DecimalNumber-based — integers only
|
|
158
|
+
if (!Number.isInteger(value)) {
|
|
159
|
+
throw new Error(`${fieldName} must be an integer (in twips), got ${value}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
164
162
|
// Reasonable range: ±22 inches (31680 twips)
|
|
165
163
|
const MIN_TWIPS = -31680;
|
|
166
164
|
const MAX_TWIPS = 31680;
|
|
@@ -304,7 +302,7 @@ export function validateAlignment(
|
|
|
304
302
|
|
|
305
303
|
/**
|
|
306
304
|
* Validates a font size (in half-points for Word)
|
|
307
|
-
* Reasonable range: 2-
|
|
305
|
+
* Reasonable range: 2-3276 (1-1638 points)
|
|
308
306
|
* @param size - The font size in half-points to validate
|
|
309
307
|
* @param fieldName - Name of the field (for error messages)
|
|
310
308
|
* @throws {Error} If the size is invalid
|
|
@@ -318,9 +316,9 @@ export function validateFontSize(size: number, fieldName = 'font size'): void {
|
|
|
318
316
|
throw new Error(`${fieldName} must be an integer (in half-points), got ${size}`);
|
|
319
317
|
}
|
|
320
318
|
|
|
321
|
-
//
|
|
319
|
+
// Word's limit is 1-1638 points, i.e. 2-3276 half-points for w:sz (ST_HpsMeasure)
|
|
322
320
|
const MIN_SIZE = 2;
|
|
323
|
-
const MAX_SIZE =
|
|
321
|
+
const MAX_SIZE = 3276;
|
|
324
322
|
|
|
325
323
|
if (size < MIN_SIZE || size > MAX_SIZE) {
|
|
326
324
|
throw new Error(
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
* - 0x09 (tab), 0x0A (newline), 0x0D (carriage return)
|
|
10
10
|
* - 0x20-0xD7FF, 0xE000-0xFFFD, 0x10000-0x10FFFF
|
|
11
11
|
*
|
|
12
|
-
* Invalid characters
|
|
12
|
+
* Invalid characters that must be removed:
|
|
13
13
|
* - 0x00-0x08 (NULL through BACKSPACE)
|
|
14
14
|
* - 0x0B-0x0C (VERTICAL TAB and FORM FEED)
|
|
15
15
|
* - 0x0E-0x1F (SHIFT OUT through UNIT SEPARATOR)
|
|
16
16
|
* - 0x7F (DELETE)
|
|
17
|
+
* - 0xFFFE-0xFFFF (Unicode noncharacters excluded by the Char production)
|
|
18
|
+
* - Unpaired surrogates (0xD800-0xDFFF outside a valid high/low pair)
|
|
17
19
|
*
|
|
18
20
|
* @module xmlSanitization
|
|
19
21
|
*/
|
|
@@ -21,26 +23,40 @@
|
|
|
21
23
|
import { getGlobalLogger } from './logger.js';
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
|
-
* Regular expression matching invalid XML 1.0
|
|
25
|
-
* Matches: 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F
|
|
26
|
+
* Regular expression matching invalid XML 1.0 characters.
|
|
27
|
+
* Matches: 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F, 0xFFFE, 0xFFFF
|
|
26
28
|
* Does NOT match valid chars: 0x09 (tab), 0x0A (newline), 0x0D (CR)
|
|
27
29
|
*/
|
|
28
|
-
const INVALID_XML_CHAR_REGEX = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
|
|
30
|
+
const INVALID_XML_CHAR_REGEX = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
|
-
*
|
|
33
|
+
* Matches surrogate code units that do not form a valid high/low pair.
|
|
34
|
+
* XML 1.0 Char excludes 0xD800-0xDFFF entirely; only properly paired
|
|
35
|
+
* surrogates (which decode to a single 0x10000-0x10FFFF character) are
|
|
36
|
+
* legal, so lone halves must be stripped or they corrupt the part at
|
|
37
|
+
* UTF-8 encode time.
|
|
38
|
+
*/
|
|
39
|
+
const UNPAIRED_SURROGATE_REGEX =
|
|
40
|
+
/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Removes invalid XML 1.0 characters from text.
|
|
32
44
|
*
|
|
33
|
-
* Per XML 1.0 spec, characters 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F
|
|
34
|
-
*
|
|
45
|
+
* Per XML 1.0 spec, characters 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F,
|
|
46
|
+
* 0xFFFE, 0xFFFF, and unpaired surrogates are invalid and cannot appear
|
|
47
|
+
* in XML documents. This function removes them.
|
|
35
48
|
*
|
|
36
49
|
* Valid control characters are preserved:
|
|
37
50
|
* - Tab (0x09)
|
|
38
51
|
* - Line Feed / Newline (0x0A)
|
|
39
52
|
* - Carriage Return (0x0D)
|
|
40
53
|
*
|
|
54
|
+
* Properly paired surrogates (astral-plane characters such as emoji)
|
|
55
|
+
* are preserved.
|
|
56
|
+
*
|
|
41
57
|
* @param text - Input text to sanitize
|
|
42
58
|
* @param logWarning - If true, logs a warning when invalid chars are found (default: true)
|
|
43
|
-
* @returns Sanitized text with invalid
|
|
59
|
+
* @returns Sanitized text with invalid characters removed
|
|
44
60
|
*
|
|
45
61
|
* @example
|
|
46
62
|
* ```typescript
|
|
@@ -54,31 +70,33 @@ const INVALID_XML_CHAR_REGEX = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
|
|
|
54
70
|
* ```
|
|
55
71
|
*/
|
|
56
72
|
export function removeInvalidXmlChars(text: string, logWarning = true): string {
|
|
57
|
-
// Reset regex lastIndex for global
|
|
73
|
+
// Reset regex lastIndex for global regexes
|
|
58
74
|
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
75
|
+
UNPAIRED_SURROGATE_REGEX.lastIndex = 0;
|
|
59
76
|
|
|
60
|
-
if (logWarning && INVALID_XML_CHAR_REGEX.test(text)) {
|
|
77
|
+
if (logWarning && (INVALID_XML_CHAR_REGEX.test(text) || UNPAIRED_SURROGATE_REGEX.test(text))) {
|
|
61
78
|
// Reset regex lastIndex after test
|
|
62
79
|
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
80
|
+
UNPAIRED_SURROGATE_REGEX.lastIndex = 0;
|
|
63
81
|
|
|
64
82
|
const invalidChars = findInvalidXmlChars(text);
|
|
65
83
|
const hexCodes = invalidChars
|
|
66
84
|
.map((c) => `0x${c.toString(16).toUpperCase().padStart(2, '0')}`)
|
|
67
85
|
.join(', ');
|
|
68
|
-
getGlobalLogger().warn(
|
|
69
|
-
`[XMLSanitization] Removing invalid XML control characters: ${hexCodes}`
|
|
70
|
-
);
|
|
86
|
+
getGlobalLogger().warn(`[XMLSanitization] Removing invalid XML characters: ${hexCodes}`);
|
|
71
87
|
}
|
|
72
88
|
|
|
73
89
|
// Reset regex lastIndex before replace
|
|
74
90
|
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
75
|
-
|
|
91
|
+
UNPAIRED_SURROGATE_REGEX.lastIndex = 0;
|
|
92
|
+
return text.replace(INVALID_XML_CHAR_REGEX, '').replace(UNPAIRED_SURROGATE_REGEX, '');
|
|
76
93
|
}
|
|
77
94
|
|
|
78
95
|
/**
|
|
79
|
-
* Finds all invalid XML 1.0
|
|
96
|
+
* Finds all invalid XML 1.0 characters in text.
|
|
80
97
|
*
|
|
81
|
-
* Returns an array of unique character codes that are invalid per XML 1.0 spec
|
|
98
|
+
* Returns an array of unique character codes that are invalid per XML 1.0 spec,
|
|
99
|
+
* including 0xFFFE/0xFFFF noncharacters and unpaired surrogate code units.
|
|
82
100
|
* This is useful for diagnostics and error reporting.
|
|
83
101
|
*
|
|
84
102
|
* @param text - Text to scan for invalid characters
|
|
@@ -100,12 +118,25 @@ export function findInvalidXmlChars(text: string): number[] {
|
|
|
100
118
|
const code = text.charCodeAt(i);
|
|
101
119
|
|
|
102
120
|
// Check if character is in invalid ranges
|
|
103
|
-
|
|
121
|
+
let isInvalid =
|
|
104
122
|
(code >= 0x00 && code <= 0x08) || // NULL through BACKSPACE
|
|
105
123
|
(code >= 0x0b && code <= 0x0c) || // VERTICAL TAB and FORM FEED
|
|
106
124
|
(code >= 0x0e && code <= 0x1f) || // SHIFT OUT through UNIT SEPARATOR
|
|
107
|
-
code === 0x7f // DELETE
|
|
108
|
-
|
|
125
|
+
code === 0x7f || // DELETE
|
|
126
|
+
code === 0xfffe || // Noncharacter excluded by XML 1.0 Char
|
|
127
|
+
code === 0xffff; // Noncharacter excluded by XML 1.0 Char
|
|
128
|
+
|
|
129
|
+
if (!isInvalid && code >= 0xd800 && code <= 0xdbff) {
|
|
130
|
+
// High surrogate is only valid when followed by a low surrogate
|
|
131
|
+
const next = text.charCodeAt(i + 1); // NaN at end of string fails the range check
|
|
132
|
+
isInvalid = !(next >= 0xdc00 && next <= 0xdfff);
|
|
133
|
+
} else if (!isInvalid && code >= 0xdc00 && code <= 0xdfff) {
|
|
134
|
+
// Low surrogate is only valid when preceded by a high surrogate
|
|
135
|
+
const prev = text.charCodeAt(i - 1); // NaN at start of string fails the range check
|
|
136
|
+
isInvalid = !(prev >= 0xd800 && prev <= 0xdbff);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (isInvalid) {
|
|
109
140
|
// Only add unique codes
|
|
110
141
|
if (!invalid.includes(code)) {
|
|
111
142
|
invalid.push(code);
|
|
@@ -117,7 +148,7 @@ export function findInvalidXmlChars(text: string): number[] {
|
|
|
117
148
|
}
|
|
118
149
|
|
|
119
150
|
/**
|
|
120
|
-
* Checks if text contains any invalid XML 1.0
|
|
151
|
+
* Checks if text contains any invalid XML 1.0 characters.
|
|
121
152
|
*
|
|
122
153
|
* This is a fast check that returns true/false without identifying specific characters.
|
|
123
154
|
* Use `findInvalidXmlChars()` if you need to know which characters are invalid.
|
|
@@ -133,9 +164,174 @@ export function findInvalidXmlChars(text: string): number[] {
|
|
|
133
164
|
* ```
|
|
134
165
|
*/
|
|
135
166
|
export function hasInvalidXmlChars(text: string): boolean {
|
|
136
|
-
// Reset regex lastIndex for global
|
|
167
|
+
// Reset regex lastIndex for global regexes
|
|
137
168
|
INVALID_XML_CHAR_REGEX.lastIndex = 0;
|
|
138
|
-
|
|
169
|
+
UNPAIRED_SURROGATE_REGEX.lastIndex = 0;
|
|
170
|
+
return INVALID_XML_CHAR_REGEX.test(text) || UNPAIRED_SURROGATE_REGEX.test(text);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* CT_RPr child element order per ECMA-376 Part 1 §17.3.2.28 (local names,
|
|
175
|
+
* `w:` namespace). Used to repair raw-preserved run-property blocks whose
|
|
176
|
+
* children are out of schema order — Word rejects, for example, a `w:b`
|
|
177
|
+
* that appears after `w:color`/`w:sz` and reports the document as corrupt.
|
|
178
|
+
*/
|
|
179
|
+
const CT_RPR_CHILD_ORDER: readonly string[] = [
|
|
180
|
+
'rStyle',
|
|
181
|
+
'rFonts',
|
|
182
|
+
'b',
|
|
183
|
+
'bCs',
|
|
184
|
+
'i',
|
|
185
|
+
'iCs',
|
|
186
|
+
'caps',
|
|
187
|
+
'smallCaps',
|
|
188
|
+
'strike',
|
|
189
|
+
'dstrike',
|
|
190
|
+
'outline',
|
|
191
|
+
'shadow',
|
|
192
|
+
'emboss',
|
|
193
|
+
'imprint',
|
|
194
|
+
'noProof',
|
|
195
|
+
'snapToGrid',
|
|
196
|
+
'vanish',
|
|
197
|
+
'webHidden',
|
|
198
|
+
'color',
|
|
199
|
+
'spacing',
|
|
200
|
+
'w',
|
|
201
|
+
'kern',
|
|
202
|
+
'position',
|
|
203
|
+
'sz',
|
|
204
|
+
'szCs',
|
|
205
|
+
'highlight',
|
|
206
|
+
'u',
|
|
207
|
+
'effect',
|
|
208
|
+
'bdr',
|
|
209
|
+
'shd',
|
|
210
|
+
'fitText',
|
|
211
|
+
'vertAlign',
|
|
212
|
+
'rtl',
|
|
213
|
+
'cs',
|
|
214
|
+
'em',
|
|
215
|
+
'lang',
|
|
216
|
+
'eastAsianLayout',
|
|
217
|
+
'specVanish',
|
|
218
|
+
'oMath',
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Splits the inner content of an element into its top-level child elements,
|
|
223
|
+
* respecting nesting so that a child's descendants are kept with it. Returns
|
|
224
|
+
* the raw XML fragment for each direct child in document order. Non-element
|
|
225
|
+
* text between children (whitespace) is dropped, which is safe for the
|
|
226
|
+
* element-only content models this helper targets (e.g. `w:rPr`).
|
|
227
|
+
*/
|
|
228
|
+
function splitTopLevelElements(inner: string): string[] {
|
|
229
|
+
const children: string[] = [];
|
|
230
|
+
const tagRegex = /<([A-Za-z][\w:.-]*)([^>]*?)(\/?)>|<\/([A-Za-z][\w:.-]*)\s*>/g;
|
|
231
|
+
let depth = 0;
|
|
232
|
+
let start = -1;
|
|
233
|
+
let match: RegExpExecArray | null;
|
|
234
|
+
while ((match = tagRegex.exec(inner)) !== null) {
|
|
235
|
+
const isClosing = match[4] !== undefined;
|
|
236
|
+
const isSelfClosing = match[3] === '/';
|
|
237
|
+
if (isClosing) {
|
|
238
|
+
if (depth > 0) {
|
|
239
|
+
depth--;
|
|
240
|
+
if (depth === 0 && start !== -1) {
|
|
241
|
+
children.push(inner.slice(start, tagRegex.lastIndex));
|
|
242
|
+
start = -1;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (isSelfClosing) {
|
|
248
|
+
if (depth === 0) {
|
|
249
|
+
children.push(inner.slice(match.index, tagRegex.lastIndex));
|
|
250
|
+
}
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
// Opening tag of a paired element
|
|
254
|
+
if (depth === 0) start = match.index;
|
|
255
|
+
depth++;
|
|
256
|
+
}
|
|
257
|
+
return children;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Reorders the direct children of every `<w:rPr>` block in a raw XML part to
|
|
262
|
+
* the ECMA-376 CT_RPr sequence. Unknown/unmodeled children retain their
|
|
263
|
+
* relative position at the end of the block. The transform is idempotent:
|
|
264
|
+
* already-ordered run properties are returned unchanged.
|
|
265
|
+
*
|
|
266
|
+
* Some producers (and older versions of this framework) appended boolean
|
|
267
|
+
* toggles such as `w:b`/`w:bCs` to the end of an existing `w:rPr`, leaving
|
|
268
|
+
* them after `w:color`/`w:sz`. Word treats the out-of-order child as an
|
|
269
|
+
* unexpected element and flags the whole document as corrupt. Numbering
|
|
270
|
+
* definitions are written back verbatim for fidelity, so this repair runs on
|
|
271
|
+
* the preserved part before it is saved.
|
|
272
|
+
*
|
|
273
|
+
* @param xml - Raw XML for a part containing `w:rPr` blocks (e.g. numbering.xml)
|
|
274
|
+
* @returns XML with every `w:rPr` child sequence normalized to schema order
|
|
275
|
+
*/
|
|
276
|
+
export function reorderRunPropertyChildren(xml: string): string {
|
|
277
|
+
if (!xml || !xml.includes('<w:rPr')) return xml;
|
|
278
|
+
|
|
279
|
+
const orderIndex = (fragment: string): number => {
|
|
280
|
+
const nameMatch = /^<w:(\w+)/.exec(fragment);
|
|
281
|
+
const name = nameMatch?.[1];
|
|
282
|
+
if (!name) return CT_RPR_CHILD_ORDER.length;
|
|
283
|
+
const idx = CT_RPR_CHILD_ORDER.indexOf(name);
|
|
284
|
+
return idx === -1 ? CT_RPR_CHILD_ORDER.length : idx;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// Only match non-empty <w:rPr>...</w:rPr> blocks; self-closing <w:rPr/> has
|
|
288
|
+
// no children to reorder.
|
|
289
|
+
return xml.replace(/<w:rPr(\s[^>]*)?>([\s\S]*?)<\/w:rPr>/g, (full, attrs, inner) => {
|
|
290
|
+
if (!inner || !(inner as string).includes('<')) return full;
|
|
291
|
+
const children = splitTopLevelElements(inner);
|
|
292
|
+
if (children.length < 2) return full;
|
|
293
|
+
|
|
294
|
+
const ordered = children
|
|
295
|
+
.map((frag, i) => ({ frag, i, order: orderIndex(frag) }))
|
|
296
|
+
// Stable sort: ties (including unknown children) keep original order.
|
|
297
|
+
.sort((a, b) => a.order - b.order || a.i - b.i);
|
|
298
|
+
|
|
299
|
+
if (ordered.every((c, i) => c.i === i)) return full; // already in order
|
|
300
|
+
|
|
301
|
+
return `<w:rPr${attrs ?? ''}>${ordered.map((c) => c.frag).join('')}</w:rPr>`;
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Normalizes malformed floating-drawing relative-size elements in a raw anchor
|
|
307
|
+
* fragment. Per ECMA-376 (DrawingML wordprocessing 2010 extensions),
|
|
308
|
+
* `wp14:sizeRelH` must contain a `wp14:pctWidth` child and `wp14:sizeRelV` a
|
|
309
|
+
* `wp14:pctHeight` child. Some producers emit the percentage as bare text
|
|
310
|
+
* content (`<wp14:sizeRelH relativeFrom="margin">0</wp14:sizeRelH>`), which
|
|
311
|
+
* Word rejects as incomplete content. This wraps such text in the required
|
|
312
|
+
* child element. Already-valid nested forms are left untouched because the
|
|
313
|
+
* text-content pattern (`[^<]`) cannot match an element child.
|
|
314
|
+
*
|
|
315
|
+
* @param xml - Raw anchor-extras fragment captured during parsing
|
|
316
|
+
* @returns Fragment with sizeRelH/sizeRelV normalized to schema-valid form
|
|
317
|
+
*/
|
|
318
|
+
export function normalizeAnchorSizeRel(xml: string): string {
|
|
319
|
+
if (!xml) return xml;
|
|
320
|
+
return xml
|
|
321
|
+
.replace(
|
|
322
|
+
/(<wp14:sizeRelH\b[^>]*>)([^<]+)(<\/wp14:sizeRelH>)/g,
|
|
323
|
+
(_m, open: string, text: string, close: string) =>
|
|
324
|
+
text.trim() === ''
|
|
325
|
+
? `${open}${text}${close}`
|
|
326
|
+
: `${open}<wp14:pctWidth>${text.trim()}</wp14:pctWidth>${close}`
|
|
327
|
+
)
|
|
328
|
+
.replace(
|
|
329
|
+
/(<wp14:sizeRelV\b[^>]*>)([^<]+)(<\/wp14:sizeRelV>)/g,
|
|
330
|
+
(_m, open: string, text: string, close: string) =>
|
|
331
|
+
text.trim() === ''
|
|
332
|
+
? `${open}${text}${close}`
|
|
333
|
+
: `${open}<wp14:pctHeight>${text.trim()}</wp14:pctHeight>${close}`
|
|
334
|
+
);
|
|
139
335
|
}
|
|
140
336
|
|
|
141
337
|
/**
|