| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896 | 
							- "use strict";
 
- Object.defineProperty(exports, "__esModule", {
 
-   value: true
 
- });
 
- exports["default"] = findOperators;
 
- exports.isInsideFunctionCall = isInsideFunctionCall;
 
- exports.mathOperatorCharType = mathOperatorCharType;
 
- /**
 
-  * Processes a string and finds Sass operators in it
 
-  *
 
-  * @param {Object} args - Named arguments object
 
-  * @param {String} args.string - the input string
 
-  * @param {Number} args.globalIndex - the position of args.string from the start of the line
 
-  * @param {Boolean} args.isAfterColon - pass "true" if the string is
 
-  *    a variable value, a mixin/function parameter default.
 
-  *    In such cases + and / tend to be operations more often
 
-  * @param {Function} args.callback - will be called on every instance of
 
-  *    an operator. Accepts parameters:
 
-  *    • string - the default source string
 
-  *    • globalIndex - the string's position in the outer input
 
-  *    • startIndex - index in string, where the operator starts
 
-  *    • endIndex - index in string, where the operator ends (for `==`, etc.)
 
-  *
 
-  * @return {Array} array of { symbol, globalIndex, startIndex, endIndex }
 
-  *    for each operator found within a string
 
-  */
 
- function findOperators(_ref) {
 
-   var string = _ref.string,
 
-     globalIndex = _ref.globalIndex,
 
-     isAfterColon = _ref.isAfterColon,
 
-     callback = _ref.callback;
 
-   var mathOperators = ["+", "/", "-", "*", "%"];
 
-   // A stack of modes activated for the current char: string, interpolation
 
-   // Calculations inside strings are not processed, so spaces are not linted
 
-   var modesEntered = [{
 
-     mode: "normal",
 
-     isCalculationEnabled: true,
 
-     character: null
 
-   }];
 
-   var result = [];
 
-   var lastModeIndex = 0;
 
-   for (var i = 0; i < string.length; i++) {
 
-     var character = string[i];
 
-     var substringStartingWithIndex = string.substring(i);
 
-     var lastMode = modesEntered[lastModeIndex];
 
-     // If entering/exiting a string
 
-     if (character === '"' || character === "'") {
 
-       if (lastMode && lastMode.isCalculationEnabled === true) {
 
-         modesEntered.push({
 
-           mode: "string",
 
-           isCalculationEnabled: false,
 
-           character: character
 
-         });
 
-         lastModeIndex++;
 
-       } else if (lastMode && lastMode.mode === "string" && lastMode.character === character && string[i - 1] !== "\\") {
 
-         modesEntered.pop();
 
-         lastModeIndex--;
 
-       }
 
-     }
 
-     // If entering/exiting interpolation (may be inside a string)
 
-     // Comparing with length-2 because `#{` at the very end doesnt matter
 
-     if (character === "#" && i + 1 < string.length - 2 && string[i + 1] === "{") {
 
-       modesEntered.push({
 
-         mode: "interpolation",
 
-         isCalculationEnabled: true
 
-       });
 
-       lastModeIndex++;
 
-     } else if (character === "}") {
 
-       modesEntered.pop();
 
-       lastModeIndex--;
 
-     }
 
-     // Don't lint if inside a string
 
-     if (lastMode && lastMode.isCalculationEnabled === false) {
 
-       continue;
 
-     }
 
-     // If it's a math operator
 
-     if (mathOperators.includes(character) && mathOperatorCharType(string, i, isAfterColon) === "op" ||
 
-     // or is "<" or ">"
 
-     substringStartingWithIndex.search(/^[<>]([^=]|$)/) !== -1) {
 
-       result.push({
 
-         symbol: string[i],
 
-         globalIndex: globalIndex,
 
-         startIndex: i,
 
-         endIndex: i
 
-       });
 
-       if (callback) {
 
-         callback(string, globalIndex, i, i);
 
-       }
 
-     }
 
-     // "<=", ">=", "!=", "=="
 
-     if (substringStartingWithIndex.search(/^[><=!]=/) !== -1) {
 
-       result.push({
 
-         symbol: string[i],
 
-         globalIndex: globalIndex,
 
-         startIndex: i,
 
-         endIndex: i + 1
 
-       });
 
-       if (callback) {
 
-         callback(string, globalIndex, i, i + 1);
 
-       }
 
-     }
 
-   }
 
-   // result.length > 0 && console.log(string, result)
 
-   return result;
 
- }
 
