Repository: lesshint/lesshint (js)

Issue:
Warnings cause exit code 1 by default
> Passing -1 to the --max-warnings flag is no longer supported. Simply omit the flag for the same behavior.

Ref: https://github.com/lesshint/lesshint/releases/tag/v3.0.0 

**Which version of `lesshint` are you using?** 
3.3.1.

Executing: `lesshint ./src` (without `-x` flag), exits with code 1 and breaks my build.

**What did you expect to happen?** 
Exit with code 0.

**What's the actual result?** 
Exit with code 1.

I did try with `-x false` etc., but it's always the same effect. It only works when I use a number, but I don't want to do that. For sure it doesn't work as states in the docs.

Pull request description:
Warnings gives exit code 0
<!--
If you're submitting a PR for a new feature, please open an issue about it first so we can discuss it.
If you're submitting a PR for something else, for example a documentation fix, go right ahead!
-->

**Changes proposed in this PR:** 
Changed the approach of exit codes to:
- Linting errors with a severity of `warning` gives exit code `0`
  - Unless `--max-warnings` flag is set and the number of linting errors with a severity of `warning` is greater than the given value. Then it gives exit code `1`
- Linting errors with a severity of `error` gives exit code `1`

**Which issue, if any, does this resolve?** 
Will close #394. 

