diff options
Diffstat (limited to 'node_modules/postcss-convert-values/src/index.js')
| -rw-r--r-- | node_modules/postcss-convert-values/src/index.js | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/node_modules/postcss-convert-values/src/index.js b/node_modules/postcss-convert-values/src/index.js new file mode 100644 index 00000000..94872a55 --- /dev/null +++ b/node_modules/postcss-convert-values/src/index.js @@ -0,0 +1,207 @@ +'use strict'; +const valueParser = require('postcss-value-parser'); +const browserslist = require('browserslist'); +const convert = require('./lib/convert.js'); + +const LENGTH_UNITS = new Set([ + 'em', + 'ex', + 'ch', + 'rem', + 'vw', + 'vh', + 'vmin', + 'vmax', + 'cm', + 'mm', + 'q', + 'in', + 'pt', + 'pc', + 'px', +]); + +// These properties only accept percentages, so no point in trying to transform +const notALength = new Set([ + 'descent-override', + 'ascent-override', + 'font-stretch', + 'size-adjust', + 'line-gap-override', +]); + +// Can't change the unit on these properties when they're 0 +const keepWhenZero = new Set([ + 'stroke-dashoffset', + 'stroke-width', + 'line-height', +]); + +// Can't remove the % on these properties when they're 0 on IE 11 +const keepZeroPercent = new Set(['max-height', 'height', 'min-width']); + +/** + * Numbers without digits after the dot are technically invalid, + * but in that case css-value-parser returns the dot as part of the unit, + * so we use this to remove the dot. + * + * @param {string} item + * @return {string} + */ +function stripLeadingDot(item) { + if (item.charCodeAt(0) === '.'.charCodeAt(0)) { + return item.slice(1); + } else { + return item; + } +} + +/** + * @param {valueParser.Node} node + * @param {Options} opts + * @param {boolean} keepZeroUnit + * @return {void} + */ +function parseWord(node, opts, keepZeroUnit) { + const pair = valueParser.unit(node.value); + if (pair) { + const num = Number(pair.number); + const u = stripLeadingDot(pair.unit); + if (num === 0) { + node.value = + 0 + + (keepZeroUnit || (!LENGTH_UNITS.has(u.toLowerCase()) && u !== '%') + ? u + : ''); + } else { + node.value = convert(num, u, opts); + + if ( + typeof opts.precision === 'number' && + u.toLowerCase() === 'px' && + pair.number.includes('.') + ) { + const precision = Math.pow(10, opts.precision); + node.value = + Math.round(parseFloat(node.value) * precision) / precision + u; + } + } + } +} + +/** + * @param {valueParser.WordNode} node + * @return {void} + */ +function clampOpacity(node) { + const pair = valueParser.unit(node.value); + if (!pair) { + return; + } + let num = Number(pair.number); + if (num > 1) { + node.value = pair.unit === '%' ? num + pair.unit : 1 + pair.unit; + } else if (num < 0) { + node.value = 0 + pair.unit; + } +} + +/** + * @param {import('postcss').Declaration} decl + * @param {string[]} browsers + * @return {boolean} + */ +function shouldKeepZeroUnit(decl, browsers) { + const { parent } = decl; + const lowerCasedProp = decl.prop.toLowerCase(); + return ( + (decl.value.includes('%') && + keepZeroPercent.has(lowerCasedProp) && + browsers.includes('ie 11')) || + (parent && + parent.parent && + parent.parent.type === 'atrule' && + /** @type {import('postcss').AtRule} */ ( + parent.parent + ).name.toLowerCase() === 'keyframes' && + lowerCasedProp === 'stroke-dasharray') || + keepWhenZero.has(lowerCasedProp) + ); +} +/** + * @param {Options} opts + * @param {string[]} browsers + * @param {import('postcss').Declaration} decl + * @return {void} + */ +function transform(opts, browsers, decl) { + const lowerCasedProp = decl.prop.toLowerCase(); + if ( + lowerCasedProp.includes('flex') || + lowerCasedProp.indexOf('--') === 0 || + notALength.has(lowerCasedProp) + ) { + return; + } + + decl.value = valueParser(decl.value) + .walk((node) => { + const lowerCasedValue = node.value.toLowerCase(); + + if (node.type === 'word') { + parseWord(node, opts, shouldKeepZeroUnit(decl, browsers)); + if ( + lowerCasedProp === 'opacity' || + lowerCasedProp === 'shape-image-threshold' + ) { + clampOpacity(node); + } + } else if (node.type === 'function') { + if ( + lowerCasedValue === 'calc' || + lowerCasedValue === 'min' || + lowerCasedValue === 'max' || + lowerCasedValue === 'clamp' || + lowerCasedValue === 'hsl' || + lowerCasedValue === 'hsla' + ) { + valueParser.walk(node.nodes, (n) => { + if (n.type === 'word') { + parseWord(n, opts, true); + } + }); + return false; + } + if (lowerCasedValue === 'url') { + return false; + } + } + }) + .toString(); +} + +const plugin = 'postcss-convert-values'; +/** + * @typedef {{precision: boolean | number, angle?: boolean, time?: boolean, length?: boolean} & browserslist.Options} Options */ +/** + * @type {import('postcss').PluginCreator<Options>} + * @param {Options} opts + * @return {import('postcss').Plugin} + */ +function pluginCreator(opts = { precision: false }) { + const browsers = browserslist(null, { + stats: opts.stats, + path: __dirname, + env: opts.env, + }); + + return { + postcssPlugin: plugin, + OnceExit(css) { + css.walkDecls((decl) => transform(opts, browsers, decl)); + }, + }; +} + +pluginCreator.postcss = true; +module.exports = pluginCreator; |