- /**
 
-  * Checks if a character is an operator, a sign (+ or -), or part of a string
 
-  *
 
-  * @param {String} string - the source string
 
-  * @param {Number} index - the index of the character in string to check
 
-  * @param {Boolean} isAfterColon - if the value string a variable
 
-  *    value, a mixin/function parameter default. In such cases + and / tend
 
-  *    to be operations more often
 
-  * @return {String|false}
 
-  *    • "op", if the character is a operator in a math/string operation
 
-  *    • "sign" if it is a + or - before a numeric,
 
-  *    • "char" if it is a part of a string,
 
-  *    • false - if it is none from above (most likely an error)
 
-  */
 
- function mathOperatorCharType(string, index, isAfterColon) {
 
-   // !Checking here to prevent unnecessary calculations and deep recursion
 
-   // when calling isPrecedingOperator()
 
-   if (!["+", "/", "-", "*", "%"].includes(string[index])) {
 
-     return "char";
 
-   }
 
-   var character = string[index];
 
-   var prevCharacter = string[index - 1];
 
-   if (prevCharacter !== "\\") {
 
-     // ---- Processing + characters
 
-     if (character === "+") {
 
-       return checkPlus(string, index, isAfterColon);
 
-     }
 
-     // ---- Processing - characters
 
-     if (character === "-") {
 
-       return checkMinus(string, index);
 
-     }
 
-     // ---- Processing * character
 
-     if (character === "*") {
 
-       return checkMultiplication(string, index);
 
-     }
 
-     // ---- Processing % character
 
-     if (character === "%") {
 
-       return checkPercent(string, index);
 
-     }
 
-     // ---- Processing / character
 
-     // https://sass-lang.com/documentation/operators/numeric#slash-separated-values
 
-     if (character === "/") {
 
-       return checkSlash(string, index, isAfterColon);
 
-     }
 
-   }
 
-   return "char";
 
- }
 
- // --------------------------------------------------------------------------
 
- // Functions for checking particular characters (+, -, /)
 
- // --------------------------------------------------------------------------
 
- /**
 
-  * Checks the specified `*` char type: operator, sign (*), part of string
 
-  *
 
-  * @param {String} string - the source string
 
-  * @param {Number} index - the index of the character in string to check
 
-  * @return {String|false}
 
-  *    • "op", if the character is a operator in a math/string operation
 
-  *    • "sign" if it is a sign before a positive number,
 
-  *    • "char" if it is a part of a string or identifier,
 
-  *    • false - if it is none from above (most likely an error)
 
-  */
 
- function checkMultiplication(string, index) {
 
-   var insideFn = isInsideFunctionCall(string, index);
 
-   if (insideFn.is && insideFn.fn) {
 
-     var fnArgsReg = new RegExp(insideFn.fn + "\\(([^)]+)\\)");
 
-     var fnArgs = string.match(fnArgsReg);
 
-     var isSingleMultiplicationChar = Array.isArray(fnArgs) && fnArgs[1] === "*";
 
-     // e.g. selector(:has(*))
 
-     if (isSingleMultiplicationChar) {
 
-       return "char";
 
-     }
 
-   }
 
-   return "op";
 
- }
 
- /**
 
-  * Checks the specified `+` char type: operator, sign (+ or -), part of string
 
-  *
 
-  * @param {String} string - the source string
 
-  * @param {Number} index - the index of the character in string to check
 
-  * @param {Boolean} isAftercolon - if the value string a variable
 
-  *    value, a mixin/function parameter default. In such cases + is always an
 
-  *    operator if surrounded by numbers/values with units
 
-  * @return {String|false}
 
-  *    • "op", if the character is a operator in a math/string operation
 
-  *    • "sign" if it is a sign before a positive number,
 
-  *    • false - if it is none from above (most likely an error)
 
-  */
 
