Skip to content

Commit

Permalink
feat: parse positive numeric
Browse files Browse the repository at this point in the history
Required for eg. <shape-radius> circle() argument, used to define clip-path, shape-outside, or
offset-path.
  • Loading branch information
cdoublev committed May 24, 2021
1 parent 852e70a commit 195ace9
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 9 deletions.
35 changes: 26 additions & 9 deletions lib/parsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ function serializeNumber(n) {
* https://drafts.csswg.org/css-values-4/#integers
* https://drafts.csswg.org/cssom/#ref-for-integer-value
*/
exports.parseInteger = function parseInteger(val) {
exports.parseInteger = function parseInteger(val, positive = false) {
if (val === '') {
return val;
}
Expand All @@ -167,7 +167,13 @@ exports.parseInteger = function parseInteger(val) {
const res = numberRegEx.exec(val);
if (res) {
const [, , integer, decimals, onlyDecimals, exponent] = res;
if (integer === undefined || decimals || onlyDecimals || (exponent && exponent.slice(1) < 0)) {
if (
integer === undefined ||
decimals ||
onlyDecimals ||
(exponent && exponent.slice(1) < 0) ||
(positive && integer < 0)
) {
return undefined;
}
return serializeNumber(val);
Expand All @@ -179,7 +185,7 @@ exports.parseInteger = function parseInteger(val) {
* https://drafts.csswg.org/css-values-4/#numbers
* https://drafts.csswg.org/cssom/#ref-for-number-value
*/
exports.parseNumber = function parseNumber(val) {
exports.parseNumber = function parseNumber(val, positive = false) {
if (val === '') {
return val;
}
Expand All @@ -188,6 +194,9 @@ exports.parseNumber = function parseNumber(val) {
val = calculated;
}
if (numberRegEx.test(val)) {
if (positive && val < 0) {
return undefined;
}
return serializeNumber(val);
}
return exports.parseCustomVariable(val);
Expand All @@ -197,14 +206,14 @@ exports.parseNumber = function parseNumber(val) {
* https://drafts.csswg.org/css-values-4/#lengths
* https://drafts.csswg.org/cssom/#ref-for-length-value
*/
exports.parseLength = function parseLength(val, resolve = false) {
exports.parseLength = function parseLength(val, resolve = false, positive = false) {
if (val === '') {
return val;
}
if (val === '0') {
return '0px';
}
const calculated = exports.parseCalc(val, v => parseLength(v, resolve));
const calculated = exports.parseCalc(val, v => parseLength(v, resolve, positive));
if (calculated) {
if (!resolve) {
return calculated;
Expand All @@ -214,6 +223,9 @@ exports.parseLength = function parseLength(val, resolve = false) {
const res = lengthRegEx.exec(val);
if (res) {
let [, number, , , , , , unit] = res;
if (positive && number < 0) {
return undefined;
}
unit = unit.toLowerCase();
if (resolve) {
switch (unit) {
Expand Down Expand Up @@ -252,14 +264,14 @@ exports.parseLength = function parseLength(val, resolve = false) {
* https://drafts.csswg.org/css-values-4/#percentages
* https://drafts.csswg.org/cssom/#ref-for-percentage-value
*/
exports.parsePercentage = function parsePercentage(val, resolve = false) {
exports.parsePercentage = function parsePercentage(val, resolve = false, positive = false) {
if (val === '') {
return val;
}
if (val === '0') {
return '0%';
}
const calculated = exports.parseCalc(val, v => parsePercentage(v, resolve));
const calculated = exports.parseCalc(val, v => parsePercentage(v, resolve, positive));
if (calculated) {
if (!resolve) {
return calculated;
Expand All @@ -269,13 +281,18 @@ exports.parsePercentage = function parsePercentage(val, resolve = false) {
const res = percentageRegEx.exec(val);
if (res) {
const [, number] = res;
if (positive && number < 0) {
return undefined;
}
return serializeNumber(number) + '%';
}
return exports.parseCustomVariable(val);
};

exports.parseLengthOrPercentage = function parseLengthOrPercentage(val, resolve) {
return exports.parseLength(val, resolve) || exports.parsePercentage(val, resolve);
exports.parseLengthOrPercentage = function parseLengthOrPercentage(val, resolve, positive) {
return (
exports.parseLength(val, resolve, positive) || exports.parsePercentage(val, resolve, positive)
);
};

/**
Expand Down
14 changes: 14 additions & 0 deletions lib/parsers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ describe('parseInteger', () => {
const invalid = ['string', '1px', '#1', '1.1', '.1', '1e-1', 'calc(1 / 2)'];
invalid.forEach(input => expect(parsers.parseInteger(input)).toBeUndefined());
});
it('returns undefined for negative values when positive is required', () => {
expect(parsers.parseInteger(-1, true)).toBeUndefined();
});
it('parses integer with exponent', () => {
expect(parsers.parseInteger('1e1')).toBe('10');
expect(parsers.parseInteger('1e+1')).toBe('10');
Expand All @@ -23,6 +26,9 @@ describe('parseNumber', () => {
const invalid = ['string', '1px', '#1', 'calc(1 * 1px)'];
invalid.forEach(input => expect(parsers.parseNumber(input)).toBeUndefined());
});
it('returns undefined for negative values when positive is required', () => {
expect(parsers.parseNumber(-1, true)).toBeUndefined();
});
it('parses number with exponent', () => {
expect(parsers.parseNumber('1e1')).toBe('10');
expect(parsers.parseNumber('1e+1')).toBe('10');
Expand All @@ -46,6 +52,10 @@ describe('parseLength', () => {
const invalid = ['string', '1', 'px', '1%', '#1px', '1px%', 'calc(1 * 1%)'];
invalid.forEach(input => expect(parsers.parseLength(input)).toBeUndefined());
});
it('returns undefined for negative values when positive is required', () => {
expect(parsers.parseLength('-1px', false, true)).toBeUndefined();
expect(parsers.parsePercentage('calc(-1px)', true, true)).toBeUndefined();
});
it('parses 0 to 0px', () => {
expect(parsers.parseLength('0')).toBe('0px');
});
Expand Down Expand Up @@ -84,6 +94,10 @@ describe('parsePercentage', () => {
const invalid = ['string', '1', '%', '1px', '#1%', '1%%', 'calc(1 * 1px)'];
invalid.forEach(input => expect(parsers.parsePercentage(input)).toBeUndefined());
});
it('returns undefined for negative values when positive is required', () => {
expect(parsers.parsePercentage('-1%', false, true)).toBeUndefined();
expect(parsers.parsePercentage('calc(-1%)', true, true)).toBeUndefined();
});
it('parses percentage with exponent', () => {
expect(parsers.parsePercentage('1e1%')).toBe('10%');
expect(parsers.parsePercentage('1e+1%')).toBe('10%');
Expand Down

0 comments on commit 195ace9

Please sign in to comment.