Compare commits

...

27 commits

Author SHA1 Message Date
Rafael Caricio 92b6e8011e
Merge pull request #15 from itaigilo-inv/support-more-directions
Support more directions
2021-07-21 15:34:54 +02:00
Itai Gilo a3494b3421 Add tests 2021-07-20 15:45:38 +03:00
Itai Gilo 330ffa92cd Support more directions 2021-07-20 15:35:29 +03:00
Rafael Caricio cce801d1df
Bump version 1.0.2 2021-03-15 14:53:53 +01:00
Rafael Caricio eff630c873
Fix declaration of result 2021-03-15 14:52:59 +01:00
Rafael Caricio c4ba2836b6
Tag version 1.0.1 2021-02-20 13:51:29 +01:00
Rafael Caricio 015088b929
Merge pull request #12 from pixelspark/master
Fix issue "undefined variable result" in built scripts as well
2021-02-20 13:45:33 +01:00
Tommy van der Vorst 4bfe95a98f Fix issue "undefined variable result" in built scripts as well 2021-02-01 11:21:42 +01:00
Rafael Caricio 04708dcb45
Bump version to 1.0.0 2021-01-20 13:46:46 +01:00
Rafael Caricio 2720da021f
Merge pull request #11 from ilyalesik/define-result
Define result variable
2021-01-19 17:13:26 +01:00
Ilia Lesik 12648a2a28 Define result variable 2019-12-25 16:05:34 +03:00
Rafael Caricio 4b49f43244 Merge pull request #5 from rafaelcaricio/fixes-4
Fails when radial-gradient shape is omitted but a size is provided
2016-01-10 13:26:56 +01:00
Rafael Caricio d0e6c24616 Fails when radial-gradient shape is omitted but a size is provided 2016-01-10 13:25:58 +01:00
Rafael Caricio ac093b15b3 Bump version 0.2.0 2014-10-01 19:31:42 +02:00
Rafael Caricio 3559c23b44 Stringify 2014-09-20 11:37:41 +02:00
Rafael Caricio 37e8f70262 Stringify 2014-09-19 19:40:56 +02:00
Rafael Caricio 129101533e Stringify 2014-09-19 19:40:56 +02:00
Rafael Caricio 75e01de8e4 Match correctly numbers 2014-09-19 19:36:32 +02:00
Rafael Caricio 77a461fc4d Fix bower 2014-09-19 19:36:32 +02:00
Rafael Caricio cb2e9e03f6 Bump version 0.1.5 2014-09-11 18:03:38 +02:00
Rafael Caricio 6c57770890 Match negatives and float values 2014-09-11 18:02:58 +02:00
Rafael Caricio 8675ce856f Bump version node 2014-09-11 17:49:37 +02:00
Rafael Caricio b61d2420c7 Bump version 0.1.3 2014-09-11 17:47:29 +02:00
Rafael Caricio 74b73132bc Bump version 0.1.3 2014-09-11 17:46:49 +02:00
Rafael Caricio ce4521b1b3 Match browser prefixes 2014-09-11 17:46:08 +02:00
Rafael Caricio f3de5fc9b6 Fix bower package 2014-09-07 21:49:29 +02:00
Rafael Caricio 4084ba4b5c Generate web and node versions of package. 2014-09-07 21:10:04 +02:00
14 changed files with 12385 additions and 80 deletions

5
Makefile Normal file
View file

@ -0,0 +1,5 @@
all:
python -m SimpleHTTPServer 3000
test:
grunt

View file

