postcss-advanced-variables-mod
Version:
Use Sass-like variables, conditionals, and iterators in CSS
68 lines (58 loc) • 1.97 kB
JavaScript
// tooling
import { list } from 'postcss';
import transformNode from './transform-node';
import getReplacedString from './get-replaced-string';
// transform @if at-rules
export default function transformIfAtrule(rule, opts) {
// @if options
const isTruthy = isIfTruthy(rule, opts);
const next = rule.next();
const transformAndInsertBeforeParent = node => transformNode(node, opts).then(
() => node.parent.insertBefore(node, node.nodes)
)
return ifPromise(
opts.transform.includes('@if'),
() => ifPromise(
isTruthy,
() => transformAndInsertBeforeParent(rule)
).then(() => {
rule.remove();
})
).then(() => ifPromise(
opts.transform.includes('@else') && isElseRule(next),
() => ifPromise(
!isTruthy,
() => transformAndInsertBeforeParent(next)
).then(() => {
next.remove();
})
))
}
const ifPromise = (condition, trueFunction) => Promise.resolve(condition && trueFunction())
// return whether the @if at-rule is truthy
const isIfTruthy = (node, opts) => {
// @if statement options (@if EXPRESSION, @if LEFT OPERATOR RIGHT)
const params = list.space(node.params);
const left = getInterprettedString(getReplacedString(params[0] || '', node, opts));
const operator = params[1];
const right = getInterprettedString(getReplacedString(params[2] || '', node, opts));
// evaluate the expression
const isTruthy = !operator && left ||
operator === '==' && left === right ||
operator === '!=' && left !== right ||
operator === '<' && left < right ||
operator === '<=' && left <= right ||
operator === '>' && left > right ||
operator === '>=' && left >= right;
return isTruthy;
};
// return the value as a boolean, number, or string
const getInterprettedString = value => 'true' === value
? true
: 'false' === value
? false
: isNaN(value)
? value
: Number(value);
// return whether the node is an else at-rule
const isElseRule = node => Object(node) === node && 'atrule' === node.type && 'else' === node.name;