/*
* @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
*/
// 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 );
};
}
/**
* A module representing a sniffer.
* @module lib/Sniff/SyntaxTree/ArrayLiteralSpacing
* @param {function( string )} require
*/
define(function( require ) {
"use strict";
/**
* @type {utilsSniff/Utils}
*/
var utils = require( "../Utils" ),
/**
* @constant
* @type {String}
* @default
*/
NAME = "ArrayLiteralSpacing",
/**
* @constructor
* @alias module:lib/Sniff/SyntaxTree/ArrayLiteralSpacing
* @param {module:lib/SourceCode} sourceCode
* @param {module:lib/Mediator} mediator
* @param {module:lib/TokenIterator} tokenIterator
*/
Sniff = function( sourceCode, mediator, tokenIterator ) {
/**
* @type {Mixin}
*/
var mixin = utils.Mixin( sourceCode, mediator, NAME );
return {
/**
* Check the contract
* @access public
* @param {Object} rule
*/
validateRule: function( rule ) {
utils.validateRule( rule, "allowElementPrecedingWhitespaces", "number", true );
utils.validateRule( rule, "allowElementTrailingWhitespaces", "number", true );
utils.validateRule( rule, "exceptions", "object" );
if ( !rule.exceptions ) {
return false;
}
if ( rule.exceptions.singleElement ) {
this.validateRule( rule.exceptions.singleElement );
}
if ( rule.exceptions.firstElement ) {
this.validateRule( rule.exceptions.firstElement );
}
if ( rule.exceptions.lastElement ) {
this.validateRule( rule.exceptions.lastElement );
}
},
/**
* Run the sniffer according a given rule if a given node type matches the case
* @access public
* @param {Object} rule
* @param {Object} node
*/
run: function( rule, node ) {
if ( node.type === "ArrayExpression" && node.elements && node.elements.length ) {
this.sniffFirst( rule, node );
// Checking preceding for each element
node.elements.forEach(function( el, i ){
var tokenIt;
if ( node.elements[ i - 1 ] && node.elements[ i + 1 ] ) {
tokenIt = tokenIterator
.findByLeftPos( el.range[ 0 ] )
.findGroupOpener( node.range[ 0 ] );
// [< >element<, >element ]
// incl. [(((el)))]
mixin.sniffExcerpt( tokenIt.get( -1 ), tokenIt.get( 0 ), rule.allowElementPrecedingWhitespaces,
"ArraylElementPrecedingSpacing", "<" );
}
});
// Checking trailing for the last element
// [ element, element< >]
this.sniffLast( rule, node );
}
},
/**
* Check the first element
* @access protected
* @param {Object} rule
* @param {Object} node
*/
sniffFirst: function( rule, node ) {
var el, expected, tokenIt;
if ( !node.elements.length ) {
return;
}
el = node.elements[ 0 ];
// Checking preceding space for the first element
// {< >element, element }
expected = rule.allowElementPrecedingWhitespaces;
if ( rule.exceptions && rule.exceptions.firstElement &&
mixin.matchesFor( rule.exceptions.firstElement, el.type ) ) {
expected = rule.exceptions.firstElement.allowElementPrecedingWhitespaces;
}
if ( rule.exceptions && rule.exceptions.singleElement && node.elements.length === 1 &&
mixin.matchesFor( rule.exceptions.singleElement, el.type ) ) {
expected = rule.exceptions.singleElement.allowElementPrecedingWhitespaces;
}
// find element token in the interator
tokenIt = tokenIterator
.findByLeftPos( el.range[ 0 ] )
.findGroupOpener( node.range[ 0 ] );
// between prev. token right pos and el left pos
mixin.sniffExcerpt( tokenIt.get( -1 ), tokenIt.get( 0 ),
expected, "ArraylElementPrecedingSpacing", "<" );
},
/**
* Check the last element
* @access protected
* @param {Object} rule
* @param {Object} node
*/
sniffLast: function( rule, node ) {
var el, expected, tokenIt;
if ( !node.elements.length ) {
return;
}
el = node.elements[ node.elements.length - 1 ];
// Checking preceding for the last element
// arr[ el,< >el ]
// also: arr[ el,< >(((el))) ]
// For the first another sniff take care
if ( node.elements.length > 1 ) {
// find element token in the interator
tokenIt = tokenIterator
.findByLeftPos( el.range[ 0 ] )
.findGroupOpener( node.range[ 1 ] );
mixin.sniffExcerpt( tokenIt.get( -1 ), tokenIt.get( 0 ),
rule.allowElementPrecedingWhitespaces, "ArraylElementPrecedingSpacing", "<" );
}
// Checking trailing for the last element
// [ el, el< >]
expected = rule.allowElementTrailingWhitespaces;
if ( rule.exceptions && rule.exceptions.lastElement &&
mixin.matchesFor( rule.exceptions.lastElement, el.type ) ) {
expected = rule.exceptions.lastElement.allowElementTrailingWhitespaces;
}
if ( rule.exceptions && rule.exceptions.singleElement && node.elements.length === 1 &&
mixin.matchesFor( rule.exceptions.singleElement, el.type ) ) {
expected = rule.exceptions.singleElement.allowElementTrailingWhitespaces;
}
// find element token in the interator
tokenIt = tokenIterator
.findByRightPos( el.range[ 1 ] )
.findGroupOpener( node.range[ 1 ] );
// find next token: foo( el, el<>)
// also: foo( el, (((el)))< >)
mixin.sniffExcerpt( tokenIt.get( 0 ), tokenIt.get( 1 ), expected, "ArraylElementTrailingSpacing", ">" );
}
};
};
return Sniff;
});