Skip to content

Commit

Permalink
DRY linter selection, select style after reading package settings
Browse files Browse the repository at this point in the history
  • Loading branch information
Thore3 committed Dec 7, 2016
1 parent a37e69a commit b863435
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 133 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ linter-js-standard
=========================
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard)

This plugin for [Linter](https://github.com/AtomLinter/Linter) provides an interface for error/warning messages from [standard](https://github.com/feross/standard), [semistandard](https://github.com/Flet/semistandard) or [happiness](https://github.com/JedWatson/happiness).
This plugin for [Linter](https://github.com/AtomLinter/Linter) provides an interface for error/warning messages from [standard](https://github.com/feross/standard), as well as variations of standard such as [semistandard](https://github.com/Flet/semistandard) and [happiness](https://github.com/JedWatson/happiness).

![demo](https://cloud.githubusercontent.com/assets/6867996/8457085/4bd7575e-2007-11e5-9762-e3f942b78232.gif)

Expand Down
22 changes: 9 additions & 13 deletions lib/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ module.exports = {
config: {
style: {
type: 'string',
default: 'standard',
enum: ['standard', 'semi-standard', 'happiness', 'uber-standard']
default: styleSettings.defaultStyle,
enum: styleSettings.styleOptions
},
checkStyleDevDependencies: {
type: 'boolean',
Expand Down Expand Up @@ -104,17 +104,13 @@ module.exports = {

__cacheTextEditor: function (config, textEditor) {
var filePath = textEditor.getPath()
var style = selectStyle(config, filePath)
var opts = {}

// If setting honorStyleSettings is checked
// and there is a valid linter
if (config.honorStyleSettings && style && style.cmd !== 'no-style') {
// This function may modify the following variables:
// - opts
// - style
styleSettings.call({ args: opts, style: style }, filePath)
}

var opts = config.honorStyleSettings ? styleSettings.checkStyleSettings(filePath) : {}

var style = selectStyle(filePath, {
style: opts.style || config.style,
checkStyleDevDependencies: config.checkStyleDevDependencies
})

// Cache style settings and args of some file
this.cache.set('text-editor', { style: style, opts: opts })
Expand Down
99 changes: 27 additions & 72 deletions lib/utils/select-style.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
// Dependencies
var allowUnsafeNewFunction = require('loophole').allowUnsafeNewFunction
var pkgConfig = require('pkg-config')
var dirname = require('path').dirname
var styleSettings = require('./style-settings')

function noStyle () {
return { cmd: 'no-style' }
}

function requireWithLocalOverride (moduleName, dir) {
try {
return module.constructor._load(moduleName, {
Expand All @@ -9,87 +16,35 @@ function requireWithLocalOverride (moduleName, dir) {
return require(moduleName)
}
}
var pickStandard = function (style, dir) {

var pickStandard = function (style, filePath) {
var dir = dirname(filePath)
return allowUnsafeNewFunction(function () {
switch (style) {
case 'standard':
return requireWithLocalOverride('standard', dir)
case 'happiness':
return requireWithLocalOverride('happiness', dir)
case 'uber-standard':
return requireWithLocalOverride('uber-standard', dir)
default:
return requireWithLocalOverride('semistandard', dir)
}
return requireWithLocalOverride(style, dir)
})
}

var pkgConfig = require('pkg-config')
var intersection = require('lodash.intersection')
var dirname = require('path').dirname

function getStyleThroughDevDeps (filePath) {
// This will get the devDependencies
// from the nearest package.json
var options = { cwd: filePath, root: 'devDependencies', cache: false }
var noStyle = { cmd: 'no-style' }
var devDeps = pkgConfig(null, options) || {}
var prodDeps = pkgConfig(null, Object.assign({}, options, { root: 'dependencies' })) || {}

// Check if there are linters defined in
// package.json devDependencies
var knownLinters = ['standard', 'semistandard', 'happiness', 'uber-standard']
var foundDevLinters = intersection(Object.keys(devDeps), knownLinters)
var foundProdLinters = intersection(Object.keys(prodDeps), knownLinters)
var hasKnownLinter = Boolean(foundDevLinters.length) || Boolean(foundProdLinters.length)
if (hasKnownLinter) {
var dir = dirname(filePath)

// standard style
if (devDeps.standard || prodDeps.standard) {
return pickStandard('standard', dir)
}

// happiness style
if (devDeps.happiness || prodDeps.happiness) {
return pickStandard('happiness', dir)
}
// Get the dependencies from the nearest package.json
function pkgOpts (root) { return { cwd: filePath, root: root, cache: false } }
var devDeps = pkgConfig(null, pkgOpts('devDependencies')) || {}
var prodDeps = pkgConfig(null, pkgOpts('dependencies')) || {}

// uber-standard
if (devDeps['uber-standard'] || prodDeps['uber-standard']) {
return pickStandard('uber-standard', dir)
}
// If one of the known linters is found as a dependency, use it
var useLinter = styleSettings.styleOptions.filter(function (style) {
return devDeps[style] || prodDeps[style]
})[0]

// semistandard style
return pickStandard('semistandard', dir)
}

// no style
return noStyle
return useLinter ? pickStandard(useLinter, filePath) : noStyle()
}

module.exports = function selectStyle (config, filePath) {
// see if setting 'checkStyleDevDependencies' is true
// if true get style from the package.json
if (config.checkStyleDevDependencies) {
module.exports = function selectStyle (filePath, options) {
// See if it should get style from the package.json
if (options.checkStyleDevDependencies) {
return getStyleThroughDevDeps(filePath)
}

function getLinterFromStyle (style) {
var dir = dirname(filePath)
if (style === 'standard') {
return pickStandard('standard', dir)
}
if (style === 'happiness') {
return pickStandard('happiness', dir)
}
if (style === 'uber-standard') {
return pickStandard('uber-standard', dir)
}
return pickStandard('semistandard', dir)
}

// fallback to style select value to decide which style
// we should use
return getLinterFromStyle(config.style)
// Fallback to style value to decide which style we should use
var shouldStyle = options.style && options.style !== 'no-style'
return shouldStyle ? pickStandard(options.style, filePath) : noStyle()
}
83 changes: 36 additions & 47 deletions lib/utils/style-settings.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
/* global atom */
// Dependencies
var minimatch = require('minimatch')
var pkgConfig = require('pkg-config')
var fs = require('fs')

module.exports = function checkStyleSettings (filePath) {
// Default value
var styleSettings = false
var styleOptions = [
'standard',
'semistandard',
'happiness',
'uber-standard'
]

function checkStyleSettings (filePath) {
var settings = {}

// Try to get the project's absolute path
// NOTE: the project's path returned will be
Expand All @@ -29,31 +34,23 @@ module.exports = function checkStyleSettings (filePath) {
// Get relative path of the filePath
var relativeFilePath = filePath.replace(projectPath, '').substring(1)

var options = { cwd: filePath, root: 'standard', cache: false }

switch (this.style.cmd) {
case 'standard':
styleSettings = pkgConfig(null, options)
break
// Get options for standard
var styleSettings

case 'semistandard':
options.root = 'semistandard'
styleSettings = pkgConfig(null, options)
break
function pkgOpts (root) { return { cwd: filePath, root: root, cache: false } }

case 'happiness':
options.root = 'happiness'
styleSettings = pkgConfig(null, options)
break

default:
throw new Error('Something went wrong.')
}
styleOptions.forEach(function (style) {
var config = pkgConfig(null, pkgOpts(style))
if (config && !styleSettings) {
config.style = style
styleSettings = config
}
})

if (styleSettings) {
// Check parser
if (styleSettings.parser) {
this.args.parser = styleSettings.parser
settings.parser = styleSettings.parser
}

// If ignore glob patterns are present
Expand All @@ -65,41 +62,33 @@ module.exports = function checkStyleSettings (filePath) {
return minimatch(relativeFilePath, pattern)
})

// If a glob pattern was matched unset the
// linter, the file needs to be ignored
// If a glob pattern was matched, do not lint the file
if (ignoreGlobPatterns) {
this.style.cmd = 'no-style'
return
settings.style = 'no-style'
return settings
}
}

styleSettings.global = styleSettings.global || styleSettings.globals

// global variables option
if (styleSettings.global) {
var globalArr = []

globalArr = globalArr.concat(styleSettings.global)

globalArr.forEach(function (item) {
if (!this.args.globals) {
this.args.globals = []
}

this.args.globals.push(item)
}.bind(this))
settings.globals = [].concat(styleSettings.global || [])
}

if (styleSettings.env) {
for (let envKey in styleSettings.env) {
if (!styleSettings.env.hasOwnProperty(envKey)) {
continue
}
if (!this.args.env) {
this.args.env = {}
}
this.args.env[envKey] = styleSettings.env[envKey]
}
settings.env = {}
Object.keys(styleSettings.env).forEach(function (key) {
settings.env[key] = styleSettings.env[key]
})
}
}

return settings
}

module.exports = {
defaultStyle: styleOptions[0],
styleOptions: styleOptions,
checkStyleSettings: checkStyleSettings
}

0 comments on commit b863435

Please sign in to comment.