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

com.redhat.ceylon.ceylondoc.IndexDoc Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * Copyright Red Hat Inc. and/or its affiliates and other contributors
 * as indicated by the authors tag. All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License version 2.
 * 
 * This particular file is subject to the "Classpath" exception as provided in the 
 * LICENSE file that accompanied this code.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * 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 distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */

package com.redhat.ceylon.ceylondoc;

import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import com.redhat.ceylon.compiler.java.codegen.Decl;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.AttributeDeclaration;
import com.redhat.ceylon.model.typechecker.model.Class;
import com.redhat.ceylon.model.typechecker.model.ClassOrInterface;
import com.redhat.ceylon.model.typechecker.model.Constructor;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Interface;
import com.redhat.ceylon.model.typechecker.model.Function;
import com.redhat.ceylon.model.typechecker.model.FunctionOrValue;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.model.typechecker.model.Package;
import com.redhat.ceylon.model.typechecker.model.Scope;
import com.redhat.ceylon.model.typechecker.model.Setter;
import com.redhat.ceylon.model.typechecker.model.TypeAlias;
import com.redhat.ceylon.model.typechecker.model.TypeParameter;
import com.redhat.ceylon.model.typechecker.model.Value;

public class IndexDoc extends CeylonDoc {

    private Module module;
    private Set tagIndex = new TreeSet();

    public IndexDoc(CeylonDocTool tool, Writer writer, Module module) throws IOException {
        super(module, tool, writer);
        this.module = module;
    }
    
    public void generate() throws IOException {
        write("var index = [\n");
        indexPackages();
        write("];\n");
        writeTagIndex();
    }

    private void writeTagIndex() throws IOException {
        write("var tagIndex = [\n");
        Iterator tagIterator = tagIndex.iterator();
        while (tagIterator.hasNext()) {
            write("'");
            write(escapeJSONString(tagIterator.next()));
            write("'");
            if (tagIterator.hasNext()) {
                write(",\n");
            }
        }
        write("];\n");
    }

    private void indexPackages() throws IOException {
        for (Package pkg : tool.getPackages(module)) {
            indexPackage(pkg);
        }
        // get rid of the eventual final dangling JSON list comma but adding a module entry 
        writeIndexElement(
                module.getNameAsString(), 
                getType(module), 
                linkRenderer().to(module).getUrl(), 
                Util.getDocFirstLine(module, linkRenderer()), 
                Util.getTags(module), 
                getIcons(module), 
                null);
    }

    private void indexPackage(Package pkg) throws IOException {
        writeIndexElement(
                pkg.getNameAsString(), 
                getType(pkg), 
                linkRenderer().to(pkg).getUrl(), 
                Util.getDocFirstLine(pkg, linkRenderer()), 
                Util.getTags(pkg), 
                getIcons(pkg),
                null);
        write(",\n");
        indexMembers(pkg, pkg.getMembers());
        
        List tags = Util.getTags(pkg);
        tagIndex.addAll(tags);
    }

    private void indexMembers(Scope container, List members) throws IOException {
        for (Declaration decl : members) {
            if (!tool.shouldInclude(decl)) {
                continue;
            }
            if (decl instanceof ClassOrInterface) {
                ClassOrInterface classOrInterface = (ClassOrInterface) decl;
                indexMembers(classOrInterface, classOrInterface.getMembers());
            }
            if (indexDecl(container, decl)) {
                write(",\n");
            }
        }
    }

    private boolean indexDecl(Scope container, Declaration decl) throws IOException {
        String url;
        String name = Util.getDeclarationName(decl);
        String qualifier = "";
        
        if (decl instanceof ClassOrInterface) {
            url = linkRenderer().to(decl).getUrl();
        } else if ((decl instanceof FunctionOrValue
                    && decl instanceof Setter == false
                    && !((FunctionOrValue)decl).isParameter()) 
                || decl instanceof TypeAlias
                || decl instanceof Constructor) {
            url = tool.getObjectUrl(module, container, false) + "#" + name;
            if (decl.isMember()) {
                qualifier = ((ClassOrInterface) container).getName() + ".";
                name = qualifier + name;
            }
        } else if (decl instanceof Setter
                || (decl instanceof FunctionOrValue && ((FunctionOrValue)decl).isParameter())
                || decl instanceof TypeParameter) {
            return false; // ignore
        } else {
            throw new RuntimeException("Unknown type of object: " + decl);
        }
        
        String type = getType(decl);
        String doc = Util.getDocFirstLine(decl, linkRenderer());
        List tags = Util.getTags(decl);
        tagIndex.addAll(tags);
        
        writeIndexElement(name, type, url, doc, tags, getIcons(decl), null);
        for(String alias : decl.getAliases()){
            write(",\n");
            writeIndexElement(qualifier+alias, type, url, doc, tags, getIcons(decl), name);
        }
        
        return true;
    }

    private void writeIndexElement(String name, String type, String url, String doc, List tags, List icons, String aliasFor) throws IOException {
        write("{'name': '");
        write(name);
        write("', 'type': '");
        write(type);
        write("', 'url': '");
        write(url);
        write("', 'doc': '");
        write(escapeJSONString(doc).trim());
        write("', 'tags': [");
        if( tags != null ) {
            Iterator tagIterator = tags.iterator();
            while (tagIterator.hasNext()) {
                write("'");
                write(escapeJSONString(tagIterator.next()).trim());
                write("'");
                if (tagIterator.hasNext()) {
                    write(", ");
                }
            }        
        }
        write("],");
        write("'icons': [");
        if( icons != null ) {
            Iterator iconIterator = icons.iterator();
            while (iconIterator.hasNext()) {
                write("'");
                write(escapeJSONString(iconIterator.next()).trim());
                write("'");
                if (iconIterator.hasNext()) {
                    write(", ");
                }
            }        
        }
        write("]");
        if(aliasFor != null){
            write(", 'aliasFor': '");
            write(aliasFor);
            write("'");
        }
        write("}");
    }

    private String escapeJSONString(String doc) {
        if(doc == null)
            return "";
        char[] chars = doc.toCharArray();
        // assume worst case size
        StringBuffer escaped = new StringBuffer(chars.length * 2);
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if(c == '\n')
                escaped.append("\\n");
            else if(c == '\'')
                escaped.append("\\'");
            else if(c == '\\')
                escaped.append("\\\\");
            else
                escaped.append(c);
        }
        return escaped.toString();
    }
    
    private String getType(Object obj) {
        if (obj instanceof Class) {
            return !((Class) obj).isAnonymous() ? "class" : "object";
        } else if (obj instanceof Interface) {
            return "interface";
        } else if (obj instanceof TypeAlias) {
            return "alias";
        } else if (obj instanceof AttributeDeclaration || (obj instanceof Declaration && Decl.isGetter((Declaration)obj))) {
            return "attribute";
        } else if (obj instanceof Function) {
            return "function";
        } else if (obj instanceof Value) {
            return "value";
        } else if (obj instanceof Package) {
            return "package";
        } else if (obj instanceof Module) {
            return "module";
        } else if (obj instanceof Constructor) {
            return "constructor";
        }
        throw new RuntimeException(CeylondMessages.msg("error.unexpected", obj));
    }
    
    @Override
    protected Object getFromObject() {
        return module;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy