Socket
Socket
Sign inDemoInstall

stylus

Package Overview
Dependencies
16
Maintainers
5
Versions
182
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.59.0 to 0.60.0

deno/test.ts

122

lib/cache/fs.js

@@ -11,71 +11,75 @@ /**

var FSCache = module.exports = function(options) {
options = options || {};
this._location = options['cache location'] || '.styl-cache';
if (!fs.existsSync(this._location)) fs.mkdirSync(this._location);
};
module.exports = class FSCache {
constructor(options) {
options = options || {};
this._location = options['cache location'] || '.styl-cache';
if (!fs.existsSync(this._location)) fs.mkdirSync(this._location);
}
/**
* Set cache item with given `key` to `value`.
*
* @param {String} key
* @param {Object} value
* @api private
*/
FSCache.prototype.set = function(key, value) {
fs.writeFileSync(join(this._location, key), JSON.stringify(value));
};
/**
* Set cache item with given `key` to `value`.
*
* @param {String} key
* @param {Object} value
* @api private
*/
/**
* Get cache item with given `key`.
*
* @param {String} key
* @return {Object}
* @api private
*/
set(key, value) {
fs.writeFileSync(join(this._location, key), JSON.stringify(value));
};
FSCache.prototype.get = function(key) {
var data = fs.readFileSync(join(this._location, key), 'utf-8');
return JSON.parse(data, FSCache.fromJSON);
};
/**
* Get cache item with given `key`.
*
* @param {String} key
* @return {Object}
* @api private
*/
/**
* Check if cache has given `key`.
*
* @param {String} key
* @return {Boolean}
* @api private
*/
get(key) {
var data = fs.readFileSync(join(this._location, key), 'utf-8');
return JSON.parse(data, FSCache.fromJSON);
};
FSCache.prototype.has = function(key) {
return fs.existsSync(join(this._location, key));
};
/**
* Check if cache has given `key`.
*
* @param {String} key
* @return {Boolean}
* @api private
*/
/**
* Generate key for the source `str` with `options`.
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api private
*/
has(key) {
return fs.existsSync(join(this._location, key));
};
FSCache.prototype.key = function(str, options) {
var hash = crypto.createHash('sha1');
hash.update(str + version + options.prefix);
return hash.digest('hex');
};
/**
* Generate key for the source `str` with `options`.
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api private
*/
/**
* JSON to Stylus nodes converter.
*
* @api private
*/
key(str, options) {
var hash = crypto.createHash('sha1');
hash.update(str + version + options.prefix);
return hash.digest('hex');
};
FSCache.fromJSON = function(key, val) {
if (val && val.__type) {
val.__proto__ = nodes[val.__type].prototype;
}
return val;
/**
* JSON to Stylus nodes converter.
*
* @api private
*/
static fromJSON(key, val) {
if (val && val.__type) {
Object.setPrototypeOf(val, nodes[val.__type].prototype);
}
return val;
};
};

@@ -8,110 +8,112 @@ /**

var MemoryCache = module.exports = function(options) {
options = options || {};
this.limit = options['cache limit'] || 256;
this._cache = {};
this.length = 0;
this.head = this.tail = null;
};
module.exports = class MemoryCache {
constructor(options) {
options = options || {};
this.limit = options['cache limit'] || 256;
this._cache = {};
this.length = 0;
this.head = this.tail = null;
}
/**
* Set cache item with given `key` to `value`.
*
* @param {String} key
* @param {Object} value
* @api private
*/
/**
* Set cache item with given `key` to `value`.
*
* @param {String} key
* @param {Object} value
* @api private
*/
MemoryCache.prototype.set = function(key, value) {
var clone = value.clone()
, item;
set(key, value) {
var clone = value.clone()
, item;
clone.filename = nodes.filename;
clone.lineno = nodes.lineno;
clone.column = nodes.column;
item = { key: key, value: clone };
this._cache[key] = item;
clone.filename = nodes.filename;
clone.lineno = nodes.lineno;
clone.column = nodes.column;
item = { key: key, value: clone };
this._cache[key] = item;
if (this.tail) {
this.tail.next = item;
item.prev = this.tail;
} else {
this.head = item;
}
if (this.tail) {
this.tail.next = item;
item.prev = this.tail;
} else {
this.head = item;
}
this.tail = item;
if (this.length++ == this.limit) this.purge();
};
this.tail = item;
if (this.length++ == this.limit) this.purge();
};
/**
* Get cache item with given `key`.
*
* @param {String} key
* @return {Object}
* @api private
*/
/**
* Get cache item with given `key`.
*
* @param {String} key
* @return {Object}
* @api private
*/
MemoryCache.prototype.get = function(key) {
var item = this._cache[key]
, val = item.value.clone();
get(key) {
var item = this._cache[key]
, val = item.value.clone();
if (item == this.tail) return val;
if (item.next) {
if (item == this.head) this.head = item.next;
item.next.prev = item.prev;
}
if (item.prev) item.prev.next = item.next;
if (item == this.tail) return val;
if (item.next) {
if (item == this.head) this.head = item.next;
item.next.prev = item.prev;
}
if (item.prev) item.prev.next = item.next;
item.next = null;
item.prev = this.tail;
item.next = null;
item.prev = this.tail;
if (this.tail) this.tail.next = item;
this.tail = item;
if (this.tail) this.tail.next = item;
this.tail = item;
return val;
};
return val;
};
/**
* Check if cache has given `key`.
*
* @param {String} key
* @return {Boolean}
* @api private
*/
/**
* Check if cache has given `key`.
*
* @param {String} key
* @return {Boolean}
* @api private
*/
MemoryCache.prototype.has = function(key) {
return !!this._cache[key];
};
has(key) {
return !!this._cache[key];
};
/**
* Generate key for the source `str` with `options`.
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api private
*/
/**
* Generate key for the source `str` with `options`.
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api private
*/
MemoryCache.prototype.key = function(str, options) {
var hash = crypto.createHash('sha1');
hash.update(str + options.prefix);
return hash.digest('hex');
};
key(str, options) {
var hash = crypto.createHash('sha1');
hash.update(str + options.prefix);
return hash.digest('hex');
};
/**
* Remove the oldest item from the cache.
*
* @api private
*/
/**
* Remove the oldest item from the cache.
*
* @api private
*/
MemoryCache.prototype.purge = function() {
var item = this.head;
purge() {
var item = this.head;
if (this.head.next) {
this.head = this.head.next;
this.head.prev = null;
}
if (this.head.next) {
this.head = this.head.next;
this.head.prev = null;
}
this._cache[item.key] = item.prev = item.next = null;
this.length--;
this._cache[item.key] = item.prev = item.next = null;
this.length--;
};
};

@@ -5,47 +5,48 @@ /**

var NullCache = module.exports = function() {};
module.exports = class NullCache {
/**
* Set cache item with given `key` to `value`.
*
* @param {String} key
* @param {Object} value
* @api private
*/
/**
* Set cache item with given `key` to `value`.
*
* @param {String} key
* @param {Object} value
* @api private
*/
NullCache.prototype.set = function(key, value) {};
set(key, value) { };
/**
* Get cache item with given `key`.
*
* @param {String} key
* @return {Object}
* @api private
*/
/**
* Get cache item with given `key`.
*
* @param {String} key
* @return {Object}
* @api private
*/
NullCache.prototype.get = function(key) {};
get(key) { };
/**
* Check if cache has given `key`.
*
* @param {String} key
* @return {Boolean}
* @api private
*/
/**
* Check if cache has given `key`.
*
* @param {String} key
* @return {Boolean}
* @api private
*/
NullCache.prototype.has = function(key) {
return false;
};
has(key) {
return false;
};
/**
* Generate key for the source `str` with `options`.
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api private
*/
/**
* Generate key for the source `str` with `options`.
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api private
*/
NullCache.prototype.key = function(str, options) {
return '';
};
key(str, options) {
return '';
};
}

@@ -15,3 +15,3 @@ /*!

module.exports = function(css){
module.exports = function (css) {
return new Converter(css).stylus();

@@ -27,304 +27,307 @@ };

function Converter(css) {
var { parse } = require('@adobe/css-tools');
this.css = css;
this.root = parse(css, { position: false });
this.indents = 0;
}
class Converter {
constructor(css) {
var { parse } = require('@adobe/css-tools');
this.css = css;
this.root = parse(css, { position: false });
this.indents = 0;
}
/**
* Convert to Stylus.
*
* @return {String}
* @api private
*/
Converter.prototype.stylus = function(){
return this.visitRules(this.root.stylesheet.rules);
};
/**
* Convert to Stylus.
*
* @return {String}
* @api private
*/
/**
* Return indent string.
*
* @return {String}
* @api private
*/
stylus() {
return this.visitRules(this.root.stylesheet.rules);
};
Converter.prototype.__defineGetter__('indent', function(){
return Array(this.indents + 1).join(' ');
});
/**
* Return indent string.
*
* @return {String}
* @api private
*/
/**
* Visit `node`.
*
* @param {*} node
* @return {String}
* @api private
*/
get indent() {
return Array(this.indents + 1).join(' ');
};
Converter.prototype.visit = function(node){
switch (node.type) {
case 'rule':
case 'comment':
case 'charset':
case 'namespace':
case 'media':
case 'import':
case 'document':
case 'keyframes':
case 'page':
case 'host':
case 'supports':
var name = node.type[0].toUpperCase() + node.type.slice(1);
return this['visit' + name](node);
case 'font-face':
return this.visitFontFace(node);
}
};
/**
* Visit `node`.
*
* @param {*} node
* @return {String}
* @api private
*/
/**
* Visit the rules on `node`.
*
* @param {Array} node
* @return {String}
* @api private
*/
visit(node) {
switch (node.type) {
case 'rule':
case 'comment':
case 'charset':
case 'namespace':
case 'media':
case 'import':
case 'document':
case 'keyframes':
case 'page':
case 'host':
case 'supports':
var name = node.type[0].toUpperCase() + node.type.slice(1);
return this['visit' + name](node);
case 'font-face':
return this.visitFontFace(node);
}
};
Converter.prototype.visitRules = function(node){
var buf = '';
for (var i = 0, len = node.length; i < len; ++i) {
buf += this.visit(node[i]);
}
return buf;
};
/**
* Visit the rules on `node`.
*
* @param {Array} node
* @return {String}
* @api private
*/
/**
* Visit FontFace `node`.
*
* @param {FontFace} node
* @return {String}
* @api private
*/
visitRules(node) {
var buf = '';
for (var i = 0, len = node.length; i < len; ++i) {
buf += this.visit(node[i]);
}
return buf;
};
Converter.prototype.visitFontFace = function(node){
var buf = this.indent + '@font-face';
buf += '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf;
};
/**
* Visit FontFace `node`.
*
* @param {FontFace} node
* @return {String}
* @api private
*/
/**
* Visit Media `node`.
*
* @param {Media} node
* @return {String}
* @api private
*/
visitFontFace(node) {
var buf = this.indent + '@font-face';
buf += '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf;
};
Converter.prototype.visitMedia = function(node){
var buf = this.indent + '@media ' + node.media;
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
/**
* Visit Media `node`.
*
* @param {Media} node
* @return {String}
* @api private
*/
/**
* Visit Declaration `node`.
*
* @param {Declaration} node
* @return {String}
* @api private
*/
Converter.prototype.visitDeclaration = function(node){
if ('comment' == node.type) {
return this.visitComment(node);
} else {
var buf = this.indent + node.property + ': ' + node.value + '\n';
visitMedia(node) {
var buf = this.indent + '@media ' + node.media;
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
}
};
};
/**
* Visit Rule `node`.`
*
* @param {Rule} node
* @return {String}
* @api private
*/
/**
* Visit Declaration `node`.
*
* @param {Declaration} node
* @return {String}
* @api private
*/
Converter.prototype.visitRule = function(node){
var buf = this.indent + node.selectors.join(',\n' + this.indent) + '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf + '\n';
};
visitDeclaration(node) {
if ('comment' == node.type) {
return this.visitComment(node);
} else {
var buf = this.indent + node.property + ': ' + node.value + '\n';
return buf;
}
};
/**
* Visit Comment `node`.`
*
* @param {Comment} node
* @return {String}
* @api private
*/
/**
* Visit Rule `node`.`
*
* @param {Rule} node
* @return {String}
* @api private
*/
Converter.prototype.visitComment = function(node){
var buf = this.indent + '/*' + node.comment + '*/';
return buf + '\n';
};
visitRule(node) {
var buf = this.indent + node.selectors.join(',\n' + this.indent) + '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf + '\n';
};
/**
* Visit Charset `node`.`
*
* @param {Charset} node
* @return {String}
* @api private
*/
/**
* Visit Comment `node`.`
*
* @param {Comment} node
* @return {String}
* @api private
*/
Converter.prototype.visitCharset = function(node){
var buf = this.indent + '@charset ' + node.charset;
return buf + '\n';
};
visitComment(node) {
var buf = this.indent + '/*' + node.comment + '*/';
return buf + '\n';
};
/**
* Visit Namespace `node`.`
*
* @param {Namespace} node
* @return {String}
* @api private
*/
/**
* Visit Charset `node`.`
*
* @param {Charset} node
* @return {String}
* @api private
*/
Converter.prototype.visitNamespace = function(node){
var buf = this.indent + '@namespace ' + node.namespace;
return buf + '\n';
};
visitCharset(node) {
var buf = this.indent + '@charset ' + node.charset;
return buf + '\n';
};
/**
* Visit Import `node`.`
*
* @param {Import} node
* @return {String}
* @api private
*/
/**
* Visit Namespace `node`.`
*
* @param {Namespace} node
* @return {String}
* @api private
*/
Converter.prototype.visitImport = function(node){
var buf = this.indent + '@import ' + node.import;
return buf + '\n';
};
visitNamespace(node) {
var buf = this.indent + '@namespace ' + node.namespace;
return buf + '\n';
};
/**
* Visit Document `node`.`
*
* @param {Document} node
* @return {String}
* @api private
*/
/**
* Visit Import `node`.`
*
* @param {Import} node
* @return {String}
* @api private
*/
Converter.prototype.visitDocument = function(node){
var buf = this.indent + '@' + node.vendor + 'document ' + node.document;
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
visitImport(node) {
var buf = this.indent + '@import ' + node.import;
return buf + '\n';
};
/**
* Visit Keyframes `node`.`
*
* @param {Keyframes} node
* @return {String}
* @api private
*/
/**
* Visit Document `node`.`
*
* @param {Document} node
* @return {String}
* @api private
*/
Converter.prototype.visitKeyframes = function(node){
var buf = this.indent + '@keyframes ' + node.name;
buf += '\n';
++this.indents;
for (var i = 0, len = node.keyframes.length; i < len; ++i) {
buf += this.visitKeyframe(node.keyframes[i]);
}
--this.indents;
return buf;
};
visitDocument(node) {
var buf = this.indent + '@' + node.vendor + 'document ' + node.document;
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
/**
* Visit Keyframe `node`.`
*
* @param {Keyframe} node
* @return {String}
* @api private
*/
/**
* Visit Keyframes `node`.`
*
* @param {Keyframes} node
* @return {String}
* @api private
*/
Converter.prototype.visitKeyframe = function(node){
var buf = this.indent + node.values.join(', ');
buf += '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf;
};
visitKeyframes(node) {
var buf = this.indent + '@keyframes ' + node.name;
buf += '\n';
++this.indents;
for (var i = 0, len = node.keyframes.length; i < len; ++i) {
buf += this.visitKeyframe(node.keyframes[i]);
}
--this.indents;
return buf;
};
/**
* Visit Page `node`.`
*
* @param {Page} node
* @return {String}
* @api private
*/
/**
* Visit Keyframe `node`.`
*
* @param {Keyframe} node
* @return {String}
* @api private
*/
Converter.prototype.visitPage = function(node){
var buf = this.indent + '@page' + (node.selectors.length ? ' ' + node.selectors.join(', ') : '');
buf += '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf;
};
visitKeyframe(node) {
var buf = this.indent + node.values.join(', ');
buf += '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf;
};
/**
* Visit Supports `node`.`
*
* @param {Supports} node
* @return {String}
* @api private
*/
/**
* Visit Page `node`.`
*
* @param {Page} node
* @return {String}
* @api private
*/
Converter.prototype.visitSupports = function(node){
var buf = this.indent + '@supports ' + node.supports;
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
visitPage(node) {
var buf = this.indent + '@page' + (node.selectors.length ? ' ' + node.selectors.join(', ') : '');
buf += '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf;
};
/**
* Visit Host `node`.`
*
* @param {Host} node
* @return {String}
* @api private
*/
/**
* Visit Supports `node`.`
*
* @param {Supports} node
* @return {String}
* @api private
*/
Converter.prototype.visitHost = function(node){
var buf = this.indent + '@host';
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
visitSupports(node) {
var buf = this.indent + '@supports ' + node.supports;
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
/**
* Visit Host `node`.`
*
* @param {Host} node
* @return {String}
* @api private
*/
visitHost(node) {
var buf = this.indent + '@host';
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
}

@@ -9,9 +9,2 @@

/**
* Expose constructors.
*/
exports.ParseError = ParseError;
exports.SyntaxError = SyntaxError;
/**
* Initialize a new `ParseError` with the given `msg`.

@@ -23,7 +16,10 @@ *

function ParseError(msg) {
this.name = 'ParseError';
this.message = msg;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ParseError);
class ParseError extends Error {
constructor(msg) {
super();
this.name = 'ParseError';
this.message = msg;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ParseError);
}
}

@@ -33,8 +29,2 @@ }

/**
* Inherit from `Error.prototype`.
*/
ParseError.prototype.__proto__ = Error.prototype;
/**
* Initialize a new `SyntaxError` with the given `msg`.

@@ -46,7 +36,10 @@ *

function SyntaxError(msg) {
this.name = 'SyntaxError';
this.message = msg;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ParseError);
class SyntaxError extends Error {
constructor(msg) {
super();
this.name = 'SyntaxError';
this.message = msg;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ParseError);
}
}

@@ -56,5 +49,6 @@ }

/**
* Inherit from `Error.prototype`.
* Expose constructors.
*/
SyntaxError.prototype.__proto__ = Error.prototype;
exports.ParseError = ParseError;
exports.SyntaxError = SyntaxError;

@@ -19,145 +19,148 @@

/**
* Initialize a new `Image` with the given `ctx` and `path.
*
* @param {Evaluator} ctx
* @param {String} path
* @api private
*/
module.exports = class Image {
/**
* Initialize a new `Image` with the given `ctx` and `path.
*
* @param {Evaluator} ctx
* @param {String} path
* @api private
*/
var Image = module.exports = function Image(ctx, path) {
this.ctx = ctx;
this.path = utils.lookup(path, ctx.paths);
if (!this.path) throw new Error('failed to locate file ' + path);
};
constructor(ctx, path) {
this.ctx = ctx;
this.path = utils.lookup(path, ctx.paths);
if (!this.path) throw new Error('failed to locate file ' + path);
}
/**
* Open the image for reading.
*
* @api private
*/
Image.prototype.open = function(){
this.fd = fs.openSync(this.path, 'r');
this.length = fs.fstatSync(this.fd).size;
this.extname = path.extname(this.path).slice(1);
};
/**
* Open the image for reading.
*
* @api private
*/
/**
* Close the file.
*
* @api private
*/
open() {
this.fd = fs.openSync(this.path, 'r');
this.length = fs.fstatSync(this.fd).size;
this.extname = path.extname(this.path).slice(1);
};
Image.prototype.close = function(){
if (this.fd) fs.closeSync(this.fd);
};
/**
* Close the file.
*
* @api private
*/
/**
* Return the type of image, supports:
*
* - gif
* - png
* - jpeg
* - svg
*
* @return {String}
* @api private
*/
close() {
if (this.fd) fs.closeSync(this.fd);
};
Image.prototype.type = function(){
var type
, buf = Buffer.alloc(4);
fs.readSync(this.fd, buf, 0, 4, 0);
/**
* Return the type of image, supports:
*
* - gif
* - png
* - jpeg
* - svg
*
* @return {String}
* @api private
*/
// GIF
if (0x47 == buf[0] && 0x49 == buf[1] && 0x46 == buf[2]) type = 'gif';
type() {
var type
, buf = Buffer.alloc(4);
// PNG
else if (0x50 == buf[1] && 0x4E == buf[2] && 0x47 == buf[3]) type = 'png';
fs.readSync(this.fd, buf, 0, 4, 0);
// JPEG
else if (0xff == buf[0] && 0xd8 == buf[1]) type = 'jpeg';
// GIF
if (0x47 == buf[0] && 0x49 == buf[1] && 0x46 == buf[2]) type = 'gif';
// SVG
else if ('svg' == this.extname) type = this.extname;
// PNG
else if (0x50 == buf[1] && 0x4E == buf[2] && 0x47 == buf[3]) type = 'png';
return type;
};
// JPEG
else if (0xff == buf[0] && 0xd8 == buf[1]) type = 'jpeg';
/**
* Return image dimensions `[width, height]`.
*
* @return {Array}
* @api private
*/
// SVG
else if ('svg' == this.extname) type = this.extname;
Image.prototype.size = function(){
var type = this.type()
, width
, height
, buf
, offset
, blockSize
, parser;
return type;
};
function uint16(b) { return b[1] << 8 | b[0]; }
function uint32(b) { return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; }
/**
* Return image dimensions `[width, height]`.
*
* @return {Array}
* @api private
*/
// Determine dimensions
switch (type) {
case 'jpeg':
buf = Buffer.alloc(this.length);
fs.readSync(this.fd, buf, 0, this.length, 0);
offset = 4;
blockSize = buf[offset] << 8 | buf[offset + 1];
size() {
var type = this.type()
, width
, height
, buf
, offset
, blockSize
, parser;
while (offset < this.length) {
offset += blockSize;
if (offset >= this.length || 0xff != buf[offset]) break;
// SOF0 or SOF2 (progressive)
if (0xc0 == buf[offset + 1] || 0xc2 == buf[offset + 1]) {
height = buf[offset + 5] << 8 | buf[offset + 6];
width = buf[offset + 7] << 8 | buf[offset + 8];
} else {
offset += 2;
blockSize = buf[offset] << 8 | buf[offset + 1];
function uint16(b) { return b[1] << 8 | b[0]; }
function uint32(b) { return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; }
// Determine dimensions
switch (type) {
case 'jpeg':
buf = Buffer.alloc(this.length);
fs.readSync(this.fd, buf, 0, this.length, 0);
offset = 4;
blockSize = buf[offset] << 8 | buf[offset + 1];
while (offset < this.length) {
offset += blockSize;
if (offset >= this.length || 0xff != buf[offset]) break;
// SOF0 or SOF2 (progressive)
if (0xc0 == buf[offset + 1] || 0xc2 == buf[offset + 1]) {
height = buf[offset + 5] << 8 | buf[offset + 6];
width = buf[offset + 7] << 8 | buf[offset + 8];
} else {
offset += 2;
blockSize = buf[offset] << 8 | buf[offset + 1];
}
}
}
break;
case 'png':
buf = Buffer.alloc(8);
// IHDR chunk width / height uint32_t big-endian
fs.readSync(this.fd, buf, 0, 8, 16);
width = uint32(buf);
height = uint32(buf.slice(4, 8));
break;
case 'gif':
buf = Buffer.alloc(4);
// width / height uint16_t little-endian
fs.readSync(this.fd, buf, 0, 4, 6);
width = uint16(buf);
height = uint16(buf.slice(2, 4));
break;
case 'svg':
offset = Math.min(this.length, 1024);
buf = Buffer.alloc(offset);
fs.readSync(this.fd, buf, 0, offset, 0);
buf = buf.toString('utf8');
parser = sax.parser(true);
parser.onopentag = function(node) {
if ('svg' == node.name && node.attributes.width && node.attributes.height) {
width = parseInt(node.attributes.width, 10);
height = parseInt(node.attributes.height, 10);
}
};
parser.write(buf).close();
break;
}
break;
case 'png':
buf = Buffer.alloc(8);
// IHDR chunk width / height uint32_t big-endian
fs.readSync(this.fd, buf, 0, 8, 16);
width = uint32(buf);
height = uint32(buf.slice(4, 8));
break;
case 'gif':
buf = Buffer.alloc(4);
// width / height uint16_t little-endian
fs.readSync(this.fd, buf, 0, 4, 6);
width = uint16(buf);
height = uint16(buf.slice(2, 4));
break;
case 'svg':
offset = Math.min(this.length, 1024);
buf = Buffer.alloc(offset);
fs.readSync(this.fd, buf, 0, offset, 0);
buf = buf.toString('utf8');
parser = sax.parser(true);
parser.onopentag = function (node) {
if ('svg' == node.name && node.attributes.width && node.attributes.height) {
width = parseInt(node.attributes.width, 10);
height = parseInt(node.attributes.height, 10);
}
};
parser.write(buf).close();
break;
}
if ('number' != typeof width) throw new Error('failed to find width of "' + this.path + '"');
if ('number' != typeof height) throw new Error('failed to find height of "' + this.path + '"');
if ('number' != typeof width) throw new Error('failed to find width of "' + this.path + '"');
if ('number' != typeof height) throw new Error('failed to find height of "' + this.path + '"');
return [width, height];
return [width, height];
};
};

@@ -17,8 +17,2 @@

/**
* Expose `Lexer`.
*/
exports = module.exports = Lexer;
/**
* Operator aliases.

@@ -28,3 +22,3 @@ */

var alias = {
'and': '&&'
'and': '&&'
, 'or': '||'

@@ -37,66 +31,61 @@ , 'is': '=='

/**
* Initialize a new `Lexer` with the given `str` and `options`.
*
* @param {String} str
* @param {Object} options
* @api private
*/
exports = module.exports = class Lexer {
/**
* Initialize a new `Lexer` with the given `str` and `options`.
*
* @param {String} str
* @param {Object} options
* @api private
*/
function Lexer(str, options) {
options = options || {};
this.stash = [];
this.indentStack = [];
this.indentRe = null;
this.lineno = 1;
this.column = 1;
constructor(str, options) {
options = options || {};
this.stash = [];
this.indentStack = [];
this.indentRe = null;
this.lineno = 1;
this.column = 1;
// HACK!
function comment(str, val, offset, s) {
var inComment = s.lastIndexOf('/*', offset) > s.lastIndexOf('*/', offset)
, commentIdx = s.lastIndexOf('//', offset)
, i = s.lastIndexOf('\n', offset)
, double = 0
, single = 0;
// HACK!
function comment(str, val, offset, s) {
var inComment = s.lastIndexOf('/*', offset) > s.lastIndexOf('*/', offset)
, commentIdx = s.lastIndexOf('//', offset)
, i = s.lastIndexOf('\n', offset)
, double = 0
, single = 0;
if (~commentIdx && commentIdx > i) {
while (i != offset) {
if ("'" == s[i]) single ? single-- : single++;
if ('"' == s[i]) double ? double-- : double++;
if (~commentIdx && commentIdx > i) {
while (i != offset) {
if ("'" == s[i]) single ? single-- : single++;
if ('"' == s[i]) double ? double-- : double++;
if ('/' == s[i] && '/' == s[i + 1]) {
inComment = !single && !double;
break;
if ('/' == s[i] && '/' == s[i + 1]) {
inComment = !single && !double;
break;
}
++i;
}
++i;
}
}
return inComment
? str
: ((val === ',' && /^[,\t\n]+$/.test(str)) ? str.replace(/\n/, '\r') : val + '\r');
};
return inComment
? str
: ((val === ',' && /^[,\t\n]+$/.test(str)) ? str.replace(/\n/, '\r') : val + '\r');
};
// Remove UTF-8 BOM.
if ('\uFEFF' == str.charAt(0)) str = str.slice(1);
// Remove UTF-8 BOM.
if ('\uFEFF' == str.charAt(0)) str = str.slice(1);
this.str = str
.replace(/\s+$/, '\n')
.replace(/\r\n?/g, '\n')
.replace(/\\ *\n/g, '\r')
.replace(/([,(:](?!\/\/[^ ])) *(?:\/\/[^\n]*|\/\*.*?\*\/)?\n\s*/g, comment)
.replace(/\s*\n[ \t]*([,)])/g, comment);
};
this.str = str
.replace(/\s+$/, '\n')
.replace(/\r\n?/g, '\n')
.replace(/\\ *\n/g, '\r')
.replace(/([,(:](?!\/\/[^ ])) *(?:\/\/[^\n]*|\/\*.*?\*\/)?\n\s*/g, comment)
.replace(/\s*\n[ \t]*([,)])/g, comment);
};
/**
* Lexer prototype.
*/
Lexer.prototype = {
/**
* Custom inspect.
*/
* Custom inspect.
*/
inspect: function(){
inspect() {
var tok

@@ -110,3 +99,3 @@ , tmp = this.str

return buf.concat(tok.inspect()).join('\n');
},
}

@@ -121,7 +110,7 @@ /**

lookahead: function(n){
lookahead(n) {
var fetch = n - this.stash.length;
while (fetch-- > 0) this.stash.push(this.advance());
return this.stash[--n];
},
}

@@ -135,3 +124,3 @@ /**

skip: function(len){
skip(len) {
var chunk = len[0];

@@ -145,3 +134,3 @@ len = chunk ? chunk.length : len;

}
},
}

@@ -155,3 +144,3 @@ /**

move: function(str){
move(str) {
var lines = str.match(/\n/g)

@@ -164,3 +153,3 @@ , idx = str.lastIndexOf('\n');

: this.column + str.length;
},
}

@@ -174,7 +163,7 @@ /**

next: function() {
next() {
var tok = this.stashed() || this.advance();
this.prev = tok;
return tok;
},
}

@@ -188,3 +177,3 @@ /**

isPartOfSelector: function() {
isPartOfSelector() {
var tok = this.stash[this.stash.length - 1] || this.prev;

@@ -202,3 +191,3 @@ switch (tok && tok.type) {

return false;
},
}

@@ -212,40 +201,40 @@ /**

advance: function() {
advance() {
var column = this.column
, line = this.lineno
, tok = this.eos()
|| this.null()
|| this.sep()
|| this.keyword()
|| this.urlchars()
|| this.comment()
|| this.newline()
|| this.escaped()
|| this.important()
|| this.literal()
|| this.anonFunc()
|| this.atrule()
|| this.function()
|| this.brace()
|| this.paren()
|| this.color()
|| this.string()
|| this.unit()
|| this.namedop()
|| this.boolean()
|| this.unicode()
|| this.ident()
|| this.op()
|| (function () {
var token = this.eol();
|| this.null()
|| this.sep()
|| this.keyword()
|| this.urlchars()
|| this.comment()
|| this.newline()
|| this.escaped()
|| this.important()
|| this.literal()
|| this.anonFunc()
|| this.atrule()
|| this.function()
|| this.brace()
|| this.paren()
|| this.color()
|| this.string()
|| this.unit()
|| this.namedop()
|| this.boolean()
|| this.unicode()
|| this.ident()
|| this.op()
|| (function () {
var token = this.eol();
if (token) {
column = token.column;
line = token.lineno;
}
if (token) {
column = token.column;
line = token.lineno;
}
return token;
}).call(this)
|| this.space()
|| this.selector();
return token;
}).call(this)
|| this.space()
|| this.selector();

@@ -256,3 +245,3 @@ tok.lineno = line;

return tok;
},
}

@@ -266,5 +255,5 @@ /**

peek: function() {
peek() {
return this.lookahead(1);
},
}

@@ -278,5 +267,5 @@ /**

stashed: function() {
stashed() {
return this.stash.shift();
},
}

@@ -287,3 +276,3 @@ /**

eos: function() {
eos() {
if (this.str.length) return;

@@ -296,3 +285,3 @@ if (this.indentStack.length) {

}
},
}

@@ -303,3 +292,3 @@ /**

urlchars: function() {
urlchars() {
var captures;

@@ -311,3 +300,3 @@ if (!this.isURL) return;

}
},
}

@@ -318,3 +307,3 @@ /**

sep: function() {
sep() {
var captures;

@@ -325,3 +314,3 @@ if (captures = /^;[ \t]*/.exec(this.str)) {

}
},
}

@@ -332,3 +321,3 @@ /**

eol: function() {
eol() {
if ('\r' == this.str[0]) {

@@ -339,7 +328,7 @@ ++this.lineno;

this.column = 1;
while(this.space());
while (this.space());
return this.advance();
}
},
}

@@ -350,3 +339,3 @@ /**

space: function() {
space() {
var captures;

@@ -357,3 +346,3 @@ if (captures = /^([ \t]+)/.exec(this.str)) {

}
},
}

@@ -364,3 +353,3 @@ /**

escaped: function() {
escaped() {
var captures;

@@ -372,3 +361,3 @@ if (captures = /^\\(.)[ \t]*/.exec(this.str)) {

}
},
}

@@ -379,3 +368,3 @@ /**

literal: function() {
literal() {
// HACK attack !!!

@@ -407,3 +396,3 @@ var captures;

}
},
}

@@ -414,3 +403,3 @@ /**

important: function() {
important() {
var captures;

@@ -421,3 +410,3 @@ if (captures = /^!important[ \t]*/.exec(this.str)) {

}
},
}

@@ -428,3 +417,3 @@ /**

brace: function() {
brace() {
var captures;

@@ -436,3 +425,3 @@ if (captures = /^([{}])/.exec(this.str)) {

}
},
}

@@ -443,3 +432,3 @@ /**

paren: function() {
paren() {
var captures;

@@ -454,3 +443,3 @@ if (captures = /^([()])([ \t]*)/.exec(this.str)) {

}
},
}

@@ -461,3 +450,3 @@ /**

null: function() {
null() {
var captures

@@ -474,3 +463,3 @@ , tok;

}
},
}

@@ -486,3 +475,3 @@ /**

keyword: function() {
keyword() {
var captures

@@ -500,3 +489,3 @@ , tok;

}
},
}

@@ -514,3 +503,3 @@ /**

namedop: function() {
namedop() {
var captures

@@ -530,3 +519,3 @@ , tok;

}
},
}

@@ -570,3 +559,3 @@ /**

op: function() {
op() {
var captures;

@@ -582,3 +571,3 @@ if (captures = /^([.]{1,3}|&&|\|\||[!<>=?:]=|\*\*|[-+*\/%]=?|[,=?:!~<>&\[\]])([ \t]*)/.exec(this.str)) {

}
},
}

@@ -589,3 +578,3 @@ /**

anonFunc: function() {
anonFunc() {
var tok;

@@ -598,3 +587,3 @@ if ('@' == this.str[0] && '(' == this.str[1]) {

}
},
}

@@ -605,3 +594,3 @@ /**

atrule: function() {
atrule() {
var captures;

@@ -635,3 +624,3 @@ if (captures = /^@(?!apply)(?:-(\w+)-)?([a-zA-Z0-9-_]+)[ \t]*/.exec(this.str)) {

}
},
}

@@ -642,3 +631,3 @@ /**

comment: function() {
comment() {
// Single line

@@ -670,3 +659,3 @@ if ('/' == this.str[0] && '/' == this.str[1]) {

}
},
}

@@ -677,6 +666,6 @@ /**

boolean: function() {
boolean() {
var captures;
if (captures = /^(true|false)\b([ \t]*)/.exec(this.str)) {
var val = nodes.Boolean('true' == captures[1]);
var val = new nodes.Boolean('true' == captures[1]);
this.skip(captures);

@@ -687,3 +676,3 @@ var tok = new Token('boolean', val);

}
},
}

@@ -694,3 +683,3 @@ /**

unicode: function() {
unicode() {
var captures;

@@ -701,3 +690,3 @@ if (captures = /^u\+[0-9a-f?]{1,6}(?:-[0-9a-f]{1,6})?/i.exec(this.str)) {

}
},
}

@@ -708,3 +697,3 @@ /**

function: function() {
function() {
var captures;

@@ -719,3 +708,3 @@ if (captures = /^(-*[_a-zA-Z$][-\w\d$]*)\(([ \t]*)/.exec(this.str)) {

}
},
}

@@ -726,3 +715,3 @@ /**

ident: function() {
ident() {
var captures;

@@ -733,3 +722,3 @@ if (captures = /^-*([_a-zA-Z$]|@apply)[-\w\d$]*/.exec(this.str)) {

}
},
}

@@ -740,9 +729,9 @@ /**

newline: function() {
newline() {
var captures, re;
// we have established the indentation regexp
if (this.indentRe){
if (this.indentRe) {
captures = this.indentRe.exec(this.str);
// figure out if we are using tabs or spaces
// figure out if we are using tabs or spaces
} else {

@@ -783,7 +772,7 @@ // try tabs

tok = this.stash.pop();
// Indent
// Indent
} else if (indents && indents != this.indentStack[0]) {
this.indentStack.unshift(indents);
tok = new Token('indent');
// Newline
// Newline
} else {

@@ -795,3 +784,3 @@ tok = new Token('newline');

}
},
}

@@ -802,3 +791,3 @@ /**

unit: function() {
unit() {
var captures;

@@ -813,3 +802,3 @@ if (captures = /^(-)?(\d+\.\d+|\d+|\.\d+)(%|[a-zA-Z]+)?[ \t]*/.exec(this.str)) {

}
},
}

@@ -820,3 +809,3 @@ /**

string: function() {
string() {
var captures;

@@ -827,6 +816,6 @@ if (captures = /^("[^"]*"|'[^']*')[ \t]*/.exec(this.str)) {

this.skip(captures);
str = str.slice(1,-1).replace(/\\n/g, '\n');
str = str.slice(1, -1).replace(/\\n/g, '\n');
return new Token('string', new nodes.String(str, quote));
}
},
}

@@ -837,3 +826,3 @@ /**

color: function() {
color() {
return this.rrggbbaa()

@@ -845,3 +834,3 @@ || this.rrggbb()

|| this.n()
},
}

@@ -852,3 +841,3 @@ /**

n: function() {
n() {
var captures;

@@ -862,3 +851,3 @@ if (captures = /^#([a-fA-F0-9]{1})[ \t]*/.exec(this.str)) {

}
},
}

@@ -869,3 +858,3 @@ /**

nn: function() {
nn() {
var captures;

@@ -879,3 +868,3 @@ if (captures = /^#([a-fA-F0-9]{2})[ \t]*/.exec(this.str)) {

}
},
}

@@ -886,3 +875,3 @@ /**

rgb: function() {
rgb() {
var captures;

@@ -899,3 +888,3 @@ if (captures = /^#([a-fA-F0-9]{3})[ \t]*/.exec(this.str)) {

}
},
}

@@ -906,3 +895,3 @@ /**

rgba: function() {
rgba() {
var captures;

@@ -916,7 +905,7 @@ if (captures = /^#([a-fA-F0-9]{4})[ \t]*/.exec(this.str)) {

, a = parseInt(rgb[3] + rgb[3], 16)
, color = new nodes.RGBA(r, g, b, a/255);
, color = new nodes.RGBA(r, g, b, a / 255);
color.raw = captures[0];
return new Token('color', color);
}
},
}

