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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RelationshipManager.d.ts","sourceRoot":"","sources":["../../src/core/RelationshipManager.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQnE,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,MAAM,CAAS;;IAevB,eAAe,CAAC,YAAY,EAAE,YAAY,GAAG,YAAY;IAmBzD,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAOrD,mBAAmB,IAAI,YAAY,EAAE;IAQrC,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,YAAY,EAAE;IAQvE,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IASpC,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAOvC,QAAQ,IAAI,MAAM;IAOlB,KAAK,IAAI,IAAI;IAUb,UAAU,IAAI,MAAM;IAQpB,SAAS,IAAI,YAAY;IASzB,YAAY,IAAI,YAAY;IAS5B,YAAY,IAAI,YAAY;IAS5B,WAAW,IAAI,YAAY;IAS3B,cAAc,IAAI,YAAY;IAS9B,QAAQ,IAAI,YAAY;IAUxB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY;IAUtC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY;IAUvC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY;IAUvC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY;IAgBvC,qBAAqB,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAyBtE,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAgBlE,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY;IAqB/C,wBAAwB,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM;IAyB5D,WAAW,IAAI,YAAY;IAS3B,YAAY,IAAI,YAAY;IAS5B,WAAW,IAAI,YAAY;IAS3B,SAAS,IAAI,YAAY;IASzB,WAAW,IAAI,MAAM;IAmBrB,MAAM,CAAC,iBAAiB,IAAI,mBAAmB;IAe/C,MAAM,CAAC,MAAM,IAAI,mBAAmB;IASpC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB;
|
|
1
|
+
{"version":3,"file":"RelationshipManager.d.ts","sourceRoot":"","sources":["../../src/core/RelationshipManager.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQnE,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,MAAM,CAAS;;IAevB,eAAe,CAAC,YAAY,EAAE,YAAY,GAAG,YAAY;IAmBzD,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAOrD,mBAAmB,IAAI,YAAY,EAAE;IAQrC,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,YAAY,EAAE;IAQvE,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IASpC,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAOvC,QAAQ,IAAI,MAAM;IAOlB,KAAK,IAAI,IAAI;IAUb,UAAU,IAAI,MAAM;IAQpB,SAAS,IAAI,YAAY;IASzB,YAAY,IAAI,YAAY;IAS5B,YAAY,IAAI,YAAY;IAS5B,WAAW,IAAI,YAAY;IAS3B,cAAc,IAAI,YAAY;IAS9B,QAAQ,IAAI,YAAY;IAUxB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY;IAUtC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY;IAUvC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY;IAUvC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY;IAgBvC,qBAAqB,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAyBtE,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAgBlE,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY;IAqB/C,wBAAwB,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM;IAyB5D,WAAW,IAAI,YAAY;IAS3B,YAAY,IAAI,YAAY;IAS5B,WAAW,IAAI,YAAY;IAS3B,SAAS,IAAI,YAAY;IASzB,WAAW,IAAI,MAAM;IAmBrB,MAAM,CAAC,iBAAiB,IAAI,mBAAmB;IAe/C,MAAM,CAAC,MAAM,IAAI,mBAAmB;IASpC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB;CA+DjD"}
|
|
@@ -171,8 +171,8 @@ class RelationshipManager {
|
|
|
171
171
|
throw new errors_js_1.CorruptedArchiveError('Relationships XML file too large (>10MB). Possible malicious input or corrupted file.');
|
|
172
172
|
}
|
|
173
173
|
const relationshipElements = XMLParser_js_1.XMLParser.extractElements(xml, 'Relationship');
|
|
174
|
-
if (relationshipElements.length >
|
|
175
|
-
throw new errors_js_1.CorruptedArchiveError('Too many relationships in XML file (>
|
|
174
|
+
if (relationshipElements.length > 100000) {
|
|
175
|
+
throw new errors_js_1.CorruptedArchiveError('Too many relationships in XML file (>100000). Possible malicious input or corrupted file.');
|
|
176
176
|
}
|
|
177
177
|
for (const relationshipElement of relationshipElements) {
|
|
178
178
|
const id = XMLParser_js_1.XMLParser.extractAttribute(relationshipElement, 'Id');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RelationshipManager.js","sourceRoot":"","sources":["../../src/core/RelationshipManager.ts"],"names":[],"mappings":";;;AAOA,uDAAmE;AACnE,sDAAgD;AAChD,0DAA8D;AAC9D,gDAA2E;AAK3E,MAAa,mBAAmB;IACtB,aAAa,CAA4B;IACzC,MAAM,CAAS;IAKvB;QACE,IAAI,CAAC,aAAa,GAAG,IAAI,GAAG,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAClB,CAAC;IAOD,eAAe,CAAC,YAA0B;QACxC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,YAAY,CAAC,CAAC;QAG3D,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC;QACxD,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvC,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACzB,IAAI,CAAC,MAAM,GAAG,KAAK,GAAG,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,YAAY,CAAC;IACtB,CAAC;IAMD,eAAe,CAAC,EAAU;QACxB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAKD,mBAAmB;QACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC;IAMD,sBAAsB,CAAC,IAA+B;QACpD,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC;IAC5E,CAAC;IAMD,eAAe,CAAC,EAAU;QACxB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAOD,kBAAkB,CAAC,EAAU;QAC3B,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC;IAKD,QAAQ;QACN,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;IACjC,CAAC;IAKD,KAAK;QACH,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAMD,UAAU;QACR,OAAO,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IAC/B,CAAC;IAMD,SAAS;QACP,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC;IAMD,YAAY;QACV,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;IAMD,YAAY;QACV,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;IAMD,WAAW;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;IAMD,cAAc;QACZ,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC;IAClE,CAAC;IAMD,QAAQ;QACN,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5D,CAAC;IAOD,QAAQ,CAAC,MAAc;QACrB,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IACpE,CAAC;IAOD,SAAS,CAAC,MAAc;QACtB,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IACrE,CAAC;IAOD,SAAS,CAAC,MAAc;QACtB,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IACrE,CAAC;IAOD,YAAY,CAAC,GAAW;QACtB,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,eAAe,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACrE,CAAC;IAaD,qBAAqB,CAAC,cAAsB,EAAE,MAAc;QAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;QAC1D,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,KAAK,CAAC;QACf,CAAC;QAGD,IAAI,YAAY,CAAC,OAAO,EAAE,KAAK,kCAAgB,CAAC,SAAS,EAAE,CAAC;YAC1D,MAAM,IAAI,4BAAgB,CACxB,gBAAgB,cAAc,oCAAoC;gBAChE,WAAW,YAAY,CAAC,OAAO,EAAE,cAAc,kCAAgB,CAAC,SAAS,EAAE,CAC9E,CAAC;QACJ,CAAC;QAGD,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAQD,qBAAqB,CAAC,SAAiB;QACrC,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,IAAI,CACpC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,kCAAgB,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,EAAE,KAAK,SAAS,CACvF,CAAC;IACJ,CAAC;IAYD,oBAAoB,CAAC,GAAW;QAE9B,MAAM,QAAQ,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QAClB,CAAC;QAGD,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAYD,wBAAwB,CAAC,aAA0B;QACjD,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAG9B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;YAC7C,IAAI,GAAG,CAAC,OAAO,EAAE,KAAK,kCAAgB,CAAC,SAAS,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;gBACpF,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAGD,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC;gBAChC,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAMD,WAAW;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;IAMD,YAAY;QACV,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;IAMD,WAAW;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;IAMD,SAAS;QACP,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,8BAAY,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC;IAMD,WAAW;QACT,MAAM,aAAa,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAEjD,IAAI,GAAG,GAAG,2DAA2D,CAAC;QACtE,GAAG,IAAI,wFAAwF,CAAC;QAEhG,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;YAChC,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC;QAC5B,CAAC;QAED,GAAG,IAAI,kBAAkB,CAAC;QAE1B,OAAO,GAAG,CAAC;IACb,CAAC;IAMD,MAAM,CAAC,iBAAiB;QACtB,MAAM,OAAO,GAAG,IAAI,mBAAmB,EAAE,CAAC;QAC1C,OAAO,CAAC,SAAS,EAAE,CAAC;QACpB,OAAO,CAAC,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,WAAW,EAAE,CAAC;QACtB,OAAO,CAAC,cAAc,EAAE,CAAC;QACzB,OAAO,CAAC,QAAQ,EAAE,CAAC;QACnB,OAAO,OAAO,CAAC;IACjB,CAAC;IAMD,MAAM,CAAC,MAAM;QACX,OAAO,IAAI,mBAAmB,EAAE,CAAC;IACnC,CAAC;IAOD,MAAM,CAAC,OAAO,CAAC,GAAW;QACxB,MAAM,OAAO,GAAG,IAAI,mBAAmB,EAAE,CAAC;QAG1C,IAAI,GAAG,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;YAC1B,MAAM,IAAI,iCAAqB,CAC7B,uFAAuF,CACxF,CAAC;QACJ,CAAC;QAGD,MAAM,oBAAoB,GAAG,wBAAS,CAAC,eAAe,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAG5E,IAAI,oBAAoB,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;YACvC,MAAM,IAAI,iCAAqB,CAC7B,uEAAuE,CACxE,CAAC;QACJ,CAAC;QAGD,KAAK,MAAM,mBAAmB,IAAI,oBAAoB,EAAE,CAAC;YAEvD,MAAM,EAAE,GAAG,wBAAS,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;YACjE,MAAM,IAAI,GAAG,wBAAS,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;YACrE,MAAM,MAAM,GAAG,wBAAS,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;YACzE,MAAM,UAAU,GAAG,wBAAS,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;YAGjF,IAAI,EAAE,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;gBAEzB,MAAM,mBAAmB,GACvB,UAAU,KAAK,UAAU,IAAI,UAAU,KAAK,UAAU,IAAI,UAAU,KAAK,SAAS;oBAChF,CAAC,CAAC,UAAU;oBACZ,CAAC,CAAC,SAAS,CAAC;gBAGhB,IAAI,eAAe,GAAG,MAAM,CAAC;gBAC7B,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;oBAChC,MAAM,MAAM,GAAG,IAAA,oCAAoB,EAAC,MAAM,CAAC,CAAC;oBAC5C,IAAI,MAAM,EAAE,CAAC;wBACX,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC;oBAC/B,CAAC;gBACH,CAAC;gBAGD,MAAM,YAAY,GAAG,8BAAY,CAAC,MAAM,CAAC;oBACvC,EAAE;oBACF,IAAI;oBACJ,MAAM,EAAE,eAAe;oBACvB,UAAU,EAAE,mBAAmB,IAAI,UAAU;iBAC9C,CAAC,CAAC;gBAEH,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AA1aD,kDA0aC","sourcesContent":["/**\n * RelationshipManager - Manages collections of relationships\n *\n * Handles relationship creation, tracking, and XML generation for various\n * document parts (document.xml, header.xml, footer.xml, etc.)\n */\n\nimport { Relationship, RelationshipType } from './Relationship.js';\nimport { XMLParser } from '../xml/XMLParser.js';\nimport { sanitizeHyperlinkUrl } from '../utils/validation.js';\nimport { InvalidDocxError, CorruptedArchiveError } from '../zip/errors.js';\n\n/**\n * Manages relationships for a document or document part\n */\nexport class RelationshipManager {\n private relationships: Map<string, Relationship>;\n private nextId: number;\n\n /**\n * Creates a new relationship manager\n */\n constructor() {\n this.relationships = new Map();\n this.nextId = 1;\n }\n\n /**\n * Adds a relationship\n * @param relationship The relationship to add\n * @returns The relationship that was added\n */\n addRelationship(relationship: Relationship): Relationship {\n this.relationships.set(relationship.getId(), relationship);\n\n // Update next ID if necessary\n const idMatch = /^rId(\\d+)$/.exec(relationship.getId());\n if (idMatch?.[1]) {\n const idNum = parseInt(idMatch[1], 10);\n if (idNum >= this.nextId) {\n this.nextId = idNum + 1;\n }\n }\n\n return relationship;\n }\n\n /**\n * Gets a relationship by ID\n * @param id The relationship ID\n */\n getRelationship(id: string): Relationship | undefined {\n return this.relationships.get(id);\n }\n\n /**\n * Gets all relationships\n */\n getAllRelationships(): Relationship[] {\n return Array.from(this.relationships.values());\n }\n\n /**\n * Gets relationships of a specific type\n * @param type The relationship type\n */\n getRelationshipsByType(type: string | RelationshipType): Relationship[] {\n return this.getAllRelationships().filter((rel) => rel.getType() === type);\n }\n\n /**\n * Checks if a relationship exists\n * @param id The relationship ID\n */\n hasRelationship(id: string): boolean {\n return this.relationships.has(id);\n }\n\n /**\n * Removes a relationship\n * @param id The relationship ID\n * @returns True if removed, false if not found\n */\n removeRelationship(id: string): boolean {\n return this.relationships.delete(id);\n }\n\n /**\n * Gets the number of relationships\n */\n getCount(): number {\n return this.relationships.size;\n }\n\n /**\n * Clears all relationships\n */\n clear(): this {\n this.relationships.clear();\n this.nextId = 1;\n return this;\n }\n\n /**\n * Generates a new unique relationship ID\n * @returns New relationship ID (e.g., 'rId1', 'rId2')\n */\n generateId(): string {\n return `rId${this.nextId++}`;\n }\n\n /**\n * Adds a styles relationship\n * @returns The created relationship\n */\n addStyles(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createStyles(id));\n }\n\n /**\n * Adds a numbering relationship\n * @returns The created relationship\n */\n addNumbering(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createNumbering(id));\n }\n\n /**\n * Adds a fontTable relationship\n * @returns The created relationship\n */\n addFontTable(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createFontTable(id));\n }\n\n /**\n * Adds a settings relationship\n * @returns The created relationship\n */\n addSettings(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createSettings(id));\n }\n\n /**\n * Adds a webSettings relationship\n * @returns The created relationship\n */\n addWebSettings(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createWebSettings(id));\n }\n\n /**\n * Adds a theme relationship\n * @returns The created relationship\n */\n addTheme(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createTheme(id));\n }\n\n /**\n * Adds an image relationship\n * @param target Image path relative to the part (e.g., 'media/image1.png')\n * @returns The created relationship\n */\n addImage(target: string): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createImage(id, target));\n }\n\n /**\n * Adds a header relationship\n * @param target Header file path (e.g., 'header1.xml')\n * @returns The created relationship\n */\n addHeader(target: string): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createHeader(id, target));\n }\n\n /**\n * Adds a footer relationship\n * @param target Footer file path (e.g., 'footer1.xml')\n * @returns The created relationship\n */\n addFooter(target: string): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createFooter(id, target));\n }\n\n /**\n * Adds a hyperlink relationship\n * @param url The hyperlink URL\n * @returns The created relationship\n */\n addHyperlink(url: string): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createHyperlink(id, url));\n }\n\n /**\n * Updates the target URL of an existing hyperlink relationship\n *\n * This method modifies an existing relationship's target in-place, maintaining\n * the same relationship ID. This is crucial for proper OpenXML compliance\n * per ECMA-376 §17.16.22, as it prevents orphaned relationships.\n *\n * @param relationshipId The ID of the relationship to update\n * @param newUrl The new URL to set\n * @returns True if updated, false if relationship not found\n */\n updateHyperlinkTarget(relationshipId: string, newUrl: string): boolean {\n const relationship = this.getRelationship(relationshipId);\n if (!relationship) {\n return false;\n }\n\n // Verify this is a hyperlink relationship\n if (relationship.getType() !== RelationshipType.HYPERLINK) {\n throw new InvalidDocxError(\n `Relationship ${relationshipId} is not a hyperlink relationship. ` +\n `Type is ${relationship.getType()}, expected ${RelationshipType.HYPERLINK}`\n );\n }\n\n // Update the target URL\n relationship.setTarget(newUrl);\n return true;\n }\n\n /**\n * Finds a hyperlink relationship by its target URL\n *\n * @param targetUrl The URL to search for\n * @returns The matching relationship, or undefined if not found\n */\n findHyperlinkByTarget(targetUrl: string): Relationship | undefined {\n return this.getAllRelationships().find(\n (rel) => rel.getType() === RelationshipType.HYPERLINK && rel.getTarget() === targetUrl\n );\n }\n\n /**\n * Gets or creates a hyperlink relationship for the given URL\n *\n * This method ensures we don't create duplicate relationships for the same URL.\n * If a relationship already exists for the URL, it returns the existing one.\n * Otherwise, it creates a new relationship.\n *\n * @param url The hyperlink URL\n * @returns The existing or newly created relationship\n */\n getOrCreateHyperlink(url: string): Relationship {\n // Check if relationship already exists for this URL\n const existing = this.findHyperlinkByTarget(url);\n if (existing) {\n return existing;\n }\n\n // Create new relationship\n return this.addHyperlink(url);\n }\n\n /**\n * Removes orphaned hyperlink relationships\n *\n * This method removes hyperlink relationships that are no longer referenced\n * by any hyperlink in the document. Call this after updating URLs to clean\n * up any orphaned relationships.\n *\n * @param referencedIds Set of relationship IDs that are still in use\n * @returns Number of relationships removed\n */\n removeOrphanedHyperlinks(referencedIds: Set<string>): number {\n let removed = 0;\n const toRemove: string[] = [];\n\n // Find orphaned relationships\n for (const rel of this.getAllRelationships()) {\n if (rel.getType() === RelationshipType.HYPERLINK && !referencedIds.has(rel.getId())) {\n toRemove.push(rel.getId());\n }\n }\n\n // Remove orphaned relationships\n for (const id of toRemove) {\n if (this.removeRelationship(id)) {\n removed++;\n }\n }\n\n return removed;\n }\n\n /**\n * Adds a comments relationship\n * @returns The created relationship\n */\n addComments(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createComments(id));\n }\n\n /**\n * Adds a footnotes relationship\n * @returns The created relationship\n */\n addFootnotes(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createFootnotes(id));\n }\n\n /**\n * Adds an endnotes relationship\n * @returns The created relationship\n */\n addEndnotes(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createEndnotes(id));\n }\n\n /**\n * Adds a people relationship (track changes authors)\n * @returns The created relationship\n */\n addPeople(): Relationship {\n const id = this.generateId();\n return this.addRelationship(Relationship.createPeople(id));\n }\n\n /**\n * Generates the relationships XML file content\n * @returns Complete XML string for .rels file\n */\n generateXml(): string {\n const relationships = this.getAllRelationships();\n\n let xml = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\\n';\n xml += '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\\n';\n\n for (const rel of relationships) {\n xml += rel.toXML() + '\\n';\n }\n\n xml += '</Relationships>';\n\n return xml;\n }\n\n /**\n * Creates a new relationship manager with common document relationships\n * @returns RelationshipManager with styles, numbering, fontTable, settings, and theme relationships\n */\n static createForDocument(): RelationshipManager {\n const manager = new RelationshipManager();\n manager.addStyles();\n manager.addNumbering();\n manager.addFontTable();\n manager.addSettings();\n manager.addWebSettings();\n manager.addTheme();\n return manager;\n }\n\n /**\n * Creates an empty relationship manager\n * @returns Empty RelationshipManager\n */\n static create(): RelationshipManager {\n return new RelationshipManager();\n }\n\n /**\n * Parses relationships from XML string and creates a populated manager\n * @param xml The relationships XML content (.rels file)\n * @returns RelationshipManager with parsed relationships\n */\n static fromXml(xml: string): RelationshipManager {\n const manager = new RelationshipManager();\n\n // Prevent ReDoS: validate input size (typical .rels files are < 10KB, max 10MB)\n if (xml.length > 10000000) {\n throw new CorruptedArchiveError(\n 'Relationships XML file too large (>10MB). Possible malicious input or corrupted file.'\n );\n }\n\n // Use XMLParser to extract all Relationship elements\n const relationshipElements = XMLParser.extractElements(xml, 'Relationship');\n\n // Prevent infinite loops: check relationship count\n if (relationshipElements.length > 1000) {\n throw new CorruptedArchiveError(\n 'Too many relationships in XML file (>1000). Possible malicious input.'\n );\n }\n\n // Process each relationship element\n for (const relationshipElement of relationshipElements) {\n // Extract attributes using XMLParser\n const id = XMLParser.extractAttribute(relationshipElement, 'Id');\n const type = XMLParser.extractAttribute(relationshipElement, 'Type');\n const target = XMLParser.extractAttribute(relationshipElement, 'Target');\n const targetMode = XMLParser.extractAttribute(relationshipElement, 'TargetMode');\n\n // Only create relationship if all required attributes present\n if (id && type && target) {\n // Validate targetMode before type assertion\n const validatedTargetMode =\n targetMode === 'Internal' || targetMode === 'External' || targetMode === undefined\n ? targetMode\n : undefined;\n\n // Sanitize hyperlink URLs (strip browser extension prefixes)\n let sanitizedTarget = target;\n if (type.endsWith('/hyperlink')) {\n const result = sanitizeHyperlinkUrl(target);\n if (result) {\n sanitizedTarget = result.url;\n }\n }\n\n // Create and add relationship\n const relationship = Relationship.create({\n id,\n type,\n target: sanitizedTarget,\n targetMode: validatedTargetMode || 'Internal',\n });\n\n manager.addRelationship(relationship);\n }\n }\n\n return manager;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"RelationshipManager.js","sourceRoot":"","sources":["../../src/core/RelationshipManager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * RelationshipManager - Manages collections of relationships\r\n *\r\n * Handles relationship creation, tracking, and XML generation for various\r\n * document parts (document.xml, header.xml, footer.xml, etc.)\r\n */\r\n\r\nimport { Relationship, RelationshipType } from './Relationship.js';\r\nimport { XMLParser } from '../xml/XMLParser.js';\r\nimport { sanitizeHyperlinkUrl } from '../utils/validation.js';\r\nimport { InvalidDocxError, CorruptedArchiveError } from '../zip/errors.js';\r\n\r\n/**\r\n * Manages relationships for a document or document part\r\n */\r\nexport class RelationshipManager {\r\n private relationships: Map<string, Relationship>;\r\n private nextId: number;\r\n\r\n /**\r\n * Creates a new relationship manager\r\n */\r\n constructor() {\r\n this.relationships = new Map();\r\n this.nextId = 1;\r\n }\r\n\r\n /**\r\n * Adds a relationship\r\n * @param relationship The relationship to add\r\n * @returns The relationship that was added\r\n */\r\n addRelationship(relationship: Relationship): Relationship {\r\n this.relationships.set(relationship.getId(), relationship);\r\n\r\n // Update next ID if necessary\r\n const idMatch = /^rId(\\d+)$/.exec(relationship.getId());\r\n if (idMatch?.[1]) {\r\n const idNum = parseInt(idMatch[1], 10);\r\n if (idNum >= this.nextId) {\r\n this.nextId = idNum + 1;\r\n }\r\n }\r\n\r\n return relationship;\r\n }\r\n\r\n /**\r\n * Gets a relationship by ID\r\n * @param id The relationship ID\r\n */\r\n getRelationship(id: string): Relationship | undefined {\r\n return this.relationships.get(id);\r\n }\r\n\r\n /**\r\n * Gets all relationships\r\n */\r\n getAllRelationships(): Relationship[] {\r\n return Array.from(this.relationships.values());\r\n }\r\n\r\n /**\r\n * Gets relationships of a specific type\r\n * @param type The relationship type\r\n */\r\n getRelationshipsByType(type: string | RelationshipType): Relationship[] {\r\n return this.getAllRelationships().filter((rel) => rel.getType() === type);\r\n }\r\n\r\n /**\r\n * Checks if a relationship exists\r\n * @param id The relationship ID\r\n */\r\n hasRelationship(id: string): boolean {\r\n return this.relationships.has(id);\r\n }\r\n\r\n /**\r\n * Removes a relationship\r\n * @param id The relationship ID\r\n * @returns True if removed, false if not found\r\n */\r\n removeRelationship(id: string): boolean {\r\n return this.relationships.delete(id);\r\n }\r\n\r\n /**\r\n * Gets the number of relationships\r\n */\r\n getCount(): number {\r\n return this.relationships.size;\r\n }\r\n\r\n /**\r\n * Clears all relationships\r\n */\r\n clear(): this {\r\n this.relationships.clear();\r\n this.nextId = 1;\r\n return this;\r\n }\r\n\r\n /**\r\n * Generates a new unique relationship ID\r\n * @returns New relationship ID (e.g., 'rId1', 'rId2')\r\n */\r\n generateId(): string {\r\n return `rId${this.nextId++}`;\r\n }\r\n\r\n /**\r\n * Adds a styles relationship\r\n * @returns The created relationship\r\n */\r\n addStyles(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createStyles(id));\r\n }\r\n\r\n /**\r\n * Adds a numbering relationship\r\n * @returns The created relationship\r\n */\r\n addNumbering(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createNumbering(id));\r\n }\r\n\r\n /**\r\n * Adds a fontTable relationship\r\n * @returns The created relationship\r\n */\r\n addFontTable(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createFontTable(id));\r\n }\r\n\r\n /**\r\n * Adds a settings relationship\r\n * @returns The created relationship\r\n */\r\n addSettings(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createSettings(id));\r\n }\r\n\r\n /**\r\n * Adds a webSettings relationship\r\n * @returns The created relationship\r\n */\r\n addWebSettings(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createWebSettings(id));\r\n }\r\n\r\n /**\r\n * Adds a theme relationship\r\n * @returns The created relationship\r\n */\r\n addTheme(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createTheme(id));\r\n }\r\n\r\n /**\r\n * Adds an image relationship\r\n * @param target Image path relative to the part (e.g., 'media/image1.png')\r\n * @returns The created relationship\r\n */\r\n addImage(target: string): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createImage(id, target));\r\n }\r\n\r\n /**\r\n * Adds a header relationship\r\n * @param target Header file path (e.g., 'header1.xml')\r\n * @returns The created relationship\r\n */\r\n addHeader(target: string): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createHeader(id, target));\r\n }\r\n\r\n /**\r\n * Adds a footer relationship\r\n * @param target Footer file path (e.g., 'footer1.xml')\r\n * @returns The created relationship\r\n */\r\n addFooter(target: string): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createFooter(id, target));\r\n }\r\n\r\n /**\r\n * Adds a hyperlink relationship\r\n * @param url The hyperlink URL\r\n * @returns The created relationship\r\n */\r\n addHyperlink(url: string): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createHyperlink(id, url));\r\n }\r\n\r\n /**\r\n * Updates the target URL of an existing hyperlink relationship\r\n *\r\n * This method modifies an existing relationship's target in-place, maintaining\r\n * the same relationship ID. This is crucial for proper OpenXML compliance\r\n * per ECMA-376 §17.16.22, as it prevents orphaned relationships.\r\n *\r\n * @param relationshipId The ID of the relationship to update\r\n * @param newUrl The new URL to set\r\n * @returns True if updated, false if relationship not found\r\n */\r\n updateHyperlinkTarget(relationshipId: string, newUrl: string): boolean {\r\n const relationship = this.getRelationship(relationshipId);\r\n if (!relationship) {\r\n return false;\r\n }\r\n\r\n // Verify this is a hyperlink relationship\r\n if (relationship.getType() !== RelationshipType.HYPERLINK) {\r\n throw new InvalidDocxError(\r\n `Relationship ${relationshipId} is not a hyperlink relationship. ` +\r\n `Type is ${relationship.getType()}, expected ${RelationshipType.HYPERLINK}`\r\n );\r\n }\r\n\r\n // Update the target URL\r\n relationship.setTarget(newUrl);\r\n return true;\r\n }\r\n\r\n /**\r\n * Finds a hyperlink relationship by its target URL\r\n *\r\n * @param targetUrl The URL to search for\r\n * @returns The matching relationship, or undefined if not found\r\n */\r\n findHyperlinkByTarget(targetUrl: string): Relationship | undefined {\r\n return this.getAllRelationships().find(\r\n (rel) => rel.getType() === RelationshipType.HYPERLINK && rel.getTarget() === targetUrl\r\n );\r\n }\r\n\r\n /**\r\n * Gets or creates a hyperlink relationship for the given URL\r\n *\r\n * This method ensures we don't create duplicate relationships for the same URL.\r\n * If a relationship already exists for the URL, it returns the existing one.\r\n * Otherwise, it creates a new relationship.\r\n *\r\n * @param url The hyperlink URL\r\n * @returns The existing or newly created relationship\r\n */\r\n getOrCreateHyperlink(url: string): Relationship {\r\n // Check if relationship already exists for this URL\r\n const existing = this.findHyperlinkByTarget(url);\r\n if (existing) {\r\n return existing;\r\n }\r\n\r\n // Create new relationship\r\n return this.addHyperlink(url);\r\n }\r\n\r\n /**\r\n * Removes orphaned hyperlink relationships\r\n *\r\n * This method removes hyperlink relationships that are no longer referenced\r\n * by any hyperlink in the document. Call this after updating URLs to clean\r\n * up any orphaned relationships.\r\n *\r\n * @param referencedIds Set of relationship IDs that are still in use\r\n * @returns Number of relationships removed\r\n */\r\n removeOrphanedHyperlinks(referencedIds: Set<string>): number {\r\n let removed = 0;\r\n const toRemove: string[] = [];\r\n\r\n // Find orphaned relationships\r\n for (const rel of this.getAllRelationships()) {\r\n if (rel.getType() === RelationshipType.HYPERLINK && !referencedIds.has(rel.getId())) {\r\n toRemove.push(rel.getId());\r\n }\r\n }\r\n\r\n // Remove orphaned relationships\r\n for (const id of toRemove) {\r\n if (this.removeRelationship(id)) {\r\n removed++;\r\n }\r\n }\r\n\r\n return removed;\r\n }\r\n\r\n /**\r\n * Adds a comments relationship\r\n * @returns The created relationship\r\n */\r\n addComments(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createComments(id));\r\n }\r\n\r\n /**\r\n * Adds a footnotes relationship\r\n * @returns The created relationship\r\n */\r\n addFootnotes(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createFootnotes(id));\r\n }\r\n\r\n /**\r\n * Adds an endnotes relationship\r\n * @returns The created relationship\r\n */\r\n addEndnotes(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createEndnotes(id));\r\n }\r\n\r\n /**\r\n * Adds a people relationship (track changes authors)\r\n * @returns The created relationship\r\n */\r\n addPeople(): Relationship {\r\n const id = this.generateId();\r\n return this.addRelationship(Relationship.createPeople(id));\r\n }\r\n\r\n /**\r\n * Generates the relationships XML file content\r\n * @returns Complete XML string for .rels file\r\n */\r\n generateXml(): string {\r\n const relationships = this.getAllRelationships();\r\n\r\n let xml = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\\n';\r\n xml += '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\\n';\r\n\r\n for (const rel of relationships) {\r\n xml += rel.toXML() + '\\n';\r\n }\r\n\r\n xml += '</Relationships>';\r\n\r\n return xml;\r\n }\r\n\r\n /**\r\n * Creates a new relationship manager with common document relationships\r\n * @returns RelationshipManager with styles, numbering, fontTable, settings, and theme relationships\r\n */\r\n static createForDocument(): RelationshipManager {\r\n const manager = new RelationshipManager();\r\n manager.addStyles();\r\n manager.addNumbering();\r\n manager.addFontTable();\r\n manager.addSettings();\r\n manager.addWebSettings();\r\n manager.addTheme();\r\n return manager;\r\n }\r\n\r\n /**\r\n * Creates an empty relationship manager\r\n * @returns Empty RelationshipManager\r\n */\r\n static create(): RelationshipManager {\r\n return new RelationshipManager();\r\n }\r\n\r\n /**\r\n * Parses relationships from XML string and creates a populated manager\r\n * @param xml The relationships XML content (.rels file)\r\n * @returns RelationshipManager with parsed relationships\r\n */\r\n static fromXml(xml: string): RelationshipManager {\r\n const manager = new RelationshipManager();\r\n\r\n // Prevent ReDoS: validate input size (typical .rels files are < 10KB, max 10MB)\r\n if (xml.length > 10000000) {\r\n throw new CorruptedArchiveError(\r\n 'Relationships XML file too large (>10MB). Possible malicious input or corrupted file.'\r\n );\r\n }\r\n\r\n // Use XMLParser to extract all Relationship elements\r\n const relationshipElements = XMLParser.extractElements(xml, 'Relationship');\r\n\r\n // The 10MB size cap above is the primary bound on the work performed here;\r\n // this count check is a far-above-normal backstop. Link- and image-heavy\r\n // documents (each unique hyperlink URL or image is one OPC relationship)\r\n // legitimately exceed several thousand entries, so the limit must stay well\r\n // clear of any realistic part.\r\n if (relationshipElements.length > 100000) {\r\n throw new CorruptedArchiveError(\r\n 'Too many relationships in XML file (>100000). Possible malicious input or corrupted file.'\r\n );\r\n }\r\n\r\n // Process each relationship element\r\n for (const relationshipElement of relationshipElements) {\r\n // Extract attributes using XMLParser\r\n const id = XMLParser.extractAttribute(relationshipElement, 'Id');\r\n const type = XMLParser.extractAttribute(relationshipElement, 'Type');\r\n const target = XMLParser.extractAttribute(relationshipElement, 'Target');\r\n const targetMode = XMLParser.extractAttribute(relationshipElement, 'TargetMode');\r\n\r\n // Only create relationship if all required attributes present\r\n if (id && type && target) {\r\n // Validate targetMode before type assertion\r\n const validatedTargetMode =\r\n targetMode === 'Internal' || targetMode === 'External' || targetMode === undefined\r\n ? targetMode\r\n : undefined;\r\n\r\n // Sanitize hyperlink URLs (strip browser extension prefixes)\r\n let sanitizedTarget = target;\r\n if (type.endsWith('/hyperlink')) {\r\n const result = sanitizeHyperlinkUrl(target);\r\n if (result) {\r\n sanitizedTarget = result.url;\r\n }\r\n }\r\n\r\n // Create and add relationship\r\n const relationship = Relationship.create({\r\n id,\r\n type,\r\n target: sanitizedTarget,\r\n targetMode: validatedTargetMode || 'Internal',\r\n });\r\n\r\n manager.addRelationship(relationship);\r\n }\r\n }\r\n\r\n return manager;\r\n }\r\n}\r\n"]}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { Run } from './Run.js';
|
|
2
2
|
import { XMLElement } from '../xml/XMLBuilder.js';
|
|
3
|
+
export interface CommentPreservedContent {
|
|
4
|
+
rawXml: string;
|
|
5
|
+
runs: Run[];
|
|
6
|
+
}
|
|
7
|
+
export type CommentContentItem = Run | CommentPreservedContent;
|
|
8
|
+
export interface CommentParagraph {
|
|
9
|
+
pPr?: string;
|
|
10
|
+
content: CommentContentItem[];
|
|
11
|
+
}
|
|
3
12
|
export interface CommentProperties {
|
|
4
13
|
id?: number;
|
|
5
14
|
author: string;
|
|
@@ -14,13 +23,16 @@ export declare class Comment {
|
|
|
14
23
|
private author;
|
|
15
24
|
private initials;
|
|
16
25
|
private date;
|
|
17
|
-
private
|
|
26
|
+
private paragraphs;
|
|
18
27
|
private parentId?;
|
|
19
28
|
private done;
|
|
29
|
+
private onModified;
|
|
20
30
|
constructor(properties: CommentProperties);
|
|
21
31
|
private generateInitials;
|
|
22
32
|
getId(): number;
|
|
23
33
|
setId(id: number): void;
|
|
34
|
+
setModifiedCallback(callback: () => void): void;
|
|
35
|
+
private notifyModified;
|
|
24
36
|
getAuthor(): string;
|
|
25
37
|
setAuthor(author: string): this;
|
|
26
38
|
getInitials(): string;
|
|
@@ -34,6 +46,8 @@ export declare class Comment {
|
|
|
34
46
|
unresolve(): this;
|
|
35
47
|
getRuns(): Run[];
|
|
36
48
|
addRun(run: Run): this;
|
|
49
|
+
getParagraphs(): CommentParagraph[];
|
|
50
|
+
setParagraphs(paragraphs: CommentParagraph[]): void;
|
|
37
51
|
getText(): string;
|
|
38
52
|
getContent(): string;
|
|
39
53
|
private formatDate;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Comment.d.ts","sourceRoot":"","sources":["../../src/elements/Comment.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"Comment.d.ts","sourceRoot":"","sources":["../../src/elements/Comment.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AASlD,MAAM,WAAW,uBAAuB;IAEtC,MAAM,EAAE,MAAM,CAAC;IAEf,IAAI,EAAE,GAAG,EAAE,CAAC;CACb;AAGD,MAAM,MAAM,kBAAkB,GAAG,GAAG,GAAG,uBAAuB,CAAC;AAO/D,MAAM,WAAW,gBAAgB;IAE/B,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAKD,MAAM,WAAW,iBAAiB;IAEhC,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,MAAM,EAAE,MAAM,CAAC;IAEf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,IAAI,CAAC,EAAE,IAAI,CAAC;IAEZ,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC;IAE9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAKD,qBAAa,OAAO;IAClB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,UAAU,CAA6B;gBAMnC,UAAU,EAAE,iBAAiB;IAwBzC,OAAO,CAAC,gBAAgB;IAmBxB,KAAK,IAAI,MAAM;IAQf,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAWvB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAI/C,OAAO,CAAC,cAAc;IAStB,SAAS,IAAI,MAAM;IAOnB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAS/B,WAAW,IAAI,MAAM;IAOrB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IASnC,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IASzB,WAAW,IAAI,MAAM,GAAG,SAAS;IAOjC,OAAO,IAAI,OAAO;IAQlB,UAAU,IAAI,OAAO;IAQrB,OAAO,IAAI,IAAI;IAUf,SAAS,IAAI,IAAI;IAUjB,OAAO,IAAI,GAAG,EAAE;IAiBhB,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IActB,aAAa,IAAI,gBAAgB,EAAE;IAcnC,aAAa,CAAC,UAAU,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAOnD,OAAO,IAAI,MAAM;IASjB,UAAU,IAAI,MAAM;IAQpB,OAAO,CAAC,UAAU;IAQlB,eAAe,IAAI,UAAU;IAc7B,aAAa,IAAI,UAAU;IAc3B,cAAc,IAAI,UAAU;IAmB5B,KAAK,IAAI,UAAU;IAkDnB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAgBxF,MAAM,CAAC,WAAW,CAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,EAC7B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO;IAgBV,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;CAOhF"}
|
package/dist/elements/Comment.js
CHANGED
|
@@ -8,9 +8,10 @@ class Comment {
|
|
|
8
8
|
author;
|
|
9
9
|
initials;
|
|
10
10
|
date;
|
|
11
|
-
|
|
11
|
+
paragraphs;
|
|
12
12
|
parentId;
|
|
13
13
|
done;
|
|
14
|
+
onModified = null;
|
|
14
15
|
constructor(properties) {
|
|
15
16
|
this.id = properties.id ?? 0;
|
|
16
17
|
this.author = properties.author;
|
|
@@ -18,15 +19,17 @@ class Comment {
|
|
|
18
19
|
this.date = properties.date || new Date();
|
|
19
20
|
this.parentId = properties.parentId;
|
|
20
21
|
this.done = properties.done ?? false;
|
|
22
|
+
let runs;
|
|
21
23
|
if (typeof properties.content === 'string') {
|
|
22
|
-
|
|
24
|
+
runs = [new Run_js_1.Run(properties.content)];
|
|
23
25
|
}
|
|
24
26
|
else if (Array.isArray(properties.content)) {
|
|
25
|
-
|
|
27
|
+
runs = properties.content;
|
|
26
28
|
}
|
|
27
29
|
else {
|
|
28
|
-
|
|
30
|
+
runs = [properties.content];
|
|
29
31
|
}
|
|
32
|
+
this.paragraphs = [{ content: runs }];
|
|
30
33
|
}
|
|
31
34
|
generateInitials(author) {
|
|
32
35
|
const words = author
|
|
@@ -49,11 +52,20 @@ class Comment {
|
|
|
49
52
|
setId(id) {
|
|
50
53
|
this.id = id;
|
|
51
54
|
}
|
|
55
|
+
setModifiedCallback(callback) {
|
|
56
|
+
this.onModified = callback;
|
|
57
|
+
}
|
|
58
|
+
notifyModified() {
|
|
59
|
+
if (this.onModified) {
|
|
60
|
+
this.onModified();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
52
63
|
getAuthor() {
|
|
53
64
|
return this.author;
|
|
54
65
|
}
|
|
55
66
|
setAuthor(author) {
|
|
56
67
|
this.author = author;
|
|
68
|
+
this.notifyModified();
|
|
57
69
|
return this;
|
|
58
70
|
}
|
|
59
71
|
getInitials() {
|
|
@@ -61,6 +73,7 @@ class Comment {
|
|
|
61
73
|
}
|
|
62
74
|
setInitials(initials) {
|
|
63
75
|
this.initials = initials;
|
|
76
|
+
this.notifyModified();
|
|
64
77
|
return this;
|
|
65
78
|
}
|
|
66
79
|
getDate() {
|
|
@@ -68,6 +81,7 @@ class Comment {
|
|
|
68
81
|
}
|
|
69
82
|
setDate(date) {
|
|
70
83
|
this.date = date;
|
|
84
|
+
this.notifyModified();
|
|
71
85
|
return this;
|
|
72
86
|
}
|
|
73
87
|
getParentId() {
|
|
@@ -81,21 +95,51 @@ class Comment {
|
|
|
81
95
|
}
|
|
82
96
|
resolve() {
|
|
83
97
|
this.done = true;
|
|
98
|
+
this.notifyModified();
|
|
84
99
|
return this;
|
|
85
100
|
}
|
|
86
101
|
unresolve() {
|
|
87
102
|
this.done = false;
|
|
103
|
+
this.notifyModified();
|
|
88
104
|
return this;
|
|
89
105
|
}
|
|
90
106
|
getRuns() {
|
|
91
|
-
|
|
107
|
+
const runs = [];
|
|
108
|
+
for (const paragraph of this.paragraphs) {
|
|
109
|
+
for (const item of paragraph.content) {
|
|
110
|
+
if (item instanceof Run_js_1.Run) {
|
|
111
|
+
runs.push(item);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
runs.push(...item.runs);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return runs;
|
|
92
119
|
}
|
|
93
120
|
addRun(run) {
|
|
94
|
-
this.
|
|
121
|
+
let last = this.paragraphs[this.paragraphs.length - 1];
|
|
122
|
+
if (!last) {
|
|
123
|
+
last = { content: [] };
|
|
124
|
+
this.paragraphs.push(last);
|
|
125
|
+
}
|
|
126
|
+
last.content.push(run);
|
|
127
|
+
this.notifyModified();
|
|
95
128
|
return this;
|
|
96
129
|
}
|
|
130
|
+
getParagraphs() {
|
|
131
|
+
return this.paragraphs.map((paragraph) => ({
|
|
132
|
+
pPr: paragraph.pPr,
|
|
133
|
+
content: [...paragraph.content],
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
setParagraphs(paragraphs) {
|
|
137
|
+
this.paragraphs = paragraphs;
|
|
138
|
+
}
|
|
97
139
|
getText() {
|
|
98
|
-
return this.
|
|
140
|
+
return this.getRuns()
|
|
141
|
+
.map((run) => run.getText())
|
|
142
|
+
.join('');
|
|
99
143
|
}
|
|
100
144
|
getContent() {
|
|
101
145
|
return this.getText();
|
|
@@ -148,14 +192,25 @@ class Comment {
|
|
|
148
192
|
if (this.done) {
|
|
149
193
|
attributes['w:done'] = '1';
|
|
150
194
|
}
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
195
|
+
const commentParagraphs = this.paragraphs.map((paragraph) => {
|
|
196
|
+
const children = [];
|
|
197
|
+
if (paragraph.pPr) {
|
|
198
|
+
children.push({ name: '__rawXml', rawXml: paragraph.pPr });
|
|
199
|
+
}
|
|
200
|
+
for (const item of paragraph.content) {
|
|
201
|
+
if (item instanceof Run_js_1.Run) {
|
|
202
|
+
children.push(item.toXML());
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
children.push({ name: '__rawXml', rawXml: item.rawXml });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return { name: 'w:p', children };
|
|
209
|
+
});
|
|
155
210
|
return {
|
|
156
211
|
name: 'w:comment',
|
|
157
212
|
attributes,
|
|
158
|
-
children:
|
|
213
|
+
children: commentParagraphs,
|
|
159
214
|
};
|
|
160
215
|
}
|
|
161
216
|
static create(author, content, initials) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Comment.js","sourceRoot":"","sources":["../../src/elements/Comment.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Comment - Represents a comment/annotation in a Word document\n *\n * Comments allow users to annotate specific text ranges in a document.\n * They include author, date, content, and can have replies.\n */\n\nimport { Run } from './Run.js';\nimport { XMLElement } from '../xml/XMLBuilder.js';\nimport { formatDateForXml } from '../utils/dateFormatting.js';\n\n/**\n * Comment properties\n */\nexport interface CommentProperties {\n /** Unique comment ID (assigned by CommentManager) */\n id?: number;\n /** Author who created the comment */\n author: string;\n /** Author's initials (optional) */\n initials?: string;\n /** Date when the comment was created */\n date?: Date;\n /** Comment content (text or runs) */\n content: string | Run | Run[];\n /** Parent comment ID (for replies) */\n parentId?: number;\n /** Whether the comment is resolved/done (w:done attribute per ECMA-376) */\n done?: boolean;\n}\n\n/**\n * Represents a comment/annotation in a document\n */\nexport class Comment {\n private id: number;\n private author: string;\n private initials: string;\n private date: Date;\n private runs: Run[];\n private parentId?: number;\n private done: boolean;\n\n /**\n * Creates a new Comment\n * @param properties - Comment properties\n */\n constructor(properties: CommentProperties) {\n this.id = properties.id ?? 0; // Will be assigned by CommentManager\n this.author = properties.author;\n this.initials = properties.initials || this.generateInitials(properties.author);\n this.date = properties.date || new Date();\n this.parentId = properties.parentId;\n this.done = properties.done ?? false;\n\n // Convert content to runs\n if (typeof properties.content === 'string') {\n this.runs = [new Run(properties.content)];\n } else if (Array.isArray(properties.content)) {\n this.runs = properties.content;\n } else {\n this.runs = [properties.content];\n }\n }\n\n /**\n * Generates initials from author name\n * Examples: \"John Doe\" -> \"JD\", \"Jane Smith\" -> \"JS\"\n */\n private generateInitials(author: string): string {\n const words = author\n .trim()\n .split(/\\s+/)\n .filter((w) => w.length > 0);\n if (words.length === 0) return 'U';\n if (words.length === 1) return (words[0] || 'U').substring(0, 2).toUpperCase();\n return (\n words\n .map((word) => word[0] || '')\n .join('')\n .toUpperCase()\n .substring(0, 3) || 'U'\n );\n }\n\n /**\n * Gets the comment ID\n */\n getId(): number {\n return this.id;\n }\n\n /**\n * Sets the comment ID (used by CommentManager)\n * @internal\n */\n setId(id: number): void {\n this.id = id;\n }\n\n /**\n * Gets the author\n */\n getAuthor(): string {\n return this.author;\n }\n\n /**\n * Sets the author\n */\n setAuthor(author: string): this {\n this.author = author;\n return this;\n }\n\n /**\n * Gets the author's initials\n */\n getInitials(): string {\n return this.initials;\n }\n\n /**\n * Sets the author's initials\n */\n setInitials(initials: string): this {\n this.initials = initials;\n return this;\n }\n\n /**\n * Gets the comment date\n */\n getDate(): Date {\n return this.date;\n }\n\n /**\n * Sets the comment date\n */\n setDate(date: Date): this {\n this.date = date;\n return this;\n }\n\n /**\n * Gets the parent comment ID (for replies)\n */\n getParentId(): number | undefined {\n return this.parentId;\n }\n\n /**\n * Checks if this is a reply to another comment\n */\n isReply(): boolean {\n return this.parentId !== undefined;\n }\n\n /**\n * Checks if the comment is resolved/done\n * Per ECMA-376 Part 1, Section 17.13.4.2 (w:done attribute)\n */\n isResolved(): boolean {\n return this.done;\n }\n\n /**\n * Marks the comment as resolved/done\n * Sets w:done=\"1\" in the XML output\n */\n resolve(): this {\n this.done = true;\n return this;\n }\n\n /**\n * Marks the comment as unresolved\n * Removes w:done attribute from XML output\n */\n unresolve(): this {\n this.done = false;\n return this;\n }\n\n /**\n * Gets the runs in this comment\n */\n getRuns(): Run[] {\n return [...this.runs];\n }\n\n /**\n * Adds a run to this comment\n */\n addRun(run: Run): this {\n this.runs.push(run);\n return this;\n }\n\n /**\n * Gets the comment text (combines all runs)\n */\n getText(): string {\n return this.runs.map((run) => run.getText()).join('');\n }\n\n /**\n * Gets the comment content (alias for getText for compatibility)\n */\n getContent(): string {\n return this.getText();\n }\n\n /**\n * Formats a date to ISO 8601 format for XML\n * Uses formatDateForXml() to strip milliseconds which Word does not accept.\n */\n private formatDate(date: Date): string {\n return formatDateForXml(date);\n }\n\n /**\n * Generates XML for the comment range start marker\n * This goes in word/document.xml at the start of the commented range\n */\n toRangeStartXML(): XMLElement {\n return {\n name: 'w:commentRangeStart',\n attributes: {\n 'w:id': this.id.toString(),\n },\n selfClosing: true,\n };\n }\n\n /**\n * Generates XML for the comment range end marker\n * This goes in word/document.xml at the end of the commented range\n */\n toRangeEndXML(): XMLElement {\n return {\n name: 'w:commentRangeEnd',\n attributes: {\n 'w:id': this.id.toString(),\n },\n selfClosing: true,\n };\n }\n\n /**\n * Generates XML for the comment reference\n * This goes in word/document.xml after the range end, inside a run\n */\n toReferenceXML(): XMLElement {\n return {\n name: 'w:r',\n children: [\n {\n name: 'w:commentReference',\n attributes: {\n 'w:id': this.id.toString(),\n },\n selfClosing: true,\n },\n ],\n };\n }\n\n /**\n * Generates XML for the comment definition\n * This goes in word/comments.xml\n */\n toXML(): XMLElement {\n const attributes: Record<string, string> = {\n 'w:id': this.id.toString(),\n 'w:author': this.author,\n 'w:date': this.formatDate(this.date),\n 'w:initials': this.initials,\n };\n\n // Add parent ID for replies (w15 namespace per Office 2012 extensions)\n if (this.parentId !== undefined) {\n attributes['w15:parentId'] = this.parentId.toString();\n }\n\n // Add done attribute for resolved comments (per ECMA-376)\n if (this.done) {\n attributes['w:done'] = '1';\n }\n\n // Create paragraph containing the comment content\n const commentParagraph: XMLElement = {\n name: 'w:p',\n children: this.runs.map((run) => run.toXML()),\n };\n\n return {\n name: 'w:comment',\n attributes,\n children: [commentParagraph],\n };\n }\n\n /**\n * Creates a new comment\n * @param author - Comment author\n * @param content - Comment content (text or runs)\n * @param initials - Optional author initials\n * @returns New Comment instance\n */\n static create(author: string, content: string | Run | Run[], initials?: string): Comment {\n return new Comment({\n author,\n content,\n initials,\n });\n }\n\n /**\n * Creates a reply to an existing comment\n * @param parentId - ID of the parent comment\n * @param author - Reply author\n * @param content - Reply content (text or runs)\n * @param initials - Optional author initials\n * @returns New Comment instance (reply)\n */\n static createReply(\n parentId: number,\n author: string,\n content: string | Run | Run[],\n initials?: string\n ): Comment {\n return new Comment({\n author,\n content,\n initials,\n parentId,\n });\n }\n\n /**\n * Creates a comment with formatted content\n * @param author - Comment author\n * @param runs - Array of formatted runs\n * @param initials - Optional author initials\n * @returns New Comment instance\n */\n static createFormatted(author: string, runs: Run[], initials?: string): Comment {\n return new Comment({\n author,\n content: runs,\n initials,\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Comment.js","sourceRoot":"","sources":["../../src/elements/Comment.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Comment - Represents a comment/annotation in a Word document\n *\n * Comments allow users to annotate specific text ranges in a document.\n * They include author, date, content, and can have replies.\n */\n\nimport { Run } from './Run.js';\nimport { XMLElement } from '../xml/XMLBuilder.js';\nimport { formatDateForXml } from '../utils/dateFormatting.js';\n\n/**\n * Inline comment content preserved as raw XML (e.g. w:hyperlink wrappers\n * from a parsed comments.xml). The wrapper is re-emitted verbatim on\n * regeneration so its r:id target survives; the runs parsed from inside\n * it are kept alongside so text extraction still sees their text.\n */\nexport interface CommentPreservedContent {\n /** Original XML emitted verbatim when comments.xml is regenerated */\n rawXml: string;\n /** Runs parsed from inside the preserved element (text extraction only) */\n runs: Run[];\n}\n\n/** Ordered item of comment paragraph content */\nexport type CommentContentItem = Run | CommentPreservedContent;\n\n/**\n * One paragraph of comment content. CT_Comment accepts block-level content\n * (ECMA-376 §17.13.4.2), so comments can span multiple paragraphs, each\n * with its own paragraph properties (typically the CommentText style).\n */\nexport interface CommentParagraph {\n /** Raw <w:pPr> XML preserved for round-trip */\n pPr?: string;\n /** Paragraph content in document order */\n content: CommentContentItem[];\n}\n\n/**\n * Comment properties\n */\nexport interface CommentProperties {\n /** Unique comment ID (assigned by CommentManager) */\n id?: number;\n /** Author who created the comment */\n author: string;\n /** Author's initials (optional) */\n initials?: string;\n /** Date when the comment was created */\n date?: Date;\n /** Comment content (text or runs) */\n content: string | Run | Run[];\n /** Parent comment ID (for replies) */\n parentId?: number;\n /** Whether the comment is resolved/done (w:done attribute per ECMA-376) */\n done?: boolean;\n}\n\n/**\n * Represents a comment/annotation in a document\n */\nexport class Comment {\n private id: number;\n private author: string;\n private initials: string;\n private date: Date;\n private paragraphs: CommentParagraph[];\n private parentId?: number;\n private done: boolean;\n private onModified: (() => void) | null = null;\n\n /**\n * Creates a new Comment\n * @param properties - Comment properties\n */\n constructor(properties: CommentProperties) {\n this.id = properties.id ?? 0; // Will be assigned by CommentManager\n this.author = properties.author;\n this.initials = properties.initials || this.generateInitials(properties.author);\n this.date = properties.date || new Date();\n this.parentId = properties.parentId;\n this.done = properties.done ?? false;\n\n // Convert content to runs in a single paragraph\n let runs: Run[];\n if (typeof properties.content === 'string') {\n runs = [new Run(properties.content)];\n } else if (Array.isArray(properties.content)) {\n runs = properties.content;\n } else {\n runs = [properties.content];\n }\n this.paragraphs = [{ content: runs }];\n }\n\n /**\n * Generates initials from author name\n * Examples: \"John Doe\" -> \"JD\", \"Jane Smith\" -> \"JS\"\n */\n private generateInitials(author: string): string {\n const words = author\n .trim()\n .split(/\\s+/)\n .filter((w) => w.length > 0);\n if (words.length === 0) return 'U';\n if (words.length === 1) return (words[0] || 'U').substring(0, 2).toUpperCase();\n return (\n words\n .map((word) => word[0] || '')\n .join('')\n .toUpperCase()\n .substring(0, 3) || 'U'\n );\n }\n\n /**\n * Gets the comment ID\n */\n getId(): number {\n return this.id;\n }\n\n /**\n * Sets the comment ID (used by CommentManager)\n * @internal\n */\n setId(id: number): void {\n this.id = id;\n }\n\n /**\n * Registers a callback invoked whenever this comment is mutated.\n * Document wires this to its comments dirty flag so edits to parsed\n * comments trigger regeneration of comments.xml instead of being\n * silently discarded by the original-XML passthrough on save.\n * @internal\n */\n setModifiedCallback(callback: () => void): void {\n this.onModified = callback;\n }\n\n private notifyModified(): void {\n if (this.onModified) {\n this.onModified();\n }\n }\n\n /**\n * Gets the author\n */\n getAuthor(): string {\n return this.author;\n }\n\n /**\n * Sets the author\n */\n setAuthor(author: string): this {\n this.author = author;\n this.notifyModified();\n return this;\n }\n\n /**\n * Gets the author's initials\n */\n getInitials(): string {\n return this.initials;\n }\n\n /**\n * Sets the author's initials\n */\n setInitials(initials: string): this {\n this.initials = initials;\n this.notifyModified();\n return this;\n }\n\n /**\n * Gets the comment date\n */\n getDate(): Date {\n return this.date;\n }\n\n /**\n * Sets the comment date\n */\n setDate(date: Date): this {\n this.date = date;\n this.notifyModified();\n return this;\n }\n\n /**\n * Gets the parent comment ID (for replies)\n */\n getParentId(): number | undefined {\n return this.parentId;\n }\n\n /**\n * Checks if this is a reply to another comment\n */\n isReply(): boolean {\n return this.parentId !== undefined;\n }\n\n /**\n * Checks if the comment is resolved/done\n * Per ECMA-376 Part 1, Section 17.13.4.2 (w:done attribute)\n */\n isResolved(): boolean {\n return this.done;\n }\n\n /**\n * Marks the comment as resolved/done\n * Persists as w15:done=\"1\" in word/commentsExtended.xml on save\n */\n resolve(): this {\n this.done = true;\n this.notifyModified();\n return this;\n }\n\n /**\n * Marks the comment as unresolved\n * Drops the w15:done flag from word/commentsExtended.xml on save\n */\n unresolve(): this {\n this.done = false;\n this.notifyModified();\n return this;\n }\n\n /**\n * Gets the runs in this comment (flattened across paragraphs,\n * including runs inside preserved inline content)\n */\n getRuns(): Run[] {\n const runs: Run[] = [];\n for (const paragraph of this.paragraphs) {\n for (const item of paragraph.content) {\n if (item instanceof Run) {\n runs.push(item);\n } else {\n runs.push(...item.runs);\n }\n }\n }\n return runs;\n }\n\n /**\n * Adds a run to this comment (appended to the last paragraph)\n */\n addRun(run: Run): this {\n let last = this.paragraphs[this.paragraphs.length - 1];\n if (!last) {\n last = { content: [] };\n this.paragraphs.push(last);\n }\n last.content.push(run);\n this.notifyModified();\n return this;\n }\n\n /**\n * Gets the comment content grouped by paragraph\n */\n getParagraphs(): CommentParagraph[] {\n return this.paragraphs.map((paragraph) => ({\n pPr: paragraph.pPr,\n content: [...paragraph.content],\n }));\n }\n\n /**\n * Replaces the comment content with parsed paragraphs.\n * Used by DocumentParser to preserve <w:p> boundaries, paragraph\n * properties, and hyperlink wrappers of comments loaded from an\n * existing comments.xml. Not a user mutation — no dirty notification.\n * @internal\n */\n setParagraphs(paragraphs: CommentParagraph[]): void {\n this.paragraphs = paragraphs;\n }\n\n /**\n * Gets the comment text (combines all runs)\n */\n getText(): string {\n return this.getRuns()\n .map((run) => run.getText())\n .join('');\n }\n\n /**\n * Gets the comment content (alias for getText for compatibility)\n */\n getContent(): string {\n return this.getText();\n }\n\n /**\n * Formats a date to ISO 8601 format for XML\n * Uses formatDateForXml() to strip milliseconds which Word does not accept.\n */\n private formatDate(date: Date): string {\n return formatDateForXml(date);\n }\n\n /**\n * Generates XML for the comment range start marker\n * This goes in word/document.xml at the start of the commented range\n */\n toRangeStartXML(): XMLElement {\n return {\n name: 'w:commentRangeStart',\n attributes: {\n 'w:id': this.id.toString(),\n },\n selfClosing: true,\n };\n }\n\n /**\n * Generates XML for the comment range end marker\n * This goes in word/document.xml at the end of the commented range\n */\n toRangeEndXML(): XMLElement {\n return {\n name: 'w:commentRangeEnd',\n attributes: {\n 'w:id': this.id.toString(),\n },\n selfClosing: true,\n };\n }\n\n /**\n * Generates XML for the comment reference\n * This goes in word/document.xml after the range end, inside a run\n */\n toReferenceXML(): XMLElement {\n return {\n name: 'w:r',\n children: [\n {\n name: 'w:commentReference',\n attributes: {\n 'w:id': this.id.toString(),\n },\n selfClosing: true,\n },\n ],\n };\n }\n\n /**\n * Generates XML for the comment definition\n * This goes in word/comments.xml\n */\n toXML(): XMLElement {\n const attributes: Record<string, string> = {\n 'w:id': this.id.toString(),\n 'w:author': this.author,\n 'w:date': this.formatDate(this.date),\n 'w:initials': this.initials,\n };\n\n // Add parent ID for replies (w15 namespace per Office 2012 extensions)\n if (this.parentId !== undefined) {\n attributes['w15:parentId'] = this.parentId.toString();\n }\n\n // Add done attribute for resolved comments (per ECMA-376)\n if (this.done) {\n attributes['w:done'] = '1';\n }\n\n // One <w:p> per stored paragraph — collapsing into a single paragraph\n // concatenates words across the lost boundaries and drops the\n // CommentText paragraph style of parsed comments\n const commentParagraphs: XMLElement[] = this.paragraphs.map((paragraph) => {\n const children: XMLElement[] = [];\n if (paragraph.pPr) {\n children.push({ name: '__rawXml', rawXml: paragraph.pPr });\n }\n for (const item of paragraph.content) {\n if (item instanceof Run) {\n children.push(item.toXML());\n } else {\n children.push({ name: '__rawXml', rawXml: item.rawXml });\n }\n }\n return { name: 'w:p', children };\n });\n\n return {\n name: 'w:comment',\n attributes,\n children: commentParagraphs,\n };\n }\n\n /**\n * Creates a new comment\n * @param author - Comment author\n * @param content - Comment content (text or runs)\n * @param initials - Optional author initials\n * @returns New Comment instance\n */\n static create(author: string, content: string | Run | Run[], initials?: string): Comment {\n return new Comment({\n author,\n content,\n initials,\n });\n }\n\n /**\n * Creates a reply to an existing comment\n * @param parentId - ID of the parent comment\n * @param author - Reply author\n * @param content - Reply content (text or runs)\n * @param initials - Optional author initials\n * @returns New Comment instance (reply)\n */\n static createReply(\n parentId: number,\n author: string,\n content: string | Run | Run[],\n initials?: string\n ): Comment {\n return new Comment({\n author,\n content,\n initials,\n parentId,\n });\n }\n\n /**\n * Creates a comment with formatted content\n * @param author - Comment author\n * @param runs - Array of formatted runs\n * @param initials - Optional author initials\n * @returns New Comment instance\n */\n static createFormatted(author: string, runs: Run[], initials?: string): Comment {\n return new Comment({\n author,\n content: runs,\n initials,\n });\n }\n}\n"]}
|
|
@@ -7,7 +7,9 @@ export declare class CommentManager {
|
|
|
7
7
|
private nextId;
|
|
8
8
|
private idProvider;
|
|
9
9
|
private idExistsNotifier;
|
|
10
|
+
private modifiedNotifier;
|
|
10
11
|
setIdProvider(provider: IdProviderCallback, existsNotifier?: IdExistsCallback): void;
|
|
12
|
+
setModifiedNotifier(notifier: () => void): void;
|
|
11
13
|
register(comment: Comment): Comment;
|
|
12
14
|
registerExisting(comment: Comment): void;
|
|
13
15
|
linkReplies(): void;
|
|
@@ -45,6 +47,8 @@ export declare class CommentManager {
|
|
|
45
47
|
nextId: number;
|
|
46
48
|
};
|
|
47
49
|
generateCommentsXml(): string;
|
|
50
|
+
static commentParaId(commentId: number): string;
|
|
51
|
+
generateCommentsExtendedXml(): string | null;
|
|
48
52
|
private commentToXmlString;
|
|
49
53
|
private runToXmlString;
|
|
50
54
|
static create(): CommentManager;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentManager.d.ts","sourceRoot":"","sources":["../../src/elements/CommentManager.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAQ/B,MAAM,MAAM,kBAAkB,GAAG,MAAM,MAAM,CAAC;AAM9C,MAAM,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;AAc5D,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,gBAAgB,CAAiC;
|
|
1
|
+
{"version":3,"file":"CommentManager.d.ts","sourceRoot":"","sources":["../../src/elements/CommentManager.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAQ/B,MAAM,MAAM,kBAAkB,GAAG,MAAM,MAAM,CAAC;AAM9C,MAAM,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;AAc5D,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,gBAAgB,CAA6B;IAUrD,aAAa,CAAC,QAAQ,EAAE,kBAAkB,EAAE,cAAc,CAAC,EAAE,gBAAgB,GAAG,IAAI;IAapF,mBAAmB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAa/C,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO;IAiCnC,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IA8BxC,WAAW,IAAI,IAAI;IAqBnB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAQ3C,cAAc,IAAI,OAAO,EAAE;IAU3B,yBAAyB,IAAI,OAAO,EAAE;IAStC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE;IAUxC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAStC,QAAQ,IAAI,MAAM;IAQlB,gBAAgB,IAAI,MAAM;IAQ1B,UAAU,IAAI,MAAM,EAAE;IAatB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE;IAY9C,sBAAsB,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,OAAO,EAAE;IAejE,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IA4BlC,KAAK,IAAI,IAAI;IAUb,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAW3B,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAcxF,WAAW,CACT,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,EAC7B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO;IAgBV,OAAO,IAAI,OAAO;IASlB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,EAAE,CAAA;KAAE,GAAG,SAAS;IAgBzF,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE;IAWjD,mBAAmB,IAAI,OAAO,EAAE;IAUhC,qBAAqB,IAAI,OAAO,EAAE;IAWlC,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE;IAW3C,QAAQ,IAAI;QACV,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB;IAkBD,mBAAmB,IAAI,MAAM;IAqD7B,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAU/C,2BAA2B,IAAI,MAAM,GAAG,IAAI;IA8B5C,OAAO,CAAC,kBAAkB;IA8C1B,OAAO,CAAC,cAAc;IAWtB,MAAM,CAAC,MAAM,IAAI,cAAc;CAGhC"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CommentManager = void 0;
|
|
4
4
|
const Comment_js_1 = require("./Comment.js");
|
|
5
|
+
const Run_js_1 = require("./Run.js");
|
|
5
6
|
const XMLBuilder_js_1 = require("../xml/XMLBuilder.js");
|
|
6
7
|
const dateFormatting_js_1 = require("../utils/dateFormatting.js");
|
|
7
8
|
class CommentManager {
|
|
@@ -9,13 +10,23 @@ class CommentManager {
|
|
|
9
10
|
nextId = 0;
|
|
10
11
|
idProvider = null;
|
|
11
12
|
idExistsNotifier = null;
|
|
13
|
+
modifiedNotifier = null;
|
|
12
14
|
setIdProvider(provider, existsNotifier) {
|
|
13
15
|
this.idProvider = provider;
|
|
14
16
|
this.idExistsNotifier = existsNotifier || null;
|
|
15
17
|
}
|
|
18
|
+
setModifiedNotifier(notifier) {
|
|
19
|
+
this.modifiedNotifier = notifier;
|
|
20
|
+
for (const entry of this.comments.values()) {
|
|
21
|
+
entry.comment.setModifiedCallback(notifier);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
16
24
|
register(comment) {
|
|
17
25
|
const id = this.idProvider ? this.idProvider() : this.nextId++;
|
|
18
26
|
comment.setId(id);
|
|
27
|
+
if (this.modifiedNotifier) {
|
|
28
|
+
comment.setModifiedCallback(this.modifiedNotifier);
|
|
29
|
+
}
|
|
19
30
|
const entry = {
|
|
20
31
|
comment,
|
|
21
32
|
replies: [],
|
|
@@ -34,6 +45,9 @@ class CommentManager {
|
|
|
34
45
|
if (this.idExistsNotifier) {
|
|
35
46
|
this.idExistsNotifier(id);
|
|
36
47
|
}
|
|
48
|
+
if (this.modifiedNotifier) {
|
|
49
|
+
comment.setModifiedCallback(this.modifiedNotifier);
|
|
50
|
+
}
|
|
37
51
|
const entry = {
|
|
38
52
|
comment,
|
|
39
53
|
replies: [],
|
|
@@ -110,6 +124,13 @@ class CommentManager {
|
|
|
110
124
|
for (const reply of entry.replies) {
|
|
111
125
|
this.comments.delete(reply.getId());
|
|
112
126
|
}
|
|
127
|
+
const parentId = entry.comment.getParentId();
|
|
128
|
+
if (parentId !== undefined) {
|
|
129
|
+
const parentEntry = this.comments.get(parentId);
|
|
130
|
+
if (parentEntry) {
|
|
131
|
+
parentEntry.replies = parentEntry.replies.filter((reply) => reply !== entry.comment);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
113
134
|
return this.comments.delete(id);
|
|
114
135
|
}
|
|
115
136
|
clear() {
|
|
@@ -186,22 +207,53 @@ class CommentManager {
|
|
|
186
207
|
</w:comments>`;
|
|
187
208
|
}
|
|
188
209
|
const hasReplies = comments.some((c) => c.isReply());
|
|
210
|
+
const hasResolved = comments.some((c) => c.isResolved());
|
|
189
211
|
let xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
|
|
190
212
|
xml += '<w:comments xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"';
|
|
191
213
|
xml += ' xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"';
|
|
214
|
+
if (hasResolved) {
|
|
215
|
+
xml += ' xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"';
|
|
216
|
+
}
|
|
192
217
|
if (hasReplies) {
|
|
193
218
|
xml += ' xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"';
|
|
194
|
-
|
|
195
|
-
|
|
219
|
+
}
|
|
220
|
+
if (hasReplies || hasResolved) {
|
|
221
|
+
const ignorable = [hasResolved ? 'w14' : '', hasReplies ? 'w15' : '']
|
|
222
|
+
.filter((ns) => ns.length > 0)
|
|
223
|
+
.join(' ');
|
|
224
|
+
xml += ` xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="${ignorable}"`;
|
|
196
225
|
}
|
|
197
226
|
xml += '>\n';
|
|
198
227
|
for (const comment of comments) {
|
|
199
|
-
xml += this.commentToXmlString(comment);
|
|
228
|
+
xml += this.commentToXmlString(comment, hasResolved ? CommentManager.commentParaId(comment.getId()) : undefined);
|
|
200
229
|
}
|
|
201
230
|
xml += '</w:comments>';
|
|
202
231
|
return xml;
|
|
203
232
|
}
|
|
204
|
-
|
|
233
|
+
static commentParaId(commentId) {
|
|
234
|
+
return ((commentId + 1) & 0x7fffffff).toString(16).toUpperCase().padStart(8, '0');
|
|
235
|
+
}
|
|
236
|
+
generateCommentsExtendedXml() {
|
|
237
|
+
const comments = this.getAllCommentsWithReplies();
|
|
238
|
+
if (!comments.some((c) => c.isResolved())) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
let xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
|
|
242
|
+
xml += '<w15:commentsEx xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"';
|
|
243
|
+
xml +=
|
|
244
|
+
' xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w15">\n';
|
|
245
|
+
for (const comment of comments) {
|
|
246
|
+
xml += ` <w15:commentEx w15:paraId="${CommentManager.commentParaId(comment.getId())}"`;
|
|
247
|
+
const parentId = comment.getParentId();
|
|
248
|
+
if (parentId !== undefined && this.comments.has(parentId)) {
|
|
249
|
+
xml += ` w15:paraIdParent="${CommentManager.commentParaId(parentId)}"`;
|
|
250
|
+
}
|
|
251
|
+
xml += ` w15:done="${comment.isResolved() ? '1' : '0'}"/>\n`;
|
|
252
|
+
}
|
|
253
|
+
xml += '</w15:commentsEx>';
|
|
254
|
+
return xml;
|
|
255
|
+
}
|
|
256
|
+
commentToXmlString(comment, paraId) {
|
|
205
257
|
let xml = ` <w:comment w:id="${comment.getId()}"`;
|
|
206
258
|
xml += ` w:author="${XMLBuilder_js_1.XMLBuilder.escapeXmlAttribute(comment.getAuthor())}"`;
|
|
207
259
|
xml += ` w:date="${(0, dateFormatting_js_1.formatDateForXml)(comment.getDate())}"`;
|
|
@@ -209,25 +261,31 @@ class CommentManager {
|
|
|
209
261
|
if (comment.isReply() && comment.getParentId() !== undefined) {
|
|
210
262
|
xml += ` w15:parentId="${comment.getParentId()}"`;
|
|
211
263
|
}
|
|
212
|
-
if (comment.isResolved()) {
|
|
213
|
-
xml += ` w:done="1"`;
|
|
214
|
-
}
|
|
215
264
|
xml += '>\n';
|
|
216
|
-
|
|
217
|
-
for (
|
|
218
|
-
|
|
265
|
+
const paragraphs = comment.getParagraphs();
|
|
266
|
+
for (let i = 0; i < paragraphs.length; i++) {
|
|
267
|
+
const paragraph = paragraphs[i];
|
|
268
|
+
const isLast = i === paragraphs.length - 1;
|
|
269
|
+
xml += isLast && paraId ? ` <w:p w14:paraId="${paraId}">\n` : ' <w:p>\n';
|
|
270
|
+
if (paragraph.pPr) {
|
|
271
|
+
xml += ` ${paragraph.pPr}\n`;
|
|
272
|
+
}
|
|
273
|
+
for (const item of paragraph.content) {
|
|
274
|
+
if (item instanceof Run_js_1.Run) {
|
|
275
|
+
xml += this.runToXmlString(item, 6);
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
xml += ` ${item.rawXml}\n`;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
xml += ' </w:p>\n';
|
|
219
282
|
}
|
|
220
|
-
xml += ' </w:p>\n';
|
|
221
283
|
xml += ' </w:comment>\n';
|
|
222
284
|
return xml;
|
|
223
285
|
}
|
|
224
286
|
runToXmlString(run, indent) {
|
|
225
287
|
const spaces = ' '.repeat(indent);
|
|
226
|
-
|
|
227
|
-
let xml = `${spaces}<w:r>\n`;
|
|
228
|
-
xml += `${spaces} <w:t xml:space="preserve">${text}</w:t>\n`;
|
|
229
|
-
xml += `${spaces}</w:r>\n`;
|
|
230
|
-
return xml;
|
|
288
|
+
return `${spaces}${XMLBuilder_js_1.XMLBuilder.elementToString(run.toXML())}\n`;
|
|
231
289
|
}
|
|
232
290
|
static create() {
|
|
233
291
|
return new CommentManager();
|