- function checkPlus(string, index, isAftercolon) {
 
-   var before = string.substring(0, index);
 
-   var after = string.substring(index + 1);
 
-   // If the character is at the beginning of the input
 
-   var isAtStart_ = isAtStart(string, index);
 
-   // If the character is at the end of the input
 
-   var isAtEnd_ = isAtEnd(string, index);
 
-   var isWhitespaceBefore = before.search(/\s$/) !== -1;
 
-   var isWhitespaceAfter = after.search(/^\s/) !== -1;
 
-   var isValueWithUnitAfter_ = isValueWithUnitAfter(after);
 
-   var isNumberAfter_ = isNumberAfter(after);
 
-   var isInterpolationAfter_ = isInterpolationAfter(after);
 
-   // The early check above helps prevent deep recursion here
 
-   var isPrecedingOperator_ = isPrecedingOperator(string, index);
 
-   if (isAtStart_) {
 
-     // console.log("+, `+<sth>` or `+ <sth>`")
 
-     return "sign";
 
-   }
 
-   // E.g. `1+1`, `string+#fff`
 
-   if (!isAtStart_ && !isWhitespaceBefore && !isAtEnd_ && !isWhitespaceAfter) {
 
-     // E.g. `1-+1`
 
-     if (isPrecedingOperator_) {
 
-       // console.log('1+1')
 
-       return "sign";
 
-     }
 
-     // console.log("+, no spaces")
 
-     return "op";
 
-   }
 
-   // e.g. `something +something`
 
-   if (!isAtEnd_ && !isWhitespaceAfter) {
 
-     // e.g. `+something`, ` ... , +something`, etc.
 
-     if (isNoOperandBefore(string, index)) {
 
-       // console.log("+, nothing before")
 
-       return "sign";
 
-     }
 
-     // e.g. `sth +10px`, `sth +1`
 
-     if (isValueWithUnitAfter_.is && !isValueWithUnitAfter_.opsBetween || isNumberAfter_.is && !isNumberAfter_.opsBetween) {
 
-       if (isAftercolon === true) {
 
-         // console.log(": 10px +1")
 
-         return "op";
 
-       }
 
-       // e.g. `(sth +10px)`, `fun(sth +1)`
 
-       if (isInsideParens(string, index) || isInsideFunctionCall(string, index).is) {
 
-         // console.log("+10px or +1, inside function or parens")
 
-         return "op";
 
-       }
 
-       // e.g. `#{10px +1}`
 
-       if (isInsideInterpolation(string, index)) {
 
-         // console.log('+, #{10px +1}')
 
-         return "op";
 
-       }
 
-       // console.log('+, default')
 
-       return "sign";
 
-     }
 
-     // e.g. `sth +#fff`, `sth +string`, `sth +#{...}`, `sth +$var`
 
-     if (isStringAfter(after) || isHexColorAfter(after) || after[0] === "$" || isInterpolationAfter_.is && !isInterpolationAfter_.opsBefore) {
 
-       // e.g. `sth+ +string`
 
-       if (isPrecedingOperator_) {
 
-         // console.log("+10px or +1, before is an operator")
 
-         return "sign";
 
-       }
 
-       // console.log("+#000, +string, +#{sth}, +$var")
 
-       return "op";
 
-     }
 
-     // console.log('sth +sth, default')
 
-     return "op";
 
-   }
 
-   // If the + is after a value, e.g. `$var+`
 
-   if (!isAtStart_ && !isWhitespaceBefore) {
 
-     // It is always an operator. Prior to Sass 4, `#{...}+` was different,
 
-     // but that's not logical and had been fixed.
 
-     // console.log('1+ sth')
 
-     return "op";
 
-   }
 
-   // If it has whitespaces on both sides
 
-   // console.log('sth + sth')
 
-   return "op";
 
- }
 
- /**
 
-  * Checks the specified `-` character: operator, sign (+ or -), part of string
 
-  *
 
-  * @param {String} string - the source string
 
-  * @param {Number} index - the index of the character in string to check
 
-  * @return {String|false}
 
-  *    • "op", if the character is a operator in a math/string operation
 
-  *    • "sign" if it is a sign before a negative number,
 
-  *    • "char" if it is a part of a string or identifier,
 
-  *    • false - if it is none from above (most likely an error)
 
-  */
 
- function checkMinus(string, index) {
 
-   var before = string.substring(0, index);
 
-   var after = string.substring(index + 1);
 
-   // If the character is at the beginning of the input
 
-   var isAtStart_ = isAtStart(string, index);
 
-   // If the character is at the end of the input
 
-   var isAtEnd_ = isAtEnd(string, index);
 
-   var isWhitespaceBefore = before.search(/\s$/) !== -1;
 
-   var isWhitespaceAfter = after.search(/^\s/) !== -1;
 
-   var isValueWithUnitAfter_ = isValueWithUnitAfter(after);
 
-   var isValueWithUnitBefore_ = isValueWithUnitBefore(before);
 
-   var isNumberAfter_ = isNumberAfter(after);
 
-   var isNumberBefore_ = isNumberBefore(before);
 
-   var isInterpolationAfter_ = isInterpolationAfter(after);
 
-   var isParensAfter_ = isParensAfter(after);
 
-   var isParensBefore_ = isParensBefore(before);
 
-   // The early check above helps prevent deep recursion here
 
-   var isPrecedingOperator_ = isPrecedingOperator(string, index);
 
-   var isInsideFunctionCall_ = isInsideFunctionCall(string, index);
 
-   if (isAtStart_) {
 
-     // console.log("-, -<sth> or - <sth>")
 
-     return "sign";
 
-   }
 
-   // `10 -    11`
 
-   if (!isAtEnd_ && !isAtStart_ && isWhitespaceBefore && isWhitespaceAfter) {
 
-     // console.log("-, Op: 10px -  10px")
 
-     return "op";
 
-   }
 
-   // e.g. `something -10px`
 
-   if (!isAtEnd_ && !isAtStart_ && isWhitespaceBefore && !isWhitespaceAfter) {
 
-     if (isParensAfter_.is && !isParensAfter_.opsBefore) {
 
-       // console.log("-, Op: <sth> -(...)")
 
-       return "op";
 
-     }
 
-     // e.g. `#{10px -1}`, `#{math.acos(-0.5)}`
 
-     if (isInsideInterpolation(string, index)) {
 
-       // e.g. `url(https://my-url.com/image-#{$i -2}-dark.svg)`
 
-       if (isInsideFunctionCall_.fn === "url") {
 
-         return "op";
 
-       }
 
-       if (isInsideFunctionCall_.is && (isValueWithUnitAfter_.is && !isValueWithUnitAfter_.opsBetween || isNumberAfter_.is && !isNumberAfter_.opsBetween)) {
 
-         return "sign";
 
-       }
 
-       // e.g. `#{$i * -10}px`
 
-       if (isWhitespaceBefore && isNumberAfter_.is && isPrecedingOperator_) {
 
-         return "sign";
 
-       }
 
-       return "op";
 
-     }
 
-     // e.g. `sth -1px`, `sth -1`.
 
-     // Always a sign, even inside parens/function args
 
-     if (isValueWithUnitAfter_.is && !isValueWithUnitAfter_.opsBetween || isNumberAfter_.is && !isNumberAfter_.opsBetween) {
 
-       // console.log("-, sign: -1px or -1")
 
-       return "sign";
 
-     }
 
-     // e.g. `sth --1`, `sth +-2px`
 
-     if (isValueWithUnitAfter_.is && isValueWithUnitAfter_.opsBetween || isNumberAfter_.is && isNumberAfter_.opsBetween) {
 
-       // console.log("-, op: --1px or --1")
 
-       return "op";
 
-     }
 
-     // `<sth> -string`, `<sth> -#{...}`
 
-     if (isStringAfter(after) || isInterpolationAfter_.is && !isInterpolationAfter_.opsBefore) {
 
-       // console.log("-, char: -#{...}")
 
-       return "char";
 
-     }
 
-     // e.g. `#0af -#f0a`, and edge-cases can take a hike
 
-     if (isHexColorAfter(after) && isHexColorBefore(before.trim())) {
 
-       // console.log("-, op: #fff-, -#fff")
 
-       return "op";
 
-     }
 
-     // If the - is before a variable, than it's most likely an operator
 
-     if (after[0] === "$") {
 
-       if (isPrecedingOperator_) {
 
-         // console.log("-, sign: -$var, another operator before")
 
-         return "sign";
 
-       }
 
-       // console.log("-, op: -$var, NO other operator before")
 
-       return "op";
 
-     }
 
-     // By default let's make it an sign for now
 
-     // console.log('-, sign: default in <sth> -<sth>')
 
-     return "sign";
 
-   }
 
-   // No whitespace before,
 
-   // e.g. `10x- something`
 
-   if (!isAtEnd_ && !isAtStart_ && !isWhitespaceBefore && isWhitespaceAfter) {
 
-     if (isParensBefore_) {
 
-       // console.log('-, op: `(...)- <sth>`')
 
-       return "op";
 
-     }
 
-     // e.g. `#{10px- 1}`
 
-     if (isInsideInterpolation(string, index)) {
 
-       return "op";
 
-     }
 
-     if (isNumberBefore(before) || isHexColorBefore(before)) {
 
-       // console.log('`-, op: 10- <sth>, #aff- <sth>`')
 
-       return "op";
 
-     }
 
-     // console.log('-, char: default in <sth>- <sth>')
 
-     return "char";
 
-   }
 
-   // NO Whitespace,
 
-   // e.g. `10px-1`
 
-   if (!isAtEnd_ && !isAtStart_ && !isWhitespaceBefore && !isWhitespaceAfter) {
 
-     // console.log('no spaces')
 
-     // `<something>-1`, `<something>-10px`
 
-     if (isValueWithUnitAfter_.is && !isValueWithUnitAfter_.opsBetween || isNumberAfter_.is && !isNumberAfter_.opsBetween) {
 
-       // `10px-1`, `1-10px`, `1-1`, `1x-1x`
 
-       if (isValueWithUnitBefore_ || isNumberBefore_) {
 
-         // console.log("-, op: 1-10px")
 
-         return "op";
 
-       }
 
-       // The - could be a "sign" here, but for now "char" does the job
 
-     }
 
-     // `1-$var`
 
-     if (isNumberBefore_ && after[0] === "$") {
 
-       // console.log("-, op: 1-$var")
 
-       return "op";
 
-     }
 
-     // `fn()-10px`
 
-     if (isFunctionBefore(before) && (isNumberAfter_.is && !isNumberAfter_.opsBetween || isValueWithUnitAfter_.is && !isValueWithUnitAfter_.opsBetween)) {
 
-       // console.log("-, op: fn()-10px")
 
-       return "op";
 
-     }
 
-   }
 
-   // And in all the other cases it's a character inside a string
 
-   // console.log("-, default: char")
 
-   return "char";
 
- }
 