**Is there anything in this PR that needs extra explaining or should something specific be focused on?** 
The whole logic was already discussed in corresponding GitHub issue (#394).

@jwilsson please take a look.


Patch:
diff --git a/.eslintrc.json b/.eslintrc.json
index f282033..170c98f 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,61 +1,3 @@
 {
-  "extends": "eslint:recommended",
-  "ecmaVersion": 2015,
-  "env": {
-    "es6": true,
-    "mocha": true,
-    "node": true
-  },
-  "rules": {
-    "array-bracket-spacing": "error",
-    "arrow-body-style": ["error", "always"],
-    "arrow-parens": "error",
-    "brace-style": "error",
-    "camelcase": "error",
-    "comma-dangle": "off",
-    "comma-spacing": "error",
-    "comma-style": "error",
-    "computed-property-spacing": "error",
-    "curly": "error",
-    "dot-location": ["error", "property"],
-    "dot-notation": "error",
-    "eol-last": "error",
-    "eqeqeq": "error",
-    "guard-for-in": "error",
-    "indent": ["error", 4, {
-        "SwitchCase": 1,
-        "VariableDeclarator": 0
-    }],
-    "key-spacing": "error",
-    "keyword-spacing": ["error", {
-        "after": true,
-        "before": true
-    }],
-    "no-bitwise": "error",
-    "no-caller": "error",
-    "no-console": "error",
-    "no-const-assign": "error",
-    "no-else-return": "error",
-    "no-eval": "error",
-    "no-extend-native": "error",
-    "no-lonely-if": "error",
-    "no-loop-func": "error",
-    "no-multi-spaces": "error",
-    "no-trailing-spaces": "error",
-    "no-var": "error",
-    "prefer-const": "error",
-    "quotes": ["error", "single", "avoid-escape"],
-    "semi": "error",
-    "space-before-blocks": "error",
-    "space-before-function-paren": "error",
-    "space-in-parens": "error",
-    "space-infix-ops": "error",
-    "space-unary-ops": ["error", {
-        "nonwords": false,
-        "words": true
-    }],
-    "strict": ["error", "global"],
-    "template-curly-spacing": ["error", "always"],
-    "yoda": "error"
-  }
+    "extends": "lesshint"
 }
diff --git a/README.md b/README.md
index 8b6120f..2d8725c 100644
--- a/README.md
+++ b/README.md
@@ -43,16 +43,15 @@ Available Flags         | Description
 `-l`/`--linters`      | Paths to custom linters to add to the built-in list. See "Linters" below for more information.
 `-r`/`--reporter`     | The reporter to use. See "Reporters" below for more information.
 `-V`/`--version`      | Show the version.
-`-x`/`--max-warnings` | Number of warnings to allow before exiting with a non-zero code.
+`-x`/`--max-warnings` | Number of warnings to allow before exiting with a non-zero code. Omit it to always exit with zero code.
 
 ### Exit status codes
 Depending on the linter results and options supplied, the exit status code returned by the CLI will differ.
 
 Exit status code   | Description
 -------------------|----------------------------------------------
-`0`                | Everything is alright, no linting errors found.
-`1`                | One or more linting errors with a severity of `warning` was found.
-`2`                | One or more linting errors with a severity of `error` was found.
+`0`                | Everything is alright or only linting errors with a severity of `warning` were found.
+`1`                | One or more linting errors with a severity of `error` were found. Or when `--max-warnings` flag is set and the number of linting errors with a severity of `warning` found is greater than the given value.
 `66`               | No files to lint were supplied.
 `70`               | An unknown error occurred within `lesshint`, possibly a bug. [Please file an issue!](https://github.com/lesshint/lesshint/issues/new)
 `78`               | Something is wrong with the config file, most likely invalid JSON.
diff --git a/bin/lesshint b/bin/lesshint
index 28e9f09..7995e6e 100755
--- a/bin/lesshint
+++ b/bin/lesshint
@@ -18,7 +18,7 @@ program
     .option('-e, --exclude [pattern]', 'path pattern to exclude')
     .option('-l, --linters [linters]', 'paths to custom linters')
     .option('-r, --reporter [reporter]', 'reporter to use (<PATH>|stylish), defaults to "stylish"')
-    .option('-x, --max-warnings [int]', 'Number of warnings to trigger nonzero exit code, defaults to 0')
+    .option('-x, --max-warnings [int]', 'Number of warnings to trigger nonzero exit code, defaults to unlimited')
     .parse(process.argv);
 
 const output = function (result) {
diff --git a/lib/linter.js b/lib/linter.js
index 815d409..2fab821 100644
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -1,6 +1,7 @@
 'use strict';
 
 const postcssLess = require('postcss-less');
+const stringify = require('postcss-less/dist/less-stringify');
 const sortBy = require('lodash.sortby');
 const merge = require('lodash.merge');
 const postcss = require('postcss');
@@ -48,12 +49,6 @@ const defaultLinters = [
     require('./linters/zero_unit')
 ];
 
-/**
-  * Tests selectors for pseudo classes/selectors. eg. :not(), :active
-  * Temporary fix for https://github.com/webschik/postcss-less/issues/56
-  */
-const rPseudo = /::?[^ ,:.]+/g;
-
 class Linter {
     constructor (source, fullPath, options) {
         // Include trailing line endings, needs to run before any normalization
@@ -63,7 +58,9 @@ class Linter {
 
         const tree = this.parse(source);
 
-        this.ast = tree.root.toResult();
+        this.ast = tree.root.toResult({
+            stringifier: stringify
+        });
         this.ast = Object.freeze(this.ast);
 
         this.filename = path.basename(fullPath);
@@ -94,21 +91,6 @@ class Linter {
                 return;
             }
 
-            // if we're dealing with a regular Rule (or other) node, which isn't
-            // an actual Mixin or AtRule, and its selector contains a pseudo
-            // class or selector, then clean up the raws and params properties.
-            // tracking: https://github.com/webschik/postcss-less/issues/56
-            // TODO: remove this when issue resolved
-            if (node.params && rPseudo.test(node.selector)) {
-                delete node.params;
-
-                // this just started showing up in postcss-less@0.14.0. not sure
-                // if it's sticking around, but making sure we're thorough.
-                if (node.raws.params) {
-                    delete node.raws.params;
-                }
-            }
-
             const lint = linter.lint.call(linter, options, node);
 
             if (lint) {
diff --git a/lib/linters/duplicate_property.js b/lib/linters/duplicate_property.js
index 06e2534..dd3c6b2 100644
--- a/lib/linters/duplicate_property.js
+++ b/lib/linters/duplicate_property.js
@@ -20,7 +20,7 @@ module.exports = {
                 return true;
             }
 
-            if (!decl.prop.match(/\+\_?$/) && properties.indexOf(decl.prop) >= 0) {
+            if (!decl.prop.match(/\+_?$/) && properties.indexOf(decl.prop) >= 0) {
                 results.push({
                     message: util.format(this.message, decl.prop),
                     column: decl.source.start.column,
diff --git a/lib/linters/empty_rule.js b/lib/linters/empty_rule.js
index cfabb75..3eefb84 100644
--- a/lib/linters/empty_rule.js
+++ b/lib/linters/empty_rule.js
@@ -7,7 +7,7 @@ module.exports = {
 
     lint: function emptyRuleLinter (config, node) {
         // If it's a bodiless rule or a mixin function definition, bail.
-        if (node.ruleWithoutBody || node.params) {
+        if (node.empty || node.params) {
             return;
         }
 
@@ -17,8 +17,9 @@ module.exports = {
          */
         let hasDeclarations = false;
 
+        const nodeTypes = ['atrule', 'decl', 'import'];
         node.walk(function (child) {
-            if (child.type === 'decl' || child.type === 'atrule' || (child.type === 'rule' && child.ruleWithoutBody)) {
+            if (nodeTypes.indexOf(child.type) !== -1 || (child.type === 'rule' && child.empty)) {
                 hasDeclarations = true;
 
                 return false;
diff --git a/lib/linters/id_selector.js b/lib/linters/id_selector.js
index 9553496..5c250ab 100644
--- a/lib/linters/id_selector.js
+++ b/lib/linters/id_selector.js
@@ -11,7 +11,7 @@ module.exports = {
         const tree = parseSelector(node.selector);
         const excludes = config.exclude.map((id) => {
             // Remove #
-            return id.replace(/^\#/, '');
+            return id.replace(/^#/, '');
         });
 
         const results = [];
diff --git a/lib/linters/import_path.js b/lib/linters/import_path.js
index 118607c..ba4694d 100644
--- a/lib/linters/import_path.js
+++ b/lib/linters/import_path.js
@@ -7,24 +7,14 @@ const util = require('util');
 
 module.exports = {
     name: 'importPath',
-    nodeTypes: ['atrule'],
+    nodeTypes: ['import'],
     message: {
         extension: 'Imported file, "%s" should%s include the file extension.',
         underscore: 'Imported file, "%s" should%s include a leading underscore.'
     },
 
     lint: function importPathLinter (config, node) {
-        if (node.name !== 'import') {
-            return;
-        }
-
-        /**
-         * Temporary fix for https://github.com/lesshint/lesshint/issues/236
-         * TODO: postcss-less really needs to be fixed to make this proper.
-         */
-        const importOptsRx = /(\s+)?\((\s+)?(reference|inline|less|css|once|multiple|optional)(\s+)?\)(\s+)?/gi;
-        const params = node.params.replace(importOptsRx, '');
-        const ast = parseValue(params);
+        const ast = parseValue(node.importPath);
 
         let value = ast.first.first;
 
@@ -41,14 +31,17 @@ module.exports = {
         }
 
         const results = [];
+        const position = node.positionBy({
+            word: value.value
+        });
 
         // Check extension
         switch (config.filenameExtension) {
             case false:
                 if (path.extname(file) === '.less') {
                     results.push({
-                        column: node.source.start.column + node.name.length + value.source.start.column + 1,
-                        line: node.source.start.line,
+                        column: position.column,
+                        line: position.line,
                         message: util.format(this.message.extension, file, ' not')
                     });
                 }
@@ -57,8 +50,8 @@ module.exports = {
             case true:
                 if (!path.extname(file)) {
                     results.push({
-                        column: node.source.start.column + node.name.length + value.source.start.column + 1,
-                        line: node.source.start.line,
+                        column: position.column,
+                        line: position.line,
                         message: util.format(this.message.extension, file, '')
                     });
                 }
@@ -71,8 +64,8 @@ module.exports = {
             case false:
                 if (/^_/.test(file)) {
                     results.push({
-                        column: node.source.start.column + node.name.length + value.source.start.column + 1,
-                        line: node.source.start.line,
+                        column: position.column,
+                        line: position.line,
                         message: util.format(this.message.underscore, file, ' not')
                     });
                 }
@@ -81,8 +74,8 @@ module.exports = {
             case true:
                 if (!/^_/.test(file)) {
                     results.push({
-                        column: node.source.start.column + node.name.length + value.source.start.column + 1,
-                        line: node.source.start.line,
+                        column: position.column,
+                        line: position.line,
                         message: util.format(this.message.underscore, file, '')
                     });
                 }
diff --git a/lib/linters/newline_after_block.js b/lib/linters/newline_after_block.js
index 9809f87..3088644 100644
--- a/lib/linters/newline_after_block.js
+++ b/lib/linters/newline_after_block.js
@@ -12,9 +12,9 @@ module.exports = {
         prev = parent.nodes[prev] || {};
 
         // Ignore at-rules without a body
-        if (node.ruleWithoutBody || (node.type === 'atrule' && !node.nodes)) {
+        if (node.empty || (node.type === 'atrule' && !node.nodes)) {
             /**
-             * Hopefully node.ruleWithoutBody will be implemented on AtRule nodes
+             * Hopefully node.empty will be implemented on AtRule nodes
              * in the future: https://github.com/webschik/postcss-less/issues/55
              */
             return;
diff --git a/lib/linters/single_line_per_property.js b/lib/linters/single_line_per_property.js
index 3a5c0eb..d427168 100644
--- a/lib/linters/single_line_per_property.js
+++ b/lib/linters/single_line_per_property.js
@@ -26,7 +26,7 @@ module.exports = {
     message: 'Each property should be on its own line.',
 
     lint: function singleLinePerPropertyLinter (config, node) {
-        if (node.ruleWithoutBody) {
+        if (node.empty) {
             return;
         }
 
@@ -36,7 +36,7 @@ module.exports = {
             }
         }
 
-        const types = ['decl', 'rule', 'atrule'];
+        const types = ['atrule', 'decl', 'import', 'rule'];
         const results = [];
 
         node.nodes.forEach((child, index) => {
diff --git a/lib/linters/space_before_brace.js b/lib/linters/space_before_brace.js
index 8f854a7..3dbd542 100644
--- a/lib/linters/space_before_brace.js
+++ b/lib/linters/space_before_brace.js
@@ -24,9 +24,9 @@ module.exports = {
          * If the node is a bodiless rule, or it's an import statement, or we
          * are dealing with an atrule without a body, bail.
          */
-        if (node.ruleWithoutBody || node.name === 'import' ||
+        if (node.empty || node.name === 'import' ||
            /**
-            * Hopefully node.ruleWithoutBody will be implemented on AtRule nodes
+            * Hopefully node.empty will be implemented on AtRule nodes
             * in the future: https://github.com/webschik/postcss-less/issues/55
             */
            (node.type === 'atrule' && !node.nodes)) {
diff --git a/lib/linters/string_quotes.js b/lib/linters/string_quotes.js
index 68ed78c..9c526d4 100644
--- a/lib/linters/string_quotes.js
+++ b/lib/linters/string_quotes.js
@@ -6,7 +6,7 @@ const util = require('util');
 
 module.exports = {
     name: 'stringQuotes',
-    nodeTypes: ['atrule', 'decl', 'rule'],
+    nodeTypes: ['atrule', 'decl', 'import', 'rule'],
     message: 'Strings should use %s quotes.',
 
     lint: function stringQuotesLinter (config, node) {
@@ -20,46 +20,27 @@ module.exports = {
         }
 
         const results = [];
+        let tree;
 
-        if (node.type === 'atrule') {
-            /**
-             * Hopefully node.ruleWithoutBody will be implemented on AtRule nodes
-             * in the future: https://github.com/webschik/postcss-less/issues/55
-             */
-            if (node.nodes) {
-                return;
-            }
-
-            // Not a string, bail
-            if (!(/"|'/.test(node.params))) {
-                return;
-            }
-
-            if (!quotes[config.style].test(node.params)) {
-                const column = (node.raws.afterName ? node.raws.afterName.length : 0) +
-                         node.source.start.column +
-                         node.name.length + 1;
-
-                results.push({
-                    column: column,
-                    line: node.source.start.line,
-                    message: util.format(this.message, config.style)
-                });
-            }
-        } else if (node.type === 'decl') {
-            const ast = parseValue(node.value);
+        switch (node.type) {
+            case 'atrule':
+                /**
+                 * Hopefully node.empty will be implemented on AtRule nodes
+                 * in the future: https://github.com/webschik/postcss-less/issues/55
+                 */
+                if (node.nodes) {
+                    return;
+                }
 
-            ast.first.walk((decl) => {
-                if (decl.type !== 'string') {
+                // Not a string, bail
+                if (!(/"|'/.test(node.params))) {
                     return;
                 }
 
-                if (!quotes[config.style].test(decl.raws.quote)) {
-                    const column = (node.raws.between ? node.raws.between.length : 0) +
+                if (!quotes[config.style].test(node.params)) {
+                    const column = (node.raws.afterName ? node.raws.afterName.length : 0) +
                              node.source.start.column +
-                             node.prop.length +
-                             decl.source.start.column -
-                             decl.raws.quote.length;
+                             node.name.length + 1;
 
                     results.push({
                         column: column,
@@ -67,14 +48,42 @@ module.exports = {
                         message: util.format(this.message, config.style)
                     });
                 }
-            });
-        } else {
-            const selectors = parseSelector(node.selector);
 
-            selectors.walkAttributes((selector) => {
-                if (selector.quoted && !quotes[config.style].test(selector.value)) {
-                    const column = node.source.start.column + selector.source.start.column
-                             + selector.attribute.length + selector.operator.length;
+                break;
+            case 'decl':
+                tree = parseValue(node.value);
+
+                tree.first.walk((decl) => {
+                    if (decl.type !== 'string') {
+                        return;
+                    }
+
+                    if (!quotes[config.style].test(decl.raws.quote)) {
+                        const column = (node.raws.between ? node.raws.between.length : 0) +
+                                 node.source.start.column +
+                                 node.prop.length +
+                                 decl.source.start.column -
+                                 decl.raws.quote.length;
+
+                        results.push({
+                            column: column,
+                            line: node.source.start.line,
+                            message: util.format(this.message, config.style)
+                        });
+                    }
+                });
+
+                break;
+            case 'import':
+                // Not a string, bail
+                if (!(/"|'/.test(node.importPath))) {
+                    return;
+                }
+
+                if (!quotes[config.style].test(node.importPath)) {
+                    const column = (node.raws.afterName ? node.raws.afterName.length : 0) +
+                             node.source.start.column +
+                             node.name.length + 1;
 
                     results.push({
                         column: column,
@@ -82,7 +91,23 @@ module.exports = {
                         message: util.format(this.message, config.style)
                     });
                 }
-            });
+
+                break;
+            default:
+                tree = parseSelector(node.selector);
+
+                tree.walkAttributes((selector) => {
+                    if (selector.quoted && !quotes[config.style].test(selector.value)) {
+                        const column = node.source.start.column + selector.source.start.column
+                                 + selector.attribute.length + selector.operator.length;
+
+                        results.push({
+                            column: column,
+                            line: node.source.start.line,
+                            message: util.format(this.message, config.style)
+                        });
+                    }
+                });
         }
 
         if (results.length) {
diff --git a/lib/linters/url_quotes.js b/lib/linters/url_quotes.js
index ecbd708..db91e68 100644
--- a/lib/linters/url_quotes.js
+++ b/lib/linters/url_quotes.js
@@ -5,56 +5,71 @@ const parseValue = require('../utils/parse-value');
 
 module.exports = {
     name: 'urlQuotes',
-    nodeTypes: ['decl', 'atrule'],
+    nodeTypes: ['atrule', 'decl', 'import'],
     message: 'URLs should be enclosed in quotes.',
 
     lint: function urlQuotesLinter (config, node) {
         // Nothing to check, bail
-        if (!node.params && !node.value) {
+        if (!node.params && !node.value && !node.importPath) {
             return;
         }
 
-        const rDouble = /^\"(.+)\"$/;
-        const rSingle = /^\'(.+)\'$/;
+        const rDouble = /^"(.+)"$/;
+        const rSingle = /^'(.+)'$/;
         const results = [];
 
-        /**
-         * Traverse all child value-nodes
-         * https://github.com/lesshint/lesshint/issues/225
-         */
-        const ast = parseValue(node.params || node.value);
+        if (node.type === 'import') {
+            // If it's a Import node, we need some special handling
+            if (!rSingle.test(node.importPath) && !rDouble.test(node.importPath)) {
+                const position = node.positionBy({
+                    word: node.importPath
+                });
 
-        ast.first.nodes.forEach((child) => {
-            if (child.type !== 'func' || child.value !== 'url') {
-                return;
+                results.push({
+                    column: position.column,
+                    line: position.line,
+                    message: this.message
+                });
             }
+        } else {
+            /**
+             * Traverse all child value-nodes
+             * https://github.com/lesshint/lesshint/issues/225
+             */
+            const ast = parseValue(node.params || node.value);
 
-            // skip over the 'paren' node; the following node is the value node.
-            const uri = child.first.next();
-            const value = uri.value.trim();
+            ast.first.nodes.forEach((child) => {
+                if (child.type !== 'func' || child.value !== 'url') {
+                    return;
+                }
 
-            if (isVariable(value)) {
-                return;
-            }
+                // skip over the 'paren' node; the following node is the value node.
+                const uri = child.first.next();
+                const value = uri.value.trim();
 
-            /**
-             * postcss-values-parser has a bug with url string params surrounded by
-             * spaces. So account for that here.
-             * Tracking: https://github.com/lesshint/postcss-values-parser/issues/1
-             */
-            if ((uri.type === 'word' && !(rSingle.test(value) || rDouble.test(value))) && uri.type !== 'string') {
-                const column = (node.raws.between ? node.raws.between.length : 0) +
-                         node.source.start.column +
-                         (node.prop || node.name).length +
-                         uri.source.start.column - 1;
+                if (isVariable(value)) {
+                    return;
+                }
 
-                results.push({
-                    column: column,
-                    line: node.source.start.line,
-                    message: this.message
-                });
-            }
-        });
+                /**
+                 * postcss-values-parser has a bug with url string params surrounded by
+                 * spaces. So account for that here.
+                 * Tracking: https://github.com/lesshint/postcss-values-parser/issues/1
+                 */
+                if ((uri.type === 'word' && !(rSingle.test(value) || rDouble.test(value))) && uri.type !== 'string') {
+                    const column = (node.raws.between ? node.raws.between.length : 0) +
+                             node.source.start.column +
+                             (node.prop || node.name).length +
+                             uri.source.start.column - 1;
+
+                    results.push({
+                        column: column,
+                        line: node.source.start.line,
+                        message: this.message
+                    });
+                }
+            });
+        }
 
         if (results.length) {
             return results;
diff --git a/lib/runner.js b/lib/runner.js
index f9c2732..4328d90 100644
--- a/lib/runner.js
+++ b/lib/runner.js
@@ -6,8 +6,7 @@ const Lesshint = require('./lesshint');
 
 const EXIT_CODES = {
     OK: 0,
-    WARNING: 1,
-    ERROR: 2,
+    ERROR: 1,
     NOINPUT: 66,
     SOFTWARE: 70,
     CONFIG: 78
@@ -88,13 +87,11 @@ class Runner {
 
                 let maxWarnings;
 
-                if (isFinite(this.options.maxWarnings)) {
+                if (this.options.maxWarnings) {
                     maxWarnings = parseInt(this.options.maxWarnings, 10) || 0;
-                } else {
-                    maxWarnings = new Boolean(this.options.maxWarnings) ? 0 : -1;
                 }
 
-                if (maxWarnings === -1) {
+                if (typeof maxWarnings === 'undefined') {
                     return resolve({
                         status: EXIT_CODES.OK
                     });
@@ -107,7 +104,7 @@ class Runner {
                 if (warnings > maxWarnings) {
                     return reject(new RunnerError(
                         '',
-                        EXIT_CODES.WARNING
+                        EXIT_CODES.ERROR
                     ));
                 }
 
diff --git a/lib/utils/parse-selector.js b/lib/utils/parse-selector.js
index 5d2163b..d873d99 100644
--- a/lib/utils/parse-selector.js
+++ b/lib/utils/parse-selector.js
@@ -7,8 +7,7 @@ module.exports = function (selector) {
 
     parser((selectors) => {
         tree = selectors;
-    })
-    .process(selector);
+    }).process(selector);
 
     return tree;
 };
diff --git a/package.json b/package.json
index acb250a..79fe456 100644
--- a/package.json
+++ b/package.json
@@ -24,8 +24,8 @@
     "lodash.merge": "^4.0.1",
     "lodash.sortby": "^4.0.1",
     "minimatch": "^3.0.2",
-    "postcss": "^5.0.19",
-    "postcss-less": "^0.16.0",
+    "postcss": "^6.0.0",
+    "postcss-less": "^1.0.0",
     "postcss-selector-parser": "^2.0.0",
     "postcss-values-parser": "^1.2.1",
     "rcfinder": "^0.1.8",
@@ -33,9 +33,10 @@
   },
   "devDependencies": {
     "chai": "^4.0.1",
+    "eslint-config-lesshint": "^1.0.3",
     "gulp": "^3.9.0",
     "gulp-coveralls": "^0.1.4",
-    "gulp-eslint": "^3.0.1",
+    "gulp-eslint": "^4.0.0",
     "gulp-mocha": "^4.1.0",
     "nyc": "^11.0.1",
     "rimraf": "^2.4.2",


Test patch:
diff --git a/test/specs/bin/lesshint.js b/test/specs/bin/lesshint.js
index f2a6b08..80e8fb1 100644
--- a/test/specs/bin/lesshint.js
+++ b/test/specs/bin/lesshint.js
@@ -34,10 +34,19 @@ describe('bin/lesshint', () => {
         return assertCode(child, 0);
     });
 
-    it('should exit with 1 when errors are found', function () {
+
+    it('should exit with 0 when warnings are found', function () {
         const filePath = path.resolve(__dirname, '../../data/files/file.less');
         const child = runLesshint([filePath]);
 
+        return assertCode(child, 0);
+    });
+
+    it('should exit with 1 when errors are found', function () {
+        const configPath = path.resolve(__dirname, '../../data/config/severity-error.json');
+        const filePath = path.resolve(__dirname, '../../data/files/file.less');
+        const child = runLesshint([`--config=${ configPath }`, filePath]);
+
         return assertCode(child, 1);
     });
 
diff --git a/test/specs/cli.js b/test/specs/cli.js
index 3478bab..80b70f9 100644
--- a/test/specs/cli.js
+++ b/test/specs/cli.js
@@ -23,14 +23,14 @@ describe('cli', function () {
         }
     });
 
-    it('should exit with a non-zero status code when lint errors were found', function () {
+    it('should exit with a zero status code when lint errors were found', function () {
         const result = cli({
             args: [path.dirname(__dirname) + '/data/files/file.less'],
             config: path.resolve(process.cwd() + '/lib/config/defaults.json')
         });
 
-        return result.catch(function (result) {
-            expect(result.status).to.equal(1);
+        return result.then(function (result) {
+            expect(result.status).to.equal(0);
         });
     });
 
@@ -82,21 +82,6 @@ describe('cli', function () {
                 path.dirname(__dirname) + '/data/files/file.less',
             ],
             config: path.resolve(process.cwd() + '/lib/config/defaults.json'),
-            maxWarnings: '999',
-        });
-
-        return result.then(function (result) {
-            expect(result.status).to.equal(0);
-        });
-    });
-
-    it('should exit with a zero status code with `--max-warnings -1` even if lint has warings', function () {
-        const result = cli({
-            args: [
-                path.dirname(__dirname) + '/data/files/file.less',
-            ],
-            config: path.resolve(process.cwd() + '/lib/config/defaults.json'),
-            maxWarnings: '-1',
         });
 
         return result.then(function (result) {
@@ -165,8 +150,8 @@ describe('cli', function () {
             linters: ['../test/plugins/sampleLinter']
         });
 
-        return result.catch(function (result) {
-            expect(result.status).to.equal(1);
+        return result.then(function (result) {
+            expect(result.status).to.equal(0);
         });
     });
 
@@ -176,8 +161,8 @@ describe('cli', function () {
             config: path.resolve(process.cwd() + '/test/data/config/linters.json')
         });
 
-        return result.catch(function (result) {
-            expect(result.status).to.equal(1);
+        return result.then(function (result) {
+            expect(result.status).to.equal(0);
         });
     });
 
@@ -188,8 +173,8 @@ describe('cli', function () {
             linters: ['../test/plugins/otherSampleLinter']
         });
 
-        return result.catch(function (result) {
-            expect(result.status).to.equal(1);
+        return result.then(function (result) {
+            expect(result.status).to.equal(0);
         });
     });
 
@@ -270,7 +255,7 @@ describe('cli', function () {
         });
 
         return result.catch(function (result) {
-            expect(result.status).to.equal(2);
+            expect(result.status).to.equal(1);
         });
     });
 });
diff --git a/test/specs/linters/import_path.js b/test/specs/linters/import_path.js
index 1f21c66..8b674b9 100644
--- a/test/specs/linters/import_path.js
+++ b/test/specs/linters/import_path.js
@@ -44,7 +44,7 @@ describe('lesshint', function () {
         it('should not allow filename with extension when "filenameExtension" is "false"', function () {
             const source = '@import "foo.less";';
             const expected = [{
-                column: 9,
+                column: 10,
                 line: 1,
                 message: 'Imported file, "foo.less" should not include the file extension.'
             }];
@@ -78,7 +78,7 @@ describe('lesshint', function () {
         it('should not allow filename without extension when "filenameExtension" is "true"', function () {
             const source = '@import "foo";';
             const expected = [{
-                column: 9,
+                column: 10,
                 line: 1,
                 message: 'Imported file, "foo" should include the file extension.'
             }];
@@ -112,7 +112,7 @@ describe('lesshint', function () {
         it('should not allow filename with leading underscore when "leadingUnderscore" is "false"', function () {
             const source = '@import "_foo";';
             const expected = [{
-                column: 9,
+                column: 10,
                 line: 1,
                 message: 'Imported file, "_foo" should not include a leading underscore.'
             }];
@@ -146,7 +146,7 @@ describe('lesshint', function () {
         it('should not allow filename without leading underscore when "leadingUnderscore" is "true"', function () {
             const source = '@import "foo";';
             const expected = [{
-                column: 9,
+                column: 10,
                 line: 1,
                 message: 'Imported file, "foo" should include a leading underscore.'
             }];
@@ -167,12 +167,12 @@ describe('lesshint', function () {
             const source = '@import "_foo.less";';
             const expected = [
                 {
-                    column: 9,
+                    column: 10,
                     line: 1,
                     message: 'Imported file, "_foo.less" should not include the file extension.'
                 },
                 {
-                    column: 9,
+                    column: 10,
                     line: 1,
                     message: 'Imported file, "_foo.less" should not include a leading underscore.'
                 }
@@ -209,7 +209,7 @@ describe('lesshint', function () {
         it('should check url imports with quotes', function () {
             const source = '@import url("foo.less");';
             const expected = [{
-                column: 13,
+                column: 14,
                 line: 1,
                 message: 'Imported file, "foo.less" should not include the file extension.'
             }];
@@ -289,16 +289,6 @@ describe('lesshint', function () {
                 expect(result).to.be.undefined;
             });
         });
-
-        it('should ignore other at-rules', function () {
-            const source = '@charset "UTF-8";';
-
-            return spec.parse(source, function (ast) {
-                const result = spec.linter.lint({}, ast.root.first);
-
-                expect(result).to.be.undefined;
-            });
-        });
     });
 
     describe('#importPath() with Import Option', function () {
@@ -334,7 +324,7 @@ describe('lesshint', function () {
         it('should not allow filename with extension when "filenameExtension" is "false"', function () {
             const source = '@import (inline) "foo.less";';
             const expected = [{
-                column: 9,
+                column: 19,
                 line: 1,
                 message: 'Imported file, "foo.less" should not include the file extension.'
             }];
@@ -368,7 +358,7 @@ describe('lesshint', function () {
         it('should not allow filename without extension when "filenameExtension" is "true"', function () {
             const source = '@import (inline) "foo";';
             const expected = [{
-                column: 9,
+                column: 19,
                 line: 1,
                 message: 'Imported file, "foo" should include the file extension.'
             }];
diff --git a/test/specs/linters/string_quotes.js b/test/specs/linters/string_quotes.js
index e974709..dc0dbc4 100644
--- a/test/specs/linters/string_quotes.js
+++ b/test/specs/linters/string_quotes.js
@@ -249,7 +249,7 @@ describe('lesshint', function () {
             });
         });
 
-        it('should not allow double quotes in @-rules when "style" is "single"', function () {
+        it('should not allow double quotes in @import-rules when "style" is "single"', function () {
             const source = '@import "foo.less";';
             const expected = [{
                 column: 9,
@@ -268,7 +268,7 @@ describe('lesshint', function () {
             });
         });
 
-        it('should not allow single quotes in @-rules when "style" is "double"', function () {
+        it('should not allow single quotes in @import-rules when "style" is "double"', function () {
             const source = "@import 'foo.less';";
             const expected = [{
                 column: 9,
@@ -287,7 +287,7 @@ describe('lesshint', function () {
             });
         });
 
-        it('should allow single quotes in @-rules when "style" is "single"', function () {
+        it('should allow single quotes in @import-rules when "style" is "single"', function () {
             const source = "@import 'foo.less';";
             const options = {
                 style: 'single'
@@ -300,7 +300,7 @@ describe('lesshint', function () {
             });
         });
 
-        it('should allow double quotes in @-rules when "style" is "double"', function () {
+        it('should allow double quotes in @import-rules when "style" is "double"', function () {
             const source = '@import "foo.less";';
             const options = {
                 style: 'double'
@@ -313,6 +313,70 @@ describe('lesshint', function () {
             });
         });
 
+        it('should not allow double quotes in @-rules when "style" is "single"', function () {
+            const source = '@charset "utf-8";';
+            const expected = [{
+                column: 10,
+                line: 1,
+                message: 'Strings should use single quotes.'
+            }];
+
+            const options = {
+                style: 'single'
+            };
+
+            return spec.parse(source, function (ast) {
+                const result = spec.linter.lint(options, ast.root.first);
+
+                expect(result).to.deep.equal(expected);
+            });
+        });
+
+        it('should not allow single quotes in @-rules when "style" is "double"', function () {
+            const source = "@charset 'utf-8';";
+            const expected = [{
+                column: 10,
+                line: 1,
+                message: 'Strings should use double quotes.'
+            }];
+
+            const options = {
+                style: 'double'
+            };
+
+            return spec.parse(source, function (ast) {
+                const result = spec.linter.lint(options, ast.root.first);
+
+                expect(result).to.deep.equal(expected);
+            });
+        });
+
+        it('should allow single quotes in @-rules when "style" is "single"', function () {
+            const source = "@charset 'utf-8';";
+            const options = {
+                style: 'single'
+            };
+
+            return spec.parse(source, function (ast) {
+                const result = spec.linter.lint(options, ast.root.first);
+
+                expect(result).to.deep.undefined;
+            });
+        });
+
+        it('should allow double quotes in @-rules when "style" is "double"', function () {
+            const source = '@charset "utf-8";';
+            const options = {
+                style: 'double'
+            };
+
+            return spec.parse(source, function (ast) {
+                const result = spec.linter.lint(options, ast.root.first);
+
+                expect(result).to.deep.undefined;
+            });
+        });
+
         it('should not check irrelevant @-rules', function () {
             const source = '@media (screen) {}';
             const options = {
diff --git a/test/specs/linters/url_quotes.js b/test/specs/linters/url_quotes.js
index 385ef27..2a5640b 100644
--- a/test/specs/linters/url_quotes.js
+++ b/test/specs/linters/url_quotes.js
@@ -121,7 +121,7 @@ describe('lesshint', function () {
         it('should not allow missing quotes in imports', function () {
             const source = '@import url(http://example.com)';
             const expected = [{
-                column: 11,
+                column: 13,
                 line: 1,
                 message: 'URLs should be enclosed in quotes.'
             }];
diff --git a/test/specs/util.js b/test/specs/util.js
index 83ca691..917c00e 100644
--- a/test/specs/util.js
+++ b/test/specs/util.js
@@ -23,37 +23,11 @@ module.exports = {
             return {};
         }
 
-        // Tests selectors for pseudo classes/selectors. eg. :not(), :active
-        const rPseudo = /::?[^ ,:.]+/g;
-
         return {
             linter: rule,
             parser: linter.parse,
             parse: function (source, callback) {
                 return linter.parse(source).then(function (ast) {
-                    /**
-                     * If we're dealing with a regular Rule (or other) node, which isn't
-                     * an actual Mixin or AtRule, and its selector contains a pseudo
-                     * class or selector, then clean up the raws and params properties.
-                     * If we don't have this here, then the tests never get the same
-                     * modified nodes.
-                     * Tracking: https://github.com/webschik/postcss-less/issues/56
-                     * TODO: remove this when issue resolved
-                     */
-                    ast.root.walk(function (node) {
-                        if (node.params && rPseudo.test(node.selector)) {
-                            delete node.params;
-
-                            /**
-                             * This just started showing up in postcss-less@0.14.0. not sure
-                             * if it's sticking around, but making sure we're thorough.
-                             */
-                            if (node.raws.params) {
-                                delete node.raws.params;
-                            }
-                        }
-                    });
-
                     callback && callback(ast);
                 });
             }