From 497db7c66cc29de40de100417e4c723ba124e8db Mon Sep 17 00:00:00 2001 From: Guillaume Date: Fri, 11 Jun 2021 09:36:40 +0200 Subject: [PATCH] feat: computed calc() - fixes https://github.com/jsdom/jsdom/issues/1332 - replace getParts by splitTokens (not extracted into a single commit for better understanding) - rename percent to percentage for matching with spec - rename measurement to lengthOrPercentage for consistency with angleOrPercentage (later commit) --- lib/parsers.js | 414 +++++++++++++++++++++------ lib/parsers.test.js | 60 +++- lib/properties/backgroundPosition.js | 9 +- lib/properties/bottom.js | 8 +- lib/properties/clip.js | 4 +- lib/properties/flexBasis.js | 4 +- lib/properties/fontSize.js | 4 +- lib/properties/height.js | 4 +- lib/properties/left.js | 8 +- lib/properties/lineHeight.js | 4 +- lib/properties/margin.js | 4 +- lib/properties/padding.js | 12 +- lib/properties/right.js | 8 +- lib/properties/top.js | 8 +- lib/properties/width.js | 4 +- 15 files changed, 419 insertions(+), 136 deletions(-) diff --git a/lib/parsers.js b/lib/parsers.js index 4af64c6e..47a1f7cb 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -45,67 +45,298 @@ const ws = `${whitespace}*`; const hexDigit = '[\\da-f]'; const escape = `\\\\([^\\n\\da-f]|${hexDigit}{1,6}${ws})`; const ident = `(-?([_a-z]|${escape})([-_\\w]|${escape})*|--([-_\\w]|${escape})*)`; +const integer = '[-+]?\\d+'; +const number = `((${integer})(\\.\\d+)?|[-+]?(\\.\\d+))(e[-+]?${integer})?`; +const angle = `(${number})(deg|grad|rad|turn)`; +const length = `(${number})(ch|cm|r?em|ex|in|lh|mm|pc|pt|px|q|vh|vmin|vmax|vw)`; +const percentage = `(${number})(%)`; // rough regular expressions +const angleRegEx = new RegExp(`^${angle}$`, 'i'); +const calcOperatorRegEx = new RegExp( + `^${whitespace}[-+]${whitespace}|${whitespace}?[*/]${whitespace}?$` +); +const calcRegEx = new RegExp(`^calc\\(${ws}(.+)${ws}\\)$`, 'i'); +const colorRegEx1 = /^#([0-9a-fA-F]{3,4}){1,2}$/; +const colorRegEx2 = /^rgb\(([^)]*)\)$/; +const colorRegEx3 = /^rgba\(([^)]*)\)$/; +const colorRegEx4 = /^hsla?\(\s*(-?\d+|-?\d*.\d+)\s*,\s*(-?\d+|-?\d*.\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%\s*(,\s*(-?\d+|-?\d*.\d+)\s*)?\)/; const identRegEx = new RegExp(`^${ident}$`, 'i'); -var integerRegEx = /^[-+]?[0-9]+$/; -var numberRegEx = /^[-+]?[0-9]*\.?[0-9]+$/; -var lengthRegEx = /^(0|[-+]?[0-9]*\.?[0-9]+(in|cm|em|mm|pt|pc|px|ex|rem|vh|vw|ch))$/; -var percentRegEx = /^[-+]?[0-9]*\.?[0-9]+%$/; -var urlRegEx = /^url\(\s*([^)]*)\s*\)$/; -var stringRegEx = /^("[^"]*"|'[^']*')$/; -var colorRegEx1 = /^#([0-9a-fA-F]{3,4}){1,2}$/; -var colorRegEx2 = /^rgb\(([^)]*)\)$/; -var colorRegEx3 = /^rgba\(([^)]*)\)$/; -var calcRegEx = /^calc\(([^)]*)\)$/; -var colorRegEx4 = /^hsla?\(\s*(-?\d+|-?\d*.\d+)\s*,\s*(-?\d+|-?\d*.\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%\s*(,\s*(-?\d+|-?\d*.\d+)\s*)?\)/; -var angleRegEx = /^([-+]?[0-9]*\.?[0-9]+)(deg|grad|rad)$/; +const integerRegEx = new RegExp(`^${integer}$`); +const lengthRegEx = new RegExp(`^${length}$`, 'i'); +const numberRegEx = new RegExp(`^${number}$`); +const numericRegEx = new RegExp(`^(${number})(%|${ident})?$`, 'i'); +const percentageRegEx = new RegExp(`^${percentage}$`); +const stringRegEx = /^("[^"]*"|'[^']*')$/; +const timeRegEx = new RegExp(`^(${number})(m?s)$`, 'i'); +const urlRegEx = /^url\(\s*([^)]*)\s*\)$/; +const whitespaceRegEx = new RegExp(`^${whitespace}$`); +const trailingWhitespaceRegEx = new RegExp(`.*${whitespace}$`); exports.parseInteger = function parseInteger(val) { - if (integerRegEx.test(val)) { + const calculated = exports.parseCalc(val); + if (calculated) { + val = calculated; + } + if (numberRegEx.test(val)) { return String(parseInt(val, 10)); } return null; }; exports.parseNumber = function parseNumber(val) { - if (numberRegEx.test(val) || integerRegEx.test(val)) { + const calculated = exports.parseCalc(val); + if (calculated) { + val = calculated; + } + if (numberRegEx.test(val)) { return String(parseFloat(val)); } return null; }; -exports.parseLength = function parseLength(val) { +exports.parseLength = function parseLength(val, resolve = false) { if (val === '0') { return '0px'; } - if (lengthRegEx.test(val)) { - return val; + const calculated = exports.parseCalc(val, v => parseLength(v, resolve)); + if (calculated) { + if (!resolve) { + return calculated; + } + [, val] = calcRegEx.exec(calculated); + } + const res = lengthRegEx.exec(val); + if (res) { + let [, number, , , , , , unit] = res; + unit = unit.toLowerCase(); + if (resolve) { + switch (unit) { + case 'cm': + number *= 96 / 2.54; + unit = 'px'; + break; + case 'mm': + number *= 96 / 2.54 / 10; + unit = 'px'; + break; + case 'q': + number *= 96 / 2.54 / 40; + unit = 'px'; + break; + case 'in': + number *= 96; + unit = 'px'; + break; + case 'pc': + number *= 96 / 6; + unit = 'px'; + break; + case 'pt': + number *= 96 / 72; + unit = 'px'; + break; + } + } + return number + unit; } return null; }; -exports.parsePercent = function parsePercent(val) { +exports.parsePercentage = function parsePercentage(val, resolve = false) { if (val === '0') { return '0%'; } - if (percentRegEx.test(val)) { + const calculated = exports.parseCalc(val, v => parsePercentage(v, resolve)); + if (calculated) { + if (!resolve) { + return calculated; + } + [, val] = calcRegEx.exec(calculated); + } + if (percentageRegEx.test(val)) { return val; } return null; }; -// either a length or a percent -exports.parseMeasurement = function parseMeasurement(val) { - if (calcRegEx.test(val)) { - return val; +exports.parseLengthOrPercentage = function parseLengthOrPercentage(val, resolve) { + return exports.parseLength(val, resolve) || exports.parsePercentage(val, resolve); +}; + +exports.parseAngle = function parseAngle(val, resolve = false) { + const calculated = exports.parseCalc(val, v => parseAngle(v, resolve)); + if (calculated) { + if (!resolve) { + return calculated; + } + [, val] = calcRegEx.exec(calculated); + } + const res = angleRegEx.exec(val); + if (res) { + let [, number, , , , , , unit = ''] = res; + unit = unit.toLowerCase(); + if (resolve) { + if (unit === 'rad') { + number *= 180 / Math.PI; + } else if (unit === 'grad') { + number *= 360 / 400; + } else if (unit === 'turn') { + number *= 360; + } + number = Math.abs(number % 360); + unit = 'deg'; + } + return number + unit; + } + return null; +}; + +exports.parseTime = function parseTime(val, resolve = false) { + const calculated = exports.parseCalc(val, v => parseTime(v, resolve)); + if (calculated) { + if (!resolve) { + return calculated; + } + [, val] = calcRegEx.exec(calculated); + } + const res = timeRegEx.exec(val); + if (res) { + let [, number, , , , , , unit] = res; + unit = unit.toLowerCase(); + if (resolve && unit === 's') { + number *= 1000; + unit = 'ms'; + } + return number + unit; + } + return null; +}; + +exports.parseCalc = function parseCalc(val, parseOperand = exports.parseNumber) { + const res = calcRegEx.exec(val); + if (!res) { + return null; + } + + // Replace ( by calc( when not preceded by var or calc + const stringArgs = res[1].replace(/^\(/, 'calc(').replace(/[^rc]\(/gi, 'calc('); + const operators = /[-+*/]/; + const [operands, ops] = exports.splitTokens(stringArgs, operators); + const { length: operandCount } = operands; + + if (ops.some(operator => !calcOperatorRegEx.test(operator))) { + return null; + } + + // Shunting-yard algorithm, eg. with (1 + 2) * 3 terms are [1, 2, +, 3, *] + const terms = []; + const stack = []; + for (let i = 0; i < operandCount; i++) { + if (i > 0) { + const operator = ops[i - 1].trim(); + let o = stack.length; + // higher or equal precedence than operator at the top of stack + while (stack[--o] && (stack[o] === operator || stack[o] === '*' || stack[o] === '/')) { + terms.push(stack.pop()); + } + stack.push(operator); + if (i === operandCount) { + break; + } + } + + let operand = operands[i]; + + const calculated = exports.parseCalc(operand, parseOperand); + if (calculated) { + // Try to extract a numeric operand from nested calc eg. 2px from calc(1px + calc(1px + 1px)) + operand = parseOperand(calculated); + if (calcRegEx.test(operand)) { + terms.push([operand, null]); + continue; + } + } + + const number = exports.parseNumber(operand); + if (number) { + terms.push([operand, '']); + continue; + } + + const res = numericRegEx.exec(parseOperand(operand)); + if (res) { + const [, number, , , , , , unit] = res; + terms.push([number, unit]); + continue; + } + + return null; } - var length = exports.parseLength(val); - if (length !== null) { - return length; + if (terms === undefined) { + return null; } - return exports.parsePercent(val); + + terms.push(...stack.reverse()); + + // Evaluate operations + const numerics = []; + const { length: termsCount } = terms; + for (let i = 0; i < termsCount; i++) { + const term = terms[i]; + + if (operators.test(term)) { + const [v2, unit2] = numerics.pop(); + const [v1, unit1] = numerics.pop(); + if ( + // + or - and 0 and + ((term === '+' || term === '-') && + ((v1 === '0' && unit1 === '' && unit2) || (v2 === '0' && unit2 === '' && unit1))) || + // * or / and with different units + ((term === '*' || term === '/') && unit1 && unit2 && unit1 !== unit2) + ) { + return null; + } + // with different units or unresolved operand + if ((unit1 !== unit2 && unit1 !== '' && unit2 !== '') || unit1 === null || unit2 === null) { + numerics.push([`${v1}${unit1 || ''} ${term} ${v2}${unit2 || ''}`, null]); + continue; + } + + const unit = unit1 || unit2; + switch (term) { + case '+': + numerics.push([Number(v1) + Number(v2), unit]); + break; + case '-': + numerics.push([Number(v1) - Number(v2), unit]); + break; + case '*': + numerics.push([Number(v1) * Number(v2), unit]); + break; + case '/': + numerics.push([Number(v1) / Number(v2), unit]); + break; + default: + return null; + } + continue; + } + numerics.push(term); + } + + if (numerics.length !== 1) { + return null; + } + + const [value, unit] = numerics[0]; + + if (unit === '') { + // Parse result for dimension type and/or positive requirements + return parseOperand(String(value)); + } + return `calc(${value}${unit || ''})`; }; exports.parseKeyword = function parseKeyword( @@ -223,7 +454,7 @@ exports.parseColor = function parseColor(val) { if (parts.length !== 3) { return null; } - if (parts.every(percentRegEx.test.bind(percentRegEx))) { + if (parts.every(percentageRegEx.test.bind(percentageRegEx))) { red = Math.floor((parseFloat(parts[0].slice(0, -1)) * 255) / 100); green = Math.floor((parseFloat(parts[1].slice(0, -1)) * 255) / 100); blue = Math.floor((parseFloat(parts[2].slice(0, -1)) * 255) / 100); @@ -246,7 +477,7 @@ exports.parseColor = function parseColor(val) { if (parts.length !== 4) { return null; } - if (parts.slice(0, 3).every(percentRegEx.test.bind(percentRegEx))) { + if (parts.slice(0, 3).every(percentageRegEx.test.bind(percentageRegEx))) { red = Math.floor((parseFloat(parts[0].slice(0, -1)) * 255) / 100); green = Math.floor((parseFloat(parts[1].slice(0, -1)) * 255) / 100); blue = Math.floor((parseFloat(parts[2].slice(0, -1)) * 255) / 100); @@ -296,27 +527,6 @@ exports.parseColor = function parseColor(val) { return exports.parseKeyword(val, namedColors); }; -exports.parseAngle = function parseAngle(val) { - if (angleRegEx.test(val)) { - var res = angleRegEx.exec(val); - var flt = parseFloat(res[1]); - if (res[2] === 'rad') { - flt *= 180 / Math.PI; - } else if (res[2] === 'grad') { - flt *= 360 / 400; - } - - while (flt < 0) { - flt += 360; - } - while (flt > 360) { - flt -= 360; - } - return flt + 'deg'; - } - return null; -}; - /** * utility to translate from border-width to borderWidth * @@ -347,51 +557,73 @@ function cssPropertyToIDLAttribute(property, lowercaseFirst = false) { } exports.cssPropertyToIDLAttribute = cssPropertyToIDLAttribute; -var is_space = /\s/; -var opening_deliminators = ['"', "'", '(']; -var closing_deliminators = ['"', "'", ')']; -// this splits on whitespace, but keeps quoted and parened parts together -var getParts = function(str) { - var deliminator_stack = []; - var length = str.length; - var i; - var parts = []; - var current_part = ''; - var opening_index; - var closing_index; - for (i = 0; i < length; i++) { - opening_index = opening_deliminators.indexOf(str[i]); - closing_index = closing_deliminators.indexOf(str[i]); - if (is_space.test(str[i])) { - if (deliminator_stack.length === 0) { - if (current_part !== '') { - parts.push(current_part); +/** + * @param {string} val + * @param {RegExp} separators + * @returns + * + * This function is used to split args from a function, components from a value, + * or a list of values, that can have nested item sharing the same separator(s). + * + * Leading/trailing whitespaces are expected to be trimmed from value. + */ +exports.splitTokens = function splitTokens(val, separators = whitespaceRegEx) { + let argIndex = 0; + let depth = 0; + + const seps = []; + const args = Array.from(val).reduce((args, char) => { + if (char === '(') { + depth++; + } else if (char === ')') { + depth--; + } else if (depth === 0 && separators.test(char)) { + if (args[argIndex] === undefined) { + // Create empty arg + if (!whitespaceRegEx.test(char) && !whitespaceRegEx.test(seps[argIndex - 1])) { + args[argIndex] = ''; + } + // Keep separator with (single) leading whitespace + if (whitespaceRegEx.test(seps[argIndex - 1])) { + if (char !== ' ') { + seps[argIndex - 1] += char; + } + return args; + } + // Keep separator with (single) trailing whitespace + if (whitespaceRegEx.test(char)) { + if (!trailingWhitespaceRegEx.test(seps[argIndex - 1])) { + seps[argIndex - 1] += char; + } + return args; } - current_part = ''; - } else { - current_part += str[i]; } - } else { - if (str[i] === '\\') { - i++; - current_part += str[i]; + // Pop trailing whitespace from arg when not specified as an operator + if (trailingWhitespaceRegEx.test(args[argIndex])) { + char = args[argIndex].slice(-1) + char; + args[argIndex] = args[argIndex].slice(0, -1); + } + argIndex++; + seps.push(char); + return args; + } + if (args[argIndex] === undefined) { + if (whitespaceRegEx.test(char)) { + seps[argIndex - 1] += char; } else { - current_part += str[i]; - if ( - closing_index !== -1 && - closing_index === deliminator_stack[deliminator_stack.length - 1] - ) { - deliminator_stack.pop(); - } else if (opening_index !== -1) { - deliminator_stack.push(opening_index); - } + args.push(char); } + } else { + args[argIndex] += char; } + return args; + }, []); + + if (args.length === seps.length) { + args.push(''); } - if (current_part !== '') { - parts.push(current_part); - } - return parts; + + return [args.map(a => a.trim('')), seps]; }; /** @@ -406,7 +638,7 @@ var getParts = function(str) { */ exports.parseShorthand = function parseShorthand(value, longhands) { const parsed = {}; - const components = getParts(value); + const [components] = exports.splitTokens(value); const entries = Object.entries(longhands); const valid = components.every((component, position) => entries.some(longhand => { @@ -436,7 +668,7 @@ exports.parseShorthand = function parseShorthand(value, longhands) { * @returns {object | null} */ exports.parseImplicitShorthand = function parseImplicitShorthand(value, longhands) { - const components = getParts(value); + const [components] = exports.splitTokens(value); const entries = Object.entries(longhands); const { length: longhandLength } = entries; let { length: currentLength } = components; diff --git a/lib/parsers.test.js b/lib/parsers.test.js index 3f84a690..ba7d15f9 100644 --- a/lib/parsers.test.js +++ b/lib/parsers.test.js @@ -20,13 +20,13 @@ describe('parseLength', () => { }); it.todo('more tests'); }); -describe('parsePercent', () => { +describe('parsePercentage', () => { it('works with calc', () => { - expect(parsers.parsePercent('calc(1% + 1%)')).toBe('calc(2%)'); + expect(parsers.parsePercentage('calc(1% + 1%)')).toBe('calc(2%)'); }); it.todo('more tests'); }); -describe('parseMeasurement', () => { +describe('parseLengthOrPercentage', () => { it.todo('test'); }); describe('parseAngle', () => { @@ -73,9 +73,7 @@ describe('parseCalc', () => { expect(parsers.parseCalc('calc(1px + 1pc)', resolveLengthOrPercentage)).toBe('calc(17px)'); expect(parsers.parseCalc('calc(1turn + 180deg)', resolveAngle)).toBe('calc(180deg)'); expect(parsers.parseCalc('calc(1s + 1000ms)', resolveTime)).toBe('calc(2000ms)'); - expect(parsers.parseCalc('CALc(1px + 1em)', resolveLengthOrPercentage)).toBe( - 'calc(1px + 1em)' - ); + expect(parsers.parseCalc('CALc(1px + 1em)', resolveLengthOrPercentage)).toBe('calc(1px + 1em)'); }); }); describe('parseKeyword', () => { @@ -263,3 +261,53 @@ describe('createShorthandGetter', () => { describe('idlAttributeToCSSProperty', () => { it.todo('test'); }); +describe('splitTokens', () => { + it('should split value components separated by space', () => { + expect(parsers.splitTokens('1px solid red')).toEqual([['1px', 'solid', 'red'], [' ', ' ']]); + }); + it('should split value components separated by space and forward slash', () => { + expect(parsers.splitTokens('url(bg.jpq) center / 50%', /[ /]/)).toEqual([ + ['url(bg.jpq)', 'center', '50%'], + [' ', ' / '], + ]); + }); + it('should split a list of values', () => { + expect(parsers.splitTokens('1px 1px black, 2px 2px silver', /,/)).toEqual([ + ['1px 1px black', '2px 2px silver'], + [', '], + ]); + }); + it('should split color function arguments', () => { + const separators = /[,/ ]/; + expect(parsers.splitTokens('0,0,0', separators)).toEqual([['0', '0', '0'], [',', ',']]); + expect(parsers.splitTokens('0,1%,2%', separators)).toEqual([['0', '1%', '2%'], [',', ',']]); + expect(parsers.splitTokens('0 , 0 , 0', separators)).toEqual([ + ['0', '0', '0'], + [' , ', ' , '], + ]); + expect(parsers.splitTokens('0deg, 1%, 2%', separators)).toEqual([ + ['0deg', '1%', '2%'], + [', ', ', '], + ]); + expect(parsers.splitTokens('0deg 1% / 2%', separators)).toEqual([ + ['0deg', '1%', '2%'], + [' ', ' / '], + ]); + }); + it('should split nested function arguments', () => { + expect(parsers.splitTokens('calc(45deg * 2) to left, rgb(255, 0, 0), cyan', /,/)).toEqual([ + ['calc(45deg * 2) to left', 'rgb(255, 0, 0)', 'cyan'], + [', ', ', '], + ]); + expect(parsers.splitTokens('calc(1 + 1) + var(--number, calc(1 + 1)) * 1', /[+*]/)).toEqual([ + ['calc(1 + 1)', 'var(--number, calc(1 + 1))', '1'], + [' + ', ' * '], + ]); + }); + it('should split function with empty arguments', () => { + expect(parsers.splitTokens(', , ,, 1%,', /,/)).toEqual([ + ['', '', '', '', '1%', ''], + [', ', ', ', ',', ', ', ','], + ]); + }); +}); diff --git a/lib/properties/backgroundPosition.js b/lib/properties/backgroundPosition.js index 129e3dc9..fff7ed6a 100644 --- a/lib/properties/backgroundPosition.js +++ b/lib/properties/backgroundPosition.js @@ -1,6 +1,6 @@ 'use strict'; -const { parseKeyword, parseMeasurement } = require('../parsers'); +const { parseKeyword, parseLengthOrPercentage } = require('../parsers'); var valid_keywords = ['top', 'center', 'bottom', 'left', 'right']; @@ -10,13 +10,16 @@ var parse = function parse(v) { return null; } if (parts.length === 1) { - const value = parseMeasurement(parts[0]) || parseKeyword(parts[0], valid_keywords); + const value = parseLengthOrPercentage(parts[0]) || parseKeyword(parts[0], valid_keywords); if (value) { return `${value} center`; } return null; } - if (parseMeasurement(parts[0]) !== null && parseMeasurement(parts[1]) !== null) { + if ( + parseLengthOrPercentage(parts[0]) !== null && + parseLengthOrPercentage(parts[1]) !== null + ) { return v; } if ( diff --git a/lib/properties/bottom.js b/lib/properties/bottom.js index e9d72b22..4bffbbd9 100644 --- a/lib/properties/bottom.js +++ b/lib/properties/bottom.js @@ -1,12 +1,12 @@ 'use strict'; -var parseMeasurement = require('../parsers').parseMeasurement; +const { parseLengthOrPercentage } = require('../parsers'); module.exports.definition = { - set: function(v) { - this._setProperty('bottom', parseMeasurement(v)); + set(v) { + this._setProperty('bottom', parseLengthOrPercentage(v)); }, - get: function() { + get() { return this.getPropertyValue('bottom'); }, enumerable: true, diff --git a/lib/properties/clip.js b/lib/properties/clip.js index c30d3f2b..5b43c2da 100644 --- a/lib/properties/clip.js +++ b/lib/properties/clip.js @@ -1,6 +1,6 @@ 'use strict'; -const { parseKeyword, parseMeasurement } = require('../parsers'); +const { parseKeyword, parseLengthOrPercentage } = require('../parsers'); var shape_regex = /^rect\((.*)\)$/i; @@ -18,7 +18,7 @@ function parse(val) { return null; } var valid = parts.every(function(part, index) { - const measurement = parseMeasurement(part.toLowerCase()); + const measurement = parseLengthOrPercentage(part); parts[index] = measurement; return measurement !== null; }); diff --git a/lib/properties/flexBasis.js b/lib/properties/flexBasis.js index 5bf01fdc..eb4d8ae5 100644 --- a/lib/properties/flexBasis.js +++ b/lib/properties/flexBasis.js @@ -1,9 +1,9 @@ 'use strict'; -const { parseKeyword, parseMeasurement } = require('../parsers'); +const { parseKeyword, parseLengthOrPercentage } = require('../parsers'); function parse(v) { - return parseKeyword(v, ['auto']) || parseMeasurement(v); + return parseKeyword(v, ['auto']) || parseLengthOrPercentage(v); } module.exports.definition = { diff --git a/lib/properties/fontSize.js b/lib/properties/fontSize.js index 45b53d0c..09941c71 100644 --- a/lib/properties/fontSize.js +++ b/lib/properties/fontSize.js @@ -1,6 +1,6 @@ 'use strict'; -const { parseKeyword, parseMeasurement } = require('../parsers'); +const { parseKeyword, parseLengthOrPercentage } = require('../parsers'); const sizes = [ // Absolute @@ -17,7 +17,7 @@ const sizes = [ ]; function parse(v) { - return parseKeyword(v, sizes) || parseMeasurement(v); + return parseKeyword(v, sizes) || parseLengthOrPercentage(v); } module.exports.definition = { diff --git a/lib/properties/height.js b/lib/properties/height.js index 6f1dcd56..80045648 100644 --- a/lib/properties/height.js +++ b/lib/properties/height.js @@ -1,10 +1,10 @@ 'use strict'; -const { parseKeyword, parseMeasurement } = require('../parsers'); +const { parseKeyword, parseLengthOrPercentage } = require('../parsers'); module.exports.definition = { set(v) { - this._setProperty('height', parseKeyword(v, ['auto']) || parseMeasurement(v)); + this._setProperty('height', parseKeyword(v, ['auto']) || parseLengthOrPercentage(v)); }, get() { return this.getPropertyValue('height'); diff --git a/lib/properties/left.js b/lib/properties/left.js index 72bb2faf..097c1517 100644 --- a/lib/properties/left.js +++ b/lib/properties/left.js @@ -1,12 +1,12 @@ 'use strict'; -var parseMeasurement = require('../parsers').parseMeasurement; +const { parseLengthOrPercentage } = require('../parsers'); module.exports.definition = { - set: function(v) { - this._setProperty('left', parseMeasurement(v)); + set(v) { + this._setProperty('left', parseLengthOrPercentage(v)); }, - get: function() { + get() { return this.getPropertyValue('left'); }, enumerable: true, diff --git a/lib/properties/lineHeight.js b/lib/properties/lineHeight.js index 627f827f..0e408624 100644 --- a/lib/properties/lineHeight.js +++ b/lib/properties/lineHeight.js @@ -1,9 +1,9 @@ 'use strict'; -const { parseKeyword, parseMeasurement, parseNumber } = require('../parsers'); +const { parseKeyword, parseLengthOrPercentage, parseNumber } = require('../parsers'); function parse(v) { - return parseKeyword(v, ['normal']) || parseNumber(v) || parseMeasurement(v); + return parseKeyword(v, ['normal']) || parseNumber(v) || parseLengthOrPercentage(v); } module.exports.definition = { diff --git a/lib/properties/margin.js b/lib/properties/margin.js index 12c0ff5f..2788f84a 100644 --- a/lib/properties/margin.js +++ b/lib/properties/margin.js @@ -5,12 +5,12 @@ const { createShorthandSetter, parseImplicitShorthand, parseKeyword, - parseMeasurement, + parseLengthOrPercentage, serializeImplicitShorthand, } = require('../parsers'); function parse(v) { - return parseKeyword(v, ['auto']) || parseMeasurement(v); + return parseKeyword(v, ['auto']) || parseLengthOrPercentage(v); } const longhands = { diff --git a/lib/properties/padding.js b/lib/properties/padding.js index 5a924abd..c5b8eb8c 100644 --- a/lib/properties/padding.js +++ b/lib/properties/padding.js @@ -4,15 +4,15 @@ const { createShorthandGetter, createShorthandSetter, parseImplicitShorthand, - parseMeasurement, + parseLengthOrPercentage, serializeImplicitShorthand, } = require('../parsers'); const longhands = { - 'padding-top': { parse: parseMeasurement }, - 'padding-right': { parse: parseMeasurement }, - 'padding-bottom': { parse: parseMeasurement }, - 'padding-left': { parse: parseMeasurement }, + 'padding-top': { parse: parseLengthOrPercentage }, + 'padding-right': { parse: parseLengthOrPercentage }, + 'padding-bottom': { parse: parseLengthOrPercentage }, + 'padding-left': { parse: parseLengthOrPercentage }, }; module.exports.definition = { @@ -22,5 +22,5 @@ module.exports.definition = { configurable: true, }; module.exports.longhands = Object.keys(longhands); -module.exports.parse = parseMeasurement; +module.exports.parse = parseLengthOrPercentage; module.exports.serialize = serializeImplicitShorthand; diff --git a/lib/properties/right.js b/lib/properties/right.js index eb4c3d49..5fba8e19 100644 --- a/lib/properties/right.js +++ b/lib/properties/right.js @@ -1,12 +1,12 @@ 'use strict'; -var parseMeasurement = require('../parsers').parseMeasurement; +const { parseLengthOrPercentage } = require('../parsers'); module.exports.definition = { - set: function(v) { - this._setProperty('right', parseMeasurement(v)); + set(v) { + this._setProperty('right', parseLengthOrPercentage(v)); }, - get: function() { + get() { return this.getPropertyValue('right'); }, enumerable: true, diff --git a/lib/properties/top.js b/lib/properties/top.js index f71986fe..a400d981 100644 --- a/lib/properties/top.js +++ b/lib/properties/top.js @@ -1,12 +1,12 @@ 'use strict'; -var parseMeasurement = require('../parsers').parseMeasurement; +const { parseLengthOrPercentage } = require('../parsers'); module.exports.definition = { - set: function(v) { - this._setProperty('top', parseMeasurement(v)); + set(v) { + this._setProperty('top', parseLengthOrPercentage(v)); }, - get: function() { + get() { return this.getPropertyValue('top'); }, enumerable: true, diff --git a/lib/properties/width.js b/lib/properties/width.js index e69a0155..9246606f 100644 --- a/lib/properties/width.js +++ b/lib/properties/width.js @@ -1,10 +1,10 @@ 'use strict'; -const { parseKeyword, parseMeasurement } = require('../parsers'); +const { parseKeyword, parseLengthOrPercentage } = require('../parsers'); module.exports.definition = { set(v) { - this._setProperty('width', parseKeyword(v, ['auto']) || parseMeasurement(v)); + this._setProperty('width', parseKeyword(v, ['auto']) || parseLengthOrPercentage(v)); }, get() { return this.getPropertyValue('width');