Skip to content

Commit

Permalink
Proper parsing of the media queries
Browse files Browse the repository at this point in the history
  • Loading branch information
Panya committed Mar 17, 2014
1 parent 3833310 commit ac40442
Show file tree
Hide file tree
Showing 17 changed files with 427 additions and 26 deletions.
9 changes: 5 additions & 4 deletions lib/lexer.js
Expand Up @@ -410,6 +410,7 @@ Lexer.prototype = {
/**
* 'not'
* | 'and'
* | 'only'
* | 'or'
* | 'is'
* | 'is not'
Expand All @@ -421,7 +422,7 @@ Lexer.prototype = {
namedop: function() {
var captures
, tok;
if (captures = /^(not|and|or|is a|is defined|isnt|is not|is)(?!-)\b([ \t]*)/.exec(this.str)) {
if (captures = /^(not|and|only|or|is a|is defined|isnt|is not|is)(?!-)\b([ \t]*)/.exec(this.str)) {
var op = captures[1];
this.skip(captures);
if (this.isPartOfSelector()) {
Expand Down Expand Up @@ -498,14 +499,14 @@ Lexer.prototype = {
},

/**
* '@media' ([^{\n]+)
* '@media'
*/

media: function() {
var captures;
if (captures = /^@media[ \t]*(.+?)(?=\/\/|[\n{])/.exec(this.str)) {
if (captures = /^@media[ \t]*/.exec(this.str)) {
this.skip(captures);
return new Token('media', captures[1].trim());
return new Token('media');
}
},

Expand Down
3 changes: 3 additions & 0 deletions lib/nodes/index.js
Expand Up @@ -32,6 +32,9 @@ exports.JSLiteral = require('./jsliteral');
exports.Boolean = require('./boolean');
exports.Return = require('./return');
exports.Media = require('./media');
exports.QueryList = require('./query-list');
exports.Query = require('./query');
exports.QueryExpr = require('./query-expression');
exports.Params = require('./params');
exports.Comment = require('./comment');
exports.Keyframes = require('./keyframes');
Expand Down
2 changes: 1 addition & 1 deletion lib/nodes/media.js
Expand Up @@ -38,7 +38,7 @@ Media.prototype.__proto__ = Node.prototype;
*/

Media.prototype.clone = function(){
var clone = new Media(this.val);
var clone = new Media(this.val.clone());
clone.block = this.block.clone();
return clone;
};
Expand Down
64 changes: 64 additions & 0 deletions lib/nodes/query-expression.js
@@ -0,0 +1,64 @@

/*!
* Stylus - QueryExpr
* Copyright(c) 2014 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/

/**
* Module dependencies.
*/

var Node = require('./node');

/**
* Initialize a new `QueryExpr` with the given `segs`.
*
* @param {Array} segs
* @api public
*/

var QueryExpr = module.exports = function QueryExpr(segs){
Node.call(this);
this.segments = segs;
this.expr = null;
};

/**
* Inherit from `Node.prototype`.
*/

QueryExpr.prototype.__proto__ = Node.prototype;

/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/

QueryExpr.prototype.clone = function(){
var clone = new QueryExpr;
clone.segments = this.segments.map(function(node){ return node.clone(); });
if (this.expr) clone.expr = this.expr.clone();
if (this.name) clone.name = this.name;
clone.lineno = this.lineno;
clone.filename = this.filename;
return clone;
};

/**
* Return "<ident>" or "(<ident>: <expr>)"
*
* @return {String}
* @api public
*/

QueryExpr.prototype.toString = function(){
if (this.expr) {
return '(' + this.segments.join('') + ': ' + this.expr.toString() + ')';
} else {
return this.segments.join('');
}
};

71 changes: 71 additions & 0 deletions lib/nodes/query-list.js
@@ -0,0 +1,71 @@

/*!
* Stylus - QueryList
* Copyright(c) 2014 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/

/**
* Module dependencies.
*/

var Node = require('./node');

/**
* Initialize a new `QueryList`.
*
* @api public
*/

var QueryList = module.exports = function QueryList(){
Node.call(this);
this.nodes = [];
};

/**
* Inherit from `Node.prototype`.
*/

QueryList.prototype.__proto__ = Node.prototype;

/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/

QueryList.prototype.clone = function(){
var clone = new QueryList;
clone.lineno = this.lineno;
clone.filename = this.filename;
for (var i = 0; i < this.nodes.length; ++i) {
clone.push(this.nodes[i].clone());
}
return clone;
};

/**
* Push the given `node`.
*
* @param {Node} node
* @api public
*/

QueryList.prototype.push = function(node){
this.nodes.push(node);
};

/**
* Return "<a>, <b>, <c>"
*
* @return {String}
* @api public
*/

QueryList.prototype.toString = function(){
return '(' + this.nodes.map(function(node){
return node.toString();
}).join(', ') + ')';
};

74 changes: 74 additions & 0 deletions lib/nodes/query.js
@@ -0,0 +1,74 @@

/*!
* Stylus - Query
* Copyright(c) 2014 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/

/**
* Module dependencies.
*/

var Node = require('./node');

/**
* Initialize a new `Query`.
*
* @param {QueryExpr} query
* @api public
*/

var Query = module.exports = function Query(query){
Node.call(this);
this.nodes = query ? [query] : [];
this.predicate = '';
};

/**
* Inherit from `Node.prototype`.
*/

Query.prototype.__proto__ = Node.prototype;

/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/

Query.prototype.clone = function(){
var clone = new Query;
clone.predicate = this.predicate;
for (var i = 0, len = this.nodes.length; i < len; ++i) {
clone.push(this.nodes[i].clone());
}
clone.lineno = this.lineno;
clone.filename = this.filename;
return clone;
};

/**
* Push the given `expr`.
*
* @param {QueryExpr} expr
* @api public
*/

Query.prototype.push = function(expr){
this.nodes.push(expr);
};

/**
* Return "<a> and <b> and <c>"
*
* @return {String}
* @api public
*/

Query.prototype.toString = function(){
return '(' + this.nodes.map(function(expr){
return expr.toString();
}).join(' and ') + ')';
};

59 changes: 56 additions & 3 deletions lib/parser.js
Expand Up @@ -895,18 +895,71 @@ Parser.prototype = {
},

/**
* media
* media queries
*/

media: function() {
var val = this.expect('media').val
, media = new nodes.Media(val);
this.expect('media');
var media = new nodes.Media(this.queries());
this.state.push('media');
media.block = this.block(media);
this.state.pop();
return media;
},

/**
* query (',' query)*
*/

queries: function() {
var queries = new nodes.QueryList;
do {
queries.push(this.query());
} while(this.accept(','));
return queries;
},

/**
* ('only' | 'not')? ident ('and' queryExpr)*
* | queryExpr ('and' queryExpr)*
*/

query: function() {
var pred = this.accept('only') || this.accept('not')
, id
, query;

if (id = this.accept('ident')) {
query = new nodes.Query(new nodes.QueryExpr([id.val]));
} else {
query = new nodes.Query(this.queryExpr());
}

if (pred) query.predicate = new nodes.Literal(pred.val);
this.skipSpaces();
if (this.accept('&&')) {
do {
query.push(this.queryExpr());
} while(this.accept('&&'));
}

return query;
},

/**
* '(' ident ( ':'? expression )? ')'
*/

queryExpr: function() {
this.expect('(');
var node = new nodes.QueryExpr(this.interpolate());
this.skipSpaces();
this.accept(':')
node.expr = this.expression();
this.expect(')');
return node;
},

/**
* @-moz-document block
*/
Expand Down
40 changes: 39 additions & 1 deletion lib/visitor/compiler.js
Expand Up @@ -182,14 +182,52 @@ Compiler.prototype.visitKeyframes = function(node){
*/

Compiler.prototype.visitMedia = function(media){
this.buf += '@media ' + media.val;
this.buf += '@media ';
this.visit(media.val);
this.buf += this.compress ? '{' : ' {\n';
++this.indents;
this.visit(media.block);
--this.indents;
this.buf += '}' + (this.compress ? '' : '\n');
};

/**
* Visit QueryList.
*/

Compiler.prototype.visitQueryList = function(queries){
for (var i = 0, len = queries.nodes.length; i < len; ++i) {
this.visit(queries.nodes[i]);
if (len - 1 != i) this.buf += ',' + (this.compress ? '' : ' ');
}
};

/**
* Visit Query.
*/

Compiler.prototype.visitQuery = function(node){
if (node.predicate) this.buf += node.predicate + ' ';
for (var i = 0, len = node.nodes.length; i < len; ++i) {
this.visit(node.nodes[i]);
if (len - 1 != i) this.buf += ' and ';
}
};

/**
* Visit QueryExpr.
*/

Compiler.prototype.visitQueryExpr = function(node){
if (!node.expr) {
this.buf += node.name;
} else if (node.expr.isEmpty) {
this.buf += '(' + node.name + ')';
} else {
this.buf += '(' + node.name + ':' + (this.compress ? '' : ' ') + this.visit(node.expr) + ')';
}
};

/**
* Visit MozDocument.
*/
Expand Down

0 comments on commit ac40442

Please sign in to comment.