gradient-parser
Advanced tools
Comparing version
@@ -109,2 +109,14 @@ // Copyright (c) 2014 Rafael Caricio. All rights reserved. | ||
'visit_hsl': function(node) { | ||
return visitor.visit_color('hsl(' + node.value[0] + ', ' + node.value[1] + '%, ' + node.value[2] + '%)', node); | ||
}, | ||
'visit_hsla': function(node) { | ||
return visitor.visit_color('hsla(' + node.value[0] + ', ' + node.value[1] + '%, ' + node.value[2] + '%, ' + node.value[3] + ')', node); | ||
}, | ||
'visit_var': function(node) { | ||
return visitor.visit_color('var(' + node.value + ')', node); | ||
}, | ||
'visit_color': function(resultColor, node) { | ||
@@ -142,2 +154,9 @@ var result = resultColor, | ||
'visit_object': function(obj) { | ||
if (obj.width && obj.height) { | ||
return visitor.visit(obj.width) + ' ' + visitor.visit(obj.height); | ||
} | ||
return ''; | ||
}, | ||
'visit': function(element) { | ||
@@ -151,2 +170,4 @@ if (!element) { | ||
return visitor.visit_array(element, result); | ||
} else if (typeof element === 'object' && !element.type) { | ||
return visitor.visit_object(element); | ||
} else if (element.type) { | ||
@@ -184,3 +205,3 @@ var nodeVisitor = visitor['visit_' + element.type]; | ||
repeatingRadialGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-radial\-gradient)/i, | ||
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|left|right|top|bottom)/i, | ||
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|top (left|right)|bottom (left|right)|left|right|top|bottom)/i, | ||
extentKeywords: /^(closest\-side|closest\-corner|farthest\-side|farthest\-corner|contain|cover)/, | ||
@@ -192,2 +213,3 @@ positionKeywords: /^(left|center|right|top|bottom)/i, | ||
angleValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))deg/, | ||
radianValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))rad/, | ||
startCall: /^\(/, | ||
@@ -200,3 +222,7 @@ endCall: /^\)/, | ||
rgbaColor: /^rgba/i, | ||
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/ | ||
varColor: /^var/i, | ||
variableName: /^(--[a-zA-Z0-9-,\s\#]+)/, | ||
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/, | ||
hslColor: /^hsl/i, | ||
hslaColor: /^hsla/i, | ||
}; | ||
@@ -294,3 +320,4 @@ | ||
function matchAngle() { | ||
return match('angular', tokens.angleValue, 1); | ||
return match('angular', tokens.angleValue, 1) || | ||
match('angular', tokens.radianValue, 1); | ||
} | ||
@@ -363,3 +390,3 @@ | ||
if (ellipse) { | ||
ellipse.style = matchDistance() || matchExtentKeyword(); | ||
ellipse.style = matchPositioning() || matchDistance() || matchExtentKeyword(); | ||
} | ||
@@ -436,4 +463,7 @@ | ||
return matchHexColor() || | ||
matchHSLAColor() || | ||
matchHSLColor() || | ||
matchRGBAColor() || | ||
matchRGBColor() || | ||
matchVarColor() || | ||
matchLiteralColor(); | ||
@@ -468,2 +498,66 @@ } | ||
function matchVarColor() { | ||
return matchCall(tokens.varColor, function () { | ||
return { | ||
type: 'var', | ||
value: matchVariableName() | ||
}; | ||
}); | ||
} | ||
function matchHSLColor() { | ||
return matchCall(tokens.hslColor, function() { | ||
// Check for percentage before trying to parse the hue | ||
var lookahead = scan(tokens.percentageValue); | ||
if (lookahead) { | ||
error('HSL hue value must be a number in degrees (0-360) or normalized (-360 to 360), not a percentage'); | ||
} | ||
var hue = matchNumber(); | ||
scan(tokens.comma); | ||
var captures = scan(tokens.percentageValue); | ||
var sat = captures ? captures[1] : null; | ||
scan(tokens.comma); | ||
captures = scan(tokens.percentageValue); | ||
var light = captures ? captures[1] : null; | ||
if (!sat || !light) { | ||
error('Expected percentage value for saturation and lightness in HSL'); | ||
} | ||
return { | ||
type: 'hsl', | ||
value: [hue, sat, light] | ||
}; | ||
}); | ||
} | ||
function matchHSLAColor() { | ||
return matchCall(tokens.hslaColor, function() { | ||
var hue = matchNumber(); | ||
scan(tokens.comma); | ||
var captures = scan(tokens.percentageValue); | ||
var sat = captures ? captures[1] : null; | ||
scan(tokens.comma); | ||
captures = scan(tokens.percentageValue); | ||
var light = captures ? captures[1] : null; | ||
scan(tokens.comma); | ||
var alpha = matchNumber(); | ||
if (!sat || !light) { | ||
error('Expected percentage value for saturation and lightness in HSLA'); | ||
} | ||
return { | ||
type: 'hsla', | ||
value: [hue, sat, light, alpha] | ||
}; | ||
}); | ||
} | ||
function matchPercentage() { | ||
var captures = scan(tokens.percentageValue); | ||
return captures ? captures[1] : null; | ||
} | ||
function matchVariableName() { | ||
return scan(tokens.variableName)[1]; | ||
} | ||
function matchNumber() { | ||
@@ -520,3 +614,7 @@ return scan(tokens.number)[1]; | ||
return function(code) { | ||
input = code.toString(); | ||
input = code.toString().trim(); | ||
// Remove trailing semicolon if present | ||
if (input.endsWith(';')) { | ||
input = input.slice(0, -1); | ||
} | ||
return getAST(); | ||
@@ -523,0 +621,0 @@ }; |
108
build/web.js
@@ -16,3 +16,3 @@ var GradientParser = (window.GradientParser || {}); | ||
repeatingRadialGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-radial\-gradient)/i, | ||
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|left|right|top|bottom)/i, | ||
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|top (left|right)|bottom (left|right)|left|right|top|bottom)/i, | ||
extentKeywords: /^(closest\-side|closest\-corner|farthest\-side|farthest\-corner|contain|cover)/, | ||
@@ -24,2 +24,3 @@ positionKeywords: /^(left|center|right|top|bottom)/i, | ||
angleValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))deg/, | ||
radianValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))rad/, | ||
startCall: /^\(/, | ||
@@ -32,3 +33,7 @@ endCall: /^\)/, | ||
rgbaColor: /^rgba/i, | ||
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/ | ||
varColor: /^var/i, | ||
variableName: /^(--[a-zA-Z0-9-,\s\#]+)/, | ||
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/, | ||
hslColor: /^hsl/i, | ||
hslaColor: /^hsla/i, | ||
}; | ||
@@ -126,3 +131,4 @@ | ||
function matchAngle() { | ||
return match('angular', tokens.angleValue, 1); | ||
return match('angular', tokens.angleValue, 1) || | ||
match('angular', tokens.radianValue, 1); | ||
} | ||
@@ -195,3 +201,3 @@ | ||
if (ellipse) { | ||
ellipse.style = matchDistance() || matchExtentKeyword(); | ||
ellipse.style = matchPositioning() || matchDistance() || matchExtentKeyword(); | ||
} | ||
@@ -268,4 +274,7 @@ | ||
return matchHexColor() || | ||
matchHSLAColor() || | ||
matchHSLColor() || | ||
matchRGBAColor() || | ||
matchRGBColor() || | ||
matchVarColor() || | ||
matchLiteralColor(); | ||
@@ -300,2 +309,66 @@ } | ||
function matchVarColor() { | ||
return matchCall(tokens.varColor, function () { | ||
return { | ||
type: 'var', | ||
value: matchVariableName() | ||
}; | ||
}); | ||
} | ||
function matchHSLColor() { | ||
return matchCall(tokens.hslColor, function() { | ||
// Check for percentage before trying to parse the hue | ||
var lookahead = scan(tokens.percentageValue); | ||
if (lookahead) { | ||
error('HSL hue value must be a number in degrees (0-360) or normalized (-360 to 360), not a percentage'); | ||
} | ||
var hue = matchNumber(); | ||
scan(tokens.comma); | ||
var captures = scan(tokens.percentageValue); | ||
var sat = captures ? captures[1] : null; | ||
scan(tokens.comma); | ||
captures = scan(tokens.percentageValue); | ||
var light = captures ? captures[1] : null; | ||
if (!sat || !light) { | ||
error('Expected percentage value for saturation and lightness in HSL'); | ||
} | ||
return { | ||
type: 'hsl', | ||
value: [hue, sat, light] | ||
}; | ||
}); | ||
} | ||
function matchHSLAColor() { | ||
return matchCall(tokens.hslaColor, function() { | ||
var hue = matchNumber(); | ||
scan(tokens.comma); | ||
var captures = scan(tokens.percentageValue); | ||
var sat = captures ? captures[1] : null; | ||
scan(tokens.comma); | ||
captures = scan(tokens.percentageValue); | ||
var light = captures ? captures[1] : null; | ||
scan(tokens.comma); | ||
var alpha = matchNumber(); | ||
if (!sat || !light) { | ||
error('Expected percentage value for saturation and lightness in HSLA'); | ||
} | ||
return { | ||
type: 'hsla', | ||
value: [hue, sat, light, alpha] | ||
}; | ||
}); | ||
} | ||
function matchPercentage() { | ||
var captures = scan(tokens.percentageValue); | ||
return captures ? captures[1] : null; | ||
} | ||
function matchVariableName() { | ||
return scan(tokens.variableName)[1]; | ||
} | ||
function matchNumber() { | ||
@@ -352,3 +425,7 @@ return scan(tokens.number)[1]; | ||
return function(code) { | ||
input = code.toString(); | ||
input = code.toString().trim(); | ||
// Remove trailing semicolon if present | ||
if (input.endsWith(';')) { | ||
input = input.slice(0, -1); | ||
} | ||
return getAST(); | ||
@@ -466,2 +543,14 @@ }; | ||
'visit_hsl': function(node) { | ||
return visitor.visit_color('hsl(' + node.value[0] + ', ' + node.value[1] + '%, ' + node.value[2] + '%)', node); | ||
}, | ||
'visit_hsla': function(node) { | ||
return visitor.visit_color('hsla(' + node.value[0] + ', ' + node.value[1] + '%, ' + node.value[2] + '%, ' + node.value[3] + ')', node); | ||
}, | ||
'visit_var': function(node) { | ||
return visitor.visit_color('var(' + node.value + ')', node); | ||
}, | ||
'visit_color': function(resultColor, node) { | ||
@@ -499,2 +588,9 @@ var result = resultColor, | ||
'visit_object': function(obj) { | ||
if (obj.width && obj.height) { | ||
return visitor.visit(obj.width) + ' ' + visitor.visit(obj.height); | ||
} | ||
return ''; | ||
}, | ||
'visit': function(element) { | ||
@@ -508,2 +604,4 @@ if (!element) { | ||
return visitor.visit_array(element, result); | ||
} else if (typeof element === 'object' && !element.type) { | ||
return visitor.visit_object(element); | ||
} else if (element.type) { | ||
@@ -510,0 +608,0 @@ var nodeVisitor = visitor['visit_' + element.type]; |
@@ -14,3 +14,3 @@ // Copyright (c) 2014 Rafael Caricio. All rights reserved. | ||
repeatingRadialGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-radial\-gradient)/i, | ||
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|left|right|top|bottom)/i, | ||
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|top (left|right)|bottom (left|right)|left|right|top|bottom)/i, | ||
extentKeywords: /^(closest\-side|closest\-corner|farthest\-side|farthest\-corner|contain|cover)/, | ||
@@ -22,2 +22,3 @@ positionKeywords: /^(left|center|right|top|bottom)/i, | ||
angleValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))deg/, | ||
radianValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))rad/, | ||
startCall: /^\(/, | ||
@@ -30,3 +31,7 @@ endCall: /^\)/, | ||
rgbaColor: /^rgba/i, | ||
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/ | ||
varColor: /^var/i, | ||
variableName: /^(--[a-zA-Z0-9-,\s\#]+)/, | ||
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/, | ||
hslColor: /^hsl/i, | ||
hslaColor: /^hsla/i, | ||
}; | ||
@@ -124,3 +129,4 @@ | ||
function matchAngle() { | ||
return match('angular', tokens.angleValue, 1); | ||
return match('angular', tokens.angleValue, 1) || | ||
match('angular', tokens.radianValue, 1); | ||
} | ||
@@ -193,3 +199,3 @@ | ||
if (ellipse) { | ||
ellipse.style = matchDistance() || matchExtentKeyword(); | ||
ellipse.style = matchPositioning() || matchDistance() || matchExtentKeyword(); | ||
} | ||
@@ -266,4 +272,7 @@ | ||
return matchHexColor() || | ||
matchHSLAColor() || | ||
matchHSLColor() || | ||
matchRGBAColor() || | ||
matchRGBColor() || | ||
matchVarColor() || | ||
matchLiteralColor(); | ||
@@ -298,2 +307,66 @@ } | ||
function matchVarColor() { | ||
return matchCall(tokens.varColor, function () { | ||
return { | ||
type: 'var', | ||
value: matchVariableName() | ||
}; | ||
}); | ||
} | ||
function matchHSLColor() { | ||
return matchCall(tokens.hslColor, function() { | ||
// Check for percentage before trying to parse the hue | ||
var lookahead = scan(tokens.percentageValue); | ||
if (lookahead) { | ||
error('HSL hue value must be a number in degrees (0-360) or normalized (-360 to 360), not a percentage'); | ||
} | ||
var hue = matchNumber(); | ||
scan(tokens.comma); | ||
var captures = scan(tokens.percentageValue); | ||
var sat = captures ? captures[1] : null; | ||
scan(tokens.comma); | ||
captures = scan(tokens.percentageValue); | ||
var light = captures ? captures[1] : null; | ||
if (!sat || !light) { | ||
error('Expected percentage value for saturation and lightness in HSL'); | ||
} | ||
return { | ||
type: 'hsl', | ||
value: [hue, sat, light] | ||
}; | ||
}); | ||
} | ||
function matchHSLAColor() { | ||
return matchCall(tokens.hslaColor, function() { | ||
var hue = matchNumber(); | ||
scan(tokens.comma); | ||
var captures = scan(tokens.percentageValue); | ||
var sat = captures ? captures[1] : null; | ||
scan(tokens.comma); | ||
captures = scan(tokens.percentageValue); | ||
var light = captures ? captures[1] : null; | ||
scan(tokens.comma); | ||
var alpha = matchNumber(); | ||
if (!sat || !light) { | ||
error('Expected percentage value for saturation and lightness in HSLA'); | ||
} | ||
return { | ||
type: 'hsla', | ||
value: [hue, sat, light, alpha] | ||
}; | ||
}); | ||
} | ||
function matchPercentage() { | ||
var captures = scan(tokens.percentageValue); | ||
return captures ? captures[1] : null; | ||
} | ||
function matchVariableName() { | ||
return scan(tokens.variableName)[1]; | ||
} | ||
function matchNumber() { | ||
@@ -350,5 +423,9 @@ return scan(tokens.number)[1]; | ||
return function(code) { | ||
input = code.toString(); | ||
input = code.toString().trim(); | ||
// Remove trailing semicolon if present | ||
if (input.endsWith(';')) { | ||
input = input.slice(0, -1); | ||
} | ||
return getAST(); | ||
}; | ||
})(); |
@@ -109,2 +109,14 @@ // Copyright (c) 2014 Rafael Caricio. All rights reserved. | ||
'visit_hsl': function(node) { | ||
return visitor.visit_color('hsl(' + node.value[0] + ', ' + node.value[1] + '%, ' + node.value[2] + '%)', node); | ||
}, | ||
'visit_hsla': function(node) { | ||
return visitor.visit_color('hsla(' + node.value[0] + ', ' + node.value[1] + '%, ' + node.value[2] + '%, ' + node.value[3] + ')', node); | ||
}, | ||
'visit_var': function(node) { | ||
return visitor.visit_color('var(' + node.value + ')', node); | ||
}, | ||
'visit_color': function(resultColor, node) { | ||
@@ -142,2 +154,9 @@ var result = resultColor, | ||
'visit_object': function(obj) { | ||
if (obj.width && obj.height) { | ||
return visitor.visit(obj.width) + ' ' + visitor.visit(obj.height); | ||
} | ||
return ''; | ||
}, | ||
'visit': function(element) { | ||
@@ -151,2 +170,4 @@ if (!element) { | ||
return visitor.visit_array(element, result); | ||
} else if (typeof element === 'object' && !element.type) { | ||
return visitor.visit_object(element); | ||
} else if (element.type) { | ||
@@ -153,0 +174,0 @@ var nodeVisitor = visitor['visit_' + element.type]; |
{ | ||
"name": "gradient-parser", | ||
"version": "1.0.2", | ||
"version": "1.1.0", | ||
"description": "Parse CSS3 gradient definitions and return an AST.", | ||
@@ -28,3 +28,9 @@ "author": { | ||
"scripts": { | ||
"test": "grunt" | ||
"test": "mocha spec/**/*.js", | ||
"build": "node build.js", | ||
"build:node": "node build.js --node", | ||
"build:web": "node build.js --web", | ||
"build:minify": "node build.js --minify", | ||
"start": "python -m SimpleHTTPServer 3000", | ||
"prepublish": "npm run build" | ||
}, | ||
@@ -37,10 +43,5 @@ "keywords": [ | ||
"devDependencies": { | ||
"expect.js": "*", | ||
"grunt": "*", | ||
"grunt-browserify": "^3.0.1", | ||
"grunt-complexity": "*", | ||
"grunt-contrib-concat": "^0.5.0", | ||
"grunt-contrib-uglify": "^0.5.1", | ||
"grunt-mocha-test": "^0.11.0", | ||
"mocha": "*" | ||
"expect.js": "^0.3.1", | ||
"esbuild": "^0.20.2", | ||
"mocha": "^10.3.0" | ||
}, | ||
@@ -47,0 +48,0 @@ "engines": { |
# Gradient Parser | ||
[](https://badge.fury.io/js/gradient-parser) | ||
## About | ||
@@ -39,6 +41,66 @@ | ||
## Install Choices | ||
- `bower install gradient-parser` | ||
- [download the zip](https://github.com/rafaelcaricio/gradient-parser/archive/master.zip) | ||
## Installation | ||
Install via npm: | ||
```bash | ||
npm install gradient-parser | ||
``` | ||
Import in Node.js: | ||
```javascript | ||
const gradient = require('gradient-parser'); | ||
``` | ||
For browser usage: | ||
```html | ||
<script src="node_modules/gradient-parser/build/web.js"></script> | ||
``` | ||
Or [download the zip](https://github.com/rafaelcaricio/gradient-parser/archive/master.zip) | ||
## Development | ||
### Project Status | ||
Gradient-parser has been modernized (as of v1.1.0): | ||
- Removed Bower support in favor of npm exclusively | ||
- Replaced Grunt with a modern build system using esbuild | ||
- Added minification support | ||
- Updated dependencies to specific versions | ||
- Improved npm scripts for better developer experience | ||
### Build | ||
Gradient-parser uses a modern build system with esbuild for building and minification. | ||
```bash | ||
# Build both Node.js and web bundles | ||
npm run build | ||
# Build only Node.js bundle | ||
npm run build:node | ||
# Build only web bundle | ||
npm run build:web | ||
# Build minified bundles | ||
npm run build:minify | ||
``` | ||
### Testing | ||
Run the test suite with: | ||
```bash | ||
npm test | ||
``` | ||
### Starting a local server | ||
You can run a simple HTTP server for development: | ||
```bash | ||
npm start | ||
``` | ||
## API | ||
@@ -134,3 +196,3 @@ | ||
Copyright (c) 2014 Rafael Caricio rafael@caricio.com | ||
Copyright (c) 2014-2025 Rafael Caricio rafael@caricio.com | ||
@@ -137,0 +199,0 @@ Permission is hereby granted, free of charge, to any person obtaining |
@@ -137,3 +137,8 @@ 'use strict'; | ||
{type: 'angular', unparsedValue: '-145deg', value: '-145'}, | ||
{type: 'directional', unparsedValue: 'to left top', value: 'left top'} | ||
{type: 'angular', unparsedValue: '1rad', value: '1'}, | ||
{type: 'directional', unparsedValue: 'to left top', value: 'left top'}, | ||
{type: 'directional', unparsedValue: 'to top left', value: 'top left'}, | ||
{type: 'directional', unparsedValue: 'to top right', value: 'top right'}, | ||
{type: 'directional', unparsedValue: 'to bottom left', value: 'bottom left'}, | ||
{type: 'directional', unparsedValue: 'to bottom right', value: 'bottom right'} | ||
].forEach(function(orientation) { | ||
@@ -159,3 +164,7 @@ describe('parse orientation ' + orientation.type, function() { | ||
{type: 'rgb', unparsedValue: 'rgb(243, 226, 195)', value: ['243', '226', '195']}, | ||
{type: 'rgba', unparsedValue: 'rgba(243, 226, 195)', value: ['243', '226', '195']} | ||
{type: 'rgba', unparsedValue: 'rgba(243, 226, 195)', value: ['243', '226', '195']}, | ||
{type: 'hsl', unparsedValue: 'hsl(120, 60%, 70%)', value: ['120', '60', '70']}, | ||
{type: 'hsla', unparsedValue: 'hsla(120, 60%, 70%, 0.3)', value: ['120', '60', '70', '0.3']}, | ||
{type: 'hsla', unparsedValue: 'hsla(240, 100%, 50%, 0.5)', value: ['240', '100', '50', '0.5']}, | ||
{type: 'var', unparsedValue: 'var(--color-red)', value: '--color-red'}, | ||
].forEach(function(color) { | ||
@@ -174,2 +183,22 @@ describe('parse color type '+ color.type, function() { | ||
}); | ||
describe('error cases for HSL/HSLA', function() { | ||
it('should error on missing percentage for saturation', function() { | ||
expect(function() { | ||
gradients.parse('linear-gradient(hsl(120, 60, 70%))'); | ||
}).to.throwException(/Expected percentage value/); | ||
}); | ||
it('should error on missing percentage for lightness', function() { | ||
expect(function() { | ||
gradients.parse('linear-gradient(hsl(120, 60%, 70))'); | ||
}).to.throwException(/Expected percentage value/); | ||
}); | ||
it('should error on percentage for hue', function() { | ||
expect(function() { | ||
gradients.parse('linear-gradient(hsl(120%, 60%, 70%))'); | ||
}).to.throwException(/HSL hue value must be a number in degrees \(0-360\) or normalized \(-360 to 360\), not a percentage/); | ||
}); | ||
}); | ||
}); | ||
@@ -214,4 +243,143 @@ | ||
}); | ||
it('should parse ellipse with dimensions and position', function() { | ||
const gradient = 'repeating-radial-gradient(ellipse 40px 134px at 50% 96%, rgb(0, 165, 223) 0%, rgb(62, 20, 123) 6.6%)'; | ||
const ast = gradients.parse(gradient); | ||
expect(ast[0].type).to.equal('repeating-radial-gradient'); | ||
expect(ast[0].orientation[0].type).to.equal('shape'); | ||
expect(ast[0].orientation[0].value).to.equal('ellipse'); | ||
// Check the style (size dimensions) | ||
expect(ast[0].orientation[0].style.type).to.equal('position'); | ||
expect(ast[0].orientation[0].style.value.x.type).to.equal('px'); | ||
expect(ast[0].orientation[0].style.value.x.value).to.equal('40'); | ||
expect(ast[0].orientation[0].style.value.y.type).to.equal('px'); | ||
expect(ast[0].orientation[0].style.value.y.value).to.equal('134'); | ||
// Check the position | ||
expect(ast[0].orientation[0].at.type).to.equal('position'); | ||
expect(ast[0].orientation[0].at.value.x.type).to.equal('%'); | ||
expect(ast[0].orientation[0].at.value.x.value).to.equal('50'); | ||
expect(ast[0].orientation[0].at.value.y.type).to.equal('%'); | ||
expect(ast[0].orientation[0].at.value.y.value).to.equal('96'); | ||
// Check the color stops | ||
expect(ast[0].colorStops).to.have.length(2); | ||
expect(ast[0].colorStops[0].type).to.equal('rgb'); | ||
expect(ast[0].colorStops[0].value).to.eql(['0', '165', '223']); | ||
expect(ast[0].colorStops[0].length.type).to.equal('%'); | ||
expect(ast[0].colorStops[0].length.value).to.equal('0'); | ||
expect(ast[0].colorStops[1].type).to.equal('rgb'); | ||
expect(ast[0].colorStops[1].value).to.eql(['62', '20', '123']); | ||
expect(ast[0].colorStops[1].length.type).to.equal('%'); | ||
expect(ast[0].colorStops[1].length.value).to.equal('6.6'); | ||
}); | ||
it('should parse full Pride flag gradient', function() { | ||
const gradient = 'repeating-radial-gradient(ellipse 40px 134px at 50% 96%,rgb(0, 165, 223) 0%,rgb(62, 20, 123) 6.6%,rgb(226, 0, 121) 13.2%,rgb(223, 19, 44) 18.8%,rgb(243, 239, 21) 24.1%,rgb(0, 152, 71) 33.3%)'; | ||
const ast = gradients.parse(gradient); | ||
expect(ast[0].type).to.equal('repeating-radial-gradient'); | ||
expect(ast[0].orientation[0].type).to.equal('shape'); | ||
expect(ast[0].orientation[0].value).to.equal('ellipse'); | ||
// Check dimensions and position | ||
expect(ast[0].orientation[0].style.type).to.equal('position'); | ||
expect(ast[0].orientation[0].at.type).to.equal('position'); | ||
// Verify all color stops are present (Pride flag colors) | ||
expect(ast[0].colorStops).to.have.length(6); | ||
// Check the first and last color stops | ||
expect(ast[0].colorStops[0].type).to.equal('rgb'); | ||
expect(ast[0].colorStops[0].value).to.eql(['0', '165', '223']); | ||
expect(ast[0].colorStops[5].type).to.equal('rgb'); | ||
expect(ast[0].colorStops[5].value).to.eql(['0', '152', '71']); | ||
expect(ast[0].colorStops[5].length.type).to.equal('%'); | ||
expect(ast[0].colorStops[5].length.value).to.equal('33.3'); | ||
}); | ||
}); | ||
describe('parse gradient strings with trailing semicolons', function() { | ||
it('should parse linear-gradient with trailing semicolon', function() { | ||
const inputWithSemicolon = 'linear-gradient(red, blue);'; | ||
const ast = gradients.parse(inputWithSemicolon); | ||
expect(ast[0].type).to.equal('linear-gradient'); | ||
expect(ast[0].colorStops).to.have.length(2); | ||
expect(ast[0].colorStops[0].value).to.equal('red'); | ||
expect(ast[0].colorStops[1].value).to.equal('blue'); | ||
}); | ||
it('should parse radial-gradient with trailing semicolon', function() { | ||
const inputWithSemicolon = 'radial-gradient(circle, red, blue);'; | ||
const ast = gradients.parse(inputWithSemicolon); | ||
expect(ast[0].type).to.equal('radial-gradient'); | ||
expect(ast[0].colorStops).to.have.length(2); | ||
expect(ast[0].colorStops[0].value).to.equal('red'); | ||
expect(ast[0].colorStops[1].value).to.equal('blue'); | ||
}); | ||
it('should parse complex gradient with trailing semicolon', function() { | ||
const inputWithSemicolon = 'linear-gradient(to right, rgb(22, 234, 174) 0%, rgb(126, 32, 207) 100%);'; | ||
const ast = gradients.parse(inputWithSemicolon); | ||
expect(ast[0].type).to.equal('linear-gradient'); | ||
expect(ast[0].orientation.type).to.equal('directional'); | ||
expect(ast[0].orientation.value).to.equal('right'); | ||
expect(ast[0].colorStops).to.have.length(2); | ||
expect(ast[0].colorStops[0].type).to.equal('rgb'); | ||
expect(ast[0].colorStops[0].length.type).to.equal('%'); | ||
expect(ast[0].colorStops[0].length.value).to.equal('0'); | ||
expect(ast[0].colorStops[1].type).to.equal('rgb'); | ||
expect(ast[0].colorStops[1].length.type).to.equal('%'); | ||
expect(ast[0].colorStops[1].length.value).to.equal('100'); | ||
}); | ||
}); | ||
describe('parse gradient strings', function() { | ||
it('should parse repeating linear gradient with bottom right direction', function() { | ||
const gradient = 'repeating-linear-gradient(to bottom right,rgb(254, 158, 150) 0%,rgb(172, 79, 115) 100%)'; | ||
const ast = gradients.parse(gradient); | ||
expect(ast[0].type).to.equal('repeating-linear-gradient'); | ||
expect(ast[0].orientation.type).to.equal('directional'); | ||
expect(ast[0].orientation.value).to.equal('bottom right'); | ||
expect(ast[0].colorStops).to.have.length(2); | ||
expect(ast[0].colorStops[0].type).to.equal('rgb'); | ||
expect(ast[0].colorStops[0].value).to.eql(['254', '158', '150']); | ||
expect(ast[0].colorStops[0].length.type).to.equal('%'); | ||
expect(ast[0].colorStops[0].length.value).to.equal('0'); | ||
expect(ast[0].colorStops[1].type).to.equal('rgb'); | ||
expect(ast[0].colorStops[1].value).to.eql(['172', '79', '115']); | ||
expect(ast[0].colorStops[1].length.type).to.equal('%'); | ||
expect(ast[0].colorStops[1].length.value).to.equal('100'); | ||
}); | ||
describe('parse different color formats', function() { | ||
const testGradients = [ | ||
'linear-gradient(red, blue)', | ||
'linear-gradient(red, #00f)', | ||
'linear-gradient(red, #0000ff)', | ||
'linear-gradient(red, rgb(0, 0, 255))', | ||
'linear-gradient(red, rgba(0, 0, 255, 1))', | ||
'linear-gradient(red, hsl(240, 50%, 100%))', | ||
'linear-gradient(red, hsla(240, 50%, 100%, 1))' | ||
]; | ||
testGradients.forEach(function(gradient) { | ||
it('should parse ' + gradient, function() { | ||
const result = gradients.parse(gradient); | ||
expect(result[0].type).to.equal('linear-gradient'); | ||
expect(result[0].colorStops).to.have.length(2); | ||
expect(result[0].colorStops[0].type).to.equal('literal'); | ||
expect(result[0].colorStops[0].value).to.equal('red'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -33,2 +33,7 @@ 'use strict'; | ||
it('should serialize gradient with var', function() { | ||
var gradientDef = 'linear-gradient(var(--color-black), white)'; | ||
expect(gradients.stringify(gradients.parse(gradientDef))).to.equal(gradientDef); | ||
}); | ||
it('should serialize gradient with rgb', function() { | ||
@@ -35,0 +40,0 @@ var gradientDef = 'linear-gradient(rgb(1, 2, 3), white)'; |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
75641
40.26%3
-62.5%1975
27.75%215
40.52%1
Infinity%