All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.groovy.tools.groovydoc.SimpleGroovyClassDoc Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2003-2013 the original author or authors.
 *
 * 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 org.codehaus.groovy.tools.groovydoc;

import org.codehaus.groovy.groovydoc.*;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SimpleGroovyClassDoc extends SimpleGroovyAbstractableElementDoc implements GroovyClassDoc {
    public static final Pattern TAG_REGEX = Pattern.compile("(?sm)\\s*@([a-zA-Z.]+)\\s+(.*?)(?=\\s+@)");
    public static final Pattern LINK_REGEX = Pattern.compile("(?m)[{]@(link)\\s+([^}]*)}");
    public static final Pattern CODE_REGEX = Pattern.compile("(?m)[{]@(code)\\s+([^}]*)}");
    public static final Pattern REF_LABEL_REGEX = Pattern.compile("([\\w.#\\$]*(\\(.*\\))?)(\\s(.*))?");
    public static final Pattern NAME_ARGS_REGEX = Pattern.compile("([^(]+)\\(([^)]*)\\)");
    public static final Pattern SPLIT_ARGS_REGEX = Pattern.compile(",\\s*");
    private static final List PRIMITIVES = Arrays.asList("void", "boolean", "byte", "short", "char", "int", "long", "float", "double");
    private static final Map TAG_TEXT = new HashMap();
    static {
        TAG_TEXT.put("see", "See Also");
        TAG_TEXT.put("param", "Parameters");
        TAG_TEXT.put("throw", "Throws");
        TAG_TEXT.put("exception", "Throws");
        TAG_TEXT.put("return", "Returns");
        TAG_TEXT.put("since", "Since");
        TAG_TEXT.put("author", "Authors");
        TAG_TEXT.put("version", "Version");
        TAG_TEXT.put("default", "Default");
    }
    private final List constructors;
    private final List fields;
    private final List properties;
    private final List enumConstants;
    private final List methods;
    private final List importedClassesAndPackages;
    private final Map aliases;
    private final List interfaceNames;
    private final List interfaceClasses;
    private final List nested;
    private final List links;
    private GroovyClassDoc superClass;
    private GroovyClassDoc outer;
    private String superClassName;
    private String fullPathName;
    private boolean isgroovy;
    private GroovyRootDoc savedRootDoc = null;

    public SimpleGroovyClassDoc(List importedClassesAndPackages, Map aliases, String name, List links) {
        super(name);
        this.importedClassesAndPackages = importedClassesAndPackages;
        this.aliases = aliases;
        this.links = links;
        constructors = new ArrayList();
        fields = new ArrayList();
        properties = new ArrayList();
        enumConstants = new ArrayList();
        methods = new ArrayList();
        interfaceNames = new ArrayList();
        interfaceClasses = new ArrayList();
        nested = new ArrayList();
    }

    public SimpleGroovyClassDoc(List importedClassesAndPackages, Map aliases, String name) {
        this(importedClassesAndPackages, aliases, name, new ArrayList());
    }

    public SimpleGroovyClassDoc(List importedClassesAndPackages, String name) {
        this(importedClassesAndPackages, new HashMap(), name, new ArrayList());
    }

    /**
     * returns a sorted array of constructors
     */
    public GroovyConstructorDoc[] constructors() {
        Collections.sort(constructors);
        return constructors.toArray(new GroovyConstructorDoc[constructors.size()]);
    }

    public boolean add(GroovyConstructorDoc constructor) {
        return constructors.add(constructor);
    }

    // TODO remove?
    public GroovyClassDoc getOuter() {
        return outer;
    }

    public void setOuter(GroovyClassDoc outer) {
        this.outer = outer;
    }

    public boolean isGroovy() {
        return isgroovy;
    }

    public void setGroovy(boolean isgroovy) {
        this.isgroovy = isgroovy;
    }

    /**
     * returns a sorted array of nested classes and interfaces
     */
    public GroovyClassDoc[] innerClasses() {
        Collections.sort(nested);
        return nested.toArray(new GroovyClassDoc[nested.size()]);
    }

    public boolean addNested(GroovyClassDoc nestedClass) {
        return nested.add(nestedClass);
    }

    /**
     * returns a sorted array of fields
     */
    public GroovyFieldDoc[] fields() {
        Collections.sort(fields);
        return fields.toArray(new GroovyFieldDoc[fields.size()]);
    }

    public boolean add(GroovyFieldDoc field) {
        return fields.add(field);
    }

    /**
     * returns a sorted array of properties
     */
    public GroovyFieldDoc[] properties() {
        Collections.sort(properties);
        return properties.toArray(new GroovyFieldDoc[properties.size()]);
    }

    public boolean addProperty(GroovyFieldDoc property) {
        return properties.add(property);
    }

    /**
     * returns a sorted array of enum constants
     */
    public GroovyFieldDoc[] enumConstants() {
        Collections.sort(enumConstants);
        return enumConstants.toArray(new GroovyFieldDoc[enumConstants.size()]);
    }

    public boolean addEnumConstant(GroovyFieldDoc field) {
        return enumConstants.add(field);
    }

    /**
     * returns a sorted array of methods
     */
    public GroovyMethodDoc[] methods() {
        Collections.sort(methods);
        return methods.toArray(new GroovyMethodDoc[methods.size()]);
    }

    public boolean add(GroovyMethodDoc method) {
        return methods.add(method);
    }

    public String getSuperClassName() {
        return superClassName;
    }

    public void setSuperClassName(String className) {
        superClassName = className;
    }

    public GroovyClassDoc superclass() {
        return superClass;
    }

    public void setSuperClass(GroovyClassDoc doc) {
        superClass = doc;
    }

    public String getFullPathName() {
        return fullPathName;
    }

    public void setFullPathName(String fullPathName) {
        this.fullPathName = fullPathName;
    }

    public String getRelativeRootPath() {
        StringTokenizer tokenizer = new StringTokenizer(fullPathName, "/"); // todo windows??
        StringBuilder sb = new StringBuilder();
        if (tokenizer.hasMoreTokens()) {
            tokenizer.nextToken(); // ignore the first token, as we want n-1 parent dirs
        }
        while (tokenizer.hasMoreTokens()) {
            tokenizer.nextToken();
            sb.append("../");
        }
        return sb.toString();
    }

    // TODO move logic here into resolve
    public List getParentClasses() {
        List result = new LinkedList();
        if (isInterface()) return result;
        result.add(0, this);
        GroovyClassDoc next = this;
        while (next.superclass() != null && !"java.lang.Object".equals(next.qualifiedTypeName())) {
            next = next.superclass();
            result.add(0, next);
        }
        GroovyClassDoc prev = next;
        Class nextClass = getClassOf(next.qualifiedTypeName());
        while (nextClass != null && nextClass.getSuperclass() != null && !Object.class.equals(nextClass)) {
            nextClass = nextClass.getSuperclass();
            GroovyClassDoc nextDoc = new ExternalGroovyClassDoc(nextClass);
            if (prev instanceof SimpleGroovyClassDoc) {
                SimpleGroovyClassDoc parent = (SimpleGroovyClassDoc) prev;
                parent.setSuperClass(nextDoc);
            }
            result.add(0, nextDoc);
            prev = nextDoc;
        }
        if (!result.get(0).qualifiedTypeName().equals("java.lang.Object")) {
            result.add(0, new ExternalGroovyClassDoc(Object.class));
        }
        return result;
    }

    public Set getParentInterfaces() {
        Set result = new HashSet();
        result.add(this);
        Set next = new HashSet();
        next.addAll(Arrays.asList(this.interfaces()));
        while (next.size() > 0) {
            Set temp = next;
            next = new HashSet();
            for (GroovyClassDoc t : temp) {
                if (t instanceof SimpleGroovyClassDoc) {
                    next.addAll(((SimpleGroovyClassDoc)t).getParentInterfaces());
                } else if (t instanceof ExternalGroovyClassDoc) {
                    ExternalGroovyClassDoc d = (ExternalGroovyClassDoc) t;
                    next.addAll(getJavaInterfaces(d));
                }
            }
            next = DefaultGroovyMethods.minus(next, result);
            result.addAll(next);
        }
        return result;
    }

    private Set getJavaInterfaces(ExternalGroovyClassDoc d) {
        Set result = new HashSet();
        Class[] interfaces = d.externalClass().getInterfaces();
        if (interfaces != null) {
            for (Class i : interfaces) {
                ExternalGroovyClassDoc doc = new ExternalGroovyClassDoc(i);
                result.add(doc);
                result.addAll(getJavaInterfaces(doc));
            }
        }
        return result;
    }

    private Class getClassOf(String next) {
        try {
            return Class.forName(next.replace("/", "."));
        } catch (Throwable t) {
            return null;
        }
    }

    void resolve(GroovyRootDoc rootDoc) {
        this.savedRootDoc = rootDoc;
        Map visibleClasses = rootDoc.getVisibleClasses(importedClassesAndPackages);

        // resolve constructor parameter types
        for (GroovyConstructorDoc constructor : constructors) {

            // parameters
            for (GroovyParameter groovyParameter : constructor.parameters()) {
                SimpleGroovyParameter param = (SimpleGroovyParameter) groovyParameter;
                String paramTypeName = param.typeName();
                if (visibleClasses.containsKey(paramTypeName)) {
                    param.setType((GroovyType) visibleClasses.get(paramTypeName));
                } else {
                    GroovyClassDoc doc = resolveClass(rootDoc, paramTypeName);
                    if (doc != null) param.setType(doc);
                }
            }
        }

        for (GroovyFieldDoc field : fields) {
            SimpleGroovyFieldDoc mutableField = (SimpleGroovyFieldDoc) field;
            GroovyType fieldType = field.type();
            String typeName = fieldType.typeName();
            if (visibleClasses.containsKey(typeName)) {
                mutableField.setType((GroovyType) visibleClasses.get(typeName));
            } else {
                GroovyClassDoc doc = resolveClass(rootDoc, typeName);
                if (doc != null) mutableField.setType(doc);
            }
        }

        // resolve method return types and parameter types
        for (GroovyMethodDoc method : methods) {

            // return types
            GroovyType returnType = method.returnType();
            String typeName = returnType.typeName();
            if (visibleClasses.containsKey(typeName)) {
                method.setReturnType((GroovyType) visibleClasses.get(typeName));
            } else {
                GroovyClassDoc doc = resolveClass(rootDoc, typeName);
                if (doc != null) method.setReturnType(doc);
            }

            // parameters
            for (GroovyParameter groovyParameter : method.parameters()) {
                SimpleGroovyParameter param = (SimpleGroovyParameter) groovyParameter;
                String paramTypeName = param.typeName();
                if (visibleClasses.containsKey(paramTypeName)) {
                    param.setType((GroovyType) visibleClasses.get(paramTypeName));
                } else {
                    GroovyClassDoc doc = resolveClass(rootDoc, paramTypeName);
                    if (doc != null) param.setType(doc);
                }
            }
        }

        // resolve property types
        for (GroovyFieldDoc property : properties)  {
            if (property instanceof SimpleGroovyFieldDoc)  {
                SimpleGroovyFieldDoc simpleGroovyFieldDoc = (SimpleGroovyFieldDoc) property;
                if (simpleGroovyFieldDoc.type() instanceof SimpleGroovyType)  {
                    SimpleGroovyType simpleGroovyType = (SimpleGroovyType) simpleGroovyFieldDoc.type();
                    GroovyClassDoc propertyTypeClassDoc = resolveClass(rootDoc, simpleGroovyType.qualifiedTypeName());
                    if (propertyTypeClassDoc != null)  {
                        simpleGroovyFieldDoc.setType(propertyTypeClassDoc);
                    }
                }
            }
        }

        if (superClassName != null && superClass == null) {
            superClass = resolveClass(rootDoc, superClassName);
        }

        for (String name : interfaceNames) {
            interfaceClasses.add(resolveClass(rootDoc, name));
        }

        for (GroovyAnnotationRef annotation : annotations()) {
            SimpleGroovyAnnotationRef ref = (SimpleGroovyAnnotationRef) annotation;
            ref.setType(resolveClass(rootDoc, ref.name()));
        }
    }

    public String getDocUrl(String type) {
        return getDocUrl(type, false);
    }

    public String getDocUrl(String type, boolean full) {
        return getDocUrl(type, full, links, getRelativeRootPath(), savedRootDoc, this);
    }

    private static String resolveMethodArgs(GroovyRootDoc rootDoc, SimpleGroovyClassDoc classDoc, String type) {
        if (!type.contains("(")) return type;
            Matcher m = NAME_ARGS_REGEX.matcher(type);
        if (m.matches()) {
            String name = m.group(1);
            String args = m.group(2);
            StringBuilder sb = new StringBuilder();
            sb.append(name);
            sb.append("(");
            String[] argParts = SPLIT_ARGS_REGEX.split(args);
            boolean first = true;
            for (String argPart : argParts) {
                if (first) first = false;
                else sb.append(", ");
                GroovyClassDoc doc = classDoc.resolveClass(rootDoc, argPart);
                sb.append(doc == null ? argPart : doc.qualifiedTypeName());
            }
            sb.append(")");
            return sb.toString();
        }
        return type;
    }

    public static String getDocUrl(String type, boolean full, List links, String relativePath, GroovyRootDoc rootDoc, SimpleGroovyClassDoc classDoc) {
        if (type == null)
            return type;
        type = type.trim();
        if (isPrimitiveType(type)) return type;
        if (type.equals("def")) type = "java.lang.Object def";

        String label = null;
        Matcher matcher = REF_LABEL_REGEX.matcher(type);
        if (matcher.find()) {
            type = matcher.group(1);
            label = matcher.group(4);
        }

        if (type.startsWith("#"))
            return "" + (label == null ? type.substring(1) : label) + "";

        if (type.endsWith("[]")) {
            if (label != null)
                return getDocUrl(type.substring(0, type.length() - 2) + " " + label, full, links, relativePath, rootDoc, classDoc);
            return getDocUrl(type.substring(0, type.length() - 2), full, links, relativePath, rootDoc, classDoc) + "[]";
        }

        if (!type.contains(".") && classDoc != null) {
            String[] pieces = type.split("#");
            String candidate = pieces[0];
            Class c = classDoc.resolveExternalClassFromImport(candidate);
            if (c != null) type = c.getName();
            if (pieces.length > 1) type += "#" + pieces[1];
            type = resolveMethodArgs(rootDoc, classDoc, type);
        }
        if (type.indexOf('.') == -1)
            return type;

        final String[] target = type.split("#");
        String shortClassName = target[0].replaceAll(".*\\.", "");
        shortClassName += (target.length > 1 ? "#" + target[1].split("\\(")[0] : "");
        String name = (full ? target[0] : shortClassName).replaceAll("#", ".").replace('$', '.');

        // last chance lookup for classes within the current codebase
        if (rootDoc != null) {
            String slashedName = target[0].replaceAll("\\.", "/");
            GroovyClassDoc doc = rootDoc.classNamed(classDoc, slashedName);
            if (doc != null) {
                return buildUrl(relativePath, target, label == null ? name : label);
            }
        }

        if (links != null) {
            for (LinkArgument link : links) {
                final StringTokenizer tokenizer = new StringTokenizer(link.getPackages(), ", ");
                while (tokenizer.hasMoreTokens()) {
                    final String token = tokenizer.nextToken();
                    if (type.startsWith(token)) {
                        return buildUrl(link.getHref(), target, label == null ? name : label);
                    }
                }
            }
        }
        return type;
    }

    private static String buildUrl(String relativeRoot, String[] target, String shortClassName) {
        if (relativeRoot.length() > 0 && !relativeRoot.endsWith("/")) {
            relativeRoot += "/";
        }
        String url = relativeRoot + target[0].replace('.', '/').replace('$', '.') + ".html" + (target.length > 1 ? "#" + target[1] : "");
        return "" + shortClassName + "";
    }

    private GroovyClassDoc resolveClass(GroovyRootDoc rootDoc, String name) {
        if (isPrimitiveType(name)) return null;
        if (name.endsWith("[]")) {
            GroovyClassDoc componentClass = resolveClass(rootDoc, name.substring(0, name.length() - 2));
            if (componentClass != null) return new ArrayClassDocWrapper(componentClass);
            return null;
        }
        if (name.equals("T") || name.equals("U") || name.equals("K") || name.equals("V") || name.equals("G")) {
            name = "java/lang/Object";
        }
        GroovyClassDoc doc = ((SimpleGroovyRootDoc)rootDoc).classNamedExact(name);
        if (doc != null) return doc;
        int slashIndex = name.lastIndexOf("/");
        if (slashIndex < 1) {
            doc = resolveInternalClassDocFromImport(rootDoc, name);
            if (doc != null) return doc;
            for (GroovyClassDoc nestedDoc : nested) {
                if (nestedDoc.name().endsWith("." + name))
                    return nestedDoc;
            }
            doc = rootDoc.classNamed(this, name);
            if (doc != null) return doc;
        }

        // The class is not in the tree being documented
        String shortname = name;
        Class c;
        if (slashIndex > 0) {
            shortname = name.substring(slashIndex + 1);
            c = resolveExternalFullyQualifiedClass(name);
        } else {
            c = resolveExternalClassFromImport(name);
        }
        if (c == null) {
            c = resolveFromJavaLang(name);
        }
        if (c != null) {
            return new ExternalGroovyClassDoc(c);
        }

        if (name.contains("/")) {
            // search for nested class
            if (slashIndex > 0) {
                String outerName = name.substring(0, slashIndex);
                GroovyClassDoc gcd = resolveClass(rootDoc, outerName);
                if (gcd instanceof ExternalGroovyClassDoc) {
                    ExternalGroovyClassDoc egcd = (ExternalGroovyClassDoc) gcd;
                    String innerName = name.substring(slashIndex+1);
                    Class outerClass = egcd.externalClass();
                    for (Class inner : outerClass.getDeclaredClasses()) {
                        if (inner.getName().equals(outerClass.getName() + "$" + innerName)) {
                            return new ExternalGroovyClassDoc(inner);
                        }
                    }
                }

                if (gcd instanceof SimpleGroovyClassDoc) {
                    String innerClassName = name.substring(slashIndex + 1);
                    SimpleGroovyClassDoc innerClass = new SimpleGroovyClassDoc(importedClassesAndPackages, aliases, innerClassName);
                    innerClass.setFullPathName(gcd.getFullPathName() + "." + innerClassName);
                    return innerClass;
                }
            }
        }

        // check if the name is actually an aliased type name
        if (hasAlias(name))  {
            String fullyQualifiedTypeName = getFullyQualifiedTypeNameForAlias(name);
            GroovyClassDoc gcd = resolveClass(rootDoc, fullyQualifiedTypeName);
            if (gcd != null) return gcd;
        }

        // and we can't find it
        SimpleGroovyClassDoc placeholder = new SimpleGroovyClassDoc(null, shortname);
        placeholder.setFullPathName(name);
        return placeholder;
    }

    private Class resolveFromJavaLang(String name) {
        try {
            return Class.forName("java.lang." + name);
        } catch (NoClassDefFoundError e) {
            // ignore
        } catch (ClassNotFoundException e) {
            // ignore
        }
        return null;
    }

    private static boolean isPrimitiveType(String name) {
        String type = name;
        if (name.endsWith("[]")) type = name.substring(0, name.length() - 2);
        return PRIMITIVES.contains(type);
    }

    private GroovyClassDoc resolveInternalClassDocFromImport(GroovyRootDoc rootDoc, String baseName) {
        if (isPrimitiveType(baseName)) return null;
        for (String importName : importedClassesAndPackages) {
            if (importName.endsWith("/" + baseName)) {
                GroovyClassDoc doc = ((SimpleGroovyRootDoc)rootDoc).classNamedExact(importName);
                if (doc != null) return doc;
            } else if (importName.endsWith("/*")) {
                GroovyClassDoc doc = ((SimpleGroovyRootDoc)rootDoc).classNamedExact(importName.substring(0, importName.length() - 2) + baseName);
                if (doc != null) return doc;
            }
        }
        return null;
    }

    private Class resolveExternalClassFromImport(String name) {
        if (isPrimitiveType(name)) return null;
        for (String importName : importedClassesAndPackages) {
            String candidate = null;
            if (importName.endsWith("/" + name)) {
                candidate = importName.replaceAll("/", ".");
            } else if (importName.endsWith("/*")) {
                candidate = importName.substring(0, importName.length() - 2).replace('/', '.') + "." + name;
            }
            if (candidate != null) {
                try {
                    // TODO cache these??
                    return Class.forName(candidate);
                } catch (NoClassDefFoundError e) {
                    // ignore
                } catch (ClassNotFoundException e) {
                    // ignore
                }
            }
        }
        return null;
    }

    private Class resolveExternalFullyQualifiedClass(String name) {
        String candidate = name.replace('/', '.');
        try {
            // TODO cache these??
            return Class.forName(candidate);
        } catch (NoClassDefFoundError e) {
            // ignore
        } catch (ClassNotFoundException e) {
            // ignore
        }
        return null;
    }

    private boolean hasAlias(String alias)  {
        return aliases.containsKey(alias);
    }

    private String getFullyQualifiedTypeNameForAlias(String alias)  {
        if (!hasAlias(alias)) return "";
        return aliases.get(alias);
    }

    // methods from GroovyClassDoc

    public GroovyConstructorDoc[] constructors(boolean filter) {/*todo*/
        return null;
    }

    public boolean definesSerializableFields() {/*todo*/
        return false;
    }

    public GroovyFieldDoc[] fields(boolean filter) {/*todo*/
        return null;
    }

    public GroovyClassDoc findClass(String className) {/*todo*/
        return null;
    }

    public GroovyClassDoc[] importedClasses() {/*todo*/
        return null;
    }

    public GroovyPackageDoc[] importedPackages() {/*todo*/
        return null;
    }

    public GroovyClassDoc[] innerClasses(boolean filter) {/*todo*/
        return null;
    }

    public GroovyClassDoc[] interfaces() {
        Collections.sort(interfaceClasses);
        return interfaceClasses.toArray(new GroovyClassDoc[interfaceClasses.size()]);
    }

    public GroovyType[] interfaceTypes() {/*todo*/
        return null;
    }

    public boolean isExternalizable() {/*todo*/
        return false;
    }

    public boolean isSerializable() {/*todo*/
        return false;
    }

    public GroovyMethodDoc[] methods(boolean filter) {/*todo*/
        return null;
    }

    public GroovyFieldDoc[] serializableFields() {/*todo*/
        return null;
    }

    public GroovyMethodDoc[] serializationMethods() {/*todo*/
        return null;
    }

    public boolean subclassOf(GroovyClassDoc gcd) {/*todo*/
        return false;
    }

    public GroovyType superclassType() {/*todo*/
        return null;
    }
//    public GroovyTypeVariable[] typeParameters() {/*todo*/return null;} // not supported in groovy
//    public GroovyParamTag[] typeParamTags() {/*todo*/return null;} // not supported in groovy


    // methods from GroovyType (todo: remove this horrible copy of SimpleGroovyType.java)
//    public GroovyAnnotationTypeDoc asAnnotationTypeDoc() {/*todo*/return null;}
//    public GroovyClassDoc asClassDoc() {/*todo*/ return null; }
//    public GroovyParameterizedType asParameterizedType() {/*todo*/return null;}
//    public GroovyTypeVariable asTypeVariable() {/*todo*/return null;}
//    public GroovyWildcardType asWildcardType() {/*todo*/return null;}
//    public String dimension() {/*todo*/ return null; }

    public boolean isPrimitive() {/*todo*/
        return false;
    }

    public String qualifiedTypeName() {
        String qtnWithSlashes = fullPathName.startsWith("DefaultPackage/") ? fullPathName.substring("DefaultPackage/".length()) : fullPathName;
        return qtnWithSlashes.replace('/', '.');
    }

    // TODO remove dupe with SimpleGroovyType
    public String simpleTypeName() {
        String typeName = qualifiedTypeName();
        int lastDot = typeName.lastIndexOf('.');
        if (lastDot < 0) return typeName;
        return typeName.substring(lastDot + 1);
    }

    public String typeName() {/*todo*/
        return null;
    }

    public void addInterfaceName(String className) {
        interfaceNames.add(className);
    }

    public String firstSentenceCommentText() {
        if (super.firstSentenceCommentText() == null)
            setFirstSentenceCommentText(replaceTags(calculateFirstSentence(getRawCommentText())));
        return super.firstSentenceCommentText();
    }

    public String commentText() {
        if (super.commentText() == null)
            setCommentText(replaceTags(getRawCommentText()));
        return super.commentText();
    }

    public String replaceTags(String comment) {
        String result = comment.replaceAll("(?m)^\\s*\\*", ""); // todo precompile regex

        // {@link processing hack}
        result = replaceAllTags(result, "", "", LINK_REGEX);

        // {@code processing hack}
        result = replaceAllTags(result, "", "", CODE_REGEX);

        // hack to reformat other groovydoc block tags (@see, @return, @param, @throws, @author, @since) into html
        result = replaceAllTagsCollated(result, "
", ":
", "
", "
", TAG_REGEX); return decodeSpecialSymbols(result); } public String replaceAllTags(String self, String s1, String s2, Pattern regex) { return replaceAllTags(self, s1, s2, regex, links, getRelativeRootPath(), savedRootDoc, this); } // TODO: this should go away once we have proper tags public static String replaceAllTags(String self, String s1, String s2, Pattern regex, List links, String relPath, GroovyRootDoc rootDoc, SimpleGroovyClassDoc classDoc) { Matcher matcher = regex.matcher(self); if (matcher.find()) { matcher.reset(); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String tagname = matcher.group(1); if (!"interface".equals(tagname)) { String content = encodeSpecialSymbols(matcher.group(2)); if ("link".equals(tagname) || "see".equals(tagname)) { content = getDocUrl(content, false, links, relPath, rootDoc, classDoc); } matcher.appendReplacement(sb, s1 + content + s2); } } matcher.appendTail(sb); return sb.toString(); } else { return self; } } // TODO: is there a better way to do this? public String replaceAllTagsCollated(String self, String preKey, String postKey, String valueSeparator, String postValues, Pattern regex) { Matcher matcher = regex.matcher(self + "@endMarker"); if (matcher.find()) { matcher.reset(); Map> savedTags = new HashMap>(); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String tagname = matcher.group(1); if (!"interface".equals(tagname)) { String content = encodeSpecialSymbols(matcher.group(2)); if ("see".equals(tagname) || "link".equals(tagname)) { content = getDocUrl(content); } else if ("param".equals(tagname)) { int index = content.indexOf(" "); if (index >= 0) { content = "" + content.substring(0, index) + " - " + content.substring(index); } } if (TAG_TEXT.containsKey(tagname)) { String text = TAG_TEXT.get(tagname); List contents = savedTags.get(text); if (contents == null) { contents = new ArrayList(); savedTags.put(text, contents); } contents.add(content); matcher.appendReplacement(sb, ""); } else { matcher.appendReplacement(sb, preKey + tagname + postKey + content + postValues); } } } matcher.appendTail(sb); // remove @endMarker sb = new StringBuffer(sb.substring(0, sb.length() - 10)); for (Map.Entry> e : savedTags.entrySet()) { sb.append(preKey); sb.append(e.getKey()); sb.append(postKey); sb.append(DefaultGroovyMethods.join(e.getValue(), valueSeparator)); sb.append(postValues); } return sb.toString(); } else { return self; } } public static String encodeSpecialSymbols(String text) { return Matcher.quoteReplacement(text.replaceAll("@", "&at;")); } public static String decodeSpecialSymbols(String text) { return text.replaceAll("&at;", "@"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy