gradient-parser/gradient-parser.js
2014-09-05 10:28:40 +02:00

161 lines
3.2 KiB
JavaScript

// Copyright (c) 2014 Rafael Caricio. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var GradientParser = module.exports = (function() {
var types = {
gradients: [
'linear-gradient',
'radial-gradient',
'repeating-radial-gradient'
],
colors: [
'hex',
'rgb',
'rgba',
'hsl',
'literal'
]
};
var tokens = {
linearGradient: /^linear\-gradient/i,
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|left|right|top|bottom)/i,
startCall: /^\(/,
endCall: /^\)/,
comma: /^,/
};
function error(input, cursor, msg) {
var err = new Error(input + ':' + cursor + ': ' + msg);
err.position = cursor;
err.message = msg;
err.source = input;
throw err;
}
function Constructor(input) {
this.input = input;
this.cursor = 0;
}
var def = Constructor.prototype;
def.parse = function(input) {
if (input) {
this.input = input;
}
var ast = this.listDefinitions();
if (this.input) {
error(input, cursor, 'Invalid input not EOF');
}
return ast;
};
def.listDefinitions = function() {
var definitions = [],
definition = this.definition();
if (definition) {
definitions.push(definition);
while (this.scan(tokens.comma)) {
definition = this.definition();
if (definition) {
definitions.push(definition);
} else {
// throw error
}
}
}
return definitions;
};
def.definition = function() {
return this.linearGradient();
};
def.linearGradient = function() {
var captures = this.scan(tokens.linearGradient),
orientation,
colorStops;
if (captures) {
this.scan(tokens.startCall);
orientation = this.orientation();
this.scan(tokens.comma);
colorStops = this.colorStops();
this.scan(tokens.endCall);
return {
type: 'linear-gradient',
orientation: orientation,
colorStops: colorStops
};
}
};
def.orientation = function() {
return this.sideOrCorner();
};
def.sideOrCorner = function() {
var captures = this.scan(tokens.sideOrCorner);
if (captures) {
return {
type: 'directional',
value: captures[1].toLowerCase()
};
}
};
def.colorStops = function() {
var literalColors = /^([a-zA-Z]+)/,
captures = this.scan(literalColors),
colors = [];
if (captures) {
colors.push(captures[0].toLowerCase());
while (this.scan(tokens.comma)) {
captures = this.scan(literalColors);
if (captures) {
colors.push(captures[0].toLowerCase());
} else {
// trow error
}
}
}
return colors;
};
def.scan = function(regexp) {
var captures,
blankCaptures;
blankCaptures = /^[\n\r\t\s]+/.exec(this.input);
if (blankCaptures) {
this.consume(blankCaptures[0].length);
}
captures = regexp.exec(this.input);
if (captures) {
this.consume(captures[0].length);
}
return captures;
};
def.consume = function(size) {
this.cursor += size;
this.input = this.input.substr(size);
};
return Constructor;
})();