Skip to content

Commit

Permalink
Allow rounding option
Browse files Browse the repository at this point in the history
  • Loading branch information
MartijnCuppens committed Mar 27, 2019
1 parent cd9da6b commit 2773092
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 45 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ var out = postcss()
.css
```

#### `allowRounding` (default: `true`)

With this variable set `true`, `calc(100% / 3)` will output `33.33333%` (with `precision: 5`). If it is set `false` it will remain `calc(100% / 3)`.

Another example with `allowRounding: false`: `calc(900% / 16)` will output `56.25%` with `precision: 5` (because `calc(900% / 16)` == `56.25%`), but `calc(900% / 16)` with `precision: 0` (because `calc(900% / 16)` != `56%`).

```js
var out = postcss()
.use(calc({allowRounding: false}))
.process(css)
.css
```

#### `warnWhenCannotResolve` (default: `false`)

Adds warnings when calc() are not reduced to a single value.
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import transform from './lib/transform';
export default plugin('postcss-calc', (opts) => {
const options = Object.assign({
precision: 5,
allowRounding: true,
preserve: false,
warnWhenCannotResolve: false,
mediaQueries: false,
Expand Down
8 changes: 4 additions & 4 deletions src/lib/convert.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import convertUnits from 'css-unit-converter';

function convertNodes(left, right, precision) {
function convertNodes(left, right, options) {
switch (left.type) {
case 'LengthValue':
case 'AngleValue':
case 'TimeValue':
case 'FrequencyValue':
case 'ResolutionValue':
return convertAbsoluteLength(left, right, precision);
return convertAbsoluteLength(left, right, options);
default:
return { left, right };
}
}

function convertAbsoluteLength(left, right, precision) {
function convertAbsoluteLength(left, right, options) {
if (right.type === left.type) {
right = {
type: left.type,
value: convertUnits(right.value, right.unit, left.unit, precision),
value: convertUnits(right.value, right.unit, left.unit, options),
unit: left.unit,
};
}
Expand Down
54 changes: 27 additions & 27 deletions src/lib/reducer.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import convert from './convert';

function reduce(node, precision) {
if (node.type === "MathExpression")
return reduceMathExpression(node, precision);
function reduce(node, options) {
if (node.type === "MathExpression")
return reduceMathExpression(node, options);

return node;
}
Expand Down Expand Up @@ -33,10 +33,10 @@ function isValueType(type) {
return false;
}

function convertMathExpression(node, precision) {
let nodes = convert(node.left, node.right, precision);
let left = reduce(nodes.left, precision);
let right = reduce(nodes.right, precision);
function convertMathExpression(node, options) {
let nodes = convert(node.left, node.right, options);
let left = reduce(nodes.left, options);
let right = reduce(nodes.right, options);

if (left.type === "MathExpression" && right.type === "MathExpression") {

Expand All @@ -46,13 +46,13 @@ function convertMathExpression(node, precision) {
(left.operator === '+' && right.operator === '-'))) {

if (isEqual(left.right, right.right))
nodes = convert(left.left, right.left, precision);
nodes = convert(left.left, right.left, options);

else if (isEqual(left.right, right.left))
nodes = convert(left.left, right.right, precision);
nodes = convert(left.left, right.right, options);

left = reduce(nodes.left, precision);
right = reduce(nodes.right, precision);
left = reduce(nodes.left, options);
right = reduce(nodes.right, options);

}
}
Expand All @@ -76,7 +76,7 @@ function flipValue(node) {
return node;
}

function reduceAddSubExpression(node, precision) {
function reduceAddSubExpression(node, options) {
const {left, right, operator: op} = node;

if (left.type === 'Function' || right.type === 'Function')
Expand Down Expand Up @@ -122,10 +122,10 @@ function reduceAddSubExpression(node, precision) {
operator: op,
left: left,
right: right.left
}, precision);
}, options);
node.right = right.right;
node.operator = op === '-' ? flip(right.operator) : right.operator;
return reduce(node, precision);
return reduce(node, options);
}
// value + (something + value) => (value + value) + something
// value + (something - value) => (value - value) + something
Expand All @@ -138,15 +138,15 @@ function reduceAddSubExpression(node, precision) {
operator: op === '-' ? flip(right.operator) : right.operator,
left: left,
right: right.right
}, precision);
}, options);
node.right = right.left;
return reduce(node, precision);
return reduce(node, options);
}
// value - (something + something) => value - something - something
else if (op === '-' && right.operator === '+') {
node = Object.assign({ }, node);
node.right.operator = '-';
return reduce(node, precision);
return reduce(node, options);
}
}

Expand All @@ -167,8 +167,8 @@ function reduceAddSubExpression(node, precision) {
operator: op,
left: left.left,
right: right
}, precision);
return reduce(node, precision);
}, options);
return reduce(node, options);
}
// (something + value) + value => something + (value + value)
// (something - value1) + value2 => something - (value2 - value1)
Expand All @@ -182,7 +182,7 @@ function reduceAddSubExpression(node, precision) {
operator: flip(op),
left: left.right,
right: right
}, precision);
}, options);
if (node.right.value && node.right.value < 0) {
node.right.value = Math.abs(node.right.value);
node.operator = '+';
Expand All @@ -196,16 +196,16 @@ function reduceAddSubExpression(node, precision) {
operator: op,
left: left.right,
right: right
}, precision);
}, options);
}
if (node.right.value < 0) {
node.right.value *= -1;
node.operator = node.operator === '-' ? '+' : '-';
}
return reduce(node, precision);
return reduce(node, options);
}
}

if (
left.type === 'MathExpression' && right.type === 'MathExpression' &&
op === '-' && right.operator === '-'
Expand Down Expand Up @@ -269,15 +269,15 @@ function reduceMultiplicationExpression(node) {
return node;
}

function reduceMathExpression(node, precision) {
node = convertMathExpression(node, precision);
function reduceMathExpression(node, options) {
node = convertMathExpression(node, options);

switch (node.operator) {
case "+":
case "-":
return reduceAddSubExpression(node, precision);
return reduceAddSubExpression(node, options);
case "/":
return reduceDivisionExpression(node, precision);
return reduceDivisionExpression(node, options);
case "*":
return reduceMultiplicationExpression(node);
}
Expand Down
22 changes: 11 additions & 11 deletions src/lib/stringifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,40 @@ const order = {
"-": 1,
};

function round(value, prec) {
if (prec !== false) {
const precision = Math.pow(10, prec);
function round(value, options) {
if (options.precision !== false && options.allowRounding) {
const precision = Math.pow(10, options.precision);
return Math.round(value * precision) / precision;
}
return value;
}

function stringify(node, prec) {
function stringify(node, options) {
switch (node.type) {
case "MathExpression": {
const {left, right, operator: op} = node;
let str = "";

if (left.type === 'MathExpression' && order[op] < order[left.operator])
str += `(${stringify(left, prec)})`;
str += `(${stringify(left, options)})`;
else
str += stringify(left, prec);
str += stringify(left, options);

str += order[op] ? ` ${node.operator} ` : node.operator;

if (right.type === 'MathExpression' && order[op] < order[right.operator])
str += `(${stringify(right, prec)})`;
str += `(${stringify(right, options)})`;
else
str += stringify(right, prec);
str += stringify(right, options);

return str;
}
case "Value":
return round(node.value, prec);
return round(node.value, options);
case 'Function':
return node.value;
default:
return round(node.value, prec) + node.unit;
return round(node.value, options) + node.unit;
}
}

Expand All @@ -50,7 +50,7 @@ export default function (
result,
item
) {
let str = stringify(node, options.precision);
let str = stringify(node, options);

if (node.type === "MathExpression") {
// if calc expression couldn't be resolved to a single value, re-wrap it as
Expand Down
16 changes: 13 additions & 3 deletions src/lib/transform.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import selectorParser from 'postcss-selector-parser';
import valueParser from 'postcss-value-parser';
import valueParser from 'postcss-value-parser';

// eslint-disable-next-line import/no-unresolved
import { parser } from '../parser';
Expand All @@ -18,10 +18,20 @@ function transformValue(value, options, result, item) {
// stringify calc expression and produce an AST
const contents = valueParser.stringify(node.nodes);
const ast = parser.parse(contents);

// reduce AST to its simplest form, that is, either to a single value
// or a simplified calc expression
const reducedAst = reducer(ast, options.precision);
const reducedAst = reducer(ast, options);

// prevent rounding if not allowed
if (!options.allowRounding && reducedAst.type !== "MathExpression") {
const precision = Math.pow(10, options.precision);

// Check if the result is rounded
if (Math.round(reducedAst.value * precision) / precision !== reducedAst.value){
return node;
}
}

// stringify AST and write it back
node.type = 'word';
Expand Down

0 comments on commit 2773092

Please sign in to comment.