mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 07:57:13 +02:00
Enable flow documentation in external build
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=241934689
This commit is contained in:
parent
1346f7ab70
commit
33cdc3ddda
34 changed files with 1412 additions and 15 deletions
|
@ -0,0 +1,182 @@
|
|||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.documentation;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.re2j.Matcher;
|
||||
import com.google.re2j.Pattern;
|
||||
import google.registry.documentation.FlowDocumentation.ErrorCase;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Formatter that converts flow documentation into Markdown.
|
||||
*/
|
||||
public final class MarkdownDocumentationFormatter {
|
||||
|
||||
/** Header for flow documentation HTML output. */
|
||||
private static final String MARKDOWN_HEADER = "# Nomulus EPP Command API Documentation\n\n";
|
||||
|
||||
/** Pattern that naively matches HTML tags and entity references. */
|
||||
private static final Pattern HTML_TAG_AND_ENTITY_PATTERN = Pattern.compile("<[^>]*>|&[^;]*;");
|
||||
|
||||
/** 8 character indentation. */
|
||||
private static final String INDENT8 = Strings.repeat(" ", 8);
|
||||
|
||||
/** Max linewidth for our markdown docs. */
|
||||
private static final int LINE_WIDTH = 80;
|
||||
|
||||
/**
|
||||
* Returns the string with all HTML tags stripped. Also, removes a single space after any
|
||||
* newlines that have one (we get a single space indent for all lines but the first because of
|
||||
* the way that javadocs are written in comments).
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static String fixHtml(String value) {
|
||||
Matcher matcher = HTML_TAG_AND_ENTITY_PATTERN.matcher(value);
|
||||
int pos = 0;
|
||||
StringBuilder result = new StringBuilder();
|
||||
while (matcher.find(pos)) {
|
||||
result.append(value, pos, matcher.start());
|
||||
switch (matcher.group(0)) {
|
||||
case "<p>":
|
||||
// <p> is simply removed.
|
||||
break;
|
||||
case "&":
|
||||
result.append("&");
|
||||
break;
|
||||
case "<":
|
||||
result.append("<");
|
||||
break;
|
||||
case ">":
|
||||
result.append(">");
|
||||
break;
|
||||
case "&squot;":
|
||||
result.append("'");
|
||||
break;
|
||||
case """:
|
||||
result.append("\"");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized HTML sequence: " + matcher.group(0));
|
||||
}
|
||||
pos = matcher.end();
|
||||
}
|
||||
|
||||
// Add the string after the last HTML sequence.
|
||||
result.append(value.substring(pos));
|
||||
|
||||
return result.toString().replace("\n ", "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a list of words into a paragraph with less than maxWidth characters per line.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static String formatParagraph(List<String> words, int maxWidth) {
|
||||
int lineLength = 0;
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
for (String word : words) {
|
||||
// This check ensures that 1) don't add a space before the word and 2) always have at least
|
||||
// one word per line, so that we don't mishandle a very long word at the end of a line by
|
||||
// adding a blank line before the word.
|
||||
if (lineLength > 0) {
|
||||
// Do we have enough room for another word?
|
||||
if (lineLength + 1 + word.length() > maxWidth) {
|
||||
// No. End the line.
|
||||
output.append('\n');
|
||||
lineLength = 0;
|
||||
} else {
|
||||
// Yes: Insert a space before the word.
|
||||
output.append(' ');
|
||||
++lineLength;
|
||||
}
|
||||
}
|
||||
|
||||
output.append(word);
|
||||
lineLength += word.length();
|
||||
}
|
||||
|
||||
output.append('\n');
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'value' with words reflowed to maxWidth characters.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static String reflow(String text, int maxWidth) {
|
||||
|
||||
// A list of words that will be constructed into the list of words in a paragraph.
|
||||
ArrayList<String> words = new ArrayList<>();
|
||||
|
||||
// Read through the lines, process a paragraph every time we get a blank line.
|
||||
StringBuilder resultBuilder = new StringBuilder();
|
||||
for (String line : Splitter.on('\n').trimResults().split(text)) {
|
||||
|
||||
// If we got a blank line, format our current paragraph and start fresh.
|
||||
if (line.trim().isEmpty()) {
|
||||
resultBuilder.append(formatParagraph(words, maxWidth));
|
||||
resultBuilder.append('\n');
|
||||
words.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Split the line into words and add them to the current paragraph.
|
||||
words.addAll(Splitter.on(
|
||||
CharMatcher.breakingWhitespace()).omitEmptyStrings().splitToList(line));
|
||||
}
|
||||
|
||||
// Format the last paragraph, if any.
|
||||
if (!words.isEmpty()) {
|
||||
resultBuilder.append(formatParagraph(words, maxWidth));
|
||||
}
|
||||
|
||||
return resultBuilder.toString();
|
||||
}
|
||||
|
||||
/** Returns a string of HTML representing the provided flow documentation objects. */
|
||||
public static String generateMarkdownOutput(Iterable<FlowDocumentation> flowDocs) {
|
||||
StringBuilder output = new StringBuilder();
|
||||
output.append(MARKDOWN_HEADER);
|
||||
for (FlowDocumentation flowDoc : flowDocs) {
|
||||
output.append(String.format("## %s\n\n", flowDoc.getName()));
|
||||
output.append("### Description\n\n");
|
||||
output.append(String.format("%s\n\n", reflow(fixHtml(flowDoc.getClassDocs()), LINE_WIDTH)));
|
||||
output.append("### Errors\n\n");
|
||||
for (Long code : flowDoc.getErrorsByCode().keySet()) {
|
||||
output.append(String.format("* %d\n", code));
|
||||
|
||||
|
||||
for (ErrorCase error : flowDoc.getErrorsByCode().get(code)) {
|
||||
output.append(" * ");
|
||||
String wrappedReason = reflow(fixHtml(error.getReason()), LINE_WIDTH - 8);
|
||||
|
||||
// Replace internal newlines with indentation and strip the final newline.
|
||||
output.append(wrappedReason.trim().replace("\n", "\n" + INDENT8));
|
||||
output.append('\n');
|
||||
}
|
||||
}
|
||||
output.append('\n');
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
private MarkdownDocumentationFormatter() {}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue