Skip to content

Commit

Permalink
trailing whitespace and mixedSpacesAndTabs checks added
Browse files Browse the repository at this point in the history
  • Loading branch information
Ross committed Dec 26, 2014
1 parent 325d145 commit f52c8b7
Show file tree
Hide file tree
Showing 16 changed files with 352 additions and 181 deletions.
5 changes: 0 additions & 5 deletions .flowconfig

This file was deleted.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ results
npm-debug.log
node_modules
styl


lib/read.js
3 changes: 3 additions & 0 deletions .stylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
"indentSpaces": 4,
"leadingZero": true,
"maxWarnings": 10,
"mixed": true,
"mixinSpace": false,
"parenSpace": true,
"placeholders": true,
"unecessaryPX": true,
"semicolons": true,
"trailingWhitespace": true,
"universal": true
}
5 changes: 0 additions & 5 deletions globals_lib/globals.js

This file was deleted.

99 changes: 64 additions & 35 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,15 @@ var blockStyleCorrect = require('./lib/checks/checkBlockStyle'),
hashEnding = require('./lib/checks/checkForHashEnd'),
hashStarting = require('./lib/checks/checkForHashStart'),
leadingZero = require('./lib/checks/checkForLeadingZero'),
mixinStyleCorrect = require('./lib/checks/checkForMixinStyle'),
mixedSpacesAndTabs = require('./lib/checks/checkForMixedSpacesTabs'),
parenStyleCorrect = require('./lib/checks/checkForParenStyle'),
placeholderStyleCorrect = require('./lib/checks/checkForPlaceholderStyle'),
pxStyleCorrect = require('./lib/checks/checkForPx'),
semicolon = require('./lib/checks/checkForSemicolon'),
startsWithComment = require('./lib/checks/checkForCommentStart'),
tooMuchNest = require('./lib/checks/checkNesting'),
universalSelector = require('./lib/checks/checkForUniversal'),
whitespace = require('./lib/checks/checkForTrailingWhitespace'),
varStyleCorrect = require('./lib/checks/checkVarStyle');


