UNPKG

stylint

Version:
156 lines (139 loc) 4.67 kB
'use strict' var fs = require( 'fs' ) var path = require( 'path' ) var userHome = require( 'user-home' ) var stripJsonComments = require( 'strip-json-comments' ) var Glob = require( 'glob' ).Glob // @TODO i just this sloppy just to fix some stuff // comes back and refactor / cleanup /** * @description overrides default config with a new config object * many potential code paths here. * 1: user passed in config object via function param * 2: user passes location of .stylintrc file to use via cli * 3: user has options obj in package.json or path to * 4: none of the above, fallback to initial config * 5: user has a .stylintrc file in a dir but doesnt pass anything * @param {String} [configpath] If defined, the path to a config-file to read * @returns {Function} kick off linter again */ var setConfig = function( configpath ) { var files = [] var customPath = '' // return default config if nothing passed in or found var returnConfig var cwd = process.cwd() var pkg = null try { pkg = require( cwd + '/package.json' ) } catch ( err ) { // no output } /** * @description sets the return config if one if found * @param {string} path [where to look for config] * @return {Object|void} [object if stylintrc found, undefined if not] */ var _parseConfig = function( path ) { return JSON.parse( stripJsonComments( fs.readFileSync( path, 'utf-8' ) ) ) } /** * @description [reverse walk from cwd to usr] * [if .stylintrc found, use it] * @param {Array<string>} files [all files for this dir level] * @param {number} level [# of dirs traversed so far] * @param {string} cwd [relative path to current directory being walked] * @return {?Object|?Function} [config if found, recurse if not. null if failed] */ var _recurseDirectories = function( files, level, cwd ) { // parse stylintrc if found, stop recursion if ( files.indexOf( '.stylintrc' ) !== -1 ) { return _parseConfig( cwd + '/.stylintrc' ) } // only go up to user home directory, stop recursion if ( userHome ) return null // next dir level var nextLevel = level + 1 // pathArr is generated by applying our dir level // to cwd, and going backwards // ie, level = 1, pathArr = [ cwd, '..' ] // ie, level = 2, pathArr = [ cwd, '..', '..' ] // and so on var pathArr = [ cwd ] // push '..' for each dir level while ( level-- ) { pathArr.push( '..' ) } // creates the path to the next directory var newPath = path.join.apply( null, pathArr ) // gets the files for the next directory var newFiles = fs.readdirSync( newPath ) // passes the newFiles, nextLevel, and newPath to itself // to start the process over again return _recurseDirectories( newFiles, nextLevel, newPath ) } // if 1, the customConfig will be what we want // this only occurs if using stylint programmatically // ie, user passed in option object if ( this.customConfig ) { returnConfig = this.customConfig } // if 2, we pass in a path to the config // this only occurs if using stylint via the command line else if ( configpath ) { customPath = path.isAbsolute( configpath ) ? configpath : cwd + '/' + configpath try { returnConfig = _parseConfig( customPath ) } catch ( err ) { throw err } } // 3, if user did not pass in option obj, or pass options via cli // check the user's package.json for either an option obj, or // at least a path to one else if ( pkg !== null && typeof pkg.stylintrc !== 'undefined' ) { var rc = pkg.stylintrc if ( typeof rc === 'object' && !( rc instanceof Array ) ) { returnConfig = rc } else if ( typeof rc === 'string' ) { returnConfig = _parseConfig( rc ) } } // 4, nothing passed in via cli or programmatically or via pkg // start at cwd, walk up to user home directory, if nothing // found, then just use the default config else { try { // recurse up to user home files = fs.readdirSync( cwd ) // null if .stylintrc file found anywhere returnConfig = _recurseDirectories( files, 1, cwd ) // default config if nothing found if ( !returnConfig ) { returnConfig = this.config } } // in case there's an issue parsing or no .stylintrc found at specified location catch ( err ) { throw err } } returnConfig.exclude = ( returnConfig.exclude || [] ).map( function( exclude ) { return new Glob( exclude, { matchBase: true } ).minimatch } ) // make sure indentPref is set no matter what returnConfig.indentPref = returnConfig.indentPref || false // 5, just return the default config if nothing found return returnConfig } module.exports = setConfig