package stanhebben.zenscript.docs; /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ import com.sun.javadoc.AnnotationDesc; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.LanguageVersion; import com.sun.javadoc.MethodDoc; import com.sun.javadoc.Parameter; import com.sun.javadoc.RootDoc; import com.sun.javadoc.Type; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import stanhebben.zenscript.util.StringUtil; /** * * Example usage: (from minetweaker API source dir): * * javadoc -doclet stanhebben.zenscript.docs.ZenScriptDoclet -docletpath ..\..\..\..\ZenScript\build\classes\main -cp ..\..\..\..\ZenScript\build\libs\ZenScript.jar -sourcepath . -subpackages minetweaker * * @author Stan Hebben */ public class ZenScriptDoclet { public static boolean start(RootDoc root) { ClassDoc[] classes = root.classes(); List documentedClasses = new ArrayList(); List expansionClasses = new ArrayList(); for (int i = 0; i < classes.length; ++i) { ClassDoc cls = classes[i]; for (AnnotationDesc annotation : cls.annotations()) { //String fullName = annotation.annotationType().containingPackage().name() + '.' + annotation.annotationType().name(); String fullName = annotation.annotationType().qualifiedName(); if (fullName.equals("stanhebben.zenscript.annotations.ZenClass")) { documentedClasses.add(new ZenClassDoc(cls, (String) (annotation.elementValues()[0].value().value()))); } else if (fullName.equals("stanhebben.zenscript.annotations.ZenExpansion")) { expansionClasses.add(new ZenExpansionDoc(cls, (String) (annotation.elementValues()[0].value().value()))); } } } Map classesByName = new HashMap(); Map classesByJavaName = new HashMap(); for (ZenClassDoc documentedClass : documentedClasses) { classesByName.put(documentedClass.getName(), documentedClass); classesByJavaName.put(documentedClass.getDoc().qualifiedName(), documentedClass); } for (ZenExpansionDoc expansion : expansionClasses) { if (classesByName.containsKey(expansion.getType())) { classesByName.get(expansion.getType()).addExpansion(expansion); } else { if (expansion.getType().endsWith("]")) { String baseName = expansion.getType().substring(0, expansion.getType().lastIndexOf('[')); if (classesByName.containsKey(baseName)) { classesByName.get(baseName).addExpansion(expansion); } } } } System.out.println("Number of classes to document: " + classesByName.size()); File output = new File("../../../build/zendoc"); if (!output.exists()) output.mkdirs(); String packageList = buildPackageList(documentedClasses); for (ZenClassDoc doc : classesByName.values()) { try { File outputDoc = new File(output, doc.getName().replace('.', '/') + ".html"); File outputDocParent = outputDoc.getParentFile(); if (!outputDocParent.exists()) outputDocParent.mkdirs(); Writer writer = new BufferedWriter(new FileWriter(outputDoc)); String simpleName = doc.getName().substring(doc.getName().lastIndexOf('.') + 1); writer.append(""); writer.append(""); writer.append("ZenDoc : " + simpleName + ""); writer.append(""); writer.append(""); writer.append(""); writer.append(""); writer.append("
"); writer.append(packageList); writer.append("
"); String pkgName = doc.getName().substring(0, doc.getName().lastIndexOf('.')); writer.append("
"); writer.append(pkgName); writer.append("
"); // output class or interface contents writer.append("

"); if (doc.getDoc().isInterface()) { writer.append("Interface "); } else { writer.append("Class "); } writer.append(doc.getDoc().name()).append("

"); if (doc.getDoc().interfaces().length > 0) { writer.append("
implements "); boolean first = true; for (Type itype : doc.getDoc().interfaceTypes()) { if (first) { first = false; } else { writer.append(", "); } outputType(writer, itype, classesByJavaName); } writer.append("
"); } writer.append("
"); writer.append("
"); for (String p : StringUtil.splitParagraphs(doc.getDoc().commentText())) { writer.append("

"); writer.append(p); writer.append("

"); } writer.append("
"); if (doc.getDoc().isInterface() && doc.getDoc().methods().length == 1) { // functional interface writer.append("

Functional interface

"); MethodDoc method = doc.getDoc().methods()[0]; writer.append("
"); writer.append("function ("); boolean first = true; for (Parameter parameter : method.parameters()) { if (first) { first = false; } else { writer.append(", "); } ZenParameterDoc paramdoc = new ZenParameterDoc(parameter); writer.append(paramdoc.getName()); writer.append(" as "); outputType(writer, paramdoc.getType(), classesByJavaName); } writer.append(") as "); outputType(writer, method.returnType(), classesByJavaName); writer.append("
"); String[] comment = StringUtil.splitParagraphs(method.commentText()); for (String line : comment) { writer.append("

"); writer.append(line); writer.append("

"); } } else { writer.append("

Member Overview

"); // collect members LinkedHashMap instanceProperties = new LinkedHashMap(); LinkedHashMap staticProperties = new LinkedHashMap(); List instanceMethods = new ArrayList(); List staticMethods = new ArrayList(); List operators = new ArrayList(); List casters = new ArrayList(); for (MethodDoc method : doc.getDoc().methods()) { for (AnnotationDesc annotation : method.annotations()) { String fullName = annotation.annotationType().qualifiedName(); if (fullName.equals("stanhebben.zenscript.annotations.ZenMethod") || fullName.equals("stanhebben.zenscript.annotations.ZenMethodStatic")) { String name = annotation.elementValues().length > 0 ? (String) (annotation.elementValues()[0].value().value()) : ""; if (name.length() == 0) { name = method.name(); } List parameters = new ArrayList(); for (Parameter parameter : method.parameters()) { parameters.add(new ZenParameterDoc(parameter)); } if (method.isStatic()) { staticMethods.add(new ZenMethodDoc(name, method, parameters)); } else { instanceMethods.add(new ZenMethodDoc(name, method, parameters)); } } else if (fullName.equals("stanhebben.zenscript.annotations.ZenGetter")) { String name = annotation.elementValues().length > 0 ? (String) (annotation.elementValues()[0].value().value()) : ""; if (name.length() == 0) { name = method.name(); } Type type = method.returnType(); String[] comment = StringUtil.splitParagraphs(method.commentText()); if (!method.isStatic()) { if (instanceProperties.containsKey(name)) { ZenPropertyDoc property = instanceProperties.get(name); property.setCanGet(true); property.setComment(comment); } else { ZenPropertyDoc property = new ZenPropertyDoc(name, type); property.setCanGet(true); property.setComment(comment); instanceProperties.put(name, property); } } else { if (staticProperties.containsKey(name)) { ZenPropertyDoc property = staticProperties.get(name); property.setCanGet(true); property.setComment(comment); } else { ZenPropertyDoc property = new ZenPropertyDoc(name, type); property.setCanGet(true); property.setComment(comment); staticProperties.put(name, property); } } } else if (fullName.equals("stanhebben.zenscript.annotations.ZenSetter")) { String name = annotation.elementValues().length > 0 ? (String) (annotation.elementValues()[0].value().value()) : ""; if (name.length() == 0) { name = method.name(); } Type type = method.parameters()[0].type(); String[] comment = StringUtil.splitParagraphs(method.commentText()); if (!method.isStatic()) { if (instanceProperties.containsKey(name)) { ZenPropertyDoc property = instanceProperties.get(name); property.setCanSet(true); } else { ZenPropertyDoc property = new ZenPropertyDoc(name, type); property.setCanGet(true); property.setComment(comment); instanceProperties.put(name, property); } } else { if (staticProperties.containsKey(name)) { ZenPropertyDoc property = staticProperties.get(name); property.setCanSet(true); } else { ZenPropertyDoc property = new ZenPropertyDoc(name, type); property.setCanGet(true); property.setComment(comment); staticProperties.put(name, property); } } } else if (fullName.equals("stanhebben.zenscript.annotations.ZenOperator")) { String operator = annotation.elementValues()[0].value().value().toString(); operators.add(new ZenOperatorDoc(operator, method)); } else if (fullName.equals("stanhebben.zenscript.annotations.ZenCaster")) { casters.add(new ZenCasterDoc(method)); } } } for (ZenExpansionDoc expansion : doc.getExpansions()) { // TODO } if (!staticProperties.isEmpty()) { writer.append("
"); writer.append("
Static Properties
"); writer.append("
"); writer.append(""); String[] names = new String[staticProperties.size()]; int namei = 0; for (String name : staticProperties.keySet()) { names[namei++] = name; } Arrays.sort(names); for (String name : names) { ZenPropertyDoc property = staticProperties.get(name); writer.append(""); writer.append(""); writer.append(""); } writer.append("
"); outputType(writer, property.getType(), classesByJavaName); writer.append(""); writer.append("
"); if (!property.isCanSet()) writer.append(" "); writer.append("") .append(property.getName()) .append("
"); if (property.getComment() != null && property.getComment().length > 0) { writer.append("
") .append(property.getComment()[0]) .append("
"); } writer.append("
"); } if (!instanceProperties.isEmpty()) { writer.append("
"); writer.append("
Properties
"); writer.append("
"); writer.append(""); String[] names = new String[instanceProperties.size()]; int namei = 0; for (String name : instanceProperties.keySet()) { names[namei++] = name; } Arrays.sort(names); for (String name : names) { ZenPropertyDoc property = instanceProperties.get(name); writer.append(""); writer.append(""); writer.append(""); } writer.append("
"); outputType(writer, property.getType(), classesByJavaName); writer.append(""); writer.append("
"); if (!property.isCanSet()) writer.append(" "); writer.append("") .append(property.getName()) .append("
"); if (property.getComment() != null && property.getComment().length > 0) { writer.append("
") .append(property.getComment()[0]) .append("
"); } writer.append("
"); } if (!staticMethods.isEmpty()) { writer.append("
"); writer.append("
Static Methods
"); writer.append("
"); writer.append(""); for (ZenMethodDoc method : staticMethods) { writer.append(""); writer.append(""); writer.append(""); } writer.append("
"); outputType(writer, method.getDoc().returnType(), classesByJavaName); writer.append(""); writer.append("
"); writer.append("") .append(method.getName()) .append("("); boolean first = true; for (ZenParameterDoc param : method.getParameters()) { if (param.isOptional()) writer.append(""); if (first) { first = false; } else { writer.append(", "); } writer.append(param.getName()); writer.append(" as "); outputType(writer, param.getType(), classesByJavaName); } writer.append(")
"); String[] comment = StringUtil.splitParagraphs(method.getDoc().commentText()); if (comment.length > 0) { writer.append("
") .append(comment[0]) .append("
"); } writer.append("
"); } if (!instanceMethods.isEmpty()) { writer.append("
"); writer.append("
Methods
"); writer.append("
"); writer.append(""); for (ZenMethodDoc method : instanceMethods) { writer.append(""); writer.append(""); writer.append(""); } writer.append("
"); outputType(writer, method.getDoc().returnType(), classesByJavaName); writer.append(""); writer.append("
"); writer.append("") .append(method.getName()) .append("("); boolean first = true; for (ZenParameterDoc param : method.getParameters()) { if (param.isOptional()) writer.append(""); if (first) { first = false; } else { writer.append(", "); } writer.append(param.getName()); writer.append(" as "); outputType(writer, param.getType(), classesByJavaName); } writer.append(")
"); String[] comment = StringUtil.splitParagraphs(method.getDoc().commentText()); if (comment.length > 0) { writer.append("
") .append(comment[0]) .append("
"); } writer.append("
"); } if (!operators.isEmpty()) { // TODO } if (!casters.isEmpty()) { writer.append("
"); writer.append("
Casters
"); writer.append("
"); writer.append(""); for (ZenCasterDoc caster : casters) { writer.append(""); writer.append(""); } writer.append("
"); writer.append(""); String[] comment = StringUtil.splitParagraphs(caster.getMethod().commentText()); if (comment.length > 0) { writer.append("
") .append(comment[0]) .append("
"); } writer.append("
"); } } writer.append("
"); writer.append(""); writer.append(""); writer.append(""); writer.append(""); writer.close(); } catch (IOException ex) { System.out.println(ex.getMessage()); } } return true; } /** * NOTE: Without this method present and returning LanguageVersion.JAVA_1_5, * Javadoc will not process generics because it assumes LanguageVersion.JAVA_1_1 * @return language version (hard coded to LanguageVersion.JAVA_1_5) */ public static LanguageVersion languageVersion() { return LanguageVersion.JAVA_1_5; } private static String buildPackageList(List classes) { // collect package list Map> packages = new HashMap>(); for (ZenClassDoc cls : classes) { String pkg = cls.getName().substring(0, cls.getName().lastIndexOf('.')); if (packages.containsKey(pkg)) { packages.get(pkg).add(cls); } else { ArrayList classList = new ArrayList(); classList.add(cls); packages.put(pkg, classList); } } String[] packageSorted = new String[packages.size()]; int packageIndex = 0; for (String packageName : packages.keySet()) { packageSorted[packageIndex++] = packageName; } Arrays.sort(packageSorted); // output data StringBuilder output = new StringBuilder(); output.append("
"); output.append("
"); output.append("

Packages

"); output.append("
"); for (int i = 0; i < packageSorted.length; i++) { String pkgId = extractId(packageSorted[i]); String pkgDir = "/doc/" + packageSorted[i].replace('.', '/'); output.append("
"); output.append("

"); output.append(" ") .append(packageSorted[i]) .append(""); output.append("

"); output.append("
"); output.append("
"); // assemble lists List interfaceNames = new ArrayList(); List classNames = new ArrayList(); for (ZenClassDoc cls : packages.get(packageSorted[i])) { if (cls.getDoc().isInterface()) { interfaceNames.add(cls.getDoc().name()); } else { classNames.add(cls.getDoc().name()); } } Collections.sort(interfaceNames); Collections.sort(classNames); if (!interfaceNames.isEmpty()) { output.append("

Interfaces

"); output.append(""); for (String ifaceName : interfaceNames) { output.append(""); } output.append("
") .append(ifaceName) .append("
"); } if (!classNames.isEmpty()) { output.append("

Classes

"); output.append(""); for (String className : classNames) { output.append(""); } output.append("
") .append(className) .append("
"); } output.append("
"); } output.append("
"); return output.toString(); } private static String extractId(String pkg) { return pkg.replace('.', '-'); } private static void outputType(Writer output, Type type, Map javaClasses) throws IOException { if (javaClasses.containsKey(type.qualifiedTypeName())) { ZenClassDoc doc = javaClasses.get(type.qualifiedTypeName()); output.append(""); output.append(doc.getName().substring(doc.getName().lastIndexOf('.') + 1)); output.append(""); } else if (type.qualifiedTypeName().equals("java.util.List")) { Type base = type.asParameterizedType().typeArguments()[0]; outputType(output, base, javaClasses); output.append("[]"); } else if (type.qualifiedTypeName().equals("java.util.Map")) { Type key = type.asParameterizedType().typeArguments()[0]; Type value = type.asParameterizedType().typeArguments()[1]; outputType(output, value, javaClasses); output.append('['); outputType(output, key, javaClasses); output.append(']'); } else if (type.qualifiedTypeName().equals("java.lang.String")) { output.append("string"); } else { output.append(type.qualifiedTypeName()); } } private static void outputTypeRaw(Writer output, Type type, Map javaClasses) throws IOException { if (javaClasses.containsKey(type.qualifiedTypeName())) { ZenClassDoc doc = javaClasses.get(type.qualifiedTypeName()); output.append(doc.getName().substring(doc.getName().lastIndexOf('.') + 1)); } else if (type.qualifiedTypeName().equals("java.util.List")) { Type base = type.asParameterizedType().typeArguments()[0]; outputTypeRaw(output, base, javaClasses); output.append("[]"); } else if (type.qualifiedTypeName().equals("java.util.Map")) { Type key = type.asParameterizedType().typeArguments()[0]; Type value = type.asParameterizedType().typeArguments()[1]; outputTypeRaw(output, value, javaClasses); output.append('['); outputTypeRaw(output, key, javaClasses); output.append(']'); } else if (type.qualifiedTypeName().equals("java.lang.String")) { output.append("string"); } else { output.append(type.qualifiedTypeName()); } } private static String makeLink(String className) { return "/doc/" + className.replace('.', '/') + ".html"; } }