diff --git a/CHANGELOG.md b/CHANGELOG.md index fc80c0c..71508e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log This project adheres to [Semantic Versioning](http://semver.org/). +## 0.3.4 + +**Fixed** + +- Fixes an issue where only the first of multiple `tidy-` functions in the same declaration value was being processed (#22) + ## 0.3.3 **Changed** diff --git a/lib/tidy-function.js b/lib/tidy-function.js index 7bc41ac..1b82462 100644 --- a/lib/tidy-function.js +++ b/lib/tidy-function.js @@ -12,55 +12,60 @@ const cleanClone = require('./cleanClone'); */ module.exports = function tidyFunction(declaration, tidy) { const FUNCTION_REGEX = /tidy-(span|offset)(|-full)\(([\d.-]+)\)/; + const globalRegExp = new RegExp(FUNCTION_REGEX, 'g'); + const localRegExp = new RegExp(FUNCTION_REGEX); - if (FUNCTION_REGEX.test(declaration.value)) { + if (localRegExp.test(declaration.value)) { const { grid } = tidy; - /** - * match: The full function expression. - * slug: One of either `span` or `offset`. - * modifier: One of either `undefined` or `-full`. - * value: The function's argument. - */ - const [match, slug, modifier, value] = declaration.value.match(FUNCTION_REGEX); + const fullMatch = declaration.value.match(globalRegExp); /** - * Get the span or offset `calc()` value(s). + * Find all matches in the declaration value. * - * fluid: calc() function based on 100vw base. - * full: calc() function based on `siteMax` base. + * @param {String} acc The accumulator, based on declaration.value + * @param {String} tidyMatch The full tidy function match(es) + * + * @return {String} The replacement value for the declaration */ - let { fluid, full } = ('span' === slug) ? - grid.spanCalc(value) : - grid.offsetCalc(value); + const replaceWithValue = fullMatch.reduce((acc, tidyMatch) => { + /** + * match: The full function expression. + * slug: One of either `span` or `offset`. + * modifier: One of either `undefined` or `-full`. + * value: The function's argument. + */ + const [match, slug, modifier, value] = tidyMatch.match(localRegExp); - /** - * If the tidy- function is nested in a calc() function, remove 'calc' - * from the span/offset values. - */ - if (/^calc\(.*\)$/.test(declaration.value)) { - [fluid, full] = [fluid, full].map(calc => ( - (undefined !== calc) ? calc.replace('calc', '') : calc)); - } + /** + * Get the span or offset `calc()` value(s). + * + * fluid: calc() function based on 100vw base. + * full: calc() function based on `siteMax` base. + */ + let { fluid, full } = ('span' === slug) ? + grid.spanCalc(value) : + grid.offsetCalc(value); + + acc = ('-full' === modifier) ? + // tidy-[span|offset]-full() + acc.replace(match, full) : + // tidy-[span|offset] () + acc.replace(match, fluid); + + /** + * Remove nested calc() function resulting from the tidy-* function replacement. + */ + const NESTED_CALC_REGEX = /(calc[(\s]+)(calc\()/; + return (NESTED_CALC_REGEX.test(acc)) ? acc.replace(NESTED_CALC_REGEX, '$1(') : acc; + }, declaration.value); // Replace declaration(s) with cloned and updated declarations. - if ('-full' === modifier) { - // tidy-[span|offset]-full() - declaration.replaceWith(cleanClone( - declaration, - { - prop: declaration.prop, - value: declaration.value.replace(match, full), - }, - )); - } else { - // tidy-[span|offset] () - declaration.replaceWith(cleanClone( - declaration, - { - prop: declaration.prop, - value: declaration.value.replace(match, fluid), - }, - )); - } + declaration.replaceWith(cleanClone( + declaration, + { + prop: declaration.prop, + value: replaceWithValue, + }, + )); } }; diff --git a/package.json b/package.json index abaf4b8..f061eca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcss-tidy-columns", - "version": "0.3.3", + "version": "0.3.4", "description": "PostCSS plugin to manage column and margin alignment.", "keywords": [ "postcss", diff --git a/test/fixtures/full-suite.css b/test/fixtures/full-suite.css index 8ce3afc..b45a995 100644 --- a/test/fixtures/full-suite.css +++ b/test/fixtures/full-suite.css @@ -31,6 +31,12 @@ max-width: calc(tidy-span-full(2) + 20px); } +/* Multiple `tidy-*` functions in the same property value */ +.span-function--multi { + padding: 0 tidy-offset(2) 0 tidy-offset-full(3); + margin: 0 calc(tidy-offset-full(2) + 50px) 0 tidy-offset(1); +} + /* `tidy-offset` with all expected values */ .offset-shorthand { tidy-offset: 3 / 4; diff --git a/test/fixtures/full-suite.expected.css b/test/fixtures/full-suite.expected.css index aa107dd..0fd66e1 100644 --- a/test/fixtures/full-suite.expected.css +++ b/test/fixtures/full-suite.expected.css @@ -40,6 +40,12 @@ max-width: calc(((((90rem - 0.625rem * 2) / 12 - 1.1458rem) * 2) + 1.25rem) + 20px); } +/* Multiple `tidy-*` functions in the same property value */ +.span-function--multi { + padding: 0 calc((((100vw - 0.625rem * 2) / 12 - 1.1458rem) * 2) + 1.25rem * 2) 0 calc((((90rem - 0.625rem * 2) / 12 - 1.1458rem) * 3) + 1.25rem * 3); + margin: 0 calc(((((90rem - 0.625rem * 2) / 12 - 1.1458rem) * 2) + 1.25rem * 2) + 50px) 0 calc(((100vw - 0.625rem * 2) / 12 - 1.1458rem) + 1.25rem); +} + /* `tidy-offset` with all expected values */ .offset-shorthand { margin-left: calc((((100vw - 0.625rem * 2) / 12 - 1.1458rem) * 3) + 1.25rem * 3);