123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _convertUnit = _interopRequireDefault(require("./convertUnit"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- function isValueType(type) {
- switch (type) {
- case 'LengthValue':
- case 'AngleValue':
- case 'TimeValue':
- case 'FrequencyValue':
- case 'ResolutionValue':
- case 'EmValue':
- case 'ExValue':
- case 'ChValue':
- case 'RemValue':
- case 'VhValue':
- case 'VwValue':
- case 'VminValue':
- case 'VmaxValue':
- case 'PercentageValue':
- case 'Number':
- return true;
- }
- return false;
- }
- function flip(operator) {
- return operator === '+' ? '-' : '+';
- }
- function isAddSubOperator(operator) {
- return operator === '+' || operator === '-';
- }
- function collectAddSubItems(preOperator, node, collected, precision) {
- if (!isAddSubOperator(preOperator)) {
- throw new Error(`invalid operator ${preOperator}`);
- }
- var type = node.type;
- if (isValueType(type)) {
- var itemIndex = collected.findIndex(function (x) {
- return x.node.type === type;
- });
- if (itemIndex >= 0) {
- if (node.value === 0) {
- return;
- }
- var _covertNodesUnits = covertNodesUnits(collected[itemIndex].node, node, precision),
- reducedNode = _covertNodesUnits.left,
- current = _covertNodesUnits.right;
- if (collected[itemIndex].preOperator === '-') {
- collected[itemIndex].preOperator = '+';
- reducedNode.value *= -1;
- }
- if (preOperator === "+") {
- reducedNode.value += current.value;
- } else {
- reducedNode.value -= current.value;
- } // make sure reducedNode.value >= 0
- if (reducedNode.value >= 0) {
- collected[itemIndex] = {
- node: reducedNode,
- preOperator: '+'
- };
- } else {
- reducedNode.value *= -1;
- collected[itemIndex] = {
- node: reducedNode,
- preOperator: '-'
- };
- }
- } else {
- // make sure node.value >= 0
- if (node.value >= 0) {
- collected.push({
- node,
- preOperator
- });
- } else {
- node.value *= -1;
- collected.push({
- node,
- preOperator: flip(preOperator)
- });
- }
- }
- } else if (type === "MathExpression") {
- if (isAddSubOperator(node.operator)) {
- collectAddSubItems(preOperator, node.left, collected, precision);
- var collectRightOperator = preOperator === '-' ? flip(node.operator) : node.operator;
- collectAddSubItems(collectRightOperator, node.right, collected, precision);
- } else {
- // * or /
- var _reducedNode = reduce(node, precision); // prevent infinite recursive call
- if (_reducedNode.type !== "MathExpression" || isAddSubOperator(_reducedNode.operator)) {
- collectAddSubItems(preOperator, _reducedNode, collected, precision);
- } else {
- collected.push({
- node: _reducedNode,
- preOperator
- });
- }
- }
- } else {
- collected.push({
- node,
- preOperator
- });
- }
- }
- function reduceAddSubExpression(node, precision) {
- var collected = [];
- collectAddSubItems('+', node, collected, precision);
- var withoutZeroItem = collected.filter(function (item) {
- return !(isValueType(item.node.type) && item.node.value === 0);
- });
- var firstNonZeroItem = withoutZeroItem[0]; // could be undefined
- // prevent producing "calc(-var(--a))" or "calc()"
- // which is invalid css
- if (!firstNonZeroItem || firstNonZeroItem.preOperator === '-' && !isValueType(firstNonZeroItem.node.type)) {
- var firstZeroItem = collected.find(function (item) {
- return isValueType(item.node.type) && item.node.value === 0;
- });
- withoutZeroItem.unshift(firstZeroItem);
- } // make sure the preOperator of the first item is +
- if (withoutZeroItem[0].preOperator === '-' && isValueType(withoutZeroItem[0].node.type)) {
- withoutZeroItem[0].node.value *= -1;
- withoutZeroItem[0].preOperator = '+';
- }
- var root = withoutZeroItem[0].node;
- for (var i = 1; i < withoutZeroItem.length; i++) {
- root = {
- type: 'MathExpression',
- operator: withoutZeroItem[i].preOperator,
- left: root,
- right: withoutZeroItem[i].node
- };
- }
- return root;
- }
- function reduceDivisionExpression(node) {
- if (!isValueType(node.right.type)) {
- return node;
- }
- if (node.right.type !== 'Number') {
- throw new Error(`Cannot divide by "${node.right.unit}", number expected`);
- }
- return applyNumberDivision(node.left, node.right.value);
- } // apply (expr) / number
- function applyNumberDivision(node, divisor) {
- if (divisor === 0) {
- throw new Error('Cannot divide by zero');
- }
- if (isValueType(node.type)) {
- node.value /= divisor;
- return node;
- }
- if (node.type === "MathExpression" && isAddSubOperator(node.operator)) {
- // turn (a + b) / num into a/num + b/num
- // is good for further reduction
- // checkout the test case
- // "should reduce division before reducing additions"
- return {
- type: "MathExpression",
- operator: node.operator,
- left: applyNumberDivision(node.left, divisor),
- right: applyNumberDivision(node.right, divisor)
- };
- } // it is impossible to reduce it into a single value
- // .e.g the node contains css variable
- // so we just preserve the division and let browser do it
- return {
- type: "MathExpression",
- operator: '/',
- left: node,
- right: {
- type: "Number",
- value: divisor
- }
- };
- }
- function reduceMultiplicationExpression(node) {
- // (expr) * number
- if (node.right.type === 'Number') {
- return applyNumberMultiplication(node.left, node.right.value);
- } // number * (expr)
- if (node.left.type === 'Number') {
- return applyNumberMultiplication(node.right, node.left.value);
- }
- return node;
- } // apply (expr) / number
- function applyNumberMultiplication(node, multiplier) {
- if (isValueType(node.type)) {
- node.value *= multiplier;
- return node;
- }
- if (node.type === "MathExpression" && isAddSubOperator(node.operator)) {
- // turn (a + b) * num into a*num + b*num
- // is good for further reduction
- // checkout the test case
- // "should reduce multiplication before reducing additions"
- return {
- type: "MathExpression",
- operator: node.operator,
- left: applyNumberMultiplication(node.left, multiplier),
- right: applyNumberMultiplication(node.right, multiplier)
- };
- } // it is impossible to reduce it into a single value
- // .e.g the node contains css variable
- // so we just preserve the division and let browser do it
- return {
- type: "MathExpression",
- operator: '*',
- left: node,
- right: {
- type: "Number",
- value: multiplier
- }
- };
- }
- function covertNodesUnits(left, right, precision) {
- switch (left.type) {
- case 'LengthValue':
- case 'AngleValue':
- case 'TimeValue':
- case 'FrequencyValue':
- case 'ResolutionValue':
- if (right.type === left.type && right.unit && left.unit) {
- var converted = (0, _convertUnit.default)(right.value, right.unit, left.unit, precision);
- right = {
- type: left.type,
- value: converted,
- unit: left.unit
- };
- }
- return {
- left,
- right
- };
- default:
- return {
- left,
- right
- };
- }
- }
- function reduce(node, precision) {
- if (node.type === "MathExpression") {
- if (isAddSubOperator(node.operator)) {
- // reduceAddSubExpression will call reduce recursively
- return reduceAddSubExpression(node, precision);
- }
- node.left = reduce(node.left, precision);
- node.right = reduce(node.right, precision);
- switch (node.operator) {
- case "/":
- return reduceDivisionExpression(node, precision);
- case "*":
- return reduceMultiplicationExpression(node, precision);
- }
- return node;
- }
- return node;
- }
- var _default = reduce;
- exports.default = _default;
- module.exports = exports.default;
|