- /**
 
-  * Checks the specified `/` character: operator, sign (+ or -), part of string
 
-  *
 
-  * @param {String} string - the source string
 
-  * @param {Number} index - the index of the character in string to check
 
-  * @param {Boolean} isAfterColon - if the value string a variable
 
-  *    value, a mixin/function parameter default. In such cases / is always an
 
-  *    operator if surrounded by numbers/values with units
 
-  * @return {String|false}
 
-  *    • "op", if the character is a operator in a math/string operation
 
-  *    • "char" if it gets compiled as-is, e.g. `font: 10px/1.2;`,
 
-  *    • false - if it is none from above (most likely an error)
 
-  */
 
- function checkSlash(string, index, isAfterColon) {
 
-   // Trimming these, as spaces before/after a slash don't matter
 
-   var before = string.substring(0, index).trim();
 
-   var after = string.substring(index + 1).trim();
 
-   var isValueWithUnitAfter_ = isValueWithUnitAfter(after);
 
-   var isValueWithUnitBefore_ = isValueWithUnitBefore(before);
 
-   var isNumberAfter_ = isNumberAfter(after);
 
-   var isNumberBefore_ = isNumberBefore(before);
 
-   var isParensAfter_ = isParensAfter(after);
 
-   var isParensBefore_ = isParensBefore(before);
 
-   // FIRST OFF. Interpolation on any of the sides is a NO-GO for division op
 
-   if (isInterpolationBefore(before).is || isInterpolationAfter(after).is) {
 
-     // console.log("/, interpolation")
 
-     return "char";
 
-   }
 
-   // having a dot before probably means a relative path.
 
-   // e.g. url(../../image.png)
 
-   if (isDotBefore(before)) {
 
-     return "char";
 
-   }
 
-   // e.g. `(1px/1)`, `fn(7 / 15)`, but not `url(8/11)`
 
-   var isInsideFn = isInsideFunctionCall(string, index);
 
-   if (isInsideFn.is && isInsideFn.fn === "url") {
 
-     // e.g. `url(https://my-url.com/image-#{$i /2}-dark.svg)`
 
-     if (isInsideInterpolation(string, index)) {
 
-       return "op";
 
-     }
 
-     return "char";
 
-   }
 
-   // e.g. `10px/normal`
 
-   if (isStringBefore(before).is || isStringAfter(after)) {
 
-     // console.log("/, string")
 
-     return "char";
 
-   }
 
-   // For all other value options (numbers, value+unit, hex color)
 
-   // `$var/1`, `#fff/-$var`
 
-   // Here we don't care if there is a sign before the var
 
-   if (isVariableBefore(before) || isVariableAfter(after).is) {
 
-     // console.log("/, variable")
 
-     return "op";
 
-   }
 
-   if (isFunctionBefore(before) || isFunctionAfter(after).is) {
 
-     // console.log("/, function as operand")
 
-     return "op";
 
-   }
 
-   if (isParensBefore_ || isParensAfter_.is) {
 
-     // console.log("/, function as operand")
 
-     return "op";
 
-   }
 
-   // `$var: 10px/2; // 5px`
 
-   if (isAfterColon === true && (isValueWithUnitAfter_.is || isNumberAfter_.is) && (isValueWithUnitBefore_ || isNumberBefore_)) {
 
-     return "op";
 
-   }
 
-   // Quick check of the following operator symbol - if it is a math operator
 
-   if (
 
-   // +, *, % count as operators unless after interpolation or at the start
 
-   before.search(/[^{,(}\s]\s*[+*%][^(){},]+$/) !== -1 ||
 
-   // We consider minus as op only if surrounded by whitespaces (` - `);
 
-   before.search(/[^{,(}\s]\s+-\s[^(){},]+$/) !== -1 ||
 
-   // `10/2 * 3`, `10/2 % 3`, with or without spaces
 
-   after.search(/^[^(){},]+[*%]/) !== -1 ||
 
-   // `10px/2px+1`, `10px/2px+ 1`
 
-   after.search(/^[^(){},\s]+\+/) !== -1 ||
 
-   // Anything but `10px/2px +1`, `10px/2px +1px`
 
-   after.search(/^[^(){},\s]+\s+(\+\D)/) !== -1 ||
 
-   // Following ` -`: only if `$var` after (`10/10 -$var`)
 
-   after.search(/^[^(){},\s]+\s+-(\$|\s)/) !== -1 ||
 
-   // Following `-`: only if number after (`10s/10s-10`, `10s/10s-.1`)
 
-   after.search(/^[^(){},\s]+-(\.)?\d/) !== -1 ||
 
-   // Or if there is a number before anything but string after (not `10s/1-str`,)
 
-   after.search(/^(\d*\.)?\d+-\s*[^#a-zA-Z_\s]/) !== -1) {
 
-     // console.log("/, math op around")
 
-     return "op";
 
-   }
 
-   if (isInsideParens(string, index) || isInsideFn.is && isInsideFn.fn !== "url") {
 
-     // console.log("/, parens or function arg")
 
-     return "op";
 
-   }
 
-   // console.log("/, default")
 
-   return "char";
 
- }
 
- /**
 
-  * Checks the specified `%` character: operator or part of value
 
-  *
 
-  * @param {String} string - the source string
 
-  * @param {Number} index - the index of the character in string to check
 
-  * @return {String|false}
 
-  *    • "op", if the character is a operator in a math/string operation
 
-  *    • "char" if it gets compiled as-is, e.g. `width: 10%`,
 
-  *    • false - if it is none from above (most likely an error)
 
-  */
 
- function checkPercent(string, index) {
 
-   // Trimming these, as spaces before/after a slash don't matter
 
-   var before = string.substring(0, index);
 
-   var after = string.substring(index + 1);
 
-   // If the character is at the beginning of the input
 
-   var isAtStart_ = isAtStart(string, index);
 
-   // If the character is at the end of the input
 
-   var isAtEnd_ = isAtEnd(string, index);
 
-   var isWhitespaceBefore = before.search(/\s$/) !== -1;
 
-   var isWhitespaceAfter = after.search(/^\s/) !== -1;
 
-   var isParensBefore_ = isParensBefore(before);
 
-   // FIRST OFF. Interpolation on any of the sides is a NO-GO
 
-   if (isInterpolationBefore(before.trim()).is || isInterpolationAfter(after.trim()).is) {
 
-     // console.log("%, interpolation")
 
-     return "char";
 
-   }
 
-   if (isAtStart_ || isAtEnd_) {
 
-     // console.log("%, start/end")
 
-     return "char";
 
-   }
 
-   // In `<sth> %<sth>` it's most likely an operator (except for interpolation
 
-   // checked above)
 
-   if (isWhitespaceBefore && !isWhitespaceAfter) {
 
-     // console.log("%, `<sth> %<sth>`")
 
-     return "op";
 
-   }
 
-   // `$var% 1`, `$var%1`, `$var%-1`
 
-   if (isVariableBefore(before) || isParensBefore_) {
 
-     // console.log("%, after a variable, function or parens")
 
-     return "op";
 
-   }
 
-   // in all other cases in `<sth>% <sth>` it is most likely a unit
 
-   if (!isWhitespaceBefore && isWhitespaceAfter) {
 
-     // console.log("%, `<sth>% <sth>`")
 
-     return "char";
 
-   }
 
-   // console.log("%, default")
 
-   return "char";
 
- }
 
- // --------------------------------------------------------------------------
 
- // Lots of elementary helpers
 
- // --------------------------------------------------------------------------
 
- function isAtStart(string, index) {
 
-   var before = string.substring(0, index).trim();
 
-   return before.length === 0 || before.search(/[({,]$/) !== -1;
 
- }
 
- function isAtEnd(string, index) {
 
-   var after = string.substring(index + 1).trim();
 
-   return after.length === 0 || after.search(/^[,)}]/) !== -1;
 
- }
 
- function isInsideParens(string, index) {
 
-   var before = string.substring(0, index).trim();
 
-   var after = string.substring(index + 1).trim();
 
-   return before.search(/(?:^|[,{\s])\([^(){},]+$/) !== -1 && after.search(/^[^(){},\s]+\s*\)/) !== -1;
 
- }
 
- function isInsideInterpolation(string, index) {
 
-   var before = string.substring(0, index).trim();
 
-   return before.search(/#{[^}]*$/) !== -1;
 
- }
 
- /**
 
-  * Checks if the character is inside a function arguments
 
-  *
 
-  * @param {String} string - the input string
 
-  * @param {Number} index - current character index
 
-  * @return {Object} return
 
-  *    {Boolean} return.is - if inside a function arguments
 
-  *    {String} return.fn - function name
 
-  */
 
- function isInsideFunctionCall(string, index) {
 
-   var result = {
 
-     is: false,
 
-     fn: null
 
-   };
 
-   var before = string.substring(0, index).trim();
 
-   var after = string.substring(index + 1).trim();
 
-   var beforeMatch = before.match(/(?:[a-zA-Z_-][\w-]*\()?(:?[a-zA-Z_-][\w-]*)\(/);
 
-   if (beforeMatch && beforeMatch[0] && after.search(/^[^(,]+\)/) !== -1) {
 
-     result.is = true;
 
-     result.fn = beforeMatch[1];
 
-   }
 
-   return result;
 
- }
 
- /**
 
-  * Checks if there is a string before the character.
 
-  * Also checks if there is a math operator in between
 
-  *
 
-  * @param {String} before - the input string that preceses the character
 
-  * @return {Object} return
 
-  *    {Boolean} return.is - if there is a string
 
-  *    {String} return.opsBetween - if there are operators in between
 
-  */
 
- function isStringBefore(before) {
 
-   var result = {
 
-     is: false,
 
-     opsBetween: false
 
-   };
 
-   var stringOpsClipped = before.replace(/(\s*[+/*%]|\s+-)+$/, "");
 
-   if (stringOpsClipped !== before) {
 
-     result.opsBetween = true;
 
-   }
 
-   // If it is quoted
 
-   if (stringOpsClipped[stringOpsClipped.length - 1] === '"' || stringOpsClipped[stringOpsClipped.length - 1] === "'") {
 
-     result.is = true;
 
-   } else if (stringOpsClipped.search(/(?:^|[/(){},: ])([a-zA-Z_][\w-]*|-+[a-zA-Z_][\w-]*)$/) !== -1) {
 
-     // First pattern: a1, a1a, a-1,
 
-     result.is = true;
 
-   }
 
-   return result;
 
- }
 
- function isStringAfter(after) {
 
-   var stringTrimmed = after.trim();
 
-   // If it is quoted
 
-   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;
 
- }
 
- function isInterpolationAfter(after) {
 
-   var result = {
 
-     is: false,
 
-     opsBetween: false
 
-   };
 
-   var matches = after.match(/^\s*([+/*%-]\s*)*#{/);
 
-   if (matches) {
 
-     if (matches[0]) {
 
-       result.is = true;
 
-     }
 
-     if (matches[1]) {
 
-       result.opsBetween = true;
 
-     }
 
-   }
 
-   return result;
 
- }
 
- function isParensAfter(after) {
 
-   var result = {
 
-     is: false,
 
-     opsBetween: false
 
-   };
 
-   var matches = after.match(/^\s*([+/*%-]\s*)*\(/);
 
-   if (matches) {
 
-     if (matches[0]) {
 
-       result.is = true;
 
-     }
 
-     if (matches[1]) {
 
-       result.opsBetween = true;
 
-     }
 
-   }
 
-   return result;
 
- }
 
- function isParensBefore(before) {
 
-   return before.search(/\)\s*$/) !== -1;
 
- }
 
- /**
 
-  * Checks if there is an interpolation before the character.
 
-  * Also checks if there is a math operator in between
 
-  *
 
-  * @param {String} before - the input string that preceses the character
 
-  * @return {Object} return
 
-  *    {Boolean} return.is - if there is an interpolation
 
-  *    {String} return.opsBetween - if there are operators in between
 
-  */
 
- function isInterpolationBefore(before) {
 
-   var result = {
 
-     is: false,
 
-     opsBetween: false
 
-   };
 
-   // Removing preceding operators if any
 
-   var beforeOpsClipped = before.replace(/(\s*[+/*%-])+$/, "");
 
-   if (beforeOpsClipped !== before) {
 
-     result.opsBetween = true;
 
-   }
 
-   if (beforeOpsClipped[beforeOpsClipped.length - 1] === "}") {
 
-     result.is = true;
 
-   }
 
-   return result;
 
- }
 
- function isValueWithUnitBefore(before) {
 
-   // 1px, 0.1p-x, .2p-, 11.2pdf-df1df_
 
-   // Surprisingly, ` d.10px` - .10px is separated from a sequence
 
-   // and is considered a value with a unit
 
-   return before.trim().search(/(^|[/(, .])\d[\w-]+$/) !== -1;
 
- }
 
- function isValueWithUnitAfter(after) {
 
-   var result = {
 
-     is: false,
 
-     opsBetween: false
 
-   };
 
-   // 1px, 0.1p-x, .2p-, 11.2pdf-dfd1f_
 
-   // Again, ` d.10px` - .10px is separated from a sequence
 
-   // and is considered a value with a unit
 
-   var matches = after.match(/^\s*([+/*%-]\s*)*(\d+(\.\d+)?|\.\d+)[\w-%]+(?:$|[)}, ])/);
 
-   if (matches) {
 
-     if (matches[0]) {
 
-       result.is = true;
 
-     }
 
-     if (matches[1]) {
 
-       result.opsBetween = true;
 
-     }
 
-   }
 
-   return result;
 
- }
 
- function isNumberAfter(after) {
 
-   var result = {
 
-     is: false,
 
-     opsBetween: false
 
-   };
 
-   var matches = after.match(/^\s*([+/*%-]\s*)*(\d+(\.\d+)?|\.\d+)(?:$|[)}, ])/);
 
-   if (matches) {
 
-     if (matches[0]) {
 
-       result.is = true;
 
-     }
 
-     if (matches[1]) {
 
-       result.opsBetween = true;
 
-     }
 
-   }
 
-   return result;
 
- }
 
- function isNumberBefore(before) {
 
-   return before.trim().search(/(?:^|[/(){},\s])(\d+(\.\d+)?|\.\d+)$/) !== -1;
 
- }
 
- function isVariableBefore(before) {
 
-   return before.trim().search(/\$[\w-]+$/) !== -1;
 
- }
 
- function isVariableAfter(after) {
 
-   var result = {
 
-     is: false,
 
-     opsBetween: false
 
-   };
 
-   var matches = after.match(/^\s*([+/*%-]\s*)*\$/);
 
-   if (matches) {
 
-     if (matches[0]) {
 
-       result.is = true;
 
-     }
 
-     if (matches[1]) {
 
-       result.opsBetween = true;
 
-     }
 
-   }
 
-   return result;
 
- }
 
- function isDotBefore(before) {
 
-   return before.slice(-1) === ".";
 
- }
 
- function isFunctionBefore(before) {
 
-   return before.trim().search(/[\w-]\(.*?\)\s*$/) !== -1;
 
- }
 
- function isFunctionAfter(after) {
 
-   var result = {
 
-     is: false,
 
-     opsBetween: false
 
-   };
 
-   // `-fn()` is a valid function name, so if a - should be a sign/operator,
 
-   // it must have a space after
 
-   var matches = after.match(/^\s*(-\s+|[+/*%]\s*)*[a-zA-Z_-][\w-]*\(/);
 
-   if (matches) {
 
-     if (matches[0]) {
 
-       result.is = true;
 
-     }
 
-     if (matches[1]) {
 
-       result.opsBetween = true;
 
-     }
 
-   }
 
-   return result;
 
- }
 
- /**
 
-  * Checks if the input string is a hex color value
 
-  *
 
-  * @param {String} string - the input
 
-  * @return {Boolean} true, if the input is a hex color
 
-  */
 
- function isHexColor(string) {
 
-   return string.trim().search(/^#([\da-fA-F]{3}|[\da-fA-F]{6})$/) !== -1;
 
- }
 
- function isHexColorAfter(after) {
 
-   var afterTrimmed = after.match(/(.*?)(?:[)},+/*%\-\s]|$)/)[1].trim();
 
-   return isHexColor(afterTrimmed);
 
- }
 
- function isHexColorBefore(before) {
 
-   return before.search(/(?:[/(){},+*%-\s]|^)#([\da-fA-F]{3}|[\da-fA-F]{6})$/) !== -1;
 
- }
 
- /**
 
-  * Checks if there is no operand before the current char
 
-  * In other words, the current char is at the start of a possible operation,
 
-  * e.g. at the string start, after the opening paren or after a comma
 
-  *
 
-  * @param {String} string - the input string
 
-  * @param {Number} index - current char's position in string
 
-  * @return {Boolean}
 
-  */
 
- function isNoOperandBefore(string, index) {
 
-   var before = string.substring(0, index).trim();
 
-   return before.length === 0 || before.search(/[({,]&/) !== -1;
 
- }
 
- function isPrecedingOperator(string, index) {
 
-   var prevCharIndex = -1;
 
-   for (var i = index - 1; i >= 0; i--) {
 
-     if (string[i].search(/\s/) === -1) {
 
-       prevCharIndex = i;
 
-       break;
 
-     }
 
-   }
 
-   if (prevCharIndex === -1) {
 
-     return false;
 
-   }
 
-   if (mathOperatorCharType(string, prevCharIndex) === "op") {
 
-     return true;
 
-   }
 
-   return false;
 
- }
 
 
  |