7/13/12

PMD and CPD for ECMAScript (Javascript)

Recently I have tried to use PMD and CPD for Javascript. I found that the offical PMD release says PMD 5.0.0 supports Javascript :D
We have strong code inspection tools like Sonar etc. But I think still helpful for setting up compact ant task.

PMD

PMD ant task setup for javascript is easy, almost same as Java. Only you have to remember is including rhino jar in the classpath.
Here is the example.
 
 <property name="buildscripts.path" location="${basedir}/generic-buildscripts"/>
  <property name="pmd.jar" value="pmd-5.0.0.jar"/>
  <property location="rhino-1.7R3.jar" name="rhino.jar"/>

  
  <path id="pmd.classpath">
      
      <fileset dir="${buildscripts.path}/pmd/">
          
          <include name="asm-3.2.jar">
          <include name="jaxen-1.1.1.jar">
          <include name="${pmd.jar}">
          <include path="${rhino.jar}">
      </fileset>
  </path>

  <taskdef classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath" name="pmd">

  <macrodef name="pmd-javascript">
    <attribute name="src.dir.id">
    <attribute name="output.xml.file">
    <sequential>
      <pmd shortfilenames="true">
        
        <ruleset>rulesets/ecmascript/basic.xml</ruleset>
        <ruleset>rulesets/ecmascript/braces.xml</ruleset>
        <ruleset>rulesets/ecmascript/unnecessary.xml</ruleset>
        <formatter tofile="@{output.xml.file}" type="xml">
        <fileset refid="@{src.dir.id}">
      </pmd>
    </sequential>
  </macrodef>

You can use above macro as below:
<fileset dir="directory for javascripts" id="target.src">
  <include name="**/*.js">
</fileset>

<pmd-javascript output.xml.file="somewhere.xml" src.dir.id="target.src" />
That's it! Quite easy eh?

CPD

The problematic setup is CPD. I have just setup CPD ant task for javascript same as Java. e.g. simply set "ecmascript" in language attribute. However ant complained the ecmascript was unsupported >_<
CPD itself supports ecmascript according to the PMD source code. So I wrote ant script which calls CPD from command line. (maybe I should contribute or report PMD project and fix the ant task source though).
java -cp  net.sourceforge.pmd.cpd.CPD --files /src/dir --minimum-tokes 50 --language ecmascript --encoding utf-8 --format xml
Below is ant macro I wrote.
  <property name="pmd.jar.path" location="${buildscripts.path}/pmd/${pmd.jar}"/>
  <property name="cpd.javascript.minimum.tokens" value="100"/>

  <macrodef name="cpd-javascript">
    <attribute name="target.src.dir">
    <attribute name="outoput.xml.file">
    <!-- you can eliminate this attribute if you are not care of result -->
    <attribute name="cpd.javascript.error">
    <sequential>
      <java 
       classname="net.sourceforge.pmd.cpd.CPD" 
       classpath="${pmd.jar.path}" 
       errorproperty="@{cpd.javascript.error}" 
       fork="true" 
       output="${pmd.javascript.report.dir}/@{outoput.xml.file}" resultproperty="${cpd.javascript.result}">
        <arg value="--files">
        <arg value="@{target.src.dir}">
        <arg line="--minimum-tokens ${cpd.javascript.minimum.tokens}">
        <arg line="--encoding utf-8">
        <arg line="--language ecmascript">
        <arg line="--format xml">
      </java>
      <!-- Added this part in order to always output valid xml cpd report. 
      If there is no duplication code, CPD outputs empty string (file). 
      This behaviour is okay but invalid for xml format stands point. -->
      <if>
        <length>
        <then>
          <echoxml file="@{outoput.xml.file}">
            <pmd-cpd>
          </echoxml>
        </then>
      </if>
    </sequential>
  </macrodef>
You can use my ant macro as below:
<fileset dir="directory for javascripts" id="target.src">
  <include name="**/*.js">
</fileset>

<cpd-javascript output.xml.file="somewhere.xml" src.dir.id="target.src" />
Phew!! I have confirmed it worked perfect for me.... Hope these infomation helps!!

No comments :