Remove AbstractExplicitGenerator.recursiveRuntimeType()
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / reactor / TypeComments.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.binding.generator.impl.reactor;
9
10 import static org.opendaylight.mdsal.binding.generator.BindingGeneratorUtil.replaceAllIllegalChars;
11
12 import com.google.common.base.CharMatcher;
13 import com.google.common.base.Strings;
14 import com.google.common.escape.Escaper;
15 import com.google.common.escape.Escapers;
16 import java.util.Optional;
17 import java.util.StringTokenizer;
18 import java.util.regex.Pattern;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.opendaylight.mdsal.binding.model.api.TypeComment;
21 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
22
23 /**
24  * Utility methods for creating {@link TypeComment}s.
25  */
26 @NonNullByDefault
27 final class TypeComments {
28     private static final Escaper ENTITY_ESCAPER = Escapers.builder()
29             .addEscape('<', "&lt;")
30             .addEscape('>', "&gt;")
31             .addEscape('&', "&amp;")
32             .addEscape('@', "&#64;").build();
33     private static final Pattern TAIL_COMMENT_PATTERN = Pattern.compile("*/", Pattern.LITERAL);
34     private static final CharMatcher NEWLINE_OR_TAB = CharMatcher.anyOf("\n\t");
35     private static final Pattern MULTIPLE_SPACES_PATTERN = Pattern.compile(" +");
36
37     private TypeComments() {
38         // Hidden on purpose
39     }
40
41     /**
42      * Create a {@link TypeComment} for a {@link DocumentedNode}'s description string.
43      *
44      * @param node Documented node containing the description to be processed
45      * @return {@link TypeComment}, or empty if the node's description was empty or non-present.
46      */
47     public static Optional<TypeComment> description(final DocumentedNode node) {
48         final String description = node.getDescription().orElse("");
49         return description.isEmpty() ? Optional.empty() : Optional.of(() -> replaceAllIllegalChars(
50             formatToParagraph(
51                 TAIL_COMMENT_PATTERN.matcher(ENTITY_ESCAPER.escape(description)).replaceAll("&#42;&#47;"), 0)));
52     }
53
54     private static String formatToParagraph(final String text, final int nextLineIndent) {
55         if (Strings.isNullOrEmpty(text)) {
56             return "";
57         }
58
59         final StringBuilder sb = new StringBuilder();
60         final StringBuilder lineBuilder = new StringBuilder();
61         final String lineIndent = " ".repeat(nextLineIndent);
62         final String formattedText = MULTIPLE_SPACES_PATTERN.matcher(NEWLINE_OR_TAB.replaceFrom(text, " "))
63                 .replaceAll(" ");
64         final StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
65
66         boolean isFirstElementOnNewLineEmptyChar = false;
67         while (tokenizer.hasMoreElements()) {
68             final String nextElement = tokenizer.nextElement().toString();
69
70             if (lineBuilder.length() + nextElement.length() > 80) {
71                 // Trim trailing whitespace
72                 for (int i = lineBuilder.length() - 1; i >= 0 && lineBuilder.charAt(i) != ' '; --i) {
73                     lineBuilder.setLength(i);
74                 }
75
76                 // Trim leading whitespace
77                 while (lineBuilder.length() > 0 && lineBuilder.charAt(0) == ' ') {
78                     lineBuilder.deleteCharAt(0);
79                 }
80
81                 sb.append(lineBuilder).append('\n');
82                 lineBuilder.setLength(0);
83
84                 if (nextLineIndent > 0) {
85                     sb.append(lineIndent);
86                 }
87
88                 if (" ".equals(nextElement)) {
89                     isFirstElementOnNewLineEmptyChar = true;
90                 }
91             }
92             if (isFirstElementOnNewLineEmptyChar) {
93                 isFirstElementOnNewLineEmptyChar = false;
94             } else {
95                 lineBuilder.append(nextElement);
96             }
97         }
98
99         return sb.append(lineBuilder).append('\n').toString();
100     }
101 }