001/*
002 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025package org.jdrupes.mdoclet.internal.doclets.toolkit.util;
026
027
028import java.util.List;
029import java.util.Locale;
030import java.util.function.Consumer;
031
032import com.sun.source.doctree.AttributeTree;
033import com.sun.source.doctree.DocCommentTree;
034import com.sun.source.doctree.DocTree;
035import com.sun.source.doctree.DocTree.Kind;
036import com.sun.source.doctree.StartElementTree;
037import com.sun.source.util.DocTreePath;
038import com.sun.source.util.DocTreePathScanner;
039import com.sun.source.util.TreePath;
040import com.sun.tools.javac.util.DefinedBy;
041import com.sun.tools.javac.util.DefinedBy.Api;
042
043/**
044 * A DocTree scanner to detect use of JavaScript in a doc comment tree.
045 */
046public class JavaScriptScanner extends DocTreePathScanner<Void, Consumer<DocTreePath>> {
047
048    public Void scan(DocCommentTree tree, TreePath p, Consumer<DocTreePath> f) {
049        return scan(new DocTreePath(p, tree), f);
050    }
051
052    @Override @DefinedBy(Api.COMPILER_TREE)
053    public Void visitStartElement(StartElementTree tree, Consumer<DocTreePath> f) {
054        String name = tree.getName().toString();
055        if (name.equalsIgnoreCase("script"))
056            f.accept(getCurrentPath());
057        return super.visitStartElement(tree, f);
058    }
059
060    @Override @DefinedBy(Api.COMPILER_TREE)
061    public Void visitAttribute(AttributeTree tree, Consumer<DocTreePath> f) {
062        String name = tree.getName().toString().toLowerCase(Locale.ENGLISH);
063        switch (name) {
064            // See https://www.w3.org/TR/html4/sgml/dtd.html
065            //     https://www.w3.org/TR/html52/fullindex.html#attributes-table
066            // These are all the attributes that take a %URI or a valid URL potentially surrounded
067            // by spaces
068            case "action":  case "cite":  case "classid":  case "codebase":  case "data":
069            case "datasrc":  case "for":  case "href":  case "longdesc":  case "profile":
070            case "src":  case "usemap":
071                List<? extends DocTree> value = tree.getValue();
072                if (value != null && !value.isEmpty() && value.get(0).getKind() == Kind.TEXT) {
073                    String v = value.get(0).toString().trim().toLowerCase(Locale.ENGLISH);
074                    if (v.startsWith("javascript:")) {
075                        f.accept(getCurrentPath());
076                    }
077                }
078                break;
079            // See https://www.w3.org/TR/html52/webappapis.html#events-event-handlers
080            // An event handler has a name, which always starts with "on" and is followed by
081            // the name of the event for which it is intended.
082            default:
083                if (name.startsWith("on")) {
084                    f.accept(getCurrentPath());
085                }
086                break;
087        }
088        return super.visitAttribute(tree, f);
089    }
090
091    /**
092     * Used to indicate a fault when parsing, typically used in
093     * lambda methods.
094     */
095    public static class Fault extends RuntimeException {
096        private static final long serialVersionUID = 0L;
097    }
098}