Skip to content

Commit

Permalink
Include field comments when no setters, better handling of HTML and code
Browse files Browse the repository at this point in the history
  • Loading branch information
Yaytay committed Jul 14, 2023
1 parent e053209 commit af9aae3
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.EndElementTree;
import com.sun.source.doctree.EntityTree;
import com.sun.source.doctree.LinkTree;
import com.sun.source.doctree.LiteralTree;
import com.sun.source.doctree.ParamTree;
import com.sun.source.doctree.ReferenceTree;
import com.sun.source.doctree.ReturnTree;
Expand All @@ -35,6 +37,8 @@
import java.io.Writer;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.tools.Diagnostic;
import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.doclet.Reporter;
Expand All @@ -54,7 +58,8 @@ public class AsciiDocDocTreeWalker extends DocTreePathScanner<Void, Void> {

private final Queue<Boolean> listOrderedStack = new ArrayDeque<>();

private boolean inMacro;
private boolean inPara;
private boolean inSource;

public AsciiDocDocTreeWalker(DocletEnvironment environment, AsciiDocOptions options, Writer writer, Reporter reporter, TreePath path) {
this.environment = environment;
Expand All @@ -79,8 +84,12 @@ public Void visitEndElement(EndElementTree node, Void p) {
listOrderedStack.poll();
write("\n");
} else if (name.equalsIgnoreCase("a")) {
inMacro = false;
write("] ");
} else if (name.equalsIgnoreCase("pre") || name.equalsIgnoreCase("code")) {
if (inSource) {
inSource = false;
write("\n----\n");
}
} else {
write(node.toString());
write(" ");
Expand Down Expand Up @@ -114,37 +123,99 @@ public Void visitStartElement(StartElementTree node, Void p) {
write("\n\n");
} else if (name.equalsIgnoreCase("a")) {
write("link:");
for (DocTree attribute : node.getAttributes()) {
if (attribute instanceof AttributeTree) {
AttributeTree attributeTree = (AttributeTree) attribute;
if (attributeTree.getName().toString().equalsIgnoreCase("href")) {
write(attributeTree.getValue().toString());
break;
}
}
String attributeValue = findAttribute(node, "href");
if (attributeValue != null) {
write(attributeValue);
}
write("[");
inMacro = true;
return null;
} else if (name.equalsIgnoreCase("pre") || name.equalsIgnoreCase("code")) {
if (!inSource) {
inSource = true;
write("\n[source");
String attributeValue = findAttribute(node, "data-lang");
if (attributeValue != null) {
write(",");
write(attributeValue);
}
write("]\n");
write("----\n");
return null;
}
} else {
reporter.print(Diagnostic.Kind.WARNING, new DocTreePath(path, dc), "Unrecognised HTML tag (" + name + ").");
write(node.toString());
}
return super.visitStartElement(node, p);
}

String findAttribute(StartElementTree node, String requiredAttribute) {
for (DocTree attribute : node.getAttributes()) {
if (attribute instanceof AttributeTree) {
AttributeTree attributeTree = (AttributeTree) attribute;
if (attributeTree.getName().toString().equalsIgnoreCase(requiredAttribute)) {
return attributeTree.getValue().toString();
}
}
}
return null;
}

@Override
public Void visitText(TextTree node, Void p) {
write(node.getBody().trim());
if (!inMacro) {
write("\n");
String text = node.getBody();
if (!inPara) {
text = text.stripLeading();
}

write(text);
return super.visitText(node, p);
}

@Override
public Void visitLiteral(LiteralTree node, Void p) {
write("`+");
super.visitLiteral(node, p);
write("+`");
return null;
}

private static final Pattern NUMERIC_ENTITY = Pattern.compile("&#([0-9]{1,6});");
private static final Pattern TEXT_ENTITY = Pattern.compile("&([a-zA-Z]{1,6});");

@Override
public Void visitEntity(EntityTree node, Void p) {
String entityRef = node.toString();

try {
Matcher matcher = NUMERIC_ENTITY.matcher(entityRef);
if (matcher.matches()) {
String ref = matcher.group(1);
int code = Integer.parseInt(ref);
write(Character.toString(code));
return null;
}
matcher = TEXT_ENTITY.matcher(entityRef);
if (matcher.matches()) {
String ref = matcher.group(1).toLowerCase();
String character = HtmlEntities.lookupEntity(ref);
if (character != null) {
write(character);
return null;
}
}
} catch (Throwable ex) {
reporter.print(Diagnostic.Kind.ERROR, new DocTreePath(path, dc), "Failed to process entity: " + node.toString());
}

write(node.toString());
return null;
}

@Override
public Void visitSee(SeeTree node, Void p) {
write("\n\nSee: ");
return super.visitSee(node, p); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody
return super.visitSee(node, p);
}

@Override
Expand All @@ -164,8 +235,7 @@ public Void visitAuthor(AuthorTree node, Void p) {

private void write(String s) {
if (s != null) {
s = s.replaceAll("\n ", " ");

inPara = !s.endsWith("\n");
try {
writer.write(s);
} catch (IOException ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.Set;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
Expand All @@ -48,6 +51,7 @@ public class AsciiDocElementVisitor implements ElementVisitor<Void, Void> {

private Writer writer;
private TypeWriter typeWriter;
private final Set<String> fields = new HashSet<>();

public AsciiDocElementVisitor(DocletEnvironment environment, AsciiDocOptions options, Reporter reporter) {
this.environment = environment;
Expand Down Expand Up @@ -86,6 +90,7 @@ public Void visitType(TypeElement e, Void p) {
return null;
}
}
fields.clear();
File output = new File(dir, e.getQualifiedName() + ".adoc");
reporter.print(Diagnostic.Kind.NOTE, "Writing file " + output.getAbsolutePath());
try (Writer newWriter = new FileWriter(output)) {
Expand All @@ -108,14 +113,14 @@ public Void visitType(TypeElement e, Void p) {
writer.write("| Details\n");
writer.write("\n\n");

e.getEnclosedElements().forEach(enclosed -> enclosed.accept(this, null));
documentFields(e);

for (TypeMirror superMirror = e.getSuperclass(); superMirror != null;) {

Element superElement = environment.getTypeUtils().asElement(superMirror);
if (superElement instanceof TypeElement) {
TypeElement superTypeElement = (TypeElement) superElement;
superTypeElement.getEnclosedElements().forEach(enclosed -> enclosed.accept(this, null));
documentFields(superTypeElement);
superMirror = superTypeElement.getSuperclass();
} else {
superMirror = null;
Expand All @@ -136,30 +141,42 @@ public Void visitType(TypeElement e, Void p) {

return null;
}

private void documentFields(TypeElement type) {
type.getEnclosedElements().forEach(enclosed -> {
if (enclosed.getKind() == ElementKind.METHOD) {
enclosed.accept(this, null);
}
});
type.getEnclosedElements().forEach(enclosed -> {
if (enclosed.getKind() == ElementKind.FIELD) {
enclosed.accept(this, null);
}
});
}



@Override
public Void visitVariable(VariableElement e, Void p) {
e.getEnclosedElements().forEach(enclosed -> enclosed.accept(this, null));
return null;
}
try {
String fieldName = e.getSimpleName().toString();
if (!this.fields.contains(fieldName)) {
this.fields.add(fieldName);

@Override
public Void visitExecutable(ExecutableElement e, Void p) {
if (e.getSimpleName().toString().startsWith("set") && e.getParameters().size() == 1) {
try {
writer.write("| ");
writer.write(JavadocCapturer.setterNameToVariableName(e.getSimpleName().toString()));
writer.write(fieldName);
writer.write("\n");

writer.write("| ");
VariableElement variableElement = (VariableElement) e.getParameters().get(0);
VariableElement variableElement = e;

DeclaredType declaredType = variableElement.asType().accept(new SimpleTypeVisitor14<DeclaredType, Void>(){
@Override
public DeclaredType visitDeclared(DeclaredType t, Void p) {
return t;
}

}, null);
Element declaredTypeElement = declaredType == null ? null : declaredType.asElement();
TypeElement typeElement = declaredTypeElement instanceof TypeElement ? (TypeElement) declaredTypeElement : null;
Expand All @@ -169,7 +186,7 @@ public DeclaredType visitDeclared(DeclaredType t, Void p) {
typeWriter.writeDeclaredType(declaredType);
}
writer.write("\n");

writer.write("| ");
AsciiDocDocTreeWalker docTreeWalker = new AsciiDocDocTreeWalker(environment, options, writer, reporter, environment.getDocTrees().getPath(e));
DocCommentTree docCommentTree = environment.getDocTrees().getDocCommentTree(e);
Expand All @@ -179,11 +196,59 @@ public DeclaredType visitDeclared(DeclaredType t, Void p) {
docTreeWalker.scan();
// environment.getDocTrees().getDocCommentTree(e).accept(docTreeWalker, null);
}
writer.write("\n");
writer.write("\n\n");
}
} catch (IOException ex) {
reporter.print(Diagnostic.Kind.ERROR, "Failed to write to file: " + ex.getMessage());
}
return null;
}

@Override
public Void visitExecutable(ExecutableElement e, Void p) {
if (e.getSimpleName().toString().startsWith("set") && e.getParameters().size() == 1) {
try {
String fieldName = JavadocCapturer.setterNameToVariableName(e.getSimpleName().toString());
if (!this.fields.contains(fieldName)) {
this.fields.add(fieldName);

writer.write("| ");
writer.write(fieldName);
writer.write("\n");

writer.write("| ");
VariableElement variableElement = (VariableElement) e.getParameters().get(0);

DeclaredType declaredType = variableElement.asType().accept(new SimpleTypeVisitor14<DeclaredType, Void>(){
@Override
public DeclaredType visitDeclared(DeclaredType t, Void p) {
return t;
}

}, null);
Element declaredTypeElement = declaredType == null ? null : declaredType.asElement();
TypeElement typeElement = declaredTypeElement instanceof TypeElement ? (TypeElement) declaredTypeElement : null;
if (typeElement == null) {
writer.write(variableElement.asType().toString());
} else {
typeWriter.writeDeclaredType(declaredType);
}
writer.write("\n");

writer.write("| ");
AsciiDocDocTreeWalker docTreeWalker = new AsciiDocDocTreeWalker(environment, options, writer, reporter, environment.getDocTrees().getPath(e));
DocCommentTree docCommentTree = environment.getDocTrees().getDocCommentTree(e);
if (docCommentTree == null) {
reporter.print(Diagnostic.Kind.WARNING, "No doc comment for " + e.getSimpleName());
} else {
docTreeWalker.scan();
// environment.getDocTrees().getDocCommentTree(e).accept(docTreeWalker, null);
}
writer.write("\n");
}
} catch (IOException ex) {
reporter.print(Diagnostic.Kind.ERROR, "Failed to write to file: " + ex.getMessage());
}

e.getEnclosedElements().forEach(enclosed -> enclosed.accept(this, null));
}
return null;
Expand Down
55 changes: 55 additions & 0 deletions src/main/java/uk/co/spudsoft/params4j/doclet/HtmlEntities.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2023 jtalbut
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package uk.co.spudsoft.params4j.doclet;

import java.util.HashMap;
import java.util.Map;

/**
*
* @author njt
*/
public class HtmlEntities {


private static final Map<String, String> ENTITIES = prepareEntities();

private static Map<String, String> prepareEntities() {
Map<String, String> result = new HashMap<>();
result.put("lt", "<");
result.put("gt", ">");
result.put("amp", "&");
result.put("quot", "\"");
result.put("dollar", "$");
result.put("percnt", "%");
result.put("apos", "'");
result.put("lpar", "(");
result.put("rpar", ")");
result.put("lcub", "{");
result.put("rcub", "}");
result.put("semi", ";");
return result;
}

private HtmlEntities() {
}

public static String lookupEntity(String ref) {
return ENTITIES.get(ref);
}

}
Loading

0 comments on commit af9aae3

Please sign in to comment.