Skip to content

Commit

Permalink
feat: Update HSLA color parsing functionality
Browse files Browse the repository at this point in the history
Updated the parsing of HSLA colors to handle different units, percentages, and number inputs correctly. Enhanced the error message for invalid HSLA color format and refactored the code to introduce reusable utility functions to parse each color component.
  • Loading branch information
mallikcheripally committed Jun 3, 2024
1 parent 2608b4e commit 5944f17
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 116 deletions.
39 changes: 11 additions & 28 deletions src/parser/parseHsla.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { isValidHsla } from '@/validations/isValidHsla';
import { hslaRegex } from '@/utils/regex';
import {parseAlpha, parseComponent, parseHue, roundTo} from '@/utils/colorUtils';

/**
* Parses an HSLA color string.
Expand All @@ -15,8 +16,9 @@ import { hslaRegex } from '@/utils/regex';
* sUnit?: string | undefined;
* l: number;
* lUnit?: string | undefined;
* a: number;
* a: number | undefined;
* aUnit?: string | undefined;
* aNum: number;
* }} Returns an object value
* @throws {Error} Throws an error if the color string is not a valid HSLA color.
*/
Expand All @@ -28,44 +30,25 @@ export function parseHsla(color: string): {
sUnit?: string | undefined;
l: number;
lUnit?: string | undefined;
a: number;
a: number | undefined;
aUnit?: string | undefined;
aNum: number;
} {
const match = color.match(hslaRegex);
if (!match || !isValidHsla(color)) {
throw new Error('Invalid HSLA color format');
}

const parseHue = (hue: string, unit: string | undefined): number => {
let hueValue = parseFloat(hue);
switch (unit) {
case 'deg':
return hueValue;
case 'rad':
return hueValue * (180 / Math.PI);
case 'grad':
return hueValue * (9 / 10);
case 'turn':
return hueValue * 360;
default:
return hueValue;
}
};

const roundTo = (num: number, precision: number): number => {
const factor = Math.pow(10, precision);
return Math.round(num * factor) / factor;
};

const h = parseFloat(match[1]);
const h = parseComponent(match[1]);
const hDeg = roundTo(parseHue(match[1], match[3]), 2);
const hUnit = match[3];
const s = parseFloat(match[4]);
const s = parseComponent(match[4]);
const sUnit = match[6];
const l = parseFloat(match[7]);
const l = parseComponent(match[7]);
const lUnit = match[9];
const a = match[10].includes('%') ? parseFloat(match[10]) / 100 : parseFloat(match[10]);
const a = parseAlpha(match[10]);
const aUnit = match[10].includes('%') ? '%' : undefined;
const aNum = match[10].includes('%') ? parseFloat(match[10]) / 100 : parseFloat(match[10]);

return { h, hUnit, hDeg, s, sUnit, l, lUnit, a, aUnit };
return { h, hUnit, hDeg, s, sUnit, l, lUnit, a, aUnit, aNum };
}
4 changes: 1 addition & 3 deletions src/utils/colorUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ export function parseHue(hue: string, unit: string | undefined): number {
* @returns {number | undefined} The parsed alpha value.
*/
export function parseAlpha(value: string): number | undefined {
if (value === 'none') {
return 1;
}
if (value === 'none') return 1;
return Number.isFinite(parseFloat(value)) ? parseFloat(value) : undefined;
}

Expand Down
116 changes: 31 additions & 85 deletions tests/parser/parseHsla.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import { parseHsla } from "@/parser/parseHsla";

describe('parseHsla', () => {
test('parses HSLA color with degrees', () => {
const result = parseHsla('hsla(180deg, 100%, 50%, 0.5)');
test('parses HSLA color with numbers correctly', () => {
const result = parseHsla('hsla(180, 100%, 50%, 0.5)');
expect(result).toEqual({
h: 180,
hUnit: 'deg',
hUnit: undefined,
hDeg: 180,
s: 100,
sUnit: '%',
l: 50,
lUnit: '%',
a: 0.5,
aUnit: undefined
aUnit: undefined,
aNum: 0.5,
});
});

test('parses HSLA color with radians', () => {
test('parses HSLA color with degrees correctly', () => {
const result = parseHsla('hsla(3.14rad, 100%, 50%, 0.5)');
expect(result).toEqual({
h: 3.14,
Expand All @@ -27,56 +28,12 @@ describe('parseHsla', () => {
l: 50,
lUnit: '%',
a: 0.5,
aUnit: undefined
});
});

test('parses HSLA color with gradians', () => {
const result = parseHsla('hsla(200grad, 100%, 50%, 0.5)');
expect(result).toEqual({
h: 200,
hUnit: 'grad',
hDeg: 180,
s: 100,
sUnit: '%',
l: 50,
lUnit: '%',
a: 0.5,
aUnit: undefined
});
});

test('parses HSLA color with turns', () => {
const result = parseHsla('hsla(0.5turn, 100%, 50%, 0.5)');
expect(result).toEqual({
h: 0.5,
hUnit: 'turn',
hDeg: 180,
s: 100,
sUnit: '%',
l: 50,
lUnit: '%',
a: 0.5,
aUnit: undefined
aUnit: undefined,
aNum: 0.5,
});
});

test('parses HSLA color without unit (default to degrees)', () => {
const result = parseHsla('hsla(180, 100%, 50%, 0.5)');
expect(result).toEqual({
h: 180,
hUnit: undefined,
hDeg: 180,
s: 100,
sUnit: '%',
l: 50,
lUnit: '%',
a: 0.5,
aUnit: undefined
});
});

test('parses HSLA color with alpha percentage', () => {
test('parses HSLA color with percentages correctly', () => {
const result = parseHsla('hsla(180, 100%, 50%, 50%)');
expect(result).toEqual({
h: 180,
Expand All @@ -86,35 +43,30 @@ describe('parseHsla', () => {
sUnit: '%',
l: 50,
lUnit: '%',
a: 0.5,
aUnit: '%'
a: 50,
aUnit: '%',
aNum: 0.5,
});
});

test('parses HSLA color with mixed case units', () => {
const result = parseHsla('hsla(180DeG, 100%, 50%, 0.5)');
test('parses HSLA color with different units correctly', () => {
const result = parseHsla('hsla(50grad, 100%, 50%, 50%)');
expect(result).toEqual({
h: 180,
hUnit: 'DeG',
hDeg: 180,
h: 50,
hUnit: 'grad',
hDeg: 45,
s: 100,
sUnit: '%',
l: 50,
lUnit: '%',
a: 0.5,
aUnit: undefined
a: 50,
aUnit: '%',
aNum: 0.5,
});
});

test('throws error for invalid HSLA color', () => {
expect(() => parseHsla('hsla(370, 100%, 50%, 0.5)')).toThrow('Invalid HSLA color format');
expect(() => parseHsla('hsla(180, 110%, 50%, 0.5)')).toThrow('Invalid HSLA color format');
expect(() => parseHsla('hsla(180, 100%, 150%, 0.5)')).toThrow('Invalid HSLA color format');
expect(() => parseHsla('hsla(180, 100%, 50%, 1.5)')).toThrow('Invalid HSLA color format');
});

test('parses HSLA color with integer alpha', () => {
const result = parseHsla('hsla(180, 100%, 50%, 1)');
test('parses HSLA color with spaces correctly', () => {
const result = parseHsla('hsla( 180 , 100% , 50% , 0.5 )');
expect(result).toEqual({
h: 180,
hUnit: undefined,
Expand All @@ -123,23 +75,17 @@ describe('parseHsla', () => {
sUnit: '%',
l: 50,
lUnit: '%',
a: 1,
aUnit: undefined
a: 0.5,
aUnit: undefined,
aNum: 0.5,
});
});

test('parses HSLA color with alpha as 0%', () => {
const result = parseHsla('hsla(180, 100%, 50%, 0%)');
expect(result).toEqual({
h: 180,
hUnit: undefined,
hDeg: 180,
s: 100,
sUnit: '%',
l: 50,
lUnit: '%',
a: 0,
aUnit: '%'
});
test('throws error for invalid HSLA color format', () => {
expect(() => parseHsla('hsla(361, 100%, 50%, 0.5)')).toThrow('Invalid HSLA color format');
expect(() => parseHsla('hsla(180, -1%, 50%, 0.5)')).toThrow('Invalid HSLA color format');
expect(() => parseHsla('hsla(180, 100%, 101%, 0.5)')).toThrow('Invalid HSLA color format');
expect(() => parseHsla('hsla(180, 100%, 50%, 1.5)')).toThrow('Invalid HSLA color format');
expect(() => parseHsla('hsla(100%, 100%, 100%, 200%)')).toThrow('Invalid HSLA color format');
});
});

0 comments on commit 5944f17

Please sign in to comment.