<?xml version="1.0"?>

<ruleset name="Basic Ecmascript"
	xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">

	<description>Rules concerning basic ECMAScript guidelines.</description>

    <rule name="AssignmentInOperand"
      language="ecmascript"
      since="5.0"
      message="Avoid assignments in operands"
      class="net.sourceforge.pmd.lang.rule.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/ecmascript/basic.html#AssignmentInOperand">
<description>
Avoid assignments in operands; this can make code more complicated and harder to read.  This is sometime
indicative of the bug where the assignment operator '=' was used instead of the equality operator '=='.
  </description>
    <priority>2</priority>
    <properties>
       <property name="xpath">
          <value>
 <![CDATA[
	//IfStatement[$allowIf = "false"]/child::node()[1]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = "false" and (@Image = "--" or @Image = "++")]]
|
	//WhileLoop[$allowWhile = "false"]/child::node()[1]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = "false" and (@Image = "--" or @Image = "++")]]
|
	//DoLoop[$allowWhile = "false"]/child::node()[2]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = "false" and (@Image = "--" or @Image = "++")]]
|
	//ForLoop[$allowFor = "false"]/child::node()[2]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = "false" and (@Image = "--" or @Image = "++")]]
|
   //ConditionalExpression[$allowTernary = "false"]/child::node()[1]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = "false" and (@Image = "--" or @Image = "++")]]
|
   //ConditionalExpression[$allowTernaryResults = "false"]/child::node()[position() = 2 or position() = 3]/descendant-or-self::node()[self::Assignment or self::UnaryExpression[$allowIncrementDecrement = "false" and (@Image = "--" or @Image = "++")]]
]]>
          </value>
       </property>
       <property name="allowIf" type="Boolean" value="false" description="Allow assignment within the conditional expression of an if statement" />
       <property name="allowFor" type="Boolean" value="false" description="Allow assignment within the conditional expression of a for statement" />
       <property name="allowWhile" type="Boolean" value="false" description="Allow assignment within the conditional expression of a while statement" />
       <property name="allowTernary" type="Boolean" value="false" description="Allow assignment within the conditional expression of a ternary operator" />
       <property name="allowTernaryResults" type="Boolean" value="false" description="Allow assignment within the result expressions of a ternary operator" />
       <property name="allowIncrementDecrement" type="Boolean" value="false" description="Allow increment or decrement operators within the conditional expression of an if, for, or while statement" />
    </properties>
  <example>
  <![CDATA[
var x = 2;
// Bad
if ((x = getX()) == 3) {
   alert('3!');
}

function getX() {
  return 3;
}
  ]]>
  </example>
</rule>

    <rule name="UnreachableCode"
    		 language="ecmascript"
    		  since="5.0"
       message="A ''return'', ''break'', ''continue'', or ''throw'' statement should be the last in a block."
          class="net.sourceforge.pmd.lang.rule.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/ecmascript/basic.html#UnreachableCode">
      <description>
A 'return', 'break', 'continue', or 'throw' statement should be the last in a block. Statements after these
will never execute.  This is a bug, or extremely poor style.
      </description>
      <priority>1</priority>
        <properties>
            <property name="xpath">
                <value>
 <![CDATA[
	//ReturnStatement[following-sibling::node()]
|
	//ContinueStatement[following-sibling::node()]
|
	//BreakStatement[following-sibling::node()]
|
	//ThrowStatement[following-sibling::node()]
]]>
                </value>
            </property>
        </properties>
      <example>
  <![CDATA[
// Ok
function foo() {
   return 1;
}
// Bad
function bar() {
   var x = 1;
   return x;
   x = 2;
}
]]>
      </example>
    </rule>

    <rule name="InnaccurateNumericLiteral"
    		 language="ecmascript"
    		  since="5.0"
       message="The numeric literal ''{0}'' will have at different value at runtime."
          class="net.sourceforge.pmd.lang.rule.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/ecmascript/basic.html#InnaccurateNumericLiteral">
      <description>
The numeric literal will have at different value at runtime, which can happen if you provide too much
precision in a floating point number.  This may result in numeric calculations being in error.
      </description>
      <priority>2</priority>
        <properties>
            <property name="xpath">
                <value>
 <![CDATA[
//NumberLiteral[
	@Image != @Number
	and translate(@Image, "e", "E") != @Number
	and concat(@Image, ".0") != @Number
	and @Image != substring-before(translate(@Number, ".", ""), "E")]
]]>
                </value>
            </property>
        </properties>
      <example>
  <![CDATA[
var a = 9; // Ok
var b = 999999999999999; // Ok
var c = 999999999999999999999; // Not good
var w = 1.12e-4; // Ok
var x = 1.12; // Ok
var y = 1.1234567890123; // Ok
var z = 1.12345678901234567; // Not good
]]>
      </example>
    </rule>

    <rule name="ConsistentReturn"
    		  since="5.0"
       message="A function should not mix 'return' statements with and without a result."
          class="net.sourceforge.pmd.lang.ecmascript.rule.basic.ConsistentReturnRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/ecmascript/basic.html#ConsistentReturn">
      <description>
ECMAScript does provide for return types on functions, and therefore there is no solid rule as to their usage.
However, when a function does use returns they should all have a value, or all with no value.  Mixed return
usage is likely a bug, or at best poor style.
      </description>
      <priority>2</priority>
      <example>
  <![CDATA[
// Ok
function foo() {
   if (condition1) {
      return true;
   }
   return false;
}

// Bad
function bar() {
   if (condition1) {
      return;
   }
   return false;
}
]]>
      </example>
    </rule>

    <rule name="ScopeForInVariable"
          language="ecmascript"
          since="5.0"
          message="The for-in loop variable ''{0}'' should be explicitly scoped with 'var' to avoid pollution."
          class="net.sourceforge.pmd.lang.rule.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/ecmascript/basic.html#ScopeForInVariable">
      <description>
