From 72bb971782974b7453fef9dd7d7dd0ca095e500c Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Wed, 22 Jul 2015 08:59:47 -0700 Subject: [PATCH 1/8] Update to the new Linter API --- .gitignore | 1 + README.md | 16 ++++++------- coffeelint.json | 38 +++++++++++++++++++++++++++++++ lib/init.coffee | 11 --------- lib/main.coffee | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 19 ++++++++++------ 6 files changed, 118 insertions(+), 27 deletions(-) create mode 100644 coffeelint.json delete mode 100644 lib/init.coffee create mode 100644 lib/main.coffee diff --git a/.gitignore b/.gitignore index ade14b9..7524296 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store +.idea npm-debug.log node_modules diff --git a/README.md b/README.md index 24846ee..98f9b98 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,16 @@ This linter plugin for [Linter](https://github.com/AtomLinter/Linter) provides a Linter package must be installed in order to use this plugin. If Linter is not installed, please follow the instructions [here](https://github.com/AtomLinter/Linter). ### Plugin installation -``` +```ShellSession $ apm install linter-csslint ``` ## Settings You can configure linter-csslint by editing ~/.atom/config.cson (choose Open Your Config in Atom menu): -``` +```cson 'linter-csslint': - 'csslintExecutablePath': null #csslint path. run 'which csslint' to find the path + #csslint path. run 'which csslint' to find the path + 'executablePath': null ``` ## Contributing @@ -25,15 +26,12 @@ If you would like to contribute enhancements or fixes, please do the following: 1. Hack on a separate topic branch created from the latest `master`. 1. Commit and push the topic branch. 1. Make a pull request. -1. welcome to the club +1. Welcome to the club! Please note that modifications should follow these coding guidelines: - Indent is 2 spaces. -- Code should pass coffeelint linter. +- Code should pass [CoffeeLint](http://www.coffeelint.org/) with the provided `coffeelint.json` - Vertical whitespace helps readability, don’t be afraid to use it. -Thank you for helping out! - -## Donation -[![Share the love!](https://chewbacco-stuff.s3.amazonaws.com/donate.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KXUYS4ARNHCN8) +**Thank you for helping out!** diff --git a/coffeelint.json b/coffeelint.json new file mode 100644 index 0000000..a0bea9b --- /dev/null +++ b/coffeelint.json @@ -0,0 +1,38 @@ +{ + "max_line_length": { + "value": 120, + "level": "warn" + }, + "no_empty_param_list": { + "level": "error" + }, + "arrow_spacing": { + "level": "error" + }, + "no_interpolation_in_single_quotes": { + "level": "error" + }, + "no_debugger": { + "level": "error" + }, + "prefer_english_operator": { + "level": "error" + }, + "colon_assignment_spacing": { + "spacing": { + "left": 0, + "right": 1 + }, + "level": "error" + }, + "braces_spacing": { + "spaces": 0, + "level": "error" + }, + "spacing_after_comma": { + "level": "error" + }, + "no_stand_alone_at": { + "level": "error" + } +} \ No newline at end of file diff --git a/lib/init.coffee b/lib/init.coffee deleted file mode 100644 index a194ab1..0000000 --- a/lib/init.coffee +++ /dev/null @@ -1,11 +0,0 @@ -path = require 'path' - -module.exports = - config: - csslintExecutablePath: - default: path.join __dirname, '..', 'node_modules', '.bin' - title: 'CSSLint Executable Path' - type: 'string' - - activate: -> - console.log 'activate linter-csslint' diff --git a/lib/main.coffee b/lib/main.coffee new file mode 100644 index 0000000..4e3b3e9 --- /dev/null +++ b/lib/main.coffee @@ -0,0 +1,60 @@ +{CompositeDisposable} = require 'atom' +{parseString} = require 'xml2js' +path = require 'path' + +module.exports = + config: + executablePath: + title: 'CSSLint Executable Path' + type: 'string' + # default: path.join(__dirname, '..', 'node_modules', '.bin', 'csslint.cmd') + default: 'csslint' + description: 'Path of the `csslint` executable.' + + activate: -> + @subscriptions = new CompositeDisposable + @subscriptions.add atom.config.observe 'linter-csslint.executablePath', + (executablePath) => + @executablePath = executablePath + + deactivate: -> + @subscriptions.dispose() + + provideLinter: -> + helpers = require('atom-linter') + provider = + grammarScopes: ['source.css', 'source.html'] + scope: 'file' + lintOnFly: false # FIXME + lint: (textEditor) => + filePath = textEditor.getPath() + text = textEditor.getText() + parameters = ['--format=lint-xml', filePath] + return helpers.exec(@executablePath, parameters, {stdin: text}).then (output) -> + # return [{ + # type: "Warning", + # text: "Unknown property 'stroke-width'.", + # range: [[1, 1], [1, 4]], + # trace: [{ + # type: "Trace", + # text: "\tstroke-width: 3px;\r", + # range: [[1, 1], [1, 4]] + # }] + # }] + toReturn = [] + parseString output, (err, result) -> + for issue in result.lint.file[0].issue + data = issue['$'] + line = parseInt(data.line, 10) - 1 + char = parseInt(data.char, 10) + toReturn.push({ + type: data.severity.charAt(0).toUpperCase() + data.severity.slice(1), + text: data.reason, + range: [[line, char], [line, char]], + trace: [{ + type: "Trace", + text: data.evidence, + range: [[line, char], [line, char]] + }] + }) + return toReturn \ No newline at end of file diff --git a/package.json b/package.json index 178147a..e4972dd 100644 --- a/package.json +++ b/package.json @@ -6,16 +6,21 @@ "linter", "lint" ], - "main": "./lib/init", - "linter-package": true, - "version": "0.0.14", + "main": "./lib/main", + "version": "0.0.15", "description": "Lint CSS on the fly, using csslint", "repository": "https://github.com/AtomLinter/linter-csslint", "license": "MIT", - "engines": { - "atom": ">0.50.0" - }, "dependencies": { - "csslint": "~0.10.0" + "csslint": "~0.10.0", + "atom-linter": "^2.0.1", + "xml2js": "^0.4.9" + }, + "providedServices": { + "linter": { + "versions": { + "1.0.0": "provideLinter" + } + } } } From 45b0c20f250d6966c3879bf40511d50a5c8e1b13 Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Wed, 22 Jul 2015 09:23:57 -0700 Subject: [PATCH 2/8] EOF for all --- coffeelint.json | 2 +- lib/main.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coffeelint.json b/coffeelint.json index a0bea9b..e54ca7b 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -35,4 +35,4 @@ "no_stand_alone_at": { "level": "error" } -} \ No newline at end of file +} diff --git a/lib/main.coffee b/lib/main.coffee index 4e3b3e9..4ede8e7 100644 --- a/lib/main.coffee +++ b/lib/main.coffee @@ -57,4 +57,4 @@ module.exports = range: [[line, char], [line, char]] }] }) - return toReturn \ No newline at end of file + return toReturn From a4a5645e7033f3566619948fc2108a8cee0b8013 Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Wed, 22 Jul 2015 09:24:17 -0700 Subject: [PATCH 3/8] Remove old linter code --- lib/linter-csslint.coffee | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 lib/linter-csslint.coffee diff --git a/lib/linter-csslint.coffee b/lib/linter-csslint.coffee deleted file mode 100644 index f3ab838..0000000 --- a/lib/linter-csslint.coffee +++ /dev/null @@ -1,37 +0,0 @@ -linterPath = atom.packages.getLoadedPackage("linter").path -Linter = require "#{linterPath}/lib/linter" - -class LinterCsslint extends Linter - - # The syntax that the linter handles. May be a string or - # list/tuple of strings. Names should be all lowercase. - @syntax: ['source.css', 'source.html'] - - # A string, list, tuple or callable that returns a string, list or tuple, - # containing the command line (with arguments) used to lint. - cmd: 'csslint --format=compact' - - linterName: 'csslint' - - # A regex pattern used to extract information from the executable's output. - regex: - '.+:\\s*' + # filename - # csslint emits errors that pertain to the code as a whole, - # in which case there is no line/col information, so that - # part is optional. - '(line (?\\d+), col (?\\d+), )?' + - '((?Error)|(?Warning)) - (?.*)' - - #isNodeExecutable: yes - - constructor: (editor)-> - super(editor) - - @configSubscription = atom.config.observe 'linter-csslint.csslintExecutablePath', => - @executablePath = atom.config.get 'linter-csslint.csslintExecutablePath' - - destroy: -> - super - @configSubscription.dispose() - -module.exports = LinterCsslint From b5507e6968200dbdb5a586fc8504b246193c271b Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Wed, 22 Jul 2015 09:30:49 -0700 Subject: [PATCH 4/8] Fix up messages Add filePath and offset character by one to the left. --- lib/main.coffee | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/main.coffee b/lib/main.coffee index 4ede8e7..61e60a0 100644 --- a/lib/main.coffee +++ b/lib/main.coffee @@ -31,25 +31,16 @@ module.exports = text = textEditor.getText() parameters = ['--format=lint-xml', filePath] return helpers.exec(@executablePath, parameters, {stdin: text}).then (output) -> - # return [{ - # type: "Warning", - # text: "Unknown property 'stroke-width'.", - # range: [[1, 1], [1, 4]], - # trace: [{ - # type: "Trace", - # text: "\tstroke-width: 3px;\r", - # range: [[1, 1], [1, 4]] - # }] - # }] toReturn = [] parseString output, (err, result) -> for issue in result.lint.file[0].issue data = issue['$'] line = parseInt(data.line, 10) - 1 - char = parseInt(data.char, 10) + char = parseInt(data.char, 10) - 1 toReturn.push({ type: data.severity.charAt(0).toUpperCase() + data.severity.slice(1), text: data.reason, + filePath: filePath range: [[line, char], [line, char]], trace: [{ type: "Trace", From 80e4c4ab9633ce477f5f2e9e3fbe41fb785ec48e Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Wed, 22 Jul 2015 10:59:07 -0700 Subject: [PATCH 5/8] Fix indentation in coffeelint.json --- coffeelint.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coffeelint.json b/coffeelint.json index e54ca7b..cf6b722 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -1,6 +1,6 @@ { "max_line_length": { - "value": 120, + "value": 120, "level": "warn" }, "no_empty_param_list": { From c080d2eac5f03e22992aa10c8d0865d64ad21b2c Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Fri, 24 Jul 2015 01:04:46 -0700 Subject: [PATCH 6/8] Move to utilizing csslint directly Pulls in the `csslint` code and utilizes it directly. Unfortunately this means we need to pull in and parse the `.csslintrc` files ourselves. Linting on the fly can be enabled however. --- lib/main.coffee | 61 ++++++++++++++++++------------------------------- package.json | 4 +--- 2 files changed, 23 insertions(+), 42 deletions(-) diff --git a/lib/main.coffee b/lib/main.coffee index 61e60a0..d4b0fd7 100644 --- a/lib/main.coffee +++ b/lib/main.coffee @@ -1,51 +1,34 @@ -{CompositeDisposable} = require 'atom' -{parseString} = require 'xml2js' -path = require 'path' +csslint = require('csslint').CSSLint module.exports = - config: - executablePath: - title: 'CSSLint Executable Path' - type: 'string' - # default: path.join(__dirname, '..', 'node_modules', '.bin', 'csslint.cmd') - default: 'csslint' - description: 'Path of the `csslint` executable.' - activate: -> - @subscriptions = new CompositeDisposable - @subscriptions.add atom.config.observe 'linter-csslint.executablePath', - (executablePath) => - @executablePath = executablePath - - deactivate: -> - @subscriptions.dispose() + @rules = csslint.getRules() provideLinter: -> helpers = require('atom-linter') provider = grammarScopes: ['source.css', 'source.html'] scope: 'file' - lintOnFly: false # FIXME + lintOnFly: true lint: (textEditor) => filePath = textEditor.getPath() text = textEditor.getText() - parameters = ['--format=lint-xml', filePath] - return helpers.exec(@executablePath, parameters, {stdin: text}).then (output) -> - toReturn = [] - parseString output, (err, result) -> - for issue in result.lint.file[0].issue - data = issue['$'] - line = parseInt(data.line, 10) - 1 - char = parseInt(data.char, 10) - 1 - toReturn.push({ - type: data.severity.charAt(0).toUpperCase() + data.severity.slice(1), - text: data.reason, - filePath: filePath - range: [[line, char], [line, char]], - trace: [{ - type: "Trace", - text: data.evidence, - range: [[line, char], [line, char]] - }] - }) - return toReturn + ruleset = @rules + lintResult = csslint.verify(text, ruleset) + if lintResult.messages.length < 1 + return [] + toReturn = [] + for data in lintResult.messages + line = data.line - 1 + col = data.col - 1 + toReturn.push({ + type: data.type.charAt(0).toUpperCase() + data.type.slice(1), + text: data.message, + filePath: filePath + range: [[line, col], [line, col]], + trace: [{ + type: "Text", + text: '[' + data.rule.id + '] ' + data.rule.desc + }] + }) + return toReturn diff --git a/package.json b/package.json index e4972dd..3121c87 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,7 @@ "repository": "https://github.com/AtomLinter/linter-csslint", "license": "MIT", "dependencies": { - "csslint": "~0.10.0", - "atom-linter": "^2.0.1", - "xml2js": "^0.4.9" + "csslint": "~0.10.0" }, "providedServices": { "linter": { From 93c4bb6869722de5a45460acb0b4c6a338955966 Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Mon, 27 Jul 2015 23:11:38 -0700 Subject: [PATCH 7/8] Add support for .csslintrc files Adds support for a .csslintrc file in the same directory as the file being linted. --- lib/main.coffee | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/main.coffee b/lib/main.coffee index d4b0fd7..bc498fd 100644 --- a/lib/main.coffee +++ b/lib/main.coffee @@ -1,4 +1,20 @@ csslint = require('csslint').CSSLint +path = require('path') +fs = require('fs') + +# Adapted from cli/common.js in CSSLint +gatherRules = (options, ruleset) -> + warnings = options.rules or options.warnings + errors = options.errors + if warnings + ruleset = ruleset or {} + warnings.split(",").map (value) -> + ruleset[value] = 1 + if errors + ruleset = ruleset or {} + errors.split(",").map (value) -> + ruleset[value] = 2 + return ruleset module.exports = activate: -> @@ -13,7 +29,14 @@ module.exports = lint: (textEditor) => filePath = textEditor.getPath() text = textEditor.getText() - ruleset = @rules + settingRules = @rules + try + configData = fs.readFileSync(path.join(path.dirname(filePath), '.csslintrc'), "utf-8") + if configData + fileConfig = JSON.parse(configData) + else + fileConfig = {} + ruleset = gatherRules(fileConfig, settingRules) lintResult = csslint.verify(text, ruleset) if lintResult.messages.length < 1 return [] From 75fcbeeeac04a49024b298614b107943af59e677 Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Tue, 28 Jul 2015 22:11:06 -0700 Subject: [PATCH 8/8] Exec async using node Move to the AtomLinter/csslint for until `stdin` and `JSON` support are implemented in the main repository. Use helpers.execNode to run the linter. --- lib/main.coffee | 69 +++++++++++++++++-------------------------------- package.json | 3 ++- 2 files changed, 25 insertions(+), 47 deletions(-) diff --git a/lib/main.coffee b/lib/main.coffee index bc498fd..d8bbbb6 100644 --- a/lib/main.coffee +++ b/lib/main.coffee @@ -1,57 +1,34 @@ -csslint = require('csslint').CSSLint +helpers = require('atom-linter') path = require('path') -fs = require('fs') - -# Adapted from cli/common.js in CSSLint -gatherRules = (options, ruleset) -> - warnings = options.rules or options.warnings - errors = options.errors - if warnings - ruleset = ruleset or {} - warnings.split(",").map (value) -> - ruleset[value] = 1 - if errors - ruleset = ruleset or {} - errors.split(",").map (value) -> - ruleset[value] = 2 - return ruleset module.exports = - activate: -> - @rules = csslint.getRules() - provideLinter: -> helpers = require('atom-linter') provider = grammarScopes: ['source.css', 'source.html'] scope: 'file' lintOnFly: true - lint: (textEditor) => + lint: (textEditor) -> filePath = textEditor.getPath() text = textEditor.getText() - settingRules = @rules - try - configData = fs.readFileSync(path.join(path.dirname(filePath), '.csslintrc'), "utf-8") - if configData - fileConfig = JSON.parse(configData) - else - fileConfig = {} - ruleset = gatherRules(fileConfig, settingRules) - lintResult = csslint.verify(text, ruleset) - if lintResult.messages.length < 1 - return [] - toReturn = [] - for data in lintResult.messages - line = data.line - 1 - col = data.col - 1 - toReturn.push({ - type: data.type.charAt(0).toUpperCase() + data.type.slice(1), - text: data.message, - filePath: filePath - range: [[line, col], [line, col]], - trace: [{ - type: "Text", - text: '[' + data.rule.id + '] ' + data.rule.desc - }] - }) - return toReturn + parameters = ['--format=json', '-'] + exec = path.join(__dirname, '..', 'node_modules', 'csslint', 'cli.js') + helpers.execNode(exec, parameters, {stdin: text}).then (output) -> + lintResult = JSON.parse(output) + toReturn = [] + if lintResult.messages.length < 1 + return toReturn + for data in lintResult.messages + line = data.line - 1 + col = data.col - 1 + toReturn.push({ + type: data.type.charAt(0).toUpperCase() + data.type.slice(1), + text: data.message, + filePath: filePath + range: [[line, col], [line, col]], + trace: [{ + type: "Text", + text: '[' + data.rule.id + '] ' + data.rule.desc + }] + }) + return toReturn diff --git a/package.json b/package.json index 3121c87..4d68912 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "repository": "https://github.com/AtomLinter/linter-csslint", "license": "MIT", "dependencies": { - "csslint": "~0.10.0" + "csslint": "AtomLinter/csslint", + "atom-linter": "^3.0.0" }, "providedServices": { "linter": {