@ -1,7 +1,7 @@
{
"name": "gradient-parser",
"version": "0.1.0",
"main": "index.js",
"version": "1.0.0",
"main": "build/web.js",
"ignore": [
".editorconfig",
".gitattributes",
@ -10,9 +10,15 @@
".npmignore",
".travis.yml",
".umd",
"gulpfile.js",
"npm-shrinkwrap.json",
"package.json"
"package.json",
"index.html",
"Makefile",
"build/node.js",
"README.md",
"*.js",
"lib/*",
"spec/*",
"LICENSE"
],
"dependencies": {

516
build/node.js Normal file
View file

@ -0,0 +1,516 @@
// 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 = (GradientParser || {});
GradientParser.stringify = (function() {
var visitor = {
'visit_linear-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_repeating-linear-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_radial-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_repeating-radial-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_gradient': function(node) {
var orientation = visitor.visit(node.orientation);
if (orientation) {
orientation += ', ';
}
return node.type + '(' + orientation + visitor.visit(node.colorStops) + ')';
},
'visit_shape': function(node) {
var result = node.value,
at = visitor.visit(node.at),
style = visitor.visit(node.style);
if (style) {
result += ' ' + style;
}
if (at) {
result += ' at ' + at;
}
return result;
},
'visit_default-radial': function(node) {
var result = '',
at = visitor.visit(node.at);
if (at) {
result += at;
}
return result;
},
'visit_extent-keyword': function(node) {
var result = node.value,
at = visitor.visit(node.at);
if (at) {
result += ' at ' + at;
}
return result;
},
'visit_position-keyword': function(node) {
return node.value;
},
'visit_position': function(node) {
return visitor.visit(node.value.x) + ' ' + visitor.visit(node.value.y);
},
'visit_%': function(node) {
return node.value + '%';
},
'visit_em': function(node) {
return node.value + 'em';
},
'visit_px': function(node) {
return node.value + 'px';
},
'visit_literal': function(node) {
return visitor.visit_color(node.value, node);
},
'visit_hex': function(node) {
return visitor.visit_color('#' + node.value, node);
},
'visit_rgb': function(node) {
return visitor.visit_color('rgb(' + node.value.join(', ') + ')', node);
},
'visit_rgba': function(node) {
return visitor.visit_color('rgba(' + node.value.join(', ') + ')', node);
},
'visit_color': function(resultColor, node) {
var result = resultColor,
length = visitor.visit(node.length);
if (length) {
result += ' ' + length;
}
return result;
},
'visit_angular': function(node) {
return node.value + 'deg';
},
'visit_directional': function(node) {
return 'to ' + node.value;
},
'visit_array': function(elements) {
var result = '',
size = elements.length;
elements.forEach(function(element, i) {
result += visitor.visit(element);
if (i < size - 1) {
result += ', ';
}
});
return result;
},
'visit': function(element) {
if (!element) {
return '';
}
var result = '';
if (element instanceof Array) {
return visitor.visit_array(element, result);
} else if (element.type) {
var nodeVisitor = visitor['visit_' + element.type];
if (nodeVisitor) {
return nodeVisitor(element);
} else {
throw Error('Missing visitor visit_' + element.type);
}
} else {
throw Error('Invalid node.');
}
}
};
return function(root) {
return visitor.visit(root);
};
})();
// 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 = (GradientParser || {});
GradientParser.parse = (function() {
var tokens = {
linearGradient: /^(\-(webkit|o|ms|moz)\-)?(linear\-gradient)/i,
repeatingLinearGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-linear\-gradient)/i,
radialGradient: /^(\-(webkit|o|ms|moz)\-)?(radial\-gradient)/i,
repeatingRadialGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-radial\-gradient)/i,
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|left|right|top|bottom)/i,
extentKeywords: /^(closest\-side|closest\-corner|farthest\-side|farthest\-corner|contain|cover)/,
positionKeywords: /^(left|center|right|top|bottom)/i,
pixelValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))px/,
percentageValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))\%/,
emValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))em/,
angleValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))deg/,
startCall: /^\(/,
endCall: /^\)/,
comma: /^,/,
hexColor: /^\#([0-9a-fA-F]+)/,
literalColor: /^([a-zA-Z]+)/,
rgbColor: /^rgb/i,
rgbaColor: /^rgba/i,
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/
};
var input = '';
function error(msg) {
var err = new Error(input + ': ' + msg);
err.source = input;
throw err;
}
function getAST() {
var ast = matchListDefinitions();
if (input.length > 0) {
error('Invalid input not EOF');
}
return ast;
}
function matchListDefinitions() {
return matchListing(matchDefinition);
}
function matchDefinition() {
return matchGradient(
'linear-gradient',
tokens.linearGradient,
matchLinearOrientation) ||
matchGradient(
'repeating-linear-gradient',
tokens.repeatingLinearGradient,
matchLinearOrientation) ||
matchGradient(
'radial-gradient',
tokens.radialGradient,
matchListRadialOrientations) ||
matchGradient(
'repeating-radial-gradient',
tokens.repeatingRadialGradient,
matchListRadialOrientations);
}
function matchGradient(gradientType, pattern, orientationMatcher) {
return matchCall(pattern, function(captures) {
var orientation = orientationMatcher();
if (orientation) {
if (!scan(tokens.comma)) {
error('Missing comma before color stops');
}
}
return {
type: gradientType,
orientation: orientation,
colorStops: matchListing(matchColorStop)
};
});
}
function matchCall(pattern, callback) {
var captures = scan(pattern);
if (captures) {
if (!scan(tokens.startCall)) {
error('Missing (');
}
var result = callback(captures);
if (!scan(tokens.endCall)) {
error('Missing )');
}
return result;
}
}
function matchLinearOrientation() {
return matchSideOrCorner() ||
matchAngle();
}
function matchSideOrCorner() {
return match('directional', tokens.sideOrCorner, 1);
}
function matchAngle() {
return match('angular', tokens.angleValue, 1);
}
function matchListRadialOrientations() {
var radialOrientations,
radialOrientation = matchRadialOrientation(),
lookaheadCache;
if (radialOrientation) {
radialOrientations = [];
radialOrientations.push(radialOrientation);
lookaheadCache = input;
if (scan(tokens.comma)) {
radialOrientation = matchRadialOrientation();
if (radialOrientation) {
radialOrientations.push(radialOrientation);
} else {
input = lookaheadCache;
}
}
}
return radialOrientations;
}
function matchRadialOrientation() {
var radialType = matchCircle() ||
matchEllipse();
if (radialType) {
radialType.at = matchAtPosition();
} else {
var extent = matchExtentKeyword();
if (extent) {
radialType = extent;
var positionAt = matchAtPosition();
if (positionAt) {
radialType.at = positionAt;
}
} else {
var defaultPosition = matchPositioning();
if (defaultPosition) {
radialType = {
type: 'default-radial',
at: defaultPosition
};
}
}
}
return radialType;
}
function matchCircle() {
var circle = match('shape', /^(circle)/i, 0);
if (circle) {
circle.style = matchLength() || matchExtentKeyword();
}
return circle;
}
function matchEllipse() {
var ellipse = match('shape', /^(ellipse)/i, 0);
if (ellipse) {
ellipse.style = matchDistance() || matchExtentKeyword();
}
return ellipse;
}
function matchExtentKeyword() {
return match('extent-keyword', tokens.extentKeywords, 1);
}
function matchAtPosition() {
if (match('position', /^at/, 0)) {
var positioning = matchPositioning();
if (!positioning) {
error('Missing positioning value');
}
return positioning;
}
}
function matchPositioning() {
var location = matchCoordinates();
if (location.x || location.y) {
return {
type: 'position',
value: location
};
}
}
function matchCoordinates() {
return {
x: matchDistance(),
y: matchDistance()
};
}
function matchListing(matcher) {
var captures = matcher(),
result = [];
if (captures) {
result.push(captures);
while (scan(tokens.comma)) {
captures = matcher();
if (captures) {
result.push(captures);
} else {
error('One extra comma');
}
}
}
return result;
}
function matchColorStop() {
var color = matchColor();
if (!color) {
error('Expected color definition');
}
color.length = matchDistance();
return color;
}
function matchColor() {
return matchHexColor() ||
matchRGBAColor() ||
matchRGBColor() ||
matchLiteralColor();
}
function matchLiteralColor() {
return match('literal', tokens.literalColor, 0);
}
function matchHexColor() {
return match('hex', tokens.hexColor, 1);
}
function matchRGBColor() {
return matchCall(tokens.rgbColor, function() {
return {
type: 'rgb',
value: matchListing(matchNumber)
};
});
}
function matchRGBAColor() {
return matchCall(tokens.rgbaColor, function() {
return {
type: 'rgba',
value: matchListing(matchNumber)
};
});
}
function matchNumber() {
return scan(tokens.number)[1];
}
function matchDistance() {
return match('%', tokens.percentageValue, 1) ||
matchPositionKeyword() ||
matchLength();
}
function matchPositionKeyword() {
return match('position-keyword', tokens.positionKeywords, 1);
}
function matchLength() {
return match('px', tokens.pixelValue, 1) ||
match('em', tokens.emValue, 1);
}
function match(type, pattern, captureIndex) {
var captures = scan(pattern);
if (captures) {
return {
type: type,
value: captures[captureIndex]
};
}
}
function scan(regexp) {
var captures,
blankCaptures;
blankCaptures = /^[\n\r\t\s]+/.exec(input);
if (blankCaptures) {
consume(blankCaptures[0].length);
}
captures = regexp.exec(input);
if (captures) {
consume(captures[0].length);
}
return captures;
}
function consume(size) {
input = input.substr(size);
}
return function(code) {
input = code.toString();
return getAST();
};
})();
exports.parse = GradientParser.parse;
exports.stringify = GradientParser.stringify;