A for-in loop in which the variable name is not explicitly scoped to the enclosing scope with the 'var' keyword can
refer to a variable in an enclosing scope outside the nearest enclosing scope.  This will overwrite the
existing value of the variable in the outer scope when the body of the for-in is evaluated.  When the for-in loop
has finished, the variable will contain the last value used in the for-in, and the original value from before
the for-in loop will be gone.  Since the for-in variable name is most likely intended to be a temporary name, it
is better to explicitly scope the variable name to the nearest enclosing scope with 'var'.
      </description>
      <priority>1</priority>
        <properties>
            <property name="xpath">
                <value>
 <![CDATA[
	//ForInLoop[not(child::VariableDeclaration)]/Name[1]
]]>
                </value>
            </property>
        </properties>
      <example>
  <![CDATA[
// Ok
function foo() {
   var p = 'clean';
   function() {
	   var obj = { dirty: 'dirty' };
	   for (var p in obj) { // Use 'var' here.
	     obj[p] = obj[p];
	   }
	   return x;
   }();

   // 'p' still has value of 'clean'.
}
// Bad
function bar() {
   var p = 'clean';
   function() {
	   var obj = { dirty: 'dirty' };
	   for (p in obj) { // Oh no, missing 'var' here!
	     obj[p] = obj[p];
	   }
	   return x;
   }();

   // 'p' is trashed and has value of 'dirty'!
}
]]>
      </example>
    </rule>

    <rule name="EqualComparison"
          language="ecmascript"
          since="5.0"
          message="Use '==='/'!==' to compare with true/false or Numbers"
          class="net.sourceforge.pmd.lang.rule.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/ecmascript/basic.html#EqualComparison">
      <description>
      Using == in condition may lead to unexpected results, as the variables are automatically casted to be of the
      same type. The === operator avoids the casting.
      </description>
      <priority>3</priority>
        <properties>
            <property name="xpath">
                <value>
 <![CDATA[
//InfixExpression[(@Image = "==" or @Image = "!=")
  and
 (child::KeywordLiteral[@Image = "true" or @Image = "false"]
 or
 child::NumberLiteral)
]
]]>
                </value>
            </property>
        </properties>
      <example>
  <![CDATA[
// Ok
if (someVar === true) {
  ...
}
// Ok
if (someVar !== 3) {
  ...
}
// Bad
if (someVar == true) {
  ...
}
// Bad
if (someVar != 3) {
  ...
}

]]>
      </example>
    </rule>

    <rule name="GlobalVariable"
          message="Avoid using global variables"
          language="ecmascript"
          since="5.0"
          class="net.sourceforge.pmd.lang.rule.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/ecmascript/basic.html#GlobalVariable">
    <description>
This rule helps to avoid using accidently global variables by simply missing the "var" declaration.
Global variables can lead to side-effects that are hard to debug.
    </description>
  <priority>1</priority>
  <properties>
    <property name="xpath">
    <value>
<![CDATA[
//Assignment[Name/@GlobalName = 'true']
]]>
    </value>
    </property>
  </properties>
  <example>
<![CDATA[
function(arg) {
    notDeclaredVariable = 1; // this will create a global variable and trigger the rule

    var someVar = 1; // this is a local variable, that's ok

    window.otherGlobal = 2; // this will not trigger the rule, although it is a global variable.
}
]]>
        </example>
    </rule>

    <rule name="AvoidTrailingComma"
          message="Avoid trailing commas in object or array literals"
          language="ecmascript"
          since="5.1"
          class="net.sourceforge.pmd.lang.rule.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/ecmascript/basic.html#AvoidTrailingComma">
    <description>
This rule helps improve code portability due to differences in browser treatment of trailing commas in object or array literals.
    </description>
  <priority>1</priority>
  <properties>
    <property name="xpath">
    <value>
<![CDATA[
	//ObjectLiteral[$allowObjectLiteral = "false" and @TrailingComma = 'true']
|
	//ArrayLiteral[$allowArrayLiteral = "false" and @TrailingComma = 'true']
]]>
    </value>
    </property>
    <property name="allowObjectLiteral" type="Boolean" value="false" description="Allow a trailing comma within an object literal" />
    <property name="allowArrayLiteral" type="Boolean" value="false" description="Allow a trailing comma within an array literal" />
    </properties>
  <example>
<![CDATA[
function(arg) {
    var obj1 = { a : 1 }; // Ok
    var arr1 = [ 1, 2 ]; // Ok

    var obj2 = { a : 1, }; // Syntax error in some browsers!
    var arr2 = [ 1, 2, ]; // Length 2 or 3 depending on the browser!
}
]]>
        </example>
    </rule>

  <rule name="UseBaseWithParseInt"
        message="Always provide a base when using parseInt() functions"
        language="ecmascript" since="5.0.1"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/ecmascript/basic.html#UseBaseWithParseInt">
    <description>TODO</description>
  <priority>1</priority>
    <properties>
      <property name="xpath">
      <value><![CDATA[
//FunctionCall/Name[
     @Image = 'parseInt'
     and
     count(../*) < 3
]
   ]]></value>
    </property>
  </properties>
  <example><![CDATA[
parseInt("10",base);
  ]]></example>
  </rule>
</ruleset>
