UNPKG

nlint

Version:
147 lines (120 loc) 3.42 kB
var Nlint = global.Nlint, fs = require( 'fs' ), Slice = Array.prototype.slice, rshebang = /^\#\!.*/, guid = 0; function Linter( path ) { var self = this, result, settings, current = Nlint.Linters.filter(function( linter ) { return linter.path === path; }); // Found existing linter if ( current.length > 0 ) { return current[ 0 ]; } // Path must be defined else if ( ! Nlint.isString( path ) || ! path.length ) { throw new Error( "Linter path not defined" ); } // Force linter instance else if ( ! ( self instanceof Linter ) ) { return new Linter( path ); } // Settings are found on module.exports of the linter file result = Nlint.require( path ); settings = result.result; // Linter checking if ( result.error ) { throw result.error; } else if ( ! settings ) { throw new Error( "No exports found on path [" + path + "]" ); } else if ( ! Nlint.isFunction( settings.render ) ) { throw new Error( "Render not set on linter [" + path + "]" ); } // Internals self.path = path; self.name = settings.name || ''; self.lname = self.name.toLowerCase(); self.defaults = settings.defaults || {}; self.match = settings.match || self.lname; self.runner = settings.render; // Stash match type if ( Nlint.isString( self.match ) ) { self.matchType = Linter.MATCH_TYPE_STRING; } else if ( Nlint.isRegExp( self.match ) ) { self.matchType = Linter.MATCH_TYPE_REGEX; } else if ( Nlint.isFunction( self.match ) ) { self.matchType = Linter.MATCH_TYPE_FUNC; } else { throw new Error( "Match has to be of type string, regex, or function on linter [" + path + "]" ); } // Attach linter to watch list Nlint.Linters.push( self ); // Create default object namespace Nlint.Defaults.Settings.linters[ self.lname ] = self.defaults; } Linter.prototype = { // Path Matching isMatch: function( path, settings, nlint ) { var self = this; if ( self.matchType == Linter.MATCH_TYPE_STRING ) { return path.split( '.' ).pop() === self.match; } else if ( self.matchType == Linter.MATCH_TYPE_REGEX ) { return !!( self.match.exec( path ) ); } else if ( self.matchType == Linter.MATCH_TYPE_FUNC ) { return self.match( path, settings, nlint ); } else { return false; } }, // Running linter on file path render: function( path, settings, callback ) { var self = this, times = { start: Date.now(), name: self.name }; fs.readFile( path, 'utf8', function( e, contents ) { times.read = Date.now(); // File error if ( e ) { return callback( e ); } // Remove possible env declaration (nodejs files) contents = ( contents || '' ).replace( rshebang, '' ); // There is content to analyze if ( contents.length ) { self.runner( path, contents, settings, function(){ times.lint = Date.now(); var args = Slice.call( arguments ); args[ 3 ] = times; callback.apply( callback, args ); }); } else { times.lint = Date.now(); callback( null, null, null, times ); } }); } }; // Constants Linter.MATCH_TYPE_STRING = 'MATCH_TYPE_STRING'; Linter.MATCH_TYPE_REGEX = 'MATCH_TYPE_REGEX'; Linter.MATCH_TYPE_FUNC = 'MATCH_TYPE_FUNC'; Linter.LINTER_DIR = __dirname + '/linters/'; // Expose Nlint.Linters = []; Nlint.Linter = Linter; // Add all included linters fs.readdirSync( Linter.LINTER_DIR ).forEach(function( name ) { Linter( Linter.LINTER_DIR + name ); });