1. Project Clover database mar. avr. 16 2024 08:19:06 CEST
  2. Package org.devacfr.maven.skins.reflow.snippet

File Processor.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart9.png
10% of files have more coverage

Code metrics

30
77
9
3
278
151
30
0,39
8,56
3
3,33

Classes

Class Line # Actions
Processor 43 63 0% 20 13
0.8522727585,2%
Processor.WebComponentProcessor 217 12 0% 8 3
0.87587,5%
Processor.ShortcodeProcessor 261 2 0% 2 0
1.0100%
 

Contributing tests

This file is covered by 6 tests. .

Source view

1    /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10    * http://www.apache.org/licenses/LICENSE-2.0
11    *
12    * Unless required by applicable law or agreed to in writing,
13    * software distributed under the License is distributed on an
14    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15    * KIND, either express or implied. See the License for the
16    * specific language governing permissions and limitations
17    * under the License.
18    */
19    package org.devacfr.maven.skins.reflow.snippet;
20   
21    import javax.annotation.Nonnull;
22    import javax.annotation.Nullable;
23   
24    import java.io.IOException;
25    import java.util.List;
26   
27    import com.google.common.collect.Iterables;
28    import com.google.common.collect.Lists;
29    import org.devacfr.maven.skins.reflow.snippet.ComponentToken.Tag;
30    import org.jsoup.nodes.Comment;
31    import org.jsoup.nodes.Element;
32    import org.jsoup.nodes.Node;
33    import org.jsoup.nodes.TextNode;
34    import org.slf4j.Logger;
35    import org.slf4j.LoggerFactory;
36   
37    /**
38    * Specific process for each type of snippet component.
39    *
40    * @author Christophe Friederich
41    * @version 2.4
42    */
 
43    public abstract class Processor {
44   
45    private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class);
46   
47    /** */
48    protected final SnippetParser parser;
49   
50    /**
51    * Default constructor
52    *
53    * @param parser
54    * current parser.
55    */
 
56  14 toggle public Processor(final SnippetParser parser) {
57  14 this.parser = parser;
58    }
59   
60    /**
61    * Specific parsing for each {@link ComponentToken}.
62    *
63    * @param token
64    * the current token.
65    */
 
66  53 toggle public void parse(final ComponentToken token) {
67  53 if (LOGGER.isDebugEnabled()) {
68  0 LOGGER.debug("Parse Token: {}", token);
69    }
70  53 switch (token.tag()) {
71  3 case empty:
72  3 parser.getSnippetContext().render(createSnippetComponent(token, null));
73  3 break;
74   
75  24 case start:
76  24 parser.push(token);
77  24 parser.parse();
78  24 break;
79   
80  24 case end:
81  24 final ComponentToken startToken = parser.pop();
82  24 if (!token.isCloseTagOf(startToken)) {
83  0 throw new RuntimeException(
84    "start token " + startToken + " should be closed, but next token is " + token);
85    }
86  24 parser.getSnippetContext().render(createSnippetComponent(startToken, token));
87  24 break;
88   
89  2 case html:
90  2 parser.getSnippetContext().render(createSnippetComponent(token, null));
91  2 break;
92   
93  0 default:
94  0 throw new SnippetParseException("unknown token tag " + token.tag());
95    }
96    }
97   
98    /**
99    * Append child {@link Node} in html rendering.
100    *
101    * @param node
102    * the node to use.
103    * @param writer
104    * the html writer
105    * @throws IOException
106    * If an I/O error occurs.
107    */
108    protected abstract void appendChildrenToHtml(Node node, Appendable writer) throws IOException;
109   
110    /**
111    * Convert the snippet to html.
112    *
113    * @param startToken
114    * the start token
115    * @param endToken
116    * the end token.
117    * @return Returns a new {@link Element} representing html represention of snippet.
118    */
 