515
build/web.js Normal file
View file

@ -0,0 +1,515 @@
var GradientParser = (window.GradientParser || {});
// 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 = (GradientParser || {});
GradientParser.parse = (function() {
var tokens = {
linearGradient: /^(\-(webkit|o|ms|moz)\-)?(linear\-gradient)/i,
repeatingLinearGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-linear\-gradient)/i,
radialGradient: /^(\-(webkit|o|ms|moz)\-)?(radial\-gradient)/i,
repeatingRadialGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-radial\-gradient)/i,
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|left|right|top|bottom)/i,
extentKeywords: /^(closest\-side|closest\-corner|farthest\-side|farthest\-corner|contain|cover)/,
positionKeywords: /^(left|center|right|top|bottom)/i,
pixelValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))px/,
percentageValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))\%/,
emValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))em/,
angleValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))deg/,
startCall: /^\(/,
endCall: /^\)/,
comma: /^,/,
hexColor: /^\#([0-9a-fA-F]+)/,
literalColor: /^([a-zA-Z]+)/,
rgbColor: /^rgb/i,
rgbaColor: /^rgba/i,
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/
};
var input = '';
function error(msg) {
var err = new Error(input + ': ' + msg);
err.source = input;
throw err;
}
function getAST() {
var ast = matchListDefinitions();
if (input.length > 0) {
error('Invalid input not EOF');
}
return ast;
}
function matchListDefinitions() {
return matchListing(matchDefinition);
}
function matchDefinition() {
return matchGradient(
'linear-gradient',
tokens.linearGradient,
matchLinearOrientation) ||
matchGradient(
'repeating-linear-gradient',
tokens.repeatingLinearGradient,
matchLinearOrientation) ||
matchGradient(
'radial-gradient',
tokens.radialGradient,
matchListRadialOrientations) ||
matchGradient(
'repeating-radial-gradient',
tokens.repeatingRadialGradient,
matchListRadialOrientations);
}
function matchGradient(gradientType, pattern, orientationMatcher) {
return matchCall(pattern, function(captures) {
var orientation = orientationMatcher();
if (orientation) {
if (!scan(tokens.comma)) {
error('Missing comma before color stops');
}
}
return {
type: gradientType,
orientation: orientation,
colorStops: matchListing(matchColorStop)
};
});
}
function matchCall(pattern, callback) {
var captures = scan(pattern);
if (captures) {
if (!scan(tokens.startCall)) {
error('Missing (');
}
var result = callback(captures);
if (!scan(tokens.endCall)) {
error('Missing )');
}
return result;
}
}
function matchLinearOrientation() {
return matchSideOrCorner() ||
matchAngle();
}
function matchSideOrCorner() {
return match('directional', tokens.sideOrCorner, 1);
}
function matchAngle() {
return match('angular', tokens.angleValue, 1);
}
function matchListRadialOrientations() {
var radialOrientations,
radialOrientation = matchRadialOrientation(),
lookaheadCache;
if (radialOrientation) {
radialOrientations = [];
radialOrientations.push(radialOrientation);
lookaheadCache = input;
if (scan(tokens.comma)) {
radialOrientation = matchRadialOrientation();
if (radialOrientation) {
radialOrientations.push(radialOrientation);
} else {
input = lookaheadCache;
}
}
}
return radialOrientations;
}
function matchRadialOrientation() {
var radialType = matchCircle() ||
matchEllipse();
if (radialType) {
radialType.at = matchAtPosition();
} else {
var extent = matchExtentKeyword();
if (extent) {
radialType = extent;
var positionAt = matchAtPosition();
if (positionAt) {
radialType.at = positionAt;
}
} else {
var defaultPosition = matchPositioning();
if (defaultPosition) {
radialType = {
type: 'default-radial',
at: defaultPosition
};
}
}
}
return radialType;
}
function matchCircle() {
var circle = match('shape', /^(circle)/i, 0);
if (circle) {
circle.style = matchLength() || matchExtentKeyword();
}
return circle;
}
function matchEllipse() {
var ellipse = match('shape', /^(ellipse)/i, 0);
if (ellipse) {
ellipse.style = matchDistance() || matchExtentKeyword();
}
return ellipse;
}
function matchExtentKeyword() {
return match('extent-keyword', tokens.extentKeywords, 1);
}
function matchAtPosition() {
if (match('position', /^at/, 0)) {
var positioning = matchPositioning();
if (!positioning) {
error('Missing positioning value');
}
return positioning;
}
}
function matchPositioning() {
var location = matchCoordinates();
if (location.x || location.y) {
return {
type: 'position',
value: location
};
}
}
function matchCoordinates() {
return {
x: matchDistance(),
y: matchDistance()
};
}
function matchListing(matcher) {
var captures = matcher(),
result = [];
if (captures) {
result.push(captures);
while (scan(tokens.comma)) {
captures = matcher();
if (captures) {
result.push(captures);
} else {
error('One extra comma');
}
}
}
return result;
}
function matchColorStop() {
var color = matchColor();
if (!color) {
error('Expected color definition');
}
color.length = matchDistance();
return color;
}
function matchColor() {
return matchHexColor() ||
matchRGBAColor() ||
matchRGBColor() ||
matchLiteralColor();
}
function matchLiteralColor() {
return match('literal', tokens.literalColor, 0);
}
function matchHexColor() {
return match('hex', tokens.hexColor, 1);
}
function matchRGBColor() {
return matchCall(tokens.rgbColor, function() {
return {
type: 'rgb',
value: matchListing(matchNumber)
};
});
}
function matchRGBAColor() {
return matchCall(tokens.rgbaColor, function() {
return {
type: 'rgba',
value: matchListing(matchNumber)
};
});
}
function matchNumber() {
return scan(tokens.number)[1];
}
function matchDistance() {
return match('%', tokens.percentageValue, 1) ||
matchPositionKeyword() ||
matchLength();
}
function matchPositionKeyword() {
return match('position-keyword', tokens.positionKeywords, 1);
}
function matchLength() {
return match('px', tokens.pixelValue, 1) ||
match('em', tokens.emValue, 1);
}
function match(type, pattern, captureIndex) {
var captures = scan(pattern);
if (captures) {
return {
type: type,
value: captures[captureIndex]
};
}
}
function scan(regexp) {
var captures,
blankCaptures;
blankCaptures = /^[\n\r\t\s]+/.exec(input);
if (blankCaptures) {
consume(blankCaptures[0].length);
}
captures = regexp.exec(input);
if (captures) {
consume(captures[0].length);
}
return captures;
}
function consume(size) {
input = input.substr(size);
}
return function(code) {
input = code.toString();
return getAST();
};
})();
// 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 = (GradientParser || {});
GradientParser.stringify = (function() {
var visitor = {
'visit_linear-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_repeating-linear-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_radial-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_repeating-radial-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_gradient': function(node) {
var orientation = visitor.visit(node.orientation);
if (orientation) {
orientation += ', ';
}
return node.type + '(' + orientation + visitor.visit(node.colorStops) + ')';
},
'visit_shape': function(node) {
var result = node.value,
at = visitor.visit(node.at),
style = visitor.visit(node.style);
if (style) {
result += ' ' + style;
}
if (at) {
result += ' at ' + at;
}
return result;
},
'visit_default-radial': function(node) {
var result = '',
at = visitor.visit(node.at);
if (at) {
result += at;
}
return result;
},
'visit_extent-keyword': function(node) {
var result = node.value,
at = visitor.visit(node.at);
if (at) {
result += ' at ' + at;
}
return result;
},
'visit_position-keyword': function(node) {
return node.value;
},
'visit_position': function(node) {
return visitor.visit(node.value.x) + ' ' + visitor.visit(node.value.y);
},
'visit_%': function(node) {
return node.value + '%';
},
'visit_em': function(node) {
return node.value + 'em';
},
'visit_px': function(node) {
return node.value + 'px';
},
'visit_literal': function(node) {
return visitor.visit_color(node.value, node);
},
'visit_hex': function(node) {
return visitor.visit_color('#' + node.value, node);
},
'visit_rgb': function(node) {
return visitor.visit_color('rgb(' + node.value.join(', ') + ')', node);
},
'visit_rgba': function(node) {
return visitor.visit_color('rgba(' + node.value.join(', ') + ')', node);
},
'visit_color': function(resultColor, node) {
var result = resultColor,
length = visitor.visit(node.length);
if (length) {
result += ' ' + length;
}
return result;
},
'visit_angular': function(node) {
return node.value + 'deg';
},
'visit_directional': function(node) {
return 'to ' + node.value;
},
'visit_array': function(elements) {
var result = '',
size = elements.length;
elements.forEach(function(element, i) {
result += visitor.visit(element);
if (i < size - 1) {
result += ', ';
}
});
return result;
},
'visit': function(element) {
if (!element) {
return '';
}
var result = '';
if (element instanceof Array) {
return visitor.visit_array(element, result);
} else if (element.type) {
var nodeVisitor = visitor['visit_' + element.type];
if (nodeVisitor) {
return nodeVisitor(element);
} else {
throw Error('Missing visitor visit_' + element.type);
}
} else {
throw Error('Invalid node.');
}
}
};
return function(root) {
return visitor.visit(root);
};
})();

