From f1bad43d49895ea0516ca38433eb5b5876df35d1 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 10:43:25 +0100 Subject: [PATCH 01/24] make parseRgba option --- src/index.js | 5 ++++- test/{test.js => hex.test.js} | 0 test/rgba.test.js | 11 +++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) rename test/{test.js => hex.test.js} (100%) create mode 100644 test/rgba.test.js diff --git a/src/index.js b/src/index.js index 17bdf05..70510a7 100644 --- a/src/index.js +++ b/src/index.js @@ -52,7 +52,10 @@ const formatRgb = (decimalObject, parameterA) => { * @param An alpha value to apply. (optional) ('0.5', '0.25') * @return An rgb or rgba value. ('rgb(11, 22, 33)'. 'rgba(11, 22, 33, 0.5)') */ -const hexToRgba = (hex, a) => { +const hexToRgba = (hex, a, parseRgba = false) => { + if (parseRgba) { + return true; + } const hashlessHex = removeHash(hex); const hexObject = parseHex(hashlessHex); const decimalObject = hexesToDecimals(hexObject); diff --git a/test/test.js b/test/hex.test.js similarity index 100% rename from test/test.js rename to test/hex.test.js diff --git a/test/rgba.test.js b/test/rgba.test.js new file mode 100644 index 0000000..815facb --- /dev/null +++ b/test/rgba.test.js @@ -0,0 +1,11 @@ +/* global describe it */ +import assert from 'assert'; +import hexToRgba from '..'; + +describe('rgba?-to-rgba', () => { + describe('parse rgba option', () => { + it('should parse rgba strings when set to true', () => { + assert.equal(true, hexToRgba('rgba(17, 34, 51, 1)', undefined, true)); + }); + }); +}); From bdf367d434801bef231e8c7d18a560c5de1e93a6 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 11:03:34 +0100 Subject: [PATCH 02/24] make rgba parse pass for a simple rgba string --- src/index.js | 17 ++++++++++++++++- test/rgba.test.js | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 70510a7..98f89bc 100644 --- a/src/index.js +++ b/src/index.js @@ -43,6 +43,20 @@ const formatRgb = (decimalObject, parameterA) => { return `rgba(${r}, ${g}, ${b}, ${a})`; }; +const RE_RGB = /^rgb\(\d{1,3}, *\d{1,3}, *\d{1,3}\)$/; +const RE_RGBA = /^rgba\(\d{1,3}, *\d{1,3}, *\d{1,3}(?:, *(?:\d\.)?\d+)?\)$/; +const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; + +const rgbaToRgba = (str, alpha) => { + if (RE_RGB.test(str)) { + return 'rgba()'; + } + if (RE_RGBA.test(str)) { + return str.replace(RE_ALPHA, `${alpha}`); + } + throw Error(`rgba string is invalid, must be in the form rgba?(num, num, num, num?), not: ${str}`); +}; + /** * Turns an old-fashioned css hex color value into a rgb color value. * @@ -54,8 +68,9 @@ const formatRgb = (decimalObject, parameterA) => { */ const hexToRgba = (hex, a, parseRgba = false) => { if (parseRgba) { - return true; + return rgbaToRgba(hex, a); } + const hashlessHex = removeHash(hex); const hexObject = parseHex(hashlessHex); const decimalObject = hexesToDecimals(hexObject); diff --git a/test/rgba.test.js b/test/rgba.test.js index 815facb..f20ea9b 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -5,7 +5,7 @@ import hexToRgba from '..'; describe('rgba?-to-rgba', () => { describe('parse rgba option', () => { it('should parse rgba strings when set to true', () => { - assert.equal(true, hexToRgba('rgba(17, 34, 51, 1)', undefined, true)); + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('rgba(17, 34, 51, 1)', '0.5', true)); }); }); }); From 4d3d544e36425167dcf6c1cf0005e9d9406f4990 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 11:05:32 +0100 Subject: [PATCH 03/24] make rgba parse pass for a simple rgba string --- test/rgba.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/rgba.test.js b/test/rgba.test.js index f20ea9b..b51fb05 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -7,5 +7,9 @@ describe('rgba?-to-rgba', () => { it('should parse rgba strings when set to true', () => { assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('rgba(17, 34, 51, 1)', '0.5', true)); }); + + it('should parse rgb strings when set to true', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('rgb(17, 34, 51)', '0.5', true)); + }); }); }); From 89b4775737b8eb1e7e93962cc78d5efb5d8fd494 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 11:08:56 +0100 Subject: [PATCH 04/24] Parse rgb strings, make pass test --- src/index.js | 3 ++- test/rgba.test.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 98f89bc..daa54f6 100644 --- a/src/index.js +++ b/src/index.js @@ -46,10 +46,11 @@ const formatRgb = (decimalObject, parameterA) => { const RE_RGB = /^rgb\(\d{1,3}, *\d{1,3}, *\d{1,3}\)$/; const RE_RGBA = /^rgba\(\d{1,3}, *\d{1,3}, *\d{1,3}(?:, *(?:\d\.)?\d+)?\)$/; const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; +const RE_NO_ALPHA = /\)/; const rgbaToRgba = (str, alpha) => { if (RE_RGB.test(str)) { - return 'rgba()'; + return str.replace(RE_NO_ALPHA, `, ${alpha})`); } if (RE_RGBA.test(str)) { return str.replace(RE_ALPHA, `${alpha}`); diff --git a/test/rgba.test.js b/test/rgba.test.js index b51fb05..e8bed9b 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -9,7 +9,7 @@ describe('rgba?-to-rgba', () => { }); it('should parse rgb strings when set to true', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('rgb(17, 34, 51)', '0.5', true)); + assert.equal('rgb(17, 34, 51, 0.5)', hexToRgba('rgb(17, 34, 51)', '0.5', true)); }); }); }); From 4f1498b68b218bb6cb231dea03bee34830132c1b Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 11:39:56 +0100 Subject: [PATCH 05/24] test rbb throws when given an alpha channel --- src/error.js | 8 ++++++++ src/index.js | 6 ++++-- test/rgba.test.js | 15 ++++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 src/error.js diff --git a/src/error.js b/src/error.js new file mode 100644 index 0000000..ebf031d --- /dev/null +++ b/src/error.js @@ -0,0 +1,8 @@ +class RgbParseError extends Error { + constructor(message) { + super(message); + this.name = 'RgbParseError'; + } +} + +module.exports = { RgbParseError }; diff --git a/src/index.js b/src/index.js index daa54f6..7e45fe8 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,5 @@ +import { RgbParseError } from './error'; + const removeHash = hex => (hex.charAt(0) === '#' ? hex.slice(1) : hex); const parseHex = (nakedHex) => { @@ -44,7 +46,7 @@ const formatRgb = (decimalObject, parameterA) => { }; const RE_RGB = /^rgb\(\d{1,3}, *\d{1,3}, *\d{1,3}\)$/; -const RE_RGBA = /^rgba\(\d{1,3}, *\d{1,3}, *\d{1,3}(?:, *(?:\d\.)?\d+)?\)$/; +const RE_RGBA = /^rgba\(\d{1,3}, *\d{1,3}, *\d{1,3}(?:, *(?:\d\.)?\d+)\)$/; const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; const RE_NO_ALPHA = /\)/; @@ -55,7 +57,7 @@ const rgbaToRgba = (str, alpha) => { if (RE_RGBA.test(str)) { return str.replace(RE_ALPHA, `${alpha}`); } - throw Error(`rgba string is invalid, must be in the form rgba?(num, num, num, num?), not: ${str}`); + throw new RgbParseError(`rgba? string is invalid, must be in the form rgba?(num, num, num, num?), not: ${str}`); }; /** diff --git a/test/rgba.test.js b/test/rgba.test.js index e8bed9b..70dd19c 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -3,7 +3,7 @@ import assert from 'assert'; import hexToRgba from '..'; describe('rgba?-to-rgba', () => { - describe('parse rgba option', () => { + describe('parseRgba option', () => { it('should parse rgba strings when set to true', () => { assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('rgba(17, 34, 51, 1)', '0.5', true)); }); @@ -12,4 +12,17 @@ describe('rgba?-to-rgba', () => { assert.equal('rgb(17, 34, 51, 0.5)', hexToRgba('rgb(17, 34, 51)', '0.5', true)); }); }); + + describe('rgb parser', () => { + it('should throw when given an alpha channel', () => { + const callback = () => hexToRgba('rgb(17, 34, 51, 1)', undefined, true); + assert.throws(callback, Error); // RgbParseError doesn't pass, even though it throws + }); + }); + describe('rgba parser', () => { + it('should throw when not given an alpha channel', () => { + const callback = () => hexToRgba('rgba(17, 34, 51)', undefined, true); + assert.throws(callback, Error); // RgbParseError doesn't pass, even though it throws + }); + }); }); From e0b8edf4c1d56c52f15baceb6d25f0bb0691fa7f Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 11:54:16 +0100 Subject: [PATCH 06/24] make default alpha --- src/index.js | 6 +++--- test/rgba.test.js | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 7e45fe8..a008def 100644 --- a/src/index.js +++ b/src/index.js @@ -50,12 +50,12 @@ const RE_RGBA = /^rgba\(\d{1,3}, *\d{1,3}, *\d{1,3}(?:, *(?:\d\.)?\d+)\)$/; const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; const RE_NO_ALPHA = /\)/; -const rgbaToRgba = (str, alpha) => { +const rgbaToRgba = (str, a = 1) => { if (RE_RGB.test(str)) { - return str.replace(RE_NO_ALPHA, `, ${alpha})`); + return str.replace(RE_NO_ALPHA, `, ${a})`).replace(/rgb\(/, 'rgba('); } if (RE_RGBA.test(str)) { - return str.replace(RE_ALPHA, `${alpha}`); + return str.replace(RE_ALPHA, `${a}`); } throw new RgbParseError(`rgba? string is invalid, must be in the form rgba?(num, num, num, num?), not: ${str}`); }; diff --git a/test/rgba.test.js b/test/rgba.test.js index 70dd19c..5047d14 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -9,7 +9,7 @@ describe('rgba?-to-rgba', () => { }); it('should parse rgb strings when set to true', () => { - assert.equal('rgb(17, 34, 51, 0.5)', hexToRgba('rgb(17, 34, 51)', '0.5', true)); + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('rgb(17, 34, 51)', '0.5', true)); }); }); @@ -18,7 +18,12 @@ describe('rgba?-to-rgba', () => { const callback = () => hexToRgba('rgb(17, 34, 51, 1)', undefined, true); assert.throws(callback, Error); // RgbParseError doesn't pass, even though it throws }); + + it('should default to 1 for alpha if no alpha is given', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('rgb(17, 34, 51)', undefined, true)); + }); }); + describe('rgba parser', () => { it('should throw when not given an alpha channel', () => { const callback = () => hexToRgba('rgba(17, 34, 51)', undefined, true); From cb9db77b1e7694733f2b5b23f9b433ecf944169e Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 12:04:11 +0100 Subject: [PATCH 07/24] don't overwrite alpha on alpha strings if alpha is undefined --- src/index.js | 7 ++++--- test/rgba.test.js | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index a008def..f87d200 100644 --- a/src/index.js +++ b/src/index.js @@ -50,12 +50,13 @@ const RE_RGBA = /^rgba\(\d{1,3}, *\d{1,3}, *\d{1,3}(?:, *(?:\d\.)?\d+)\)$/; const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; const RE_NO_ALPHA = /\)/; -const rgbaToRgba = (str, a = 1) => { +const rgbaToRgba = (str, a) => { if (RE_RGB.test(str)) { - return str.replace(RE_NO_ALPHA, `, ${a})`).replace(/rgb\(/, 'rgba('); + const alpha = a !== undefined ? a : 1; // alpha, or default alpha + return str.replace(RE_NO_ALPHA, `, ${alpha})`).replace(/rgb\(/, 'rgba('); } if (RE_RGBA.test(str)) { - return str.replace(RE_ALPHA, `${a}`); + return a !== undefined ? str.replace(RE_ALPHA, `${a}`) : str; // replace alpha if defined, otherwise don't } throw new RgbParseError(`rgba? string is invalid, must be in the form rgba?(num, num, num, num?), not: ${str}`); }; diff --git a/test/rgba.test.js b/test/rgba.test.js index 5047d14..4af6d88 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -29,5 +29,9 @@ describe('rgba?-to-rgba', () => { const callback = () => hexToRgba('rgba(17, 34, 51)', undefined, true); assert.throws(callback, Error); // RgbParseError doesn't pass, even though it throws }); + + it('should leave the alpha channel untouched if no alpha is given', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('rgba(17, 34, 51, 0.5)', undefined, true)); + }); }); }); From ca0272e065224a491497664d5b6f50f14724bcda Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 13:37:48 +0100 Subject: [PATCH 08/24] Move parser to dedicated module --- src/index.js | 18 +----------------- src/rgb-parser.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 17 deletions(-) create mode 100644 src/rgb-parser.js diff --git a/src/index.js b/src/index.js index f87d200..b9addb4 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import { RgbParseError } from './error'; +import rgbaToRgba from './rgb-parser'; const removeHash = hex => (hex.charAt(0) === '#' ? hex.slice(1) : hex); @@ -45,22 +45,6 @@ const formatRgb = (decimalObject, parameterA) => { return `rgba(${r}, ${g}, ${b}, ${a})`; }; -const RE_RGB = /^rgb\(\d{1,3}, *\d{1,3}, *\d{1,3}\)$/; -const RE_RGBA = /^rgba\(\d{1,3}, *\d{1,3}, *\d{1,3}(?:, *(?:\d\.)?\d+)\)$/; -const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; -const RE_NO_ALPHA = /\)/; - -const rgbaToRgba = (str, a) => { - if (RE_RGB.test(str)) { - const alpha = a !== undefined ? a : 1; // alpha, or default alpha - return str.replace(RE_NO_ALPHA, `, ${alpha})`).replace(/rgb\(/, 'rgba('); - } - if (RE_RGBA.test(str)) { - return a !== undefined ? str.replace(RE_ALPHA, `${a}`) : str; // replace alpha if defined, otherwise don't - } - throw new RgbParseError(`rgba? string is invalid, must be in the form rgba?(num, num, num, num?), not: ${str}`); -}; - /** * Turns an old-fashioned css hex color value into a rgb color value. * diff --git a/src/rgb-parser.js b/src/rgb-parser.js new file mode 100644 index 0000000..333a78e --- /dev/null +++ b/src/rgb-parser.js @@ -0,0 +1,17 @@ +import { RgbParseError } from './error'; + +const RE_RGB = /^rgb\(\d{1,3}, *\d{1,3}, *\d{1,3}\)$/; +const RE_RGBA = /^rgba\(\d{1,3}, *\d{1,3}, *\d{1,3}(?:, *(?:\d\.)?\d+)\)$/; +const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; +const RE_NO_ALPHA = /\)/; + +module.exports = (str, a) => { + if (RE_RGB.test(str)) { + const alpha = a !== undefined ? a : 1; // alpha, or default alpha + return str.replace(RE_NO_ALPHA, `, ${alpha})`).replace(/rgb\(/, 'rgba('); + } + if (RE_RGBA.test(str)) { + return a !== undefined ? str.replace(RE_ALPHA, `${a}`) : str; // replace alpha if defined, otherwise don't + } + throw new RgbParseError(`rgba? string is invalid, must be in the form rgba?(num, num, num, num?), not: ${str}`); +}; From d6fe14f7944dc96b0866ccb3325f77bfc06c6310 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 13:57:27 +0100 Subject: [PATCH 09/24] test all valid rgb values for rgba --- test/rgba.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/rgba.test.js b/test/rgba.test.js index 4af6d88..e7f586d 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -33,5 +33,12 @@ describe('rgba?-to-rgba', () => { it('should leave the alpha channel untouched if no alpha is given', () => { assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('rgba(17, 34, 51, 0.5)', undefined, true)); }); + + it('should accept all valid rgb values', () => { + for (let i = 0; i <= 255; i++) { // eslint-disable-line no-plusplus + const result = hexToRgba(`rgba(${i}, ${i}, ${i}, 1)`, undefined, true); + assert.equal(result, `rgba(${i}, ${i}, ${i}, 1)`); + } + }); }); }); From 0f56ab46b03fcfc82551ef75de5233fac8f43d49 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 13:58:59 +0100 Subject: [PATCH 10/24] test all valid rgb values for rgb --- test/rgba.test.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/rgba.test.js b/test/rgba.test.js index e7f586d..6b2a06a 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -22,6 +22,13 @@ describe('rgba?-to-rgba', () => { it('should default to 1 for alpha if no alpha is given', () => { assert.equal('rgba(17, 34, 51, 1)', hexToRgba('rgb(17, 34, 51)', undefined, true)); }); + + it('should accept all valid rgb values', () => { + for (let i = 0; i <= 255; i++) { // eslint-disable-line no-plusplus + const result = hexToRgba(`rgb(${i}, ${i}, ${i})`, '1', true); + assert.equal(result, `rgba(${i}, ${i}, ${i}, 1)`); + } + }); }); describe('rgba parser', () => { @@ -36,7 +43,7 @@ describe('rgba?-to-rgba', () => { it('should accept all valid rgb values', () => { for (let i = 0; i <= 255; i++) { // eslint-disable-line no-plusplus - const result = hexToRgba(`rgba(${i}, ${i}, ${i}, 1)`, undefined, true); + const result = hexToRgba(`rgba(${i}, ${i}, ${i}, 1)`, '1', true); assert.equal(result, `rgba(${i}, ${i}, ${i}, 1)`); } }); From 71265787fab01170fb6269279d5d389532ec6313 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 14:04:12 +0100 Subject: [PATCH 11/24] test all alpha values are accepted when a is undefined --- test/rgba.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/rgba.test.js b/test/rgba.test.js index 6b2a06a..3f7634a 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -47,5 +47,12 @@ describe('rgba?-to-rgba', () => { assert.equal(result, `rgba(${i}, ${i}, ${i}, 1)`); } }); + + it('should accept at least all rgb-alpha values from 0.001 to 1, when a is undefined', () => { + for (let i = 0.001; i <= 1; i += 0.001) { + const result = hexToRgba(`rgba(0, 0, 0, ${i})`, undefined, true); + assert.equal(result, `rgba(0, 0, 0, ${i})`); + } + }); }); }); From 2be9a1c4c3b3824ec7dd39ffd3a75ebeea15e47b Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 14:09:26 +0100 Subject: [PATCH 12/24] test that a mix of alpha and rgb values pass --- test/rgba.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/rgba.test.js b/test/rgba.test.js index 3f7634a..e601220 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -54,5 +54,12 @@ describe('rgba?-to-rgba', () => { assert.equal(result, `rgba(0, 0, 0, ${i})`); } }); + + it('should accept a mix of valid rgb and alpha values, when a is undefined', () => { + for (let i = 0; i <= 255; i++) { // eslint-disable-line no-plusplus + const result = hexToRgba(`rgba(${i}, ${i}, ${i}, ${i * 0.00392156862745098})`, undefined, true); + assert.equal(result, `rgba(${i}, ${i}, ${i}, ${i * 0.00392156862745098})`); + } + }); }); }); From 2914c651c1ce3ff1e9992b27f1192365d46f6f96 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 14:17:57 +0100 Subject: [PATCH 13/24] test invalid rgba values --- src/rgb-parser.js | 2 +- test/rgba.test.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/rgb-parser.js b/src/rgb-parser.js index 333a78e..14590f2 100644 --- a/src/rgb-parser.js +++ b/src/rgb-parser.js @@ -1,7 +1,7 @@ import { RgbParseError } from './error'; const RE_RGB = /^rgb\(\d{1,3}, *\d{1,3}, *\d{1,3}\)$/; -const RE_RGBA = /^rgba\(\d{1,3}, *\d{1,3}, *\d{1,3}(?:, *(?:\d\.)?\d+)\)$/; +const RE_RGBA = /^rgba\((?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){3}(?:(?:0\.)?\d+)\)$/; const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; const RE_NO_ALPHA = /\)/; diff --git a/test/rgba.test.js b/test/rgba.test.js index e601220..3749ad8 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -61,5 +61,23 @@ describe('rgba?-to-rgba', () => { assert.equal(result, `rgba(${i}, ${i}, ${i}, ${i * 0.00392156862745098})`); } }); + + ['-1', '-2', '-100', '256', '257', '1000'].forEach((val) => { + describe(`given the invalid rgb value: ${val}`, () => { + [ + `rgba(${val}, 0, 0, 1)`, + `rgba(0, ${val}, 0, 1)`, + `rgba(0, 0, ${val}, 1)`, + `rgba(0, ${val}, ${val}, 1)`, + `rgba(${val}, ${val}, 0, 1)`, + `rgba(${val}, ${val}, ${val}, 1)`, + ].forEach((rgbaStr) => { + it(`should throw for: ${rgbaStr}`, () => { + const callback = () => hexToRgba(rgbaStr, undefined, true); + assert.throws(callback, Error); // RgbParseError doesn't pass, even though it throws + }); + }); + }); + }); }); }); From 7276dd10f407c4c3262f01bdbcf904933f76377c Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 14:44:59 +0100 Subject: [PATCH 14/24] test invalid values for rgb --- src/rgb-parser.js | 4 ++-- test/rgba.test.js | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/rgb-parser.js b/src/rgb-parser.js index 14590f2..0a0106c 100644 --- a/src/rgb-parser.js +++ b/src/rgb-parser.js @@ -1,7 +1,7 @@ import { RgbParseError } from './error'; -const RE_RGB = /^rgb\(\d{1,3}, *\d{1,3}, *\d{1,3}\)$/; -const RE_RGBA = /^rgba\((?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){3}(?:(?:0\.)?\d+)\)$/; +const RE_RGB = /^rgb\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){2}(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]) *\)$/; +const RE_RGBA = /^rgba\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){3}(?:(?:0\.)?\d+) *\)$/; const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; const RE_NO_ALPHA = /\)/; diff --git a/test/rgba.test.js b/test/rgba.test.js index 3749ad8..8633963 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -29,6 +29,25 @@ describe('rgba?-to-rgba', () => { assert.equal(result, `rgba(${i}, ${i}, ${i}, 1)`); } }); + + ['-1', '-2', '-100', '256', '257', '1000'].forEach((val) => { + describe(`given the invalid rgb value: ${val}`, () => { + [ + `rgb(${val}, 0, 0)`, + `rgb(0, ${val}, 0)`, + `rgb(0, 0, ${val})`, + `rgb(0, ${val}, ${val})`, + `rgb(${val}, ${val}, 0)`, + `rgb(${val}, 0, ${val})`, + `rgb(${val}, ${val}, ${val})`, + ].forEach((rgbStr) => { + it(`should throw for: ${rgbStr}`, () => { + const callback = () => hexToRgba(rgbStr, undefined, true); + assert.throws(callback, Error); // RgbParseError doesn't pass, even though it throws + }); + }); + }); + }); }); describe('rgba parser', () => { @@ -70,6 +89,7 @@ describe('rgba?-to-rgba', () => { `rgba(0, 0, ${val}, 1)`, `rgba(0, ${val}, ${val}, 1)`, `rgba(${val}, ${val}, 0, 1)`, + `rgba(${val}, 0, ${val}, 1)`, `rgba(${val}, ${val}, ${val}, 1)`, ].forEach((rgbaStr) => { it(`should throw for: ${rgbaStr}`, () => { From be150174674e130222847b3a2cba5bc5a48579b5 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 15:35:30 +0100 Subject: [PATCH 15/24] move error to parser module --- src/error.js | 8 -------- src/index.js | 4 ++-- src/rgb-parser.js | 11 +++++++++-- 3 files changed, 11 insertions(+), 12 deletions(-) delete mode 100644 src/error.js diff --git a/src/error.js b/src/error.js deleted file mode 100644 index ebf031d..0000000 --- a/src/error.js +++ /dev/null @@ -1,8 +0,0 @@ -class RgbParseError extends Error { - constructor(message) { - super(message); - this.name = 'RgbParseError'; - } -} - -module.exports = { RgbParseError }; diff --git a/src/index.js b/src/index.js index b9addb4..970be2d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import rgbaToRgba from './rgb-parser'; +import { rgbToRgba } from './rgb-parser'; const removeHash = hex => (hex.charAt(0) === '#' ? hex.slice(1) : hex); @@ -56,7 +56,7 @@ const formatRgb = (decimalObject, parameterA) => { */ const hexToRgba = (hex, a, parseRgba = false) => { if (parseRgba) { - return rgbaToRgba(hex, a); + return rgbToRgba(hex, a); } const hashlessHex = removeHash(hex); diff --git a/src/rgb-parser.js b/src/rgb-parser.js index 0a0106c..9d7f0f0 100644 --- a/src/rgb-parser.js +++ b/src/rgb-parser.js @@ -1,11 +1,16 @@ -import { RgbParseError } from './error'; +class RgbParseError extends Error { + constructor(message) { + super(message); + this.name = 'RgbParseError'; + } +} const RE_RGB = /^rgb\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){2}(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]) *\)$/; const RE_RGBA = /^rgba\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){3}(?:(?:0\.)?\d+) *\)$/; const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; const RE_NO_ALPHA = /\)/; -module.exports = (str, a) => { +const rgbToRgba = (str, a) => { if (RE_RGB.test(str)) { const alpha = a !== undefined ? a : 1; // alpha, or default alpha return str.replace(RE_NO_ALPHA, `, ${alpha})`).replace(/rgb\(/, 'rgba('); @@ -15,3 +20,5 @@ module.exports = (str, a) => { } throw new RgbParseError(`rgba? string is invalid, must be in the form rgba?(num, num, num, num?), not: ${str}`); }; + +module.exports = { rgbToRgba, RgbParseError }; From a947d23bf777e5fd67c0902674e06364e9693e60 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 15:37:29 +0100 Subject: [PATCH 16/24] rename parseRgba option to parseRgb --- src/index.js | 4 ++-- test/rgba.test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 970be2d..e59a1ad 100644 --- a/src/index.js +++ b/src/index.js @@ -54,8 +54,8 @@ const formatRgb = (decimalObject, parameterA) => { * @param An alpha value to apply. (optional) ('0.5', '0.25') * @return An rgb or rgba value. ('rgb(11, 22, 33)'. 'rgba(11, 22, 33, 0.5)') */ -const hexToRgba = (hex, a, parseRgba = false) => { - if (parseRgba) { +const hexToRgba = (hex, a, parseRgb = false) => { + if (parseRgb) { return rgbToRgba(hex, a); } diff --git a/test/rgba.test.js b/test/rgba.test.js index 8633963..8b5c669 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -3,7 +3,7 @@ import assert from 'assert'; import hexToRgba from '..'; describe('rgba?-to-rgba', () => { - describe('parseRgba option', () => { + describe('parseRgb option', () => { it('should parse rgba strings when set to true', () => { assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('rgba(17, 34, 51, 1)', '0.5', true)); }); From 5b9a0b67b09d860dedddc7f1aa7b95379741f575 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 15:42:09 +0100 Subject: [PATCH 17/24] fix error string --- src/rgb-parser.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rgb-parser.js b/src/rgb-parser.js index 9d7f0f0..5f0ce2a 100644 --- a/src/rgb-parser.js +++ b/src/rgb-parser.js @@ -18,7 +18,9 @@ const rgbToRgba = (str, a) => { if (RE_RGBA.test(str)) { return a !== undefined ? str.replace(RE_ALPHA, `${a}`) : str; // replace alpha if defined, otherwise don't } - throw new RgbParseError(`rgba? string is invalid, must be in the form rgba?(num, num, num, num?), not: ${str}`); + throw new RgbParseError( + `rgba? string is invalid, must be in the form rgba?('0-255', '0-255', '0-255', '0-1'?), not: ${str}`, + ); }; module.exports = { rgbToRgba, RgbParseError }; From bcab58a3bf81a3190d432c054208863ae4d8ef92 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 16:01:34 +0100 Subject: [PATCH 18/24] do isRgb test in index --- src/index.js | 4 ++-- src/rgb-parser.js | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index e59a1ad..dcf9b0b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import { rgbToRgba } from './rgb-parser'; +import { isRgb, rgbToRgba } from './rgb-parser'; const removeHash = hex => (hex.charAt(0) === '#' ? hex.slice(1) : hex); @@ -55,7 +55,7 @@ const formatRgb = (decimalObject, parameterA) => { * @return An rgb or rgba value. ('rgb(11, 22, 33)'. 'rgba(11, 22, 33, 0.5)') */ const hexToRgba = (hex, a, parseRgb = false) => { - if (parseRgb) { + if (parseRgb && isRgb(hex)) { return rgbToRgba(hex, a); } diff --git a/src/rgb-parser.js b/src/rgb-parser.js index 5f0ce2a..63608c1 100644 --- a/src/rgb-parser.js +++ b/src/rgb-parser.js @@ -5,10 +5,14 @@ class RgbParseError extends Error { } } +// The long expressions are just to catch errors const RE_RGB = /^rgb\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){2}(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]) *\)$/; const RE_RGBA = /^rgba\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){3}(?:(?:0\.)?\d+) *\)$/; const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; const RE_NO_ALPHA = /\)/; +const RE_IS_RGB = /^rgba?/; + +const isRgb = str => RE_IS_RGB.test(str); const rgbToRgba = (str, a) => { if (RE_RGB.test(str)) { @@ -23,4 +27,4 @@ const rgbToRgba = (str, a) => { ); }; -module.exports = { rgbToRgba, RgbParseError }; +module.exports = { isRgb, rgbToRgba, RgbParseError }; From f2045d1050a60696b906ac6552f294ee9c995e44 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 16:02:25 +0100 Subject: [PATCH 19/24] rename hex to colorStr --- src/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index dcf9b0b..f807ded 100644 --- a/src/index.js +++ b/src/index.js @@ -54,12 +54,12 @@ const formatRgb = (decimalObject, parameterA) => { * @param An alpha value to apply. (optional) ('0.5', '0.25') * @return An rgb or rgba value. ('rgb(11, 22, 33)'. 'rgba(11, 22, 33, 0.5)') */ -const hexToRgba = (hex, a, parseRgb = false) => { - if (parseRgb && isRgb(hex)) { - return rgbToRgba(hex, a); +const hexToRgba = (colorStr, a, parseRgb = false) => { + if (parseRgb && isRgb(colorStr)) { + return rgbToRgba(colorStr, a); } - const hashlessHex = removeHash(hex); + const hashlessHex = removeHash(colorStr); const hexObject = parseHex(hashlessHex); const decimalObject = hexesToDecimals(hexObject); From a440e348cb3b9113cbf489adedda77a94b4c011e Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 16:18:46 +0100 Subject: [PATCH 20/24] fix hex tests to include parseRgb param --- test/hex.test.js | 344 ++++++++++++++++++++++++----------------------- 1 file changed, 174 insertions(+), 170 deletions(-) diff --git a/test/hex.test.js b/test/hex.test.js index 15a9668..702b593 100644 --- a/test/hex.test.js +++ b/test/hex.test.js @@ -2,176 +2,180 @@ import assert from 'assert'; import hexToRgba from '..'; -describe('hex-to-rgba', () => { - describe('6-digit hex values, no a', () => { - it('should calculate correct rgb values', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('112233')); - }); - - it('should ignore a leading hash sign', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('#112233')); - }); - - it('should correctly calculate uppercase hex', () => { - assert.equal('rgba(127, 127, 127, 1)', hexToRgba('#7F7F7F')); - }); - - it('should correctly calculate lowercase hex', () => { - assert.equal('rgba(127, 127, 127, 1)', hexToRgba('#7f7f7f')); - }); - }); - - describe('6-digit hex values, a as parameter', () => { - it('should calculate rgba values from hex and string alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('112233', '0.5')); - }); - - it('should calculate rgba values from hex and numerical alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('112233', 0.75)); - }); - - it('should handle the edge case where alpha value is 1', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('112233', 1)); - }); - - it('should handle the edge case where alpha value is 0', () => { - assert.equal('rgba(17, 34, 51, 0)', hexToRgba('112233', 0)); - }); - - it('should calculate rgba values from hex with leading hash and string alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('#112233', '0.5')); - }); - - it('should calculate rgba values from hex with leading hash and numerical alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('#112233', 0.75)); - }); - }); - - describe('3-digit hex values, no a', () => { - it('should calculate correct rgb values', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('123')); - }); - - it('should ignore a leading hash sign', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('#123')); - }); - }); - - describe('3-digit hex values, a as parameter', () => { - it('should calculate rgba values from hex and string alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('123', '0.5')); - }); - - it('should calculate rgba values from hex and numerical alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('123', 0.75)); - }); - - it('should handle the edge case where alpha value is 1', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('123', 1)); - }); - - it('should handle the edge case where alpha value is 0', () => { - assert.equal('rgba(17, 34, 51, 0)', hexToRgba('123', 0)); - }); - - it('should calculate rgba values from hex with leading hash and string alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('#123', '0.5')); - }); - - it('should calculate rgba values from hex with leading hash and numerical alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('#123', 0.75)); - }); - }); - - describe('8-digit hex values, no a', () => { - it('should calculate correct rgb values', () => { - assert.equal('rgba(17, 34, 51, 0.27)', hexToRgba('11223344')); - }); - - it('should ignore a leading hash sign', () => { - assert.equal('rgba(17, 34, 51, 0.27)', hexToRgba('#11223344')); - }); - - it('should remove trailing zeros', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('1122337f')); - }); - - it('should handle the edge case where alpha value is 1', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('112233ff')); - }); - - it('should handle the edge case where alpha value is 0', () => { - assert.equal('rgba(17, 34, 51, 0)', hexToRgba('112233', 0)); - }); - }); - - describe('8-digit hex values, a as parameter (separate parameter should override alpha in hex)', () => { - it('should calculate rgba values from hex and string alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('11223344', '0.5')); - }); - - it('should calculate rgba values from hex and numerical alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('11223344', 0.75)); - }); - - it('should handle the edge case where alpha value is 1', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('11223344', 1)); - }); - - it('should handle the edge case where alpha value is 0', () => { - assert.equal('rgba(17, 34, 51, 0)', hexToRgba('11223344', 0)); - }); - - it('should calculate rgba values from hex with leading hash and string alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('#11223344', '0.5')); - }); - - it('should calculate rgba values from hex with leading hash and numerical alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('#11223344', 0.75)); - }); - }); - - describe('4-digit hex values, no a', () => { - it('should calculate correct rgb values', () => { - assert.equal('rgba(17, 34, 51, 0.27)', hexToRgba('1234')); - }); - - it('should ignore a leading hash sign', () => { - assert.equal('rgba(17, 34, 51, 0.27)', hexToRgba('#1234')); - }); - - it('should handle the edge case where alpha value is 1', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('123f')); - }); - - it('should handle the edge case where alpha value is 0', () => { - assert.equal('rgba(17, 34, 51, 0)', hexToRgba('1230')); - }); - }); - - describe('4-digit hex values, a as parameter (separate parameter should override alpha in hex)', () => { - it('should calculate rgba values from hex and string alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('1234', '0.5')); - }); - - it('should calculate rgba values from hex and numerical alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('1234', 0.75)); - }); - - it('should handle the edge case where alpha value is 1', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('1234', 1)); - }); - - it('should handle the edge case where alpha value is 0', () => { - assert.equal('rgba(17, 34, 51, 0)', hexToRgba('1234', 0)); - }); - - it('should calculate rgba values from hex with leading hash and string alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('#1234', '0.5')); - }); - - it('should calculate rgba values from hex with leading hash and numerical alpha value', () => { - assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('#1234', 0.75)); +[false, true].forEach((parseRgb) => { + describe('hex-to-rgba', () => { + describe(`when parseRgb is ${parseRgb}`, () => { + describe('6-digit hex values, no a', () => { + it('should calculate correct rgb values', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('112233', undefined, parseRgb)); + }); + + it('should ignore a leading hash sign', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('#112233', undefined, parseRgb)); + }); + + it('should correctly calculate uppercase hex', () => { + assert.equal('rgba(127, 127, 127, 1)', hexToRgba('#7F7F7F', undefined, parseRgb)); + }); + + it('should correctly calculate lowercase hex', () => { + assert.equal('rgba(127, 127, 127, 1)', hexToRgba('#7f7f7f', undefined, parseRgb)); + }); + }); + + describe('6-digit hex values, a as parameter', () => { + it('should calculate rgba values from hex and string alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('112233', '0.5', parseRgb)); + }); + + it('should calculate rgba values from hex and numerical alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('112233', 0.75, parseRgb)); + }); + + it('should handle the edge case where alpha value is 1', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('112233', 1, parseRgb)); + }); + + it('should handle the edge case where alpha value is 0', () => { + assert.equal('rgba(17, 34, 51, 0)', hexToRgba('112233', 0, parseRgb)); + }); + + it('should calculate rgba values from hex with leading hash and string alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('#112233', '0.5', parseRgb)); + }); + + it('should calculate rgba values from hex with leading hash and numerical alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('#112233', 0.75, parseRgb)); + }); + }); + + describe('3-digit hex values, no a', () => { + it('should calculate correct rgb values', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('123', undefined, parseRgb)); + }); + + it('should ignore a leading hash sign', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('#123', undefined, parseRgb)); + }); + }); + + describe('3-digit hex values, a as parameter', () => { + it('should calculate rgba values from hex and string alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('123', '0.5', parseRgb)); + }); + + it('should calculate rgba values from hex and numerical alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('123', 0.75, parseRgb)); + }); + + it('should handle the edge case where alpha value is 1', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('123', 1, parseRgb)); + }); + + it('should handle the edge case where alpha value is 0', () => { + assert.equal('rgba(17, 34, 51, 0)', hexToRgba('123', 0, parseRgb)); + }); + + it('should calculate rgba values from hex with leading hash and string alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('#123', '0.5', parseRgb)); + }); + + it('should calculate rgba values from hex with leading hash and numerical alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('#123', 0.75, parseRgb)); + }); + }); + + describe('8-digit hex values, no a', () => { + it('should calculate correct rgb values', () => { + assert.equal('rgba(17, 34, 51, 0.27)', hexToRgba('11223344', undefined, parseRgb)); + }); + + it('should ignore a leading hash sign', () => { + assert.equal('rgba(17, 34, 51, 0.27)', hexToRgba('#11223344', undefined, parseRgb)); + }); + + it('should remove trailing zeros', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('1122337f', undefined, parseRgb)); + }); + + it('should handle the edge case where alpha value is 1', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('112233ff', undefined, parseRgb)); + }); + + it('should handle the edge case where alpha value is 0', () => { + assert.equal('rgba(17, 34, 51, 0)', hexToRgba('112233', 0, parseRgb)); + }); + }); + + describe('8-digit hex values, a as parameter (separate parameter should override alpha in hex)', () => { + it('should calculate rgba values from hex and string alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('11223344', '0.5', parseRgb)); + }); + + it('should calculate rgba values from hex and numerical alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('11223344', 0.75, parseRgb)); + }); + + it('should handle the edge case where alpha value is 1', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('11223344', 1, parseRgb)); + }); + + it('should handle the edge case where alpha value is 0', () => { + assert.equal('rgba(17, 34, 51, 0)', hexToRgba('11223344', 0, parseRgb)); + }); + + it('should calculate rgba values from hex with leading hash and string alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('#11223344', '0.5', parseRgb)); + }); + + it('should calculate rgba values from hex with leading hash and numerical alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('#11223344', 0.75, parseRgb)); + }); + }); + + describe('4-digit hex values, no a', () => { + it('should calculate correct rgb values', () => { + assert.equal('rgba(17, 34, 51, 0.27)', hexToRgba('1234', undefined, parseRgb)); + }); + + it('should ignore a leading hash sign', () => { + assert.equal('rgba(17, 34, 51, 0.27)', hexToRgba('#1234', undefined, parseRgb)); + }); + + it('should handle the edge case where alpha value is 1', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('123f', undefined, parseRgb)); + }); + + it('should handle the edge case where alpha value is 0', () => { + assert.equal('rgba(17, 34, 51, 0)', hexToRgba('1230', undefined, parseRgb)); + }); + }); + + describe('4-digit hex values, a as parameter (separate parameter should override alpha in hex)', () => { + it('should calculate rgba values from hex and string alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('1234', '0.5', parseRgb)); + }); + + it('should calculate rgba values from hex and numerical alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('1234', 0.75, parseRgb)); + }); + + it('should handle the edge case where alpha value is 1', () => { + assert.equal('rgba(17, 34, 51, 1)', hexToRgba('1234', 1, parseRgb)); + }); + + it('should handle the edge case where alpha value is 0', () => { + assert.equal('rgba(17, 34, 51, 0)', hexToRgba('1234', 0, parseRgb)); + }); + + it('should calculate rgba values from hex with leading hash and string alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.5)', hexToRgba('#1234', '0.5', parseRgb)); + }); + + it('should calculate rgba values from hex with leading hash and numerical alpha value', () => { + assert.equal('rgba(17, 34, 51, 0.75)', hexToRgba('#1234', 0.75, parseRgb)); + }); + }); }); }); }); From 70859482eb025f78951d1f3b68ab658ee61314d1 Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 16:26:41 +0100 Subject: [PATCH 21/24] add potential space to regex patterns --- src/rgb-parser.js | 4 ++-- test/rgba.test.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rgb-parser.js b/src/rgb-parser.js index 63608c1..5f7882e 100644 --- a/src/rgb-parser.js +++ b/src/rgb-parser.js @@ -6,8 +6,8 @@ class RgbParseError extends Error { } // The long expressions are just to catch errors -const RE_RGB = /^rgb\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){2}(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]) *\)$/; -const RE_RGBA = /^rgba\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]), *){3}(?:(?:0\.)?\d+) *\)$/; +const RE_RGB = /^rgb\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]) *, *){2}(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]) *\)$/; +const RE_RGBA = /^rgba\( *(?:(?:[01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]) *, *){3}(?:(?:0\.)?\d+) *\)$/; const RE_ALPHA = /(?:0\.)?\d+ *(?=\))/; const RE_NO_ALPHA = /\)/; const RE_IS_RGB = /^rgba?/; diff --git a/test/rgba.test.js b/test/rgba.test.js index 8b5c669..cfbd2e9 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -76,6 +76,7 @@ describe('rgba?-to-rgba', () => { it('should accept a mix of valid rgb and alpha values, when a is undefined', () => { for (let i = 0; i <= 255; i++) { // eslint-disable-line no-plusplus + // Magic number: 1/255 = 0.00392156862745098 - allows alpha to scale with RGB values, <= 1 const result = hexToRgba(`rgba(${i}, ${i}, ${i}, ${i * 0.00392156862745098})`, undefined, true); assert.equal(result, `rgba(${i}, ${i}, ${i}, ${i * 0.00392156862745098})`); } From dcef8f4cc459f4a5c6b6ee41b971140c663fb78e Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 16:41:47 +0100 Subject: [PATCH 22/24] update doc comment --- src/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index f807ded..ff9d5e2 100644 --- a/src/index.js +++ b/src/index.js @@ -50,8 +50,12 @@ const formatRgb = (decimalObject, parameterA) => { * * If you specify an alpha value, you'll get a rgba() value instead. * - * @param The hex value to convert. ('123456'. '#123456', ''123', '#123') - * @param An alpha value to apply. (optional) ('0.5', '0.25') + * @param colorStr: The value to convert. ('123456', '#123456', ''123', '#123', rgb(0, 0, 0), + * rgba(0, 1, 2, 1) ) + * @param a: An alpha value to apply. (optional) ('0.5', '0.25') + * @param parseRgb: enable rgb and rgba string parsing. (optional) (true, false), false by default. + * Useful in situations where the input value is unpredictable (hex or rgb), but you still need to + * return an rgba string consistently. * @return An rgb or rgba value. ('rgb(11, 22, 33)'. 'rgba(11, 22, 33, 0.5)') */ const hexToRgba = (colorStr, a, parseRgb = false) => { From 1f4f50225d26b6779fbf7dddc6a65458fe04717b Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 17:23:10 +0100 Subject: [PATCH 23/24] refactor and make rgb strings, with an undefined 'a', return the rgb string --- src/rgb-parser.js | 8 ++++++-- test/rgba.test.js | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/rgb-parser.js b/src/rgb-parser.js index 5f7882e..182909f 100644 --- a/src/rgb-parser.js +++ b/src/rgb-parser.js @@ -16,12 +16,16 @@ const isRgb = str => RE_IS_RGB.test(str); const rgbToRgba = (str, a) => { if (RE_RGB.test(str)) { - const alpha = a !== undefined ? a : 1; // alpha, or default alpha - return str.replace(RE_NO_ALPHA, `, ${alpha})`).replace(/rgb\(/, 'rgba('); + if (a !== undefined) { + return str.replace(RE_NO_ALPHA, `, ${a})`).replace(/rgb\(/, 'rgba('); + } + return str; } + if (RE_RGBA.test(str)) { return a !== undefined ? str.replace(RE_ALPHA, `${a}`) : str; // replace alpha if defined, otherwise don't } + throw new RgbParseError( `rgba? string is invalid, must be in the form rgba?('0-255', '0-255', '0-255', '0-1'?), not: ${str}`, ); diff --git a/test/rgba.test.js b/test/rgba.test.js index cfbd2e9..f1d0bec 100644 --- a/test/rgba.test.js +++ b/test/rgba.test.js @@ -19,8 +19,8 @@ describe('rgba?-to-rgba', () => { assert.throws(callback, Error); // RgbParseError doesn't pass, even though it throws }); - it('should default to 1 for alpha if no alpha is given', () => { - assert.equal('rgba(17, 34, 51, 1)', hexToRgba('rgb(17, 34, 51)', undefined, true)); + it('should return the rgb string if "a" is undefined', () => { + assert.equal('rgb(17, 34, 51)', hexToRgba('rgb(17, 34, 51)', undefined, true)); }); it('should accept all valid rgb values', () => { From 396e1f06b78266e480503d8feeddbeb626c1fabf Mon Sep 17 00:00:00 2001 From: 0b10 <0b10@pm.me> Date: Fri, 23 Aug 2019 18:36:03 +0100 Subject: [PATCH 24/24] update type definitions --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index a63f779..baabed0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,3 +1,3 @@ -declare function hexToRgba(color: string, alpha?: string | number): string; +declare function hexToRgba(color: string, alpha?: string | number, parseRgb?: boolean): string; export = hexToRgba;