Repository: lesshint/lesshint
Pull request #402 (2017-07-05 13:55:02)

Fix column reporting in spaceAroundOperator
<!--
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!
-->

**Which issue, if any, does this resolve?**
#343

**Is there anything in this PR that needs extra explaining or should something specific be focused on?**
No, should be pretty straightforward.


Patch:
diff --git a/lib/linters/single_line_per_property.js b/lib/linters/single_line_per_property.js
index d427168..2a27186 100644
--- a/lib/linters/single_line_per_property.js
+++ b/lib/linters/single_line_per_property.js
@@ -30,8 +30,10 @@ module.exports = {
             return;
         }
 
+        const nodeEnd = node.source.end || {};
+
         if (config.allowSingleLineRules) {
-            if (node.source.start.line === node.source.end.line && node.nodes.length === 1) {
+            if (node.source.start.line === nodeEnd.line && node.nodes.length === 1) {
                 return;
             }
         }
@@ -45,10 +47,12 @@ module.exports = {
             }
 
             const validBefore = hasNewlineBefore(child);
+            const childEnd = child.source.end || {};
+
             let validAfter = isValidAfter(child, index);
 
             // Check if the closing bracket is on the same line as the last property
-            if (index === node.nodes.length - 1 && child.source.end.line === node.source.end.line) {
+            if (index === node.nodes.length - 1 && childEnd.line === nodeEnd.line) {
                 validAfter = false;
             }
 
diff --git a/lib/linters/space_after_property_value.js b/lib/linters/space_after_property_value.js
index b420ce2..8236631 100644
--- a/lib/linters/space_after_property_value.js
+++ b/lib/linters/space_after_property_value.js
@@ -8,6 +8,7 @@ module.exports = {
     message: 'Semicolon after property value should%s be preceded by %s space.',
 
     lint: function spaceAfterPropertyValueLinter (config, node) {
+        const nodeEnd = node.source.end || {};
         const results = [];
 
         switch (config.style) {
@@ -15,7 +16,7 @@ module.exports = {
                 if (/.*\s$/.test(node.raws.important) || node.raws.value && /.*\s$/.test(node.raws.value.raw)) {
                     results.push({
                         column: node.source.start.column + node.prop.length + node.raws.between.length + node.value.length,
-                        line: node.source.end.line,
+                        line: nodeEnd.line,
                         message: util.format(this.message, ' not', 'any')
                     });
                 }
@@ -25,7 +26,7 @@ module.exports = {
                 if (!/.*\s$/.test(node.raws.important) && !node.raws.value) {
                     results.push({
                         column: node.source.start.column + node.prop.length + node.raws.between.length + node.value.length,
-                        line: node.source.end.line,
+                        line: nodeEnd.line,
                         message: util.format(this.message, '', 'one')
                     });
                 }
diff --git a/lib/linters/space_around_operator.js b/lib/linters/space_around_operator.js
index d54f582..30bbe67 100644
--- a/lib/linters/space_around_operator.js
+++ b/lib/linters/space_around_operator.js
@@ -39,21 +39,20 @@ module.exports = {
                 return;
             }
 
-            let startElement;
+            let operator;
             let message;
 
             switch (config.style) {
                 case 'both':
-                    if (child.raws.before !== ' ' || !/^\s/.test(child.raws.before) ||
-                        nextElement.raws.before !== ' ' || !/\s$/.test(nextElement.raws.before)) {
-                        startElement = !/\s$/.test(child.raws.before) ? child : nextElement;
+                    if (child.raws.before !== ' ' || !/^\s/.test(child.raws.before) || nextElement.raws.before !== ' ' || !/\s$/.test(nextElement.raws.before)) {
+                        operator = child.value;
                         message = util.format(this.message, '', 'preceded and followed', 'one');
                     }
 
                     break;
                 case 'none':
                     if (child.raws.before || nextElement.raws.before) {
-                        startElement = child.raws.before ? child : nextElement;
+                        operator = child.value;
                         message = util.format(this.message, ' not', 'preceded nor followed', 'any');
                     }
 
@@ -63,8 +62,13 @@ module.exports = {
             }
 
             if (message) {
+                const position = node.positionBy({
+                    word: operator
+                });
+
                 results.push({
-                    column: node.source.start.column + node.prop.length + node.raws.between.length + startElement.source.start.column + 1,
+                    column: position.column,
+                    line: position.line,
                     message: message
                 });
             }


Test patch:
diff --git a/test/specs/linters/space_around_operator.js b/test/specs/linters/space_around_operator.js
index 6578500..ec539c5 100644
--- a/test/specs/linters/space_around_operator.js
+++ b/test/specs/linters/space_around_operator.js
@@ -35,7 +35,8 @@ describe('lesshint', function () {
             it('should not allow missing space before operator', function () {
                 const source = 'height: calc(10px+ 10px);';
                 const expected = [{
-                    column: 20,
+                    column: 18,
+                    line: 1,
                     message: 'Operators should be preceded and followed by one space.'
                 }];
 
@@ -49,7 +50,8 @@ describe('lesshint', function () {
             it('should not allow missing space after operator', function () {
                 const source = 'height: calc(10px +10px);';
                 const expected = [{
-                    column: 22,
+                    column: 19,
+                    line: 1,
                     message: 'Operators should be preceded and followed by one space.'
                 }];
 
@@ -63,7 +65,8 @@ describe('lesshint', function () {
             it('should not allow missing space before and after operator', function () {
                 const source = 'height: calc(10px+10px);';
                 const expected = [{
-                    column: 20,
+                    column: 18,
+                    line: 1,
                     message: 'Operators should be preceded and followed by one space.'
                 }];
 
@@ -175,7 +178,8 @@ describe('lesshint', function () {
             it('should not allow one space before operator', function () {
                 const source = 'height: calc(10px +10px);';
                 const expected = [{
-                    column: 21,
+                    column: 19,
+                    line: 1,
                     message: 'Operators should not be preceded nor followed by any space.'
                 }];
 
@@ -189,7 +193,8 @@ describe('lesshint', function () {
             it('should not allow one space after operator', function () {
                 const source = 'height: calc(10px+ 10px);';
                 const expected = [{
-                    column: 22,
+                    column: 18,
+                    line: 1,
                     message: 'Operators should not be preceded nor followed by any space.'
                 }];
 
@@ -203,7 +208,8 @@ describe('lesshint', function () {
             it('should not allow a space after operator in shorthand values', function () {
                 const source = 'margin: 10px - 1px 0px 20px;';
                 const expected = [{
-                    column: 16,
+                    column: 14,
+                    line: 1,
                     message: 'Operators should not be preceded nor followed by any space.'
                 }];