1 | package pro.verron.officestamper.preset.preprocessors.malformedcomments; | |
2 | ||
3 | import org.docx4j.TraversalUtil; | |
4 | import org.docx4j.openpackaging.exceptions.Docx4JException; | |
5 | import org.docx4j.openpackaging.packages.WordprocessingMLPackage; | |
6 | import org.docx4j.openpackaging.parts.WordprocessingML.CommentsPart; | |
7 | import org.docx4j.wml.*; | |
8 | import org.jvnet.jaxb2_commons.ppp.Child; | |
9 | import org.slf4j.Logger; | |
10 | import org.slf4j.LoggerFactory; | |
11 | import pro.verron.officestamper.api.OfficeStamperException; | |
12 | import pro.verron.officestamper.api.PreProcessor; | |
13 | import pro.verron.officestamper.utils.WmlUtils; | |
14 | ||
15 | import java.math.BigInteger; | |
16 | import java.util.*; | |
17 | ||
18 | import static java.util.stream.Collectors.toSet; | |
19 | ||
20 | public class RemoveMalformedComments | |
21 | implements PreProcessor { | |
22 | private static final Logger log = LoggerFactory.getLogger(RemoveMalformedComments.class); | |
23 | ||
24 | @Override public void process(WordprocessingMLPackage document) { | |
25 | var commentElements = WmlUtils.extractCommentElements(document); | |
26 | ||
27 | var commentIds = new ArrayList<BigInteger>(commentElements.size()); | |
28 | var openedCommentsIds = new ArrayDeque<BigInteger>(); | |
29 | for (Child commentElement : commentElements) { | |
30 |
1
1. process : negated conditional → KILLED |
if (commentElement instanceof CommentRangeStart crs) { |
31 | var lastOpenedCommentId = crs.getId(); | |
32 | assert lastOpenedCommentId != null; | |
33 | log.debug("Comment {} opened.", lastOpenedCommentId); | |
34 | commentIds.add(lastOpenedCommentId); | |
35 | openedCommentsIds.add(lastOpenedCommentId); | |
36 | } | |
37 |
1
1. process : negated conditional → KILLED |
else if (commentElement instanceof CommentRangeEnd cre) { |
38 | var lastClosedCommentId = cre.getId(); | |
39 | assert lastClosedCommentId != null; | |
40 | log.debug("Comment {} closed.", lastClosedCommentId); | |
41 | commentIds.add(lastClosedCommentId); | |
42 | ||
43 | var lastOpenedCommentId = openedCommentsIds.pollLast(); | |
44 |
1
1. process : negated conditional → KILLED |
if (!lastClosedCommentId.equals(lastOpenedCommentId)) { |
45 | log.debug("Comment {} is closing just after comment {} starts.", | |
46 | lastClosedCommentId, | |
47 | lastOpenedCommentId); | |
48 | throw new OfficeStamperException("Cannot figure which comment contains the other !"); | |
49 | } | |
50 | } | |
51 |
1
1. process : negated conditional → SURVIVED |
else if (commentElement instanceof R.CommentReference cr) { |
52 | var commentId = cr.getId(); | |
53 | assert commentId != null; | |
54 | log.debug("Comment {} referenced.", commentId); | |
55 | commentIds.add(commentId); | |
56 | } | |
57 | } | |
58 | ||
59 | log.debug("These comments have been opened, but never closed: {}", openedCommentsIds); | |
60 | var malformedCommentIds = new ArrayList<>(openedCommentsIds); | |
61 | ||
62 | var mainDocumentPart = document.getMainDocumentPart(); | |
63 | Set<BigInteger> writtenCommentsId = Optional.ofNullable(mainDocumentPart.getCommentsPart()) | |
64 | .map(RemoveMalformedComments::tryGetCommentsPart) | |
65 | .map(Comments::getComment) | |
66 | .orElse(Collections.emptyList()) | |
67 | .stream() | |
68 |
2
1. lambda$process$0 : replaced boolean return with true for pro/verron/officestamper/preset/preprocessors/malformedcomments/RemoveMalformedComments::lambda$process$0 → SURVIVED 2. lambda$process$0 : negated conditional → KILLED |
.filter(c -> !isEmpty(c)) |
69 | .map(CTMarkup::getId) | |
70 | .collect(toSet()); | |
71 | ||
72 | commentIds.removeAll(writtenCommentsId); | |
73 | ||
74 | log.debug("These comments have been referenced in body, but have no related content: {}", commentIds); | |
75 | malformedCommentIds.addAll(commentIds); | |
76 | ||
77 | var crVisitor = new CommentReferenceRemoverVisitor(malformedCommentIds); | |
78 | var crsVisitor = new CommentRangeStartRemoverVisitor(malformedCommentIds); | |
79 | var creVisitor = new CommentRangeEndRemoverVisitor(malformedCommentIds); | |
80 |
1
1. process : removed call to org/docx4j/TraversalUtil::visit → SURVIVED |
TraversalUtil.visit(document, true, List.of(crVisitor, crsVisitor, creVisitor)); |
81 |
1
1. process : removed call to pro/verron/officestamper/preset/preprocessors/malformedcomments/CommentReferenceRemoverVisitor::run → SURVIVED |
crVisitor.run(); |
82 |
1
1. process : removed call to pro/verron/officestamper/preset/preprocessors/malformedcomments/CommentRangeStartRemoverVisitor::run → SURVIVED |
crsVisitor.run(); |
83 |
1
1. process : removed call to pro/verron/officestamper/preset/preprocessors/malformedcomments/CommentRangeEndRemoverVisitor::run → SURVIVED |
creVisitor.run(); |
84 | } | |
85 | ||
86 | private static Comments tryGetCommentsPart(CommentsPart commentsPart) { | |
87 | try { | |
88 |
1
1. tryGetCommentsPart : replaced return value with null for pro/verron/officestamper/preset/preprocessors/malformedcomments/RemoveMalformedComments::tryGetCommentsPart → KILLED |
return commentsPart.getContents(); |
89 | } catch (Docx4JException e) { | |
90 | throw new OfficeStamperException(e); | |
91 | } | |
92 | } | |
93 | ||
94 | private static boolean isEmpty(Comments.Comment c) { | |
95 | var content = c.getContent(); | |
96 |
3
1. isEmpty : negated conditional → KILLED 2. isEmpty : negated conditional → KILLED 3. isEmpty : replaced boolean return with true for pro/verron/officestamper/preset/preprocessors/malformedcomments/RemoveMalformedComments::isEmpty → KILLED |
return content == null || content.isEmpty(); |
97 | } | |
98 | ||
99 | } | |
Mutations | ||
30 |
1.1 |
|
37 |
1.1 |
|
44 |
1.1 |
|
51 |
1.1 |
|
68 |
1.1 2.2 |
|
80 |
1.1 |
|
81 |
1.1 |
|
82 |
1.1 |
|
83 |
1.1 |
|
88 |
1.1 |
|
96 |
1.1 2.2 3.3 |