Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add very basic RGB/RGBA color parsing support #3

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
93 changes: 82 additions & 11 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,46 @@
module.exports = parse;

function parse(str) {
return new Parser(str).parse();
var cleanStr = str.replace(/^\s+|\s+$/, '');
return new Parser(cleanStr).parse();
}

function Parser(str) {
this.str = str;
}

Parser.prototype.skip = function(m){
this.str = this.str.slice(m[0].length);
this.str = this.str.slice(m.length);
};

Parser.prototype.comma = function(){
var m = /^, */.exec(this.str);
if (!m) return;
this.skip(m);
this.skip(m[0]);
return { type: 'comma', string: ',' };
};

Parser.prototype.operator = function(){
var m = /^\/ */.exec(this.str);
if (!m) return;
this.skip(m[0]);
return { type: 'operator', value: '/' };
};

Parser.prototype.ident = function(){
var m = /^([\w-]+) */.exec(this.str);
if (!m) return;
this.skip(m);
this.skip(m[0]);
return {
type: 'ident',
string: m[1]
}
};

Parser.prototype.int = function(){
var m = /^((\d+)(\S+)?) */.exec(this.str);
var m = /^((-?\d+)([^\s\/]+)?) */.exec(this.str);
if (!m) return;
this.skip(m);
this.skip(m[0]);
var n = ~~m[2];
var u = m[3];

Expand All @@ -46,9 +54,9 @@ Parser.prototype.int = function(){
};

Parser.prototype.float = function(){
var m = /^(((?:\d+)?\.\d+)(\S+)?) */.exec(this.str);
var m = /^((-?(?:\d+)?\.\d+)([^\s\/]+)?) */.exec(this.str);
if (!m) return;
this.skip(m);
this.skip(m[0]);
var n = parseFloat(m[2]);
var u = m[3];

Expand All @@ -67,7 +75,7 @@ Parser.prototype.number = function(){
Parser.prototype.double = function(){
var m = /^"([^"]*)" */.exec(this.str);
if (!m) return m;
this.skip(m);
this.skip(m[0]);
return {
type: 'string',
quote: '"',
Expand All @@ -79,7 +87,7 @@ Parser.prototype.double = function(){
Parser.prototype.single = function(){
var m = /^'([^']*)' */.exec(this.str);
if (!m) return m;
this.skip(m);
this.skip(m[0]);
return {
type: 'string',
quote: "'",
Expand All @@ -92,9 +100,72 @@ Parser.prototype.string = function(){
return this.single() || this.double();
};

Parser.prototype.color = function(){
var m = /^(rgba?\([^)]*\)) */.exec(this.str);
if (!m) return m;
this.skip(m[0]);
return {
type: 'color',
value: m[1]
}
};

Parser.prototype.url = function(){
var m = /^(url\([^)]*\)) */.exec(this.str);
if (!m) return m;
this.skip(m[0]);
return {
type: 'url',
value: m[1]
}
};

function readToMatchingParen(str) {
if(str[0] !== '(') {
throw new Error('expected opening paren');
}

var opens = 0;
for(var i = 0; i < str.length; i++) {
if(str[i] === '(') {
opens++;
}
else if(str[i] === ')') {
opens--;
}

if(opens === 0) {
break;
}
}

if(opens !== 0) {
throw new Error('Failed parsing: No matching paren');
}

return str.slice(0, i + 1);
}

Parser.prototype.gradient = function(){
var m = /^(radial|linear)-gradient/.exec(this.str);
if (!m) return m;
this.skip(m[0]);

var gradientStr = readToMatchingParen(this.str);
this.skip(gradientStr);
return {
type: 'gradient',
value: m[0] + gradientStr
}
};

Parser.prototype.value = function(){
return this.number()
this.str = this.str.replace(/^\s+/, '');
return this.operator()
|| this.number()
|| this.color()
|| this.gradient()
|| this.url()
|| this.ident()
|| this.string()
|| this.comma();
Expand Down
13 changes: 10 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
{
"name": "css-value",
"version": "0.0.1",
"version": "0.0.2",
"description": "CSS value parser",
"keywords": ["css", "parser", "value"],
"keywords": [
"css",
"parser",
"value"
],
"author": "TJ Holowaychuk <[email protected]>",
"repository": {
"type": "git",
Expand All @@ -13,5 +17,8 @@
"mocha": "~1.9.0",
"should": "~1.2.2"
},
"main": "index"
"main": "index",
"scripts": {
"test": "mocha -r should"
}
}
6 changes: 6 additions & 0 deletions test/cases/colors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exports.string = 'rgba(1,2,3,4) rgb(9,8,7)';

exports.object = [
{ type: 'color', value: 'rgba(1,2,3,4)' },
{ type: 'color', value: 'rgb(9,8,7)' }
];
6 changes: 6 additions & 0 deletions test/cases/gradients.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exports.string = 'linear-gradient(to bottom, rgb(142, 75, 75), rgb(0, 0, 0))';

exports.object = [
{ type: 'gradient', value: 'linear-gradient(to bottom, rgb(142, 75, 75), rgb(0, 0, 0))' }
];

6 changes: 4 additions & 2 deletions test/cases/numbers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

exports.string = '1px 0 0 5% .5px .10 1.5';
exports.string = '1px 0 0 5% .5px .10 1.5 -1 -0.1';

exports.object = [
{ type: 'number', string: '1px', unit: 'px', value: 1 },
Expand All @@ -8,5 +8,7 @@ exports.object = [
{ type: 'number', string: '5%', unit: '%', value: 5 },
{ type: 'number', string: '.5px', unit: 'px', value: .5 },
{ type: 'number', string: '.10', unit: '', value: .1 },
{ type: 'number', string: '1.5', unit: '', value: 1.5 }
{ type: 'number', string: '1.5', unit: '', value: 1.5 },
{ type: 'number', string: '-1', unit: '', value: -1 },
{ type: 'number', string: '-0.1', unit: '', value: -0.1 }
];
12 changes: 12 additions & 0 deletions test/cases/operators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
exports.string = '50px/50% auto/auto';

exports.object = [
{ type: 'number', string: '50px', unit: 'px', value: 50 },
{ type: 'operator', value: '/' },
{ type: 'number', string: '50%', unit: '%', value: 50 },
{ type: 'ident', string: 'auto' },
{ type: 'operator', value: '/' },
{ type: 'ident', string: 'auto' }
];


5 changes: 5 additions & 0 deletions test/cases/space-in-front.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.string = ' rgba(1,2,3,4)';

exports.object = [
{ type: 'color', value: 'rgba(1,2,3,4)' }
]
6 changes: 6 additions & 0 deletions test/cases/urls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exports.string = 'url(http://foo.bar.com/whatever.png)';

exports.object = [
{ type: 'url', value: 'url(http://foo.bar.com/whatever.png)' }
];

4 changes: 3 additions & 1 deletion test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ var readdir = fs.readdirSync;
var path = require('path');
var basename = path.basename;

readdir('test/cases').forEach(function(file){
readdir('test/cases')
.filter(function(fn) { return /\.js$/.test(fn); })
.forEach(function(file){
var mod = require(path.resolve('test/cases/' + file));
var title = basename(file, '.js');
it('should support ' + title, function(){
Expand Down