View file

@ -15,12 +15,22 @@ module.exports = function (grunt) {
},
src: ['spec/**/*.js']
}
},
concat: {
release: {
files: {
'build/node.js': ['lib/stringify.js', 'lib/parser.js', 'index.js'],
'build/web.js': ['webify.js', 'lib/parser.js', 'lib/stringify.js']
}
}
}
});
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', [
'concat',
'mochaTest'
]);
};

12
index.html Normal file
View file

@ -0,0 +1,12 @@
<html>
<head>
<script src="build/web.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.body.innerHTML = '<pre>'+ JSON.stringify(GradientParser.parse('radial-gradient(ellipse cover, rgb(0, 57, 115), rgb(229, 229, 190))'), null, 2) +'</pre>';
});
</script>
</head>
<body>
</body>
</html>

View file

@ -1 +1,2 @@
exports.parse = require('./lib/parser');
exports.parse = GradientParser.parse;
exports.stringify = GradientParser.stringify;

View file

@ -2,39 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module.exports = (function() {
var GradientParser = (GradientParser || {});
var types = {
gradients: [
'linear-gradient',
'repeating-linear-gradient',
'radial-gradient',
'repeating-radial-gradient'
],
colors: [
'hex',
'rgb',
'rgba',
'hsl',
'literal'
],
metrics: [
'px'
]
};
GradientParser.parse = (function() {
var tokens = {
linearGradient: /^linear\-gradient/i,
repeatingLinearGradient: /^repeating\-linear\-gradient/i,
radialGradient: /^radial\-gradient/i,
repeatingRadialGradient: /^repeating\-radial\-gradient/i,
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|left|right|top|bottom)/i,
linearGradient: /^(\-(webkit|o|ms|moz)\-)?(linear\-gradient)/i,
repeatingLinearGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-linear\-gradient)/i,
radialGradient: /^(\-(webkit|o|ms|moz)\-)?(radial\-gradient)/i,
repeatingRadialGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-radial\-gradient)/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)/,
positionKeywords: /^(left|center|right|top|bottom)/i,
pixelValue: /^([0-9]+)px/,
percentageValue: /^([0-9]+)\%/,
emValue: /^([0-9]+)em/,
angleValue: /^([0-9]+)deg/,
pixelValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))px/,
percentageValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))\%/,
emValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))em/,
angleValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))deg/,
startCall: /^\(/,
endCall: /^\)/,
comma: /^,/,
@ -115,7 +98,7 @@ module.exports = (function() {
error('Missing (');
}
result = callback(captures);
var result = callback(captures);
if (!scan(tokens.endCall)) {
error('Missing )');
@ -168,12 +151,21 @@ module.exports = (function() {
if (radialType) {
radialType.at = matchAtPosition();
} else {
var defaultPosition = matchPositioning();
if (defaultPosition) {
radialType = {
type: 'default-radial',
at: defaultPosition
};
var extent = matchExtentKeyword();
if (extent) {
radialType = extent;
var positionAt = matchAtPosition();
if (positionAt) {
radialType.at = positionAt;
}
} else {
var defaultPosition = matchPositioning();
if (defaultPosition) {
radialType = {
type: 'default-radial',
at: defaultPosition
};
}
}
}

166
lib/stringify.js Normal file
View file

@ -0,0 +1,166 @@
// 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 = (GradientParser || {});
GradientParser.stringify = (function() {
var visitor = {
'visit_linear-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_repeating-linear-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_radial-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_repeating-radial-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_gradient': function(node) {
var orientation = visitor.visit(node.orientation);
if (orientation) {
orientation += ', ';
}
return node.type + '(' + orientation + visitor.visit(node.colorStops) + ')';
},
'visit_shape': function(node) {
var result = node.value,
at = visitor.visit(node.at),
style = visitor.visit(node.style);
if (style) {
result += ' ' + style;
}
if (at) {
result += ' at ' + at;
}
return result;
},
'visit_default-radial': function(node) {
var result = '',
at = visitor.visit(node.at);
if (at) {
result += at;
}
return result;
},
'visit_extent-keyword': function(node) {
var result = node.value,
at = visitor.visit(node.at);
if (at) {
result += ' at ' + at;
}
return result;
},
'visit_position-keyword': function(node) {
return node.value;
},
'visit_position': function(node) {
return visitor.visit(node.value.x) + ' ' + visitor.visit(node.value.y);
},
'visit_%': function(node) {
return node.value + '%';
},
'visit_em': function(node) {
return node.value + 'em';
},
'visit_px': function(node) {
return node.value + 'px';
},
'visit_literal': function(node) {
return visitor.visit_color(node.value, node);
},
'visit_hex': function(node) {
return visitor.visit_color('#' + node.value, node);
},
'visit_rgb': function(node) {
return visitor.visit_color('rgb(' + node.value.join(', ') + ')', node);
},
'visit_rgba': function(node) {
return visitor.visit_color('rgba(' + node.value.join(', ') + ')', node);
},
'visit_color': function(resultColor, node) {
var result = resultColor,
length = visitor.visit(node.length);
if (length) {
result += ' ' + length;
}
return result;
},
'visit_angular': function(node) {
return node.value + 'deg';
},
'visit_directional': function(node) {
return 'to ' + node.value;
},
'visit_array': function(elements) {
var result = '',
size = elements.length;
elements.forEach(function(element, i) {
result += visitor.visit(element);
if (i < size - 1) {
result += ', ';
}
});
return result;
},
'visit': function(element) {
if (!element) {
return '';
}
var result = '';
if (element instanceof Array) {
return visitor.visit_array(element, result);
} else if (element.type) {
var nodeVisitor = visitor['visit_' + element.type];
if (nodeVisitor) {
return nodeVisitor(element);
} else {
throw Error('Missing visitor visit_' + element.type);
}
} else {
throw Error('Invalid node.');
}
}
};
return function(root) {
return visitor.visit(root);
};
})();

10999
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "gradient-parser",
"version": "0.1.0",
"version": "1.0.2",
"description": "Parse CSS3 gradient definitions and return an AST.",
"author": {
"name": "Rafael Carcicio",
@ -23,7 +23,7 @@
"type": "git",
"url": "git://github.com/rafaelcaricio/gradient-parser.git"
},
"main": "index.js",
"main": "build/node.js",
"scripts": {
"test": "grunt"
},
@ -32,10 +32,12 @@
"css3",
"parser"
],
"dependencies": {},
"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": "*"

View file

@ -1,37 +1,10 @@
'use strict';
var expect = require('expect.js');
var gradients = require('index');
var gradients = require('../build/node');
// [
// {
// type: 'linear-gradient',
// orientation: {
// type: 'directional',
// value: 'right'
// },
// colorStops: [
// {
// type: 'literal',
// value: 'transparent',
// length: {
// value: '10',
// type: 'px'
// }
// },
// {
// type: 'hex',
// value: 'c2c2c2',
// length: {
// value: '10',
// type: 'px'
// }
// }
// ]
// }
// ]
describe('gradient-parser.js', function () {
describe('lib/parser.js', function () {
var ast,
subject;
@ -42,13 +15,13 @@ describe('gradient-parser.js', function () {
describe('error cases', function() {
it('one more comma in definitions', function() {
expect(function() {
gradients.parse('linear-gradient(red, blue),');
gradients.parse('-webkit-linear-gradient(red, blue),');
}).to.throwException(/One extra comma/);
});
it('one more comma in colors', function() {
expect(function() {
gradients.parse('linear-gradient(red, blue,)');
gradients.parse('-o-linear-gradient(red, blue,)');
}).to.throwException(/Expected color definition/);
});
@ -140,7 +113,7 @@ describe('gradient-parser.js', function () {
].forEach(function(metric) {
describe('parse color stop for metric '+ metric, function() {
beforeEach(function() {
ast = gradients.parse('linear-gradient(blue 10' + metric + ', transparent)');
ast = gradients.parse('linear-gradient(blue 10.3' + metric + ', transparent)');
subject = ast[0];
});
@ -151,7 +124,7 @@ describe('gradient-parser.js', function () {
it('should have the length', function() {
expect(subject.length.type).to.equal(metric);
expect(subject.length.value).to.equal('10');
expect(subject.length.value).to.equal('10.3');
});
});
});
@ -160,8 +133,12 @@ describe('gradient-parser.js', function () {
describe('parse all linear directional', function() {
[
{type: 'angular', unparsedValue: '145deg', value: '145'},
{type: 'directional', unparsedValue: 'to left top', value: 'left top'}
{type: 'angular', unparsedValue: '-145deg', value: '-145'},
{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) {
describe('parse orientation ' + orientation.type, function() {
beforeEach(function() {
@ -224,7 +201,10 @@ describe('gradient-parser.js', function () {
'ellipse cover',
'circle cover',
'center bottom, ellipse cover',
'circle at 119px 58px'
'circle at 87.23px -58.3px',
'farthest-side, red, blue',
'farthest-corner, red, blue',
'farthest-corner at 87.23px -58.3px, red, blue'
].forEach(function(declaration) {
it('should parse ' + declaration + ' declaration', function() {

100
spec/stringify.spec.js Normal file
View file

@ -0,0 +1,100 @@
'use strict';
var expect = require('expect.js');
var gradients = require('../build/node');
function pprint(ast) {
console.log(JSON.stringify(ast, true, 2));
}
describe('lib/stringify.js', function () {
var subject;
it('should exist', function () {
expect(typeof gradients.stringify).to.equal('function');
});
describe('serialization', function() {
it('if tree is null', function() {
expect(gradients.stringify(null)).to.equal('');
});
it('should serialize a simple gradient', function() {
var gradientDef = 'linear-gradient(black, white)';
expect(gradients.stringify(gradients.parse(gradientDef))).to.equal(gradientDef);
});
it('should serialize gradient with hex', function() {
var gradientDef = 'linear-gradient(#fff, white)';
expect(gradients.stringify(gradients.parse(gradientDef))).to.equal(gradientDef);
});
it('should serialize gradient with rgb', function() {
var gradientDef = 'linear-gradient(rgb(1, 2, 3), white)';
expect(gradients.stringify(gradients.parse(gradientDef))).to.equal(gradientDef);
});
it('should serialize gradient with rgba', function() {
var gradientDef = 'linear-gradient(rgba(1, 2, 3, .0), white)';
expect(gradients.stringify(gradients.parse(gradientDef))).to.equal(gradientDef);
});
it('should serialize gradient with deg', function() {
var gradientDef = 'linear-gradient(45deg, #fff, transparent)';
expect(gradients.stringify(gradients.parse(gradientDef))).to.equal(gradientDef);
});
it('should serialize gradient with directional', function() {
var gradientDef = 'linear-gradient(to left, #fff, transparent)';
expect(gradients.stringify(gradients.parse(gradientDef))).to.equal(gradientDef);
});
describe('all metric values', function() {
[
'px',
'em',
'%'
].forEach(function(metric) {
var expectedResult;
describe('stringify color stop for metric '+ metric, function() {
beforeEach(function() {
expectedResult = 'linear-gradient(blue 10.3' + metric + ', transparent)';
var ast = gradients.parse(expectedResult);
subject = gradients.stringify(ast);
});
it('should result as expected', function() {
expect(subject).to.equal(expectedResult);
});
});
});
});
describe('different radial declarations', function() {
[
'ellipse farthest-corner',
'ellipse cover',
'circle cover',
'center bottom, ellipse cover',
'circle at 87.23px -58.3px',
'farthest-corner, red, blue',
'farthest-corner at 87.23px -58.3px, red, blue'
].forEach(function(declaration) {
it('should parse ' + declaration + ' declaration', function() {
var expectedResult = 'radial-gradient(' + declaration + ', red, blue)';
var ast = gradients.parse(expectedResult);
subject = gradients.stringify(ast);
expect(subject).to.equal(expectedResult);
});
});
});
});
});

1
webify.js Normal file
View file

@ -0,0 +1 @@
var GradientParser = (window.GradientParser || {});