docxmlater 11.0.10 → 12.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -13
- package/dist/core/Document.d.ts +28 -2
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +725 -170
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentGenerator.d.ts +1 -0
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +77 -25
- package/dist/core/DocumentGenerator.js.map +1 -1
- package/dist/core/DocumentParser.d.ts +7 -3
- package/dist/core/DocumentParser.d.ts.map +1 -1
- package/dist/core/DocumentParser.js +427 -81
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +2 -2
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/Comment.d.ts +15 -1
- package/dist/elements/Comment.d.ts.map +1 -1
- package/dist/elements/Comment.js +67 -12
- package/dist/elements/Comment.js.map +1 -1
- package/dist/elements/CommentManager.d.ts +4 -0
- package/dist/elements/CommentManager.d.ts.map +1 -1
- package/dist/elements/CommentManager.js +74 -16
- package/dist/elements/CommentManager.js.map +1 -1
- package/dist/elements/EndnoteManager.d.ts.map +1 -1
- package/dist/elements/EndnoteManager.js.map +1 -1
- package/dist/elements/Field.d.ts +10 -1
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +76 -34
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/FieldHelpers.d.ts +1 -0
- package/dist/elements/FieldHelpers.d.ts.map +1 -1
- package/dist/elements/FieldHelpers.js +8 -4
- package/dist/elements/FieldHelpers.js.map +1 -1
- package/dist/elements/Footer.d.ts +3 -1
- package/dist/elements/Footer.d.ts.map +1 -1
- package/dist/elements/Footer.js +39 -53
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/FootnoteManager.d.ts.map +1 -1
- package/dist/elements/FootnoteManager.js.map +1 -1
- package/dist/elements/Header.d.ts +3 -1
- package/dist/elements/Header.d.ts.map +1 -1
- package/dist/elements/Header.js +39 -53
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/HeaderFooterManager.d.ts +4 -2
- package/dist/elements/HeaderFooterManager.d.ts.map +1 -1
- package/dist/elements/HeaderFooterManager.js +36 -6
- package/dist/elements/HeaderFooterManager.js.map +1 -1
- package/dist/elements/Hyperlink.d.ts +6 -1
- package/dist/elements/Hyperlink.d.ts.map +1 -1
- package/dist/elements/Hyperlink.js +69 -44
- package/dist/elements/Hyperlink.js.map +1 -1
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +33 -6
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/ImageManager.d.ts +1 -0
- package/dist/elements/ImageManager.d.ts.map +1 -1
- package/dist/elements/ImageManager.js +11 -0
- package/dist/elements/ImageManager.js.map +1 -1
- package/dist/elements/Paragraph.d.ts +3 -0
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +91 -26
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/Revision.d.ts +4 -0
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +369 -29
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/Run.d.ts +1 -0
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +24 -4
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +17 -7
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.d.ts.map +1 -1
- package/dist/elements/Shape.js +50 -42
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/StructuredDocumentTag.d.ts +9 -1
- package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
- package/dist/elements/StructuredDocumentTag.js +46 -6
- package/dist/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/elements/Table.d.ts +2 -0
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +90 -42
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +1 -0
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +32 -13
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableOfContents.d.ts.map +1 -1
- package/dist/elements/TableOfContents.js +5 -7
- package/dist/elements/TableOfContents.js.map +1 -1
- package/dist/elements/TableRow.d.ts +1 -0
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +16 -1
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/elements/TextBox.d.ts.map +1 -1
- package/dist/elements/TextBox.js +55 -42
- package/dist/elements/TextBox.js.map +1 -1
- package/dist/esm/core/Document.js +726 -171
- package/dist/esm/core/Document.js.map +1 -1
- package/dist/esm/core/DocumentGenerator.js +77 -25
- package/dist/esm/core/DocumentGenerator.js.map +1 -1
- package/dist/esm/core/DocumentParser.js +427 -81
- package/dist/esm/core/DocumentParser.js.map +1 -1
- package/dist/esm/core/RelationshipManager.js +2 -2
- package/dist/esm/core/RelationshipManager.js.map +1 -1
- package/dist/esm/elements/Comment.js +67 -12
- package/dist/esm/elements/Comment.js.map +1 -1
- package/dist/esm/elements/CommentManager.js +74 -16
- package/dist/esm/elements/CommentManager.js.map +1 -1
- package/dist/esm/elements/EndnoteManager.js.map +1 -1
- package/dist/esm/elements/Field.js +77 -35
- package/dist/esm/elements/Field.js.map +1 -1
- package/dist/esm/elements/FieldHelpers.js +7 -4
- package/dist/esm/elements/FieldHelpers.js.map +1 -1
- package/dist/esm/elements/Footer.js +39 -53
- package/dist/esm/elements/Footer.js.map +1 -1
- package/dist/esm/elements/FootnoteManager.js.map +1 -1
- package/dist/esm/elements/Header.js +39 -53
- package/dist/esm/elements/Header.js.map +1 -1
- package/dist/esm/elements/HeaderFooterManager.js +36 -6
- package/dist/esm/elements/HeaderFooterManager.js.map +1 -1
- package/dist/esm/elements/Hyperlink.js +69 -44
- package/dist/esm/elements/Hyperlink.js.map +1 -1
- package/dist/esm/elements/Image.js +33 -6
- package/dist/esm/elements/Image.js.map +1 -1
- package/dist/esm/elements/ImageManager.js +11 -0
- package/dist/esm/elements/ImageManager.js.map +1 -1
- package/dist/esm/elements/Paragraph.js +91 -26
- package/dist/esm/elements/Paragraph.js.map +1 -1
- package/dist/esm/elements/Revision.js +369 -29
- package/dist/esm/elements/Revision.js.map +1 -1
- package/dist/esm/elements/Run.js +24 -4
- package/dist/esm/elements/Run.js.map +1 -1
- package/dist/esm/elements/Section.js +17 -7
- package/dist/esm/elements/Section.js.map +1 -1
- package/dist/esm/elements/Shape.js +50 -42
- package/dist/esm/elements/Shape.js.map +1 -1
- package/dist/esm/elements/StructuredDocumentTag.js +46 -6
- package/dist/esm/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/esm/elements/Table.js +90 -42
- package/dist/esm/elements/Table.js.map +1 -1
- package/dist/esm/elements/TableCell.js +32 -13
- package/dist/esm/elements/TableCell.js.map +1 -1
- package/dist/esm/elements/TableOfContents.js +5 -7
- package/dist/esm/elements/TableOfContents.js.map +1 -1
- package/dist/esm/elements/TableRow.js +16 -1
- package/dist/esm/elements/TableRow.js.map +1 -1
- package/dist/esm/elements/TextBox.js +55 -42
- package/dist/esm/elements/TextBox.js.map +1 -1
- package/dist/esm/formatting/AbstractNumbering.js +1 -1
- package/dist/esm/formatting/AbstractNumbering.js.map +1 -1
- package/dist/esm/formatting/NumberingLevel.js +8 -6
- package/dist/esm/formatting/NumberingLevel.js.map +1 -1
- package/dist/esm/formatting/NumberingManager.js +16 -1
- package/dist/esm/formatting/NumberingManager.js.map +1 -1
- package/dist/esm/formatting/Style.js +14 -0
- package/dist/esm/formatting/Style.js.map +1 -1
- package/dist/esm/formatting/StylesManager.js +14 -2
- package/dist/esm/formatting/StylesManager.js.map +1 -1
- package/dist/esm/helpers/CleanupHelper.js +103 -26
- package/dist/esm/helpers/CleanupHelper.js.map +1 -1
- package/dist/esm/images/ImageOptimizer.js +52 -4
- package/dist/esm/images/ImageOptimizer.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal.js +1 -1
- package/dist/esm/internal.js.map +1 -1
- package/dist/esm/processors/CompatibilityUpgrader.js +7 -1
- package/dist/esm/processors/CompatibilityUpgrader.js.map +1 -1
- package/dist/esm/processors/InMemoryRevisionAcceptor.js +134 -13
- package/dist/esm/processors/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/esm/processors/RevisionWalker.js +58 -8
- package/dist/esm/processors/RevisionWalker.js.map +1 -1
- package/dist/esm/processors/SelectiveRevisionAcceptor.js +116 -17
- package/dist/esm/processors/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/esm/processors/cnfStyleDecoder.js +7 -7
- package/dist/esm/processors/cnfStyleDecoder.js.map +1 -1
- package/dist/esm/processors/stripTrackedChanges.js +16 -5
- package/dist/esm/processors/stripTrackedChanges.js.map +1 -1
- package/dist/esm/utils/deepClone.js +24 -11
- package/dist/esm/utils/deepClone.js.map +1 -1
- package/dist/esm/utils/units.js +1 -1
- package/dist/esm/utils/units.js.map +1 -1
- package/dist/esm/utils/validation.js +11 -23
- package/dist/esm/utils/validation.js.map +1 -1
- package/dist/esm/utils/xmlSanitization.js +131 -7
- package/dist/esm/utils/xmlSanitization.js.map +1 -1
- package/dist/esm/validation/RevisionAutoFixer.js +69 -55
- package/dist/esm/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/esm/validation/RevisionValidator.js +24 -20
- package/dist/esm/validation/RevisionValidator.js.map +1 -1
- package/dist/esm/xml/XMLBuilder.js +52 -20
- package/dist/esm/xml/XMLBuilder.js.map +1 -1
- package/dist/esm/xml/XMLParser.js +55 -13
- package/dist/esm/xml/XMLParser.js.map +1 -1
- package/dist/esm/zip/ZipHandler.js +37 -13
- package/dist/esm/zip/ZipHandler.js.map +1 -1
- package/dist/esm/zip/ZipReader.js +53 -6
- package/dist/esm/zip/ZipReader.js.map +1 -1
- package/dist/esm/zip/errors.js +7 -0
- package/dist/esm/zip/errors.js.map +1 -1
- package/dist/esm/zip/types.js +4 -0
- package/dist/esm/zip/types.js.map +1 -1
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +1 -1
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts +1 -1
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +8 -6
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/NumberingManager.d.ts.map +1 -1
- package/dist/formatting/NumberingManager.js +16 -1
- package/dist/formatting/NumberingManager.js.map +1 -1
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +14 -0
- package/dist/formatting/Style.js.map +1 -1
- package/dist/formatting/StylesManager.d.ts +2 -0
- package/dist/formatting/StylesManager.d.ts.map +1 -1
- package/dist/formatting/StylesManager.js +14 -2
- package/dist/formatting/StylesManager.js.map +1 -1
- package/dist/helpers/CleanupHelper.d.ts.map +1 -1
- package/dist/helpers/CleanupHelper.js +103 -26
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/images/ImageOptimizer.d.ts.map +1 -1
- package/dist/images/ImageOptimizer.js +52 -4
- package/dist/images/ImageOptimizer.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -1
- package/dist/internal.js.map +1 -1
- package/dist/processors/CompatibilityUpgrader.d.ts.map +1 -1
- package/dist/processors/CompatibilityUpgrader.js +7 -1
- package/dist/processors/CompatibilityUpgrader.js.map +1 -1
- package/dist/processors/InMemoryRevisionAcceptor.d.ts +1 -0
- package/dist/processors/InMemoryRevisionAcceptor.d.ts.map +1 -1
- package/dist/processors/InMemoryRevisionAcceptor.js +135 -13
- package/dist/processors/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/processors/RevisionWalker.d.ts +2 -0
- package/dist/processors/RevisionWalker.d.ts.map +1 -1
- package/dist/processors/RevisionWalker.js +58 -8
- package/dist/processors/RevisionWalker.js.map +1 -1
- package/dist/processors/SelectiveRevisionAcceptor.d.ts.map +1 -1
- package/dist/processors/SelectiveRevisionAcceptor.js +116 -17
- package/dist/processors/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/processors/cnfStyleDecoder.d.ts.map +1 -1
- package/dist/processors/cnfStyleDecoder.js +7 -7
- package/dist/processors/cnfStyleDecoder.js.map +1 -1
- package/dist/processors/stripTrackedChanges.d.ts.map +1 -1
- package/dist/processors/stripTrackedChanges.js +16 -5
- package/dist/processors/stripTrackedChanges.js.map +1 -1
- package/dist/utils/deepClone.d.ts.map +1 -1
- package/dist/utils/deepClone.js +24 -11
- package/dist/utils/deepClone.js.map +1 -1
- package/dist/utils/units.d.ts.map +1 -1
- package/dist/utils/units.js +1 -1
- package/dist/utils/units.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +11 -23
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/xmlSanitization.d.ts +2 -0
- package/dist/utils/xmlSanitization.d.ts.map +1 -1
- package/dist/utils/xmlSanitization.js +133 -7
- package/dist/utils/xmlSanitization.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.d.ts +6 -2
- package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
- package/dist/validation/RevisionAutoFixer.js +68 -54
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/validation/RevisionValidator.d.ts +2 -0
- package/dist/validation/RevisionValidator.d.ts.map +1 -1
- package/dist/validation/RevisionValidator.js +26 -21
- package/dist/validation/RevisionValidator.js.map +1 -1
- package/dist/xml/XMLBuilder.d.ts +1 -0
- package/dist/xml/XMLBuilder.d.ts.map +1 -1
- package/dist/xml/XMLBuilder.js +52 -20
- package/dist/xml/XMLBuilder.js.map +1 -1
- package/dist/xml/XMLParser.d.ts +1 -0
- package/dist/xml/XMLParser.d.ts.map +1 -1
- package/dist/xml/XMLParser.js +55 -13
- package/dist/xml/XMLParser.js.map +1 -1
- package/dist/zip/ZipHandler.d.ts.map +1 -1
- package/dist/zip/ZipHandler.js +37 -13
- package/dist/zip/ZipHandler.js.map +1 -1
- package/dist/zip/ZipReader.d.ts.map +1 -1
- package/dist/zip/ZipReader.js +52 -5
- package/dist/zip/ZipReader.js.map +1 -1
- package/dist/zip/errors.d.ts +3 -0
- package/dist/zip/errors.d.ts.map +1 -1
- package/dist/zip/errors.js +9 -1
- package/dist/zip/errors.js.map +1 -1
- package/dist/zip/types.d.ts +4 -0
- package/dist/zip/types.d.ts.map +1 -1
- package/dist/zip/types.js +4 -0
- package/dist/zip/types.js.map +1 -1
- package/package.json +2 -2
- package/src/core/Document.ts +1159 -240
- package/src/core/DocumentGenerator.ts +106 -26
- package/src/core/DocumentParser.ts +681 -114
- package/src/core/RelationshipManager.ts +446 -442
- package/src/elements/Comment.ts +123 -18
- package/src/elements/CommentManager.ts +121 -22
- package/src/elements/EndnoteManager.ts +4 -1
- package/src/elements/Field.ts +134 -43
- package/src/elements/FieldHelpers.ts +20 -4
- package/src/elements/Footer.ts +62 -67
- package/src/elements/FootnoteManager.ts +4 -1
- package/src/elements/Header.ts +62 -67
- package/src/elements/HeaderFooterManager.ts +56 -8
- package/src/elements/Hyperlink.ts +150 -55
- package/src/elements/Image.ts +51 -7
- package/src/elements/ImageManager.ts +24 -0
- package/src/elements/Paragraph.ts +161 -40
- package/src/elements/Revision.ts +446 -47
- package/src/elements/Run.ts +44 -6
- package/src/elements/Section.ts +25 -9
- package/src/elements/Shape.ts +52 -44
- package/src/elements/StructuredDocumentTag.ts +83 -8
- package/src/elements/Table.ts +151 -50
- package/src/elements/TableCell.ts +57 -17
- package/src/elements/TableOfContents.ts +10 -9
- package/src/elements/TableRow.ts +35 -3
- package/src/elements/TextBox.ts +58 -43
- package/src/formatting/AbstractNumbering.ts +4 -2
- package/src/formatting/NumberingLevel.ts +50 -12
- package/src/formatting/NumberingManager.ts +32 -3
- package/src/formatting/Style.ts +14 -0
- package/src/formatting/StylesManager.ts +29 -2
- package/src/helpers/CleanupHelper.ts +122 -30
- package/src/images/ImageOptimizer.ts +64 -5
- package/src/index.ts +7 -0
- package/src/internal.ts +1 -0
- package/src/processors/CompatibilityUpgrader.ts +15 -2
- package/src/processors/InMemoryRevisionAcceptor.ts +276 -17
- package/src/processors/RevisionWalker.ts +83 -7
- package/src/processors/SelectiveRevisionAcceptor.ts +164 -28
- package/src/processors/cnfStyleDecoder.ts +18 -12
- package/src/processors/stripTrackedChanges.ts +47 -10
- package/src/utils/deepClone.ts +48 -14
- package/src/utils/units.ts +3 -1
- package/src/utils/validation.ts +30 -32
- package/src/utils/xmlSanitization.ts +218 -22
- package/src/validation/RevisionAutoFixer.ts +109 -65
- package/src/validation/RevisionValidator.ts +48 -23
- package/src/xml/XMLBuilder.ts +82 -22
- package/src/xml/XMLParser.ts +87 -20
- package/src/zip/ZipHandler.ts +61 -21
- package/src/zip/ZipReader.ts +135 -13
- package/src/zip/errors.ts +15 -0
- package/src/zip/types.ts +44 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevisionAutoFixer.js","sourceRoot":"","sources":["../../../src/validation/RevisionAutoFixer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RevisionAutoFixer - Automatically fixes revision validation issues\n *\n * Provides auto-fix capabilities for common revision compliance issues,\n * helping to prevent document corruption while preserving user intent.\n *\n * @module RevisionAutoFixer\n */\n\nimport type { Document } from '../core/Document.js';\nimport type { Revision } from '../elements/Revision.js';\nimport type { RevisionManager } from '../elements/RevisionManager.js';\nimport {\n REVISION_RULES,\n AutoFixOptions,\n AutoFixResult,\n FixAction,\n ValidationIssue,\n} from './ValidationRules.js';\nimport { RevisionValidator } from './RevisionValidator.js';\n\n/**\n * Automatically fixes revision validation issues.\n *\n * @example\n * ```typescript\n * // Auto-fix all issues\n * const result = RevisionAutoFixer.fix(doc);\n * console.log(`Fixed ${result.issuesFixed} issues`);\n *\n * // Dry run (preview fixes without applying)\n * const preview = RevisionAutoFixer.fix(doc, { dryRun: true });\n * for (const action of preview.actions) {\n * console.log(`Would fix: ${action.action}`);\n * }\n * ```\n */\nexport class RevisionAutoFixer {\n /**\n * Auto-fix all fixable issues in a document.\n *\n * @param doc - Document to fix\n * @param options - Fix options\n * @returns Result with details of all fixes applied\n */\n static fix(doc: Document, options?: AutoFixOptions): AutoFixResult {\n const actions: FixAction[] = [];\n const errors: string[] = [];\n const revisionManager = doc.getRevisionManager();\n\n if (!revisionManager) {\n return {\n allFixed: true,\n issuesFixed: 0,\n issuesRemaining: 0,\n actions: [],\n errors: [],\n };\n }\n\n const revisions = revisionManager.getAllRevisions();\n const skipRules = new Set(options?.skipRules || []);\n const onlyRules = options?.onlyRules ? new Set(options.onlyRules) : null;\n\n // Helper to check if a rule should be processed\n const shouldProcess = (ruleCode: string) => {\n if (skipRules.has(ruleCode)) return false;\n if (onlyRules && !onlyRules.has(ruleCode)) return false;\n return true;\n };\n\n try {\n // Fix duplicate IDs (REV001)\n if (shouldProcess('REV001')) {\n actions.push(...this.fixDuplicateIds(revisions, options?.dryRun));\n }\n\n // Fix missing authors (REV002)\n if (shouldProcess('REV002')) {\n const defaultAuthor = options?.defaultAuthor || 'Unknown Author';\n actions.push(...this.fixMissingAuthors(revisions, defaultAuthor, options?.dryRun));\n }\n\n // Fix orphaned move markers (REV003, REV004)\n if (shouldProcess('REV003') || shouldProcess('REV004')) {\n actions.push(...this.fixOrphanedMoveMarkers(revisionManager, revisions, options?.dryRun));\n }\n\n // Fix missing dates (REV101)\n if (shouldProcess('REV101')) {\n actions.push(...this.fixMissingDates(revisions, options?.dryRun));\n }\n\n // Fix invalid dates (REV102)\n if (shouldProcess('REV102')) {\n actions.push(...this.fixInvalidDates(revisions, options?.dryRun));\n }\n\n // Fix empty revisions (REV103)\n if (shouldProcess('REV103')) {\n actions.push(...this.fixEmptyRevisions(revisionManager, revisions, options?.dryRun));\n }\n\n // Fix non-sequential IDs (REV104)\n if (shouldProcess('REV104')) {\n actions.push(...this.fixNonSequentialIds(revisions, options?.dryRun));\n }\n } catch (error: unknown) {\n errors.push(`Fix error: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Validate after fixes\n const postValidation = RevisionValidator.validate(doc);\n\n // Log actions if verbose\n if (options?.verbose) {\n for (const action of actions) {\n console.log(`[AutoFix] ${action.action}: ${action.issue.code}`);\n }\n }\n\n return {\n allFixed: postValidation.valid,\n issuesFixed: actions.filter((a) => a.success).length,\n issuesRemaining: postValidation.summary.errorCount + postValidation.summary.warningCount,\n actions,\n errors,\n };\n }\n\n /**\n * Fix duplicate revision IDs by reassigning.\n *\n * Assigns new unique IDs to revisions with duplicate IDs.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixDuplicateIds(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const usedIds = new Set<number>();\n let nextId = Math.max(...revisions.map((r) => r.getId()), 0) + 1;\n\n for (const rev of revisions) {\n const id = rev.getId();\n\n if (usedIds.has(id)) {\n const newId = nextId++;\n const issue: ValidationIssue = {\n code: REVISION_RULES.DUPLICATE_ID.code,\n severity: 'error',\n message: `Duplicate ID ${id}`,\n location: { revisionId: id },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Reassigned duplicate ID ${id} to ${newId}`,\n before: id,\n after: newId,\n success: true,\n });\n\n if (!dryRun) {\n rev.setId(newId);\n }\n }\n usedIds.add(rev.getId());\n }\n\n return actions;\n }\n\n /**\n * Fix missing authors by setting a default value.\n *\n * @param revisions - Array of revisions\n * @param defaultAuthor - Default author name to use\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixMissingAuthors(\n revisions: Revision[],\n defaultAuthor: string,\n dryRun?: boolean\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n for (const rev of revisions) {\n const author = rev.getAuthor();\n\n if (!author || author.trim() === '') {\n const issue: ValidationIssue = {\n code: REVISION_RULES.MISSING_AUTHOR.code,\n severity: 'error',\n message: `Missing author for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Set author to \"${defaultAuthor}\" for revision ${rev.getId()}`,\n before: author,\n after: defaultAuthor,\n success: true,\n });\n\n if (!dryRun) {\n rev.setAuthor(defaultAuthor);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix missing dates by setting current date.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixMissingDates(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const now = new Date();\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (!date) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.MISSING_DATE.code,\n severity: 'warning',\n message: `Missing date for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Set date to ${now.toISOString()} for revision ${rev.getId()}`,\n before: null,\n after: now,\n success: true,\n });\n\n if (!dryRun) {\n rev.setDate(now);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix invalid dates by replacing with current date.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixInvalidDates(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const now = new Date();\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (date && isNaN(date.getTime())) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.INVALID_DATE_FORMAT.code,\n severity: 'warning',\n message: `Invalid date for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Replaced invalid date with ${now.toISOString()} for revision ${rev.getId()}`,\n before: date,\n after: now,\n success: true,\n });\n\n if (!dryRun) {\n rev.setDate(now);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix orphaned move markers by removing them.\n *\n * @param revisionManager - RevisionManager instance\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixOrphanedMoveMarkers(\n revisionManager: { removeById(id: number): boolean },\n revisions: Revision[],\n dryRun?: boolean\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n const moveFromIds = new Map<string, Revision>();\n const moveToIds = new Map<string, Revision>();\n\n for (const rev of revisions) {\n const moveId = rev.getMoveId();\n if (!moveId) continue;\n\n if (rev.getType() === 'moveFrom') {\n moveFromIds.set(moveId, rev);\n } else if (rev.getType() === 'moveTo') {\n moveToIds.set(moveId, rev);\n }\n }\n\n // Remove orphaned moveFrom\n for (const [moveId, rev] of moveFromIds) {\n if (!moveToIds.has(moveId)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.ORPHANED_MOVE_FROM.code,\n severity: 'error',\n message: `Orphaned moveFrom with moveId=\"${moveId}\"`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed orphaned moveFrom (ID: ${rev.getId()}, moveId: ${moveId})`,\n before: { type: 'moveFrom', moveId },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n }\n }\n }\n\n // Remove orphaned moveTo\n for (const [moveId, rev] of moveToIds) {\n if (!moveFromIds.has(moveId)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.ORPHANED_MOVE_TO.code,\n severity: 'error',\n message: `Orphaned moveTo with moveId=\"${moveId}\"`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed orphaned moveTo (ID: ${rev.getId()}, moveId: ${moveId})`,\n before: { type: 'moveTo', moveId },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix empty revisions by removing them.\n *\n * @param revisionManager - RevisionManager instance\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixEmptyRevisions(\n revisionManager: RevisionManager,\n revisions: Revision[],\n dryRun?: boolean\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n const propertyChangeTypes = [\n 'runPropertiesChange',\n 'paragraphPropertiesChange',\n 'tablePropertiesChange',\n 'tableExceptionPropertiesChange',\n 'tableRowPropertiesChange',\n 'tableCellPropertiesChange',\n 'sectionPropertiesChange',\n 'numberingChange',\n ];\n\n for (const rev of revisions) {\n const type = rev.getType();\n\n // Skip property changes\n if (propertyChangeTypes.includes(type)) {\n continue;\n }\n\n const runs = rev.getRuns();\n const hasContent = runs.length > 0 && runs.some((r) => r.getText().length > 0);\n\n if (!hasContent) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.EMPTY_REVISION.code,\n severity: 'warning',\n message: `Empty revision ${rev.getId()} (type: ${type})`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed empty revision (ID: ${rev.getId()}, type: ${type})`,\n before: { id: rev.getId(), type },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix non-sequential IDs by reassigning.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixNonSequentialIds(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n\n if (revisions.length === 0) return actions;\n\n // Check if IDs are already sequential\n const ids = revisions.map((r) => r.getId()).sort((a, b) => a - b);\n let isSequential = true;\n\n for (let i = 1; i < ids.length; i++) {\n const currentId = ids[i]!;\n const prevId = ids[i - 1]!;\n if (currentId !== prevId + 1) {\n isSequential = false;\n break;\n }\n }\n\n if (!isSequential) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.NON_SEQUENTIAL_IDS.code,\n severity: 'warning',\n message: 'Revision IDs are not sequential',\n autoFixable: true,\n };\n\n const oldIds = revisions.map((r) => r.getId());\n const newIds: number[] = [];\n\n revisions.forEach((rev, index) => {\n newIds.push(index);\n if (!dryRun) {\n rev.setId(index);\n }\n });\n\n actions.push({\n issue,\n action: `Reassigned ${revisions.length} revision IDs to be sequential (0 to ${revisions.length - 1})`,\n before: oldIds,\n after: newIds,\n success: true,\n });\n }\n\n return actions;\n }\n\n /**\n * Preview fixes without applying them.\n *\n * Convenience method that calls fix() with dryRun: true.\n *\n * @param doc - Document to preview fixes for\n * @param options - Fix options (dryRun is forced to true)\n * @returns Result showing what would be fixed\n */\n static preview(doc: Document, options?: Omit<AutoFixOptions, 'dryRun'>): AutoFixResult {\n return this.fix(doc, { ...options, dryRun: true });\n }\n\n /**\n * Format fix result as a human-readable string.\n *\n * @param result - AutoFixResult to format\n * @returns Formatted string\n */\n static formatResult(result: AutoFixResult): string {\n const lines: string[] = [];\n\n lines.push(`Auto-Fix ${result.allFixed ? 'COMPLETE' : 'PARTIAL'}`);\n lines.push(`Fixed: ${result.issuesFixed}, Remaining: ${result.issuesRemaining}`);\n\n if (result.actions.length > 0) {\n lines.push('\\nActions taken:');\n for (const action of result.actions) {\n const status = action.success ? 'OK' : 'FAILED';\n lines.push(` [${status}] ${action.action}`);\n }\n }\n\n if (result.errors.length > 0) {\n lines.push('\\nErrors:');\n for (const error of result.errors) {\n lines.push(` - ${error}`);\n }\n }\n\n return lines.join('\\n');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"RevisionAutoFixer.js","sourceRoot":"","sources":["../../../src/validation/RevisionAutoFixer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RevisionAutoFixer - Automatically fixes revision validation issues\n *\n * Provides auto-fix capabilities for common revision compliance issues,\n * helping to prevent document corruption while preserving user intent.\n *\n * @module RevisionAutoFixer\n */\n\nimport type { Document } from '../core/Document.js';\nimport type { Revision } from '../elements/Revision.js';\nimport type { RevisionManager } from '../elements/RevisionManager.js';\nimport {\n REVISION_RULES,\n AutoFixOptions,\n AutoFixResult,\n FixAction,\n ValidationIssue,\n} from './ValidationRules.js';\nimport {\n CONTENTLESS_REVISION_TYPES,\n RevisionValidator,\n revisionHasContent,\n} from './RevisionValidator.js';\n\n/**\n * Automatically fixes revision validation issues.\n *\n * @example\n * ```typescript\n * // Auto-fix all issues\n * const result = RevisionAutoFixer.fix(doc);\n * console.log(`Fixed ${result.issuesFixed} issues`);\n *\n * // Dry run (preview fixes without applying)\n * const preview = RevisionAutoFixer.fix(doc, { dryRun: true });\n * for (const action of preview.actions) {\n * console.log(`Would fix: ${action.action}`);\n * }\n * ```\n */\nexport class RevisionAutoFixer {\n /**\n * Auto-fix all fixable issues in a document.\n *\n * @param doc - Document to fix\n * @param options - Fix options\n * @returns Result with details of all fixes applied\n */\n static fix(doc: Document, options?: AutoFixOptions): AutoFixResult {\n const actions: FixAction[] = [];\n const errors: string[] = [];\n const revisionManager = doc.getRevisionManager();\n\n if (!revisionManager) {\n return {\n allFixed: true,\n issuesFixed: 0,\n issuesRemaining: 0,\n actions: [],\n errors: [],\n };\n }\n\n const revisions = revisionManager.getAllRevisions();\n const skipRules = new Set(options?.skipRules || []);\n const onlyRules = options?.onlyRules ? new Set(options.onlyRules) : null;\n\n // Helper to check if a rule should be processed\n const shouldProcess = (ruleCode: string) => {\n if (skipRules.has(ruleCode)) return false;\n if (onlyRules && !onlyRules.has(ruleCode)) return false;\n return true;\n };\n\n try {\n // Fix duplicate IDs (REV001)\n if (shouldProcess('REV001')) {\n actions.push(...this.fixDuplicateIds(revisions, options?.dryRun));\n }\n\n // Fix missing authors (REV002)\n if (shouldProcess('REV002')) {\n const defaultAuthor = options?.defaultAuthor || 'Unknown Author';\n actions.push(...this.fixMissingAuthors(revisions, defaultAuthor, options?.dryRun));\n }\n\n // Fix orphaned move markers (REV003, REV004) — one pairing pass\n // produces both rules, so gate each side individually to honor\n // onlyRules/skipRules without mutating revisions the caller excluded.\n if (shouldProcess('REV003') || shouldProcess('REV004')) {\n actions.push(\n ...this.fixOrphanedMoveMarkers(revisionManager, revisions, options?.dryRun, doc, {\n moveFrom: shouldProcess('REV003'),\n moveTo: shouldProcess('REV004'),\n })\n );\n }\n\n // Fix missing dates (REV101)\n if (shouldProcess('REV101')) {\n actions.push(...this.fixMissingDates(revisions, options?.dryRun));\n }\n\n // Fix invalid dates (REV102)\n if (shouldProcess('REV102')) {\n actions.push(...this.fixInvalidDates(revisions, options?.dryRun));\n }\n\n // Fix empty revisions (REV103)\n if (shouldProcess('REV103')) {\n actions.push(...this.fixEmptyRevisions(revisionManager, revisions, options?.dryRun, doc));\n }\n\n // Fix non-sequential IDs (REV104)\n if (shouldProcess('REV104')) {\n actions.push(...this.fixNonSequentialIds(revisions, options?.dryRun));\n }\n } catch (error: unknown) {\n errors.push(`Fix error: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Validate after fixes\n const postValidation = RevisionValidator.validate(doc);\n\n // Log actions if verbose\n if (options?.verbose) {\n for (const action of actions) {\n console.log(`[AutoFix] ${action.action}: ${action.issue.code}`);\n }\n }\n\n return {\n allFixed: postValidation.valid,\n issuesFixed: actions.filter((a) => a.success).length,\n issuesRemaining: postValidation.summary.errorCount + postValidation.summary.warningCount,\n actions,\n errors,\n };\n }\n\n /**\n * Fix duplicate revision IDs by reassigning.\n *\n * Assigns new unique IDs to revisions with duplicate IDs.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixDuplicateIds(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const usedIds = new Set<number>();\n let nextId = Math.max(...revisions.map((r) => r.getId()), 0) + 1;\n\n for (const rev of revisions) {\n const id = rev.getId();\n\n if (usedIds.has(id)) {\n const newId = nextId++;\n const issue: ValidationIssue = {\n code: REVISION_RULES.DUPLICATE_ID.code,\n severity: 'error',\n message: `Duplicate ID ${id}`,\n location: { revisionId: id },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Reassigned duplicate ID ${id} to ${newId}`,\n before: id,\n after: newId,\n success: true,\n });\n\n if (!dryRun) {\n rev.setId(newId);\n }\n }\n usedIds.add(rev.getId());\n }\n\n return actions;\n }\n\n /**\n * Fix missing authors by setting a default value.\n *\n * @param revisions - Array of revisions\n * @param defaultAuthor - Default author name to use\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixMissingAuthors(\n revisions: Revision[],\n defaultAuthor: string,\n dryRun?: boolean\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n for (const rev of revisions) {\n const author = rev.getAuthor();\n\n if (!author || author.trim() === '') {\n const issue: ValidationIssue = {\n code: REVISION_RULES.MISSING_AUTHOR.code,\n severity: 'error',\n message: `Missing author for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Set author to \"${defaultAuthor}\" for revision ${rev.getId()}`,\n before: author,\n after: defaultAuthor,\n success: true,\n });\n\n if (!dryRun) {\n rev.setAuthor(defaultAuthor);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix missing dates by setting current date.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixMissingDates(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const now = new Date();\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (!date) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.MISSING_DATE.code,\n severity: 'warning',\n message: `Missing date for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Set date to ${now.toISOString()} for revision ${rev.getId()}`,\n before: null,\n after: now,\n success: true,\n });\n\n if (!dryRun) {\n rev.setDate(now);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix invalid dates by replacing with current date.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixInvalidDates(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n const now = new Date();\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (date && isNaN(date.getTime())) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.INVALID_DATE_FORMAT.code,\n severity: 'warning',\n message: `Invalid date for revision ${rev.getId()}`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Replaced invalid date with ${now.toISOString()} for revision ${rev.getId()}`,\n before: date,\n after: now,\n success: true,\n });\n\n if (!dryRun) {\n rev.setDate(now);\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Removes a revision from the paragraph content that owns it.\n *\n * RevisionManager.removeById() only deregisters the revision from the\n * manager registry, but serialization reads Paragraph.content directly —\n * without this step the removed markup would still be written on save.\n *\n * @param doc - Document whose paragraphs are searched\n * @param revision - Revision instance to remove\n * @returns True if the revision was found and removed from a paragraph\n */\n private static removeRevisionFromContent(doc: Document, revision: Revision): boolean {\n for (const paragraph of doc.getAllParagraphs()) {\n // replaceContent matches by identity and splices without tracking side effects\n if (paragraph.replaceContent(revision, [])) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Fix orphaned move markers by removing them.\n *\n * @param revisionManager - RevisionManager instance\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @param doc - Document to remove the revision content from; without it\n * only the manager registry is pruned and saved XML keeps the markup\n * @param ruleFilter - Which sides of the pairing to fix; REV003 (moveFrom)\n * and REV004 (moveTo) are separate rules, so callers honoring\n * onlyRules/skipRules must be able to fix one without the other.\n * Defaults to both.\n * @returns Array of fix actions\n */\n static fixOrphanedMoveMarkers(\n revisionManager: { removeById(id: number): boolean },\n revisions: Revision[],\n dryRun?: boolean,\n doc?: Document,\n ruleFilter?: { moveFrom?: boolean; moveTo?: boolean }\n ): FixAction[] {\n const actions: FixAction[] = [];\n const fixMoveFrom = ruleFilter?.moveFrom ?? true;\n const fixMoveTo = ruleFilter?.moveTo ?? true;\n\n const moveFromIds = new Map<string, Revision>();\n const moveToIds = new Map<string, Revision>();\n\n for (const rev of revisions) {\n const moveId = rev.getMoveId();\n if (!moveId) continue;\n\n if (rev.getType() === 'moveFrom') {\n moveFromIds.set(moveId, rev);\n } else if (rev.getType() === 'moveTo') {\n moveToIds.set(moveId, rev);\n }\n }\n\n // Remove orphaned moveFrom (REV003)\n if (fixMoveFrom) {\n for (const [moveId, rev] of moveFromIds) {\n if (!moveToIds.has(moveId)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.ORPHANED_MOVE_FROM.code,\n severity: 'error',\n message: `Orphaned moveFrom with moveId=\"${moveId}\"`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed orphaned moveFrom (ID: ${rev.getId()}, moveId: ${moveId})`,\n before: { type: 'moveFrom', moveId },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n if (doc) {\n this.removeRevisionFromContent(doc, rev);\n }\n }\n }\n }\n }\n\n // Remove orphaned moveTo (REV004)\n if (fixMoveTo) {\n for (const [moveId, rev] of moveToIds) {\n if (!moveFromIds.has(moveId)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.ORPHANED_MOVE_TO.code,\n severity: 'error',\n message: `Orphaned moveTo with moveId=\"${moveId}\"`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed orphaned moveTo (ID: ${rev.getId()}, moveId: ${moveId})`,\n before: { type: 'moveTo', moveId },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n if (doc) {\n this.removeRevisionFromContent(doc, rev);\n }\n }\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix empty revisions by removing them.\n *\n * @param revisionManager - RevisionManager instance\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @param doc - Document to remove the revision content from; without it\n * only the manager registry is pruned and saved XML keeps the markup\n * @returns Array of fix actions\n */\n static fixEmptyRevisions(\n revisionManager: RevisionManager,\n revisions: Revision[],\n dryRun?: boolean,\n doc?: Document\n ): FixAction[] {\n const actions: FixAction[] = [];\n\n for (const rev of revisions) {\n const type = rev.getType();\n\n // Property changes and cell markers are contentless by design\n if (CONTENTLESS_REVISION_TYPES.has(type)) {\n continue;\n }\n\n if (!revisionHasContent(rev)) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.EMPTY_REVISION.code,\n severity: 'warning',\n message: `Empty revision ${rev.getId()} (type: ${type})`,\n location: { revisionId: rev.getId() },\n autoFixable: true,\n };\n\n actions.push({\n issue,\n action: `Removed empty revision (ID: ${rev.getId()}, type: ${type})`,\n before: { id: rev.getId(), type },\n after: null,\n success: true,\n });\n\n if (!dryRun) {\n revisionManager.removeById(rev.getId());\n if (doc) {\n this.removeRevisionFromContent(doc, rev);\n }\n }\n }\n }\n\n return actions;\n }\n\n /**\n * Fix non-sequential IDs by reassigning.\n *\n * @param revisions - Array of revisions\n * @param dryRun - If true, only report changes without applying\n * @returns Array of fix actions\n */\n static fixNonSequentialIds(revisions: Revision[], dryRun?: boolean): FixAction[] {\n const actions: FixAction[] = [];\n\n if (revisions.length === 0) return actions;\n\n // Check if IDs are already sequential\n const ids = revisions.map((r) => r.getId()).sort((a, b) => a - b);\n let isSequential = true;\n\n for (let i = 1; i < ids.length; i++) {\n const currentId = ids[i]!;\n const prevId = ids[i - 1]!;\n if (currentId !== prevId + 1) {\n isSequential = false;\n break;\n }\n }\n\n if (!isSequential) {\n const issue: ValidationIssue = {\n code: REVISION_RULES.NON_SEQUENTIAL_IDS.code,\n severity: 'warning',\n message: 'Revision IDs are not sequential',\n autoFixable: true,\n };\n\n const oldIds = revisions.map((r) => r.getId());\n const newIds: number[] = [];\n\n revisions.forEach((rev, index) => {\n newIds.push(index);\n if (!dryRun) {\n rev.setId(index);\n }\n });\n\n actions.push({\n issue,\n action: `Reassigned ${revisions.length} revision IDs to be sequential (0 to ${revisions.length - 1})`,\n before: oldIds,\n after: newIds,\n success: true,\n });\n }\n\n return actions;\n }\n\n /**\n * Preview fixes without applying them.\n *\n * Convenience method that calls fix() with dryRun: true.\n *\n * @param doc - Document to preview fixes for\n * @param options - Fix options (dryRun is forced to true)\n * @returns Result showing what would be fixed\n */\n static preview(doc: Document, options?: Omit<AutoFixOptions, 'dryRun'>): AutoFixResult {\n return this.fix(doc, { ...options, dryRun: true });\n }\n\n /**\n * Format fix result as a human-readable string.\n *\n * @param result - AutoFixResult to format\n * @returns Formatted string\n */\n static formatResult(result: AutoFixResult): string {\n const lines: string[] = [];\n\n lines.push(`Auto-Fix ${result.allFixed ? 'COMPLETE' : 'PARTIAL'}`);\n lines.push(`Fixed: ${result.issuesFixed}, Remaining: ${result.issuesRemaining}`);\n\n if (result.actions.length > 0) {\n lines.push('\\nActions taken:');\n for (const action of result.actions) {\n const status = action.success ? 'OK' : 'FAILED';\n lines.push(` [${status}] ${action.action}`);\n }\n }\n\n if (result.errors.length > 0) {\n lines.push('\\nErrors:');\n for (const error of result.errors) {\n lines.push(` - ${error}`);\n }\n }\n\n return lines.join('\\n');\n }\n}\n"]}
|
|
@@ -1,5 +1,25 @@
|
|
|
1
|
+
import { isHyperlinkContent, isImageRunContent } from '../elements/RevisionContent.js';
|
|
1
2
|
import { REVISION_RULES, createIssueFromRule, } from './ValidationRules.js';
|
|
2
3
|
import { ValidationRuleRegistry } from './ValidationRuleRegistry.js';
|
|
4
|
+
export const CONTENTLESS_REVISION_TYPES = new Set([
|
|
5
|
+
'runPropertiesChange',
|
|
6
|
+
'paragraphPropertiesChange',
|
|
7
|
+
'tablePropertiesChange',
|
|
8
|
+
'tableExceptionPropertiesChange',
|
|
9
|
+
'tableRowPropertiesChange',
|
|
10
|
+
'tableCellPropertiesChange',
|
|
11
|
+
'sectionPropertiesChange',
|
|
12
|
+
'numberingChange',
|
|
13
|
+
'tableCellInsert',
|
|
14
|
+
'tableCellDelete',
|
|
15
|
+
'tableCellMerge',
|
|
16
|
+
]);
|
|
17
|
+
export function revisionHasContent(rev) {
|
|
18
|
+
if (rev.getText().length > 0) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
return rev.getContent().some((item) => isHyperlinkContent(item) || isImageRunContent(item));
|
|
22
|
+
}
|
|
3
23
|
export class RevisionValidator {
|
|
4
24
|
static validate(doc, options) {
|
|
5
25
|
const revisionManager = doc.getRevisionManager();
|
|
@@ -17,15 +37,11 @@ export class RevisionValidator {
|
|
|
17
37
|
if (!skipRules.has('REV001')) {
|
|
18
38
|
allIssues.push(...this.validateRevisionIds(revisions));
|
|
19
39
|
}
|
|
20
|
-
|
|
21
|
-
allIssues.push(...this.validateMovePairs(revisions));
|
|
22
|
-
}
|
|
40
|
+
allIssues.push(...this.validateMovePairs(revisions).filter((i) => !skipRules.has(i.code)));
|
|
23
41
|
if (!skipRules.has('REV002')) {
|
|
24
42
|
allIssues.push(...this.validateAuthors(revisions));
|
|
25
43
|
}
|
|
26
|
-
|
|
27
|
-
allIssues.push(...this.validateDates(revisions));
|
|
28
|
-
}
|
|
44
|
+
allIssues.push(...this.validateDates(revisions).filter((i) => !skipRules.has(i.code)));
|
|
29
45
|
if (!skipRules.has('REV103')) {
|
|
30
46
|
allIssues.push(...this.validateContent(revisions));
|
|
31
47
|
}
|
|
@@ -147,24 +163,12 @@ export class RevisionValidator {
|
|
|
147
163
|
}
|
|
148
164
|
static validateContent(revisions) {
|
|
149
165
|
const issues = [];
|
|
150
|
-
const propertyChangeTypes = [
|
|
151
|
-
'runPropertiesChange',
|
|
152
|
-
'paragraphPropertiesChange',
|
|
153
|
-
'tablePropertiesChange',
|
|
154
|
-
'tableExceptionPropertiesChange',
|
|
155
|
-
'tableRowPropertiesChange',
|
|
156
|
-
'tableCellPropertiesChange',
|
|
157
|
-
'sectionPropertiesChange',
|
|
158
|
-
'numberingChange',
|
|
159
|
-
];
|
|
160
166
|
for (const rev of revisions) {
|
|
161
167
|
const type = rev.getType();
|
|
162
|
-
if (
|
|
168
|
+
if (CONTENTLESS_REVISION_TYPES.has(type)) {
|
|
163
169
|
continue;
|
|
164
170
|
}
|
|
165
|
-
|
|
166
|
-
const hasContent = runs.length > 0 && runs.some((r) => r.getText().length > 0);
|
|
167
|
-
if (!hasContent) {
|
|
171
|
+
if (!revisionHasContent(rev)) {
|
|
168
172
|
issues.push(createIssueFromRule(REVISION_RULES.EMPTY_REVISION, { revisionId: rev.getId() }, `Revision ${rev.getId()} (type: ${type}) has no content`));
|
|
169
173
|
}
|
|
170
174
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RevisionValidator.js","sourceRoot":"","sources":["../../../src/validation/RevisionValidator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RevisionValidator - Validates document revisions for ECMA-376 compliance\n *\n * Checks tracked changes against OOXML specifications to prevent\n * document corruption and ensure compatibility with Microsoft Word.\n *\n * @module RevisionValidator\n */\n\nimport type { Document } from '../core/Document.js';\nimport type { Revision } from '../elements/Revision.js';\nimport {\n REVISION_RULES,\n ValidationIssue,\n ValidationOptions,\n ValidationResult,\n createIssueFromRule,\n} from './ValidationRules.js';\nimport { ValidationRuleRegistry } from './ValidationRuleRegistry.js';\n\n/**\n * Validates document revisions for ECMA-376 compliance.\n *\n * @example\n * ```typescript\n * const result = RevisionValidator.validate(doc);\n * if (!result.valid) {\n * console.error(`Found ${result.errors.length} errors`);\n * for (const error of result.errors) {\n * console.error(` ${error.code}: ${error.message}`);\n * }\n * }\n * ```\n */\nexport class RevisionValidator {\n /**\n * Validates all revisions in a document.\n *\n * @param doc - Document to validate\n * @param options - Validation options\n * @returns Validation result with all issues found\n */\n static validate(doc: Document, options?: ValidationOptions): ValidationResult {\n const revisionManager = doc.getRevisionManager();\n const allIssues: ValidationIssue[] = [];\n\n // Custom rules from ValidationRuleRegistry run regardless of whether\n // the document has a revision manager — they validate document-level\n // properties, not just revisions.\n allIssues.push(...this.runCustomRules(doc));\n\n if (!revisionManager) {\n return this.finalize(allIssues, options);\n }\n\n const revisions = revisionManager.getAllRevisions();\n\n // Skip certain rules if lenient mode\n const skipRules = new Set(options?.skipRules || []);\n if (options?.level === 'lenient') {\n // In lenient mode, skip info rules\n skipRules.add('REV201');\n skipRules.add('REV202');\n }\n\n // Run all validations\n if (!skipRules.has('REV001')) {\n allIssues.push(...this.validateRevisionIds(revisions));\n }\n if (!skipRules.has('REV003') && !skipRules.has('REV004')) {\n allIssues.push(...this.validateMovePairs(revisions));\n }\n if (!skipRules.has('REV002')) {\n allIssues.push(...this.validateAuthors(revisions));\n }\n if (!skipRules.has('REV101') && !skipRules.has('REV102')) {\n allIssues.push(...this.validateDates(revisions));\n }\n if (!skipRules.has('REV103')) {\n allIssues.push(...this.validateContent(revisions));\n }\n if (!skipRules.has('REV104') && options?.level === 'strict') {\n allIssues.push(...this.validateSequentialIds(revisions));\n }\n if (!skipRules.has('REV201')) {\n allIssues.push(...this.validateRevisionCount(revisions));\n }\n if (!skipRules.has('REV202')) {\n allIssues.push(...this.validateRevisionDates(revisions));\n }\n\n return this.finalize(allIssues, options);\n }\n\n /**\n * Run every rule in `ValidationRuleRegistry` against `doc` and convert\n * the produced `CustomValidationIssue`s into the built-in\n * `ValidationIssue` shape so they can be merged into the final result.\n */\n private static runCustomRules(doc: Document): ValidationIssue[] {\n const customIssues = ValidationRuleRegistry.runAll(doc);\n return customIssues.map((c) => ({\n code: c.ruleCode,\n severity: c.severity,\n message: c.message,\n location: c.location ? { element: c.location } : undefined,\n autoFixable: false,\n }));\n }\n\n /**\n * Apply maxIssues / warningsAsErrors options and bucket the issues\n * into the standard `ValidationResult` shape.\n */\n private static finalize(\n allIssues: ValidationIssue[],\n options?: ValidationOptions\n ): ValidationResult {\n const limitedIssues = options?.maxIssues ? allIssues.slice(0, options.maxIssues) : allIssues;\n\n let errors = limitedIssues.filter((i) => i.severity === 'error');\n let warnings = limitedIssues.filter((i) => i.severity === 'warning');\n const infos = limitedIssues.filter((i) => i.severity === 'info');\n const autoFixable = limitedIssues.filter((i) => i.autoFixable);\n\n if (options?.warningsAsErrors) {\n errors = [...errors, ...warnings];\n warnings = [];\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n infos,\n autoFixable,\n summary: {\n totalIssues: limitedIssues.length,\n errorCount: errors.length,\n warningCount: warnings.length,\n infoCount: infos.length,\n autoFixableCount: autoFixable.length,\n },\n };\n }\n\n /**\n * Validates revision ID uniqueness.\n *\n * Per ECMA-376, revision IDs must be unique within a document.\n * Duplicate IDs can cause Word to reject the document.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for duplicate IDs\n */\n static validateRevisionIds(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n const seenIds = new Map<number, number[]>(); // id -> indices\n\n revisions.forEach((rev, index) => {\n const id = rev.getId();\n if (!seenIds.has(id)) {\n seenIds.set(id, []);\n }\n seenIds.get(id)!.push(index);\n });\n\n for (const [id, indices] of seenIds) {\n if (indices.length > 1) {\n const rule = REVISION_RULES.DUPLICATE_ID;\n if (rule) {\n issues.push(\n createIssueFromRule(\n rule,\n { revisionId: id },\n `Duplicate revision ID ${id} found at ${indices.length} locations (indices: ${indices.join(', ')})`\n )\n );\n }\n }\n }\n\n return issues;\n }\n\n /**\n * Validates move operation pairs.\n *\n * Each moveFrom must have a matching moveTo with the same moveId,\n * and vice versa. Orphaned move markers can cause document corruption.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for orphaned move operations\n */\n static validateMovePairs(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n const moveFromIds = new Map<string, Revision>();\n const moveToIds = new Map<string, Revision>();\n\n for (const rev of revisions) {\n const moveId = rev.getMoveId();\n if (!moveId) continue;\n\n if (rev.getType() === 'moveFrom') {\n moveFromIds.set(moveId, rev);\n } else if (rev.getType() === 'moveTo') {\n moveToIds.set(moveId, rev);\n }\n }\n\n // Check for orphaned moveFrom\n for (const [moveId, rev] of moveFromIds) {\n if (!moveToIds.has(moveId)) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.ORPHANED_MOVE_FROM,\n { revisionId: rev.getId() },\n `moveFrom with moveId=\"${moveId}\" has no matching moveTo`\n )\n );\n }\n }\n\n // Check for orphaned moveTo\n for (const [moveId, rev] of moveToIds) {\n if (!moveFromIds.has(moveId)) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.ORPHANED_MOVE_TO,\n { revisionId: rev.getId() },\n `moveTo with moveId=\"${moveId}\" has no matching moveFrom`\n )\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Validates author presence.\n *\n * Per ECMA-376, the author attribute is required for revisions.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for missing authors\n */\n static validateAuthors(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n for (const rev of revisions) {\n const author = rev.getAuthor();\n if (!author || author.trim() === '') {\n issues.push(\n createIssueFromRule(REVISION_RULES.MISSING_AUTHOR, { revisionId: rev.getId() })\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Validates date presence and format.\n *\n * Per ECMA-376, revision dates should be in ISO 8601 format.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for date problems\n */\n static validateDates(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (!date) {\n issues.push(createIssueFromRule(REVISION_RULES.MISSING_DATE, { revisionId: rev.getId() }));\n } else if (isNaN(date.getTime())) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.INVALID_DATE_FORMAT,\n { revisionId: rev.getId() },\n `Revision ${rev.getId()} has an invalid date`\n )\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Validates revision content.\n *\n * Revisions (except property changes) should have content.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for empty revisions\n */\n static validateContent(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n const propertyChangeTypes = [\n 'runPropertiesChange',\n 'paragraphPropertiesChange',\n 'tablePropertiesChange',\n 'tableExceptionPropertiesChange',\n 'tableRowPropertiesChange',\n 'tableCellPropertiesChange',\n 'sectionPropertiesChange',\n 'numberingChange',\n ];\n\n for (const rev of revisions) {\n const type = rev.getType();\n\n // Property changes don't need text content\n if (propertyChangeTypes.includes(type)) {\n continue;\n }\n\n const runs = rev.getRuns();\n const hasContent = runs.length > 0 && runs.some((r) => r.getText().length > 0);\n\n if (!hasContent) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.EMPTY_REVISION,\n { revisionId: rev.getId() },\n `Revision ${rev.getId()} (type: ${type}) has no content`\n )\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Validates that revision IDs are sequential.\n *\n * While not strictly required, sequential IDs are best practice.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for non-sequential IDs\n */\n static validateSequentialIds(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n if (revisions.length === 0) return issues;\n\n // Use Set for O(n) lookup instead of sorting\n const idSet = new Set(revisions.map((r) => r.getId()));\n const ids = Array.from(idSet);\n\n if (ids.length === 0) return issues;\n\n const minId = Math.min(...ids);\n const maxId = Math.max(...ids);\n\n // Find actual missing IDs in the range\n const missingIds: number[] = [];\n for (let i = minId; i <= maxId; i++) {\n if (!idSet.has(i)) {\n missingIds.push(i);\n }\n }\n\n if (missingIds.length > 0) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.NON_SEQUENTIAL_IDS,\n undefined,\n `Revision IDs are not sequential. Missing IDs: ${missingIds.slice(0, 10).join(', ')}${missingIds.length > 10 ? ` (and ${missingIds.length - 10} more)` : ''}`\n )\n );\n }\n\n return issues;\n }\n\n /**\n * Validates revision count (info-level).\n *\n * Large numbers of revisions can slow down Word.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for large revision counts\n */\n static validateRevisionCount(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n if (revisions.length > 1000) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.LARGE_REVISION_COUNT,\n undefined,\n `Document has ${revisions.length} revisions (>1000). Consider accepting or rejecting some.`\n )\n );\n }\n\n return issues;\n }\n\n /**\n * Validates revision dates for staleness (info-level).\n *\n * Very old revisions may indicate stale tracked changes.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for old revisions\n */\n static validateRevisionDates(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n const oneYearAgo = new Date();\n oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);\n\n let oldCount = 0;\n for (const rev of revisions) {\n const date = rev.getDate();\n if (date && date < oneYearAgo) {\n oldCount++;\n }\n }\n\n if (oldCount > 0) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.OLD_REVISION_DATE,\n undefined,\n `${oldCount} revision(s) are older than 1 year. Consider reviewing and accepting.`\n )\n );\n }\n\n return issues;\n }\n\n /**\n * Quick check if a document has any validation errors.\n *\n * @param doc - Document to check\n * @returns True if the document has no errors\n */\n static isValid(doc: Document): boolean {\n const result = this.validate(doc, { level: 'normal' });\n return result.valid;\n }\n\n /**\n * Get a summary string of validation results.\n *\n * @param result - Validation result\n * @returns Human-readable summary string\n */\n static formatSummary(result: ValidationResult): string {\n const lines: string[] = [];\n\n lines.push(`Validation ${result.valid ? 'PASSED' : 'FAILED'}`);\n lines.push(`Total issues: ${result.summary.totalIssues}`);\n\n if (result.summary.errorCount > 0) {\n lines.push(` Errors: ${result.summary.errorCount}`);\n }\n if (result.summary.warningCount > 0) {\n lines.push(` Warnings: ${result.summary.warningCount}`);\n }\n if (result.summary.infoCount > 0) {\n lines.push(` Info: ${result.summary.infoCount}`);\n }\n\n if (result.summary.autoFixableCount > 0) {\n lines.push(` Auto-fixable: ${result.summary.autoFixableCount}`);\n }\n\n return lines.join('\\n');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"RevisionValidator.js","sourceRoot":"","sources":["../../../src/validation/RevisionValidator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RevisionValidator - Validates document revisions for ECMA-376 compliance\n *\n * Checks tracked changes against OOXML specifications to prevent\n * document corruption and ensure compatibility with Microsoft Word.\n *\n * @module RevisionValidator\n */\n\nimport type { Document } from '../core/Document.js';\nimport type { Revision } from '../elements/Revision.js';\nimport { isHyperlinkContent, isImageRunContent } from '../elements/RevisionContent.js';\nimport {\n REVISION_RULES,\n ValidationIssue,\n ValidationOptions,\n ValidationResult,\n createIssueFromRule,\n} from './ValidationRules.js';\nimport { ValidationRuleRegistry } from './ValidationRuleRegistry.js';\n\n/**\n * Revision types that are structurally contentless per ECMA-376: property\n * change markers carry before/after property snapshots rather than runs, and\n * table cell markers (w:cellIns/w:cellDel/w:cellMerge) annotate the cell\n * itself. The REV103 empty-content rule must never flag these.\n *\n * Shared with RevisionAutoFixer so the validator and fixer cannot drift\n * apart on which revision types are allowed to be empty.\n */\nexport const CONTENTLESS_REVISION_TYPES: ReadonlySet<string> = new Set([\n 'runPropertiesChange',\n 'paragraphPropertiesChange',\n 'tablePropertiesChange',\n 'tableExceptionPropertiesChange',\n 'tableRowPropertiesChange',\n 'tableCellPropertiesChange',\n 'sectionPropertiesChange',\n 'numberingChange',\n 'tableCellInsert',\n 'tableCellDelete',\n 'tableCellMerge',\n]);\n\n/**\n * True when a revision carries real content. Per ECMA-376, w:ins/w:del may\n * contain w:hyperlink and image runs (w:r with w:drawing) in addition to\n * text runs, so a runs-only text check would falsely flag hyperlink-only\n * and image-only tracked changes as empty. Shared with RevisionAutoFixer.\n */\nexport function revisionHasContent(rev: Revision): boolean {\n // Covers text runs and hyperlink display text\n if (rev.getText().length > 0) {\n return true;\n }\n // Hyperlinks count even without display text; ImageRuns have no text at all\n return rev.getContent().some((item) => isHyperlinkContent(item) || isImageRunContent(item));\n}\n\n/**\n * Validates document revisions for ECMA-376 compliance.\n *\n * @example\n * ```typescript\n * const result = RevisionValidator.validate(doc);\n * if (!result.valid) {\n * console.error(`Found ${result.errors.length} errors`);\n * for (const error of result.errors) {\n * console.error(` ${error.code}: ${error.message}`);\n * }\n * }\n * ```\n */\nexport class RevisionValidator {\n /**\n * Validates all revisions in a document.\n *\n * @param doc - Document to validate\n * @param options - Validation options\n * @returns Validation result with all issues found\n */\n static validate(doc: Document, options?: ValidationOptions): ValidationResult {\n const revisionManager = doc.getRevisionManager();\n const allIssues: ValidationIssue[] = [];\n\n // Custom rules from ValidationRuleRegistry run regardless of whether\n // the document has a revision manager — they validate document-level\n // properties, not just revisions.\n allIssues.push(...this.runCustomRules(doc));\n\n if (!revisionManager) {\n return this.finalize(allIssues, options);\n }\n\n const revisions = revisionManager.getAllRevisions();\n\n // Skip certain rules if lenient mode\n const skipRules = new Set(options?.skipRules || []);\n if (options?.level === 'lenient') {\n // In lenient mode, skip info rules\n skipRules.add('REV201');\n skipRules.add('REV202');\n }\n\n // Run all validations\n if (!skipRules.has('REV001')) {\n allIssues.push(...this.validateRevisionIds(revisions));\n }\n // validateMovePairs emits both REV003 and REV004 from one pairing pass;\n // filter per issue code so skipping one rule does not silently disable\n // the other (REV004 is error-severity and corruption-relevant).\n allIssues.push(...this.validateMovePairs(revisions).filter((i) => !skipRules.has(i.code)));\n if (!skipRules.has('REV002')) {\n allIssues.push(...this.validateAuthors(revisions));\n }\n // validateDates emits both REV101 and REV102 — same per-code filtering.\n allIssues.push(...this.validateDates(revisions).filter((i) => !skipRules.has(i.code)));\n if (!skipRules.has('REV103')) {\n allIssues.push(...this.validateContent(revisions));\n }\n if (!skipRules.has('REV104') && options?.level === 'strict') {\n allIssues.push(...this.validateSequentialIds(revisions));\n }\n if (!skipRules.has('REV201')) {\n allIssues.push(...this.validateRevisionCount(revisions));\n }\n if (!skipRules.has('REV202')) {\n allIssues.push(...this.validateRevisionDates(revisions));\n }\n\n return this.finalize(allIssues, options);\n }\n\n /**\n * Run every rule in `ValidationRuleRegistry` against `doc` and convert\n * the produced `CustomValidationIssue`s into the built-in\n * `ValidationIssue` shape so they can be merged into the final result.\n */\n private static runCustomRules(doc: Document): ValidationIssue[] {\n const customIssues = ValidationRuleRegistry.runAll(doc);\n return customIssues.map((c) => ({\n code: c.ruleCode,\n severity: c.severity,\n message: c.message,\n location: c.location ? { element: c.location } : undefined,\n autoFixable: false,\n }));\n }\n\n /**\n * Apply maxIssues / warningsAsErrors options and bucket the issues\n * into the standard `ValidationResult` shape.\n */\n private static finalize(\n allIssues: ValidationIssue[],\n options?: ValidationOptions\n ): ValidationResult {\n const limitedIssues = options?.maxIssues ? allIssues.slice(0, options.maxIssues) : allIssues;\n\n let errors = limitedIssues.filter((i) => i.severity === 'error');\n let warnings = limitedIssues.filter((i) => i.severity === 'warning');\n const infos = limitedIssues.filter((i) => i.severity === 'info');\n const autoFixable = limitedIssues.filter((i) => i.autoFixable);\n\n if (options?.warningsAsErrors) {\n errors = [...errors, ...warnings];\n warnings = [];\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n infos,\n autoFixable,\n summary: {\n totalIssues: limitedIssues.length,\n errorCount: errors.length,\n warningCount: warnings.length,\n infoCount: infos.length,\n autoFixableCount: autoFixable.length,\n },\n };\n }\n\n /**\n * Validates revision ID uniqueness.\n *\n * Per ECMA-376, revision IDs must be unique within a document.\n * Duplicate IDs can cause Word to reject the document.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for duplicate IDs\n */\n static validateRevisionIds(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n const seenIds = new Map<number, number[]>(); // id -> indices\n\n revisions.forEach((rev, index) => {\n const id = rev.getId();\n if (!seenIds.has(id)) {\n seenIds.set(id, []);\n }\n seenIds.get(id)!.push(index);\n });\n\n for (const [id, indices] of seenIds) {\n if (indices.length > 1) {\n const rule = REVISION_RULES.DUPLICATE_ID;\n if (rule) {\n issues.push(\n createIssueFromRule(\n rule,\n { revisionId: id },\n `Duplicate revision ID ${id} found at ${indices.length} locations (indices: ${indices.join(', ')})`\n )\n );\n }\n }\n }\n\n return issues;\n }\n\n /**\n * Validates move operation pairs.\n *\n * Each moveFrom must have a matching moveTo with the same moveId,\n * and vice versa. Orphaned move markers can cause document corruption.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for orphaned move operations\n */\n static validateMovePairs(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n const moveFromIds = new Map<string, Revision>();\n const moveToIds = new Map<string, Revision>();\n\n for (const rev of revisions) {\n const moveId = rev.getMoveId();\n if (!moveId) continue;\n\n if (rev.getType() === 'moveFrom') {\n moveFromIds.set(moveId, rev);\n } else if (rev.getType() === 'moveTo') {\n moveToIds.set(moveId, rev);\n }\n }\n\n // Check for orphaned moveFrom\n for (const [moveId, rev] of moveFromIds) {\n if (!moveToIds.has(moveId)) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.ORPHANED_MOVE_FROM,\n { revisionId: rev.getId() },\n `moveFrom with moveId=\"${moveId}\" has no matching moveTo`\n )\n );\n }\n }\n\n // Check for orphaned moveTo\n for (const [moveId, rev] of moveToIds) {\n if (!moveFromIds.has(moveId)) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.ORPHANED_MOVE_TO,\n { revisionId: rev.getId() },\n `moveTo with moveId=\"${moveId}\" has no matching moveFrom`\n )\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Validates author presence.\n *\n * Per ECMA-376, the author attribute is required for revisions.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for missing authors\n */\n static validateAuthors(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n for (const rev of revisions) {\n const author = rev.getAuthor();\n if (!author || author.trim() === '') {\n issues.push(\n createIssueFromRule(REVISION_RULES.MISSING_AUTHOR, { revisionId: rev.getId() })\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Validates date presence and format.\n *\n * Per ECMA-376, revision dates should be in ISO 8601 format.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for date problems\n */\n static validateDates(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n for (const rev of revisions) {\n const date = rev.getDate();\n\n if (!date) {\n issues.push(createIssueFromRule(REVISION_RULES.MISSING_DATE, { revisionId: rev.getId() }));\n } else if (isNaN(date.getTime())) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.INVALID_DATE_FORMAT,\n { revisionId: rev.getId() },\n `Revision ${rev.getId()} has an invalid date`\n )\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Validates revision content.\n *\n * Revisions (except property changes) should have content.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for empty revisions\n */\n static validateContent(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n for (const rev of revisions) {\n const type = rev.getType();\n\n // Property changes and cell markers are contentless by design\n if (CONTENTLESS_REVISION_TYPES.has(type)) {\n continue;\n }\n\n if (!revisionHasContent(rev)) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.EMPTY_REVISION,\n { revisionId: rev.getId() },\n `Revision ${rev.getId()} (type: ${type}) has no content`\n )\n );\n }\n }\n\n return issues;\n }\n\n /**\n * Validates that revision IDs are sequential.\n *\n * While not strictly required, sequential IDs are best practice.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for non-sequential IDs\n */\n static validateSequentialIds(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n if (revisions.length === 0) return issues;\n\n // Use Set for O(n) lookup instead of sorting\n const idSet = new Set(revisions.map((r) => r.getId()));\n const ids = Array.from(idSet);\n\n if (ids.length === 0) return issues;\n\n const minId = Math.min(...ids);\n const maxId = Math.max(...ids);\n\n // Find actual missing IDs in the range\n const missingIds: number[] = [];\n for (let i = minId; i <= maxId; i++) {\n if (!idSet.has(i)) {\n missingIds.push(i);\n }\n }\n\n if (missingIds.length > 0) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.NON_SEQUENTIAL_IDS,\n undefined,\n `Revision IDs are not sequential. Missing IDs: ${missingIds.slice(0, 10).join(', ')}${missingIds.length > 10 ? ` (and ${missingIds.length - 10} more)` : ''}`\n )\n );\n }\n\n return issues;\n }\n\n /**\n * Validates revision count (info-level).\n *\n * Large numbers of revisions can slow down Word.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for large revision counts\n */\n static validateRevisionCount(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n if (revisions.length > 1000) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.LARGE_REVISION_COUNT,\n undefined,\n `Document has ${revisions.length} revisions (>1000). Consider accepting or rejecting some.`\n )\n );\n }\n\n return issues;\n }\n\n /**\n * Validates revision dates for staleness (info-level).\n *\n * Very old revisions may indicate stale tracked changes.\n *\n * @param revisions - Array of revisions to validate\n * @returns Array of validation issues for old revisions\n */\n static validateRevisionDates(revisions: Revision[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n const oneYearAgo = new Date();\n oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);\n\n let oldCount = 0;\n for (const rev of revisions) {\n const date = rev.getDate();\n if (date && date < oneYearAgo) {\n oldCount++;\n }\n }\n\n if (oldCount > 0) {\n issues.push(\n createIssueFromRule(\n REVISION_RULES.OLD_REVISION_DATE,\n undefined,\n `${oldCount} revision(s) are older than 1 year. Consider reviewing and accepting.`\n )\n );\n }\n\n return issues;\n }\n\n /**\n * Quick check if a document has any validation errors.\n *\n * @param doc - Document to check\n * @returns True if the document has no errors\n */\n static isValid(doc: Document): boolean {\n const result = this.validate(doc, { level: 'normal' });\n return result.valid;\n }\n\n /**\n * Get a summary string of validation results.\n *\n * @param result - Validation result\n * @returns Human-readable summary string\n */\n static formatSummary(result: ValidationResult): string {\n const lines: string[] = [];\n\n lines.push(`Validation ${result.valid ? 'PASSED' : 'FAILED'}`);\n lines.push(`Total issues: ${result.summary.totalIssues}`);\n\n if (result.summary.errorCount > 0) {\n lines.push(` Errors: ${result.summary.errorCount}`);\n }\n if (result.summary.warningCount > 0) {\n lines.push(` Warnings: ${result.summary.warningCount}`);\n }\n if (result.summary.infoCount > 0) {\n lines.push(` Info: ${result.summary.infoCount}`);\n }\n\n if (result.summary.autoFixableCount > 0) {\n lines.push(` Auto-fixable: ${result.summary.autoFixableCount}`);\n }\n\n return lines.join('\\n');\n }\n}\n"]}
|
|
@@ -74,8 +74,8 @@ export class XMLBuilder {
|
|
|
74
74
|
let xml = `<${element.name}`;
|
|
75
75
|
if (element.attributes) {
|
|
76
76
|
for (const [key, value] of Object.entries(element.attributes)) {
|
|
77
|
-
if (value !== undefined && value !== null
|
|
78
|
-
const attrValue = value === true ?
|
|
77
|
+
if (value !== undefined && value !== null) {
|
|
78
|
+
const attrValue = value === true ? '1' : value === false ? '0' : String(value);
|
|
79
79
|
xml += ` ${key}="${XMLBuilder.escapeXmlAttribute(attrValue)}"`;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -115,13 +115,27 @@ export class XMLBuilder {
|
|
|
115
115
|
.replace(/"/g, '"')
|
|
116
116
|
.replace(/'/g, ''');
|
|
117
117
|
}
|
|
118
|
+
static NAMED_ENTITIES = {
|
|
119
|
+
lt: '<',
|
|
120
|
+
gt: '>',
|
|
121
|
+
quot: '"',
|
|
122
|
+
apos: "'",
|
|
123
|
+
amp: '&',
|
|
124
|
+
};
|
|
118
125
|
static unescapeXml(text) {
|
|
119
|
-
return text
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
return text.replace(/&(?:(lt|gt|quot|apos|amp)|#x([0-9A-Fa-f]+)|#(\d+));/g, (match, named, hex, dec) => {
|
|
127
|
+
if (named !== undefined) {
|
|
128
|
+
return XMLBuilder.NAMED_ENTITIES[named] ?? match;
|
|
129
|
+
}
|
|
130
|
+
const code = hex !== undefined ? parseInt(hex, 16) : Number(dec);
|
|
131
|
+
const isXmlChar = code === 0x9 ||
|
|
132
|
+
code === 0xa ||
|
|
133
|
+
code === 0xd ||
|
|
134
|
+
(code >= 0x20 && code <= 0xd7ff) ||
|
|
135
|
+
(code >= 0xe000 && code <= 0xfffd) ||
|
|
136
|
+
(code >= 0x10000 && code <= 0x10ffff);
|
|
137
|
+
return isXmlChar ? String.fromCodePoint(code) : match;
|
|
138
|
+
});
|
|
125
139
|
}
|
|
126
140
|
static sanitizeXmlContent(text) {
|
|
127
141
|
return (removeInvalidXmlChars(text)
|
|
@@ -311,12 +325,7 @@ export class XMLBuilder {
|
|
|
311
325
|
const builder = new XMLBuilder();
|
|
312
326
|
const element = XMLBuilder.objectToElement(obj, rootName);
|
|
313
327
|
if (element) {
|
|
314
|
-
|
|
315
|
-
builder.text(element);
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
builder.elements.push(element);
|
|
319
|
-
}
|
|
328
|
+
builder.elements.push(element);
|
|
320
329
|
}
|
|
321
330
|
return builder.build();
|
|
322
331
|
}
|
|
@@ -324,14 +333,11 @@ export class XMLBuilder {
|
|
|
324
333
|
if (obj === null || obj === undefined) {
|
|
325
334
|
return null;
|
|
326
335
|
}
|
|
327
|
-
if (typeof obj !== 'object'
|
|
328
|
-
return String(obj);
|
|
336
|
+
if (typeof obj !== 'object') {
|
|
337
|
+
return { name, children: [String(obj)] };
|
|
329
338
|
}
|
|
330
339
|
const attributes = {};
|
|
331
340
|
const children = [];
|
|
332
|
-
if (obj['#text'] && Object.keys(obj).length === 1) {
|
|
333
|
-
return String(obj['#text']);
|
|
334
|
-
}
|
|
335
341
|
for (const key in obj) {
|
|
336
342
|
if (key.startsWith('@_')) {
|
|
337
343
|
const attrName = key.substring(2);
|
|
@@ -342,7 +348,33 @@ export class XMLBuilder {
|
|
|
342
348
|
else if (key === '#text') {
|
|
343
349
|
children.push(String(obj[key]));
|
|
344
350
|
}
|
|
345
|
-
|
|
351
|
+
}
|
|
352
|
+
const orderedChildren = obj['_orderedChildren'];
|
|
353
|
+
if (orderedChildren && orderedChildren.length > 0) {
|
|
354
|
+
for (const childInfo of orderedChildren) {
|
|
355
|
+
const childValue = obj[childInfo.type];
|
|
356
|
+
if (childValue === undefined) {
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
const item = Array.isArray(childValue)
|
|
360
|
+
? childValue[childInfo.index]
|
|
361
|
+
: childInfo.index === 0
|
|
362
|
+
? childValue
|
|
363
|
+
: undefined;
|
|
364
|
+
if (item === undefined) {
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
const childElement = XMLBuilder.objectToElement(item, childInfo.type);
|
|
368
|
+
if (childElement) {
|
|
369
|
+
children.push(childElement);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
for (const key in obj) {
|
|
375
|
+
if (key.startsWith('@_') || key === '#text' || key === '_orderedChildren') {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
346
378
|
const childObj = obj[key];
|
|
347
379
|
if (Array.isArray(childObj)) {
|
|
348
380
|
childObj.forEach((item) => {
|