Repository: stylelint-scss/stylelint-scss (js)

Issue:
False positive scss/operator-no-unspaced  Expected single space after "-"
Input:

```
@mixin test {
  @for $i from 0 through 10 {
    &:nth-child(#{$i + 1}) {
      top: #{$i * -10}px;
      transform: scale(#{(10 - $i) * 0.1}) !important;
    }
  }
}
```
Require:

```
@mixin test {
  @for $i from 0 through 10 {
    &:nth-child(#{$i + 1}) {
      top: #{$i * - 10}px;
      transform: scale(#{(10 - $i) * 0.1}) !important;
    }
  }
}
```
Expected (no errors):

```
@mixin test {
  @for $i from 0 through 10 {
    &:nth-child(#{$i + 1}) {
      top: #{$i * -10}px;
      transform: scale(#{(10 - $i) * 0.1}) !important;
    }
  }
}
```

Pull request:
operator-no-unspaced: fix false positive
Fixes #561

Patch:
diff --git a/src/utils/sassValueParser/index.js b/src/utils/sassValueParser/index.js
index 3d1d79c..5508fd0 100644
--- a/src/utils/sassValueParser/index.js
+++ b/src/utils/sassValueParser/index.js
@@ -358,6 +358,11 @@ function checkMinus(string, index) {
         return "sign";
       }
 
+      // e.g. `#{$i * -10}px`
+      if (isWhitespaceBefore && isNumberAfter_.is && isPrecedingOperator_) {
+        return "sign";
+      }
+
       return "op";
     }
 
@@ -726,7 +731,9 @@ function isStringBefore(before) {
   ) {
     result.is = true;
   } else if (
-    stringOpsClipped.search(/(?:^|[/(){},: ])([a-zA-Z_][\w-]*|-+[a-zA-Z_][\w-]*)$/) !== -1
+    stringOpsClipped.search(
+      /(?:^|[/(){},: ])([a-zA-Z_][\w-]*|-+[a-zA-Z_][\w-]*)$/
+    ) !== -1
   ) {
     // First pattern: a1, a1a, a-1,
     result.is = true;
@@ -742,7 +749,10 @@ function isStringAfter(after) {
   if (stringTrimmed[0] === '"' || stringTrimmed[0] === "'") return true;
 
   // e.g. `a1`, `a1a`, `a-1`, and even `--s323`
-  return stringTrimmed.search(/^([a-zA-Z_][\w-]*|-+[a-zA-Z_][\w-]*)(?:$|[)}, ])/) !== -1;
+  return (
+    stringTrimmed.search(/^([a-zA-Z_][\w-]*|-+[a-zA-Z_][\w-]*)(?:$|[)}, ])/) !==
+    -1
+  );
 }
 
 function isInterpolationAfter(after) {
@@ -929,7 +939,9 @@ function isHexColorAfter(after) {
 }
 
 function isHexColorBefore(before) {
-  return before.search(/(?:[/(){},+*%-\s]|^)#([\da-fA-F]{3}|[\da-fA-F]{6})$/) !== -1;
+  return (
+    before.search(/(?:[/(){},+*%-\s]|^)#([\da-fA-F]{3}|[\da-fA-F]{6})$/) !== -1
+  );
 }
 
 /**


Test patch:
diff --git a/src/rules/operator-no-unspaced/__tests__/index.js b/src/rules/operator-no-unspaced/__tests__/index.js
index 00a936d..9299cc9 100644
--- a/src/rules/operator-no-unspaced/__tests__/index.js
+++ b/src/rules/operator-no-unspaced/__tests__/index.js
@@ -40,6 +40,19 @@ testRule({
       code: ":root { --foo: '{{}}'; }",
       description: "Custom property"
     },
+    {
+      code: `
+      @mixin test {
+        @for $i from 0 through 10 {
+          &:nth-child(#{$i + 1}) {
+            top: #{$i * -10}px;
+            transform: scale(#{(10 - $i) * 0.1}) !important;
+          }
+        }
+      }
+      `,
+      description: "issue #561"
+    },
     {
       code: `
       @font-face {