Expand Down Expand Up @@ -115,11 +117,14 @@ var Lint = (function() {
'indentSpaces': 4, // how many spaces should we prefer when indenting, pass in false if hard tabs
'leadingZero': true, // find cases where 0.# is used, prefer .#
'maxWarnings': 10, // should we have a max amount of warnings, and error out if we go over
'mixinSpace': false, // check for extra space inside parens when defining or using mixins
'mixed': true, // check for mixed spaces and tabs
'mixinSpace': false, // @deprecated check for extra space inside parens when defining or using mixins
'parenSpace': true, // check for extra space inside parens when defining or using mixins
'placeholders': true, // only allow @extending of placeholder vars
'unecessaryPX': true, // check for use of 0px and recommend 0
'semicolons': true, // check for unecessary semicolons
'universal': true // check for use of * and recommend against it
'trailingWhitespace': true, // check for trailing whitespace
'universal': true, // check for use of * and recommend against it
'unecessaryPX': true // check for use of 0px and recommend 0
};

// if custom config file passed in
Expand All @@ -128,17 +133,17 @@ var Lint = (function() {
try {
config = JSON.parse( fs.readFileSync(file) );
}
catch (err) {
console.log(err);
catch ( err ) {
console.log( err );
}
}
// else no config passed in, so try default dir
else {
try {
config = JSON.parse( fs.readFileSync('./.stylintrc') );
}
catch (err) {
console.log(err);
catch ( err ) {
console.log( err );
}
}

Expand Down Expand Up @@ -252,6 +257,13 @@ var Lint = (function() {
* @return void
*/
test: function( line, num, output, file ) {
var strict = false;

// if strict flag passed, run all tests
if ( argv.s || argv.strict ) {
strict = true;
}

// check for @stylint off comments
if ( hasComment(line) ) {
/**
Expand Down Expand Up @@ -314,109 +326,126 @@ var Lint = (function() {
}

// check that commas are followed by a space
if ( config.cssLiteral || argv.strict || argv.s ) {
if ( config.cssLiteral || strict ) {
if ( cssLiteral(line) ) {
cssBlock = true;
warnings.push(chalk.yellow('refrain from using css literals') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
}
}

// check that commas are followed by a space
if ( config.commaSpace || argv.strict || argv.s ) {
if ( config.commaSpace || strict ) {
if ( commaStyleCorrect(line) === false ) {
warnings.push(chalk.yellow('commas must be followed by a space for readability') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
}
}

// check for extra spaces when defining or using a mixin
if ( config.mixinSpace || argv.strict || argv.s ) {
if ( mixinStyleCorrect(line) === false ) {
warnings.push(chalk.yellow('mixin( $param1, $param2 ) is preferred over mixin($param1, $param2)') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
// check for extra spaces when using parens
if ( config.mixinSpace || config.parenSpace || strict ) {
if ( parenStyleCorrect(line) === false ) {
warnings.push(chalk.yellow('( $param1, $param2 ) is preferred over ($param1, $param2)') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
}
}

// check for border none (prefer border 0)
if ( config.borderNone || argv.strict || argv.s ) {
if ( config.borderNone || strict ) {
if ( checkBorderNone(line) ) {
warnings.push( chalk.yellow('border 0 is preferred over border none') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check for border none (prefer border 0)
if ( config.leadingZero || argv.strict || argv.s ) {
if ( config.leadingZero || strict ) {
if ( leadingZero(line) ) {
warnings.push( chalk.yellow('leading zeroes for decimal points are unecessary') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
warnings.push( chalk.yellow('leading zeros for decimal points are unecessary') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check for @block when defining block var
if ( config.enforceBlockStyle || argv.strict || argv.s ) {
if ( config.enforceBlockStyle || strict ) {
if ( blockStyleCorrect(line) === false ) {
warnings.push( chalk.yellow('block variables must include @block') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check for @extend(s) preference
if ( config.extendPref || argv.strict || argv.s ) {
if ( config.extendPref || strict ) {
if ( extendStyleCorrect(line, config.extendPref) === false ) {
warnings.push( chalk.yellow('please use the ' + config.extendPref + ' syntax when extending') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// only extend placeholder vars (or not)
if ( config.placeholders || argv.strict || argv.s ) {
if ( config.placeholders || strict ) {
if ( placeholderStyleCorrect(line) === false ) {
warnings.push(chalk.yellow('please extend only placeholder vars') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
warnings.push( chalk.yellow('please extend only placeholder vars') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check for $ at start of var
if ( config.enforceVarStyle || argv.strict || argv.s ) {
if ( config.enforceVarStyle || strict ) {
if ( varStyleCorrect(line) === false ) {
warnings.push(chalk.yellow('variables must be prefixed with the $ sign.') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
warnings.push( chalk.yellow('variables must be prefixed with the $ sign.') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check for 0px (margin 0 is preferred over margin 0px)
if ( config.unecessaryPX || argv.strict || argv.s ) {
if ( config.unecessaryPX || strict ) {
if ( pxStyleCorrect(line) === false ) {
warnings.push(chalk.yellow('0 is preferred over 0px.') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
warnings.push( chalk.yellow('0 is preferred over 0px.') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check for * selector (* is discouraged)
if ( config.universal || argv.strict || argv.s ) {
if ( config.universal || strict ) {
if ( universalSelector(line) ) {
warnings.push(chalk.yellow('* selector is slow. Consider a different selector.') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
warnings.push( chalk.yellow('* selector is slow. Consider a different selector.') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check for unecessary : (margin 0 is preferred over margin: 0)
if ( config.colons || argv.strict || argv.s ) {
if ( config.colons || strict ) {
if ( colon(line, areWeInAHash) ) {
warnings.push(chalk.yellow('unecessary colon found:') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
warnings.push( chalk.yellow('unecessary colon found:') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check for unecessary ; (margin 0; is invalid)
if ( config.semicolons || argv.strict || argv.s ) {
if ( config.semicolons || strict ) {
if ( semicolon(line) ) {
warnings.push(chalk.yellow('unecessary semicolon found:') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
warnings.push( chalk.yellow('unecessary semicolon found:') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check for places where we can be more efficient (margin 0 50px vs margin 0 50px 0 50px)
if ( config.efficient || argv.strict || argv.s ) {
if ( config.efficient || strict ) {
if ( efficient(line) === false ) {
warnings.push(chalk.yellow('the value on this line could be more succinct:') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
warnings.push( chalk.yellow('the value on this line could be more succinct:') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check mixed spaces and tabs
if ( config.mixed || strict ) {
// else check tabs against tabs and spaces against spaces
if ( mixedSpacesAndTabs( line, config.indentSpaces ) ) {
warnings.push( chalk.yellow('mixed spaces and tabs') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}


// check for trailing whitespace
if ( config.trailingWhitespace || strict ) {
// else check tabs against tabs and spaces against spaces
if ( whitespace( line ) ) {
warnings.push( chalk.yellow('trailing whitespace') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}

// check selector depth
if ( config.depthLimit || argv.strict || argv.s ) {
if ( config.depthLimit || strict ) {
// else check tabs against tabs and spaces against spaces
if ( tooMuchNest( line, config.depthLimit, config.indentSpaces ) ) {
warnings.push(chalk.yellow('selector depth greater than', config.depthLimit + ':') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output);
warnings.push( chalk.yellow('selector depth greater than', config.depthLimit + ':') + '\nFile: ' + file + '\nLine: ' + num + ': ' + output );
}
}
}
Expand Down
34 changes: 34 additions & 0 deletions lib/checks/checkForMixedSpacesTabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* check for mixed spaces and tabs
* @param {string} line the line being tested
* @param {number} indentSpaces default is 4. if set to false the we do hard tabs instead of spaces
* @return {boolean} true if mixed spaces and tabs, false if not
* @todo this is kinda not 100% reliable in it's current form
*/
var tabs = /\t/, // was a tab used, at all
spaces = /\s{2,}/; // check for 2 or more spaces (if hard tabs, shouldn't find anything)

module.exports = function checkMixedSpacesAndTabs( line, indentSpaces ) {
// if this isnt set to false then we're indenting with spaces
if ( indentSpaces ) {
// look for hard tabs
if ( tabs.test( line ) ) {
return true;
}
// soft tabs, no hard tabs, all good
else {
return false;
}
}
// else you're a hard tab believer
else {
// look for 2 or more spaces
if ( spaces.test( line ) ) {
return true;
}
// hard tab, no spaces, all good
else {
return false;
}
}
}
File renamed without changes.
17 changes: 17 additions & 0 deletions lib/checks/checkForTrailingWhitespace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* check for trailing whitespace
* @param {string} line the line being tested
* @return {boolean} true if whitespace found, false if not
*/
var whitespace = /[ \t]+$/, // check for unecessary tabs or whitespace at eol
anythingElse = /[^ \t]/; // anything BUT whitespace (we dont want to return false positives on empty lines)

module.exports = function checkWhitespace( line ) {
// not an empty line, with whitespace at the end
if ( anythingElse.test(line) && whitespace.test(line) ) {
return true;
}
else {
return false;
}
}
10 changes: 5 additions & 5 deletions lib/checks/checkNesting.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
* @param {number} limit the total number of indents allowed, not counting &: selectors
* @param {number} indentSpaces default is 4. if no indents found will check depth using spaces
* @return {boolean} true if nesting is too deep, false if not
* @todo this is kinda not 100% reliable in it's current form
*/
var amp = /^(\&\:)/; // check if using & selector before we count tabs
// tabs = /^(\t)*/, // returns all tabs
//space = /^( {4})*/, // check spaces

module.exports = function checkNesting( line, limit, indentSpaces ) {
var arr = line.split(' ');
var arr = line.split(' '),
// get all single spaces in the line
arr = arr.filter(function( str ) {
return str.length === 0;
}),
count = 0, index = 0;

// pref is defined (it is by default), then assume we indent with tabs
// pref is defined (it is by default), then assume we indent with spaces
if ( indentSpaces ) {
if ( arr.length / indentSpaces > limit ) {
return true;
Expand All @@ -28,7 +28,7 @@ module.exports = function checkNesting( line, limit, indentSpaces ) {
// if not we check hard tabs
else {
// get all tabs, starting at beginning of string
while ( line.charAt(index++) === '\t' ) {
while ( line.charAt( index++ ) === '\t' ) {
count++;
}

Expand Down
4 changes: 2 additions & 2 deletions styl/test2.styl
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ a

// Prevent modern browsers from displaying `audio` without controls.
// Remove excess height in iOS 5 devices.
audio:not([controls])
audio:not( [controls] )
display none
height 0


transition( $prop, $timing, $accelerate )
transition($prop, $timing, $accelerate)
var = 'test'
transition $prop $timing cubic-bezier(0, 1, .55, .97)
// turn on hardware acceleration for stuff (dont abuse)
Expand Down
Loading

0 comments on commit f52c8b7

Please sign in to comment.