@@ -927,3 +916,3 @@ /**

rrggbb: function() {
rrggbb() {
var captures;

@@ -940,3 +929,3 @@ if (captures = /^#([a-fA-F0-9]{6})[ \t]*/.exec(this.str)) {

}
},
}

@@ -947,3 +936,3 @@ /**

rrggbbaa: function() {
rrggbbaa() {
var captures;

@@ -957,7 +946,7 @@ if (captures = /^#([a-fA-F0-9]{8})[ \t]*/.exec(this.str)) {

, a = parseInt(rgb.substr(6, 2), 16)
, color = new nodes.RGBA(r, g, b, a/255);
, color = new nodes.RGBA(r, g, b, a / 255);
color.raw = captures[0];
return new Token('color', color);
}
},
}

@@ -968,3 +957,3 @@ /**

selector: function() {
selector() {
var captures;

@@ -971,0 +960,0 @@ if (captures = /^\^|.*?(?=\/\/(?![^\[]*\])|[,\n{])/.exec(this.str)) {

@@ -14,78 +14,78 @@

/**
* Initialize a new `Arguments`.
*
* @api public
*/
module.exports = class Arguments extends nodes.Expression {
/**
* Initialize a new `Arguments`.
*
* @api public
*/
var Arguments = module.exports = function Arguments(){
nodes.Expression.call(this);
this.map = {};
};
constructor() {
super();
this.map = {};
}
/**
* Inherit from `nodes.Expression.prototype`.
*/
/**
* Initialize an `Arguments` object with the nodes
* from the given `expr`.
*
* @param {Expression} expr
* @return {Arguments}
* @api public
*/
Arguments.prototype.__proto__ = nodes.Expression.prototype;
static fromExpression(expr) {
var args = new Arguments
, len = expr.nodes.length;
args.lineno = expr.lineno;
args.column = expr.column;
args.isList = expr.isList;
for (var i = 0; i < len; ++i) {
args.push(expr.nodes[i]);
}
return args;
};
/**
* Initialize an `Arguments` object with the nodes
* from the given `expr`.
*
* @param {Expression} expr
* @return {Arguments}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Arguments.fromExpression = function(expr){
var args = new Arguments
, len = expr.nodes.length;
args.lineno = expr.lineno;
args.column = expr.column;
args.isList = expr.isList;
for (var i = 0; i < len; ++i) {
args.push(expr.nodes[i]);
}
return args;
};
clone(parent) {
var clone = super.clone(parent);
clone.map = {};
for (var key in this.map) {
clone.map[key] = this.map[key].clone(parent, clone);
}
clone.isList = this.isList;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Arguments.prototype.clone = function(parent){
var clone = nodes.Expression.prototype.clone.call(this, parent);
clone.map = {};
for (var key in this.map) {
clone.map[key] = this.map[key].clone(parent, clone);
}
clone.isList = this.isList;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
toJSON() {
return {
__type: 'Arguments',
map: this.map,
isList: this.isList,
preserve: this.preserve,
lineno: this.lineno,
column: this.column,
filename: this.filename,
nodes: this.nodes
};
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Arguments.prototype.toJSON = function(){
return {
__type: 'Arguments',
map: this.map,
isList: this.isList,
preserve: this.preserve,
lineno: this.lineno,
column: this.column,
filename: this.filename,
nodes: this.nodes
};
};

@@ -13,68 +13,64 @@ /*!

/**
* Initialize a new `@block` node.
*
* @api public
*/
module.exports = class Atblock extends Node {
/**
* Initialize a new `@block` node.
*
* @api public
*/
var Atblock = module.exports = function Atblock(){
Node.call(this);
};
constructor() {
super();
}
/**
* Return `block` nodes.
*/
/**
* Return `block` nodes.
*/
Atblock.prototype.__defineGetter__('nodes', function(){
return this.block.nodes;
});
get nodes() {
return this.block.nodes;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Atblock.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Atblock;
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return @block.
*
* @return {String}
* @api public
*/
Atblock.prototype.clone = function(parent){
var clone = new Atblock;
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
toString() {
return '@block';
};
/**
* Return @block.
*
* @return {String}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Atblock.prototype.toString = function(){
return '@block';
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Atblock.prototype.toJSON = function(){
return {
__type: 'Atblock',
block: this.block,
lineno: this.lineno,
column: this.column,
fileno: this.fileno
toJSON() {
return {
__type: 'Atblock',
block: this.block,
lineno: this.lineno,
column: this.column,
fileno: this.fileno
};
};
};

@@ -13,103 +13,99 @@ /*!

/**
* Initialize a new at-rule node.
*
* @param {String} type
* @api public
*/
module.exports = class Atrule extends Node {
/**
* Initialize a new at-rule node.
*
* @param {String} type
* @api public
*/
var Atrule = module.exports = function Atrule(type){
Node.call(this);
this.type = type;
};
constructor(type) {
super()
this.type = type;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Check if at-rule's block has only properties.
*
* @return {Boolean}
* @api public
*/
Atrule.prototype.__proto__ = Node.prototype;
get hasOnlyProperties() {
if (!this.block) return false;
/**
* Check if at-rule's block has only properties.
*
* @return {Boolean}
* @api public
*/
Atrule.prototype.__defineGetter__('hasOnlyProperties', function(){
if (!this.block) return false;
var nodes = this.block.nodes;
for (var i = 0, len = nodes.length; i < len; ++i) {
var nodeName = nodes[i].nodeName;
switch(nodes[i].nodeName) {
case 'property':
case 'expression':
case 'comment':
continue;
default:
return false;
var nodes = this.block.nodes;
for (var i = 0, len = nodes.length; i < len; ++i) {
var nodeName = nodes[i].nodeName;
switch (nodes[i].nodeName) {
case 'property':
case 'expression':
case 'comment':
continue;
default:
return false;
}
}
return true;
}
return true;
});
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Atrule.prototype.clone = function(parent){
var clone = new Atrule(this.type);
if (this.block) clone.block = this.block.clone(parent, clone);
clone.segments = this.segments.map(function(node){ return node.clone(parent, clone); });
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
clone(parent) {
var clone = new Atrule(this.type);
if (this.block) clone.block = this.block.clone(parent, clone);
clone.segments = this.segments.map(function (node) { return node.clone(parent, clone); });
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Atrule.prototype.toJSON = function(){
var json = {
__type: 'Atrule',
type: this.type,
segments: this.segments,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
var json = {
__type: 'Atrule',
type: this.type,
segments: this.segments,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.block) json.block = this.block;
return json;
};
if (this.block) json.block = this.block;
return json;
};
/**
* Return @<type>.
*
* @return {String}
* @api public
*/
/**
* Return @<type>.
*
* @return {String}
* @api public
*/
Atrule.prototype.toString = function(){
return '@' + this.type;
};
toString() {
return '@' + this.type;
};
/**
* Check if the at-rule's block has output nodes.
*
* @return {Boolean}
* @api public
*/
/**
* Check if the at-rule's block has output nodes.
*
* @return {Boolean}
* @api public
*/
Atrule.prototype.__defineGetter__('hasOutput', function(){
return !!this.block && hasOutput(this.block);
});
get hasOutput() {
return !!this.block && hasOutput(this.block);
};
};

@@ -120,3 +116,3 @@ function hasOutput(block) {

// only placeholder selectors
if (nodes.every(function(node){
if (nodes.every(function (node) {
return 'group' == node.nodeName && node.hasOnlyPlaceholders;

@@ -126,3 +122,3 @@ })) return false;

// something visible
return nodes.some(function(node) {
return nodes.some(function (node) {
switch (node.nodeName) {

@@ -129,0 +125,0 @@ case 'property':

@@ -14,71 +14,68 @@

/**
* Initialize a new `BinOp` with `op`, `left` and `right`.
*
* @param {String} op
* @param {Node} left
* @param {Node} right
* @api public
*/
module.exports = class BinOp extends Node {
/**
* Initialize a new `BinOp` with `op`, `left` and `right`.
*
* @param {String} op
* @param {Node} left
* @param {Node} right
* @api public
*/
var BinOp = module.exports = function BinOp(op, left, right){
Node.call(this);
this.op = op;
this.left = left;
this.right = right;
};
constructor(op, left, right) {
super();
this.op = op;
this.left = left;
this.right = right;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
BinOp.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new BinOp(this.op);
clone.left = this.left.clone(parent, clone);
clone.right = this.right && this.right.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
if (this.val) clone.val = this.val.clone(parent, clone);
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return <left> <op> <right>
*
* @return {String}
* @api public
*/
toString() {
return this.left.toString() + ' ' + this.op + ' ' + this.right.toString();
};
BinOp.prototype.clone = function(parent){
var clone = new BinOp(this.op);
clone.left = this.left.clone(parent, clone);
clone.right = this.right && this.right.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
if (this.val) clone.val = this.val.clone(parent, clone);
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return <left> <op> <right>
*
* @return {String}
* @api public
*/
BinOp.prototype.toString = function() {
return this.left.toString() + ' ' + this.op + ' ' + this.right.toString();
};
toJSON() {
var json = {
__type: 'BinOp',
left: this.left,
right: this.right,
op: this.op,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.val) json.val = this.val;
return json;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
BinOp.prototype.toJSON = function(){
var json = {
__type: 'BinOp',
left: this.left,
right: this.right,
op: this.op,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.val) json.val = this.val;
return json;
};

@@ -14,115 +14,112 @@

/**
* Initialize a new `Block` node with `parent` Block.
*
* @param {Block} parent
* @api public
*/
module.exports = class Block extends Node {
/**
* Initialize a new `Block` node with `parent` Block.
*
* @param {Block} parent
* @api public
*/
var Block = module.exports = function Block(parent, node){
Node.call(this);
this.nodes = [];
this.parent = parent;
this.node = node;
this.scope = true;
};
constructor(parent, node) {
super();
this.nodes = [];
this.parent = parent;
this.node = node;
this.scope = true;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Check if this block has properties..
*
* @return {Boolean}
* @api public
*/
Block.prototype.__proto__ = Node.prototype;
/**
* Check if this block has properties..
*
* @return {Boolean}
* @api public
*/
Block.prototype.__defineGetter__('hasProperties', function(){
for (var i = 0, len = this.nodes.length; i < len; ++i) {
if ('property' == this.nodes[i].nodeName) {
return true;
get hasProperties() {
for (var i = 0, len = this.nodes.length; i < len; ++i) {
if ('property' == this.nodes[i].nodeName) {
return true;
}
}
}
});
};
/**
* Check if this block has @media nodes.
*
* @return {Boolean}
* @api public
*/
/**
* Check if this block has @media nodes.
*
* @return {Boolean}
* @api public
*/
Block.prototype.__defineGetter__('hasMedia', function(){
for (var i = 0, len = this.nodes.length; i < len; ++i) {
var nodeName = this.nodes[i].nodeName;
if ('media' == nodeName) {
return true;
get hasMedia() {
for (var i = 0, len = this.nodes.length; i < len; ++i) {
var nodeName = this.nodes[i].nodeName;
if ('media' == nodeName) {
return true;
}
}
}
return false;
});
return false;
};
/**
* Check if this block is empty.
*
* @return {Boolean}
* @api public
*/
/**
* Check if this block is empty.
*
* @return {Boolean}
* @api public
*/
Block.prototype.__defineGetter__('isEmpty', function(){
return !this.nodes.length || this.nodes.every(function(n){return n.nodeName == 'comment'});
});
get isEmpty() {
return !this.nodes.length || this.nodes.every(function (n) { return n.nodeName == 'comment' });
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Block.prototype.clone = function(parent, node){
parent = parent || this.parent;
var clone = new Block(parent, node || this.node);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.scope = this.scope;
this.nodes.forEach(function(node){
clone.push(node.clone(clone, clone));
});
return clone;
};
clone(parent, node) {
parent = parent || this.parent;
var clone = new Block(parent, node || this.node);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.scope = this.scope;
this.nodes.forEach(function (node) {
clone.push(node.clone(clone, clone));
});
return clone;
};
/**
* Push a `node` to this block.
*
* @param {Node} node
* @api public
*/
/**
* Push a `node` to this block.
*
* @param {Node} node
* @api public
*/
Block.prototype.push = function(node){
this.nodes.push(node);
};
push(node) {
this.nodes.push(node);
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Block.prototype.toJSON = function(){
return {
__type: 'Block',
// parent: this.parent,
// node: this.node,
scope: this.scope,
lineno: this.lineno,
column: this.column,
filename: this.filename,
nodes: this.nodes
toJSON() {
return {
__type: 'Block',
// parent: this.parent,
// node: this.node,
scope: this.scope,
lineno: this.lineno,
column: this.column,
filename: this.filename,
nodes: this.nodes
};
};
};

@@ -15,104 +15,100 @@

/**
* Initialize a new `Boolean` node with the given `val`.
*
* @param {Boolean} val
* @api public
*/
module.exports = class Boolean extends Node {
/**
* Initialize a new `Boolean` node with the given `val`.
*
* @param {Boolean} val
* @api public
*/
var Boolean = module.exports = function Boolean(val){
Node.call(this);
if (this.nodeName) {
this.val = !!val;
} else {
return new Boolean(val);
constructor(val) {
super();
if (this.nodeName) {
this.val = !!val;
} else {
return new Boolean(val);
}
}
};
/**
* Inherit from `Node.prototype`.
*/
/**
* Return `this` node.
*
* @return {Boolean}
* @api public
*/
Boolean.prototype.__proto__ = Node.prototype;
toBoolean() {
return this;
};
/**
* Return `this` node.
*
* @return {Boolean}
* @api public
*/
/**
* Return `true` if this node represents `true`.
*
* @return {Boolean}
* @api public
*/
Boolean.prototype.toBoolean = function(){
return this;
};
get isTrue() {
return this.val;
};
/**
* Return `true` if this node represents `true`.
*
* @return {Boolean}
* @api public
*/
/**
* Return `true` if this node represents `false`.
*
* @return {Boolean}
* @api public
*/
Boolean.prototype.__defineGetter__('isTrue', function(){
return this.val;
});
get isFalse() {
return !this.val;
};
/**
* Return `true` if this node represents `false`.
*
* @return {Boolean}
* @api public
*/
/**
* Negate the value.
*
* @return {Boolean}
* @api public
*/
Boolean.prototype.__defineGetter__('isFalse', function(){
return ! this.val;
});
negate() {
return new Boolean(!this.val);
};
/**
* Negate the value.
*
* @return {Boolean}
* @api public
*/
/**
* Return 'Boolean'.
*
* @return {String}
* @api public
*/
Boolean.prototype.negate = function(){
return new Boolean(!this.val);
};
inspect() {
return '[Boolean ' + this.val + ']';
};
/**
* Return 'Boolean'.
*
* @return {String}
* @api public
*/
/**
* Return 'true' or 'false'.
*
* @return {String}
* @api public
*/
Boolean.prototype.inspect = function(){
return '[Boolean ' + this.val + ']';
};
toString() {
return this.val
? 'true'
: 'false';
};
/**
* Return 'true' or 'false'.
*
* @return {String}
* @api public
*/
/**
* Return a JSON representaiton of this node.
*
* @return {Object}
* @api public
*/
Boolean.prototype.toString = function(){
return this.val
? 'true'
: 'false';
};
/**
* Return a JSON representaiton of this node.
*
* @return {Object}
* @api public
*/
Boolean.prototype.toJSON = function(){
return {
__type: 'Boolean',
val: this.val
toJSON() {
return {
__type: 'Boolean',
val: this.val
};
};
};

@@ -14,73 +14,69 @@

/**
* Initialize a new `Call` with `name` and `args`.
*
* @param {String} name
* @param {Expression} args
* @api public
*/
module.exports = class Call extends Node {
/**
* Initialize a new `Call` with `name` and `args`.
*
* @param {String} name
* @param {Expression} args
* @api public
*/
var Call = module.exports = function Call(name, args){
Node.call(this);
this.name = name;
this.args = args;
};
constructor(name, args) {
super();
this.name = name;
this.args = args;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Call.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Call(this.name);
clone.args = this.args.clone(parent, clone);
if (this.block) clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return <name>(param1, param2, ...).
*
* @return {String}
* @api public
*/
Call.prototype.clone = function(parent){
var clone = new Call(this.name);
clone.args = this.args.clone(parent, clone);
if (this.block) clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
toString() {
var args = this.args.nodes.map(function (node) {
var str = node.toString();
return str.slice(1, str.length - 1);
}).join(', ');
/**
* Return <name>(param1, param2, ...).
*
* @return {String}
* @api public
*/
return this.name + '(' + args + ')';
};
Call.prototype.toString = function(){
var args = this.args.nodes.map(function(node) {
var str = node.toString();
return str.slice(1, str.length - 1);
}).join(', ');
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
return this.name + '(' + args + ')';
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Call.prototype.toJSON = function(){
var json = {
__type: 'Call',
name: this.name,
args: this.args,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
var json = {
__type: 'Call',
name: this.name,
args: this.args,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.block) json.block = this.block;
return json;
};
if (this.block) json.block = this.block;
return json;
};

@@ -14,46 +14,43 @@

/**
* Initialize a new `Charset` with the given `val`
*
* @param {String} val
* @api public
*/
module.exports = class Charset extends Node {
/**
* Initialize a new `Charset` with the given `val`
*
* @param {String} val
* @api public
*/
var Charset = module.exports = function Charset(val){
Node.call(this);
this.val = val;
};
constructor(val) {
super();
this.val = val;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return @charset "val".
*
* @return {String}
* @api public
*/
Charset.prototype.__proto__ = Node.prototype;
toString() {
return '@charset ' + this.val;
};
/**
* Return @charset "val".
*
* @return {String}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Charset.prototype.toString = function(){
return '@charset ' + this.val;
};
toJSON() {
return {
__type: 'Charset',
val: this.val,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Charset.prototype.toJSON = function(){
return {
__type: 'Charset',
val: this.val,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};

@@ -14,52 +14,49 @@

/**
* Initialize a new `Comment` with the given `str`.
*
* @param {String} str
* @param {Boolean} suppress
* @param {Boolean} inline
* @api public
*/
module.exports = class Comment extends Node {
/**
* Initialize a new `Comment` with the given `str`.
*
* @param {String} str
* @param {Boolean} suppress
* @param {Boolean} inline
* @api public
*/
var Comment = module.exports = function Comment(str, suppress, inline){
Node.call(this);
this.str = str;
this.suppress = suppress;
this.inline = inline;
};
constructor(str, suppress, inline) {
super();
this.str = str;
this.suppress = suppress;
this.inline = inline;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Comment.prototype.__proto__ = Node.prototype;
toJSON() {
return {
__type: 'Comment',
str: this.str,
suppress: this.suppress,
inline: this.inline,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return comment.
*
* @return {String}
* @api public
*/
Comment.prototype.toJSON = function(){
return {
__type: 'Comment',
str: this.str,
suppress: this.suppress,
inline: this.inline,
lineno: this.lineno,
column: this.column,
filename: this.filename
toString() {
return this.str;
};
};
/**
* Return comment.
*
* @return {String}
* @api public
*/
Comment.prototype.toString = function(){
return this.str;
};

@@ -15,62 +15,59 @@

/**
* Initialize a new `Each` node with the given `val` name,
* `key` name, `expr`, and `block`.
*
* @param {String} val
* @param {String} key
* @param {Expression} expr
* @param {Block} block
* @api public
*/
module.exports = class Each extends Node {
/**
* Initialize a new `Each` node with the given `val` name,
* `key` name, `expr`, and `block`.
*
* @param {String} val
* @param {String} key
* @param {Expression} expr
* @param {Block} block
* @api public
*/
var Each = module.exports = function Each(val, key, expr, block){
Node.call(this);
this.val = val;
this.key = key;
this.expr = expr;
this.block = block;
};
constructor(val, key, expr, block) {
super();
this.val = val;
this.key = key;
this.expr = expr;
this.block = block;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Each.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Each(this.val, this.key);
clone.expr = this.expr.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Each.prototype.clone = function(parent){
var clone = new Each(this.val, this.key);
clone.expr = this.expr.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
toJSON() {
return {
__type: 'Each',
val: this.val,
key: this.key,
expr: this.expr,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Each.prototype.toJSON = function(){
return {
__type: 'Each',
val: this.val,
key: this.key,
expr: this.expr,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
}

@@ -16,206 +16,202 @@

/**
* Initialize a new `Expression`.
*
* @param {Boolean} isList
* @api public
*/
module.exports = class Expression extends Node {
/**
* Initialize a new `Expression`.
*
* @param {Boolean} isList
* @api public
*/
var Expression = module.exports = function Expression(isList){
Node.call(this);
this.nodes = [];
this.isList = isList;
};
constructor(isList) {
super();
this.nodes = [];
this.isList = isList;
}
/**
* Check if the variable has a value.
*
* @return {Boolean}
* @api public
*/
/**
* Check if the variable has a value.
*
* @return {Boolean}
* @api public
*/
Expression.prototype.__defineGetter__('isEmpty', function(){
return !this.nodes.length;
});
get isEmpty() {
return !this.nodes.length;
};
/**
* Return the first node in this expression.
*
* @return {Node}
* @api public
*/
/**
* Return the first node in this expression.
*
* @return {Node}
* @api public
*/
Expression.prototype.__defineGetter__('first', function(){
return this.nodes[0]
? this.nodes[0].first
: nodes.null;
});
get first() {
return this.nodes[0]
? this.nodes[0].first
: nodes.null;
};
/**
* Hash all the nodes in order.
*
* @return {String}
* @api public
*/
/**
* Hash all the nodes in order.
*
* @return {String}
* @api public
*/
Expression.prototype.__defineGetter__('hash', function(){
return this.nodes.map(function(node){
return node.hash;
}).join('::');
});
get hash() {
return this.nodes.map(function (node) {
return node.hash;
}).join('::');
};
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Expression.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new this.constructor(this.isList);
clone.preserve = this.preserve;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.nodes = this.nodes.map(function (node) {
return node.clone(parent, clone);
});
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Push the given `node`.
*
* @param {Node} node
* @api public
*/
Expression.prototype.clone = function(parent){
var clone = new this.constructor(this.isList);
clone.preserve = this.preserve;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.nodes = this.nodes.map(function(node) {
return node.clone(parent, clone);
});
return clone;
};
push(node) {
this.nodes.push(node);
};
/**
* Push the given `node`.
*
* @param {Node} node
* @api public
*/
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Expression.prototype.push = function(node){
this.nodes.push(node);
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Expression.prototype.operate = function(op, right, val){
switch (op) {
case '[]=':
var self = this
, range = utils.unwrap(right).nodes
, val = utils.unwrap(val)
, len
, node;
range.forEach(function(unit){
len = self.nodes.length;
if ('unit' == unit.nodeName) {
var i = unit.val < 0 ? len + unit.val : unit.val
, n = i;
while (i-- > len) self.nodes[i] = nodes.null;
self.nodes[n] = val;
} else if (unit.string) {
node = self.nodes[0];
if (node && 'object' == node.nodeName) node.set(unit.string, val.clone());
operate(op, right, val) {
switch (op) {
case '[]=':
var self = this
, range = utils.unwrap(right).nodes
, val = utils.unwrap(val)
, len
, node;
range.forEach(function (unit) {
len = self.nodes.length;
if ('unit' == unit.nodeName) {
var i = unit.val < 0 ? len + unit.val : unit.val
, n = i;
while (i-- > len) self.nodes[i] = nodes.null;
self.nodes[n] = val;
} else if (unit.string) {
node = self.nodes[0];
if (node && 'object' == node.nodeName) node.set(unit.string, val.clone());
}
});
return val;
case '[]':
var expr = new nodes.Expression
, vals = utils.unwrap(this).nodes
, range = utils.unwrap(right).nodes
, node;
range.forEach(function (unit) {
if ('unit' == unit.nodeName) {
node = vals[unit.val < 0 ? vals.length + unit.val : unit.val];
} else if ('object' == vals[0].nodeName) {
node = vals[0].get(unit.string);
}
if (node) expr.push(node);
});
return expr.isEmpty
? nodes.null
: utils.unwrap(expr);
case '||':
return this.toBoolean().isTrue
? this
: right;
case 'in':
return super.operate(op, right);
case '!=':
return this.operate('==', right, val).negate();
case '==':
var len = this.nodes.length
, right = right.toExpression()
, a
, b;
if (len != right.nodes.length) return nodes.false;
for (var i = 0; i < len; ++i) {
a = this.nodes[i];
b = right.nodes[i];
if (a.operate(op, b).isTrue) continue;
return nodes.false;
}
});
return val;
case '[]':
var expr = new nodes.Expression
, vals = utils.unwrap(this).nodes
, range = utils.unwrap(right).nodes
, node;
range.forEach(function(unit){
if ('unit' == unit.nodeName) {
node = vals[unit.val < 0 ? vals.length + unit.val : unit.val];
} else if ('object' == vals[0].nodeName) {
node = vals[0].get(unit.string);
}
if (node) expr.push(node);
});
return expr.isEmpty
? nodes.null
: utils.unwrap(expr);
case '||':
return this.toBoolean().isTrue
? this
: right;
case 'in':
return Node.prototype.operate.call(this, op, right);
case '!=':
return this.operate('==', right, val).negate();
case '==':
var len = this.nodes.length
, right = right.toExpression()
, a
, b;
if (len != right.nodes.length) return nodes.false;
for (var i = 0; i < len; ++i) {
a = this.nodes[i];
b = right.nodes[i];
if (a.operate(op, b).isTrue) continue;
return nodes.false;
}
return nodes.true;
break;
default:
return this.first.operate(op, right, val);
}
};
return nodes.true;
break;
default:
return this.first.operate(op, right, val);
}
};
/**
* Expressions with length > 1 are truthy,
* otherwise the first value's toBoolean()
* method is invoked.
*
* @return {Boolean}
* @api public
*/
/**
* Expressions with length > 1 are truthy,
* otherwise the first value's toBoolean()
* method is invoked.
*
* @return {Boolean}
* @api public
*/
Expression.prototype.toBoolean = function(){
if (this.nodes.length > 1) return nodes.true;
return this.first.toBoolean();
};
toBoolean() {
if (this.nodes.length > 1) return nodes.true;
return this.first.toBoolean();
};
/**
* Return "<a> <b> <c>" or "<a>, <b>, <c>" if
* the expression represents a list.
*
* @return {String}
* @api public
*/
/**
* Return "<a> <b> <c>" or "<a>, <b>, <c>" if
* the expression represents a list.
*
* @return {String}
* @api public
*/
Expression.prototype.toString = function(){
return '(' + this.nodes.map(function(node){
return node.toString();
}).join(this.isList ? ', ' : ' ') + ')';
};
toString() {
return '(' + this.nodes.map(function (node) {
return node.toString();
}).join(this.isList ? ', ' : ' ') + ')';
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Expression.prototype.toJSON = function(){
return {
__type: 'Expression',
isList: this.isList,
preserve: this.preserve,
lineno: this.lineno,
column: this.column,
filename: this.filename,
nodes: this.nodes
toJSON() {
return {
__type: 'Expression',
isList: this.isList,
preserve: this.preserve,
lineno: this.lineno,
column: this.column,
filename: this.filename,
nodes: this.nodes
};
};
};

@@ -14,57 +14,54 @@

/**
* Initialize a new `Extend` with the given `selectors` array.
*
* @param {Array} selectors array of the selectors
* @api public
*/
module.exports = class Extend extends Node {
/**
* Initialize a new `Extend` with the given `selectors` array.
*
* @param {Array} selectors array of the selectors
* @api public
*/
var Extend = module.exports = function Extend(selectors){
Node.call(this);
this.selectors = selectors;
};
constructor(selectors) {
super();
this.selectors = selectors;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Extend.prototype.__proto__ = Node.prototype;
clone() {
return new Extend(this.selectors);
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return `@extend selectors`.
*
* @return {String}
* @api public
*/
Extend.prototype.clone = function(){
return new Extend(this.selectors);
};
toString() {
return '@extend ' + this.selectors.join(', ');
};
/**
* Return `@extend selectors`.
*
* @return {String}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Extend.prototype.toString = function(){
return '@extend ' + this.selectors.join(', ');
};
toJSON() {
return {
__type: 'Extend',
selectors: this.selectors,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Extend.prototype.toJSON = function(){
return {
__type: 'Extend',
selectors: this.selectors,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};

@@ -14,72 +14,68 @@

/**
* Initialize a new `Feature` with the given `segs`.
*
* @param {Array} segs
* @api public
*/
module.exports = class Feature extends Node {
/**
* Initialize a new `Feature` with the given `segs`.
*
* @param {Array} segs
* @api public
*/
var Feature = module.exports = function Feature(segs){
Node.call(this);
this.segments = segs;
this.expr = null;
};
constructor(segs) {
super();
this.segments = segs;
this.expr = null;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Feature.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Feature;
clone.segments = this.segments.map(function (node) { return node.clone(parent, clone); });
if (this.expr) clone.expr = this.expr.clone(parent, clone);
if (this.name) clone.name = this.name;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return "<ident>" or "(<ident>: <expr>)"
*
* @return {String}
* @api public
*/
Feature.prototype.clone = function(parent){
var clone = new Feature;
clone.segments = this.segments.map(function(node){ return node.clone(parent, clone); });
if (this.expr) clone.expr = this.expr.clone(parent, clone);
if (this.name) clone.name = this.name;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
toString() {
if (this.expr) {
return '(' + this.segments.join('') + ': ' + this.expr.toString() + ')';
} else {
return this.segments.join('');
}
};
/**
* Return "<ident>" or "(<ident>: <expr>)"
*
* @return {String}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Feature.prototype.toString = function(){
if (this.expr) {
return '(' + this.segments.join('') + ': ' + this.expr.toString() + ')';
} else {
return this.segments.join('');
}
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Feature.prototype.toJSON = function(){
var json = {
__type: 'Feature',
segments: this.segments,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
var json = {
__type: 'Feature',
segments: this.segments,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.expr) json.expr = this.expr;
if (this.name) json.name = this.name;
return json;
};
if (this.expr) json.expr = this.expr;
if (this.name) json.name = this.name;
return json;
};

@@ -14,116 +14,113 @@

/**
* Initialize a new `Function` with `name`, `params`, and `body`.
*
* @param {String} name
* @param {Params|Function} params
* @param {Block} body
* @api public
*/
module.exports = class Function extends Node {
/**
* Initialize a new `Function` with `name`, `params`, and `body`.
*
* @param {String} name
* @param {Params|Function} params
* @param {Block} body
* @api public
*/
var Function = module.exports = function Function(name, params, body){
Node.call(this);
this.name = name;
this.params = params;
this.block = body;
if ('function' == typeof params) this.fn = params;
};
constructor(name, params, body) {
super();
this.name = name;
this.params = params;
this.block = body;
if ('function' == typeof params) this.fn = params;
}
/**
* Check function arity.
*
* @return {Boolean}
* @api public
*/
/**
* Check function arity.
*
* @return {Boolean}
* @api public
*/
Function.prototype.__defineGetter__('arity', function(){
return this.params.length;
});
get arity() {
return this.params.length;
};
/**
* Inherit from `Node.prototype`.
*/
/**
* Return hash.
*
* @return {String}
* @api public
*/
Function.prototype.__proto__ = Node.prototype;
get hash() {
return 'function ' + this.name;
};
/**
* Return hash.
*
* @return {String}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Function.prototype.__defineGetter__('hash', function(){
return 'function ' + this.name;
});
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Function.prototype.clone = function(parent){
if (this.fn) {
var clone = new Function(
clone(parent) {
if (this.fn) {
var clone = new Function(
this.name
, this.fn);
} else {
var clone = new Function(this.name);
clone.params = this.params.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
}
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
, this.fn);
} else {
var clone = new Function(this.name);
clone.params = this.params.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
}
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return <name>(param1, param2, ...).
*
* @return {String}
* @api public
*/
/**
* Return <name>(param1, param2, ...).
*
* @return {String}
* @api public
*/
Function.prototype.toString = function(){
if (this.fn) {
return this.name
+ '('
+ this.fn.toString()
.match(/^function *\w*\((.*?)\)/)
.slice(1)
.join(', ')
+ ')';
} else {
return this.name
+ '('
+ this.params.nodes.join(', ')
+ ')';
}
};
toString() {
if (this.fn) {
return this.name
+ '('
+ this.fn.toString()
.match(/^function *\w*\((.*?)\)/)
.slice(1)
.join(', ')
+ ')';
} else {
return this.name
+ '('
+ this.params.nodes.join(', ')
+ ')';
}
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Function.prototype.toJSON = function(){
var json = {
__type: 'Function',
name: this.name,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
var json = {
__type: 'Function',
name: this.name,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.fn) {
json.fn = this.fn;
} else {
json.params = this.params;
json.block = this.block;
}
return json;
};
if (this.fn) {
json.fn = this.fn;
} else {
json.params = this.params;
json.block = this.block;
}
return json;
};

@@ -14,98 +14,94 @@

/**
* Initialize a new `Group`.
*
* @api public
*/
module.exports = class Group extends Node {
/**
* Initialize a new `Group`.
*
* @api public
*/
var Group = module.exports = function Group(){
Node.call(this);
this.nodes = [];
this.extends = [];
};
constructor() {
super();
this.nodes = [];
this.extends = [];
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Push the given `selector` node.
*
* @param {Selector} selector
* @api public
*/
Group.prototype.__proto__ = Node.prototype;
push(selector) {
this.nodes.push(selector);
};
/**
* Push the given `selector` node.
*
* @param {Selector} selector
* @api public
*/
/**
* Return this set's `Block`.
*/
Group.prototype.push = function(selector){
this.nodes.push(selector);
};
get block() {
return this.nodes[0].block;
};
/**
* Return this set's `Block`.
*/
/**
* Assign `block` to each selector in this set.
*
* @param {Block} block
* @api public
*/
Group.prototype.__defineGetter__('block', function(){
return this.nodes[0].block;
});
set block(block) {
for (var i = 0, len = this.nodes.length; i < len; ++i) {
this.nodes[i].block = block;
}
};
/**
* Assign `block` to each selector in this set.
*
* @param {Block} block
* @api public
*/
/**
* Check if this set has only placeholders.
*
* @return {Boolean}
* @api public
*/
Group.prototype.__defineSetter__('block', function(block){
for (var i = 0, len = this.nodes.length; i < len; ++i) {
this.nodes[i].block = block;
}
});
get hasOnlyPlaceholders() {
return this.nodes.every(function (selector) { return selector.isPlaceholder; });
};
/**
* Check if this set has only placeholders.
*
* @return {Boolean}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Group.prototype.__defineGetter__('hasOnlyPlaceholders', function(){
return this.nodes.every(function(selector) { return selector.isPlaceholder; });
});
clone(parent) {
var clone = new Group;
clone.lineno = this.lineno;
clone.column = this.column;
this.nodes.forEach(function (node) {
clone.push(node.clone(parent, clone));
});
clone.filename = this.filename;
clone.block = this.block.clone(parent, clone);
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Group.prototype.clone = function(parent){
var clone = new Group;
clone.lineno = this.lineno;
clone.column = this.column;
this.nodes.forEach(function(node){
clone.push(node.clone(parent, clone));
});
clone.filename = this.filename;
clone.block = this.block.clone(parent, clone);
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Group.prototype.toJSON = function(){
return {
__type: 'Group',
nodes: this.nodes,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'Group',
nodes: this.nodes,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};

@@ -25,217 +25,215 @@

var HSLA = exports = module.exports = function HSLA(h,s,l,a){
Node.call(this);
this.h = clampDegrees(h);
this.s = clampPercentage(s);
this.l = clampPercentage(l);
this.a = clampAlpha(a);
this.hsla = this;
};
exports = module.exports = class HSLA extends Node {
constructor(h, s, l, a) {
super();
this.h = clampDegrees(h);
this.s = clampPercentage(s);
this.l = clampPercentage(l);
this.a = clampAlpha(a);
this.hsla = this;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return hsla(n,n,n,n).
*
* @return {String}
* @api public
*/
HSLA.prototype.__proto__ = Node.prototype;
toString() {
return 'hsla('
+ this.h + ','
+ this.s.toFixed(0) + '%,'
+ this.l.toFixed(0) + '%,'
+ this.a + ')';
};
/**
* Return hsla(n,n,n,n).
*
* @return {String}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
HSLA.prototype.toString = function(){
return 'hsla('
+ this.h + ','
+ this.s.toFixed(0) + '%,'
+ this.l.toFixed(0) + '%,'
+ this.a + ')';
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
HSLA.prototype.clone = function(parent){
var clone = new HSLA(
clone(parent) {
var clone = new HSLA(
this.h
, this.s
, this.l
, this.a);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
, this.s
, this.l
, this.a);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
HSLA.prototype.toJSON = function(){
return {
__type: 'HSLA',
h: this.h,
s: this.s,
l: this.l,
a: this.a,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'HSLA',
h: this.h,
s: this.s,
l: this.l,
a: this.a,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};
/**
* Return rgba `RGBA` representation.
*
* @return {RGBA}
* @api public
*/
/**
* Return rgba `RGBA` representation.
*
* @return {RGBA}
* @api public
*/
HSLA.prototype.__defineGetter__('rgba', function(){
return nodes.RGBA.fromHSLA(this);
});
get rgba() {
return nodes.RGBA.fromHSLA(this);
};
/**
* Return hash.
*
* @return {String}
* @api public
*/
/**
* Return hash.
*
* @return {String}
* @api public
*/
HSLA.prototype.__defineGetter__('hash', function(){
return this.rgba.toString();
});
get hash() {
return this.rgba.toString();
};
/**
* Add h,s,l to the current component values.
*
* @param {Number} h
* @param {Number} s
* @param {Number} l
* @return {HSLA} new node
* @api public
*/
/**
* Add h,s,l to the current component values.
*
* @param {Number} h
* @param {Number} s
* @param {Number} l
* @return {HSLA} new node
* @api public
*/
HSLA.prototype.add = function(h,s,l){
return new HSLA(
add(h, s, l) {
return new HSLA(
this.h + h
, this.s + s
, this.l + l
, this.a);
};
, this.s + s
, this.l + l
, this.a);
};
/**
* Subtract h,s,l from the current component values.
*
* @param {Number} h
* @param {Number} s
* @param {Number} l
* @return {HSLA} new node
* @api public
*/
/**
* Subtract h,s,l from the current component values.
*
* @param {Number} h
* @param {Number} s
* @param {Number} l
* @return {HSLA} new node
* @api public
*/
HSLA.prototype.sub = function(h,s,l){
return this.add(-h, -s, -l);
};
sub(h, s, l) {
return this.add(-h, -s, -l);
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
HSLA.prototype.operate = function(op, right){
switch (op) {
case '==':
case '!=':
case '<=':
case '>=':
case '<':
case '>':
case 'is a':
case '||':
case '&&':
return this.rgba.operate(op, right);
default:
return this.rgba.operate(op, right).hsla;
}
};
operate(op, right) {
switch (op) {
case '==':
case '!=':
case '<=':
case '>=':
case '<':
case '>':
case 'is a':
case '||':
case '&&':
return this.rgba.operate(op, right);
default:
return this.rgba.operate(op, right).hsla;
}
};
/**
* Return `HSLA` representation of the given `color`.
*
* @param {RGBA} color
* @return {HSLA}
* @api public
*/
exports.fromRGBA = function(rgba){
var r = rgba.r / 255
, g = rgba.g / 255
, b = rgba.b / 255
, a = rgba.a;
/**
* Adjust lightness by `percent`.
*
* @param {Number} percent
* @return {HSLA} for chaining
* @api public
*/
var min = Math.min(r,g,b)
, max = Math.max(r,g,b)
, l = (max + min) / 2
, d = max - min
, h, s;
adjustLightness(percent) {
this.l = clampPercentage(this.l + this.l * (percent / 100));
return this;
};
switch (max) {
case min: h = 0; break;
case r: h = 60 * (g-b) / d; break;
case g: h = 60 * (b-r) / d + 120; break;
case b: h = 60 * (r-g) / d + 240; break;
}
/**
* Adjust hue by `deg`.
*
* @param {Number} deg
* @return {HSLA} for chaining
* @api public
*/
if (max == min) {
s = 0;
} else if (l < .5) {
s = d / (2 * l);
} else {
s = d / (2 - 2 * l);
}
adjustHue(deg) {
this.h = clampDegrees(this.h + deg);
return this;
};
h %= 360;
s *= 100;
l *= 100;
return new HSLA(h,s,l,a);
};
/**
* Return `HSLA` representation of the given `color`.
*
* @param {RGBA} color
* @return {HSLA}
* @api public
*/
/**
* Adjust lightness by `percent`.
*
* @param {Number} percent
* @return {HSLA} for chaining
* @api public
*/
static fromRGBA(rgba) {
var r = rgba.r / 255
, g = rgba.g / 255
, b = rgba.b / 255
, a = rgba.a;
HSLA.prototype.adjustLightness = function(percent){
this.l = clampPercentage(this.l + this.l * (percent / 100));
return this;
};
var min = Math.min(r, g, b)
, max = Math.max(r, g, b)
, l = (max + min) / 2
, d = max - min
, h, s;
/**
* Adjust hue by `deg`.
*
* @param {Number} deg
* @return {HSLA} for chaining
* @api public
*/
switch (max) {
case min: h = 0; break;
case r: h = 60 * (g - b) / d; break;
case g: h = 60 * (b - r) / d + 120; break;
case b: h = 60 * (r - g) / d + 240; break;
}
HSLA.prototype.adjustHue = function(deg){
this.h = clampDegrees(this.h + deg);
return this;
if (max == min) {
s = 0;
} else if (l < .5) {
s = d / (2 * l);
} else {
s = d / (2 - 2 * l);
}
h %= 360;
s *= 100;
l *= 100;
return new HSLA(h, s, l, a);
};
};

@@ -242,0 +240,0 @@

@@ -15,143 +15,139 @@

/**
* Initialize a new `Ident` by `name` with the given `val` node.
*
* @param {String} name
* @param {Node} val
* @api public
*/
module.exports = class Ident extends Node {
/**
* Initialize a new `Ident` by `name` with the given `val` node.
*
* @param {String} name
* @param {Node} val
* @api public
*/
var Ident = module.exports = function Ident(name, val, mixin){
Node.call(this);
this.name = name;
this.string = name;
this.val = val || nodes.null;
this.mixin = !!mixin;
};
constructor(name, val, mixin) {
super();
this.name = name;
this.string = name;
this.val = val || nodes.null;
this.mixin = !!mixin;
}
/**
* Check if the variable has a value.
*
* @return {Boolean}
* @api public
*/
/**
* Check if the variable has a value.
*
* @return {Boolean}
* @api public
*/
Ident.prototype.__defineGetter__('isEmpty', function(){
return undefined == this.val;
});
get isEmpty() {
return undefined == this.val;
};
/**
* Return hash.
*
* @return {String}
* @api public
*/
/**
* Return hash.
*
* @return {String}
* @api public
*/
Ident.prototype.__defineGetter__('hash', function(){
return this.name;
});
get hash() {
return this.name;
};
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Ident.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Ident(this.name);
clone.val = this.val.clone(parent, clone);
clone.mixin = this.mixin;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.property = this.property;
clone.rest = this.rest;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Ident.prototype.clone = function(parent){
var clone = new Ident(this.name);
clone.val = this.val.clone(parent, clone);
clone.mixin = this.mixin;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.property = this.property;
clone.rest = this.rest;
return clone;
};
toJSON() {
return {
__type: 'Ident',
name: this.name,
val: this.val,
mixin: this.mixin,
property: this.property,
rest: this.rest,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return <name>.
*
* @return {String}
* @api public
*/
Ident.prototype.toJSON = function(){
return {
__type: 'Ident',
name: this.name,
val: this.val,
mixin: this.mixin,
property: this.property,
rest: this.rest,
lineno: this.lineno,
column: this.column,
filename: this.filename
toString() {
return this.name;
};
};
/**
* Return <name>.
*
* @return {String}
* @api public
*/
/**
* Coerce `other` to an ident.
*
* @param {Node} other
* @return {String}
* @api public
*/
Ident.prototype.toString = function(){
return this.name;
};
coerce(other) {
switch (other.nodeName) {
case 'ident':
case 'string':
case 'literal':
return new Ident(other.string);
case 'unit':
return new Ident(other.toString());
default:
return super.coerce(other);
}
};
/**
* Coerce `other` to an ident.
*
* @param {Node} other
* @return {String}
* @api public
*/
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Ident.prototype.coerce = function(other){
switch (other.nodeName) {
case 'ident':
case 'string':
case 'literal':
return new Ident(other.string);
case 'unit':
return new Ident(other.toString());
default:
return Node.prototype.coerce.call(this, other);
}
operate(op, right) {
var val = right.first;
switch (op) {
case '-':
if ('unit' == val.nodeName) {
var expr = new nodes.Expression;
val = val.clone();
val.val = -val.val;
expr.push(this);
expr.push(val);
return expr;
}
case '+':
return new nodes.Ident(this.string + this.coerce(val).string);
}
return super.operate(op, right);
};
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Ident.prototype.operate = function(op, right){
var val = right.first;
switch (op) {
case '-':
if ('unit' == val.nodeName) {
var expr = new nodes.Expression;
val = val.clone();
val.val = -val.val;
expr.push(this);
expr.push(val);
return expr;
}
case '+':
return new nodes.Ident(this.string + this.coerce(val).string);
}
return Node.prototype.operate.call(this, op, right);
};

@@ -14,66 +14,62 @@

/**
* Initialize a new `If` with the given `cond`.
*
* @param {Expression} cond
* @param {Boolean|Block} negate, block
* @api public
*/
module.exports = class If extends Node {
/**
* Initialize a new `If` with the given `cond`.
*
* @param {Expression} cond
* @param {Boolean|Block} negate, block
* @api public
*/
var If = module.exports = function If(cond, negate){
Node.call(this);
this.cond = cond;
this.elses = [];
if (negate && negate.nodeName) {
this.block = negate;
} else {
this.negate = negate;
constructor(cond, negate) {
super();
this.cond = cond;
this.elses = [];
if (negate && negate.nodeName) {
this.block = negate;
} else {
this.negate = negate;
}
}
};
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
If.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new If();
clone.cond = this.cond.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.elses = this.elses.map(function (node) { return node.clone(parent, clone); });
clone.negate = this.negate;
clone.postfix = this.postfix;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
If.prototype.clone = function(parent){
var clone = new If();
clone.cond = this.cond.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.elses = this.elses.map(function(node){ return node.clone(parent, clone); });
clone.negate = this.negate;
clone.postfix = this.postfix;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
If.prototype.toJSON = function(){
return {
__type: 'If',
cond: this.cond,
block: this.block,
elses: this.elses,
negate: this.negate,
postfix: this.postfix,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'If',
cond: this.cond,
block: this.block,
elses: this.elses,
negate: this.negate,
postfix: this.postfix,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};

@@ -14,56 +14,53 @@

/**
* Initialize a new `Import` with the given `expr`.
*
* @param {Expression} expr
* @api public
*/
module.exports = class Import extends Node {
/**
* Initialize a new `Import` with the given `expr`.
*
* @param {Expression} expr
* @api public
*/
var Import = module.exports = function Import(expr, once){
Node.call(this);
this.path = expr;
this.once = once || false;
};
constructor(expr, once) {
super();
this.path = expr;
this.once = once || false;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Import.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Import();
clone.path = this.path.nodeName ? this.path.clone(parent, clone) : this.path;
clone.once = this.once;
clone.mtime = this.mtime;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Import.prototype.clone = function(parent){
var clone = new Import();
clone.path = this.path.nodeName ? this.path.clone(parent, clone) : this.path;
clone.once = this.once;
clone.mtime = this.mtime;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
toJSON() {
return {
__type: 'Import',
path: this.path,
once: this.once,
mtime: this.mtime,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Import.prototype.toJSON = function(){
return {
__type: 'Import',
path: this.path,
once: this.once,
mtime: this.mtime,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};

@@ -14,69 +14,66 @@

/**
* Initialize a new `Keyframes` with the given `segs`,
* and optional vendor `prefix`.
*
* @param {Array} segs
* @param {String} prefix
* @api public
*/
module.exports = class Keyframes extends Atrule {
/**
* Initialize a new `Keyframes` with the given `segs`,
* and optional vendor `prefix`.
*
* @param {Array} segs
* @param {String} prefix
* @api public
*/
var Keyframes = module.exports = function Keyframes(segs, prefix){
Atrule.call(this, 'keyframes');
this.segments = segs;
this.prefix = prefix || 'official';
};
constructor(segs, prefix) {
super('keyframes')
this.segments = segs;
this.prefix = prefix || 'official';
}
/**
* Inherit from `Atrule.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Keyframes.prototype.__proto__ = Atrule.prototype;
clone(parent) {
var clone = new Keyframes;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.segments = this.segments.map(function (node) { return node.clone(parent, clone); });
clone.prefix = this.prefix;
clone.block = this.block.clone(parent, clone);
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Keyframes.prototype.clone = function(parent){
var clone = new Keyframes;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.segments = this.segments.map(function(node) { return node.clone(parent, clone); });
clone.prefix = this.prefix;
clone.block = this.block.clone(parent, clone);
return clone;
};
toJSON() {
return {
__type: 'Keyframes',
segments: this.segments,
prefix: this.prefix,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return `@keyframes name`.
*
* @return {String}
* @api public
*/
Keyframes.prototype.toJSON = function(){
return {
__type: 'Keyframes',
segments: this.segments,
prefix: this.prefix,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
toString() {
return '@keyframes ' + this.segments.join('');
};
};
/**
* Return `@keyframes name`.
*
* @return {String}
* @api public
*/
Keyframes.prototype.toString = function(){
return '@keyframes ' + this.segments.join('');
};
};

@@ -15,99 +15,96 @@

/**
* Initialize a new `Literal` with the given `str`.
*
* @param {String} str
* @api public
*/
module.exports = class Literal extends Node {
/**
* Initialize a new `Literal` with the given `str`.
*
* @param {String} str
* @api public
*/
var Literal = module.exports = function Literal(str){
Node.call(this);
this.val = str;
this.string = str;
this.prefixed = false;
};
constructor(str) {
super();
this.val = str;
this.string = str;
this.prefixed = false;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return hash.
*
* @return {String}
* @api public
*/
Literal.prototype.__proto__ = Node.prototype;
get hash() {
return this.val;
};
/**
* Return hash.
*
* @return {String}
* @api public
*/
/**
* Return literal value.
*
* @return {String}
* @api public
*/
Literal.prototype.__defineGetter__('hash', function(){
return this.val;
});
toString() {
return this.val.toString();
};
/**
* Return literal value.
*
* @return {String}
* @api public
*/
/**
* Coerce `other` to a literal.
*
* @param {Node} other
* @return {String}
* @api public
*/
Literal.prototype.toString = function(){
return this.val.toString();
};
coerce(other) {
switch (other.nodeName) {
case 'ident':
case 'string':
case 'literal':
return new Literal(other.string);
default:
return super.coerce(other);
}
};
/**
* Coerce `other` to a literal.
*
* @param {Node} other
* @return {String}
* @api public
*/
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Literal.prototype.coerce = function(other){
switch (other.nodeName) {
case 'ident':
case 'string':
case 'literal':
return new Literal(other.string);
default:
return Node.prototype.coerce.call(this, other);
}
};
operate(op, right) {
var val = right.first;
switch (op) {
case '+':
return new nodes.Literal(this.string + this.coerce(val).string);
default:
return super.operate(op, right);
}
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Literal.prototype.operate = function(op, right){
var val = right.first;
switch (op) {
case '+':
return new nodes.Literal(this.string + this.coerce(val).string);
default:
return Node.prototype.operate.call(this, op, right);
}
};
toJSON() {
return {
__type: 'Literal',
val: this.val,
string: this.string,
prefixed: this.prefixed,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Literal.prototype.toJSON = function(){
return {
__type: 'Literal',
val: this.val,
string: this.string,
prefixed: this.prefixed,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};

@@ -14,64 +14,60 @@

/**
* Initialize a new `Media` with the given `val`
*
* @param {String} val
* @api public
*/
module.exports = class Media extends Atrule {
/**
* Initialize a new `Media` with the given `val`
*
* @param {String} val
* @api public
*/
var Media = module.exports = function Media(val){
Atrule.call(this, 'media');
this.val = val;
};
constructor(val) {
super('media');
this.val = val;
}
/**
* Inherit from `Atrule.prototype`.
*/
/**
* Clone this node.
*
* @return {Media}
* @api public
*/
Media.prototype.__proto__ = Atrule.prototype;
clone(parent) {
var clone = new Media;
clone.val = this.val.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Clone this node.
*
* @return {Media}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Media.prototype.clone = function(parent){
var clone = new Media;
clone.val = this.val.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
toJSON() {
return {
__type: 'Media',
val: this.val,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return @media "val".
*
* @return {String}
* @api public
*/
Media.prototype.toJSON = function(){
return {
__type: 'Media',
val: this.val,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
toString() {
return '@media ' + this.val;
};
};
/**
* Return @media "val".
*
* @return {String}
* @api public
*/
Media.prototype.toString = function(){
return '@media ' + this.val;
};

@@ -14,70 +14,66 @@

/**
* Initialize a new `Member` with `left` and `right`.
*
* @param {Node} left
* @param {Node} right
* @api public
*/
module.exports = class Member extends Node {
/**
* Initialize a new `Member` with `left` and `right`.
*
* @param {Node} left
* @param {Node} right
* @api public
*/
var Member = module.exports = function Member(left, right){
Node.call(this);
this.left = left;
this.right = right;
};
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Member.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Member;
clone.left = this.left.clone(parent, clone);
clone.right = this.right.clone(parent, clone);
if (this.val) clone.val = this.val.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Member.prototype.clone = function(parent){
var clone = new Member;
clone.left = this.left.clone(parent, clone);
clone.right = this.right.clone(parent, clone);
if (this.val) clone.val = this.val.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
toJSON() {
var json = {
__type: 'Member',
left: this.left,
right: this.right,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.val) json.val = this.val;
return json;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a string representation of this node.
*
* @return {String}
* @api public
*/
Member.prototype.toJSON = function(){
var json = {
__type: 'Member',
left: this.left,
right: this.right,
lineno: this.lineno,
column: this.column,
filename: this.filename
toString() {
return this.left.toString()
+ '.' + this.right.toString();
};
if (this.val) json.val = this.val;
return json;
};
/**
* Return a string representation of this node.
*
* @return {String}
* @api public
*/
Member.prototype.toString = function(){
return this.left.toString()
+ '.' + this.right.toString();
};

@@ -13,49 +13,45 @@ /*!

/**
* Initialize a new `Namespace` with the given `val` and `prefix`
*
* @param {String|Call} val
* @param {String} [prefix]
* @api public
*/
module.exports = class Namespace extends Node {
/**
* Initialize a new `Namespace` with the given `val` and `prefix`
*
* @param {String|Call} val
* @param {String} [prefix]
* @api public
*/
var Namespace = module.exports = function Namespace(val, prefix){
Node.call(this);
this.val = val;
this.prefix = prefix;
};
constructor(val, prefix) {
super();
this.val = val;
this.prefix = prefix;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return @namespace "val".
*
* @return {String}
* @api public
*/
Namespace.prototype.__proto__ = Node.prototype;
toString() {
return '@namespace ' + (this.prefix ? this.prefix + ' ' : '') + this.val;
};
/**
* Return @namespace "val".
*
* @return {String}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Namespace.prototype.toString = function(){
return '@namespace ' + (this.prefix ? this.prefix + ' ' : '') + this.val;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Namespace.prototype.toJSON = function(){
return {
__type: 'Namespace',
val: this.val,
prefix: this.prefix,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'Namespace',
val: this.val,
prefix: this.prefix,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};

@@ -16,38 +16,35 @@

/**
* Initialize a new `CoercionError` with the given `msg`.
*
* @param {String} msg
* @api private
*/
class CoercionError extends Error {
/**
* Initialize a new `CoercionError` with the given `msg`.
*
* @param {String} msg
* @api private
*/
function CoercionError(msg) {
this.name = 'CoercionError'
this.message = msg
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CoercionError);
constructor(msg) {
super();
this.name = 'CoercionError'
this.message = msg
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CoercionError);
}
}
}
/**
* Inherit from `Error.prototype`.
*/
CoercionError.prototype.__proto__ = Error.prototype;
/**
* Node constructor.
*
* @api public
*/
module.exports = class Node {
/**
* Node constructor.
*
* @api public
*/
var Node = module.exports = function Node(){
this.lineno = nodes.lineno || 1;
this.column = nodes.column || 1;
this.filename = nodes.filename;
};
constructor() {
this.lineno = nodes.lineno || 1;
this.column = nodes.column || 1;
this.filename = nodes.filename;
}
Node.prototype = {
constructor: Node,
/**

@@ -62,3 +59,3 @@ * Return this node.

return this;
},
}

@@ -74,3 +71,3 @@ /**

return this.val;
},
}

@@ -86,3 +83,3 @@ /**

return this.constructor.name.toLowerCase();
},
}

@@ -96,5 +93,5 @@ /**

clone: function(){
clone() {
return this;
},
}

@@ -108,3 +105,3 @@ /**

toJSON: function(){
toJSON() {
return {

@@ -115,3 +112,3 @@ lineno: this.lineno,

};
},
}

@@ -125,5 +122,5 @@ /**

eval: function(){
eval() {
return new Evaluator(this).evaluate();
},
}

@@ -137,5 +134,5 @@ /**

toBoolean: function(){
toBoolean() {
return nodes.true;
},
}

@@ -149,3 +146,3 @@ /**

toExpression: function(){
toExpression() {
if ('expression' == this.nodeName) return this;

@@ -155,3 +152,3 @@ var expr = new nodes.Expression;

return expr;
},
}

@@ -166,3 +163,3 @@ /**

shouldCoerce: function(op){
shouldCoerce(op) {
switch (op) {

@@ -177,3 +174,3 @@ case 'is a':

}
},
}

@@ -189,7 +186,7 @@ /**

operate: function(op, right){
operate(op, right) {
switch (op) {
case 'is a':
if ('string' == right.first.nodeName) {
return nodes.Boolean(this.nodeName == right.val);
return new nodes.Boolean(this.nodeName == right.val);
} else {

@@ -199,13 +196,13 @@ throw new Error('"is a" expects a string, got ' + right.toString());

case '==':
return nodes.Boolean(this.hash == right.hash);
return new nodes.Boolean(this.hash == right.hash);
case '!=':
return nodes.Boolean(this.hash != right.hash);
return new nodes.Boolean(this.hash != right.hash);
case '>=':
return nodes.Boolean(this.hash >= right.hash);
return new nodes.Boolean(this.hash >= right.hash);
case '<=':
return nodes.Boolean(this.hash <= right.hash);
return new nodes.Boolean(this.hash <= right.hash);
case '>':
return nodes.Boolean(this.hash > right.hash);
return new nodes.Boolean(this.hash > right.hash);
case '<':
return nodes.Boolean(this.hash < right.hash);
return new nodes.Boolean(this.hash < right.hash);
case '||':

@@ -223,3 +220,3 @@ return this.toBoolean().isTrue

if (1 == len && 'object' == vals[0].nodeName) {
return nodes.Boolean(vals[0].has(this.hash));
return new nodes.Boolean(vals[0].has(this.hash));
}

@@ -254,3 +251,3 @@

}
},
}

@@ -265,3 +262,3 @@ /**

coerce: function(other){
coerce(other) {
if (other.nodeName == this.nodeName) return other;

@@ -271,1 +268,2 @@ throw new CoercionError('cannot coerce ' + other + ' to ' + this.nodeName);

};

@@ -21,11 +21,4 @@

var Null = module.exports = function Null(){};
/**
* Inherit from `Node.prototype`.
*/
Null.prototype.__proto__ = Node.prototype;
/**
module.exports = class Null extends Node {
/**
* Return 'Null'.

@@ -37,54 +30,58 @@ *

Null.prototype.inspect =
Null.prototype.toString = function(){
return 'null';
};
toString() {
return 'null';
};
/**
* Return false.
*
* @return {Boolean}
* @api public
*/
inspect() {
return 'null';
}
Null.prototype.toBoolean = function(){
return nodes.false;
};
/**
* Return false.
*
* @return {Boolean}
* @api public
*/
/**
* Check if the node is a null node.
*
* @return {Boolean}
* @api public
*/
toBoolean() {
return nodes.false;
};
Null.prototype.__defineGetter__('isNull', function(){
return true;
});
/**
* Check if the node is a null node.
*
* @return {Boolean}
* @api public
*/
/**
* Return hash.
*
* @return {String}
* @api public
*/
get isNull() {
return true;
};
Null.prototype.__defineGetter__('hash', function(){
return null;
});
/**
* Return hash.
*
* @return {String}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
get hash() {
return null;
};
Null.prototype.toJSON = function(){
return {
__type: 'Null',
lineno: this.lineno,
column: this.column,
filename: this.filename
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
toJSON() {
return {
__type: 'Null',
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};

@@ -16,230 +16,230 @@

/**
* Initialize a new `Object`.
*
* @api public
*/
module.exports = class Object extends Node {
/**
* Initialize a new `Object`.
*
* @api public
*/
var Object = module.exports = function Object(){
Node.call(this);
this.vals = {};
this.keys = {};
};
constructor() {
super();
this.vals = {};
this.keys = {};
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Set `key` to `val`.
*
* @param {String} key
* @param {Node} val
* @return {Object} for chaining
* @api public
*/
Object.prototype.__proto__ = Node.prototype;
setValue(key, val) {
this.vals[key] = val;
return this;
};
/**
* Set `key` to `val`.
*
* @param {String} key
* @param {Node} val
* @return {Object} for chaining
* @api public
*/
/**
* Alias for `setValue` for compatible API
*/
Object.prototype.setValue = function(key, val){
this.vals[key] = val;
return this;
};
get set() {
return this.setValue;
}
/**
* Alias for `setValue` for compatible API
*/
Object.prototype.set = Object.prototype.setValue;
/**
* Set `key` to `val`.
*
* @param {String} key
* @param {Node} val
* @return {Object} for chaining
* @api public
*/
/**
* Set `key` to `val`.
*
* @param {String} key
* @param {Node} val
* @return {Object} for chaining
* @api public
*/
setKey(key, val) {
this.keys[key] = val;
return this;
};
Object.prototype.setKey = function(key, val){
this.keys[key] = val;
return this;
};
/**
* Return length.
*
* @return {Number}
* @api public
*/
/**
* Return length.
*
* @return {Number}
* @api public
*/
get length() {
return nativeObj.keys(this.vals).length;
};
Object.prototype.__defineGetter__('length', function() {
return nativeObj.keys(this.vals).length;
});
/**
* Get `key`.
*
* @param {String} key
* @return {Node}
* @api public
*/
/**
* Get `key`.
*
* @param {String} key
* @return {Node}
* @api public
*/
get(key) {
return this.vals[key] || nodes.null;
};
Object.prototype.get = function(key){
return this.vals[key] || nodes.null;
};
/**
* Has `key`?
*
* @param {String} key
* @return {Boolean}
* @api public
*/
/**
* Has `key`?
*
* @param {String} key
* @return {Boolean}
* @api public
*/
has(key) {
return key in this.vals;
};
Object.prototype.has = function(key){
return key in this.vals;
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Object.prototype.operate = function(op, right){
switch (op) {
case '.':
case '[]':
return this.get(right.hash);
case '==':
var vals = this.vals
, a
, b;
if ('object' != right.nodeName || this.length != right.length)
return nodes.false;
for (var key in vals) {
a = vals[key];
b = right.vals[key];
if (a.operate(op, b).isFalse)
operate(op, right) {
switch (op) {
case '.':
case '[]':
return this.get(right.hash);
case '==':
var vals = this.vals
, a
, b;
if ('object' != right.nodeName || this.length != right.length)
return nodes.false;
}
return nodes.true;
case '!=':
return this.operate('==', right).negate();
default:
return Node.prototype.operate.call(this, op, right);
}
};
for (var key in vals) {
a = vals[key];
b = right.vals[key];
if (a.operate(op, b).isFalse)
return nodes.false;
}
return nodes.true;
case '!=':
return this.operate('==', right).negate();
default:
return super.operate.call(op, right);
}
};
/**
* Return Boolean based on the length of this object.
*
* @return {Boolean}
* @api public
*/
/**
* Return Boolean based on the length of this object.
*
* @return {Boolean}
* @api public
*/
Object.prototype.toBoolean = function(){
return nodes.Boolean(this.length);
};
toBoolean() {
return new nodes.Boolean(this.length);
};
/**
* Convert object to string with properties.
*
* @return {String}
* @api private
*/
/**
* Convert object to string with properties.
*
* @return {String}
* @api private
*/
Object.prototype.toBlock = function(){
var str = '{'
, key
, val;
toBlock() {
var str = '{'
, key
, val;
for (key in this.vals) {
val = this.get(key);
if ('object' == val.first.nodeName) {
str += key + ' ' + val.first.toBlock();
} else {
switch (key) {
case '@charset':
str += key + ' ' + val.first.toString() + ';';
break;
default:
str += key + ':' + toString(val) + ';';
for (key in this.vals) {
val = this.get(key);
if ('object' == val.first.nodeName) {
str += key + ' ' + val.first.toBlock();
} else {
switch (key) {
case '@charset':
str += key + ' ' + val.first.toString() + ';';
break;
default:
str += key + ':' + toString(val) + ';';
}
}
}
}
str += '}';
str += '}';
return str;
return str;
function toString(node) {
if (node.nodes) {
return node.nodes.map(toString).join(node.isList ? ',' : ' ');
} else if ('literal' == node.nodeName && ',' == node.val) {
return '\\,';
function toString(node) {
if (node.nodes) {
return node.nodes.map(toString).join(node.isList ? ',' : ' ');
} else if ('literal' == node.nodeName && ',' == node.val) {
return '\\,';
}
return node.toString();
}
return node.toString();
}
};
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Object.prototype.clone = function(parent){
var clone = new Object;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone(parent) {
var clone = new Object;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
var key;
for (key in this.vals) {
clone.vals[key] = this.vals[key].clone(parent, clone);
}
var key;
for (key in this.vals) {
clone.vals[key] = this.vals[key].clone(parent, clone);
}
for (key in this.keys) {
clone.keys[key] = this.keys[key].clone(parent, clone);
}
for (key in this.keys) {
clone.keys[key] = this.keys[key].clone(parent, clone);
}
return clone;
};
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Object.prototype.toJSON = function(){
return {
__type: 'Object',
vals: this.vals,
keys: this.keys,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'Object',
vals: this.vals,
keys: this.keys,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};
/**
* Return "{ <prop>: <val> }"
*
* @return {String}
* @api public
*/
/**
* Return "{ <prop>: <val> }"
*
* @return {String}
* @api public
*/
Object.prototype.toString = function(){
var obj = {};
for (var prop in this.vals) {
obj[prop] = this.vals[prop].toString();
}
return JSON.stringify(obj);
toString() {
var obj = {};
for (var prop in this.vals) {
obj[prop] = this.vals[prop].toString();
}
return JSON.stringify(obj);
};
};

@@ -14,78 +14,73 @@

/**
* Initialize a new `Params` with `name`, `params`, and `body`.
*
* @param {String} name
* @param {Params} params
* @param {Expression} body
* @api public
*/
module.exports = class Params extends Node {
/**
* Initialize a new `Params` with `name`, `params`, and `body`.
*
* @param {String} name
* @param {Params} params
* @param {Expression} body
* @api public
*/
var Params = module.exports = function Params(){
Node.call(this);
this.nodes = [];
};
constructor() {
super();
this.nodes = [];
}
/**
* Check function arity.
*
* @return {Boolean}
* @api public
*/
/**
* Check function arity.
*
* @return {Boolean}
* @api public
*/
Params.prototype.__defineGetter__('length', function(){
return this.nodes.length;
});
get length() {
return this.nodes.length;
};
/**
* Inherit from `Node.prototype`.
*/
/**
* Push the given `node`.
*
* @param {Node} node
* @api public
*/
Params.prototype.__proto__ = Node.prototype;
push(node) {
this.nodes.push(node);
};
/**
* Push the given `node`.
*
* @param {Node} node
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Params.prototype.push = function(node){
this.nodes.push(node);
};
clone(parent) {
var clone = new Params;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
this.nodes.forEach(function (node) {
clone.push(node.clone(parent, clone));
});
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Params.prototype.clone = function(parent){
var clone = new Params;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
this.nodes.forEach(function(node){
clone.push(node.clone(parent, clone));
});
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Params.prototype.toJSON = function(){
return {
__type: 'Params',
nodes: this.nodes,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'Params',
nodes: this.nodes,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};

@@ -14,84 +14,80 @@

/**
* Initialize a new `Property` with the given `segs` and optional `expr`.
*
* @param {Array} segs
* @param {Expression} expr
* @api public
*/
module.exports = class Property extends Node {
/**
* Initialize a new `Property` with the given `segs` and optional `expr`.
*
* @param {Array} segs
* @param {Expression} expr
* @api public
*/
var Property = module.exports = function Property(segs, expr){
Node.call(this);
this.segments = segs;
this.expr = expr;
};
constructor(segs, expr) {
super();
this.segments = segs;
this.expr = expr;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Property.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Property(this.segments);
clone.name = this.name;
if (this.literal) clone.literal = this.literal;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.segments = this.segments.map(function (node) { return node.clone(parent, clone); });
if (this.expr) clone.expr = this.expr.clone(parent, clone);
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Property.prototype.clone = function(parent){
var clone = new Property(this.segments);
clone.name = this.name;
if (this.literal) clone.literal = this.literal;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.segments = this.segments.map(function(node){ return node.clone(parent, clone); });
if (this.expr) clone.expr = this.expr.clone(parent, clone);
return clone;
};
toJSON() {
var json = {
__type: 'Property',
segments: this.segments,
name: this.name,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.expr) json.expr = this.expr;
if (this.literal) json.literal = this.literal;
return json;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return string representation of this node.
*
* @return {String}
* @api public
*/
Property.prototype.toJSON = function(){
var json = {
__type: 'Property',
segments: this.segments,
name: this.name,
lineno: this.lineno,
column: this.column,
filename: this.filename
toString() {
return 'property(' + this.segments.join('') + ', ' + this.expr + ')';
};
if (this.expr) json.expr = this.expr;
if (this.literal) json.literal = this.literal;
return json;
};
/**
* Return string representation of this node.
*
* @return {String}
* @api public
*/
/**
* Operate on the property expression.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Property.prototype.toString = function(){
return 'property(' + this.segments.join('') + ', ' + this.expr + ')';
operate(op, right, val) {
return this.expr.operate(op, right, val);
};
};
/**
* Operate on the property expression.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Property.prototype.operate = function(op, right, val){
return this.expr.operate(op, right, val);
};

@@ -14,96 +14,93 @@

/**
* Initialize a new `QueryList`.
*
* @api public
*/
module.exports = class QueryList extends Node {
/**
* Initialize a new `QueryList`.
*
* @api public
*/
var QueryList = module.exports = function QueryList(){
Node.call(this);
this.nodes = [];
};
constructor() {
super();
this.nodes = [];
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
QueryList.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new QueryList;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
for (var i = 0; i < this.nodes.length; ++i) {
clone.push(this.nodes[i].clone(parent, clone));
}
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Push the given `node`.
*
* @param {Node} node
* @api public
*/
QueryList.prototype.clone = function(parent){
var clone = new QueryList;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
for (var i = 0; i < this.nodes.length; ++i) {
clone.push(this.nodes[i].clone(parent, clone));
}
return clone;
};
push(node) {
this.nodes.push(node);
};
/**
* Push the given `node`.
*
* @param {Node} node
* @api public
*/
/**
* Merges this query list with the `other`.
*
* @param {QueryList} other
* @return {QueryList}
* @api private
*/
QueryList.prototype.push = function(node){
this.nodes.push(node);
};
merge(other) {
var list = new QueryList
, merged;
this.nodes.forEach(function (query) {
for (var i = 0, len = other.nodes.length; i < len; ++i) {
merged = query.merge(other.nodes[i]);
if (merged) list.push(merged);
}
});
return list;
};
/**
* Merges this query list with the `other`.
*
* @param {QueryList} other
* @return {QueryList}
* @api private
*/
/**
* Return "<a>, <b>, <c>"
*
* @return {String}
* @api public
*/
QueryList.prototype.merge = function(other){
var list = new QueryList
, merged;
this.nodes.forEach(function(query){
for (var i = 0, len = other.nodes.length; i < len; ++i){
merged = query.merge(other.nodes[i]);
if (merged) list.push(merged);
}
});
return list;
};
toString() {
return '(' + this.nodes.map(function (node) {
return node.toString();
}).join(', ') + ')';
};
/**
* Return "<a>, <b>, <c>"
*
* @return {String}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
QueryList.prototype.toString = function(){
return '(' + this.nodes.map(function(node){
return node.toString();
}).join(', ') + ')';
};
toJSON() {
return {
__type: 'QueryList',
nodes: this.nodes,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
QueryList.prototype.toJSON = function(){
return {
__type: 'QueryList',
nodes: this.nodes,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};

@@ -14,158 +14,154 @@

/**
* Initialize a new `Query`.
*
* @api public
*/
module.exports = class Query extends Node {
/**
* Initialize a new `Query`.
*
* @api public
*/
var Query = module.exports = function Query(){
Node.call(this);
this.nodes = [];
this.type = '';
this.predicate = '';
};
constructor() {
super();
this.nodes = [];
this.type = '';
this.predicate = '';
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Query.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Query;
clone.predicate = this.predicate;
clone.type = this.type;
for (var i = 0, len = this.nodes.length; i < len; ++i) {
clone.push(this.nodes[i].clone(parent, clone));
}
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Push the given `feature`.
*
* @param {Feature} feature
* @api public
*/
Query.prototype.clone = function(parent){
var clone = new Query;
clone.predicate = this.predicate;
clone.type = this.type;
for (var i = 0, len = this.nodes.length; i < len; ++i) {
clone.push(this.nodes[i].clone(parent, clone));
}
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
push(feature) {
this.nodes.push(feature);
};
/**
* Push the given `feature`.
*
* @param {Feature} feature
* @api public
*/
/**
* Return resolved type of this query.
*
* @return {String}
* @api private
*/
Query.prototype.push = function(feature){
this.nodes.push(feature);
};
get resolvedType() {
if (this.type) {
return this.type.nodeName
? this.type.string
: this.type;
}
};
/**
* Return resolved type of this query.
*
* @return {String}
* @api private
*/
/**
* Return resolved predicate of this query.
*
* @return {String}
* @api private
*/
Query.prototype.__defineGetter__('resolvedType', function(){
if (this.type) {
return this.type.nodeName
? this.type.string
: this.type;
}
});
get resolvedPredicate() {
if (this.predicate) {
return this.predicate.nodeName
? this.predicate.string
: this.predicate;
}
};
/**
* Return resolved predicate of this query.
*
* @return {String}
* @api private
*/
/**
* Merges this query with the `other`.
*
* @param {Query} other
* @return {Query}
* @api private
*/
Query.prototype.__defineGetter__('resolvedPredicate', function(){
if (this.predicate) {
return this.predicate.nodeName
? this.predicate.string
: this.predicate;
}
});
merge(other) {
var query = new Query
, p1 = this.resolvedPredicate
, p2 = other.resolvedPredicate
, t1 = this.resolvedType
, t2 = other.resolvedType
, type, pred;
/**
* Merges this query with the `other`.
*
* @param {Query} other
* @return {Query}
* @api private
*/
// Stolen from Sass :D
t1 = t1 || t2;
t2 = t2 || t1;
if (('not' == p1) ^ ('not' == p2)) {
if (t1 == t2) return;
type = ('not' == p1) ? t2 : t1;
pred = ('not' == p1) ? p2 : p1;
} else if (('not' == p1) && ('not' == p2)) {
if (t1 != t2) return;
type = t1;
pred = 'not';
} else if (t1 != t2) {
return;
} else {
type = t1;
pred = p1 || p2;
}
query.predicate = pred;
query.type = type;
query.nodes = this.nodes.concat(other.nodes);
return query;
};
Query.prototype.merge = function(other){
var query = new Query
, p1 = this.resolvedPredicate
, p2 = other.resolvedPredicate
, t1 = this.resolvedType
, t2 = other.resolvedType
, type, pred;
/**
* Return "<a> and <b> and <c>"
*
* @return {String}
* @api public
*/
// Stolen from Sass :D
t1 = t1 || t2;
t2 = t2 || t1;
if (('not' == p1) ^ ('not' == p2)) {
if (t1 == t2) return;
type = ('not' == p1) ? t2 : t1;
pred = ('not' == p1) ? p2 : p1;
} else if (('not' == p1) && ('not' == p2)) {
if (t1 != t2) return;
type = t1;
pred = 'not';
} else if (t1 != t2) {
return;
} else {
type = t1;
pred = p1 || p2;
}
query.predicate = pred;
query.type = type;
query.nodes = this.nodes.concat(other.nodes);
return query;
};
toString() {
var pred = this.predicate ? this.predicate + ' ' : ''
, type = this.type || ''
, len = this.nodes.length
, str = pred + type;
if (len) {
str += (type && ' and ') + this.nodes.map(function (expr) {
return expr.toString();
}).join(' and ');
}
return str;
};
/**
* Return "<a> and <b> and <c>"
*
* @return {String}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Query.prototype.toString = function(){
var pred = this.predicate ? this.predicate + ' ' : ''
, type = this.type || ''
, len = this.nodes.length
, str = pred + type;
if (len) {
str += (type && ' and ') + this.nodes.map(function(expr){
return expr.toString();
}).join(' and ');
}
return str;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Query.prototype.toJSON = function(){
return {
__type: 'Query',
predicate: this.predicate,
type: this.type,
nodes: this.nodes,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'Query',
predicate: this.predicate,
type: this.type,
nodes: this.nodes,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};

@@ -22,43 +22,40 @@

var Return = module.exports = function Return(expr){
this.expr = expr || nodes.null;
};
module.exports = class Return extends Node {
constructor(expr) {
super();
this.expr = expr || nodes.null;
};
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Return.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Return();
clone.expr = this.expr.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Return.prototype.clone = function(parent){
var clone = new Return();
clone.expr = this.expr.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Return.prototype.toJSON = function(){
return {
__type: 'Return',
expr: this.expr,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'Return',
expr: this.expr,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};

@@ -18,327 +18,324 @@

/**
* Initialize a new `RGBA` with the given r,g,b,a component values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @api public
*/
exports = module.exports = class RGBA extends Node {
/**
* Initialize a new `RGBA` with the given r,g,b,a component values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @api public
*/
var RGBA = exports = module.exports = function RGBA(r,g,b,a){
Node.call(this);
this.r = clamp(r);
this.g = clamp(g);
this.b = clamp(b);
this.a = clampAlpha(a);
this.name = '';
this.rgba = this;
};
constructor(r, g, b, a) {
super();
this.r = clamp(r);
this.g = clamp(g);
this.b = clamp(b);
this.a = clampAlpha(a);
this.name = '';
this.rgba = this;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return an `RGBA` without clamping values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @return {RGBA}
* @api public
*/
RGBA.prototype.__proto__ = Node.prototype;
static withoutClamping(r, g, b, a) {
var rgba = new RGBA(0, 0, 0, 0);
rgba.r = r;
rgba.g = g;
rgba.b = b;
rgba.a = a;
return rgba;
};
/**
* Return an `RGBA` without clamping values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @return {RGBA}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
RGBA.withoutClamping = function(r,g,b,a){
var rgba = new RGBA(0,0,0,0);
rgba.r = r;
rgba.g = g;
rgba.b = b;
rgba.a = a;
return rgba;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
RGBA.prototype.clone = function(){
var clone = new RGBA(
clone() {
var clone = new RGBA(
this.r
, this.g
, this.b
, this.a);
clone.raw = this.raw;
clone.name = this.name;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
, this.g
, this.b
, this.a);
clone.raw = this.raw;
clone.name = this.name;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
RGBA.prototype.toJSON = function(){
return {
__type: 'RGBA',
r: this.r,
g: this.g,
b: this.b,
a: this.a,
raw: this.raw,
name: this.name,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'RGBA',
r: this.r,
g: this.g,
b: this.b,
a: this.a,
raw: this.raw,
name: this.name,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};
/**
* Return true.
*
* @return {Boolean}
* @api public
*/
/**
* Return true.
*
* @return {Boolean}
* @api public
*/
RGBA.prototype.toBoolean = function(){
return nodes.true;
};
toBoolean() {
return nodes.true;
};
/**
* Return `HSLA` representation.
*
* @return {HSLA}
* @api public
*/
/**
* Return `HSLA` representation.
*
* @return {HSLA}
* @api public
*/
RGBA.prototype.__defineGetter__('hsla', function(){
return HSLA.fromRGBA(this);
});
get hsla() {
return HSLA.fromRGBA(this);
};
/**
* Return hash.
*
* @return {String}
* @api public
*/
/**
* Return hash.
*
* @return {String}
* @api public
*/
RGBA.prototype.__defineGetter__('hash', function(){
return this.toString();
});
get hash() {
return this.toString();
};
/**
* Add r,g,b,a to the current component values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @return {RGBA} new node
* @api public
*/
/**
* Add r,g,b,a to the current component values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @return {RGBA} new node
* @api public
*/
RGBA.prototype.add = function(r,g,b,a){
return new RGBA(
add(r, g, b, a) {
return new RGBA(
this.r + r
, this.g + g
, this.b + b
, this.a + a);
};
, this.g + g
, this.b + b
, this.a + a);
};
/**
* Subtract r,g,b,a from the current component values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @return {RGBA} new node
* @api public
*/
/**
* Subtract r,g,b,a from the current component values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @return {RGBA} new node
* @api public
*/
RGBA.prototype.sub = function(r,g,b,a){
return new RGBA(
sub(r, g, b, a) {
return new RGBA(
this.r - r
, this.g - g
, this.b - b
, a == 1 ? this.a : this.a - a);
};
, this.g - g
, this.b - b
, a == 1 ? this.a : this.a - a);
};
/**
* Multiply rgb components by `n`.
*
* @param {String} n
* @return {RGBA} new node
* @api public
*/
/**
* Multiply rgb components by `n`.
*
* @param {String} n
* @return {RGBA} new node
* @api public
*/
RGBA.prototype.multiply = function(n){
return new RGBA(
multiply(n) {
return new RGBA(
this.r * n
, this.g * n
, this.b * n
, this.a);
};
, this.g * n
, this.b * n
, this.a);
};
/**
* Divide rgb components by `n`.
*
* @param {String} n
* @return {RGBA} new node
* @api public
*/
/**
* Divide rgb components by `n`.
*
* @param {String} n
* @return {RGBA} new node
* @api public
*/
RGBA.prototype.divide = function(n){
return new RGBA(
divide(n) {
return new RGBA(
this.r / n
, this.g / n
, this.b / n
, this.a);
};
, this.g / n
, this.b / n
, this.a);
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
RGBA.prototype.operate = function(op, right){
if ('in' != op) right = right.first
operate(op, right) {
if ('in' != op) right = right.first
switch (op) {
case 'is a':
if ('string' == right.nodeName && 'color' == right.string) {
return nodes.true;
}
break;
case '+':
switch (right.nodeName) {
case 'unit':
var n = right.val;
switch (right.type) {
case '%': return adjust(this, new nodes.String('lightness'), right);
case 'deg': return this.hsla.adjustHue(n).rgba;
default: return this.add(n,n,n,0);
}
case 'rgba':
return this.add(right.r, right.g, right.b, right.a);
case 'hsla':
return this.hsla.add(right.h, right.s, right.l);
}
break;
case '-':
switch (right.nodeName) {
case 'unit':
var n = right.val;
switch (right.type) {
case '%': return adjust(this, new nodes.String('lightness'), new nodes.Unit(-n, '%'));
case 'deg': return this.hsla.adjustHue(-n).rgba;
default: return this.sub(n,n,n,0);
}
case 'rgba':
return this.sub(right.r, right.g, right.b, right.a);
case 'hsla':
return this.hsla.sub(right.h, right.s, right.l);
}
break;
case '*':
switch (right.nodeName) {
case 'unit':
return this.multiply(right.val);
}
break;
case '/':
switch (right.nodeName) {
case 'unit':
return this.divide(right.val);
}
break;
}
return Node.prototype.operate.call(this, op, right);
};
switch (op) {
case 'is a':
if ('string' == right.nodeName && 'color' == right.string) {
return nodes.true;
}
break;
case '+':
switch (right.nodeName) {
case 'unit':
var n = right.val;
switch (right.type) {
case '%': return adjust(this, new nodes.String('lightness'), right);
case 'deg': return this.hsla.adjustHue(n).rgba;
default: return this.add(n, n, n, 0);
}
case 'rgba':
return this.add(right.r, right.g, right.b, right.a);
case 'hsla':
return this.hsla.add(right.h, right.s, right.l);
}
break;
case '-':
switch (right.nodeName) {
case 'unit':
var n = right.val;
switch (right.type) {
case '%': return adjust(this, new nodes.String('lightness'), new nodes.Unit(-n, '%'));
case 'deg': return this.hsla.adjustHue(-n).rgba;
default: return this.sub(n, n, n, 0);
}
case 'rgba':
return this.sub(right.r, right.g, right.b, right.a);
case 'hsla':
return this.hsla.sub(right.h, right.s, right.l);
}
break;
case '*':
switch (right.nodeName) {
case 'unit':
return this.multiply(right.val);
}
break;
case '/':
switch (right.nodeName) {
case 'unit':
return this.divide(right.val);
}
break;
}
return super.operate(op, right);
};
/**
* Return #nnnnnn, #nnn, or rgba(n,n,n,n) string representation of the color.
*
* @return {String}
* @api public
*/
/**
* Return #nnnnnn, #nnn, or rgba(n,n,n,n) string representation of the color.
*
* @return {String}
* @api public
*/
RGBA.prototype.toString = function(){
function pad(n) {
return n < 16
? '0' + n.toString(16)
: n.toString(16);
}
toString() {
function pad(n) {
return n < 16
? '0' + n.toString(16)
: n.toString(16);
}
// special case for transparent named color
if ('transparent' == this.name)
return this.name;
// special case for transparent named color
if ('transparent' == this.name)
return this.name;
if (1 == this.a) {
var r = pad(this.r)
, g = pad(this.g)
, b = pad(this.b);
if (1 == this.a) {
var r = pad(this.r)
, g = pad(this.g)
, b = pad(this.b);
// Compress
if (r[0] == r[1] && g[0] == g[1] && b[0] == b[1]) {
return '#' + r[0] + g[0] + b[0];
// Compress
if (r[0] == r[1] && g[0] == g[1] && b[0] == b[1]) {
return '#' + r[0] + g[0] + b[0];
} else {
return '#' + r + g + b;
}
} else {
return '#' + r + g + b;
return 'rgba('
+ this.r + ','
+ this.g + ','
+ this.b + ','
+ (+this.a.toFixed(3)) + ')';
}
} else {
return 'rgba('
+ this.r + ','
+ this.g + ','
+ this.b + ','
+ (+this.a.toFixed(3)) + ')';
}
};
};
/**
* Return a `RGBA` from the given `hsla`.
*
* @param {HSLA} hsla
* @return {RGBA}
* @api public
*/
/**
* Return a `RGBA` from the given `hsla`.
*
* @param {HSLA} hsla
* @return {RGBA}
* @api public
*/
exports.fromHSLA = function(hsla){
var h = hsla.h / 360
, s = hsla.s / 100
, l = hsla.l / 100
, a = hsla.a;
static fromHSLA(hsla) {
var h = hsla.h / 360
, s = hsla.s / 100
, l = hsla.l / 100
, a = hsla.a;
var m2 = l <= .5 ? l * (s + 1) : l + s - l * s
, m1 = l * 2 - m2;
var m2 = l <= .5 ? l * (s + 1) : l + s - l * s
, m1 = l * 2 - m2;
var r = hue(h + 1/3) * 0xff
, g = hue(h) * 0xff
, b = hue(h - 1/3) * 0xff;
var r = hue(h + 1 / 3) * 0xff
, g = hue(h) * 0xff
, b = hue(h - 1 / 3) * 0xff;
function hue(h) {
if (h < 0) ++h;
if (h > 1) --h;
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
if (h * 2 < 1) return m2;
if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
return m1;
}
return new RGBA(r,g,b,a);
function hue(h) {
if (h < 0) ++h;
if (h > 1) --h;
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
if (h * 2 < 1) return m2;
if (h * 3 < 2) return m1 + (m2 - m1) * (2 / 3 - h) * 6;
return m1;
}
return new RGBA(r, g, b, a);
};
};

@@ -345,0 +342,0 @@

@@ -14,84 +14,82 @@

/**
* Initialize a new `Root` node.
*
* @api public
*/
module.exports = class Root extends Node {
/**
* Initialize a new `Root` node.
*
* @api public
*/
var Root = module.exports = function Root(){
this.nodes = [];
};
constructor() {
super();
this.nodes = [];
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Push a `node` to this block.
*
* @param {Node} node
* @api public
*/
Root.prototype.__proto__ = Node.prototype;
push(node) {
this.nodes.push(node);
};
/**
* Push a `node` to this block.
*
* @param {Node} node
* @api public
*/
/**
* Unshift a `node` to this block.
*
* @param {Node} node
* @api public
*/
Root.prototype.push = function(node){
this.nodes.push(node);
};
unshift(node) {
this.nodes.unshift(node);
};
/**
* Unshift a `node` to this block.
*
* @param {Node} node
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Root.prototype.unshift = function(node){
this.nodes.unshift(node);
};
clone() {
var clone = new Root();
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
this.nodes.forEach(function (node) {
clone.push(node.clone(clone, clone));
});
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return "root".
*
* @return {String}
* @api public
*/
Root.prototype.clone = function(){
var clone = new Root();
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
this.nodes.forEach(function(node){
clone.push(node.clone(clone, clone));
});
return clone;
};
toString() {
return '[Root]';
};
/**
* Return "root".
*
* @return {String}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Root.prototype.toString = function(){
return '[Root]';
};
toJSON() {
return {
__type: 'Root',
nodes: this.nodes,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Root.prototype.toJSON = function(){
return {
__type: 'Root',
nodes: this.nodes,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};

@@ -15,81 +15,78 @@

/**
* Initialize a new `Selector` with the given `segs`.
*
* @param {Array} segs
* @api public
*/
module.exports = class Selector extends Node {
/**
* Initialize a new `Selector` with the given `segs`.
*
* @param {Array} segs
* @api public
*/
var Selector = module.exports = function Selector(segs){
Node.call(this);
this.inherits = true;
this.segments = segs;
this.optional = false;
};
constructor(segs) {
super();
this.inherits = true;
this.segments = segs;
this.optional = false;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return the selector string.
*
* @return {String}
* @api public
*/
Selector.prototype.__proto__ = Node.prototype;
toString() {
return this.segments.join('') + (this.optional ? ' !optional' : '');
};
/**
* Return the selector string.
*
* @return {String}
* @api public
*/
/**
* Check if this is placeholder selector.
*
* @return {Boolean}
* @api public
*/
Selector.prototype.toString = function(){
return this.segments.join('') + (this.optional ? ' !optional' : '');
};
get isPlaceholder() {
return this.val && ~this.val.substr(0, 2).indexOf('$');
};
/**
* Check if this is placeholder selector.
*
* @return {Boolean}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Selector.prototype.__defineGetter__('isPlaceholder', function(){
return this.val && ~this.val.substr(0, 2).indexOf('$');
});
clone(parent) {
var clone = new Selector;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.inherits = this.inherits;
clone.val = this.val;
clone.segments = this.segments.map(function (node) { return node.clone(parent, clone); });
clone.optional = this.optional;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Selector.prototype.clone = function(parent){
var clone = new Selector;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.inherits = this.inherits;
clone.val = this.val;
clone.segments = this.segments.map(function(node){ return node.clone(parent, clone); });
clone.optional = this.optional;
return clone;
};
toJSON() {
return {
__type: 'Selector',
inherits: this.inherits,
segments: this.segments,
optional: this.optional,
val: this.val,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Selector.prototype.toJSON = function(){
return {
__type: 'Selector',
inherits: this.inherits,
segments: this.segments,
optional: this.optional,
val: this.val,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};

@@ -16,133 +16,130 @@ /*!

/**
* Initialize a new `String` with the given `val`.
*
* @param {String} val
* @param {String} quote
* @api public
*/
module.exports = class String extends Node {
/**
* Initialize a new `String` with the given `val`.
*
* @param {String} val
* @param {String} quote
* @api public
*/
var String = module.exports = function String(val, quote){
Node.call(this);
this.val = val;
this.string = val;
this.prefixed = false;
if (typeof quote !== 'string') {
this.quote = "'";
} else {
this.quote = quote;
constructor(val, quote) {
super();
this.val = val;
this.string = val;
this.prefixed = false;
if (typeof quote !== 'string') {
this.quote = "'";
} else {
this.quote = quote;
}
}
};
/**
* Inherit from `Node.prototype`.
*/
/**
* Return quoted string.
*
* @return {String}
* @api public
*/
String.prototype.__proto__ = Node.prototype;
toString() {
return this.quote + this.val + this.quote;
};
/**
* Return quoted string.
*
* @return {String}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
String.prototype.toString = function(){
return this.quote + this.val + this.quote;
};
clone() {
var clone = new String(this.val, this.quote);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
String.prototype.clone = function(){
var clone = new String(this.val, this.quote);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
toJSON() {
return {
__type: 'String',
val: this.val,
quote: this.quote,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return Boolean based on the length of this string.
*
* @return {Boolean}
* @api public
*/
String.prototype.toJSON = function(){
return {
__type: 'String',
val: this.val,
quote: this.quote,
lineno: this.lineno,
column: this.column,
filename: this.filename
toBoolean() {
return new nodes.Boolean(this.val.length);
};
};
/**
* Return Boolean based on the length of this string.
*
* @return {Boolean}
* @api public
*/
/**
* Coerce `other` to a string.
*
* @param {Node} other
* @return {String}
* @api public
*/
String.prototype.toBoolean = function(){
return nodes.Boolean(this.val.length);
};
coerce(other) {
switch (other.nodeName) {
case 'string':
return other;
case 'expression':
return new String(other.nodes.map(function (node) {
return this.coerce(node).val;
}, this).join(' '));
default:
return new String(other.toString());
}
};
/**
* Coerce `other` to a string.
*
* @param {Node} other
* @return {String}
* @api public
*/
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
String.prototype.coerce = function(other){
switch (other.nodeName) {
case 'string':
return other;
case 'expression':
return new String(other.nodes.map(function(node){
return this.coerce(node).val;
}, this).join(' '));
default:
return new String(other.toString());
}
};
operate(op, right) {
switch (op) {
case '%':
var expr = new nodes.Expression;
expr.push(this);
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
// constructargs
var args = 'expression' == right.nodeName
? utils.unwrap(right).nodes
: [right];
String.prototype.operate = function(op, right){
switch (op) {
case '%':
var expr = new nodes.Expression;
expr.push(this);
// apply
return sprintf.apply(null, [expr].concat(args));
case '+':
var expr = new nodes.Expression;
expr.push(new String(this.val + this.coerce(right).val));
return expr;
default:
return super.operate(op, right);
}
};
// constructargs
var args = 'expression' == right.nodeName
? utils.unwrap(right).nodes
: [right];
// apply
return sprintf.apply(null, [expr].concat(args));
case '+':
var expr = new nodes.Expression;
expr.push(new String(this.val + this.coerce(right).val));
return expr;
default:
return Node.prototype.operate.call(this, op, right);
}
};

@@ -13,64 +13,60 @@ /*!

/**
* Initialize a new supports node.
*
* @param {Expression} condition
* @api public
*/
module.exports = class Supports extends Atrule {
/**
* Initialize a new supports node.
*
* @param {Expression} condition
* @api public
*/
var Supports = module.exports = function Supports(condition){
Atrule.call(this, 'supports');
this.condition = condition;
};
constructor(condition) {
super('supports');
this.condition = condition;
}
/**
* Inherit from `Atrule.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Supports.prototype.__proto__ = Atrule.prototype;
clone(parent) {
var clone = new Supports;
clone.condition = this.condition.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Supports.prototype.clone = function(parent){
var clone = new Supports;
clone.condition = this.condition.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
toJSON() {
return {
__type: 'Supports',
condition: this.condition,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return @supports
*
* @return {String}
* @api public
*/
Supports.prototype.toJSON = function(){
return {
__type: 'Supports',
condition: this.condition,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
toString() {
return '@supports ' + this.condition;
};
};
/**
* Return @supports
*
* @return {String}
* @api public
*/
Supports.prototype.toString = function(){
return '@supports ' + this.condition;
};

@@ -14,59 +14,55 @@

/**
* Initialize a new `Ternary` with `cond`, `trueExpr` and `falseExpr`.
*
* @param {Expression} cond
* @param {Expression} trueExpr
* @param {Expression} falseExpr
* @api public
*/
module.exports = class Ternary extends Node {
/**
* Initialize a new `Ternary` with `cond`, `trueExpr` and `falseExpr`.
*
* @param {Expression} cond
* @param {Expression} trueExpr
* @param {Expression} falseExpr
* @api public
*/
var Ternary = module.exports = function Ternary(cond, trueExpr, falseExpr){
Node.call(this);
this.cond = cond;
this.trueExpr = trueExpr;
this.falseExpr = falseExpr;
};
constructor(cond, trueExpr, falseExpr) {
super();
this.cond = cond;
this.trueExpr = trueExpr;
this.falseExpr = falseExpr;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Ternary.prototype.__proto__ = Node.prototype;
clone(parent) {
var clone = new Ternary();
clone.cond = this.cond.clone(parent, clone);
clone.trueExpr = this.trueExpr.clone(parent, clone);
clone.falseExpr = this.falseExpr.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Ternary.prototype.clone = function(parent){
var clone = new Ternary();
clone.cond = this.cond.clone(parent, clone);
clone.trueExpr = this.trueExpr.clone(parent, clone);
clone.falseExpr = this.falseExpr.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Ternary.prototype.toJSON = function(){
return {
__type: 'Ternary',
cond: this.cond,
trueExpr: this.trueExpr,
falseExpr: this.falseExpr,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'Ternary',
cond: this.cond,
trueExpr: this.trueExpr,
falseExpr: this.falseExpr,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};

@@ -14,54 +14,52 @@

/**
* Initialize a new `UnaryOp` with `op`, and `expr`.
*
* @param {String} op
* @param {Node} expr
* @api public
*/
module.exports = class UnaryOp extends Node {
/**
* Initialize a new `UnaryOp` with `op`, and `expr`.
*
* @param {String} op
* @param {Node} expr
* @api public
*/
var UnaryOp = module.exports = function UnaryOp(op, expr){
Node.call(this);
this.op = op;
this.expr = expr;
};
constructor(op, expr) {
super();
this.op = op;
this.expr = expr;
}
/**
* Inherit from `Node.prototype`.
*/
UnaryOp.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
clone(parent) {
var clone = new UnaryOp(this.op);
clone.expr = this.expr.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
UnaryOp.prototype.clone = function(parent){
var clone = new UnaryOp(this.op);
clone.expr = this.expr.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
toJSON() {
return {
__type: 'UnaryOp',
op: this.op,
expr: this.expr,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
UnaryOp.prototype.toJSON = function(){
return {
__type: 'UnaryOp',
op: this.op,
expr: this.expr,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};

@@ -20,196 +20,192 @@

var FACTOR_TABLE = {
'mm': {val: 1, label: 'mm'},
'cm': {val: 10, label: 'mm'},
'in': {val: 25.4, label: 'mm'},
'pt': {val: 25.4/72, label: 'mm'},
'ms': {val: 1, label: 'ms'},
's': {val: 1000, label: 'ms'},
'Hz': {val: 1, label: 'Hz'},
'kHz': {val: 1000, label: 'Hz'}
'mm': { val: 1, label: 'mm' },
'cm': { val: 10, label: 'mm' },
'in': { val: 25.4, label: 'mm' },
'pt': { val: 25.4 / 72, label: 'mm' },
'ms': { val: 1, label: 'ms' },
's': { val: 1000, label: 'ms' },
'Hz': { val: 1, label: 'Hz' },
'kHz': { val: 1000, label: 'Hz' }
};
/**
* Initialize a new `Unit` with the given `val` and unit `type`
* such as "px", "pt", "in", etc.
*
* @param {String} val
* @param {String} type
* @api public
*/
module.exports = class Unit extends Node {
/**
* Initialize a new `Unit` with the given `val` and unit `type`
* such as "px", "pt", "in", etc.
*
* @param {String} val
* @param {String} type
* @api public
*/
var Unit = module.exports = function Unit(val, type){
Node.call(this);
this.val = val;
this.type = type;
};
constructor(val, type) {
super();
this.val = val;
this.type = type;
}
/**
* Inherit from `Node.prototype`.
*/
/**
* Return Boolean based on the unit value.
*
* @return {Boolean}
* @api public
*/
Unit.prototype.__proto__ = Node.prototype;
/**
* Return Boolean based on the unit value.
*
* @return {Boolean}
* @api public
*/
Unit.prototype.toBoolean = function(){
return nodes.Boolean(this.type
toBoolean() {
return new nodes.Boolean(this.type
? true
: this.val);
};
};
/**
* Return unit string.
*
* @return {String}
* @api public
*/
/**
* Return unit string.
*
* @return {String}
* @api public
*/
Unit.prototype.toString = function(){
return this.val + (this.type || '');
};
toString() {
return this.val + (this.type || '');
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Unit.prototype.clone = function(){
var clone = new Unit(this.val, this.type);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
clone() {
var clone = new Unit(this.val, this.type);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Unit.prototype.toJSON = function(){
return {
__type: 'Unit',
val: this.val,
type: this.type,
lineno: this.lineno,
column: this.column,
filename: this.filename
toJSON() {
return {
__type: 'Unit',
val: this.val,
type: this.type,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Unit.prototype.operate = function(op, right){
var type = this.type || right.first.type;
operate(op, right) {
var type = this.type || right.first.type;
// swap color
if ('rgba' == right.nodeName || 'hsla' == right.nodeName) {
return right.operate(op, this);
}
// operate
if (this.shouldCoerce(op)) {
right = right.first;
// percentages
if ('%' != this.type && ('-' == op || '+' == op) && '%' == right.type) {
right = new Unit(this.val * (right.val / 100), '%');
} else {
right = this.coerce(right);
// swap color
if ('rgba' == right.nodeName || 'hsla' == right.nodeName) {
return right.operate(op, this);
}
switch (op) {
case '-':
return new Unit(this.val - right.val, type);
case '+':
// keyframes interpolation
type = type || (right.type == '%' && right.type);
return new Unit(this.val + right.val, type);
case '/':
return new Unit(this.val / right.val, type);
case '*':
return new Unit(this.val * right.val, type);
case '%':
return new Unit(this.val % right.val, type);
case '**':
return new Unit(Math.pow(this.val, right.val), type);
case '..':
case '...':
var start = this.val
, end = right.val
, expr = new nodes.Expression
, inclusive = '..' == op;
if (start < end) {
do {
expr.push(new nodes.Unit(start));
} while (inclusive ? ++start <= end : ++start < end);
} else {
do {
expr.push(new nodes.Unit(start));
} while (inclusive ? --start >= end : --start > end);
}
return expr;
// operate
if (this.shouldCoerce(op)) {
right = right.first;
// percentages
if ('%' != this.type && ('-' == op || '+' == op) && '%' == right.type) {
right = new Unit(this.val * (right.val / 100), '%');
} else {
right = this.coerce(right);
}
switch (op) {
case '-':
return new Unit(this.val - right.val, type);
case '+':
// keyframes interpolation
type = type || (right.type == '%' && right.type);
return new Unit(this.val + right.val, type);
case '/':
return new Unit(this.val / right.val, type);
case '*':
return new Unit(this.val * right.val, type);
case '%':
return new Unit(this.val % right.val, type);
case '**':
return new Unit(Math.pow(this.val, right.val), type);
case '..':
case '...':
var start = this.val
, end = right.val
, expr = new nodes.Expression
, inclusive = '..' == op;
if (start < end) {
do {
expr.push(new nodes.Unit(start));
} while (inclusive ? ++start <= end : ++start < end);
} else {
do {
expr.push(new nodes.Unit(start));
} while (inclusive ? --start >= end : --start > end);
}
return expr;
}
}
}
return Node.prototype.operate.call(this, op, right);
};
return super.operate(op, right);
};
/**
* Coerce `other` unit to the same type as `this` unit.
*
* Supports:
*
* mm -> cm | in
* cm -> mm | in
* in -> mm | cm
*
* ms -> s
* s -> ms
*
* Hz -> kHz
* kHz -> Hz
*
* @param {Unit} other
* @return {Unit}
* @api public
*/
/**
* Coerce `other` unit to the same type as `this` unit.
*
* Supports:
*
* mm -> cm | in
* cm -> mm | in
* in -> mm | cm
*
* ms -> s
* s -> ms
*
* Hz -> kHz
* kHz -> Hz
*
* @param {Unit} other
* @return {Unit}
* @api public
*/
Unit.prototype.coerce = function(other){
if ('unit' == other.nodeName) {
var a = this
, b = other
, factorA = FACTOR_TABLE[a.type]
, factorB = FACTOR_TABLE[b.type];
coerce(other) {
if ('unit' == other.nodeName) {
var a = this
, b = other
, factorA = FACTOR_TABLE[a.type]
, factorB = FACTOR_TABLE[b.type];
if (factorA && factorB && (factorA.label == factorB.label)) {
var bVal = b.val * (factorB.val / factorA.val);
return new nodes.Unit(bVal, a.type);
if (factorA && factorB && (factorA.label == factorB.label)) {
var bVal = b.val * (factorB.val / factorA.val);
return new nodes.Unit(bVal, a.type);
} else {
return new nodes.Unit(b.val, a.type);
}
} else if ('string' == other.nodeName) {
// keyframes interpolation
if ('%' == other.val) return new nodes.Unit(0, '%');
var val = parseFloat(other.val);
if (isNaN(val)) super.coerce(other);
return new nodes.Unit(val);
} else {
return new nodes.Unit(b.val, a.type);
return super.coerce(other);
}
} else if ('string' == other.nodeName) {
// keyframes interpolation
if ('%' == other.val) return new nodes.Unit(0, '%');
var val = parseFloat(other.val);
if (isNaN(val)) Node.prototype.coerce.call(this, other);
return new nodes.Unit(val);
} else {
return Node.prototype.coerce.call(this, other);
}
};
};

@@ -21,3 +21,3 @@ /*!

var debug = {
lexer: require('debug')('stylus:lexer')
lexer: require('debug')('stylus:lexer')
, selector: require('debug')('stylus:parser:selector')

@@ -31,3 +31,3 @@ };

var selectorTokens = [
'ident'
'ident'
, 'string'

@@ -73,3 +73,3 @@ , 'selector'

// Logical Combinations
'is'
'is'
, 'has'

@@ -149,56 +149,46 @@ , 'where'

/**
* Initialize a new `Parser` with the given `str` and `options`.
*
* @param {String} str
* @param {Object} options
* @api private
*/
module.exports = class Parser {
/**
* Initialize a new `Parser` with the given `str` and `options`.
*
* @param {String} str
* @param {Object} options
* @api private
*/
var Parser = module.exports = function Parser(str, options) {
var self = this;
options = options || {};
Parser.cache = Parser.cache || Parser.getCache(options);
this.hash = Parser.cache.key(str, options);
this.lexer = {};
if (!Parser.cache.has(this.hash)) {
this.lexer = new Lexer(str, options);
}
this.prefix = options.prefix || '';
this.root = options.root || new nodes.Root;
this.state = ['root'];
this.stash = [];
this.parens = 0;
this.css = 0;
this.state.pop = function(){
self.prevState = [].pop.call(this);
constructor(str, options) {
var self = this;
options = options || {};
Parser.cache = Parser.cache || Parser.getCache(options);
this.hash = Parser.cache.key(str, options);
this.lexer = {};
if (!Parser.cache.has(this.hash)) {
this.lexer = new Lexer(str, options);
}
this.prefix = options.prefix || '';
this.root = options.root || new nodes.Root;
this.state = ['root'];
this.stash = [];
this.parens = 0;
this.css = 0;
this.state.pop = function () {
self.prevState = [].pop.call(this);
};
};
};
/**
* Get cache instance.
*
* @param {Object} options
* @return {Object}
* @api private
*/
Parser.getCache = function(options) {
return false === options.cache
? cache(false)
: cache(options.cache || 'memory', options);
};
/**
* Parser prototype.
*/
Parser.prototype = {
/**
* Constructor.
* Get cache instance.
*
* @param {Object} options
* @return {Object}
* @api private
*/
constructor: Parser,
static getCache(options) {
return false === options.cache
? cache(false)
: cache(options.cache || 'memory', options);
};
/**

@@ -211,5 +201,5 @@ * Return current state.

currentState: function() {
currentState() {
return this.state[this.state.length - 1];
},
}

@@ -223,5 +213,5 @@ /**

previousState: function() {
previousState() {
return this.state[this.state.length - 2];
},
}

@@ -235,3 +225,3 @@ /**

parse: function(){
parse() {
var block = this.parent = this.root;

@@ -254,3 +244,3 @@ if (Parser.cache.has(this.hash)) {

return block;
},
}

@@ -264,3 +254,3 @@ /**

error: function(msg){
error(msg) {
var type = this.peek().type

@@ -272,3 +262,3 @@ , val = undefined == this.peek().val

throw new errors.ParseError(msg.replace('{peek}', '"' + type + val + '"'));
},
}

@@ -284,7 +274,7 @@ /**

accept: function(type){
accept(type) {
if (type == this.peek().type) {
return this.next();
}
},
}

@@ -299,3 +289,3 @@ /**

expect: function(type){
expect(type) {
if (type != this.peek().type) {

@@ -305,3 +295,3 @@ this.error('expected "' + type + '", got {peek}');

return this.next();
},
}

@@ -315,3 +305,3 @@ /**

next: function() {
next() {
var tok = this.stash.length

@@ -331,3 +321,3 @@ ? this.stash.pop()

return tok;
},
}

@@ -341,5 +331,5 @@ /**

peek: function() {
peek() {
return this.lexer.peek();
},
}

@@ -354,5 +344,5 @@ /**

lookahead: function(n){
lookahead(n) {
return this.lexer.lookahead(n);
},
}

@@ -367,3 +357,3 @@ /**

isSelectorToken: function(n) {
isSelectorToken(n) {
var la = this.lookahead(n).type;

@@ -382,3 +372,3 @@ switch (la) {

}
},
}

@@ -393,6 +383,6 @@ /**

isPseudoSelector: function(n){
isPseudoSelector(n) {
var val = this.lookahead(n).val;
return val && ~pseudoSelectors.indexOf(val.name);
},
}

@@ -407,3 +397,3 @@ /**

lineContains: function(type){
lineContains(type) {
var i = 1

@@ -416,3 +406,3 @@ , la;

}
},
}

@@ -423,3 +413,3 @@ /**

selectorToken: function() {
selectorToken() {
if (this.isSelectorToken(1)) {

@@ -448,3 +438,3 @@ if ('{' == this.peek().type) {

}
},
}

@@ -458,6 +448,6 @@ /**

skip: function(tokens) {
skip(tokens) {
while (~tokens.indexOf(this.peek().type))
this.next();
},
}

@@ -468,5 +458,5 @@ /**

skipWhitespace: function() {
skipWhitespace() {
this.skip(['space', 'indent', 'outdent', 'newline']);
},
}

@@ -477,6 +467,6 @@ /**

skipNewlines: function() {
skipNewlines() {
while ('newline' == this.peek().type)
this.next();
},
}

@@ -487,6 +477,6 @@ /**

skipSpaces: function() {
skipSpaces() {
while ('space' == this.peek().type)
this.next();
},
}

@@ -497,7 +487,7 @@ /**

skipSpacesAndComments: function() {
skipSpacesAndComments() {
while ('space' == this.peek().type
|| 'comment' == this.peek().type)
this.next();
},
}

@@ -510,6 +500,6 @@ /**

looksLikeFunctionDefinition: function(i) {
looksLikeFunctionDefinition(i) {
return 'indent' == this.lookahead(i).type
|| '{' == this.lookahead(i).type;
},
}

@@ -525,3 +515,3 @@ /**

looksLikeSelector: function(fromProperty) {
looksLikeSelector(fromProperty) {
var i = 1

@@ -540,3 +530,3 @@ , node

&& ('newline' == this.lookahead(i + 1).type
|| ',' == this.lookahead(i + 1).type)) i += 2;
|| ',' == this.lookahead(i + 1).type)) i += 2;

@@ -662,3 +652,3 @@ while (this.isSelectorToken(i)

if (':' == this.lookahead(i++).type
&& !this.lookahead(i-1).space
&& !this.lookahead(i - 1).space
&& this.isPseudoSelector(i))

@@ -691,3 +681,3 @@ return true;

if (';' == this.lookahead(i).type ||
'}' == this.lookahead(i - 1).type)
'}' == this.lookahead(i - 1).type)
return false;

@@ -698,3 +688,3 @@ }

while (!~[
'indent'
'indent'
, 'outdent'

@@ -711,3 +701,3 @@ , 'newline'

return true;
},
}

@@ -719,3 +709,3 @@ /**

looksLikeAttributeSelector: function(n) {
looksLikeAttributeSelector(n) {
var type = this.lookahead(n).type;

@@ -728,3 +718,3 @@ if ('=' == type && this.bracketed) return true;

&& !this.lineContains('=');
},
}

@@ -736,3 +726,3 @@ /**

looksLikeKeyframe: function() {
looksLikeKeyframe() {
var i = 2

@@ -747,7 +737,7 @@ , type;

while ('unit' == this.lookahead(++i).type
|| 'newline' == this.lookahead(i).type) ;
|| 'newline' == this.lookahead(i).type);
type = this.lookahead(i).type;
return 'indent' == type || '{' == type;
}
},
}

@@ -758,3 +748,3 @@ /**

stateAllowsSelector: function() {
stateAllowsSelector() {
switch (this.currentState()) {

@@ -770,3 +760,3 @@ case 'root':

}
},
}

@@ -780,9 +770,9 @@ /**

assignAtblock: function(expr) {
assignAtblock(expr) {
try {
expr.push(this.atblock(expr));
} catch(err) {
} catch (err) {
this.error('invalid right-hand side operand in assignment, got {peek}');
}
},
}

@@ -795,3 +785,3 @@ /**

statement: function() {
statement() {
var stmt = this.stmt()

@@ -817,3 +807,3 @@ , state = this.prevState

while (op =
this.accept('if')
this.accept('if')
|| this.accept('unless')

@@ -844,3 +834,3 @@ || this.accept('for')) {

return stmt;
},
}

@@ -868,3 +858,3 @@ /**

stmt: function() {
stmt() {
var tok = this.peek(), selector;

@@ -945,3 +935,3 @@ switch (tok.type) {

}
},
}

@@ -952,3 +942,3 @@ /**

block: function(node, scope) {
block(node, scope) {
var delim

@@ -1009,3 +999,3 @@ , stmt

return block;
},
}

@@ -1016,7 +1006,7 @@ /**

comment: function(){
comment() {
var node = this.next().val;
this.skipSpaces();
return node;
},
}

@@ -1027,3 +1017,3 @@ /**

for: function() {
for() {
this.expect('for');

@@ -1041,3 +1031,3 @@ var key

return each;
},
}

@@ -1048,3 +1038,3 @@ /**

return: function() {
return() {
this.expect('return');

@@ -1055,3 +1045,3 @@ var expr = this.expression();

: new nodes.Return(expr);
},
}

@@ -1062,3 +1052,3 @@ /**

unless: function() {
unless() {
this.expect('unless');

@@ -1072,3 +1062,3 @@ this.state.push('conditional');

return node;
},
}

@@ -1079,3 +1069,3 @@ /**

if: function() {
if() {
var token = this.expect('if');

@@ -1115,3 +1105,3 @@

return node;
},
}

@@ -1124,3 +1114,3 @@ /**

atblock: function(node){
atblock(node) {
if (!node) this.expect('atblock');

@@ -1132,3 +1122,3 @@ node = new nodes.Atblock;

return node;
},
}

@@ -1139,3 +1129,3 @@ /**

atrule: function(){
atrule() {
var type = this.expect('atrule').val

@@ -1155,3 +1145,3 @@ , node = new nodes.Atrule(type)

return node;
},
}

@@ -1162,10 +1152,10 @@ /**

scope: function(){
scope() {
this.expect('scope');
var selector = this.selectorParts()
.map(function(selector) { return selector.val; })
.map(function (selector) { return selector.val; })
.join('');
this.selectorScope = selector.trim();
return nodes.null;
},
}

@@ -1176,3 +1166,3 @@ /**

supports: function(){
supports() {
this.expect('supports');

@@ -1184,3 +1174,3 @@ var node = new nodes.Supports(this.supportsCondition());

return node;
},
}

@@ -1193,3 +1183,3 @@ /**

supportsCondition: function(){
supportsCondition() {
var node = this.supportsNegation()

@@ -1203,3 +1193,3 @@ || this.supportsOp();

return node;
},
}

@@ -1210,3 +1200,3 @@ /**

supportsNegation: function(){
supportsNegation() {
if (this.accept('not')) {

@@ -1218,3 +1208,3 @@ var node = new nodes.Expression;

}
},
}

@@ -1225,3 +1215,3 @@ /**

supportsOp: function(){
supportsOp() {
var feature = this.supportsFeature()

@@ -1239,3 +1229,3 @@ , op

}
},
}

@@ -1247,3 +1237,3 @@ /**

supportsFeature: function(){
supportsFeature() {
this.skipSpacesAndComments();

@@ -1266,3 +1256,3 @@ if ('(' == this.peek().type) {

}
},
}

@@ -1273,3 +1263,3 @@ /**

extend: function(){
extend() {
var tok = this.expect('extend')

@@ -1296,3 +1286,3 @@ , selectors = []

sel.optional = true;
} while(this.accept(','));
} while (this.accept(','));

@@ -1303,3 +1293,3 @@ node = new nodes.Extend(selectors);

return node;
},
}

@@ -1310,3 +1300,3 @@ /**

media: function() {
media() {
this.expect('media');

@@ -1318,3 +1308,3 @@ this.state.push('atrule');

return media;
},
}

@@ -1325,3 +1315,3 @@ /**

queries: function() {
queries() {
var queries = new nodes.QueryList

@@ -1336,3 +1326,3 @@ , skip = ['comment', 'newline', 'space'];

return queries;
},
}

@@ -1345,3 +1335,3 @@ /**

query: function() {
query() {
var query = new nodes.Query

@@ -1355,3 +1345,3 @@ , expr

&& ('.' == this.lookahead(2).type
|| '[' == this.lookahead(2).type)) {
|| '[' == this.lookahead(2).type)) {
this.cond = true;

@@ -1384,3 +1374,3 @@ expr = this.expression();

return query;
},
}

@@ -1391,3 +1381,3 @@ /**

feature: function() {
feature() {
this.skipSpacesAndComments();

@@ -1407,3 +1397,3 @@ this.expect('(');

return node;
},
}

@@ -1414,3 +1404,3 @@ /**

mozdocument: function(){
mozdocument() {
this.expect('-moz-document');

@@ -1429,3 +1419,3 @@ var mozdocument = new nodes.Atrule('-moz-document')

return mozdocument;
},
}

@@ -1436,7 +1426,7 @@ /**

import: function() {
import() {
this.expect('import');
this.allowPostfix = true;
return new nodes.Import(this.expression(), false);
},
}

@@ -1447,7 +1437,7 @@ /**

require: function() {
require() {
this.expect('require');
this.allowPostfix = true;
return new nodes.Import(this.expression(), true);
},
}

@@ -1458,3 +1448,3 @@ /**

charset: function() {
charset() {
this.expect('charset');

@@ -1464,3 +1454,3 @@ var str = this.expect('string').val;

return new nodes.Charset(str);
},
}

@@ -1471,3 +1461,3 @@ /**

namespace: function() {
namespace() {
var str

@@ -1486,3 +1476,3 @@ , prefix;

return new nodes.Namespace(str, prefix);
},
}

@@ -1493,3 +1483,3 @@ /**

keyframes: function() {
keyframes() {
var tok = this.expect('keyframes')

@@ -1510,3 +1500,3 @@ , keyframes;

return keyframes;
},
}

@@ -1517,5 +1507,5 @@ /**

literal: function() {
literal() {
return this.expect('literal').val;
},
}

@@ -1526,7 +1516,7 @@ /**

id: function() {
id() {
var tok = this.expect('ident');
this.accept('space');
return tok.val;
},
}

@@ -1540,3 +1530,3 @@ /**

ident: function() {
ident() {
var i = 2

@@ -1562,3 +1552,3 @@ , la = this.lookahead(i).type;

while ('=' != this.lookahead(++i).type
&& !~['[', ',', 'newline', 'indent', 'eos'].indexOf(this.lookahead(i).type)) ;
&& !~['[', ',', 'newline', 'indent', 'eos'].indexOf(this.lookahead(i).type));
if ('=' == this.lookahead(i).type) {

@@ -1575,3 +1565,3 @@ this._ident = this.peek();

&& 'selector' != this.lookahead(i).type
&& 'eos' != this.lookahead(i).type) ;
&& 'eos' != this.lookahead(i).type);
if ('=' == this.lookahead(i).type) {

@@ -1649,3 +1639,3 @@ this._ident = this.peek();

}
},
}

@@ -1656,3 +1646,3 @@ /**

interpolate: function() {
interpolate() {
var node

@@ -1671,5 +1661,5 @@ , segs = []

this.state.pop();
} else if (node = this.accept('-')){
} else if (node = this.accept('-')) {
segs.push(new nodes.Literal('-'));
} else if (node = this.accept('ident')){
} else if (node = this.accept('ident')) {
segs.push(node.val);

@@ -1682,3 +1672,3 @@ } else {

return segs;
},
}

@@ -1690,3 +1680,3 @@ /**

property: function() {
property() {
if (this.looksLikeSelector(true)) return this.selector();

@@ -1715,3 +1705,3 @@

return ret;
},
}

@@ -1724,3 +1714,3 @@ /**

selector: function() {
selector() {
var arr

@@ -1755,5 +1745,5 @@ , group = new nodes.Group

return group;
},
}
selectorParts: function(){
selectorParts() {
var tok

@@ -1804,3 +1794,3 @@ , arr = [];

return arr;
},
}

@@ -1811,3 +1801,3 @@ /**

assignment: function() {
assignment() {
var

@@ -1820,3 +1810,3 @@ op,

if (op =
this.accept('=')
this.accept('=')
|| this.accept('?=')

@@ -1857,3 +1847,3 @@ || this.accept('+=')

return node;
},
}

@@ -1865,3 +1855,3 @@ /**

function: function() {
function() {
var parens = 1

@@ -1898,3 +1888,3 @@ , i = 2

}
},
}

@@ -1905,3 +1895,3 @@ /**

url: function() {
url() {
this.expect('function');

@@ -1913,3 +1903,3 @@ this.state.push('function arguments');

return new nodes.Call('url', args);
},
}

@@ -1920,3 +1910,3 @@ /**

functionCall: function() {
functionCall() {
var withBlock = this.accept('+');

@@ -1945,3 +1935,3 @@ if ('url' == this.peek().val.name) return this.url();

return call;
},
}

@@ -1952,3 +1942,3 @@ /**

functionDefinition: function() {
functionDefinition() {
var

@@ -1976,3 +1966,3 @@ tok = this.expect('function'),

return new nodes.Ident(name, fn);
},
}

@@ -1986,3 +1976,3 @@ /**

params: function() {
params() {
var tok

@@ -2004,3 +1994,3 @@ , node

return params;
},
}

@@ -2011,3 +2001,3 @@ /**

args: function() {
args() {
var args = new nodes.Arguments

@@ -2022,3 +2012,3 @@ , keyword;

args.map[keyword] = this.expression();
// arg
// arg
} else {

@@ -2030,3 +2020,3 @@ args.push(this.expression());

return args;
},
}

@@ -2037,3 +2027,3 @@ /**

list: function() {
list() {
var node = this.expression();

@@ -2052,3 +2042,3 @@

return node;
},
}

@@ -2059,3 +2049,3 @@ /**

expression: function() {
expression() {
var node

@@ -2074,3 +2064,3 @@ , expr = new nodes.Expression;

return expr;
},
}

@@ -2082,3 +2072,3 @@ /**

negation: function() {
negation() {
if (this.accept('not')) {

@@ -2088,3 +2078,3 @@ return new nodes.UnaryOp('!', this.negation());

return this.ternary();
},
}

@@ -2095,3 +2085,3 @@ /**

ternary: function() {
ternary() {
var node = this.logical();

@@ -2105,3 +2095,3 @@ if (this.accept('?')) {

return node;
},
}

@@ -2112,3 +2102,3 @@ /**

logical: function() {
logical() {
var op

@@ -2120,3 +2110,3 @@ , node = this.typecheck();

return node;
},
}

@@ -2127,3 +2117,3 @@ /**

typecheck: function() {
typecheck() {
var op

@@ -2138,3 +2128,3 @@ , node = this.equality();

return node;
},
}

@@ -2145,3 +2135,3 @@ /**

equality: function() {
equality() {
var op

@@ -2156,3 +2146,3 @@ , node = this.in();

return node;
},
}

@@ -2163,3 +2153,3 @@ /**

in: function() {
in() {
var node = this.relational();

@@ -2173,3 +2163,3 @@ while (this.accept('in')) {

return node;
},
}

@@ -2180,11 +2170,11 @@ /**

relational: function() {
relational() {
var op
, node = this.range();
while (op =
this.accept('>=')
this.accept('>=')
|| this.accept('<=')
|| this.accept('<')
|| this.accept('>')
) {
) {
this.operand = true;

@@ -2196,3 +2186,3 @@ if (!node) this.error('illegal unary "' + op + '", missing left-hand operand');

return node;
},
}

@@ -2203,3 +2193,3 @@ /**

range: function() {
range() {
var op

@@ -2214,3 +2204,3 @@ , node = this.additive();

return node;
},
}

@@ -2221,3 +2211,3 @@ /**

additive: function() {
additive() {
var op

@@ -2231,3 +2221,3 @@ , node = this.multiplicative();

return node;
},
}

@@ -2238,7 +2228,7 @@ /**

multiplicative: function() {
multiplicative() {
var op
, node = this.defined();
while (op =
this.accept('**')
this.accept('**')
|| this.accept('*')

@@ -2259,3 +2249,3 @@ || this.accept('/')

return node;
},
}

@@ -2267,3 +2257,3 @@ /**

defined: function() {
defined() {
var node = this.unary();

@@ -2275,3 +2265,3 @@ if (this.accept('is defined')) {

return node;
},
}

@@ -2283,7 +2273,7 @@ /**

unary: function() {
unary() {
var op
, node;
if (op =
this.accept('!')
this.accept('!')
|| this.accept('~')

@@ -2300,3 +2290,3 @@ || this.accept('+')

return this.subscript();
},
}

@@ -2308,3 +2298,3 @@ /**

subscript: function() {
subscript() {
var node = this.member()

@@ -2324,3 +2314,3 @@ , id;

return node;
},
}

@@ -2332,3 +2322,3 @@ /**

member: function() {
member() {
var node = this.primary();

@@ -2348,3 +2338,3 @@ if (node) {

return node;
},
}

@@ -2356,3 +2346,3 @@ /**

object: function(){
object() {
var obj = new nodes.Object

@@ -2389,3 +2379,3 @@ , id, val, comma, hash;

return obj;
},
}

@@ -2406,3 +2396,3 @@ /**

primary: function() {
primary() {
var tok;

@@ -2409,0 +2399,0 @@ this.skipSpaces();

@@ -21,227 +21,222 @@

/**
* Expose `Renderer`.
*/
class Renderer extends EventEmitter {
/**
* Initialize a new `Renderer` with the given `str` and `options`.
*
* @param {String} str
* @param {Object} options
* @api public
*/
module.exports = Renderer;
constructor(str, options) {
super();
options = options || {};
options.globals = options.globals || {};
options.functions = options.functions || {};
options.use = options.use || [];
options.use = Array.isArray(options.use) ? options.use : [options.use];
options.imports = [join(__dirname, 'functions/index.styl')].concat(options.imports || []);
options.paths = options.paths || [];
options.filename = options.filename || 'stylus';
options.Evaluator = options.Evaluator || Evaluator;
this.options = options;
this.str = str;
this.events = events;
}
/**
* Initialize a new `Renderer` with the given `str` and `options`.
*
* @param {String} str
* @param {Object} options
* @api public
*/
/**
* Parse and evaluate AST, then callback `fn(err, css, js)`.
*
* @param {Function} fn
* @api public
*/
function Renderer(str, options) {
options = options || {};
options.globals = options.globals || {};
options.functions = options.functions || {};
options.use = options.use || [];
options.use = Array.isArray(options.use) ? options.use : [options.use];
options.imports = [join(__dirname, 'functions/index.styl')].concat(options.imports || []);
options.paths = options.paths || [];
options.filename = options.filename || 'stylus';
options.Evaluator = options.Evaluator || Evaluator;
this.options = options;
this.str = str;
this.events = events;
};
render(fn) {
var parser = this.parser = new Parser(this.str, this.options);
/**
* Inherit from `EventEmitter.prototype`.
*/
// use plugin(s)
for (var i = 0, len = this.options.use.length; i < len; i++) {
this.use(this.options.use[i]);
}
Renderer.prototype.__proto__ = EventEmitter.prototype;
try {
nodes.filename = this.options.filename;
// parse
var ast = parser.parse();
/**
* Expose events explicitly.
*/
// evaluate
this.evaluator = new this.options.Evaluator(ast, this.options);
this.nodes = nodes;
this.evaluator.renderer = this;
ast = this.evaluator.evaluate();
module.exports.events = events;
// normalize
var normalizer = new Normalizer(ast, this.options);
ast = normalizer.normalize();
/**
* Parse and evaluate AST, then callback `fn(err, css, js)`.
*
* @param {Function} fn
* @api public
*/
// compile
var compiler = this.options.sourcemap
? new (require('./visitor/sourcemapper'))(ast, this.options)
: new (require('./visitor/compiler'))(ast, this.options)
, css = compiler.compile();
Renderer.prototype.render = function(fn){
var parser = this.parser = new Parser(this.str, this.options);
// expose sourcemap
if (this.options.sourcemap) this.sourcemap = compiler.map.toJSON();
} catch (err) {
var options = {};
options.input = err.input || this.str;
options.filename = err.filename || this.options.filename;
options.lineno = err.lineno || parser.lexer.lineno;
options.column = err.column || parser.lexer.column;
if (!fn) throw utils.formatException(err, options);
return fn(utils.formatException(err, options));
}
// use plugin(s)
for (var i = 0, len = this.options.use.length; i < len; i++) {
this.use(this.options.use[i]);
// fire `end` event
var listeners = this.listeners('end');
if (fn) listeners.push(fn);
for (var i = 0, len = listeners.length; i < len; i++) {
var ret = listeners[i](null, css);
if (ret) css = ret;
}
if (!fn) return css;
}
try {
nodes.filename = this.options.filename;
// parse
var ast = parser.parse();
/**
* Get dependencies of the compiled file.
*
* @param {String} [filename]
* @return {Array}
* @api public
*/
// evaluate
this.evaluator = new this.options.Evaluator(ast, this.options);
this.nodes = nodes;
this.evaluator.renderer = this;
ast = this.evaluator.evaluate();
deps(filename) {
var opts = utils.merge({ cache: false }, this.options);
if (filename) opts.filename = filename;
// normalize
var normalizer = new Normalizer(ast, this.options);
ast = normalizer.normalize();
var DepsResolver = require('./visitor/deps-resolver')
, parser = new Parser(this.str, opts);
// compile
var compiler = this.options.sourcemap
? new (require('./visitor/sourcemapper'))(ast, this.options)
: new (require('./visitor/compiler'))(ast, this.options)
, css = compiler.compile();
try {
nodes.filename = opts.filename;
// parse
var ast = parser.parse()
, resolver = new DepsResolver(ast, opts);
// expose sourcemap
if (this.options.sourcemap) this.sourcemap = compiler.map.toJSON();
} catch (err) {
var options = {};
options.input = err.input || this.str;
options.filename = err.filename || this.options.filename;
options.lineno = err.lineno || parser.lexer.lineno;
options.column = err.column || parser.lexer.column;
if (!fn) throw utils.formatException(err, options);
return fn(utils.formatException(err, options));
}
// resolve dependencies
return resolver.resolve();
} catch (err) {
var options = {};
options.input = err.input || this.str;
options.filename = err.filename || opts.filename;
options.lineno = err.lineno || parser.lexer.lineno;
options.column = err.column || parser.lexer.column;
throw utils.formatException(err, options);
}
};
// fire `end` event
var listeners = this.listeners('end');
if (fn) listeners.push(fn);
for (var i = 0, len = listeners.length; i < len; i++) {
var ret = listeners[i](null, css);
if (ret) css = ret;
}
if (!fn) return css;
};
/**
* Set option `key` to `val`.
*
* @param {String} key
* @param {Mixed} val
* @return {Renderer} for chaining
* @api public
*/
/**
* Get dependencies of the compiled file.
*
* @param {String} [filename]
* @return {Array}
* @api public
*/
set(key, val) {
this.options[key] = val;
return this;
};
Renderer.prototype.deps = function(filename){
var opts = utils.merge({ cache: false }, this.options);
if (filename) opts.filename = filename;
/**
* Get option `key`.
*
* @param {String} key
* @return {Mixed} val
* @api public
*/
var DepsResolver = require('./visitor/deps-resolver')
, parser = new Parser(this.str, opts);
get(key) {
return this.options[key];
};
try {
nodes.filename = opts.filename;
// parse
var ast = parser.parse()
, resolver = new DepsResolver(ast, opts);
/**
* Include the given `path` to the lookup paths array.
*
* @param {String} path
* @return {Renderer} for chaining
* @api public
*/
// resolve dependencies
return resolver.resolve();
} catch (err) {
var options = {};
options.input = err.input || this.str;
options.filename = err.filename || opts.filename;
options.lineno = err.lineno || parser.lexer.lineno;
options.column = err.column || parser.lexer.column;
throw utils.formatException(err, options);
}
};
include(path) {
this.options.paths.push(path);
return this;
};
/**
* Set option `key` to `val`.
*
* @param {String} key
* @param {Mixed} val
* @return {Renderer} for chaining
* @api public
*/
/**
* Use the given `fn`.
*
* This allows for plugins to alter the renderer in
* any way they wish, exposing paths etc.
*
* @param {Function}
* @return {Renderer} for chaining
* @api public
*/
Renderer.prototype.set = function(key, val){
this.options[key] = val;
return this;
};
use(fn) {
fn.call(this, this);
return this;
};
/**
* Get option `key`.
*
* @param {String} key
* @return {Mixed} val
* @api public
*/
/**
* Define function or global var with the given `name`. Optionally
* the function may accept full expressions, by setting `raw`
* to `true`.
*
* @param {String} name
* @param {Function|Node} fn
* @return {Renderer} for chaining
* @api public
*/
Renderer.prototype.get = function(key){
return this.options[key];
};
define(name, fn, raw) {
fn = utils.coerce(fn, raw);
/**
* Include the given `path` to the lookup paths array.
*
* @param {String} path
* @return {Renderer} for chaining
* @api public
*/
if (fn.nodeName) {
this.options.globals[name] = fn;
return this;
}
Renderer.prototype.include = function(path){
this.options.paths.push(path);
return this;
};
// function
this.options.functions[name] = fn;
if (undefined != raw) fn.raw = raw;
return this;
};
/**
* Use the given `fn`.
*
* This allows for plugins to alter the renderer in
* any way they wish, exposing paths etc.
*
* @param {Function}
* @return {Renderer} for chaining
* @api public
*/
/**
* Import the given `file`.
*
* @param {String} file
* @return {Renderer} for chaining
* @api public
*/
Renderer.prototype.use = function(fn){
fn.call(this, this);
return this;
import(file) {
this.options.imports.push(file);
return this;
};
};
/**
* Define function or global var with the given `name`. Optionally
* the function may accept full expressions, by setting `raw`
* to `true`.
*
* @param {String} name
* @param {Function|Node} fn
* @return {Renderer} for chaining
* @api public
* Expose `Renderer`.
*/
Renderer.prototype.define = function(name, fn, raw){
fn = utils.coerce(fn, raw);
module.exports = Renderer;
if (fn.nodeName) {
this.options.globals[name] = fn;
return this;
}
// function
this.options.functions[name] = fn;
if (undefined != raw) fn.raw = raw;
return this;
};
/**
* Import the given `file`.
*
* @param {String} file
* @return {Renderer} for chaining
* @api public
* Expose events explicitly.
*/
Renderer.prototype.import = function(file){
this.options.imports.push(file);
return this;
};
module.exports.events = events;

@@ -9,251 +9,253 @@ /*!

/**
* Initialize a new `SelectorParser`
* with the given `str` and selectors `stack`.
*
* @param {String} str
* @param {Array} stack
* @param {Array} parts
* @api private
*/
module.exports = class SelectorParser {
/**
* Initialize a new `SelectorParser`
* with the given `str` and selectors `stack`.
*
* @param {String} str
* @param {Array} stack
* @param {Array} parts
* @api private
*/
var SelectorParser = module.exports = function SelectorParser(str, stack, parts) {
this.str = str;
this.stack = stack || [];
this.parts = parts || [];
this.pos = 0;
this.level = 2;
this.nested = true;
this.ignore = false;
};
constructor(str, stack, parts) {
this.str = str;
this.stack = stack || [];
this.parts = parts || [];
this.pos = 0;
this.level = 2;
this.nested = true;
this.ignore = false;
}
/**
* Consume the given `len` and move current position.
*
* @param {Number} len
* @api private
*/
/**
* Consume the given `len` and move current position.
*
* @param {Number} len
* @api private
*/
SelectorParser.prototype.skip = function(len) {
this.str = this.str.substr(len);
this.pos += len;
};
skip(len) {
this.str = this.str.substr(len);
this.pos += len;
};
/**
* Consume spaces.
*/
/**
* Consume spaces.
*/
SelectorParser.prototype.skipSpaces = function() {
while (' ' == this.str[0]) this.skip(1);
};
skipSpaces() {
while (' ' == this.str[0]) this.skip(1);
};
/**
* Fetch next token.
*
* @return {String}
* @api private
*/
/**
* Fetch next token.
*
* @return {String}
* @api private
*/
SelectorParser.prototype.advance = function() {
return this.root()
|| this.relative()
|| this.initial()
|| this.escaped()
|| this.parent()
|| this.partial()
|| this.char();
};
advance() {
return this.root()
|| this.relative()
|| this.initial()
|| this.escaped()
|| this.parent()
|| this.partial()
|| this.char();
};
/**
* '/'
*/
/**
* '/'
*/
SelectorParser.prototype.root = function() {
if (!this.pos && '/' == this.str[0]
&& 'deep' != this.str.slice(1, 5)) {
this.nested = false;
this.skip(1);
}
};
root() {
if (!this.pos && '/' == this.str[0]
&& 'deep' != this.str.slice(1, 5)) {
this.nested = false;
this.skip(1);
}
};
/**
* '../'
*/
/**
* '../'
*/
SelectorParser.prototype.relative = function(multi) {
if ((!this.pos || multi) && '../' == this.str.slice(0, 3)) {
this.nested = false;
this.skip(3);
while (this.relative(true)) this.level++;
if (!this.raw) {
var ret = this.stack[this.stack.length - this.level];
if (ret) {
return ret;
} else {
this.ignore = true;
relative(multi) {
if ((!this.pos || multi) && '../' == this.str.slice(0, 3)) {
this.nested = false;
this.skip(3);
while (this.relative(true)) this.level++;
if (!this.raw) {
var ret = this.stack[this.stack.length - this.level];
if (ret) {
return ret;
} else {
this.ignore = true;
}
}
}
}
};
};
/**
* '~/'
*/
/**
* '~/'
*/
SelectorParser.prototype.initial = function() {
if (!this.pos && '~' == this.str[0] && '/' == this.str[1]) {
this.nested = false;
this.skip(2);
return this.stack[0];
}
};
initial() {
if (!this.pos && '~' == this.str[0] && '/' == this.str[1]) {
this.nested = false;
this.skip(2);
return this.stack[0];
}
};
/**
* '\' ('&' | '^')
*/
/**
* '\' ('&' | '^')
*/
SelectorParser.prototype.escaped = function() {
if ('\\' == this.str[0]) {
var char = this.str[1];
if ('&' == char || '^' == char) {
this.skip(2);
return char;
escaped() {
if ('\\' == this.str[0]) {
var char = this.str[1];
if ('&' == char || '^' == char) {
this.skip(2);
return char;
}
}
}
};
};
/**
* '&'
*/
/**
* '&'
*/
SelectorParser.prototype.parent = function() {
if ('&' == this.str[0]) {
this.nested = false;
parent() {
if ('&' == this.str[0]) {
this.nested = false;
if (!this.pos && (!this.stack.length || this.raw)) {
var i = 0;
while (' ' == this.str[++i]) ;
if (~COMBINATORS.indexOf(this.str[i])) {
this.skip(i + 1);
return;
if (!this.pos && (!this.stack.length || this.raw)) {
var i = 0;
while (' ' == this.str[++i]);
if (~COMBINATORS.indexOf(this.str[i])) {
this.skip(i + 1);
return;
}
}
this.skip(1);
if (!this.raw)
return this.stack[this.stack.length - 1];
}
};
this.skip(1);
if (!this.raw)
return this.stack[this.stack.length - 1];
}
};
/**
* '^[' range ']'
*/
/**
* '^[' range ']'
*/
SelectorParser.prototype.partial = function() {
if ('^' == this.str[0] && '[' == this.str[1]) {
this.skip(2);
this.skipSpaces();
var ret = this.range();
this.skipSpaces();
if (']' != this.str[0]) return '^[';
this.nested = false;
this.skip(1);
if (ret) {
return ret;
} else {
this.ignore = true;
partial() {
if ('^' == this.str[0] && '[' == this.str[1]) {
this.skip(2);
this.skipSpaces();
var ret = this.range();
this.skipSpaces();
if (']' != this.str[0]) return '^[';
this.nested = false;
this.skip(1);
if (ret) {
return ret;
} else {
this.ignore = true;
}
}
}
};
};
/**
* '-'? 0-9+
*/
/**
* '-'? 0-9+
*/
SelectorParser.prototype.number = function() {
var i = 0, ret = '';
if ('-' == this.str[i])
ret += this.str[i++];
number() {
var i = 0, ret = '';
if ('-' == this.str[i])
ret += this.str[i++];
while (this.str.charCodeAt(i) >= 48
&& this.str.charCodeAt(i) <= 57)
ret += this.str[i++];
while (this.str.charCodeAt(i) >= 48
&& this.str.charCodeAt(i) <= 57)
ret += this.str[i++];
if (ret) {
this.skip(i);
return Number(ret);
}
};
if (ret) {
this.skip(i);
return Number(ret);
}
};
/**
* number ('..' number)?
*/
/**
* number ('..' number)?
*/
SelectorParser.prototype.range = function() {
var start = this.number()
, ret;
range() {
var start = this.number()
, ret;
if ('..' == this.str.slice(0, 2)) {
this.skip(2);
var end = this.number()
, len = this.parts.length;
if ('..' == this.str.slice(0, 2)) {
this.skip(2);
var end = this.number()
, len = this.parts.length;
if (start < 0) start = len + start - 1;
if (end < 0) end = len + end - 1;
if (start < 0) start = len + start - 1;
if (end < 0) end = len + end - 1;
if (start > end) {
var tmp = start;
start = end;
end = tmp;
if (start > end) {
var tmp = start;
start = end;
end = tmp;
}
if (end < len - 1) {
ret = this.parts.slice(start, end + 1).map(function (part) {
var selector = new SelectorParser(part, this.stack, this.parts);
selector.raw = true;
return selector.parse();
}, this).map(function (selector) {
return (selector.nested ? ' ' : '') + selector.val;
}).join('').trim();
}
} else {
ret = this.stack[
start < 0 ? this.stack.length + start - 1 : start
];
}
if (end < len - 1) {
ret = this.parts.slice(start, end + 1).map(function(part) {
var selector = new SelectorParser(part, this.stack, this.parts);
selector.raw = true;
return selector.parse();
}, this).map(function(selector) {
return (selector.nested ? ' ' : '') + selector.val;
}).join('').trim();
if (ret) {
return ret;
} else {
this.ignore = true;
}
} else {
ret = this.stack[
start < 0 ? this.stack.length + start - 1 : start
];
}
};
if (ret) {
return ret;
} else {
this.ignore = true;
}
};
/**
* .+
*/
/**
* .+
*/
char() {
var char = this.str[0];
this.skip(1);
return char;
};
SelectorParser.prototype.char = function() {
var char = this.str[0];
this.skip(1);
return char;
};
/**
* Parses the selector.
*
* @return {Object}
* @api private
*/
/**
* Parses the selector.
*
* @return {Object}
* @api private
*/
SelectorParser.prototype.parse = function() {
var val = '';
while (this.str.length) {
val += this.advance() || '';
if (this.ignore) {
val = '';
break;
parse() {
var val = '';
while (this.str.length) {
val += this.advance() || '';
if (this.ignore) {
val = '';
break;
}
}
}
return { val: val.trimRight(), nested: this.nested };
return { val: val.trimRight(), nested: this.nested };
};
};

@@ -14,53 +14,55 @@

/**
* Initialize a new `Frame` with the given `block`.
*
* @param {Block} block
* @api private
*/
module.exports = class Frame {
/**
* Initialize a new `Frame` with the given `block`.
*
* @param {Block} block
* @api private
*/
var Frame = module.exports = function Frame(block) {
this._scope = false === block.scope
? null
: new Scope;
this.block = block;
};
constructor(block) {
this._scope = false === block.scope
? null
: new Scope;
this.block = block;
}
/**
* Return this frame's scope or the parent scope
* for scope-less blocks.
*
* @return {Scope}
* @api public
*/
/**
* Return this frame's scope or the parent scope
* for scope-less blocks.
*
* @return {Scope}
* @api public
*/
Frame.prototype.__defineGetter__('scope', function(){
return this._scope || this.parent.scope;
});
get scope() {
return this._scope || this.parent.scope;
};
/**
* Lookup the given local variable `name`.
*
* @param {String} name
* @return {Node}
* @api private
*/
/**
* Lookup the given local variable `name`.
*
* @param {String} name
* @return {Node}
* @api private
*/
Frame.prototype.lookup = function(name){
return this.scope.lookup(name)
};
lookup(name) {
return this.scope.lookup(name)
};
/**
* Custom inspect.
*
* @return {String}
* @api public
*/
/**
* Custom inspect.
*
* @return {String}
* @api public
*/
Frame.prototype.inspect = function(){
return '[Frame '
+ (false === this.block.scope
inspect() {
return '[Frame '
+ (false === this.block.scope
? 'scope-less'
: this.scope.inspect())
+ ']';
+ ']';
};
};

@@ -8,129 +8,126 @@

/**
* Initialize a new `Stack`.
*
* @api private
*/
module.exports = class Stack extends Array {
/**
* Initialize a new `Stack`.
*
* @api private
*/
var Stack = module.exports = function Stack() {
Array.apply(this, arguments);
};
constructor() {
super()
Array.apply(this, arguments);
}
/**
* Inherit from `Array.prototype`.
*/
/**
* Push the given `frame`.
*
* @param {Frame} frame
* @api public
*/
Stack.prototype.__proto__ = Array.prototype;
push(frame) {
frame.stack = this;
frame.parent = this.currentFrame;
return [].push.apply(this, arguments);
};
/**
* Push the given `frame`.
*
* @param {Frame} frame
* @api public
*/
/**
* Return the current stack `Frame`.
*
* @return {Frame}
* @api private
*/
Stack.prototype.push = function(frame){
frame.stack = this;
frame.parent = this.currentFrame;
return [].push.apply(this, arguments);
};
get currentFrame() {
return this[this.length - 1];
};
/**
* Return the current stack `Frame`.
*
* @return {Frame}
* @api private
*/
/**
* Lookup stack frame for the given `block`.
*
* @param {Block} block
* @return {Frame}
* @api private
*/
Stack.prototype.__defineGetter__('currentFrame', function(){
return this[this.length - 1];
});
/**
* Lookup stack frame for the given `block`.
*
* @param {Block} block
* @return {Frame}
* @api private
*/
Stack.prototype.getBlockFrame = function(block){
for (var i = 0; i < this.length; ++i) {
if (block == this[i].block) {
return this[i];
getBlockFrame(block) {
for (var i = 0; i < this.length; ++i) {
if (block == this[i].block) {
return this[i];
}
}
}
};
};
/**
* Lookup the given local variable `name`, relative
* to the lexical scope of the current frame's `Block`.
*
* When the result of a lookup is an identifier
* a recursive lookup is performed, defaulting to
* returning the identifier itself.
*
* @param {String} name
* @return {Node}
* @api private
*/
/**
* Lookup the given local variable `name`, relative
* to the lexical scope of the current frame's `Block`.
*
* When the result of a lookup is an identifier
* a recursive lookup is performed, defaulting to
* returning the identifier itself.
*
* @param {String} name
* @return {Node}
* @api private
*/
Stack.prototype.lookup = function(name){
var block = this.currentFrame.block
, val
, ret;
lookup(name) {
var block = this.currentFrame.block
, val
, ret;
do {
var frame = this.getBlockFrame(block);
if (frame && (val = frame.lookup(name))) {
return val;
}
} while (block = block.parent);
};
do {
var frame = this.getBlockFrame(block);
if (frame && (val = frame.lookup(name))) {
return val;
}
} while (block = block.parent);
};
/**
* Custom inspect.
*
* @return {String}
* @api private
*/
/**
* Custom inspect.
*
* @return {String}
* @api private
*/
Stack.prototype.inspect = function(){
return this.reverse().map(function(frame){
return frame.inspect();
}).join('\n');
};
inspect() {
return this.reverse().map(function (frame) {
return frame.inspect();
}).join('\n');
};
/**
* Return stack string formatted as:
*
* at <context> (<filename>:<lineno>:<column>)
*
* @return {String}
* @api private
*/
/**
* Return stack string formatted as:
*
* at <context> (<filename>:<lineno>:<column>)
*
* @return {String}
* @api private
*/
Stack.prototype.toString = function(){
var block
, node
, buf = []
, location
, len = this.length;
toString() {
var block
, node
, buf = []
, location
, len = this.length;
while (len--) {
block = this[len].block;
if (node = block.node) {
location = '(' + node.filename + ':' + (node.lineno + 1) + ':' + node.column + ')';
switch (node.nodeName) {
case 'function':
buf.push(' at ' + node.name + '() ' + location);
break;
case 'group':
buf.push(' at "' + node.nodes[0].val + '" ' + location);
break;
while (len--) {
block = this[len].block;
if (node = block.node) {
location = '(' + node.filename + ':' + (node.lineno + 1) + ':' + node.column + ')';
switch (node.nodeName) {
case 'function':
buf.push(' at ' + node.name + '() ' + location);
break;
case 'group':
buf.push(' at "' + node.nodes[0].val + '" ' + location);
break;
}
}
}
}
return buf.join('\n');
return buf.join('\n');
};
};

@@ -8,56 +8,49 @@

/**
* Initialize a new `Scope`.
*
* @api private
*/
module.exports = class Scope {
/**
* Initialize a new `Scope`.
*
* @api private
*/
var Scope = module.exports = function Scope() {
this.locals = {};
};
constructor() {
this.locals = {};
}
/**
* Add `ident` node to the current scope.
*
* @param {Ident} ident
* @api private
*/
/**
* Add `ident` node to the current scope.
*
* @param {Ident} ident
* @api private
*/
Scope.prototype.add = function(ident){
this.locals[ident.name] = ident.val;
};
add(ident) {
this.locals[ident.name] = ident.val;
};
/**
* Lookup the given local variable `name`.
*
* @param {String} name
* @return {Node}
* @api private
*/
/**
* Lookup the given local variable `name`.
*
* @param {String} name
* @return {Node}
* @api private
*/
Scope.prototype.lookup = function(name){
return hasOwnProperty(this.locals, name) ? this.locals[name] : undefined;
};
lookup(name) {
return this.locals.hasOwnProperty(name) ? this.locals[name] : undefined;
};
/**
* Custom inspect.
*
* @return {String}
* @api public
*/
/**
* Custom inspect.
*
* @return {String}
* @api public
*/
Scope.prototype.inspect = function(){
var keys = Object.keys(this.locals).map(function(key){ return '@' + key; });
return '[Scope'
+ (keys.length ? ' ' + keys.join(', ') : '')
+ ']';
inspect() {
var keys = Object.keys(this.locals).map(function (key) { return '@' + key; });
return '[Scope'
+ (keys.length ? ' ' + keys.join(', ') : '')
+ ']';
};
};
/**
* @param {Object} obj
* @param {String} propName
* @returns {Boolean}
*/
function hasOwnProperty(obj, propName) {
return Object.prototype.hasOwnProperty.call(obj, propName);
}

@@ -14,41 +14,43 @@

/**
* Initialize a new `Token` with the given `type` and `val`.
*
* @param {String} type
* @param {Mixed} val
* @api private
*/
exports = module.exports = class Token {
/**
* Initialize a new `Token` with the given `type` and `val`.
*
* @param {String} type
* @param {Mixed} val
* @api private
*/
var Token = exports = module.exports = function Token(type, val) {
this.type = type;
this.val = val;
};
constructor(type, val) {
this.type = type;
this.val = val;
}
/**
* Custom inspect.
*
* @return {String}
* @api public
*/
/**
* Custom inspect.
*
* @return {String}
* @api public
*/
Token.prototype.inspect = function(){
var val = ' ' + inspect(this.val);
return '[Token:' + this.lineno + ':' + this.column + ' '
+ '\x1b[32m' + this.type + '\x1b[0m'
+ '\x1b[33m' + (this.val ? val : '') + '\x1b[0m'
+ ']';
};
inspect() {
var val = ' ' + inspect(this.val);
return '[Token:' + this.lineno + ':' + this.column + ' '
+ '\x1b[32m' + this.type + '\x1b[0m'
+ '\x1b[33m' + (this.val ? val : '') + '\x1b[0m'
+ ']';
};
/**
* Return type or val.
*
* @return {String}
* @api public
*/
/**
* Return type or val.
*
* @return {String}
* @api public
*/
Token.prototype.toString = function(){
return (undefined === this.val
? this.type
: this.val).toString();
toString() {
return (undefined === this.val
? this.type
: this.val).toString();
};
};

@@ -9,6 +9,14 @@

// units found in http://www.w3.org/TR/css3-values
// and in https://www.w3.org/TR/css-values-4
module.exports = [
'em', 'ex', 'ch', 'rem' // relative lengths
, 'vw', 'vh', 'vmin', 'vmax' // relative viewport-percentage lengths
, 'vw', 'svw', 'lvw', 'dvw' // relative viewport-percentage lengths (including de-facto standard)
, 'vh', 'svh', 'lvh', 'dvh'
, 'vi', 'svi', 'lvi', 'dvi'
, 'vb', 'svb', 'lvb', 'dvb'
, 'vmin', 'svmin', 'lvmin', 'dvmin'
, 'vmax', 'svmax', 'lvmax', 'dvmax'
, 'cm', 'mm', 'in', 'pt', 'pc', 'px' // absolute lengths

@@ -15,0 +23,0 @@ , 'deg', 'grad', 'rad', 'turn' // angles

@@ -15,538 +15,543 @@ /*!

/**
* Initialize a new `Compiler` with the given `root` Node
* and the following `options`.
*
* Options:
*
* - `compress` Compress the CSS output (default: false)
*
* @param {Node} root
* @api public
*/
module.exports = class Compiler extends Visitor {
/**
* Initialize a new `Compiler` with the given `root` Node
* and the following `options`.
*
* Options:
*
* - `compress` Compress the CSS output (default: false)
*
* @param {Node} root
* @api public
*/
var Compiler = module.exports = function Compiler(root, options) {
options = options || {};
this.compress = options.compress;
this.firebug = options.firebug;
this.linenos = options.linenos;
this.spaces = options['indent spaces'] || 2;
this.indents = 1;
Visitor.call(this, root);
this.stack = [];
};
constructor(root, options) {
super(root);
options = options || {};
this.compress = options.compress;
this.firebug = options.firebug;
this.linenos = options.linenos;
this.spaces = options['indent spaces'] || 2;
this.indents = 1;
this.stack = [];
}
/**
* Inherit from `Visitor.prototype`.
*/
/**
* Compile to css, and return a string of CSS.
*
* @return {String}
* @api private
*/
Compiler.prototype.__proto__ = Visitor.prototype;
compile() {
return this.visit(this.root);
};
/**
* Compile to css, and return a string of CSS.
*
* @return {String}
* @api private
*/
/**
* Output `str`
*
* @param {String} str
* @param {Node} node
* @return {String}
* @api private
*/
Compiler.prototype.compile = function(){
return this.visit(this.root);
};
out(str, node) {
return str;
};
/**
* Output `str`
*
* @param {String} str
* @param {Node} node
* @return {String}
* @api private
*/
/**
* Return indentation string.
*
* @return {String}
* @api private
*/
Compiler.prototype.out = function(str, node){
return str;
};
get indent() {
if (this.compress) return '';
return new Array(this.indents).join(Array(this.spaces + 1).join(' '));
};
/**
* Return indentation string.
*
* @return {String}
* @api private
*/
/**
* Check if given `node` needs brackets.
*
* @param {Node} node
* @return {Boolean}
* @api private
*/
Compiler.prototype.__defineGetter__('indent', function(){
if (this.compress) return '';
return new Array(this.indents).join(Array(this.spaces + 1).join(' '));
});
needBrackets(node) {
return 1 == this.indents
|| 'atrule' != node.nodeName
|| node.hasOnlyProperties;
};
/**
* Check if given `node` needs brackets.
*
* @param {Node} node
* @return {Boolean}
* @api private
*/
/**
* Visit Root.
*/
Compiler.prototype.needBrackets = function(node){
return 1 == this.indents
|| 'atrule' != node.nodeName
|| node.hasOnlyProperties;
};
visitRoot(block) {
this.buf = '';
for (var i = 0, len = block.nodes.length; i < len; ++i) {
var node = block.nodes[i];
if (this.linenos || this.firebug) this.debugInfo(node);
var ret = this.visit(node);
if (ret) this.buf += this.out(ret + '\n', node);
}
return this.buf;
};
/**
* Visit Root.
*/
/**
* Visit Block.
*/
Compiler.prototype.visitRoot = function(block){
this.buf = '';
for (var i = 0, len = block.nodes.length; i < len; ++i) {
var node = block.nodes[i];
if (this.linenos || this.firebug) this.debugInfo(node);
var ret = this.visit(node);
if (ret) this.buf += this.out(ret + '\n', node);
}
return this.buf;
};
visitBlock(block) {
var node
, separator = this.compress ? '' : '\n'
, needBrackets
, lastPropertyIndex;
/**
* Visit Block.
*/
if (block.hasProperties && !block.lacksRenderedSelectors) {
needBrackets = this.needBrackets(block.node);
Compiler.prototype.visitBlock = function(block){
var node
, separator = this.compress ? '' : '\n'
, needBrackets
, lastPropertyIndex;
if (block.hasProperties && !block.lacksRenderedSelectors) {
needBrackets = this.needBrackets(block.node);
if (this.compress) {
if (this.compress) {
for (var i = block.nodes.length - 1; i >= 0; --i) {
if (block.nodes[i].nodeName === 'property') {
lastPropertyIndex = i;
break;
}
if (block.nodes[i].nodeName === 'property') {
lastPropertyIndex = i;
break;
}
}
}
if (needBrackets) {
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
}
for (var i = 0, len = block.nodes.length; i < len; ++i) {
this.last = lastPropertyIndex === i;
node = block.nodes[i];
switch (node.nodeName) {
case 'null':
case 'expression':
case 'function':
case 'group':
case 'block':
case 'unit':
case 'media':
case 'keyframes':
case 'atrule':
case 'supports':
continue;
// inline comments
case !this.compress && node.inline && 'comment':
this.buf = this.buf.slice(0, -1);
this.buf += this.out(' ' + this.visit(node) + '\n', node);
break;
case 'property':
var ret = this.visit(node) + separator;
this.buf += this.compress ? ret : this.out(ret, node);
break;
default:
this.buf += this.out(this.visit(node) + separator, node);
}
}
if (needBrackets) {
--this.indents;
this.buf += this.out(this.indent + '}' + separator);
}
}
if (needBrackets) {
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
}
// Nesting
for (var i = 0, len = block.nodes.length; i < len; ++i) {
this.last = lastPropertyIndex === i;
node = block.nodes[i];
switch (node.nodeName) {
case 'null':
case 'expression':
case 'function':
case 'group':
case 'block':
case 'unit':
case 'keyframes':
if (this.linenos || this.firebug) this.debugInfo(node);
this.visit(node);
break;
case 'media':
case 'keyframes':
case 'import':
case 'atrule':
case 'supports':
continue;
// inline comments
case !this.compress && node.inline && 'comment':
this.buf = this.buf.slice(0, -1);
this.buf += this.out(' ' + this.visit(node) + '\n', node);
this.visit(node);
break;
case 'property':
var ret = this.visit(node) + separator;
this.buf += this.compress ? ret : this.out(ret, node);
case 'comment':
// only show unsuppressed comments
if (!node.suppress) {
this.buf += this.out(this.indent + this.visit(node) + '\n', node);
}
break;
default:
this.buf += this.out(this.visit(node) + separator, node);
case 'charset':
case 'literal':
case 'namespace':
this.buf += this.out(this.visit(node) + '\n', node);
break;
}
}
if (needBrackets) {
--this.indents;
this.buf += this.out(this.indent + '}' + separator);
}
}
};
// Nesting
for (var i = 0, len = block.nodes.length; i < len; ++i) {
node = block.nodes[i];
switch (node.nodeName) {
case 'group':
case 'block':
case 'keyframes':
if (this.linenos || this.firebug) this.debugInfo(node);
this.visit(node);
break;
case 'media':
case 'import':
case 'atrule':
case 'supports':
this.visit(node);
break;
case 'comment':
// only show unsuppressed comments
if (!node.suppress) {
this.buf += this.out(this.indent + this.visit(node) + '\n', node);
}
break;
case 'charset':
case 'literal':
case 'namespace':
this.buf += this.out(this.visit(node) + '\n', node);
break;
}
}
};
/**
* Visit Keyframes.
*/
/**
* Visit Keyframes.
*/
visitKeyframes(node) {
if (!node.frames) return;
Compiler.prototype.visitKeyframes = function(node){
if (!node.frames) return;
var prefix = 'official' == node.prefix
? ''
: '-' + node.prefix + '-';
var prefix = 'official' == node.prefix
? ''
: '-' + node.prefix + '-';
this.buf += this.out('@' + prefix + 'keyframes '
+ this.visit(node.val)
+ (this.compress ? '{' : ' {\n'), node);
this.buf += this.out('@' + prefix + 'keyframes '
+ this.visit(node.val)
+ (this.compress ? '{' : ' {\n'), node);
this.keyframe = true;
++this.indents;
this.visit(node.block);
--this.indents;
this.keyframe = false;
this.keyframe = true;
++this.indents;
this.visit(node.block);
--this.indents;
this.keyframe = false;
this.buf += this.out('}' + (this.compress ? '' : '\n'));
};
this.buf += this.out('}' + (this.compress ? '' : '\n'));
};
/**
* Visit Media.
*/
/**
* Visit Media.
*/
visitMedia(media) {
var val = media.val;
if (!media.hasOutput || !val.nodes.length) return;
Compiler.prototype.visitMedia = function(media){
var val = media.val;
if (!media.hasOutput || !val.nodes.length) return;
this.buf += this.out('@media ', media);
this.visit(val);
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
this.visit(media.block);
--this.indents;
this.buf += this.out('}' + (this.compress ? '' : '\n'));
};
this.buf += this.out('@media ', media);
this.visit(val);
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
this.visit(media.block);
--this.indents;
this.buf += this.out('}' + (this.compress ? '' : '\n'));
};
/**
* Visit QueryList.
*/
/**
* Visit QueryList.
*/
visitQueryList(queries) {
for (var i = 0, len = queries.nodes.length; i < len; ++i) {
this.visit(queries.nodes[i]);
if (len - 1 != i) this.buf += this.out(',' + (this.compress ? '' : ' '));
}
};
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.out(',' + (this.compress ? '' : ' '));
}
};
/**
* Visit Query.
*/
/**
* Visit Query.
*/
visitQuery(node) {
var len = node.nodes.length;
if (node.predicate) this.buf += this.out(node.predicate + ' ');
if (node.type) this.buf += this.out(node.type + (len ? ' and ' : ''));
for (var i = 0; i < len; ++i) {
this.buf += this.out(this.visit(node.nodes[i]));
if (len - 1 != i) this.buf += this.out(' and ');
}
};
Compiler.prototype.visitQuery = function(node){
var len = node.nodes.length;
if (node.predicate) this.buf += this.out(node.predicate + ' ');
if (node.type) this.buf += this.out(node.type + (len ? ' and ' : ''));
for (var i = 0; i < len; ++i) {
this.buf += this.out(this.visit(node.nodes[i]));
if (len - 1 != i) this.buf += this.out(' and ');
}
};
/**
* Visit Feature.
*/
/**
* Visit Feature.
*/
visitFeature(node) {
if (!node.expr) {
return node.name;
} else if (node.expr.isEmpty) {
return '(' + node.name + ')';
} else {
return '(' + node.name + ':' + (this.compress ? '' : ' ') + this.visit(node.expr) + ')';
}
};
Compiler.prototype.visitFeature = function(node){
if (!node.expr) {
return node.name;
} else if (node.expr.isEmpty) {
return '(' + node.name + ')';
} else {
return '(' + node.name + ':' + (this.compress ? '' : ' ') + this.visit(node.expr) + ')';
}
};
/**
* Visit Import.
*/
/**
* Visit Import.
*/
visitImport(imported) {
this.buf += this.out('@import ' + this.visit(imported.path) + ';\n', imported);
};
Compiler.prototype.visitImport = function(imported){
this.buf += this.out('@import ' + this.visit(imported.path) + ';\n', imported);
};
/**
* Visit Atrule.
*/
/**
* Visit Atrule.
*/
visitAtrule(atrule) {
var newline = this.compress ? '' : '\n';
Compiler.prototype.visitAtrule = function(atrule){
var newline = this.compress ? '' : '\n';
this.buf += this.out(this.indent + '@' + atrule.type, atrule);
this.buf += this.out(this.indent + '@' + atrule.type, atrule);
if (atrule.val) this.buf += this.out(' ' + atrule.val.trim());
if (atrule.val) this.buf += this.out(' ' + atrule.val.trim());
if (atrule.block) {
if (atrule.block.isEmpty) {
this.buf += this.out((this.compress ? '' : ' ') + '{}' + newline);
} else if (atrule.hasOnlyProperties) {
this.visit(atrule.block);
if (atrule.block) {
if (atrule.block.isEmpty) {
this.buf += this.out((this.compress ? '' : ' ') + '{}' + newline);
} else if (atrule.hasOnlyProperties) {
this.visit(atrule.block);
} else {
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
this.visit(atrule.block);
--this.indents;
this.buf += this.out(this.indent + '}' + newline);
}
} else {
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
this.visit(atrule.block);
--this.indents;
this.buf += this.out(this.indent + '}' + newline);
this.buf += this.out(';' + newline);
}
} else {
this.buf += this.out(';' + newline);
}
};
};
/**
* Visit Supports.
*/
/**
* Visit Supports.
*/
Compiler.prototype.visitSupports = function(node){
if (!node.hasOutput) return;
visitSupports(node) {
if (!node.hasOutput) return;
this.buf += this.out(this.indent + '@supports ', node);
this.isCondition = true;
this.buf += this.out(this.visit(node.condition));
this.isCondition = false;
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
this.visit(node.block);
--this.indents;
this.buf += this.out(this.indent + '}' + (this.compress ? '' : '\n'));
},
this.buf += this.out(this.indent + '@supports ', node);
this.isCondition = true;
this.buf += this.out(this.visit(node.condition));
this.isCondition = false;
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
this.visit(node.block);
--this.indents;
this.buf += this.out(this.indent + '}' + (this.compress ? '' : '\n'));
}
/**
* Visit Comment.
*/
/**
* Visit Comment.
*/
Compiler.prototype.visitComment = function(comment){
return this.compress
? comment.suppress
? ''
: comment.str
: comment.str;
};
visitComment(comment) {
return this.compress
? comment.suppress
? ''
: comment.str
: comment.str;
};
/**
* Visit Function.
*/
/**
* Visit Function.
*/
Compiler.prototype.visitFunction = function(fn){
return fn.name;
};
visitFunction(fn) {
return fn.name;
};
/**
* Visit Charset.
*/
/**
* Visit Charset.
*/
Compiler.prototype.visitCharset = function(charset){
return '@charset ' + this.visit(charset.val) + ';';
};
visitCharset(charset) {
return '@charset ' + this.visit(charset.val) + ';';
};
/**
* Visit Namespace.
*/
/**
* Visit Namespace.
*/
Compiler.prototype.visitNamespace = function(namespace){
return '@namespace '
+ (namespace.prefix ? this.visit(namespace.prefix) + ' ' : '')
+ this.visit(namespace.val) + ';';
};
visitNamespace(namespace) {
return '@namespace '
+ (namespace.prefix ? this.visit(namespace.prefix) + ' ' : '')
+ this.visit(namespace.val) + ';';
};
/**
* Visit Literal.
*/
/**
* Visit Literal.
*/
Compiler.prototype.visitLiteral = function(lit){
var val = lit.val;
if (lit.css) val = val.replace(/^ /gm, '');
return val;
};
visitLiteral(lit) {
var val = lit.val;
if (lit.css) val = val.replace(/^ /gm, '');
return val;
};
/**
* Visit Boolean.
*/
/**
* Visit Boolean.
*/
Compiler.prototype.visitBoolean = function(bool){
return bool.toString();
};
visitBoolean(bool) {
return bool.toString();
};
/**
* Visit RGBA.
*/
/**
* Visit RGBA.
*/
Compiler.prototype.visitRGBA = function(rgba){
return rgba.toString();
};
visitRGBA(rgba) {
return rgba.toString();
};
/**
* Visit HSLA.
*/
/**
* Visit HSLA.
*/
Compiler.prototype.visitHSLA = function(hsla){
return hsla.rgba.toString();
};
visitHSLA(hsla) {
return hsla.rgba.toString();
};
/**
* Visit Unit.
*/
/**
* Visit Unit.
*/
Compiler.prototype.visitUnit = function(unit){
var type = unit.type || ''
, n = unit.val
, float = n != (n | 0);
visitUnit(unit) {
var type = unit.type || ''
, n = unit.val
, float = n != (n | 0);
// Compress
if (this.compress) {
// Always return '0' unless the unit is a percentage, time, degree or fraction
if (!(['%', 's', 'ms', 'deg', 'fr'].includes(type)) && 0 == n) return '0';
// Omit leading '0' on floats
if (float && n < 1 && n > -1) {
return n.toString().replace('0.', '.') + type;
// Compress
if (this.compress) {
// Always return '0' unless the unit is a percentage, time, degree or fraction
if (!(['%', 's', 'ms', 'deg', 'fr'].includes(type)) && 0 == n) return '0';
// Omit leading '0' on floats
if (float && n < 1 && n > -1) {
return n.toString().replace('0.', '.') + type;
}
}
}
return (float ? parseFloat(n.toFixed(15)) : n).toString() + type;
};
return (float ? parseFloat(n.toFixed(15)) : n).toString() + type;
};
/**
* Visit Group.
*/
/**
* Visit Group.
*/
Compiler.prototype.visitGroup = function(group){
var stack = this.keyframe ? [] : this.stack
, comma = this.compress ? ',' : ',\n';
visitGroup(group) {
var stack = this.keyframe ? [] : this.stack
, comma = this.compress ? ',' : ',\n';
stack.push(group.nodes);
stack.push(group.nodes);
// selectors
if (group.block.hasProperties) {
var selectors = utils.compileSelectors.call(this, stack)
, len = selectors.length;
// selectors
if (group.block.hasProperties) {
var selectors = utils.compileSelectors.call(this, stack)
, len = selectors.length;
if (len) {
if (this.keyframe) comma = this.compress ? ',' : ', ';
if (len) {
if (this.keyframe) comma = this.compress ? ',' : ', ';
for (var i = 0; i < len; ++i) {
var selector = selectors[i]
, last = (i == len - 1);
for (var i = 0; i < len; ++i) {
var selector = selectors[i]
, last = (i == len - 1);
// keyframe blocks (10%, 20% { ... })
if (this.keyframe) selector = i ? selector.trim() : selector;
// keyframe blocks (10%, 20% { ... })
if (this.keyframe) selector = i ? selector.trim() : selector;
this.buf += this.out(selector + (last ? '' : comma), group.nodes[i]);
this.buf += this.out(selector + (last ? '' : comma), group.nodes[i]);
}
} else {
group.block.lacksRenderedSelectors = true;
}
} else {
group.block.lacksRenderedSelectors = true;
}
}
// output block
this.visit(group.block);
stack.pop();
};
// output block
this.visit(group.block);
stack.pop();
};
/**
* Visit Ident.
*/
/**
* Visit Ident.
*/
Compiler.prototype.visitIdent = function(ident){
return ident.name;
};
visitIdent(ident) {
return ident.name;
};
/**
* Visit String.
*/
/**
* Visit String.
*/
Compiler.prototype.visitString = function(string){
return this.isURL
? string.val
: string.toString();
};
visitString(string) {
return this.isURL
? string.val
: string.toString();
};
/**
* Visit Null.
*/
/**
* Visit Null.
*/
Compiler.prototype.visitNull = function(node){
return '';
};
visitNull(node) {
return '';
};
/**
* Visit Call.
*/
/**
* Visit Call.
*/
Compiler.prototype.visitCall = function(call){
this.isURL = 'url' == call.name;
var args = call.args.nodes.map(function(arg){
return this.visit(arg);
}, this).join(this.compress ? ',' : ', ');
if (this.isURL) args = '"' + args + '"';
this.isURL = false;
return call.name + '(' + args + ')';
};
visitCall(call) {
this.isURL = 'url' == call.name;
var args = call.args.nodes.map(function (arg) {
return this.visit(arg);
}, this).join(this.compress ? ',' : ', ');
if (this.isURL) args = '"' + args + '"';
this.isURL = false;
return call.name + '(' + args + ')';
};
/**
* Visit Expression.
*/
/**
* Visit Expression.
*/
Compiler.prototype.visitExpression = function(expr){
var buf = []
, self = this
, len = expr.nodes.length
, nodes = expr.nodes.map(function(node){ return self.visit(node); });
visitExpression(expr) {
var buf = []
, self = this
, len = expr.nodes.length
, nodes = expr.nodes.map(function (node) { return self.visit(node); });
nodes.forEach(function(node, i){
var last = i == len - 1;
buf.push(node);
if ('/' == nodes[i + 1] || '/' == node) return;
if (last) return;
nodes.forEach(function (node, i) {
var last = i == len - 1;
buf.push(node);
if ('/' == nodes[i + 1] || '/' == node) return;
if (last) return;
var space = self.isURL || (self.isCondition
var space = self.isURL || (self.isCondition
&& (')' == nodes[i + 1] || '(' == node))
? '' : ' ';
buf.push(expr.isList
? (self.compress ? ',' : ', ')
: space);
});
buf.push(expr.isList
? (self.compress ? ',' : ', ')
: space);
});
return buf.join('');
};
return buf.join('');
};
/**
* Visit Arguments.
*/
/**
* Visit Arguments.
*/
Compiler.prototype.visitArguments = Compiler.prototype.visitExpression;
get visitArguments() {
return this.visitExpression;
}
/**
* Visit Property.
*/
/**
* Visit Property.
*/
Compiler.prototype.visitProperty = function(prop){
var val = this.visit(prop.expr).trim()
, name = (prop.name || prop.segments.join(''))
, arr = [];
visitProperty(prop) {
var val = this.visit(prop.expr).trim()
, name = (prop.name || prop.segments.join(''))
, arr = [];
if (name === '@apply') {
if (name === '@apply') {
arr.push(
this.out(this.indent),
this.out(name + ' ', prop),
this.out(val, prop.expr),
this.out(this.compress ? (this.last ? '' : ';') : ';')
);
return arr.join('');
}
arr.push(
this.out(this.indent),
this.out(name + ' ', prop),
this.out(name + (this.compress ? ':' : ': '), prop),
this.out(val, prop.expr),

@@ -556,35 +561,29 @@ this.out(this.compress ? (this.last ? '' : ';') : ';')

return arr.join('');
}
arr.push(
this.out(this.indent),
this.out(name + (this.compress ? ':' : ': '), prop),
this.out(val, prop.expr),
this.out(this.compress ? (this.last ? '' : ';') : ';')
);
return arr.join('');
};
};
/**
* Debug info.
*/
/**
* Debug info.
*/
Compiler.prototype.debugInfo = function(node){
debugInfo(node) {
var path = node.filename == 'stdin' ? 'stdin' : fs.realpathSync(node.filename)
, line = (node.nodes && node.nodes.length ? node.nodes[0].lineno : node.lineno) || 1;
var path = node.filename == 'stdin' ? 'stdin' : fs.realpathSync(node.filename)
, line = (node.nodes && node.nodes.length ? node.nodes[0].lineno : node.lineno) || 1;
if (this.linenos){
this.buf += '\n/* ' + 'line ' + line + ' : ' + path + ' */\n';
if (this.linenos) {
this.buf += '\n/* ' + 'line ' + line + ' : ' + path + ' */\n';
}
if (this.firebug) {
// debug info for firebug, the crazy formatting is needed
path = 'file\\\:\\\/\\\/' + path.replace(/([.:/\\])/g, function (m) {
return '\\' + (m === '\\' ? '\/' : m)
});
line = '\\00003' + line;
this.buf += '\n@media -stylus-debug-info'
+ '{filename{font-family:' + path
+ '}line{font-family:' + line + '}}\n';
}
}
if (this.firebug){
// debug info for firebug, the crazy formatting is needed
path = 'file\\\:\\\/\\\/' + path.replace(/([.:/\\])/g, function(m) {
return '\\' + (m === '\\' ? '\/' : m)
});
line = '\\00003' + line;
this.buf += '\n@media -stylus-debug-info'
+ '{filename{font-family:' + path
+ '}line{font-family:' + line + '}}\n';
}
}
};

@@ -13,161 +13,156 @@

/**
* Initialize a new `DepsResolver` with the given `root` Node
* and the `options`.
*
* @param {Node} root
* @param {Object} options
* @api private
*/
module.exports = class DepsResolver extends Visitor {
/**
* Initialize a new `DepsResolver` with the given `root` Node
* and the `options`.
*
* @param {Node} root
* @param {Object} options
* @api private
*/
var DepsResolver = module.exports = function DepsResolver(root, options) {
this.root = root;
this.filename = options.filename;
this.paths = options.paths || [];
this.paths.push(dirname(options.filename || '.'));
this.options = options;
this.functions = {};
this.deps = [];
};
constructor(root, options) {
super(root)
this.filename = options.filename;
this.paths = options.paths || [];
this.paths.push(dirname(options.filename || '.'));
this.options = options;
this.functions = {};
this.deps = [];
}
/**
* Inherit from `Visitor.prototype`.
*/
DepsResolver.prototype.__proto__ = Visitor.prototype;
visit(node) {
switch (node.nodeName) {
case 'root':
case 'block':
case 'expression':
this.visitRoot(node);
break;
case 'group':
case 'media':
case 'atblock':
case 'atrule':
case 'keyframes':
case 'each':
case 'supports':
this.visit(node.block);
break;
default:
super.visit(node);
}
};
var visit = DepsResolver.prototype.visit;
/**
* Visit Root.
*/
DepsResolver.prototype.visit = function(node) {
switch (node.nodeName) {
case 'root':
case 'block':
case 'expression':
this.visitRoot(node);
break;
case 'group':
case 'media':
case 'atblock':
case 'atrule':
case 'keyframes':
case 'each':
case 'supports':
this.visit(node.block);
break;
default:
visit.call(this, node);
}
};
visitRoot(block) {
for (var i = 0, len = block.nodes.length; i < len; ++i) {
this.visit(block.nodes[i]);
}
};
/**
* Visit Root.
*/
/**
* Visit Ident.
*/
DepsResolver.prototype.visitRoot = function(block) {
for (var i = 0, len = block.nodes.length; i < len; ++i) {
this.visit(block.nodes[i]);
}
};
visitIdent(ident) {
this.visit(ident.val);
};
/**
* Visit Ident.
*/
/**
* Visit If.
*/
DepsResolver.prototype.visitIdent = function(ident) {
this.visit(ident.val);
};
visitIf(node) {
this.visit(node.block);
this.visit(node.cond);
for (var i = 0, len = node.elses.length; i < len; ++i) {
this.visit(node.elses[i]);
}
};
/**
* Visit If.
*/
/**
* Visit Function.
*/
DepsResolver.prototype.visitIf = function(node) {
this.visit(node.block);
this.visit(node.cond);
for (var i = 0, len = node.elses.length; i < len; ++i) {
this.visit(node.elses[i]);
}
};
visitFunction(fn) {
this.functions[fn.name] = fn.block;
};
/**
* Visit Function.
*/
/**
* Visit Call.
*/
DepsResolver.prototype.visitFunction = function(fn) {
this.functions[fn.name] = fn.block;
};
visitCall(call) {
if (call.name in this.functions) this.visit(this.functions[call.name]);
if (call.block) this.visit(call.block);
};
/**
* Visit Call.
*/
/**
* Visit Import.
*/
DepsResolver.prototype.visitCall = function(call) {
if (call.name in this.functions) this.visit(this.functions[call.name]);
if (call.block) this.visit(call.block);
};
visitImport(node) {
// If it's a url() call, skip
if (node.path.first.name === 'url') return;
/**
* Visit Import.
*/
var path = !node.path.first.val.isNull && node.path.first.val || node.path.first.name
, literal, found, oldPath;
DepsResolver.prototype.visitImport = function(node) {
// If it's a url() call, skip
if (node.path.first.name === 'url') return;
if (!path) return;
var path = !node.path.first.val.isNull && node.path.first.val || node.path.first.name
, literal, found, oldPath;
literal = /\.css(?:"|$)/.test(path);
if (!path) return;
// support optional .styl
if (!literal && !/\.styl$/i.test(path)) {
oldPath = path;
path += '.styl';
}
literal = /\.css(?:"|$)/.test(path);
// Lookup
found = utils.find(path, this.paths, this.filename);
// support optional .styl
if (!literal && !/\.styl$/i.test(path)) {
oldPath = path;
path += '.styl';
}
// support optional index
if (!found && oldPath) found = utils.lookupIndex(oldPath, this.paths, this.filename);
// Lookup
found = utils.find(path, this.paths, this.filename);
if (!found) return;
// support optional index
if (!found && oldPath) found = utils.lookupIndex(oldPath, this.paths, this.filename);
this.deps = this.deps.concat(found);
if (!found) return;
if (literal) return;
this.deps = this.deps.concat(found);
// nested imports
for (var i = 0, len = found.length; i < len; ++i) {
var file = found[i]
, dir = dirname(file)
, str = fs.readFileSync(file, 'utf-8')
, block = new nodes.Block
, parser = new Parser(str, utils.merge({ root: block }, this.options));
if (literal) return;
if (!~this.paths.indexOf(dir)) this.paths.push(dir);
// nested imports
for (var i = 0, len = found.length; i < len; ++i) {
var file = found[i]
, dir = dirname(file)
, str = fs.readFileSync(file, 'utf-8')
, block = new nodes.Block
, parser = new Parser(str, utils.merge({ root: block }, this.options));
try {
block = parser.parse();
} catch (err) {
err.filename = file;
err.lineno = parser.lexer.lineno;
err.column = parser.lexer.column;
err.input = str;
throw err;
}
if (!~this.paths.indexOf(dir)) this.paths.push(dir);
try {
block = parser.parse();
} catch (err) {
err.filename = file;
err.lineno = parser.lexer.lineno;
err.column = parser.lexer.column;
err.input = str;
throw err;
this.visit(block);
}
};
this.visit(block);
}
};
/**
* Get dependencies.
*/
/**
* Get dependencies.
*/
DepsResolver.prototype.resolve = function() {
this.visit(this.root);
return utils.uniq(this.deps);
resolve() {
this.visit(this.root);
return utils.uniq(this.deps);
};
};

@@ -106,1509 +106,1506 @@

/**
* Initialize a new `Evaluator` with the given `root` Node
* and the following `options`.
*
* Options:
*
* - `compress` Compress the css output, defaults to false
* - `warn` Warn the user of duplicate function definitions etc
*
* @param {Node} root
* @api private
*/
module.exports = class Evaluator extends Visitor {
/**
* Initialize a new `Evaluator` with the given `root` Node
* and the following `options`.
*
* Options:
*
* - `compress` Compress the css output, defaults to false
* - `warn` Warn the user of duplicate function definitions etc
*
* @param {Node} root
* @api private
*/
var Evaluator = module.exports = function Evaluator(root, options) {
options = options || {};
Visitor.call(this, root);
var functions = this.functions = options.functions || {};
this.stack = new Stack;
this.imports = options.imports || [];
this.globals = options.globals || {};
this.paths = options.paths || [];
this.prefix = options.prefix || '';
this.filename = options.filename;
this.includeCSS = options['include css'];
this.resolveURL = functions.url
&& 'resolver' == functions.url.name
&& functions.url.options;
this.paths.push(dirname(options.filename || '.'));
this.stack.push(this.global = new Frame(root));
this.warnings = options.warn;
this.options = options;
this.calling = []; // TODO: remove, use stack
this.importStack = [];
this.requireHistory = {};
this.return = 0;
};
constructor(root, options) {
super(root);
options = options || {};
var functions = this.functions = options.functions || {};
this.stack = new Stack;
this.imports = options.imports || [];
this.globals = options.globals || {};
this.paths = options.paths || [];
this.prefix = options.prefix || '';
this.filename = options.filename;
this.includeCSS = options['include css'];
this.resolveURL = functions.url
&& 'resolver' == functions.url.name
&& functions.url.options;
this.paths.push(dirname(options.filename || '.'));
this.stack.push(this.global = new Frame(root));
this.warnings = options.warn;
this.options = options;
this.calling = []; // TODO: remove, use stack
this.importStack = [];
this.requireHistory = {};
this.return = 0;
}
/**
* Inherit from `Visitor.prototype`.
*/
/**
* Proxy visit to expose node line numbers.
*
* @param {Node} node
* @return {Node}
* @api private
*/
Evaluator.prototype.__proto__ = Visitor.prototype;
/**
* Proxy visit to expose node line numbers.
*
* @param {Node} node
* @return {Node}
* @api private
*/
var visit = Visitor.prototype.visit;
Evaluator.prototype.visit = function(node){
try {
return visit.call(this, node);
} catch (err) {
if (err.filename) throw err;
err.lineno = node.lineno;
err.column = node.column;
err.filename = node.filename;
err.stylusStack = this.stack.toString();
visit(node) {
try {
err.input = fs.readFileSync(err.filename, 'utf8');
return super.visit(node);
} catch (err) {
// ignore
if (err.filename) throw err;
err.lineno = node.lineno;
err.column = node.column;
err.filename = node.filename;
err.stylusStack = this.stack.toString();
try {
err.input = fs.readFileSync(err.filename, 'utf8');
} catch (err) {
// ignore
}
throw err;
}
throw err;
}
};
};
/**
* Perform evaluation setup:
*
* - populate global scope
* - iterate imports
*
* @api private
*/
/**
* Perform evaluation setup:
*
* - populate global scope
* - iterate imports
*
* @api private
*/
Evaluator.prototype.setup = function(){
var root = this.root;
var imports = [];
setup() {
var root = this.root;
var imports = [];
this.populateGlobalScope();
this.imports.forEach(function(file){
var expr = new nodes.Expression;
expr.push(new nodes.String(file));
imports.push(new nodes.Import(expr));
}, this);
this.populateGlobalScope();
this.imports.forEach(function (file) {
var expr = new nodes.Expression;
expr.push(new nodes.String(file));
imports.push(new nodes.Import(expr));
}, this);
root.nodes = imports.concat(root.nodes);
};
root.nodes = imports.concat(root.nodes);
};
/**
* Populate the global scope with:
*
* - css colors
* - user-defined globals
*
* @api private
*/
/**
* Populate the global scope with:
*
* - css colors
* - user-defined globals
*
* @api private
*/
Evaluator.prototype.populateGlobalScope = function(){
var scope = this.global.scope;
populateGlobalScope() {
var scope = this.global.scope;
// colors
Object.keys(colors).forEach(function(name){
var color = colors[name]
, rgba = new nodes.RGBA(color[0], color[1], color[2], color[3])
, node = new nodes.Ident(name, rgba);
rgba.name = name;
scope.add(node);
});
// colors
Object.keys(colors).forEach(function (name) {
var color = colors[name]
, rgba = new nodes.RGBA(color[0], color[1], color[2], color[3])
, node = new nodes.Ident(name, rgba);
rgba.name = name;
scope.add(node);
});
// expose url function
scope.add(new nodes.Ident(
'embedurl',
new nodes.Function('embedurl', require('../functions/url')({
limit: false
}))
));
// expose url function
scope.add(new nodes.Ident(
'embedurl',
new nodes.Function('embedurl', require('../functions/url')({
limit: false
}))
));
// user-defined globals
var globals = this.globals;
Object.keys(globals).forEach(function(name){
var val = globals[name];
if (!val.nodeName) val = new nodes.Literal(val);
scope.add(new nodes.Ident(name, val));
});
};
// user-defined globals
var globals = this.globals;
Object.keys(globals).forEach(function (name) {
var val = globals[name];
if (!val.nodeName) val = new nodes.Literal(val);
scope.add(new nodes.Ident(name, val));
});
};
/**
* Evaluate the tree.
*
* @return {Node}
* @api private
*/
/**
* Evaluate the tree.
*
* @return {Node}
* @api private
*/
Evaluator.prototype.evaluate = function(){
debug('eval %s', this.filename);
this.setup();
return this.visit(this.root);
};
evaluate() {
debug('eval %s', this.filename);
this.setup();
return this.visit(this.root);
};
/**
* Visit Group.
*/
/**
* Visit Group.
*/
Evaluator.prototype.visitGroup = function(group){
group.nodes = group.nodes.map(function(selector){
selector.val = this.interpolate(selector);
debug('ruleset %s', selector.val);
return selector;
}, this);
visitGroup(group) {
group.nodes = group.nodes.map(function (selector) {
selector.val = this.interpolate(selector);
debug('ruleset %s', selector.val);
return selector;
}, this);
group.block = this.visit(group.block);
return group;
};
group.block = this.visit(group.block);
return group;
};
/**
* Visit Return.
*/
/**
* Visit Return.
*/
Evaluator.prototype.visitReturn = function(ret){
ret.expr = this.visit(ret.expr);
throw ret;
};
visitReturn(ret) {
ret.expr = this.visit(ret.expr);
throw ret;
};
/**
* Visit Media.
*/
/**
* Visit Media.
*/
Evaluator.prototype.visitMedia = function(media){
media.block = this.visit(media.block);
media.val = this.visit(media.val);
return media;
};
visitMedia(media) {
media.block = this.visit(media.block);
media.val = this.visit(media.val);
return media;
};
/**
* Visit QueryList.
*/
/**
* Visit QueryList.
*/
Evaluator.prototype.visitQueryList = function(queries){
var val, query;
queries.nodes.forEach(this.visit, this);
visitQueryList(queries) {
var val, query;
queries.nodes.forEach(this.visit, this);
if (1 == queries.nodes.length) {
query = queries.nodes[0];
if (val = this.lookup(query.type)) {
val = val.first.string;
if (!val) return queries;
var Parser = require('../parser')
, parser = new Parser(val, this.options);
queries = this.visit(parser.queries());
if (1 == queries.nodes.length) {
query = queries.nodes[0];
if (val = this.lookup(query.type)) {
val = val.first.string;
if (!val) return queries;
var Parser = require('../parser')
, parser = new Parser(val, this.options);
queries = this.visit(parser.queries());
}
}
}
return queries;
};
return queries;
};
/**
* Visit Query.
*/
/**
* Visit Query.
*/
Evaluator.prototype.visitQuery = function(node){
node.predicate = this.visit(node.predicate);
node.type = this.visit(node.type);
node.nodes.forEach(this.visit, this);
return node;
};
visitQuery(node) {
node.predicate = this.visit(node.predicate);
node.type = this.visit(node.type);
node.nodes.forEach(this.visit, this);
return node;
};
/**
* Visit Feature.
*/
/**
* Visit Feature.
*/
Evaluator.prototype.visitFeature = function(node){
node.name = this.interpolate(node);
if (node.expr) {
this.return++;
node.expr = this.visit(node.expr);
this.return--;
}
return node;
};
visitFeature(node) {
node.name = this.interpolate(node);
if (node.expr) {
this.return++;
node.expr = this.visit(node.expr);
this.return--;
}
return node;
};
/**
* Visit Object.
*/
/**
* Visit Object.
*/
Evaluator.prototype.visitObject = function(obj){
for (var key in obj.vals) {
obj.vals[key] = this.visit(obj.vals[key]);
}
return obj;
};
visitObject(obj) {
for (var key in obj.vals) {
obj.vals[key] = this.visit(obj.vals[key]);
}
return obj;
};
/**
* Visit Member.
*/
/**
* Visit Member.
*/
Evaluator.prototype.visitMember = function(node){
var left = node.left
, right = node.right
, obj = this.visit(left).first;
visitMember(node) {
var left = node.left
, right = node.right
, obj = this.visit(left).first;
if ('object' != obj.nodeName) {
throw new Error(left.toString() + ' has no property .' + right);
}
if (node.val) {
this.return++;
obj.set(right.name, this.visit(node.val));
this.return--;
}
return obj.get(right.name);
};
if ('object' != obj.nodeName) {
throw new Error(left.toString() + ' has no property .' + right);
}
if (node.val) {
this.return++;
obj.set(right.name, this.visit(node.val));
this.return--;
}
return obj.get(right.name);
};
/**
* Visit Keyframes.
*/
/**
* Visit Keyframes.
*/
Evaluator.prototype.visitKeyframes = function(keyframes){
var val;
if (keyframes.fabricated) return keyframes;
keyframes.val = this.interpolate(keyframes).trim();
if (val = this.lookup(keyframes.val)) {
keyframes.val = val.first.string || val.first.name;
}
keyframes.block = this.visit(keyframes.block);
visitKeyframes(keyframes) {
var val;
if (keyframes.fabricated) return keyframes;
keyframes.val = this.interpolate(keyframes).trim();
if (val = this.lookup(keyframes.val)) {
keyframes.val = val.first.string || val.first.name;
}
keyframes.block = this.visit(keyframes.block);
if ('official' != keyframes.prefix) return keyframes;
if ('official' != keyframes.prefix) return keyframes;
this.vendors.forEach(function(prefix){
// IE never had prefixes for keyframes
if ('ms' == prefix) return;
var node = keyframes.clone();
node.val = keyframes.val;
node.prefix = prefix;
node.block = keyframes.block;
node.fabricated = true;
this.currentBlock.push(node);
}, this);
this.vendors.forEach(function (prefix) {
// IE never had prefixes for keyframes
if ('ms' == prefix) return;
var node = keyframes.clone();
node.val = keyframes.val;
node.prefix = prefix;
node.block = keyframes.block;
node.fabricated = true;
this.currentBlock.push(node);
}, this);
return nodes.null;
};
return nodes.null;
};
/**
* Visit Function.
*/
/**
* Visit Function.
*/
Evaluator.prototype.visitFunction = function(fn){
// check local
var local = this.stack.currentFrame.scope.lookup(fn.name);
if (local) this.warn('local ' + local.nodeName + ' "' + fn.name + '" previously defined in this scope');
visitFunction(fn) {
// check local
var local = this.stack.currentFrame.scope.lookup(fn.name);
if (local) this.warn('local ' + local.nodeName + ' "' + fn.name + '" previously defined in this scope');
// user-defined
var user = this.functions[fn.name];
if (user) this.warn('user-defined function "' + fn.name + '" is already defined');
// user-defined
var user = this.functions[fn.name];
if (user) this.warn('user-defined function "' + fn.name + '" is already defined');
// BIF
var bif = bifs[fn.name];
if (bif) this.warn('built-in function "' + fn.name + '" is already defined');
// BIF
var bif = bifs[fn.name];
if (bif) this.warn('built-in function "' + fn.name + '" is already defined');
return fn;
};
return fn;
};
/**
* Visit Each.
*/
/**
* Visit Each.
*/
Evaluator.prototype.visitEach = function(each){
this.return++;
var expr = utils.unwrap(this.visit(each.expr))
, len = expr.nodes.length
, val = new nodes.Ident(each.val)
, key = new nodes.Ident(each.key || '__index__')
, scope = this.currentScope
, block = this.currentBlock
, vals = []
, self = this
, body
, obj;
this.return--;
visitEach(each) {
this.return++;
var expr = utils.unwrap(this.visit(each.expr))
, len = expr.nodes.length
, val = new nodes.Ident(each.val)
, key = new nodes.Ident(each.key || '__index__')
, scope = this.currentScope
, block = this.currentBlock
, vals = []
, self = this
, body
, obj;
this.return--;
each.block.scope = false;
each.block.scope = false;
function visitBody(key, val) {
scope.add(val);
scope.add(key);
body = self.visit(each.block.clone());
vals = vals.concat(body.nodes);
}
function visitBody(key, val) {
scope.add(val);
scope.add(key);
body = self.visit(each.block.clone());
vals = vals.concat(body.nodes);
}
// for prop in obj
if (1 == len && 'object' == expr.nodes[0].nodeName) {
obj = expr.nodes[0];
for (var prop in obj.vals) {
val.val = new nodes.String(prop);
key.val = obj.get(prop);
visitBody(key, val);
// for prop in obj
if (1 == len && 'object' == expr.nodes[0].nodeName) {
obj = expr.nodes[0];
for (var prop in obj.vals) {
val.val = new nodes.String(prop);
key.val = obj.get(prop);
visitBody(key, val);
}
} else {
for (var i = 0; i < len; ++i) {
val.val = expr.nodes[i];
key.val = new nodes.Unit(i);
visitBody(key, val);
}
}
} else {
for (var i = 0; i < len; ++i) {
val.val = expr.nodes[i];
key.val = new nodes.Unit(i);
visitBody(key, val);
}
}
this.mixin(vals, block);
return vals[vals.length - 1] || nodes.null;
};
this.mixin(vals, block);
return vals[vals.length - 1] || nodes.null;
};
/**
* Visit Call.
*/
/**
* Visit Call.
*/
Evaluator.prototype.visitCall = function(call){
debug('call %s', call);
var fn = this.lookup(call.name)
, literal
, ret;
visitCall(call) {
debug('call %s', call);
var fn = this.lookup(call.name)
, literal
, ret;
// url()
this.ignoreColors = 'url' == call.name;
// url()
this.ignoreColors = 'url' == call.name;
// Variable function
if (fn && 'expression' == fn.nodeName) {
fn = fn.nodes[0];
}
// Variable function
if (fn && 'expression' == fn.nodeName) {
fn = fn.nodes[0];
}
// Not a function? try user-defined or built-ins
if (fn && 'function' != fn.nodeName) {
fn = this.lookupFunction(call.name);
}
// Not a function? try user-defined or built-ins
if (fn && 'function' != fn.nodeName) {
fn = this.lookupFunction(call.name);
}
// Undefined function? render literal CSS
if (!fn || fn.nodeName != 'function') {
debug('%s is undefined', call);
// Special case for `calc`
if ('calc' == this.unvendorize(call.name)) {
literal = call.args.nodes && call.args.nodes[0];
if (literal) ret = new nodes.Literal(call.name + literal);
} else {
ret = this.literalCall(call);
// Undefined function? render literal CSS
if (!fn || fn.nodeName != 'function') {
debug('%s is undefined', call);
// Special case for `calc`
if ('calc' == this.unvendorize(call.name)) {
literal = call.args.nodes && call.args.nodes[0];
if (literal) ret = new nodes.Literal(call.name + literal);
} else {
ret = this.literalCall(call);
}
this.ignoreColors = false;
return ret;
}
this.ignoreColors = false;
return ret;
}
this.calling.push(call.name);
this.calling.push(call.name);
// Massive stack
if (this.calling.length > 200) {
throw new RangeError('Maximum stylus call stack size exceeded');
}
// Massive stack
if (this.calling.length > 200) {
throw new RangeError('Maximum stylus call stack size exceeded');
}
// First node in expression
if ('expression' == fn.nodeName) fn = fn.first;
// First node in expression
if ('expression' == fn.nodeName) fn = fn.first;
// Evaluate arguments
this.return++;
var args = this.visit(call.args);
// Evaluate arguments
this.return++;
var args = this.visit(call.args);
for (var key in args.map) {
args.map[key] = this.visit(args.map[key].clone());
}
this.return--;
for (var key in args.map) {
args.map[key] = this.visit(args.map[key].clone());
}
this.return--;
// Built-in
if (fn.fn) {
debug('%s is built-in', call);
ret = this.invokeBuiltin(fn.fn, args);
// User-defined
} else if ('function' == fn.nodeName) {
debug('%s is user-defined', call);
// Evaluate mixin block
if (call.block) call.block = this.visit(call.block);
ret = this.invokeFunction(fn, args, call.block);
}
// Built-in
if (fn.fn) {
debug('%s is built-in', call);
ret = this.invokeBuiltin(fn.fn, args);
// User-defined
} else if ('function' == fn.nodeName) {
debug('%s is user-defined', call);
// Evaluate mixin block
if (call.block) call.block = this.visit(call.block);
ret = this.invokeFunction(fn, args, call.block);
}
this.calling.pop();
this.ignoreColors = false;
return ret;
};
this.calling.pop();
this.ignoreColors = false;
return ret;
};
/**
* Visit Ident.
*/
/**
* Visit Ident.
*/
Evaluator.prototype.visitIdent = function(ident){
var prop;
// Property lookup
if (ident.property) {
if (prop = this.lookupProperty(ident.name)) {
return this.visit(prop.expr.clone());
visitIdent(ident) {
var prop;
// Property lookup
if (ident.property) {
if (prop = this.lookupProperty(ident.name)) {
return this.visit(prop.expr.clone());
}
return nodes.null;
// Lookup
} else if (ident.val.isNull) {
var val = this.lookup(ident.name);
// Object or Block mixin
if (val && ident.mixin) this.mixinNode(val);
return val ? this.visit(val) : ident;
// Assign
} else {
this.return++;
ident.val = this.visit(ident.val);
this.return--;
this.currentScope.add(ident);
return ident.val;
}
return nodes.null;
// Lookup
} else if (ident.val.isNull) {
var val = this.lookup(ident.name);
// Object or Block mixin
if (val && ident.mixin) this.mixinNode(val);
return val ? this.visit(val) : ident;
// Assign
} else {
this.return++;
ident.val = this.visit(ident.val);
this.return--;
this.currentScope.add(ident);
return ident.val;
}
};
};
/**
* Visit BinOp.
*/
/**
* Visit BinOp.
*/
Evaluator.prototype.visitBinOp = function(binop){
// Special-case "is defined" pseudo binop
if ('is defined' == binop.op) return this.isDefined(binop.left);
visitBinOp(binop) {
// Special-case "is defined" pseudo binop
if ('is defined' == binop.op) return this.isDefined(binop.left);
this.return++;
// Visit operands
var op = binop.op
, left = this.visit(binop.left)
, right = ('||' == op || '&&' == op)
? binop.right : this.visit(binop.right);
this.return++;
// Visit operands
var op = binop.op
, left = this.visit(binop.left)
, right = ('||' == op || '&&' == op)
? binop.right : this.visit(binop.right);
// HACK: ternary
var val = binop.val
? this.visit(binop.val)
: null;
this.return--;
// HACK: ternary
var val = binop.val
? this.visit(binop.val)
: null;
this.return--;
// Operate
try {
return this.visit(left.operate(op, right, val));
} catch (err) {
// disregard coercion issues in equality
// checks, and simply return false
if ('CoercionError' == err.name) {
switch (op) {
case '==':
return nodes.false;
case '!=':
return nodes.true;
// Operate
try {
return this.visit(left.operate(op, right, val));
} catch (err) {
// disregard coercion issues in equality
// checks, and simply return false
if ('CoercionError' == err.name) {
switch (op) {
case '==':
return nodes.false;
case '!=':
return nodes.true;
}
}
throw err;
}
throw err;
}
};
};
/**
* Visit UnaryOp.
*/
/**
* Visit UnaryOp.
*/
Evaluator.prototype.visitUnaryOp = function(unary){
var op = unary.op
, node = this.visit(unary.expr);
visitUnaryOp(unary) {
var op = unary.op
, node = this.visit(unary.expr);
if ('!' != op) {
node = node.first.clone();
utils.assertType(node, 'unit');
}
if ('!' != op) {
node = node.first.clone();
utils.assertType(node, 'unit');
}
switch (op) {
case '-':
node.val = -node.val;
break;
case '+':
node.val = +node.val;
break;
case '~':
node.val = ~node.val;
break;
case '!':
return node.toBoolean().negate();
}
switch (op) {
case '-':
node.val = -node.val;
break;
case '+':
node.val = +node.val;
break;
case '~':
node.val = ~node.val;
break;
case '!':
return node.toBoolean().negate();
}
return node;
};
return node;
};
/**
* Visit TernaryOp.
*/
/**
* Visit TernaryOp.
*/
Evaluator.prototype.visitTernary = function(ternary){
var ok = this.visit(ternary.cond).toBoolean();
return ok.isTrue
? this.visit(ternary.trueExpr)
: this.visit(ternary.falseExpr);
};
visitTernary(ternary) {
var ok = this.visit(ternary.cond).toBoolean();
return ok.isTrue
? this.visit(ternary.trueExpr)
: this.visit(ternary.falseExpr);
};
/**
* Visit Expression.
*/
/**
* Visit Expression.
*/
Evaluator.prototype.visitExpression = function(expr){
for (var i = 0, len = expr.nodes.length; i < len; ++i) {
expr.nodes[i] = this.visit(expr.nodes[i]);
}
visitExpression(expr) {
for (var i = 0, len = expr.nodes.length; i < len; ++i) {
expr.nodes[i] = this.visit(expr.nodes[i]);
}
// support (n * 5)px etc
if (this.castable(expr)) expr = this.cast(expr);
// support (n * 5)px etc
if (this.castable(expr)) expr = this.cast(expr);
return expr;
};
return expr;
};
/**
* Visit Arguments.
*/
/**
* Visit Arguments.
*/
Evaluator.prototype.visitArguments = Evaluator.prototype.visitExpression;
get visitArguments() {
return this.visitExpression;
}
/**
* Visit Property.
*/
/**
* Visit Property.
*/
Evaluator.prototype.visitProperty = function(prop){
var name = this.interpolate(prop)
, fn = this.lookup(name)
, call = fn && 'function' == fn.first.nodeName
, literal = ~this.calling.indexOf(name)
, _prop = this.property;
visitProperty(prop) {
var name = this.interpolate(prop)
, fn = this.lookup(name)
, call = fn && 'function' == fn.first.nodeName
, literal = ~this.calling.indexOf(name)
, _prop = this.property;
// Function of the same name
if (call && !literal && !prop.literal) {
var args = nodes.Arguments.fromExpression(utils.unwrap(prop.expr.clone()));
prop.name = name;
this.property = prop;
this.return++;
this.property.expr = this.visit(prop.expr);
this.return--;
var ret = this.visit(new nodes.Call(name, args));
this.property = _prop;
return ret;
// Regular property
} else {
this.return++;
prop.name = name;
prop.literal = true;
this.property = prop;
prop.expr = this.visit(prop.expr);
this.property = _prop;
this.return--;
return prop;
}
};
// Function of the same name
if (call && !literal && !prop.literal) {
var args = nodes.Arguments.fromExpression(utils.unwrap(prop.expr.clone()));
prop.name = name;
this.property = prop;
this.return++;
this.property.expr = this.visit(prop.expr);
this.return--;
var ret = this.visit(new nodes.Call(name, args));
this.property = _prop;
return ret;
// Regular property
} else {
this.return++;
prop.name = name;
prop.literal = true;
this.property = prop;
prop.expr = this.visit(prop.expr);
this.property = _prop;
this.return--;
return prop;
}
};
/**
* Visit Root.
*/
/**
* Visit Root.
*/
Evaluator.prototype.visitRoot = function(block){
// normalize cached imports
if (block != this.root) {
block.constructor = nodes.Block;
return this.visit(block);
}
visitRoot(block) {
// normalize cached imports
if (block != this.root) {
block.constructor = nodes.Block;
return this.visit(block);
}
for (var i = 0; i < block.nodes.length; ++i) {
block.index = i;
block.nodes[i] = this.visit(block.nodes[i]);
}
return block;
};
for (var i = 0; i < block.nodes.length; ++i) {
block.index = i;
block.nodes[i] = this.visit(block.nodes[i]);
}
return block;
};
/**
* Visit Block.
*/
/**
* Visit Block.
*/
Evaluator.prototype.visitBlock = function(block){
this.stack.push(new Frame(block));
for (block.index = 0; block.index < block.nodes.length; ++block.index) {
try {
block.nodes[block.index] = this.visit(block.nodes[block.index]);
} catch (err) {
if ('return' == err.nodeName) {
if (this.return) {
this.stack.pop();
visitBlock(block) {
this.stack.push(new Frame(block));
for (block.index = 0; block.index < block.nodes.length; ++block.index) {
try {
block.nodes[block.index] = this.visit(block.nodes[block.index]);
} catch (err) {
if ('return' == err.nodeName) {
if (this.return) {
this.stack.pop();
throw err;
} else {
block.nodes[block.index] = err;
break;
}
} else {
throw err;
} else {
block.nodes[block.index] = err;
break;
}
} else {
throw err;
}
}
}
this.stack.pop();
return block;
};
this.stack.pop();
return block;
};
/**
* Visit Atblock.
*/
/**
* Visit Atblock.
*/
Evaluator.prototype.visitAtblock = function(atblock){
atblock.block = this.visit(atblock.block);
return atblock;
};
visitAtblock(atblock) {
atblock.block = this.visit(atblock.block);
return atblock;
};
/**
* Visit Atrule.
*/
/**
* Visit Atrule.
*/
Evaluator.prototype.visitAtrule = function(atrule){
atrule.val = this.interpolate(atrule);
if (atrule.block) atrule.block = this.visit(atrule.block);
return atrule;
};
visitAtrule(atrule) {
atrule.val = this.interpolate(atrule);
if (atrule.block) atrule.block = this.visit(atrule.block);
return atrule;
};
/**
* Visit Supports.
*/
/**
* Visit Supports.
*/
Evaluator.prototype.visitSupports = function(node){
var condition = node.condition
, val;
visitSupports(node) {
var condition = node.condition
, val;
this.return++;
node.condition = this.visit(condition);
this.return--;
this.return++;
node.condition = this.visit(condition);
this.return--;
val = condition.first;
if (1 == condition.nodes.length
&& 'string' == val.nodeName) {
node.condition = val.string;
}
node.block = this.visit(node.block);
return node;
};
val = condition.first;
if (1 == condition.nodes.length
&& 'string' == val.nodeName) {
node.condition = val.string;
}
node.block = this.visit(node.block);
return node;
};
/**
* Visit If.
*/
/**
* Visit If.
*/
Evaluator.prototype.visitIf = function(node){
var ret
, block = this.currentBlock
, negate = node.negate;
visitIf(node) {
var ret
, block = this.currentBlock
, negate = node.negate;
this.return++;
var ok = this.visit(node.cond).first.toBoolean();
this.return--;
this.return++;
var ok = this.visit(node.cond).first.toBoolean();
this.return--;
node.block.scope = node.block.hasMedia;
node.block.scope = node.block.hasMedia;
// Evaluate body
if (negate) {
// unless
if (ok.isFalse) {
ret = this.visit(node.block);
}
} else {
// if
if (ok.isTrue) {
ret = this.visit(node.block);
// else
} else if (node.elses.length) {
var elses = node.elses
, len = elses.length
, cond;
for (var i = 0; i < len; ++i) {
// else if
if (elses[i].cond) {
elses[i].block.scope = elses[i].block.hasMedia;
this.return++;
cond = this.visit(elses[i].cond).first.toBoolean();
this.return--;
if (cond.isTrue) {
ret = this.visit(elses[i].block);
break;
// Evaluate body
if (negate) {
// unless
if (ok.isFalse) {
ret = this.visit(node.block);
}
} else {
// if
if (ok.isTrue) {
ret = this.visit(node.block);
// else
} else if (node.elses.length) {
var elses = node.elses
, len = elses.length
, cond;
for (var i = 0; i < len; ++i) {
// else if
if (elses[i].cond) {
elses[i].block.scope = elses[i].block.hasMedia;
this.return++;
cond = this.visit(elses[i].cond).first.toBoolean();
this.return--;
if (cond.isTrue) {
ret = this.visit(elses[i].block);
break;
}
// else
} else {
elses[i].scope = elses[i].hasMedia;
ret = this.visit(elses[i]);
}
// else
} else {
elses[i].scope = elses[i].hasMedia;
ret = this.visit(elses[i]);
}
}
}
}
// mixin conditional statements within
// a selector group or at-rule
if (ret && !node.postfix && block.node
&& ~['group'
, 'atrule'
, 'media'
, 'supports'
, 'keyframes'].indexOf(block.node.nodeName)) {
this.mixin(ret.nodes, block);
return nodes.null;
}
// mixin conditional statements within
// a selector group or at-rule
if (ret && !node.postfix && block.node
&& ~['group'
, 'atrule'
, 'media'
, 'supports'
, 'keyframes'].indexOf(block.node.nodeName)) {
this.mixin(ret.nodes, block);
return nodes.null;
}
return ret || nodes.null;
};
return ret || nodes.null;
};
/**
* Visit Extend.
*/
/**
* Visit Extend.
*/
Evaluator.prototype.visitExtend = function(extend){
var block = this.currentBlock;
if ('group' != block.node.nodeName) block = this.closestGroup;
extend.selectors.forEach(function(selector){
block.node.extends.push({
// Cloning the selector for when we are in a loop and don't want it to affect
// the selector nodes and cause the values to be different to expected
selector: this.interpolate(selector.clone()).trim(),
optional: selector.optional,
lineno: selector.lineno,
column: selector.column
});
}, this);
return nodes.null;
};
visitExtend(extend) {
var block = this.currentBlock;
if ('group' != block.node.nodeName) block = this.closestGroup;
extend.selectors.forEach(function (selector) {
block.node.extends.push({
// Cloning the selector for when we are in a loop and don't want it to affect
// the selector nodes and cause the values to be different to expected
selector: this.interpolate(selector.clone()).trim(),
optional: selector.optional,
lineno: selector.lineno,
column: selector.column
});
}, this);
return nodes.null;
};
/**
* Visit Import.
*/
/**
* Visit Import.
*/
Evaluator.prototype.visitImport = function(imported){
this.return++;
visitImport(imported) {
this.return++;
var path = this.visit(imported.path).first
, nodeName = imported.once ? 'require' : 'import'
, found
, literal;
var path = this.visit(imported.path).first
, nodeName = imported.once ? 'require' : 'import'
, found
, literal;
this.return--;
debug('import %s', path);
this.return--;
debug('import %s', path);
// url() passed
if ('url' == path.name) {
if (imported.once) throw new Error('You cannot @require a url');
// url() passed
if ('url' == path.name) {
if (imported.once) throw new Error('You cannot @require a url');
return imported;
}
return imported;
}
// Ensure string
if (!path.string) throw new Error('@' + nodeName + ' string expected');
// Ensure string
if (!path.string) throw new Error('@' + nodeName + ' string expected');
var name = path = path.string;
var name = path = path.string;
// Absolute URL or hash
if (/(?:url\s*\(\s*)?['"]?(?:#|(?:https?:)?\/\/)/i.test(path)) {
if (imported.once) throw new Error('You cannot @require a url');
return imported;
}
// Literal
if (/\.css(?:"|$)/.test(path)) {
literal = true;
if (!imported.once && !this.includeCSS) {
// Absolute URL or hash
if (/(?:url\s*\(\s*)?['"]?(?:#|(?:https?:)?\/\/)/i.test(path)) {
if (imported.once) throw new Error('You cannot @require a url');
return imported;
}
}
// support optional .styl
if (!literal && !/\.styl$/i.test(path)) path += '.styl';
// Literal
if (/\.css(?:"|$)/.test(path)) {
literal = true;
if (!imported.once && !this.includeCSS) {
return imported;
}
}
// Lookup
found = utils.find(path, this.paths, this.filename);
if (!found) {
found = utils.lookupIndex(name, this.paths, this.filename);
}
// support optional .styl
if (!literal && !/\.styl$/i.test(path)) path += '.styl';
// Throw if import failed
if (!found) throw new Error('failed to locate @' + nodeName + ' file ' + path);
var block = new nodes.Block;
// Lookup
found = utils.find(path, this.paths, this.filename);
if (!found) {
found = utils.lookupIndex(name, this.paths, this.filename);
}
for (var i = 0, len = found.length; i < len; ++i) {
block.push(importFile.call(this, imported, found[i], literal));
}
// Throw if import failed
if (!found) throw new Error('failed to locate @' + nodeName + ' file ' + path);
return block;
};
var block = new nodes.Block;
/**
* Invoke `fn` with `args`.
*
* @param {Function} fn
* @param {Array} args
* @return {Node}
* @api private
*/
for (var i = 0, len = found.length; i < len; ++i) {
block.push(importFile.call(this, imported, found[i], literal));
}
Evaluator.prototype.invokeFunction = function(fn, args, content){
var block = new nodes.Block(fn.block.parent);
return block;
};
// Clone the function body
// to prevent mutation of subsequent calls
var body = fn.block.clone(block);
/**
* Invoke `fn` with `args`.
*
* @param {Function} fn
* @param {Array} args
* @return {Node}
* @api private
*/
// mixin block
var mixinBlock = this.stack.currentFrame.block;
invokeFunction(fn, args, content) {
var block = new nodes.Block(fn.block.parent);
// new block scope
this.stack.push(new Frame(block));
var scope = this.currentScope;
// Clone the function body
// to prevent mutation of subsequent calls
var body = fn.block.clone(block);
// normalize arguments
if ('arguments' != args.nodeName) {
var expr = new nodes.Expression;
expr.push(args);
args = nodes.Arguments.fromExpression(expr);
}
// mixin block
var mixinBlock = this.stack.currentFrame.block;
// arguments local
scope.add(new nodes.Ident('arguments', args));
// new block scope
this.stack.push(new Frame(block));
var scope = this.currentScope;
// mixin scope introspection
scope.add(new nodes.Ident('mixin', this.return
? nodes.false
: new nodes.String(mixinBlock.nodeName)));
// normalize arguments
if ('arguments' != args.nodeName) {
var expr = new nodes.Expression;
expr.push(args);
args = nodes.Arguments.fromExpression(expr);
}
// current property
if (this.property) {
var prop = this.propertyExpression(this.property, fn.name);
scope.add(new nodes.Ident('current-property', prop));
} else {
scope.add(new nodes.Ident('current-property', nodes.null));
}
// arguments local
scope.add(new nodes.Ident('arguments', args));
// current call stack
var expr = new nodes.Expression;
for (var i = this.calling.length - 1; i-- ; ) {
expr.push(new nodes.Literal(this.calling[i]));
};
scope.add(new nodes.Ident('called-from', expr));
// mixin scope introspection
scope.add(new nodes.Ident('mixin', this.return
? nodes.false
: new nodes.String(mixinBlock.nodeName)));
// inject arguments as locals
var i = 0
, len = args.nodes.length;
fn.params.nodes.forEach(function(node){
// rest param support
if (node.rest) {
node.val = new nodes.Expression;
for (; i < len; ++i) node.val.push(args.nodes[i]);
node.val.preserve = true;
node.val.isList = args.isList;
// argument default support
// current property
if (this.property) {
var prop = this.propertyExpression(this.property, fn.name);
scope.add(new nodes.Ident('current-property', prop));
} else {
var arg = args.map[node.name] || args.nodes[i++];
node = node.clone();
if (arg) {
arg.isEmpty ? args.nodes[i - 1] = this.visit(node) : node.val = arg;
scope.add(new nodes.Ident('current-property', nodes.null));
}
// current call stack
var expr = new nodes.Expression;
for (var i = this.calling.length - 1; i--;) {
expr.push(new nodes.Literal(this.calling[i]));
};
scope.add(new nodes.Ident('called-from', expr));
// inject arguments as locals
var i = 0
, len = args.nodes.length;
fn.params.nodes.forEach(function (node) {
// rest param support
if (node.rest) {
node.val = new nodes.Expression;
for (; i < len; ++i) node.val.push(args.nodes[i]);
node.val.preserve = true;
node.val.isList = args.isList;
// argument default support
} else {
args.push(node.val);
}
var arg = args.map[node.name] || args.nodes[i++];
node = node.clone();
if (arg) {
arg.isEmpty ? args.nodes[i - 1] = this.visit(node) : node.val = arg;
} else {
args.push(node.val);
}
// required argument not satisfied
if (node.val.isNull) {
throw new Error('argument "' + node + '" required for ' + fn);
// required argument not satisfied
if (node.val.isNull) {
throw new Error('argument "' + node + '" required for ' + fn);
}
}
}
scope.add(node);
}, this);
scope.add(node);
}, this);
// mixin block
if (content) scope.add(new nodes.Ident('block', content, true));
// mixin block
if (content) scope.add(new nodes.Ident('block', content, true));
// invoke
return this.invoke(body, true, fn.filename);
};
// invoke
return this.invoke(body, true, fn.filename);
};
/**
* Invoke built-in `fn` with `args`.
*
* @param {Function} fn
* @param {Array} args
* @return {Node}
* @api private
*/
/**
* Invoke built-in `fn` with `args`.
*
* @param {Function} fn
* @param {Array} args
* @return {Node}
* @api private
*/
Evaluator.prototype.invokeBuiltin = function(fn, args){
// Map arguments to first node
// providing a nicer js api for
// BIFs. Functions may specify that
// they wish to accept full expressions
// via .raw
if (fn.raw) {
args = args.nodes;
} else {
if (!fn.params) {
fn.params = utils.params(fn);
}
args = fn.params.reduce(function(ret, param){
var arg = args.map[param] || args.nodes.shift()
if (arg) {
arg = utils.unwrap(arg);
var len = arg.nodes.length;
if (len > 1) {
for (var i = 0; i < len; ++i) {
ret.push(utils.unwrap(arg.nodes[i].first));
invokeBuiltin(fn, args) {
// Map arguments to first node
// providing a nicer js api for
// BIFs. Functions may specify that
// they wish to accept full expressions
// via .raw
if (fn.raw) {
args = args.nodes;
} else {
if (!fn.params) {
fn.params = utils.params(fn);
}
args = fn.params.reduce(function (ret, param) {
var arg = args.map[param] || args.nodes.shift()
if (arg) {
arg = utils.unwrap(arg);
var len = arg.nodes.length;
if (len > 1) {
for (var i = 0; i < len; ++i) {
ret.push(utils.unwrap(arg.nodes[i].first));
}
} else {
ret.push(arg.first);
}
} else {
ret.push(arg.first);
}
}
return ret;
}, []);
}
return ret;
}, []);
}
// Invoke the BIF
var body = utils.coerce(fn.apply(this, args));
// Invoke the BIF
var body = utils.coerce(fn.apply(this, args));
// Always wrapping allows js functions
// to return several values with a single
// Expression node
var expr = new nodes.Expression;
expr.push(body);
body = expr;
// Always wrapping allows js functions
// to return several values with a single
// Expression node
var expr = new nodes.Expression;
expr.push(body);
body = expr;
// Invoke
return this.invoke(body);
};
// Invoke
return this.invoke(body);
};
/**
* Invoke the given function `body`.
*
* @param {Block} body
* @return {Node}
* @api private
*/
/**
* Invoke the given function `body`.
*
* @param {Block} body
* @return {Node}
* @api private
*/
Evaluator.prototype.invoke = function(body, stack, filename){
var self = this
, ret;
invoke(body, stack, filename) {
var self = this
, ret;
if (filename) this.paths.push(dirname(filename));
if (filename) this.paths.push(dirname(filename));
// Return
if (this.return) {
ret = this.eval(body.nodes);
if (stack) this.stack.pop();
// Mixin
} else {
body = this.visit(body);
if (stack) this.stack.pop();
this.mixin(body.nodes, this.currentBlock);
ret = nodes.null;
}
// Return
if (this.return) {
ret = this.eval(body.nodes);
if (stack) this.stack.pop();
// Mixin
} else {
body = this.visit(body);
if (stack) this.stack.pop();
this.mixin(body.nodes, this.currentBlock);
ret = nodes.null;
}
if (filename) this.paths.pop();
if (filename) this.paths.pop();
return ret;
};
return ret;
};
/**
* Mixin the given `nodes` to the given `block`.
*
* @param {Array} nodes
* @param {Block} block
* @api private
*/
/**
* Mixin the given `nodes` to the given `block`.
*
* @param {Array} nodes
* @param {Block} block
* @api private
*/
Evaluator.prototype.mixin = function(nodes, block){
if (!nodes.length) return;
var len = block.nodes.length
, head = block.nodes.slice(0, block.index)
, tail = block.nodes.slice(block.index + 1, len);
this._mixin(nodes, head, block);
block.index = 0;
block.nodes = head.concat(tail);
};
mixin(nodes, block) {
if (!nodes.length) return;
var len = block.nodes.length
, head = block.nodes.slice(0, block.index)
, tail = block.nodes.slice(block.index + 1, len);
this._mixin(nodes, head, block);
block.index = 0;
block.nodes = head.concat(tail);
};
/**
* Mixin the given `items` to the `dest` array.
*
* @param {Array} items
* @param {Array} dest
* @param {Block} block
* @api private
*/
/**
* Mixin the given `items` to the `dest` array.
*
* @param {Array} items
* @param {Array} dest
* @param {Block} block
* @api private
*/
Evaluator.prototype._mixin = function(items, dest, block){
var node
, len = items.length;
for (var i = 0; i < len; ++i) {
switch ((node = items[i]).nodeName) {
case 'return':
return;
case 'block':
this._mixin(node.nodes, dest, block);
break;
case 'media':
// fix link to the parent block
var parentNode = node.block.parent.node;
if (parentNode && 'call' != parentNode.nodeName) {
node.block.parent = block;
}
case 'property':
var val = node.expr;
// prevent `block` mixin recursion
if (node.literal && 'block' == val.first.name) {
val = utils.unwrap(val);
val.nodes[0] = new nodes.Literal('block');
}
default:
dest.push(node);
_mixin(items, dest, block) {
var node
, len = items.length;
for (var i = 0; i < len; ++i) {
switch ((node = items[i]).nodeName) {
case 'return':
return;
case 'block':
this._mixin(node.nodes, dest, block);
break;
case 'media':
// fix link to the parent block
var parentNode = node.block.parent.node;
if (parentNode && 'call' != parentNode.nodeName) {
node.block.parent = block;
}
case 'property':
var val = node.expr;
// prevent `block` mixin recursion
if (node.literal && 'block' == val.first.name) {
val = utils.unwrap(val);
val.nodes[0] = new nodes.Literal('block');
}
default:
dest.push(node);
}
}
}
};
};
/**
* Mixin the given `node` to the current block.
*
* @param {Node} node
* @api private
*/
/**
* Mixin the given `node` to the current block.
*
* @param {Node} node
* @api private
*/
Evaluator.prototype.mixinNode = function(node){
node = this.visit(node.first);
switch (node.nodeName) {
case 'object':
this.mixinObject(node);
return nodes.null;
case 'block':
case 'atblock':
this.mixin(node.nodes, this.currentBlock);
return nodes.null;
}
};
mixinNode(node) {
node = this.visit(node.first);
switch (node.nodeName) {
case 'object':
this.mixinObject(node);
return nodes.null;
case 'block':
case 'atblock':
this.mixin(node.nodes, this.currentBlock);
return nodes.null;
}
};
/**
* Mixin the given `object` to the current block.
*
* @param {Object} object
* @api private
*/
/**
* Mixin the given `object` to the current block.
*
* @param {Object} object
* @api private
*/
Evaluator.prototype.mixinObject = function(object){
var Parser = require('../parser')
, root = this.root
, str = '$block ' + object.toBlock()
, parser = new Parser(str, utils.merge({ root: block }, this.options))
, block;
mixinObject(object) {
var Parser = require('../parser')
, root = this.root
, str = '$block ' + object.toBlock()
, parser = new Parser(str, utils.merge({ root: block }, this.options))
, block;
try {
block = parser.parse();
} catch (err) {
err.filename = this.filename;
err.lineno = parser.lexer.lineno;
err.column = parser.lexer.column;
err.input = str;
throw err;
}
try {
block = parser.parse();
} catch (err) {
err.filename = this.filename;
err.lineno = parser.lexer.lineno;
err.column = parser.lexer.column;
err.input = str;
throw err;
}
block.parent = root;
block.scope = false;
var ret = this.visit(block)
, vals = ret.first.nodes;
for (var i = 0, len = vals.length; i < len; ++i) {
if (vals[i].block) {
this.mixin(vals[i].block.nodes, this.currentBlock);
break;
block.parent = root;
block.scope = false;
var ret = this.visit(block)
, vals = ret.first.nodes;
for (var i = 0, len = vals.length; i < len; ++i) {
if (vals[i].block) {
this.mixin(vals[i].block.nodes, this.currentBlock);
break;
}
}
}
};
};
/**
* Evaluate the given `vals`.
*
* @param {Array} vals
* @return {Node}
* @api private
*/
/**
* Evaluate the given `vals`.
*
* @param {Array} vals
* @return {Node}
* @api private
*/
Evaluator.prototype.eval = function(vals){
if (!vals) return nodes.null;
var len = vals.length
, node = nodes.null;
eval(vals) {
if (!vals) return nodes.null;
var len = vals.length
, node = nodes.null;
try {
for (var i = 0; i < len; ++i) {
node = vals[i];
switch (node.nodeName) {
case 'if':
if ('block' != node.block.nodeName) {
try {
for (var i = 0; i < len; ++i) {
node = vals[i];
switch (node.nodeName) {
case 'if':
if ('block' != node.block.nodeName) {
node = this.visit(node);
break;
}
case 'each':
case 'block':
node = this.visit(node);
if (node.nodes) node = this.eval(node.nodes);
break;
}
case 'each':
case 'block':
node = this.visit(node);
if (node.nodes) node = this.eval(node.nodes);
break;
default:
node = this.visit(node);
default:
node = this.visit(node);
}
}
} catch (err) {
if ('return' == err.nodeName) {
return err.expr;
} else {
throw err;
}
}
} catch (err) {
if ('return' == err.nodeName) {
return err.expr;
} else {
throw err;
}
}
return node;
};
return node;
};
/**
* Literal function `call`.
*
* @param {Call} call
* @return {call}
* @api private
*/
/**
* Literal function `call`.
*
* @param {Call} call
* @return {call}
* @api private
*/
Evaluator.prototype.literalCall = function(call){
call.args = this.visit(call.args);
return call;
};
literalCall(call) {
call.args = this.visit(call.args);
return call;
};
/**
* Lookup property `name`.
*
* @param {String} name
* @return {Property}
* @api private
*/
/**
* Lookup property `name`.
*
* @param {String} name
* @return {Property}
* @api private
*/
Evaluator.prototype.lookupProperty = function(name){
var i = this.stack.length
, index = this.currentBlock.index
, top = i
, nodes
, block
, len
, other;
lookupProperty(name) {
var i = this.stack.length
, index = this.currentBlock.index
, top = i
, nodes
, block
, len
, other;
while (i--) {
block = this.stack[i].block;
if (!block.node) continue;
switch (block.node.nodeName) {
case 'group':
case 'function':
case 'if':
case 'each':
case 'atrule':
case 'media':
case 'atblock':
case 'call':
nodes = block.nodes;
// scan siblings from the property index up
if (i + 1 == top) {
while (index--) {
// ignore current property
if (this.property == nodes[index]) continue;
other = this.interpolate(nodes[index]);
if (name == other) return nodes[index].clone();
}
// sequential lookup for non-siblings (for now)
} else {
len = nodes.length;
while (len--) {
if ('property' != nodes[len].nodeName
|| this.property == nodes[len]) continue;
other = this.interpolate(nodes[len]);
if (name == other) return nodes[len].clone();
}
}
break;
}
}
return nodes.null;
};
/**
* Return the closest mixin-able `Block`.
*
* @return {Block}
* @api private
*/
Evaluator.prototype.__defineGetter__('closestBlock', function(){
var i = this.stack.length
, block;
while (i--) {
block = this.stack[i].block;
if (block.node) {
while (i--) {
block = this.stack[i].block;
if (!block.node) continue;
switch (block.node.nodeName) {
case 'group':
case 'keyframes':
case 'function':
case 'if':
case 'each':
case 'atrule':
case 'media':
case 'atblock':
case 'media':
case 'call':
return block;
nodes = block.nodes;
// scan siblings from the property index up
if (i + 1 == top) {
while (index--) {
// ignore current property
if (this.property == nodes[index]) continue;
other = this.interpolate(nodes[index]);
if (name == other) return nodes[index].clone();
}
// sequential lookup for non-siblings (for now)
} else {
len = nodes.length;
while (len--) {
if ('property' != nodes[len].nodeName
|| this.property == nodes[len]) continue;
other = this.interpolate(nodes[len]);
if (name == other) return nodes[len].clone();
}
}
break;
}
}
}
});
/**
* Return the closest group block.
*
* @return {Block}
* @api private
*/
return nodes.null;
};
Evaluator.prototype.__defineGetter__('closestGroup', function(){
var i = this.stack.length
, block;
while (i--) {
block = this.stack[i].block;
if (block.node && 'group' == block.node.nodeName) {
return block;
/**
* Return the closest mixin-able `Block`.
*
* @return {Block}
* @api private
*/
get closestBlock() {
var i = this.stack.length
, block;
while (i--) {
block = this.stack[i].block;
if (block.node) {
switch (block.node.nodeName) {
case 'group':
case 'keyframes':
case 'atrule':
case 'atblock':
case 'media':
case 'call':
return block;
}
}
}
}
});
};
/**
* Return the current selectors stack.
*
* @return {Array}
* @api private
*/
/**
* Return the closest group block.
*
* @return {Block}
* @api private
*/
Evaluator.prototype.__defineGetter__('selectorStack', function(){
var block
, stack = [];
for (var i = 0, len = this.stack.length; i < len; ++i) {
block = this.stack[i].block;
if (block.node && 'group' == block.node.nodeName) {
block.node.nodes.forEach(function(selector) {
if (!selector.val) selector.val = this.interpolate(selector);
}, this);
stack.push(block.node.nodes);
get closestGroup() {
var i = this.stack.length
, block;
while (i--) {
block = this.stack[i].block;
if (block.node && 'group' == block.node.nodeName) {
return block;
}
}
}
return stack;
});
};
/**
* Lookup `name`, with support for JavaScript
* functions, and BIFs.
*
* @param {String} name
* @return {Node}
* @api private
*/
/**
* Return the current selectors stack.
*
* @return {Array}
* @api private
*/
Evaluator.prototype.lookup = function(name){
var val;
if (this.ignoreColors && name in colors) return;
if (val = this.stack.lookup(name)) {
return utils.unwrap(val);
} else {
return this.lookupFunction(name);
}
};
get selectorStack() {
var block
, stack = [];
for (var i = 0, len = this.stack.length; i < len; ++i) {
block = this.stack[i].block;
if (block.node && 'group' == block.node.nodeName) {
block.node.nodes.forEach(function (selector) {
if (!selector.val) selector.val = this.interpolate(selector);
}, this);
stack.push(block.node.nodes);
}
}
return stack;
};
/**
* Map segments in `node` returning a string.
*
* @param {Node} node
* @return {String}
* @api private
*/
/**
* Lookup `name`, with support for JavaScript
* functions, and BIFs.
*
* @param {String} name
* @return {Node}
* @api private
*/
Evaluator.prototype.interpolate = function(node){
var self = this
, isSelector = ('selector' == node.nodeName);
function toString(node) {
switch (node.nodeName) {
case 'function':
case 'ident':
return node.name;
case 'literal':
case 'string':
if (self.prefix && !node.prefixed && !node.val.nodeName) {
node.val = node.val.replace(/\.(?=[\w-])|^\.$/g, '.' + self.prefix);
node.prefixed = true;
}
return node.val;
case 'unit':
// Interpolation inside keyframes
return '%' == node.type ? node.val + '%' : node.val;
case 'member':
return toString(self.visit(node));
case 'expression':
// Prevent cyclic `selector()` calls.
if (self.calling && ~self.calling.indexOf('selector') && self._selector) return self._selector;
self.return++;
var ret = toString(self.visit(node).first);
self.return--;
if (isSelector) self._selector = ret;
return ret;
lookup(name) {
var val;
if (this.ignoreColors && name in colors) return;
if (val = this.stack.lookup(name)) {
return utils.unwrap(val);
} else {
return this.lookupFunction(name);
}
}
};
if (node.segments) {
return node.segments.map(toString).join('');
} else {
return toString(node);
}
};
/**
* Map segments in `node` returning a string.
*
* @param {Node} node
* @return {String}
* @api private
*/
/**
* Lookup JavaScript user-defined or built-in function.
*
* @param {String} name
* @return {Function}
* @api private
*/
interpolate(node) {
var self = this
, isSelector = ('selector' == node.nodeName);
function toString(node) {
switch (node.nodeName) {
case 'function':
case 'ident':
return node.name;
case 'literal':
case 'string':
if (self.prefix && !node.prefixed && !node.val.nodeName) {
node.val = node.val.replace(/\.(?=[\w-])|^\.$/g, '.' + self.prefix);
node.prefixed = true;
}
return node.val;
case 'unit':
// Interpolation inside keyframes
return '%' == node.type ? node.val + '%' : node.val;
case 'member':
return toString(self.visit(node));
case 'expression':
// Prevent cyclic `selector()` calls.
if (self.calling && ~self.calling.indexOf('selector') && self._selector) return self._selector;
self.return++;
var ret = toString(self.visit(node).first);
self.return--;
if (isSelector) self._selector = ret;
return ret;
}
}
Evaluator.prototype.lookupFunction = function(name){
var fn = this.functions[name] || bifs[name];
if (fn) return new nodes.Function(name, fn);
};
if (node.segments) {
return node.segments.map(toString).join('');
} else {
return toString(node);
}
};
/**
* Check if the given `node` is an ident, and if it is defined.
*
* @param {Node} node
* @return {Boolean}
* @api private
*/
/**
* Lookup JavaScript user-defined or built-in function.
*
* @param {String} name
* @return {Function}
* @api private
*/
Evaluator.prototype.isDefined = function(node){
if ('ident' == node.nodeName) {
return nodes.Boolean(this.lookup(node.name));
} else {
throw new Error('invalid "is defined" check on non-variable ' + node);
}
};
lookupFunction(name) {
var fn = this.functions[name] || bifs[name];
if (fn) return new nodes.Function(name, fn);
};
/**
* Return `Expression` based on the given `prop`,
* replacing cyclic calls to the given function `name`
* with "__CALL__".
*
* @param {Property} prop
* @param {String} name
* @return {Expression}
* @api private
*/
/**
* Check if the given `node` is an ident, and if it is defined.
*
* @param {Node} node
* @return {Boolean}
* @api private
*/
Evaluator.prototype.propertyExpression = function(prop, name){
var expr = new nodes.Expression
, val = prop.expr.clone();
isDefined(node) {
if ('ident' == node.nodeName) {
return new nodes.Boolean(this.lookup(node.name));
} else {
throw new Error('invalid "is defined" check on non-variable ' + node);
}
};
// name
expr.push(new nodes.String(prop.name));
/**
* Return `Expression` based on the given `prop`,
* replacing cyclic calls to the given function `name`
* with "__CALL__".
*
* @param {Property} prop
* @param {String} name
* @return {Expression}
* @api private
*/
// replace cyclic call with __CALL__
function replace(node) {
if ('call' == node.nodeName && name == node.name) {
return new nodes.Literal('__CALL__');
propertyExpression(prop, name) {
var expr = new nodes.Expression
, val = prop.expr.clone();
// name
expr.push(new nodes.String(prop.name));
// replace cyclic call with __CALL__
function replace(node) {
if ('call' == node.nodeName && name == node.name) {
return new nodes.Literal('__CALL__');
}
if (node.nodes) node.nodes = node.nodes.map(replace);
return node;
}
if (node.nodes) node.nodes = node.nodes.map(replace);
return node;
}
replace(val);
expr.push(val);
return expr;
};
replace(val);
expr.push(val);
return expr;
};
/**
* Cast `expr` to the trailing ident.
*
* @param {Expression} expr
* @return {Unit}
* @api private
*/
/**
* Cast `expr` to the trailing ident.
*
* @param {Expression} expr
* @return {Unit}
* @api private
*/
cast(expr) {
return new nodes.Unit(expr.first.val, expr.nodes[1].name);
};
Evaluator.prototype.cast = function(expr){
return new nodes.Unit(expr.first.val, expr.nodes[1].name);
};
/**
* Check if `expr` is castable.
*
* @param {Expression} expr
* @return {Boolean}
* @api private
*/
/**
* Check if `expr` is castable.
*
* @param {Expression} expr
* @return {Boolean}
* @api private
*/
castable(expr) {
return 2 == expr.nodes.length
&& 'unit' == expr.first.nodeName
&& ~units.indexOf(expr.nodes[1].name);
};
Evaluator.prototype.castable = function(expr){
return 2 == expr.nodes.length
&& 'unit' == expr.first.nodeName
&& ~units.indexOf(expr.nodes[1].name);
};
/**
* Warn with the given `msg`.
*
* @param {String} msg
* @api private
*/
/**
* Warn with the given `msg`.
*
* @param {String} msg
* @api private
*/
warn(msg) {
if (!this.warnings) return;
console.warn('\u001b[33mWarning:\u001b[0m ' + msg);
};
Evaluator.prototype.warn = function(msg){
if (!this.warnings) return;
console.warn('\u001b[33mWarning:\u001b[0m ' + msg);
};
/**
* Return the current `Block`.
*
* @return {Block}
* @api private
*/
/**
* Return the current `Block`.
*
* @return {Block}
* @api private
*/
get currentBlock() {
return this.stack.currentFrame.block;
};
Evaluator.prototype.__defineGetter__('currentBlock', function(){
return this.stack.currentFrame.block;
});
/**
* Return an array of vendor names.
*
* @return {Array}
* @api private
*/
/**
* Return an array of vendor names.
*
* @return {Array}
* @api private
*/
get vendors() {
return this.lookup('vendors').nodes.map(function (node) {
return node.string;
});
};
Evaluator.prototype.__defineGetter__('vendors', function(){
return this.lookup('vendors').nodes.map(function(node){
return node.string;
});
});
/**
* Return the property name without vendor prefix.
*
* @param {String} prop
* @return {String}
* @api public
*/
/**
* Return the property name without vendor prefix.
*
* @param {String} prop
* @return {String}
* @api public
*/
Evaluator.prototype.unvendorize = function(prop){
for (var i = 0, len = this.vendors.length; i < len; i++) {
if ('official' != this.vendors[i]) {
var vendor = '-' + this.vendors[i] + '-';
if (~prop.indexOf(vendor)) return prop.replace(vendor, '');
unvendorize(prop) {
for (var i = 0, len = this.vendors.length; i < len; i++) {
if ('official' != this.vendors[i]) {
var vendor = '-' + this.vendors[i] + '-';
if (~prop.indexOf(vendor)) return prop.replace(vendor, '');
}
}
}
return prop;
};
return prop;
};
/**
* Return the current frame `Scope`.
*
* @return {Scope}
* @api private
*/
/**
* Return the current frame `Scope`.
*
* @return {Scope}
* @api private
*/
Evaluator.prototype.__defineGetter__('currentScope', function(){
return this.stack.currentFrame.scope;
});
get currentScope() {
return this.stack.currentFrame.scope;
};
/**
* Return the current `Frame`.
*
* @return {Frame}
* @api private
*/
/**
* Return the current `Frame`.
*
* @return {Frame}
* @api private
*/
Evaluator.prototype.__defineGetter__('currentFrame', function(){
return this.stack.currentFrame;
});
get currentFrame() {
return this.stack.currentFrame;
};
};

@@ -8,25 +8,26 @@

/**
* Initialize a new `Visitor` with the given `root` Node.
*
* @param {Node} root
* @api private
*/
module.exports = class Visitor {
/**
* Initialize a new `Visitor` with the given `root` Node.
*
* @param {Node} root
* @api private
*/
var Visitor = module.exports = function Visitor(root) {
this.root = root;
};
constructor(root) {
this.root = root;
}
/**
* Visit the given `node`.
*
* @param {Node|Array} node
* @api public
*/
/**
* Visit the given `node`.
*
* @param {Node|Array} node
* @api public
*/
Visitor.prototype.visit = function(node, fn){
var method = 'visit' + node.constructor.name;
if (this[method]) return this[method](node);
return node;
visit(node, fn) {
var method = 'visit' + node.constructor.name;
if (this[method]) return this[method](node);
return node;
};
};

@@ -16,200 +16,141 @@

/**
* Initialize a new `Normalizer` with the given `root` Node.
*
* This visitor implements the first stage of the duel-stage
* compiler, tasked with stripping the "garbage" from
* the evaluated nodes, ditching null rules, resolving
* ruleset selectors etc. This step performs the logic
* necessary to facilitate the "@extend" functionality,
* as these must be resolved _before_ buffering output.
*
* @param {Node} root
* @api public
*/
module.exports = class Normalizer extends Visitor {
/**
* Initialize a new `Normalizer` with the given `root` Node.
*
* This visitor implements the first stage of the duel-stage
* compiler, tasked with stripping the "garbage" from
* the evaluated nodes, ditching null rules, resolving
* ruleset selectors etc. This step performs the logic
* necessary to facilitate the "@extend" functionality,
* as these must be resolved _before_ buffering output.
*
* @param {Node} root
* @api public
*/
var Normalizer = module.exports = function Normalizer(root, options) {
options = options || {};
Visitor.call(this, root);
this.hoist = options['hoist atrules'];
this.stack = [];
this.map = {};
this.imports = [];
};
/**
* Inherit from `Visitor.prototype`.
*/
Normalizer.prototype.__proto__ = Visitor.prototype;
/**
* Normalize the node tree.
*
* @return {Node}
* @api private
*/
Normalizer.prototype.normalize = function(){
var ret = this.visit(this.root);
if (this.hoist) {
// hoist @import
if (this.imports.length) ret.nodes = this.imports.concat(ret.nodes);
// hoist @charset
if (this.charset) ret.nodes = [this.charset].concat(ret.nodes);
constructor(root, options) {
super(root);
options = options || {};
this.hoist = options['hoist atrules'];
this.stack = [];
this.map = {};
this.imports = [];
}
return ret;
};
/**
* Normalize the node tree.
*
* @return {Node}
* @api private
*/
/**
* Bubble up the given `node`.
*
* @param {Node} node
* @api private
*/
normalize() {
var ret = this.visit(this.root);
Normalizer.prototype.bubble = function(node){
var props = []
, other = []
, self = this;
if (this.hoist) {
// hoist @import
if (this.imports.length) ret.nodes = this.imports.concat(ret.nodes);
function filterProps(block) {
block.nodes.forEach(function(node) {
node = self.visit(node);
// hoist @charset
if (this.charset) ret.nodes = [this.charset].concat(ret.nodes);
}
switch (node.nodeName) {
case 'property':
props.push(node);
break;
case 'block':
filterProps(node);
break;
default:
other.push(node);
}
});
}
return ret;
};
filterProps(node.block);
/**
* Bubble up the given `node`.
*
* @param {Node} node
* @api private
*/
if (props.length) {
var selector = new nodes.Selector([new nodes.Literal('&')]);
selector.lineno = node.lineno;
selector.column = node.column;
selector.filename = node.filename;
selector.val = '&';
bubble(node) {
var props = []
, other = []
, self = this;
var group = new nodes.Group;
group.lineno = node.lineno;
group.column = node.column;
group.filename = node.filename;
function filterProps(block) {
block.nodes.forEach(function (node) {
node = self.visit(node);
var block = new nodes.Block(node.block, group);
block.lineno = node.lineno;
block.column = node.column;
block.filename = node.filename;
switch (node.nodeName) {
case 'property':
props.push(node);
break;
case 'block':
filterProps(node);
break;
default:
other.push(node);
}
});
}
props.forEach(function(prop){
block.push(prop);
});
filterProps(node.block);
group.push(selector);
group.block = block;
if (props.length) {
var selector = new nodes.Selector([new nodes.Literal('&')]);
selector.lineno = node.lineno;
selector.column = node.column;
selector.filename = node.filename;
selector.val = '&';
node.block.nodes = [];
node.block.push(group);
other.forEach(function(n){
node.block.push(n);
});
var group = new nodes.Group;
group.lineno = node.lineno;
group.column = node.column;
group.filename = node.filename;
var group = this.closestGroup(node.block);
if (group) node.group = group.clone();
var block = new nodes.Block(node.block, group);
block.lineno = node.lineno;
block.column = node.column;
block.filename = node.filename;
node.bubbled = true;
}
};
props.forEach(function (prop) {
block.push(prop);
});
/**
* Return group closest to the given `block`.
*
* @param {Block} block
* @return {Group}
* @api private
*/
group.push(selector);
group.block = block;
Normalizer.prototype.closestGroup = function(block){
var parent = block.parent
, node;
while (parent && (node = parent.node)) {
if ('group' == node.nodeName) return node;
parent = node.block && node.block.parent;
}
};
node.block.nodes = [];
node.block.push(group);
other.forEach(function (n) {
node.block.push(n);
});
/**
* Visit Root.
*/
var group = this.closestGroup(node.block);
if (group) node.group = group.clone();
Normalizer.prototype.visitRoot = function(block){
var ret = new nodes.Root
, node;
for (var i = 0; i < block.nodes.length; ++i) {
node = block.nodes[i];
switch (node.nodeName) {
case 'null':
case 'expression':
case 'function':
case 'unit':
case 'atblock':
continue;
default:
this.rootIndex = i;
ret.push(this.visit(node));
node.bubbled = true;
}
}
};
return ret;
};
/**
* Return group closest to the given `block`.
*
* @param {Block} block
* @return {Group}
* @api private
*/
/**
* Visit Property.
*/
Normalizer.prototype.visitProperty = function(prop){
this.visit(prop.expr);
return prop;
};
/**
* Visit Expression.
*/
Normalizer.prototype.visitExpression = function(expr){
expr.nodes = expr.nodes.map(function(node){
// returns `block` literal if mixin's block
// is used as part of a property value
if ('block' == node.nodeName) {
var literal = new nodes.Literal('block');
literal.lineno = expr.lineno;
literal.column = expr.column;
return literal;
closestGroup(block) {
var parent = block.parent
, node;
while (parent && (node = parent.node)) {
if ('group' == node.nodeName) return node;
parent = node.block && node.block.parent;
}
return node;
});
return expr;
};
};
/**
* Visit Block.
*/
/**
* Visit Root.
*/
Normalizer.prototype.visitBlock = function(block){
var node;
visitRoot(block) {
var ret = new nodes.Root
, node;
if (block.hasProperties) {
for (var i = 0, len = block.nodes.length; i < len; ++i) {
for (var i = 0; i < block.nodes.length; ++i) {
node = block.nodes[i];

@@ -220,3 +161,2 @@ switch (node.nodeName) {

case 'function':
case 'group':
case 'unit':

@@ -226,221 +166,277 @@ case 'atblock':

default:
block.nodes[i] = this.visit(node);
this.rootIndex = i;
ret.push(this.visit(node));
}
}
}
// nesting
for (var i = 0, len = block.nodes.length; i < len; ++i) {
node = block.nodes[i];
block.nodes[i] = this.visit(node);
}
return ret;
};
return block;
};
/**
* Visit Property.
*/
/**
* Visit Group.
*/
visitProperty(prop) {
this.visit(prop.expr);
return prop;
};
Normalizer.prototype.visitGroup = function(group){
var stack = this.stack
, map = this.map
, parts;
/**
* Visit Expression.
*/
// normalize interpolated selectors with comma
group.nodes.forEach(function(selector, i){
if (!~selector.val.indexOf(',')) return;
if (~selector.val.indexOf('\\,')) {
selector.val = selector.val.replace(/\\,/g, ',');
return;
}
parts = selector.val.split(',');
var root = '/' == selector.val.charAt(0)
, part, s;
for (var k = 0, len = parts.length; k < len; ++k){
part = parts[k].trim();
if (root && k > 0 && !~part.indexOf('&')) {
part = '/' + part;
visitExpression(expr) {
expr.nodes = expr.nodes.map(function (node) {
// returns `block` literal if mixin's block
// is used as part of a property value
if ('block' == node.nodeName) {
var literal = new nodes.Literal('block');
literal.lineno = expr.lineno;
literal.column = expr.column;
return literal;
}
s = new nodes.Selector([new nodes.Literal(part)]);
s.val = part;
s.block = group.block;
group.nodes[i++] = s;
}
});
stack.push(group.nodes);
return node;
});
return expr;
};
var selectors = utils.compileSelectors(stack, true);
/**
* Visit Block.
*/
// map for extension lookup
selectors.forEach(function(selector){
map[selector] = map[selector] || [];
map[selector].push(group);
});
visitBlock(block) {
var node;
// extensions
this.extend(group, selectors);
if (block.hasProperties) {
for (var i = 0, len = block.nodes.length; i < len; ++i) {
node = block.nodes[i];
switch (node.nodeName) {
case 'null':
case 'expression':
case 'function':
case 'group':
case 'unit':
case 'atblock':
continue;
default:
block.nodes[i] = this.visit(node);
}
}
}
stack.pop();
return group;
};
// nesting
for (var i = 0, len = block.nodes.length; i < len; ++i) {
node = block.nodes[i];
block.nodes[i] = this.visit(node);
}
/**
* Visit Function.
*/
return block;
};
Normalizer.prototype.visitFunction = function(){
return nodes.null;
};
/**
* Visit Group.
*/
/**
* Visit Media.
*/
visitGroup(group) {
var stack = this.stack
, map = this.map
, parts;
Normalizer.prototype.visitMedia = function(media){
var medias = []
, group = this.closestGroup(media.block)
, parent;
function mergeQueries(block) {
block.nodes.forEach(function(node, i){
switch (node.nodeName) {
case 'media':
node.val = media.val.merge(node.val);
medias.push(node);
block.nodes[i] = nodes.null;
break;
case 'block':
mergeQueries(node);
break;
default:
if (node.block && node.block.nodes)
mergeQueries(node.block);
// normalize interpolated selectors with comma
group.nodes.forEach(function (selector, i) {
if (!~selector.val.indexOf(',')) return;
if (~selector.val.indexOf('\\,')) {
selector.val = selector.val.replace(/\\,/g, ',');
return;
}
parts = selector.val.split(',');
var root = '/' == selector.val.charAt(0)
, part, s;
for (var k = 0, len = parts.length; k < len; ++k) {
part = parts[k].trim();
if (root && k > 0 && !~part.indexOf('&')) {
part = '/' + part;
}
s = new nodes.Selector([new nodes.Literal(part)]);
s.val = part;
s.block = group.block;
group.nodes[i++] = s;
}
});
}
stack.push(group.nodes);
mergeQueries(media.block);
this.bubble(media);
var selectors = utils.compileSelectors(stack, true);
if (medias.length) {
medias.forEach(function(node){
if (group) {
group.block.push(node);
} else {
this.root.nodes.splice(++this.rootIndex, 0, node);
}
node = this.visit(node);
parent = node.block.parent;
if (node.bubbled && (!group || 'group' == parent.node.nodeName)) {
node.group.block = node.block.nodes[0].block;
node.block.nodes[0] = node.group;
}
}, this);
}
return media;
};
// map for extension lookup
selectors.forEach(function (selector) {
map[selector] = map[selector] || [];
map[selector].push(group);
});
/**
* Visit Supports.
*/
// extensions
this.extend(group, selectors);
Normalizer.prototype.visitSupports = function(node){
this.bubble(node);
return node;
};
stack.pop();
return group;
};
/**
* Visit Atrule.
*/
/**
* Visit Function.
*/
Normalizer.prototype.visitAtrule = function(node){
if (node.block) node.block = this.visit(node.block);
return node;
};
visitFunction() {
return nodes.null;
};
/**
* Visit Keyframes.
*/
/**
* Visit Media.
*/
Normalizer.prototype.visitKeyframes = function(node){
var frames = node.block.nodes.filter(function(frame){
return frame.block && frame.block.hasProperties;
});
node.frames = frames.length;
return node;
};
visitMedia(media) {
var medias = []
, group = this.closestGroup(media.block)
, parent;
/**
* Visit Import.
*/
function mergeQueries(block) {
block.nodes.forEach(function (node, i) {
switch (node.nodeName) {
case 'media':
node.val = media.val.merge(node.val);
medias.push(node);
block.nodes[i] = nodes.null;
break;
case 'block':
mergeQueries(node);
break;
default:
if (node.block && node.block.nodes)
mergeQueries(node.block);
}
});
}
Normalizer.prototype.visitImport = function(node){
this.imports.push(node);
return this.hoist ? nodes.null : node;
};
mergeQueries(media.block);
this.bubble(media);
/**
* Visit Charset.
*/
if (medias.length) {
medias.forEach(function (node) {
if (group) {
group.block.push(node);
} else {
this.root.nodes.splice(++this.rootIndex, 0, node);
}
node = this.visit(node);
parent = node.block.parent;
if (node.bubbled && (!group || 'group' == parent.node.nodeName)) {
node.group.block = node.block.nodes[0].block;
node.block.nodes[0] = node.group;
}
}, this);
}
return media;
};
Normalizer.prototype.visitCharset = function(node){
this.charset = node;
return this.hoist ? nodes.null : node;
};
/**
* Visit Supports.
*/
/**
* Apply `group` extensions.
*
* @param {Group} group
* @param {Array} selectors
* @api private
*/
visitSupports(node) {
this.bubble(node);
return node;
};
Normalizer.prototype.extend = function(group, selectors){
var map = this.map
, self = this
, parent = this.closestGroup(group.block);
/**
* Visit Atrule.
*/
group.extends.forEach(function(extend){
var groups = map[extend.selector];
if (!groups) {
if (extend.optional) return;
groups = self._checkForPrefixedGroups(extend.selector);
if(!groups) {
var err = new Error('Failed to @extend "' + extend.selector + '"');
err.lineno = extend.lineno;
err.column = extend.column;
throw err;
visitAtrule(node) {
if (node.block) node.block = this.visit(node.block);
return node;
};
/**
* Visit Keyframes.
*/
visitKeyframes(node) {
var frames = node.block.nodes.filter(function (frame) {
return frame.block && frame.block.hasProperties;
});
node.frames = frames.length;
return node;
};
/**
* Visit Import.
*/
visitImport(node) {
this.imports.push(node);
return this.hoist ? nodes.null : node;
};
/**
* Visit Charset.
*/
visitCharset(node) {
this.charset = node;
return this.hoist ? nodes.null : node;
};
/**
* Apply `group` extensions.
*
* @param {Group} group
* @param {Array} selectors
* @api private
*/
extend(group, selectors) {
var map = this.map
, self = this
, parent = this.closestGroup(group.block);
group.extends.forEach(function (extend) {
var groups = map[extend.selector];
if (!groups) {
if (extend.optional) return;
groups = self._checkForPrefixedGroups(extend.selector);
if (!groups) {
var err = new Error('Failed to @extend "' + extend.selector + '"');
err.lineno = extend.lineno;
err.column = extend.column;
throw err;
}
}
}
selectors.forEach(function(selector){
var node = new nodes.Selector;
node.val = selector;
node.inherits = false;
groups.forEach(function(group){
// prevent recursive extend
if (!parent || (parent != group)) self.extend(group, selectors);
group.push(node);
selectors.forEach(function (selector) {
var node = new nodes.Selector;
node.val = selector;
node.inherits = false;
groups.forEach(function (group) {
// prevent recursive extend
if (!parent || (parent != group)) self.extend(group, selectors);
group.push(node);
});
});
});
});
group.block = this.visit(group.block);
group.block = this.visit(group.block);
};
_checkForPrefixedGroups(selector) {
var prefix = [];
var map = this.map;
var result = null;
for (var i = 0; i < this.stack.length; i++) {
var stackElementArray = this.stack[i];
var stackElement = stackElementArray[0];
prefix.push(stackElement.val);
var fullSelector = prefix.join(" ") + " " + selector;
result = map[fullSelector];
if (result)
break;
}
return result;
};
};
Normalizer.prototype._checkForPrefixedGroups = function (selector) {
var prefix = [];
var map = this.map;
var result = null;
for (var i = 0; i < this.stack.length; i++) {
var stackElementArray=this.stack[i];
var stackElement = stackElementArray[0];
prefix.push(stackElement.val);
var fullSelector = prefix.join(" ") + " " + selector;
result = map[fullSelector];
if (result)
break;
}
return result;
};

@@ -22,184 +22,178 @@ /*!

/**
* Initialize a new `SourceMapper` generator with the given `root` Node
* and the following `options`.
*
* @param {Node} root
* @api public
*/
module.exports = class SourceMapper extends Compiler {
/**
* Initialize a new `SourceMapper` generator with the given `root` Node
* and the following `options`.
*
* @param {Node} root
* @api public
*/
var SourceMapper = module.exports = function SourceMapper(root, options){
options = options || {};
this.column = 1;
this.lineno = 1;
this.contents = {};
this.filename = options.filename;
this.dest = options.dest;
var sourcemap = options.sourcemap;
this.basePath = sourcemap.basePath || '.';
this.inline = sourcemap.inline;
this.comment = sourcemap.comment;
if (this.dest && extname(this.dest) === '.css') {
this.basename = basename(this.dest);
this.dest = dirname(this.dest);
} else {
this.basename = basename(this.filename, extname(this.filename)) + '.css';
}
this.utf8 = false;
constructor(root, options) {
super(root, options);
options = options || {};
this.column = 1;
this.lineno = 1;
this.contents = {};
this.filename = options.filename;
this.dest = options.dest;
this.map = new SourceMapGenerator({
file: this.basename,
sourceRoot: sourcemap.sourceRoot || null
});
Compiler.call(this, root, options);
};
var sourcemap = options.sourcemap;
this.basePath = sourcemap.basePath || '.';
this.inline = sourcemap.inline;
this.comment = sourcemap.comment;
if (this.dest && extname(this.dest) === '.css') {
this.basename = basename(this.dest);
this.dest = dirname(this.dest);
} else {
this.basename = basename(this.filename, extname(this.filename)) + '.css';
}
this.utf8 = false;
/**
* Inherit from `Compiler.prototype`.
*/
this.map = new SourceMapGenerator({
file: this.basename,
sourceRoot: sourcemap.sourceRoot || null
});
}
SourceMapper.prototype.__proto__ = Compiler.prototype;
/**
* Generate and write source map.
*
* @return {String}
* @api private
*/
/**
* Generate and write source map.
*
* @return {String}
* @api private
*/
compile() {
var css = super.compile.call(this)
, out = this.basename + '.map'
, url = this.normalizePath(this.dest
? join(this.dest, out)
: join(dirname(this.filename), out))
, map;
var compile = Compiler.prototype.compile;
SourceMapper.prototype.compile = function(){
var css = compile.call(this)
, out = this.basename + '.map'
, url = this.normalizePath(this.dest
? join(this.dest, out)
: join(dirname(this.filename), out))
, map;
if (this.inline) {
map = this.map.toString();
url = 'data:application/json;'
+ (this.utf8 ? 'charset=utf-8;' : '') + 'base64,'
+ Buffer.from(map).toString('base64');
}
if (this.inline || false !== this.comment)
css += '/*# sourceMappingURL=' + url + ' */';
return css;
};
if (this.inline) {
map = this.map.toString();
url = 'data:application/json;'
+ (this.utf8 ? 'charset=utf-8;' : '') + 'base64,'
+ Buffer.from(map).toString('base64');
}
if (this.inline || false !== this.comment)
css += '/*# sourceMappingURL=' + url + ' */';
return css;
};
/**
* Add mapping information.
*
* @param {String} str
* @param {Node} node
* @return {String}
* @api private
*/
/**
* Add mapping information.
*
* @param {String} str
* @param {Node} node
* @return {String}
* @api private
*/
out(str, node) {
if (node && node.lineno) {
var filename = this.normalizePath(node.filename);
SourceMapper.prototype.out = function(str, node){
if (node && node.lineno) {
var filename = this.normalizePath(node.filename);
this.map.addMapping({
original: {
line: node.lineno,
column: node.column - 1
},
generated: {
line: this.lineno,
column: this.column - 1
},
source: filename
});
this.map.addMapping({
original: {
line: node.lineno,
column: node.column - 1
},
generated: {
line: this.lineno,
column: this.column - 1
},
source: filename
});
if (this.inline && !this.contents[filename]) {
this.map.setSourceContent(filename, fs.readFileSync(node.filename, 'utf-8'));
this.contents[filename] = true;
if (this.inline && !this.contents[filename]) {
this.map.setSourceContent(filename, fs.readFileSync(node.filename, 'utf-8'));
this.contents[filename] = true;
}
}
}
this.move(str);
return str;
};
this.move(str);
return str;
};
/**
* Move current line and column position.
*
* @param {String} str
* @api private
*/
/**
* Move current line and column position.
*
* @param {String} str
* @api private
*/
SourceMapper.prototype.move = function(str){
var lines = str.match(/\n/g)
, idx = str.lastIndexOf('\n');
move(str) {
var lines = str.match(/\n/g)
, idx = str.lastIndexOf('\n');
if (lines) this.lineno += lines.length;
this.column = ~idx
? str.length - idx
: this.column + str.length;
};
if (lines) this.lineno += lines.length;
this.column = ~idx
? str.length - idx
: this.column + str.length;
};
/**
* Normalize the given `path`.
*
* @param {String} path
* @return {String}
* @api private
*/
/**
* Normalize the given `path`.
*
* @param {String} path
* @return {String}
* @api private
*/
SourceMapper.prototype.normalizePath = function(path){
path = relative(this.dest || this.basePath, path);
if ('\\' == sep) {
path = path.replace(/^[a-z]:\\/i, '/')
.replace(/\\/g, '/');
}
return path;
};
normalizePath(path) {
path = relative(this.dest || this.basePath, path);
if ('\\' == sep) {
path = path.replace(/^[a-z]:\\/i, '/')
.replace(/\\/g, '/');
}
return path;
};
/**
* Visit Literal.
*/
/**
* Visit Literal.
*/
var literal = Compiler.prototype.visitLiteral;
SourceMapper.prototype.visitLiteral = function(lit){
var val = literal.call(this, lit)
, filename = this.normalizePath(lit.filename)
, indentsRe = /^\s+/
, lines = val.split('\n');
visitLiteral(lit) {
var val = super.visitLiteral.call(this, lit)
, filename = this.normalizePath(lit.filename)
, indentsRe = /^\s+/
, lines = val.split('\n');
// add mappings for multiline literals
if (lines.length > 1) {
lines.forEach(function(line, i) {
var indents = line.match(indentsRe)
, column = indents && indents[0]
// add mappings for multiline literals
if (lines.length > 1) {
lines.forEach(function (line, i) {
var indents = line.match(indentsRe)
, column = indents && indents[0]
? indents[0].length
: 0;
if (lit.css) column += 2;
if (lit.css) column += 2;
this.map.addMapping({
original: {
line: lit.lineno + i,
column: column
},
generated: {
line: this.lineno + i,
column: 0
},
source: filename
});
}, this);
}
return val;
};
this.map.addMapping({
original: {
line: lit.lineno + i,
column: column
},
generated: {
line: this.lineno + i,
column: 0
},
source: filename
});
}, this);
}
return val;
};
/**
* Visit Charset.
*/
/**
* Visit Charset.
*/
var charset = Compiler.prototype.visitCharset;
SourceMapper.prototype.visitCharset = function(node){
this.utf8 = ('utf-8' == node.val.string.toLowerCase());
return charset.call(this, node);
visitCharset(node) {
this.utf8 = ('utf-8' == node.val.string.toLowerCase());
return super.visitCharset(node);
};
};
{
"name": "stylus",
"description": "Robust, expressive, and feature-rich CSS superset",
"version": "0.59.0",
"version": "0.60.0",
"author": "TJ Holowaychuk <tj@vision-media.ca>",

@@ -31,3 +31,3 @@ "keywords": [

"dependencies": {
"@adobe/css-tools": "^4.0.1",
"@adobe/css-tools": "~4.2.0",
"debug": "^4.3.2",

@@ -34,0 +34,0 @@ "glob": "^7.1.6",

@@ -62,6 +62,2 @@ <p align="center"><a href="https://stylus-lang.com" target="_blank" rel="noopener noreferrer"><img width="150" src="https://raw.githubusercontent.com/stylus/stylus/dev/graphics/Logos/stylus.png" alt="Stylus logo"></a></p>

### 📖 New Docs (alpha)
Try our new [official documentation website](http://stylus-docs.netlify.app/) and give us feedback via [github issues](https://github.com/stylus/stylus/issues), thanks.
### Community modules

@@ -68,0 +64,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc