Repository: tapestry-5
Updated Branches:
  refs/heads/master c44abfd6a -> fd3c9e6b7


TAP5-2266: extend support for HTML content inside parameter JavaDoc


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/bb309644
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/bb309644
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/bb309644

Branch: refs/heads/master
Commit: bb3096442155f68a69cee0b709717c09287bdea9
Parents: c44abfd
Author: Jochen Kemnade <jkemn...@apache.org>
Authored: Sat May 17 13:57:30 2014 +0200
Committer: Jochen Kemnade <jkemn...@apache.org>
Committed: Sat May 17 14:05:30 2014 +0200

----------------------------------------------------------------------
 .../tapestry5/corelib/components/DevTool.java   |   2 +-
 tapestry-javadoc/build.gradle                   |   3 +
 .../tapestry5/javadoc/ParameterDescription.java |  55 ++++++--
 .../javadoc/ParameterDescriptionSpec.groovy     | 125 +++++++++++++++++++
 4 files changed, 172 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb309644/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DevTool.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DevTool.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DevTool.java
index 320e1cd..0954e66 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DevTool.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/DevTool.java
@@ -58,7 +58,7 @@ public class DevTool
 
     /**
      * If true, then the DevTool modifies its markup so as to work within a 
Bootstrap 3 NavBar. This renders
-     * the component as an {@code <li>} (instead of a {@code <div>}), and 
removes the "btn" CSS classes.
+     * the component as a {@code <li>} (instead of a {@code <div>}), and 
removes the "btn" CSS classes.
      */
     @Parameter
     private boolean navbar;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb309644/tapestry-javadoc/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-javadoc/build.gradle b/tapestry-javadoc/build.gradle
index 032114a..efc6f9d 100644
--- a/tapestry-javadoc/build.gradle
+++ b/tapestry-javadoc/build.gradle
@@ -4,6 +4,9 @@ dependencies {
   compile project(':tapestry-core')
   compile "commons-lang:commons-lang:2.6"
   compile files(getTools())
+  
+  testCompile "org.spockframework:spock-core:${versions.spock}"
+  
 }
 
 /** Returns the tools.jar/classes.jar of the Java runtime. */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb309644/tapestry-javadoc/src/main/java/org/apache/tapestry5/javadoc/ParameterDescription.java
----------------------------------------------------------------------
diff --git 
a/tapestry-javadoc/src/main/java/org/apache/tapestry5/javadoc/ParameterDescription.java
 
b/tapestry-javadoc/src/main/java/org/apache/tapestry5/javadoc/ParameterDescription.java
index a60f8a7..ff8bc11 100644
--- 
a/tapestry-javadoc/src/main/java/org/apache/tapestry5/javadoc/ParameterDescription.java
+++ 
b/tapestry-javadoc/src/main/java/org/apache/tapestry5/javadoc/ParameterDescription.java
@@ -14,14 +14,18 @@
 
 package org.apache.tapestry5.javadoc;
 
-import com.sun.javadoc.FieldDoc;
-import com.sun.javadoc.SeeTag;
-import com.sun.javadoc.Tag;
-
 import java.io.IOException;
+import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.SeeTag;
+import com.sun.javadoc.Tag;
 
 public class ParameterDescription
 {
@@ -45,10 +49,12 @@ public class ParameterDescription
 
     public final boolean deprecated;
 
-    private static final Pattern STRIPPER = Pattern.compile("(<.*?>|&.*?;)", 
Pattern.DOTALL);
+    private static final Pattern SPECIAL_CONTENT = 
Pattern.compile("(?:</?(\\p{Alpha}+)>)|(?:&\\p{Alpha}+;)");
+    private static final Set<String> PASS_THROUGH_TAGS = 
CollectionFactory.newSet("b", "em", "i", "code", "strong");
 
-    public ParameterDescription(FieldDoc fieldDoc, String name, String type, 
String defaultValue, String defaultPrefix,
-                                boolean required, boolean allowNull, boolean 
cache, String since, boolean deprecated)
+
+    public ParameterDescription(final FieldDoc fieldDoc, final String name, 
final String type, final String defaultValue, final String defaultPrefix,
+            final boolean required, final boolean allowNull, final boolean 
cache, final String since, final boolean deprecated)
     {
         this.field = fieldDoc;
         this.name = name;
@@ -76,7 +82,7 @@ public class ParameterDescription
         {
             if (tag.name().equals("Text"))
             {
-                builder.append(tag.text());
+                appendContentSafe(builder, tag.text());
                 continue;
             }
 
@@ -87,17 +93,17 @@ public class ParameterDescription
                 String label = seeTag.label();
                 if (label != null && !label.equals(""))
                 {
-                    builder.append(label);
+                    builder.append(StringEscapeUtils.escapeHtml(label));
                     continue;
                 }
 
                 if (seeTag.referencedClassName() != null)
-                    builder.append(seeTag.referencedClassName());
+                    
builder.append(StringEscapeUtils.escapeHtml(seeTag.referencedClassName()));
 
                 if (seeTag.referencedMemberName() != null)
                 {
                     builder.append("#");
-                    builder.append(seeTag.referencedMemberName());
+                    
builder.append(StringEscapeUtils.escapeHtml(seeTag.referencedMemberName()));
                 }
             }
             else if (tag.name().equals("@code"))
@@ -114,6 +120,31 @@ public class ParameterDescription
 
         // Remove any simple open or close tags found in the text, as well as 
any XML entities.
 
-        return STRIPPER.matcher(text).replaceAll("").trim();
+        return text.trim();
+    }
+
+    private static void appendContentSafe(final StringBuilder sb, final String 
string){
+        Matcher m = SPECIAL_CONTENT.matcher(string);
+        int index = 0;
+        while (index < string.length()){
+            boolean match = m.find(index);
+            if (match){
+                if (index != m.start()){
+                    
sb.append(StringEscapeUtils.escapeHtml(string.substring(index, m.start())));
+                }
+                String tagName = m.group(1);
+                if (tagName!= null){
+                    
if(PASS_THROUGH_TAGS.contains(tagName.toLowerCase(Locale.US))){
+                        sb.append(m.group());
+                    }
+                }else{
+                    sb.append(m.group());
+                }
+                index = m.end();
+            }else{
+                
sb.append(StringEscapeUtils.escapeHtml(string.substring(index)));
+                break;
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bb309644/tapestry-javadoc/src/test/groovy/org/apache/tapestry5/javadoc/ParameterDescriptionSpec.groovy
----------------------------------------------------------------------
diff --git 
a/tapestry-javadoc/src/test/groovy/org/apache/tapestry5/javadoc/ParameterDescriptionSpec.groovy
 
b/tapestry-javadoc/src/test/groovy/org/apache/tapestry5/javadoc/ParameterDescriptionSpec.groovy
new file mode 100644
index 0000000..008d1b1
--- /dev/null
+++ 
b/tapestry-javadoc/src/test/groovy/org/apache/tapestry5/javadoc/ParameterDescriptionSpec.groovy
@@ -0,0 +1,125 @@
+package org.apache.tapestry5.javadoc
+
+import spock.lang.Specification
+
+import com.sun.javadoc.FieldDoc
+import com.sun.tools.doclets.internal.toolkit.util.TextTag
+import com.sun.tools.javadoc.TagImpl
+
+
+class ParameterDescriptionSpec extends Specification {
+
+       def "Parameter description without embedded tags is passed through"(){
+               setup:
+               FieldDoc fieldDoc = Mock()
+               def inlineTags = [
+                       new TextTag(null, "Plain text")
+               ]
+               ParameterDescription parameterDescription = new 
ParameterDescription(fieldDoc, "parameter", "String", "value", "literal", 
false, true, false, "1", false)
+               when:
+               def extracted = parameterDescription.extractDescription()
+               then:
+               1 * fieldDoc.inlineTags() >> inlineTags
+               extracted == "Plain text"
+       }
+
+       def "Embedded code tags are turned into HTML <code> elements"(){
+               setup:
+               FieldDoc fieldDoc = Mock()
+               def inlineTags = [
+                       new TagImpl(null, "@code", "blah")
+               ]
+               ParameterDescription parameterDescription = new 
ParameterDescription(fieldDoc, "parameter", "String", "value", "literal", 
false, true, false, "1", false)
+               when:
+               def extracted = parameterDescription.extractDescription()
+               then:
+               1 * fieldDoc.inlineTags() >> inlineTags
+               extracted == "<code>blah</code>"
+       }
+
+       // TAP5-2266
+       def "HTML in embedded code tags is escaped"(){
+               setup:
+               FieldDoc fieldDoc = Mock()
+               def inlineTags = [
+                       new TextTag(null, "This renders the component as a "),
+                       new TagImpl(null, "@code", "<li>"),
+                       new TextTag(null, " (instead of a "),
+                       new TagImpl(null, "@code", "<div>"),
+                       new TextTag(null, ")")
+               ]
+               ParameterDescription parameterDescription = new 
ParameterDescription(fieldDoc, "parameter", "String", "value", "literal", 
false, true, false, "1", false)
+               when:
+               def extracted = parameterDescription.extractDescription()
+               then:
+               1 * fieldDoc.inlineTags() >> inlineTags
+               extracted == "This renders the component as a 
<code>&lt;li&gt;</code> (instead of a <code>&lt;div&gt;</code>)"
+       }
+
+
+       def "Characters with special meaning are escaped"(){
+               setup:
+               FieldDoc fieldDoc = Mock()
+               def inlineTags = [
+                       new TextTag(null, "Javadoc with < character")
+               ]
+               ParameterDescription parameterDescription = new 
ParameterDescription(fieldDoc, "parameter", "String", "value", "literal", 
false, true, false, "1", false)
+               when:
+               def extracted = parameterDescription.extractDescription()
+               then:
+               1 * fieldDoc.inlineTags() >> inlineTags
+               extracted == "Javadoc with &lt; character"
+       }
+
+       def "Entities in Javadoc are left alone"(){
+               setup:
+               FieldDoc fieldDoc = Mock()
+               def inlineTags = [
+                       new TextTag(null, "Text &amp; entity")
+               ]
+               ParameterDescription parameterDescription = new 
ParameterDescription(fieldDoc, "parameter", "String", "value", "literal", 
false, true, false, "1", false)
+               when:
+               def extracted = parameterDescription.extractDescription()
+               then:
+               1 * fieldDoc.inlineTags() >> inlineTags
+               extracted == "Text &amp; entity"
+       }
+
+       def "Un-safe tags in Javadoc are removed"(){
+               setup:
+               FieldDoc fieldDoc = Mock()
+               def inlineTags = [
+                       new TextTag(null, "We don't <br>want new lines or</td> 
table stuff")
+               ]
+               ParameterDescription parameterDescription = new 
ParameterDescription(fieldDoc, "parameter", "String", "value", "literal", 
false, true, false, "1", false)
+               when:
+               def extracted = parameterDescription.extractDescription()
+               then:
+               1 * fieldDoc.inlineTags() >> inlineTags
+               extracted == "We don't want new lines or table stuff"
+       }
+
+       def "#src in Javadoc becomes #target in HTML"(){
+               setup:
+               FieldDoc fieldDoc = Mock()
+               def inlineTags = [
+                       new TextTag(null, src)
+               ]
+               ParameterDescription parameterDescription = new 
ParameterDescription(fieldDoc, "parameter", "String", "value", "literal", 
false, true, false, "1", false)
+               when:
+               def extracted = parameterDescription.extractDescription()
+               then:
+               1 * fieldDoc.inlineTags() >> inlineTags
+               extracted == target
+               where:
+               src     | target
+               "&"     | "&amp;"
+               "&amp;" | "&amp;"
+               "<"     | "&lt;"
+               "<b>"   | "<b>"
+
+       }
+
+
+
+}

Reply via email to