119  27 toggle protected Element convertToHtml(@Nonnull final ComponentToken startToken, @Nullable final ComponentToken endToken) {
120  27 final Element startElement = startToken.getElement();
121  27 final Node previousElement = startElement.previousSibling();
122  27 Element endElement = null;
123  27 if (endToken != null) {
124  24 endElement = endToken.getElement();
125    }
126  27 final Element tmp = new Element("component");
127  27 final Node parent = startElement.parentNode();
128   
129  27 final StringBuilder html = new StringBuilder(convertElementToHtml(startElement));
130  27 final List<Node> nodesToRemove = Lists.newArrayList();
131  27 nodesToRemove.add(startElement);
132  27 if (endElement != null) {
133  24 boolean startCopy = false;
134   
135  24 for (final Node n : parent.childNodes()) {
136  329 if (n.equals(endElement)) {
137  24 nodesToRemove.add(n);
138  24 break;
139    }
140  305 if (startCopy) {
141  83 try {
142  83 appendChildrenToHtml(n, html);
143    } catch (final IOException e) {
144  0 throw new RuntimeException(e.getMessage(), e);
145    }
146  83 nodesToRemove.add(n);
147    }
148  305 if (n.equals(startElement)) {
149  24 startCopy = true;
150    }
151    }
152  24 html.append(convertElementToHtml(endElement));
153    }
154  27 tmp.append(html.toString());
155  27 final Element component = tmp.children().first();
156  27 final Element parentElement = startElement.parent();
157   
158  27 if (previousElement != null) {
159  27 previousElement.after(component);
160    } else {
161  0 if (parentElement.children().first() != null) {
162  0 parentElement.children().first().before(component);
163    } else {
164  0 parentElement.children().add(component);
165    }
166    }
167  27 nodesToRemove.forEach(Node::remove);
168  27 return component;
169    }
170   
171    /**
172    * Create a {@link SnippetComponent}.
173    *
174    * @param startToken
175    * the start token.
176    * @param endToken
177    * the end token.
178    * @return Returns a new instance of {@link SnippetComponent} representing the information contained between
179    * {@code startToken} and {@code endToken}.
180    */
 
181  29 toggle protected SnippetComponent<?> createSnippetComponent(final ComponentToken startToken,
182    final ComponentToken endToken) {
183  29 final SnippetContext snippetContext = parser.getSnippetContext();
184  29 Element componentElement = null;
185  29 if (Tag.html.equals(startToken.tag())) {
186  2 componentElement = startToken.getElement();
187    } else {
188  27 componentElement = convertToHtml(startToken, endToken);
189    }
190  29 return snippetContext.create(componentElement, startToken, endToken);
191    }
192   
193    /**
194    * Converts the snippet element to html format.
195    *
196    * @param element
197    * the html element to use.
198    * @return Returns a {@link String} representing the snippet element in html format.
199    */
 
200  51 toggle protected String convertElementToHtml(final Element element) {
201  51 return element.text()
202    .replace("{{< ", "<")
203    .replace(" />}}", "/>")
204    .replace(" /%}}", "/>")
205    .replace(" >}}", ">")
206    .replace("{{% ", "<")
207    .replace(" %}}", ">")
208    .replaceAll("\\u201c|\\u201d", "\"");
209    }
210   
211    /**
212    * Specific process for snippet web component.
213    *
214    * @author Christophe Friederich
215    * @version 2.4
216    */
 
217    public static class WebComponentProcessor extends Processor {
218   
219    /**
220    * Default constructor
221    *
222    * @param parser
223    * current parser.
224    */
 
225  7 toggle public WebComponentProcessor(final SnippetParser parser) {
226  7 super(parser);
227    }
228   
229    /**
230    * {@inheritDoc}
231    */
 
232  33 toggle @Override
233    protected void appendChildrenToHtml(final Node node, final Appendable writer) throws IOException {
234  33 if (node instanceof Element) {
235  7 final Element el = (Element) node;
236    // when use code highlighting
237  7 if ("div".equals(el.tagName()) && el.hasClass("source")) {
238  4 writer.append(el.text());
239    } else {
240    // comment can be enclose in <p> element.
241  3 if (Iterables.tryFind(el.childNodes(), n -> n instanceof Comment).isPresent()) {
242  3 writer.append(el.data());
243    } else {
244  0 writer.append(el.outerHtml());
245    }
246    }
247  26 } else if (node instanceof Comment) {
248  6 writer.append(((Comment) node).getData());
249  20 } else if (node instanceof TextNode) {
250  20 writer.append(((TextNode) node).text());
251    }
252    }
253    }
254   
255    /**
256    * Specific process for snippet shortcode component.
257    *
258    * @author Christophe Friederich
259    * @version 2.4
260    */
 
261    public static class ShortcodeProcessor extends Processor {
262   
263    /**
264    * Default constructor
265    *
266    * @param parser
267    * current parser.
268    */
 
269  7 toggle public ShortcodeProcessor(final SnippetParser parser) {
270  7 super(parser);
271    }
272   
 
273  50 toggle @Override
274    protected void appendChildrenToHtml(final Node node, final Appendable writer) throws IOException {
275  50 writer.append(node.outerHtml());
276    }
277    }
278    }