Source: Sniff/SourceCode/Indentation.js

/*
* @package jscodesniffer
* @author sheiko
* @license MIT
* @copyright (c) Dmitry Sheiko http://www.dsheiko.com
* jscs standard:Jquery
* jshint unused:false
* Code style: http://docs.jquery.com/JQuery_Core_Style_Guidelines
*/
/*
* A module representing a sniffer.
* @module lib/Sniff/SourceCode/Indentation
*/

// UMD boilerplate according to https://github.com/umdjs/umd
if ( typeof module === "object" && typeof define !== "function" ) {
	/**
	* Override AMD `define` function for RequireJS
	* @param {function( function, Object, Object )} factory
	*/
	var define = function ( factory ) {
	module.exports = factory( require, exports, module );
	};
}
/**
	* @param {function( string )} require
	*/
define(function( require ) {
"use strict";
		/**
		* @type {module:lib/utilsSniff/Utils}
		* @access private
		*/
var utils = require( "../Utils" ),
		/**
		* @constant
		* @type {String}
		* @default
		* @access private
		*/
		NAME = "Indentation";
/**
* @constructor
* @alias module:lib/Sniff/SourceCode/Indentation
* @param {module:lib/SourceCode} sourceCode
* @param {module:lib/Mediator} mediator
*/
return function( sourceCode, mediator ) {
	/** @lends module:lib/Sniff/SourceCode/Indentation.prototype */
	return {
		/**
		* Check the contract
		* @access public
		* @param {Object} rule
		* @memberOf module:lib/Sniff/SourceCode/Indentation
		*/
		validateRule: function( rule ) {
			utils.validateRule( rule, "allowOnlyTabs", "boolean" );
			utils.validateRule( rule, "allowOnlySpaces", "boolean" );
			utils.validateRule( rule, "disallowMixed", "boolean" );
		},
		/**
		* Run the sniffer according a given rule if a given node type matches the case
		* @access public
		* @param {Object} rule
		* @memberOf module:lib/Sniff/SourceCode/Indentation
		*/
		run: function( rule ) {
			var that = this,
				lines = sourceCode.asLines();

			lines.forEach(function( line, inx ){
				var
					/**
					* Position on the line
					* @type {number}
					*/
					pos,
					/**
					* @type {string[]|null}
					*/
					matches = that.getWhitespacesInTheBeginning( line );

				if ( rule.disallowMixed ) {
					if ( that.matchesMixedPattern( line ) ) {
						pos = that.getRangePosition( lines, inx );
						that.sniff( inx + 1, pos, matches[ 1 ], "MixedWhitespacesNotAllowedForIndentation", "any" );
					}
				}
				if ( !rule.allowOnlyTabs && !rule.allowOnlySpaces ) {
					return;
				}
				if ( matches && !that.matchesSpecPattern( matches[ 1 ], rule.allowOnlyTabs ) ) {
					pos = that.getRangePosition( lines, inx );
					if ( rule.allowOnlyTabs ) {
						that.sniff( inx + 1, pos, matches[ 1 ], "OnlyTabsAllowedForIndentation", "tabs" );
					} else {
						that.sniff( inx + 1, pos, matches[ 1 ], "OnlySpacesAllowedForIndentation", "spaces" );
					}
				}
			});
		},
		/**
		* Get range left position for the line associated with a given `inx`
		* @param {string[]} lines
		* @param {number} inx
		* @returns {number}
		* @memberOf module:lib/Sniff/SourceCode/Indentation
		*/
		getRangePosition: function( lines, inx ) {
			return lines.slice( 0, inx - 1 ).join( "\n" ).length;
		},
		/**
		* Give all the whitespaces (spaces and tabs) forun in the beginning fo the line
		* @access protected
		* @param {string} line
		* @returns {array}
		* @memberOf module:lib/Sniff/SourceCode/Indentation
		*/
		getWhitespacesInTheBeginning: function( line ) {
			var re = /^(\s*)/g;
			return re.exec( line );
		},
		/**
		* Test if a given line matches specified pattern
		* @access protected
		* @param {string} line
		* @param {type} reqTabs
		* @returns {Boolean}
		* @memberOf module:lib/Sniff/SourceCode/Indentation
		*/
		matchesSpecPattern: function( line, reqTabs ) {
			var re = new RegExp( ( reqTabs ? "^\t*$" : "^ *$" ), "g" );
			return re.test( line );
		},

		/**
		* Test if a given line is of mixed tbas and spaces
		* @access protected
		* @param {string} line
		* @returns {Boolean}
		* @memberOf module:lib/Sniff/SourceCode/Indentation
		*/
		matchesMixedPattern: function( line ) {
			return line.indexOf( " " ) !== -1 && line.indexOf( "\t" ) !== -1;
		},

		/**
		* Report to mediator
		* @access protected
		* @param {number} line
		* @param {number} pos
		* @param {string} foundWsString
		* @param {string} errorCode
		* @param {string} expected
		* @memberOf module:lib/Sniff/SourceCode/Indentation
		*/
		sniff: function( line, pos, foundWsString, errorCode, expected ) {
			var actualLen = foundWsString.length;
			mediator.publish( "violation", NAME, errorCode, [ pos, pos + actualLen ], {
				start: {
					line: line,
					column: 0
				},
				end: {
					line: line,
					column: actualLen
				}
			}, {
				actual: foundWsString,
				expected: expected,
				excerpt: foundWsString,
				where: ""
			});
		}
	};
};

});