aboutsummaryrefslogtreecommitdiff
path: root/node_modules/reduce-css-calc/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/reduce-css-calc/index.js')
-rwxr-xr-xnode_modules/reduce-css-calc/index.js164
1 files changed, 164 insertions, 0 deletions
diff --git a/node_modules/reduce-css-calc/index.js b/node_modules/reduce-css-calc/index.js
new file mode 100755
index 00000000..3ec72471
--- /dev/null
+++ b/node_modules/reduce-css-calc/index.js
@@ -0,0 +1,164 @@
+/**
+ * Module dependencies
+ */
+var balanced = require("balanced-match")
+var reduceFunctionCall = require("reduce-function-call")
+var mexp = require("math-expression-evaluator")
+
+/**
+ * Constantes
+ */
+var MAX_STACK = 100 // should be enough for a single calc()...
+var NESTED_CALC_RE = /(\+|\-|\*|\\|[^a-z]|)(\s*)(\()/g
+
+/**
+ * Global variables
+ */
+var stack
+
+/**
+ * Expose reduceCSSCalc plugin
+ *
+ * @type {Function}
+ */
+module.exports = reduceCSSCalc
+
+/**
+ * Reduce CSS calc() in a string, whenever it's possible
+ *
+ * @param {String} value css input
+ */
+function reduceCSSCalc(value, decimalPrecision) {
+ stack = 0
+ decimalPrecision = Math.pow(10, decimalPrecision === undefined ? 5 : decimalPrecision)
+
+ // Allow calc() on multiple lines
+ value = value.replace(/\n+/g, " ")
+
+ /**
+ * Evaluates an expression
+ *
+ * @param {String} expression
+ * @returns {String}
+ */
+ function evaluateExpression (expression, functionIdentifier, call) {
+ if (stack++ > MAX_STACK) {
+ stack = 0
+ throw new Error("Call stack overflow for " + call)
+ }
+
+ if (expression === "") {
+ throw new Error(functionIdentifier + "(): '" + call + "' must contain a non-whitespace string")
+ }
+
+ expression = evaluateNestedExpression(expression, call)
+
+ var units = getUnitsInExpression(expression)
+
+ // If the expression contains multiple units or CSS variables,
+ // then let the expression be (i.e. browser calc())
+ if (units.length > 1 || expression.indexOf("var(") > -1) {
+ return functionIdentifier + "(" + expression + ")"
+ }
+
+ var unit = units[0] || ""
+
+ if (unit === "%") {
+ // Convert percentages to numbers, to handle expressions like: 50% * 50% (will become: 25%):
+ // console.log(expression)
+ expression = expression.replace(/\b[0-9\.]+%/g, function(percent) {
+ return parseFloat(percent.slice(0, -1)) * 0.01
+ })
+ }
+
+ // Remove units in expression:
+ var toEvaluate = expression.replace(new RegExp(unit, "gi"), "")
+ var result
+
+ try {
+ result = mexp.eval(toEvaluate)
+ }
+ catch (e) {
+ return functionIdentifier + "(" + expression + ")"
+ }
+
+ // Transform back to a percentage result:
+ if (unit === "%") {
+ result *= 100
+ }
+
+ // adjust rounding shit
+ // (0.1 * 0.2 === 0.020000000000000004)
+ if (functionIdentifier.length || unit === "%") {
+ result = Math.round(result * decimalPrecision) / decimalPrecision
+ }
+
+ // Add unit
+ result += unit
+
+ return result
+ }
+
+ /**
+ * Evaluates nested expressions
+ *
+ * @param {String} expression
+ * @returns {String}
+ */
+ function evaluateNestedExpression(expression, call) {
+ // Remove the calc part from nested expressions to ensure
+ // better browser compatibility
+ expression = expression.replace(/((?:\-[a-z]+\-)?calc)/g, "")
+ var evaluatedPart = ""
+ var nonEvaluatedPart = expression
+ var matches
+ while ((matches = NESTED_CALC_RE.exec(nonEvaluatedPart))) {
+ if (matches[0].index > 0) {
+ evaluatedPart += nonEvaluatedPart.substring(0, matches[0].index)
+ }
+
+ var balancedExpr = balanced("(", ")", nonEvaluatedPart.substring([0].index))
+ if (balancedExpr.body === "") {
+ throw new Error("'" + expression + "' must contain a non-whitespace string")
+ }
+
+ var evaluated = evaluateExpression(balancedExpr.body, "", call)
+
+ evaluatedPart += balancedExpr.pre + evaluated
+ nonEvaluatedPart = balancedExpr.post
+ }
+
+ return evaluatedPart + nonEvaluatedPart
+ }
+
+ return reduceFunctionCall(value, /((?:\-[a-z]+\-)?calc)\(/, evaluateExpression)
+}
+
+/**
+ * Checks what units are used in an expression
+ *
+ * @param {String} expression
+ * @returns {Array}
+ */
+
+function getUnitsInExpression(expression) {
+ var uniqueUnits = []
+ var uniqueLowerCaseUnits = []
+ var unitRegEx = /[\.0-9]([%a-z]+)/gi
+ var matches = unitRegEx.exec(expression)
+
+ while (matches) {
+ if (!matches || !matches[1]) {
+ continue
+ }
+
+ if (uniqueLowerCaseUnits.indexOf(matches[1].toLowerCase()) === -1) {
+ uniqueUnits.push(matches[1])
+ uniqueLowerCaseUnits.push(matches[1].toLowerCase())
+ }
+
+ matches = unitRegEx.exec(expression)
+ }
+
+ return uniqueUnits
+}