Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

less

Package Overview
Dependencies
Maintainers
2
Versions
130
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

less - npm Package Compare versions

Comparing version 1.4.2 to 1.5.0-b1

.jshintignore

26

CHANGELOG.md

@@ -0,1 +1,23 @@

# 1.5.0 Beta 1
2013-09-01
- sourcemap support
- support for import inline option to include css that you do NOT want less to parse e.g. `@import (inline) "file.css";`
- better support for modifyVars (refresh styles with new variables, using a file cache), is now more resiliant
- support for import reference option to reference external css, but not output it. Any mixin calls or extend's will be output.
- support for guards on selectors (currently only if you have a single selector)
- Added min/max functions
- fix bad spaces between namespace operators
- do not compress comment if it begins with an exclamation mark
- change to not throw exceptions in toCSS - always return an error object
- allow property merging through the +: syntax
- Fix the saturate function to pass through when using the CSS syntax
- Added svg-gradient function
- Added no-js option to lessc (in browser, use javascriptEnabled: false) which disallows JavaScript in less files
- switched from the little supported and buggy cssmin (previously ycssmin) to clean-css
- Browser: added logLevel option to control logging (2 = everything, 1 = errors only, 0 = no logging)
- Browser: added errorReporting option which can be "html" (default) or "console" or a function
- A few bug fixes for media queries and extends
# 1.4.2

@@ -25,3 +47,3 @@

# 1.4.0 Beta 4
2013-05-04

@@ -59,3 +81,3 @@

- an error is shown if properties are used outside of a ruleset
- added extract function which picks a value out of a list, e.g. extract(12 13 14, 3) => 3
- added extract function which picks a value out of a list, e.g. extract(12 13 14, 3) => 14
- added luma, hsvhue, hsvsaturation, hsvvalue functions

@@ -62,0 +84,0 @@ - added pow, pi, mod, tan, sin, cos, atan, asin, acos and sqrt math functions

847

lib/less/browser.js
//
// browser.js - client-side engine
//
/*global less, window, document, XMLHttpRequest, location */

@@ -14,2 +15,15 @@ var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);

var logLevel = {
info: 2,
errors: 1,
none: 0
};
// The amount of logging in the javascript console.
// 2 - Information and errors
// 1 - Errors
// 0 - None
// Defaults to 2
less.logLevel = typeof(less.logLevel) != 'undefined' ? less.logLevel : logLevel.info;
// Load styles asynchronously (default: false)

@@ -39,158 +53,271 @@ //

//
// Watch mode
//
less.watch = function () {
if (!less.watchMode ){
less.env = 'development';
initRunningMode();
}
return this.watchMode = true
};
var typePattern = /^text\/(x-)?less$/;
var cache = null;
var fileCache = {};
less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; };
function initRunningMode(){
if (less.env === 'development') {
less.optimization = 0;
less.watchTimer = setInterval(function () {
if (less.watchMode) {
loadStyleSheets(function (e, root, _, sheet, env) {
if (e) {
error(e, sheet.href);
} else if (root) {
createCSS(root.toCSS(less), sheet, env.lastModified);
}
});
}
}, less.poll);
} else {
less.optimization = 3;
function log(str, level) {
if (less.env == 'development' && typeof(console) !== 'undefined' && less.logLevel >= level) {
console.log('less: ' + str);
}
}
if (/!watch/.test(location.hash)) {
less.watch();
function extractId(href) {
return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain
.replace(/^\//, '' ) // Remove root /
.replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension
.replace(/[^\.\w-]+/g, '-') // Replace illegal characters
.replace(/\./g, ':'); // Replace dots with colons(for valid id)
}
var cache = null;
function errorConsole(e, rootHref) {
var template = '{line} {content}';
var filename = e.filename || rootHref;
var errors = [];
var content = (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
" in " + filename + " ";
if (less.env != 'development') {
try {
cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
} catch (_) {}
var errorline = function (e, i, classname) {
if (e.extract[i] !== undefined) {
errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
.replace(/\{class\}/, classname)
.replace(/\{content\}/, e.extract[i]));
}
};
if (e.extract) {
errorline(e, 0, '');
errorline(e, 1, 'line');
errorline(e, 2, '');
content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n' +
errors.join('\n');
} else if (e.stack) {
content += e.stack;
}
log(content, logLevel.errors);
}
//
// Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
//
var links = document.getElementsByTagName('link');
var typePattern = /^text\/(x-)?less$/;
function createCSS(styles, sheet, lastModified) {
// Strip the query-string
var href = sheet.href || '';
less.sheets = [];
// If there is no title set, use the filename, minus the extension
var id = 'less:' + (sheet.title || extractId(href));
for (var i = 0; i < links.length; i++) {
if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
(links[i].type.match(typePattern)))) {
less.sheets.push(links[i]);
// If this has already been inserted into the DOM, we may need to replace it
var oldCss = document.getElementById(id);
var keepOldCss = false;
// Create a new stylesheet node for insertion or (if necessary) replacement
var css = document.createElement('style');
css.setAttribute('type', 'text/css');
if (sheet.media) {
css.setAttribute('media', sheet.media);
}
}
css.id = id;
//
// With this function, it's possible to alter variables and re-render
// CSS without reloading less-files
//
var session_cache = '';
less.modifyVars = function(record) {
var str = session_cache;
for (var name in record) {
str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+
((record[name].slice(-1) === ';')? record[name] : record[name] +';');
if (css.styleSheet) { // IE
try {
css.styleSheet.cssText = styles;
} catch (e) {
throw new(Error)("Couldn't reassign styleSheet.cssText.");
}
} else {
css.appendChild(document.createTextNode(styles));
// If new contents match contents of oldCss, don't replace oldCss
keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 &&
oldCss.firstChild.nodeValue === css.firstChild.nodeValue);
}
new(less.Parser)(new less.tree.parseEnv(less)).parse(str, function (e, root) {
if (e) {
error(e, "session_cache");
var head = document.getElementsByTagName('head')[0];
// If there is no oldCss, just append; otherwise, only append if we need
// to replace oldCss with an updated stylesheet
if (oldCss === null || keepOldCss === false) {
var nextEl = sheet && sheet.nextSibling || null;
if (nextEl) {
nextEl.parentNode.insertBefore(css, nextEl);
} else {
createCSS(root.toCSS(less), less.sheets[less.sheets.length - 1]);
head.appendChild(css);
}
});
};
}
if (oldCss && keepOldCss === false) {
oldCss.parentNode.removeChild(oldCss);
}
less.refresh = function (reload) {
var startTime, endTime;
startTime = endTime = new(Date);
// Don't update the local store if the file wasn't modified
if (lastModified && cache) {
log('saving ' + href + ' to cache.', logLevel.info);
try {
cache.setItem(href, styles);
cache.setItem(href + ':timestamp', lastModified);
} catch(e) {
//TODO - could do with adding more robust error handling
log('failed to save', logLevel.errors);
}
}
}
loadStyleSheets(function (e, root, _, sheet, env) {
if (e) {
return error(e, sheet.href);
function errorHTML(e, rootHref) {
var id = 'less-error-message:' + extractId(rootHref || "");
var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
var elem = document.createElement('div'), timer, content, errors = [];
var filename = e.filename || rootHref;
var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
elem.id = id;
elem.className = "less-error-message";
content = '<h3>' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
'</h3>' + '<p>in <a href="' + filename + '">' + filenameNoPath + "</a> ";
var errorline = function (e, i, classname) {
if (e.extract[i] !== undefined) {
errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
.replace(/\{class\}/, classname)
.replace(/\{content\}/, e.extract[i]));
}
if (env.local) {
log("loading " + sheet.href + " from cache.");
} else {
log("parsed " + sheet.href + " successfully.");
createCSS(root.toCSS(less), sheet, env.lastModified);
}
log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
(env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
endTime = new(Date);
}, reload);
};
loadStyles();
};
less.refreshStyles = loadStyles;
if (e.extract) {
errorline(e, 0, '');
errorline(e, 1, 'line');
errorline(e, 2, '');
content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
'<ul>' + errors.join('') + '</ul>';
} else if (e.stack) {
content += '<br/>' + e.stack.split('\n').slice(1).join('<br/>');
}
elem.innerHTML = content;
less.refresh(less.env === 'development');
// CSS for error messages
createCSS([
'.less-error-message ul, .less-error-message li {',
'list-style-type: none;',
'margin-right: 15px;',
'padding: 4px 0;',
'margin: 0;',
'}',
'.less-error-message label {',
'font-size: 12px;',
'margin-right: 15px;',
'padding: 4px 0;',
'color: #cc7777;',
'}',
'.less-error-message pre {',
'color: #dd6666;',
'padding: 4px 0;',
'margin: 0;',
'display: inline-block;',
'}',
'.less-error-message pre.line {',
'color: #ff0000;',
'}',
'.less-error-message h3 {',
'font-size: 20px;',
'font-weight: bold;',
'padding: 15px 0 5px 0;',
'margin: 0;',
'}',
'.less-error-message a {',
'color: #10a',
'}',
'.less-error-message .error {',
'color: red;',
'font-weight: bold;',
'padding-bottom: 2px;',
'border-bottom: 1px dashed red;',
'}'
].join('\n'), { title: 'error-message' });
function loadStyles() {
var styles = document.getElementsByTagName('style');
for (var i = 0; i < styles.length; i++) {
if (styles[i].type.match(typePattern)) {
var env = new less.tree.parseEnv(less);
env.filename = document.location.href.replace(/#.*$/, '');
elem.style.cssText = [
"font-family: Arial, sans-serif",
"border: 1px solid #e00",
"background-color: #eee",
"border-radius: 5px",
"-webkit-border-radius: 5px",
"-moz-border-radius: 5px",
"color: #e00",
"padding: 15px",
"margin-bottom: 15px"
].join(';');
new(less.Parser)(env).parse(styles[i].innerHTML || '', function (e, cssAST) {
if (e) {
return error(e, "inline");
}
var css = cssAST.toCSS(less);
var style = styles[i];
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
if (less.env == 'development') {
timer = setInterval(function () {
if (document.body) {
if (document.getElementById(id)) {
document.body.replaceChild(elem, document.getElementById(id));
} else {
style.innerHTML = css;
document.body.insertBefore(elem, document.body.firstChild);
}
});
}
clearInterval(timer);
}
}, 10);
}
}
function loadStyleSheets(callback, reload) {
for (var i = 0; i < less.sheets.length; i++) {
loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
function error(e, rootHref) {
if (!less.errorReporting || less.errorReporting === "html") {
errorHTML(e, rootHref);
} else if (less.errorReporting === "console") {
errorConsole(e, rootHref);
} else if (typeof less.errorReporting === 'function') {
less.errorReporting("add", e, rootHref);
}
}
function pathDiff(url, baseUrl) {
// diff between two paths to create a relative path
function removeErrorHTML(path) {
var node = document.getElementById('less-error-message:' + extractId(path));
if (node) {
node.parentNode.removeChild(node);
}
}
var urlParts = extractUrlParts(url),
baseUrlParts = extractUrlParts(baseUrl),
i, max, urlDirectories, baseUrlDirectories, diff = "";
if (urlParts.hostPart !== baseUrlParts.hostPart) {
return "";
function removeErrorConsole(path) {
//no action
}
function removeError(path) {
if (!less.errorReporting || less.errorReporting === "html") {
removeErrorHTML(path);
} else if (less.errorReporting === "console") {
removeErrorConsole(path);
} else if (typeof less.errorReporting === 'function') {
less.errorReporting("remove", path);
}
max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
for(i = 0; i < max; i++) {
if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
}
function loadStyles(newVars) {
var styles = document.getElementsByTagName('style'),
style;
for (var i = 0; i < styles.length; i++) {
style = styles[i];
if (style.type.match(typePattern)) {
var env = new less.tree.parseEnv(less),
lessText = style.innerHTML || '';
env.filename = document.location.href.replace(/#.*$/, '');
if (newVars) {
env.useFileCache = true;
lessText += "\n" + newVars;
}
/*jshint loopfunc:true */
// use closure to store current value of i
var callback = (function(style) {
return function (e, cssAST) {
if (e) {
return error(e, "inline");
}
var css = cssAST.toCSS(less);
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.innerHTML = css;
}
};
})(style);
new(less.Parser)(env).parse(lessText, callback);
}
}
baseUrlDirectories = baseUrlParts.directories.slice(i);
urlDirectories = urlParts.directories.slice(i);
for(i = 0; i < baseUrlDirectories.length-1; i++) {
diff += "../";
}
for(i = 0; i < urlDirectories.length-1; i++) {
diff += urlDirectories[i] + "/";
}
return diff;
}

@@ -213,3 +340,3 @@

// Stylesheets in IE don't always return the full path
// Stylesheets in IE don't always return the full path
if (!urlParts[1] || urlParts[2]) {

@@ -225,3 +352,3 @@ baseUrlParts = baseUrl.match(urlPartsRegex);

}
if (urlParts[3]) {

@@ -254,148 +381,41 @@ directories = urlParts[3].replace(/\\/g, "/").split("/");

function loadStyleSheet(sheet, callback, reload, remaining) {
function pathDiff(url, baseUrl) {
// diff between two paths to create a relative path
// sheet may be set to the stylesheet for the initial load or a collection of properties including
// some env variables for imports
var hrefParts = extractUrlParts(sheet.href, window.location.href);
var href = hrefParts.url;
var css = cache && cache.getItem(href);
var timestamp = cache && cache.getItem(href + ':timestamp');
var styles = { css: css, timestamp: timestamp };
var env;
var newFileInfo = {
relativeUrls: less.relativeUrls,
currentDirectory: hrefParts.path,
filename: href
};
if (sheet instanceof less.tree.parseEnv) {
env = new less.tree.parseEnv(sheet);
newFileInfo.entryPath = env.currentFileInfo.entryPath;
newFileInfo.rootpath = env.currentFileInfo.rootpath;
newFileInfo.rootFilename = env.currentFileInfo.rootFilename;
} else {
env = new less.tree.parseEnv(less);
env.mime = sheet.type;
newFileInfo.entryPath = hrefParts.path;
newFileInfo.rootpath = less.rootpath || hrefParts.path;
newFileInfo.rootFilename = href;
var urlParts = extractUrlParts(url),
baseUrlParts = extractUrlParts(baseUrl),
i, max, urlDirectories, baseUrlDirectories, diff = "";
if (urlParts.hostPart !== baseUrlParts.hostPart) {
return "";
}
if (env.relativeUrls) {
//todo - this relies on option being set on less object rather than being passed in as an option
// - need an originalRootpath
if (less.rootpath) {
newFileInfo.rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path;
} else {
newFileInfo.rootpath = hrefParts.path;
}
max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
for(i = 0; i < max; i++) {
if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
}
xhr(href, sheet.type, function (data, lastModified) {
// Store data this session
session_cache += data.replace(/@import .+?;/ig, '');
if (!reload && styles && lastModified &&
(new(Date)(lastModified).valueOf() ===
new(Date)(styles.timestamp).valueOf())) {
// Use local copy
createCSS(styles.css, sheet);
callback(null, null, data, sheet, { local: true, remaining: remaining }, href);
} else {
// Use remote copy (re-parse)
try {
env.contents[href] = data; // Updating content cache
env.paths = [hrefParts.path];
env.currentFileInfo = newFileInfo;
new(less.Parser)(env).parse(data, function (e, root) {
if (e) { return callback(e, null, null, sheet); }
try {
callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href);
//TODO - there must be a better way? A generic less-to-css function that can both call error
//and removeNode where appropriate
//should also add tests
if (env.currentFileInfo.rootFilename === href) {
removeNode(document.getElementById('less-error-message:' + extractId(href)));
}
} catch (e) {
callback(e, null, null, sheet);
}
});
} catch (e) {
callback(e, null, null, sheet);
}
}
}, function (status, url) {
callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, null, sheet);
});
baseUrlDirectories = baseUrlParts.directories.slice(i);
urlDirectories = urlParts.directories.slice(i);
for(i = 0; i < baseUrlDirectories.length-1; i++) {
diff += "../";
}
for(i = 0; i < urlDirectories.length-1; i++) {
diff += urlDirectories[i] + "/";
}
return diff;
}
function extractId(href) {
return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain
.replace(/^\//, '' ) // Remove root /
.replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension
.replace(/[^\.\w-]+/g, '-') // Replace illegal characters
.replace(/\./g, ':'); // Replace dots with colons(for valid id)
}
function createCSS(styles, sheet, lastModified) {
// Strip the query-string
var href = sheet.href || '';
// If there is no title set, use the filename, minus the extension
var id = 'less:' + (sheet.title || extractId(href));
// If this has already been inserted into the DOM, we may need to replace it
var oldCss = document.getElementById(id);
var keepOldCss = false;
// Create a new stylesheet node for insertion or (if necessary) replacement
var css = document.createElement('style');
css.setAttribute('type', 'text/css');
if (sheet.media) {
css.setAttribute('media', sheet.media);
}
css.id = id;
if (css.styleSheet) { // IE
function getXMLHttpRequest() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else {
try {
css.styleSheet.cssText = styles;
/*global ActiveXObject */
return new ActiveXObject("MSXML2.XMLHTTP.3.0");
} catch (e) {
throw new(Error)("Couldn't reassign styleSheet.cssText.");
log("browser doesn't support AJAX.", logLevel.errors);
return null;
}
} else {
css.appendChild(document.createTextNode(styles));
// If new contents match contents of oldCss, don't replace oldCss
keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 &&
oldCss.firstChild.nodeValue === css.firstChild.nodeValue);
}
var head = document.getElementsByTagName('head')[0];
// If there is no oldCss, just append; otherwise, only append if we need
// to replace oldCss with an updated stylesheet
if (oldCss == null || keepOldCss === false) {
var nextEl = sheet && sheet.nextSibling || null;
(nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl);
}
if (oldCss && keepOldCss === false) {
head.removeChild(oldCss);
}
// Don't update the local store if the file wasn't modified
if (lastModified && cache) {
log('saving ' + href + ' to cache.');
try {
cache.setItem(href, styles);
cache.setItem(href + ':timestamp', lastModified);
} catch(e) {
//TODO - could do with adding more robust error handling
log('failed to save');
}
}
}
function xhr(url, type, callback, errback) {
function doXHR(url, type, callback, errback) {
var xhr = getXMLHttpRequest();

@@ -407,2 +427,3 @@ var async = isFileProtocol ? less.fileAsync : less.async;

}
log("XHR: Getting '" + url + "'", logLevel.info);
xhr.open('GET', url, async);

@@ -412,2 +433,11 @@ xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');

function handleResponse(xhr, callback, errback) {
if (xhr.status >= 200 && xhr.status < 300) {
callback(xhr.responseText,
xhr.getResponseHeader("Last-Modified"));
} else if (typeof(errback) === 'function') {
errback(xhr.status, url);
}
}
if (isFileProtocol && !less.fileAsync) {

@@ -428,130 +458,217 @@ if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {

}
}
function handleResponse(xhr, callback, errback) {
if (xhr.status >= 200 && xhr.status < 300) {
callback(xhr.responseText,
xhr.getResponseHeader("Last-Modified"));
} else if (typeof(errback) === 'function') {
errback(xhr.status, url);
function loadFile(originalHref, currentFileInfo, callback, env, newVars) {
if (currentFileInfo && currentFileInfo.currentDirectory && !/^([a-z-]+:)?\//.test(originalHref)) {
originalHref = currentFileInfo.currentDirectory + originalHref;
}
// sheet may be set to the stylesheet for the initial load or a collection of properties including
// some env variables for imports
var hrefParts = extractUrlParts(originalHref, window.location.href);
var href = hrefParts.url;
var newFileInfo = {
currentDirectory: hrefParts.path,
filename: href
};
if (currentFileInfo) {
newFileInfo.entryPath = currentFileInfo.entryPath;
newFileInfo.rootpath = currentFileInfo.rootpath;
newFileInfo.rootFilename = currentFileInfo.rootFilename;
newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
} else {
newFileInfo.entryPath = hrefParts.path;
newFileInfo.rootpath = less.rootpath || hrefParts.path;
newFileInfo.rootFilename = href;
newFileInfo.relativeUrls = env.relativeUrls;
}
if (newFileInfo.relativeUrls) {
if (env.rootpath) {
newFileInfo.rootpath = extractUrlParts(env.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path;
} else {
newFileInfo.rootpath = hrefParts.path;
}
}
}
function getXMLHttpRequest() {
if (window.XMLHttpRequest) {
return new(XMLHttpRequest);
} else {
if (env.useFileCache && fileCache[href]) {
try {
return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
var lessText = fileCache[href];
if (newVars) {
lessText += "\n" + newVars;
}
callback(null, lessText, href, newFileInfo, { lastModified: new Date() });
} catch (e) {
log("browser doesn't support AJAX.");
return null;
callback(e, null, href);
}
return;
}
}
function removeNode(node) {
return node && node.parentNode.removeChild(node);
}
doXHR(href, env.mime, function (data, lastModified) {
// per file cache
fileCache[href] = data;
function log(str) {
if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
// Use remote copy (re-parse)
try {
callback(null, data, href, newFileInfo, { lastModified: lastModified });
} catch (e) {
callback(e, null, href);
}
}, function (status, url) {
callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, href);
});
}
function error(e, rootHref) {
var id = 'less-error-message:' + extractId(rootHref || "");
var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
var elem = document.createElement('div'), timer, content, error = [];
var filename = e.filename || rootHref;
var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
function loadStyleSheet(sheet, callback, reload, remaining, newVars) {
elem.id = id;
elem.className = "less-error-message";
var env = new less.tree.parseEnv(less);
env.mime = sheet.type;
content = '<h3>' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
'</h3>' + '<p>in <a href="' + filename + '">' + filenameNoPath + "</a> ";
if (newVars) {
env.useFileCache = true;
}
var errorline = function (e, i, classname) {
if (e.extract[i] != undefined) {
error.push(template.replace(/\{line\}/, (parseInt(e.line) || 0) + (i - 1))
.replace(/\{class\}/, classname)
.replace(/\{content\}/, e.extract[i]));
loadFile(sheet.href, null, function(e, data, path, newFileInfo, webInfo) {
if (webInfo) {
webInfo.remaining = remaining;
var css = cache && cache.getItem(path),
timestamp = cache && cache.getItem(path + ':timestamp');
if (!reload && timestamp && webInfo.lastModified &&
(new(Date)(webInfo.lastModified).valueOf() ===
new(Date)(timestamp).valueOf())) {
// Use local copy
createCSS(css, sheet);
webInfo.local = true;
callback(null, null, data, sheet, webInfo, path);
return;
}
}
};
if (e.extract) {
errorline(e, 0, '');
errorline(e, 1, 'line');
errorline(e, 2, '');
content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
'<ul>' + error.join('') + '</ul>';
} else if (e.stack) {
content += '<br/>' + e.stack.split('\n').slice(1).join('<br/>');
}
elem.innerHTML = content;
//TODO add tests around how this behaves when reloading
removeError(path);
// CSS for error messages
createCSS([
'.less-error-message ul, .less-error-message li {',
'list-style-type: none;',
'margin-right: 15px;',
'padding: 4px 0;',
'margin: 0;',
'}',
'.less-error-message label {',
'font-size: 12px;',
'margin-right: 15px;',
'padding: 4px 0;',
'color: #cc7777;',
'}',
'.less-error-message pre {',
'color: #dd6666;',
'padding: 4px 0;',
'margin: 0;',
'display: inline-block;',
'}',
'.less-error-message pre.line {',
'color: #ff0000;',
'}',
'.less-error-message h3 {',
'font-size: 20px;',
'font-weight: bold;',
'padding: 15px 0 5px 0;',
'margin: 0;',
'}',
'.less-error-message a {',
'color: #10a',
'}',
'.less-error-message .error {',
'color: red;',
'font-weight: bold;',
'padding-bottom: 2px;',
'border-bottom: 1px dashed red;',
'}'
].join('\n'), { title: 'error-message' });
if (data) {
env.currentFileInfo = newFileInfo;
new(less.Parser)(env).parse(data, function (e, root) {
if (e) { return callback(e, null, null, sheet); }
try {
callback(e, root, data, sheet, webInfo, path);
} catch (e) {
callback(e, null, null, sheet);
}
});
} else {
callback(e, null, null, sheet, webInfo, path);
}
}, env, newVars);
}
elem.style.cssText = [
"font-family: Arial, sans-serif",
"border: 1px solid #e00",
"background-color: #eee",
"border-radius: 5px",
"-webkit-border-radius: 5px",
"-moz-border-radius: 5px",
"color: #e00",
"padding: 15px",
"margin-bottom: 15px"
].join(';');
function loadStyleSheets(callback, reload, newVars) {
for (var i = 0; i < less.sheets.length; i++) {
loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), newVars);
}
}
if (less.env == 'development') {
timer = setInterval(function () {
if (document.body) {
if (document.getElementById(id)) {
document.body.replaceChild(elem, document.getElementById(id));
} else {
document.body.insertBefore(elem, document.body.firstChild);
}
clearInterval(timer);
function initRunningMode(){
if (less.env === 'development') {
less.optimization = 0;
less.watchTimer = setInterval(function () {
if (less.watchMode) {
loadStyleSheets(function (e, root, _, sheet, env) {
if (e) {
error(e, sheet.href);
} else if (root) {
createCSS(root.toCSS(less), sheet, env.lastModified);
}
});
}
}, 10);
}, less.poll);
} else {
less.optimization = 3;
}
}
//
// Watch mode
//
less.watch = function () {
if (!less.watchMode ){
less.env = 'development';
initRunningMode();
}
return this.watchMode = true;
};
less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; };
if (/!watch/.test(location.hash)) {
less.watch();
}
if (less.env != 'development') {
try {
cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
} catch (_) {}
}
//
// Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
//
var links = document.getElementsByTagName('link');
less.sheets = [];
for (var i = 0; i < links.length; i++) {
if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
(links[i].type.match(typePattern)))) {
less.sheets.push(links[i]);
}
}
//
// With this function, it's possible to alter variables and re-render
// CSS without reloading less-files
//
less.modifyVars = function(record) {
var newVars = "";
for (var name in record) {
newVars += ((name.slice(0,1) === '@')? '' : '@') + name +': '+
((record[name].slice(-1) === ';')? record[name] : record[name] +';');
}
less.refresh(false, newVars);
};
less.refresh = function (reload, newVars) {
var startTime, endTime;
startTime = endTime = new Date();
loadStyleSheets(function (e, root, _, sheet, env) {
if (e) {
return error(e, sheet.href);
}
if (env.local) {
log("loading " + sheet.href + " from cache.", logLevel.info);
} else {
log("parsed " + sheet.href + " successfully.", logLevel.info);
createCSS(root.toCSS(less), sheet, env.lastModified);
}
log("css for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms', logLevel.info);
if (env.remaining === 0) {
log("css generated in " + (new Date() - startTime) + 'ms', logLevel.info);
}
endTime = new Date();
}, reload, newVars);
loadStyles(newVars);
};
less.refreshStyles = loadStyles;
less.Parser.fileLoader = loadFile;
less.refresh(less.env === 'development');

@@ -9,2 +9,3 @@ (function (tree) {

'relativeUrls', // option - whether to adjust URL's to be relative
'rootpath', // option - rootpath to append to URL's
'strictImports', // option -

@@ -15,3 +16,5 @@ 'dumpLineNumbers', // option - whether to dump line numbers

'syncImport', // option - whether to import synchronously
'javascriptEnabled',// option - whether JavaScript is enabled. if undefined, defaults to true
'mime', // browser only - mime type for sheet import
'useFileCache', // browser only - whether to use the per file session cache
'currentFileInfo' // information about the current file - for error reporting and importing and making urls relative etc.

@@ -26,3 +29,4 @@ ];

// 'rootFilename' - filename of the base file
// 'entryPath' = absolute path to the entry file
// 'entryPath' - absolute path to the entry file
// 'reference' - whether the file should not be output and only output parts that are referenced

@@ -52,10 +56,2 @@ tree.parseEnv = function(options) {

tree.parseEnv.prototype.toSheet = function (path) {
var env = new tree.parseEnv(this);
env.href = path;
//env.title = path;
env.type = this.mime;
return env;
};
var evalCopyProperties = [

@@ -68,3 +64,5 @@ 'silent', // whether to swallow errors and warnings

'strictMath', // whether math has to be within parenthesis
'strictUnits' // whether units need to evaluate correctly
'strictUnits', // whether units need to evaluate correctly
'cleancss', // whether to compress with clean-css
'sourceMap' // whether to output a source map
];

@@ -97,2 +95,29 @@

tree.evalEnv.prototype.normalizePath = function( path ) {
var
segments = path.split("/").reverse(),
segment;
path = [];
while (segments.length !== 0 ) {
segment = segments.pop();
switch( segment ) {
case ".":
break;
case "..":
if ((path.length === 0) || (path[path.length - 1] === "..")) {
path.push( segment );
} else {
path.pop();
}
break;
default:
path.push( segment );
break;
}
}
return path.join("/");
};
//todo - do the same for the toCSS env

@@ -110,3 +135,4 @@ //tree.toCSSEnv = function (options) {

}
}
})(require('./tree'));
};
})(require('./tree'));
(function (tree) {
/*jshint loopfunc:true */
tree.extendFinderVisitor = function() {

@@ -249,3 +251,3 @@ this._visitor = new tree.visitor(this);

// if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
if (extend.allowBefore || (haystackSelectorIndex == 0 && hackstackElementIndex == 0)) {
if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator});

@@ -261,3 +263,3 @@ }

targetCombinator = haystackElement.combinator.value;
if (targetCombinator == '' && hackstackElementIndex === 0) {
if (targetCombinator === '' && hackstackElementIndex === 0) {
targetCombinator = ' ';

@@ -330,3 +332,4 @@ }

firstElement,
match;
match,
newElements;

@@ -339,3 +342,4 @@ for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {

replacementSelector.elements[0].value,
replacementSelector.elements[0].index
replacementSelector.elements[0].index,
replacementSelector.elements[0].currentFileInfo
);

@@ -349,13 +353,20 @@

path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
newElements = selector.elements
.slice(currentSelectorPathElementIndex, match.index)
.concat([firstElement])
.concat(replacementSelector.elements.slice(1));
path.push(new tree.Selector(
selector.elements
.slice(currentSelectorPathElementIndex, match.index)
.concat([firstElement])
.concat(replacementSelector.elements.slice(1))
));
if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {
path[path.length - 1].elements =
path[path.length - 1].elements.concat(newElements);
} else {
path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
path.push(new tree.Selector(
newElements
));
}
currentSelectorPathIndex = match.endPathIndex;
currentSelectorPathElementIndex = match.endPathElementIndex;
if (currentSelectorPathElementIndex >= selector.elements.length) {
if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {
currentSelectorPathElementIndex = 0;

@@ -396,2 +407,2 @@ currentSelectorPathIndex++;

})(require('./tree'));
})(require('./tree'));

@@ -16,2 +16,10 @@ (function (tree) {

hsla: function (h, s, l, a) {
function hue(h) {
h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
if (h * 6 < 1) { return m1 + (m2 - m1) * h * 6; }
else if (h * 2 < 1) { return m2; }
else if (h * 3 < 2) { return m1 + (m2 - m1) * (2/3 - h) * 6; }
else { return m1; }
}
h = (number(h) % 360) / 360;

@@ -27,10 +35,2 @@ s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a));

a);
function hue(h) {
h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
else if (h * 2 < 1) return m2;
else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
else return m1;
}
},

@@ -101,2 +101,7 @@

saturate: function (color, amount) {
// filter: saturate(3.2);
// should be kept as is, so check for color
if (!color.rgb) {
return null;
}
var hsl = color.toHSL();

@@ -224,2 +229,3 @@

for (var i = 0; i < args.length; i++) {
/*jshint loopfunc:true */
str = str.replace(/%[sda]/i, function(token) {

@@ -261,2 +267,3 @@ var value = token.match(/s/i) ? args[i].value : args[i].toCSS();

if (n instanceof tree.Dimension) {
/*jshint eqnull:true */
return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit);

@@ -269,2 +276,45 @@ } else if (typeof(n) === 'number') {

},
_minmax: function (isMin, args) {
args = Array.prototype.slice.call(args);
switch(args.length) {
case 0: throw { type: "Argument", message: "one or more arguments required" };
case 1: return args[0];
}
var i, j, current, currentUnified, referenceUnified, unit,
order = [], // elems only contains original argument values.
values = {}; // key is the unit.toString() for unified tree.Dimension values,
// value is the index into the order array.
for (i = 0; i < args.length; i++) {
current = args[i];
if (!(current instanceof tree.Dimension)) {
order.push(current);
continue;
}
currentUnified = current.unify();
unit = currentUnified.unit.toString();
j = values[unit];
if (j === undefined) {
values[unit] = order.length;
order.push(current);
continue;
}
referenceUnified = order[j].unify();
if ( isMin && currentUnified.value < referenceUnified.value ||
!isMin && currentUnified.value > referenceUnified.value) {
order[j] = current;
}
}
if (order.length == 1) {
return order[0];
}
args = order.map(function (a) { return a.toCSS(this.env); })
.join(this.env.compress ? "," : ", ");
return new(tree.Anonymous)((isMin ? "min" : "max") + "(" + args + ")");
},
min: function () {
return this._minmax(true, arguments);
},
max: function () {
return this._minmax(false, arguments);
},
argb: function (color) {

@@ -424,6 +474,6 @@ return new(tree.Anonymous)(color.toARGB());

useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
if (useBase64) mimetype += ';base64';
if (useBase64) { mimetype += ';base64'; }
}
else {
useBase64 = /;base64$/.test(mimetype)
useBase64 = /;base64$/.test(mimetype);
}

@@ -456,2 +506,79 @@

return new(tree.URL)(new(tree.Anonymous)(uri));
},
"svg-gradient": function(direction) {
function throwArgumentDescriptor() {
throw { type: "Argument", message: "svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]" };
}
if (arguments.length < 3) {
throwArgumentDescriptor();
}
var stops = Array.prototype.slice.call(arguments, 1),
gradientDirectionSvg,
gradientType = "linear",
rectangleDimension = 'x="0" y="0" width="1" height="1"',
useBase64 = true,
renderEnv = {compress: false},
returner,
directionValue = direction.toCSS(renderEnv),
i, color, position, positionValue, alpha;
switch (directionValue) {
case "to bottom":
gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
break;
case "to right":
gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
break;
case "to bottom right":
gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
break;
case "to top right":
gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
break;
case "ellipse":
case "ellipse at center":
gradientType = "radial";
gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
break;
default:
throw { type: "Argument", message: "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" };
}
returner = '<?xml version="1.0" ?>' +
'<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' +
'<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>';
for (i = 0; i < stops.length; i+= 1) {
if (stops[i].value) {
color = stops[i].value[0];
position = stops[i].value[1];
} else {
color = stops[i];
position = undefined;
}
if (!(color instanceof tree.Color) || (!((i === 0 || i+1 === stops.length) && position === undefined) && !(position instanceof tree.Dimension))) {
throwArgumentDescriptor();
}
positionValue = position ? position.toCSS(renderEnv) : i === 0 ? "0%" : "100%";
alpha = color.alpha;
returner += '<stop offset="' + positionValue + '" stop-color="' + color.toRGB() + '"' + (alpha < 1 ? ' stop-opacity="' + alpha + '"' : '') + '/>';
}
returner += '</' + gradientType + 'Gradient>' +
'<rect ' + rectangleDimension + ' fill="url(#gradient)" /></svg>';
if (useBase64) {
// only works in node, needs interface to what is supported in environment
try {
returner = new Buffer(returner).toString('base64');
} catch(e) {
useBase64 = false;
}
}
returner = "'data:image/svg+xml" + (useBase64 ? ";base64" : "") + "," + returner + "'";
return new(tree.URL)(new(tree.Anonymous)(returner));
}

@@ -493,2 +620,3 @@ };

return function(n) {
/*jshint eqnull:true */
if (unit != null) {

@@ -495,0 +623,0 @@ n = n.unify();

@@ -30,5 +30,6 @@ (function (tree) {

var importVisitor = this,
evaldImportNode;
evaldImportNode,
inlineCSS = importNode.options.inline;
if (!importNode.css) {
if (!importNode.css || inlineCSS) {

@@ -45,7 +46,8 @@ try {

if (evaldImportNode && !evaldImportNode.css) {
if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {
importNode = evaldImportNode;
this.importCount++;
var env = new tree.evalEnv(this.env, this.env.frames.slice(0));
this._importer.push(importNode.getPath(), importNode.currentFileInfo, function (e, root, imported) {
this._importer.push(importNode.getPath(), importNode.currentFileInfo, importNode.options, function (e, root, imported) {
if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }

@@ -64,7 +66,10 @@ if (imported && !importNode.options.multiple) { importNode.skip = imported; }

importNode.root = root;
new(tree.importVisitor)(importVisitor._importer, subFinish, env)
.run(root);
} else {
subFinish();
if (!inlineCSS && !importNode.skip) {
new(tree.importVisitor)(importVisitor._importer, subFinish, env)
.run(root);
return;
}
}
subFinish();
});

@@ -71,0 +76,0 @@ }

@@ -8,5 +8,4 @@ var path = require('path'),

var less = {
version: [1, 4, 2],
version: [1, 5, "0-b1"],
Parser: require('./parser').Parser,
importer: require('./parser').importer,
tree: require('./tree'),

@@ -25,11 +24,13 @@ render: function (input, options, callback) {

parser.parse(input, function (e, root) {
callback(e, root && root.toCSS && root.toCSS(options));
try { callback(e, root && root.toCSS && root.toCSS(options)); }
catch (err) { callback(err); }
});
} else {
ee = new(require('events').EventEmitter);
ee = new (require('events').EventEmitter)();
process.nextTick(function () {
parser.parse(input, function (e, root) {
if (e) { ee.emit('error', e) }
else { ee.emit('success', root.toCSS(options)) }
if (e) { return ee.emit('error', e); }
try { ee.emit('success', root.toCSS(options)); }
catch (err) { ee.emit('error', err); }
});

@@ -46,6 +47,6 @@ });

var error = [];
var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str };
var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
// only output a stack if it isn't a less error
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red') }
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }

@@ -90,3 +91,3 @@ if (!ctx.hasOwnProperty('index') || !extract) {

options = options || {};
if (options.silent) { return }
if (options.silent) { return; }
sys.error(less.formatError(ctx, options));

@@ -110,3 +111,3 @@ }

less.Parser.importer = function (file, currentFileInfo, callback, env) {
less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
var pathname, dirname, data,

@@ -120,8 +121,3 @@ newFileInfo = {

function parseFile(e, data) {
if (e) { return callback(e); }
env = new less.tree.parseEnv(env);
env.processImports = false;
function handleDataAndCallCallback(data) {
var j = file.lastIndexOf('/');

@@ -144,8 +140,4 @@

env.contents[pathname] = data; // Updating top importing parser content cache.
env.currentFileInfo = newFileInfo;
new(less.Parser)(env).parse(data, function (e, root) {
callback(e, root, pathname);
});
};
callback(null, data, pathname, newFileInfo);
}

@@ -164,8 +156,3 @@ var isUrl = isUrlRe.test( file );

var urlStr = isUrl ? file : url.resolve(currentFileInfo.currentDirectory, file),
urlObj = url.parse(urlStr),
req = {
host: urlObj.hostname,
port: urlObj.port || 80,
path: urlObj.pathname + (urlObj.search||'')
};
urlObj = url.parse(urlStr);

@@ -185,3 +172,3 @@ request.get(urlStr, function (error, res, body) {

dirname = urlObj.protocol +'//'+ urlObj.host + urlObj.pathname.replace(/[^\/]*$/, '');
parseFile(null, body);
handleDataAndCallCallback(body);
});

@@ -214,11 +201,14 @@ } else {

data = fs.readFileSync(pathname, 'utf-8');
parseFile(null, data);
handleDataAndCallCallback(data);
} catch (e) {
parseFile(e);
callback(e);
}
} else {
fs.readFile(pathname, 'utf-8', parseFile);
fs.readFile(pathname, 'utf-8', function(e, data) {
if (e) { callback(e); }
handleDataAndCallCallback(data);
});
}
}
}
};

@@ -232,3 +222,5 @@ require('./env');

require('./join-selector-visitor.js');
require('./to-css-visitor.js');
require('./source-map-output.js');
for (var k in less) { exports[k] = less[k]; }

@@ -24,2 +24,6 @@ (function (tree) {

if (! rulesetNode.root) {
rulesetNode.selectors = rulesetNode.selectors.filter(function(selector) { return selector.getIsOutput(); });
if (rulesetNode.selectors.length === 0) {
rulesetNode.rules.length = 0;
}
rulesetNode.joinSelectors(paths, context, rulesetNode.selectors);

@@ -34,3 +38,3 @@ rulesetNode.paths = paths;

var context = this.contexts[this.contexts.length - 1];
mediaNode.ruleset.root = (context.length === 0 || context[0].multiMedia);
mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);
}

@@ -37,0 +41,0 @@ };

@@ -36,2 +36,3 @@ // lessc_helper.js

sys.puts(" --no-ie-compat Disable IE compatibility checks.");
sys.puts(" --no-js Disable JavaScript in less files");
sys.puts(" -l, --lint Syntax check only (lint).");

@@ -43,4 +44,3 @@ sys.puts(" -s, --silent Suppress output of error messages.");

sys.puts(" -x, --compress Compress output by removing some whitespaces.");
sys.puts(" --yui-compress Compress output using ycssmin");
sys.puts(" --max-line-len=LINELEN Max line length used by ycssmin");
sys.puts(" --clean-css Compress output using clean-css");
sys.puts(" -O0, -O1, -O2 Set the parser's optimization level. The lower");

@@ -56,2 +56,5 @@ sys.puts(" the number, the less nodes it will create in the");

sys.puts(" format, and 'all' which will do both.");
sys.puts(" --source-map[=FILENAME] Outputs a v3 sourcemap to the filename (or output filename.map)");
sys.puts(" --source-map-rootpath=X adds this path onto the sourcemap filename and less file paths");
sys.puts(" --source-map-inline puts the less files into the map instead of referencing them");
sys.puts(" -rp, --rootpath=URL Set rootpath for url rewriting in relative imports and urls.");

@@ -66,10 +69,8 @@ sys.puts(" Works with or without the relative-urls option.");

sys.puts("");
sys.puts("Report bugs to: http://github.com/cloudhead/less.js/issues");
sys.puts("Report bugs to: http://github.com/less/less.js/issues");
sys.puts("Home page: <http://lesscss.org/>");
}
};
}
// Exports helper functions
for (var h in lessc_helper) { exports[h] = lessc_helper[h] }
for (var h in lessc_helper) { exports[h] = lessc_helper[h]; }

@@ -1,21 +0,8 @@

var less, tree, charset;
var less, tree;
if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
// Rhino
// Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
if (typeof(window) === 'undefined') { less = {} }
else { less = window.less = {} }
tree = less.tree = {};
less.mode = 'rhino';
} else if (typeof(window) === 'undefined') {
// Node.js
less = exports,
// Node.js does not have a header file added which defines less
if (less === undefined) {
less = exports;
tree = require('./tree');
less.mode = 'node';
} else {
// Browser
if (typeof(window.less) === 'undefined') { window.less = {} }
less = window.less,
tree = window.less.tree = {};
less.mode = 'browser';
}

@@ -66,4 +53,2 @@ //

var that = this;
// Top parser on an import tree must be sure there is one "env"

@@ -82,20 +67,43 @@ // which will then be passed around by reference.

error: null, // Error in parsing/evaluating an import
push: function (path, currentFileInfo, callback) {
var parserImporter = this;
push: function (path, currentFileInfo, importOptions, callback) {
var parserImports = this;
this.queue.push(path);
//
// Import a file asynchronously
//
less.Parser.importer(path, currentFileInfo, function (e, root, fullPath) {
parserImporter.queue.splice(parserImporter.queue.indexOf(path), 1); // Remove the path from the queue
var fileParsedFunc = function (e, root, fullPath) {
parserImports.queue.splice(parserImports.queue.indexOf(path), 1); // Remove the path from the queue
var imported = fullPath in parserImporter.files;
var importedPreviously = fullPath in parserImports.files;
parserImporter.files[fullPath] = root; // Store the root
parserImports.files[fullPath] = root; // Store the root
if (e && !parserImporter.error) { parserImporter.error = e; }
callback(e, root, imported);
}, env);
if (e && !parserImports.error) { parserImports.error = e; }
callback(e, root, importedPreviously);
};
if (less.Parser.importer) {
less.Parser.importer(path, currentFileInfo, fileParsedFunc, env);
} else {
less.Parser.fileLoader(path, currentFileInfo, function(e, contents, fullPath, newFileInfo) {
if (e) {fileParsedFunc(e); return;}
var newEnv = new tree.parseEnv(env);
newEnv.currentFileInfo = newFileInfo;
newEnv.processImports = false;
newEnv.contents[fullPath] = contents;
if (currentFileInfo.reference || importOptions.reference) {
newFileInfo.reference = true;
}
if (importOptions.inline) {
fileParsedFunc(null, contents, fullPath);
} else {
new(less.Parser)(newEnv).parse(contents, function (e, root) {
fileParsedFunc(e, root, fullPath);
});
}
}, env);
}
}

@@ -122,3 +130,3 @@ };

function $(tok) {
var match, args, length, index, k;
var match, length;

@@ -172,3 +180,3 @@ //

while (i < endIndex) {
if (! isWhitespace(input.charAt(i))) { break }
if (! isWhitespace(input.charAt(i))) { break; }
i++;

@@ -179,3 +187,3 @@ }

if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
if (chunks[j].length === 0 && j < chunks.length - 1) { j++; }

@@ -208,7 +216,3 @@ return oldi !== i || oldj !== j;

} else {
if (tok.test(chunks[j])) {
return true;
} else {
return false;
}
return tok.test(chunks[j]);
}

@@ -225,9 +229,19 @@ }

function getLocation(index, input) {
for (var n = index, column = -1;
n >= 0 && input.charAt(n) !== '\n';
n--) { column++ }
function getLocation(index, inputStream) {
var n = index + 1,
line = null,
column = -1;
return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null,
column: column };
while (--n >= 0 && inputStream.charAt(n) !== '\n') {
column++;
}
if (typeof index === 'number') {
line = (inputStream.slice(0, index).match(/\n/g) || "").length;
}
return {
line: line,
column: column
};
}

@@ -252,2 +266,3 @@

col = loc.column,
callLine = e.call && getLocation(e.call, input).line,
lines = input.split('\n');

@@ -260,4 +275,4 @@

this.line = typeof(line) === 'number' ? line + 1 : null;
this.callLine = e.call && (getLocation(e.call, input).line + 1);
this.callExtract = lines[getLocation(e.call, input).line];
this.callLine = callLine + 1;
this.callExtract = lines[callLine];
this.stack = e.stack;

@@ -294,3 +309,3 @@ this.column = col;

parse: function (str, callback) {
var root, start, end, zone, line, lines, buff = [], c, error = null;
var root, line, lines, error = null;

@@ -303,2 +318,4 @@ i = j = current = furthest = 0;

parser.imports.contents[env.currentFileInfo.filename] = input;
// Split the input into chunks.

@@ -348,7 +365,33 @@ chunks = (function (chunks) {

switch (c) {
case '{': if (! inParam) { level ++; chunk.push(c); break }
case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break }
case '(': if (! inParam) { inParam = true; chunk.push(c); break }
case ')': if ( inParam) { inParam = false; chunk.push(c); break }
default: chunk.push(c);
case '{':
if (!inParam) {
level++;
chunk.push(c);
break;
}
/* falls through */
case '}':
if (!inParam) {
level--;
chunk.push(c);
chunks[++j] = chunk = [];
break;
}
/* falls through */
case '(':
if (!inParam) {
inParam = true;
chunk.push(c);
break;
}
/* falls through */
case ')':
if (inParam) {
inParam = false;
chunk.push(c);
break;
}
/* falls through */
default:
chunk.push(c);
}

@@ -358,3 +401,3 @@

}
if (level != 0) {
if (level !== 0) {
error = new(LessError)({

@@ -368,3 +411,3 @@ index: i-1,

return chunks.map(function (c) { return c.join('') });;
return chunks.map(function (c) { return c.join(''); });
})([[]]);

@@ -389,7 +432,6 @@

root.toCSS = (function (evaluate) {
var line, lines, column;
return function (options, variables) {
options = options || {};
var importError,
var evaldRoot,
css,
evalEnv = new tree.evalEnv(options);

@@ -420,3 +462,3 @@

}
return new(tree.Rule)('@' + k, value, false, 0);
return new(tree.Rule)('@' + k, value, false, null, 0);
});

@@ -427,3 +469,3 @@ evalEnv.frames = [new(tree.Ruleset)(null, variables)];

try {
var evaldRoot = evaluate.call(this, evalEnv);
evaldRoot = evaluate.call(this, evalEnv);

@@ -436,3 +478,20 @@ new(tree.joinSelectorVisitor)()

var css = evaldRoot.toCSS({
new(tree.toCSSVisitor)({compress: Boolean(options.compress)})
.run(evaldRoot);
if (options.sourceMap) {
evaldRoot = new tree.sourceMapOutput(
{
writeSourceMap: options.writeSourceMap,
rootNode: evaldRoot,
contentsMap: parser.imports.contents,
sourceMapFilename: options.sourceMapFilename,
outputFilename: options.sourceMapOutputFilename,
sourceMapBasepath: options.sourceMapBasepath,
sourceMapRootpath: options.sourceMapRootpath,
outputSourceFiles: options.outputSourceFiles
});
}
css = evaldRoot.toCSS({
compress: Boolean(options.compress),

@@ -445,6 +504,6 @@ dumpLineNumbers: env.dumpLineNumbers,

if (options.yuicompress && less.mode === 'node') {
return require('ycssmin').cssmin(css, options.maxLineLen);
if (options.cleancss && less.mode === 'node') {
return require('clean-css').process(css);
} else if (options.compress) {
return css.replace(/(\s)+/g, "$1");
return css.replace(/(^(\s)+)|((\s)+$)/g, "");
} else {

@@ -466,7 +525,6 @@ return css;

i = furthest;
var loc = getLocation(i, input);
lines = input.split('\n');
line = (input.slice(0, i).match(/\n/g) || "").length + 1;
line = loc.line + 1;
for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
error = {

@@ -478,3 +536,3 @@ type: "Parse",

line: line,
column: column,
column: loc.column,
extract: [

@@ -573,11 +631,21 @@ lines[line - 2],

if (input.charAt(i) !== '/') return;
if (input.charAt(i) !== '/') { return; }
if (input.charAt(i + 1) === '/') {
return new(tree.Comment)($(/^\/\/.*/), true);
return new(tree.Comment)($(/^\/\/.*/), true, i, env.currentFileInfo);
} else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
return new(tree.Comment)(comment);
return new(tree.Comment)(comment, false, i, env.currentFileInfo);
}
},
comments: function () {
var comment, comments = [];
while(comment = $(this.comment)) {
comments.push(comment);
}
return comments;
},
//

@@ -595,4 +663,4 @@ // Entities are tokens which can be found inside an Expression

if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
if (input.charAt(j) === '~') { j++, e = true; } // Escaped strings
if (input.charAt(j) !== '"' && input.charAt(j) !== "'") { return; }

@@ -637,3 +705,3 @@ e && $('~');

if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return;
if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) { return; }

@@ -643,4 +711,4 @@ name = name[1];

if (nameLC === 'url') { return null }
else { i += name.length }
if (nameLC === 'url') { return null; }
else { i += name.length; }

@@ -669,3 +737,5 @@ if (nameLC === 'alpha') {

args.push(arg);
if (! $(',')) { break }
if (! $(',')) {
break;
}
}

@@ -704,3 +774,6 @@ return args;

if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
if (input.charAt(i) !== 'u' || !$(/^url\(/)) {
return;
}
value = $(this.entities.quoted) || $(this.entities.variable) ||

@@ -711,2 +784,3 @@ $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";

/*jshint eqnull:true */
return new(tree.URL)((value.value != null || value instanceof tree.Variable)

@@ -734,3 +808,3 @@ ? value : new(tree.Anonymous)(value), env.currentFileInfo);

variableCurly: function () {
var name, curly, index = i;
var curly, index = i;

@@ -765,3 +839,5 @@ if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) {

//Is the first char of the dimension 0-9, '.', '+' or '-'
if ((c > 57 || c < 43) || c === 47 || c == 44) return;
if ((c > 57 || c < 43) || c === 47 || c == 44) {
return;
}

@@ -794,6 +870,9 @@ if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) {

if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
if (input.charAt(j) !== '`') { return }
if (input.charAt(j) === '~') { j++; e = true; } // Escaped strings
if (input.charAt(j) !== '`') { return; }
if (env.javascriptEnabled !== undefined && !env.javascriptEnabled) {
error("You are using JavaScript, which has been disabled.");
}
e && $('~');
if (e) { $('~'); }

@@ -814,3 +893,3 @@ if (str = $(/^`([^`]*)`/)) {

if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1]; }
},

@@ -841,3 +920,3 @@

} while($(","))
} while($(","));

@@ -876,5 +955,5 @@ expect(/^\)/);

call: function () {
var elements = [], e, c, args, delim, arg, index = i, s = input.charAt(i), important = false;
var elements = [], e, c, args, index = i, s = input.charAt(i), important = false;
if (s !== '.' && s !== '#') { return }
if (s !== '.' && s !== '#') { return; }

@@ -884,3 +963,3 @@ save(); // stop us absorbing part of an invalid selector

while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
elements.push(new(tree.Element)(c, e, i));
elements.push(new(tree.Element)(c, e, i, env.currentFileInfo));
c = $('>');

@@ -912,3 +991,3 @@ }

} else {
$(this.comment);
$(this.comments);
if (input.charAt(i) === '.' && $(/^\.{3}/)) {

@@ -941,3 +1020,3 @@ returner.variadic = true;

if (arg.value.length == 1) {
var val = arg.value[0];
val = arg.value[0];
}

@@ -991,3 +1070,3 @@ } else {

if (expressions.length > 1) {
value = new (tree.Value)(expressions);
value = new(tree.Value)(expressions);
}

@@ -1025,5 +1104,7 @@ argsSemiColon.push({ name:name, value:value });

definition: function () {
var name, params = [], match, ruleset, param, value, cond, variadic = false;
var name, params = [], match, ruleset, cond, variadic = false;
if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
peek(/^[^{]*\}/)) return;
peek(/^[^{]*\}/)) {
return;
}

@@ -1046,3 +1127,3 @@ save();

$(this.comment);
$(this.comments);

@@ -1091,3 +1172,3 @@ if ($(/^when/)) { // Guard

if (! $(/^\(opacity=/i)) return;
if (! $(/^\(opacity=/i)) { return; }
if (value = $(/^\d+/) || $(this.entities.variable)) {

@@ -1112,3 +1193,3 @@ expect(')');

element: function () {
var e, t, c, v;
var e, c, v;

@@ -1129,3 +1210,3 @@ c = $(this.combinator);

if (e) { return new(tree.Element)(c, e, i) }
if (e) { return new(tree.Element)(c, e, i, env.currentFileInfo); }
},

@@ -1147,3 +1228,3 @@

i++;
while (input.charAt(i).match(/\s/)) { i++ }
while (input.charAt(i).match(/\s/)) { i++; }
return new(tree.Combinator)(c);

@@ -1156,4 +1237,10 @@ } else if (input.charAt(i - 1).match(/\s/)) {

},
//
// A CSS selector (see selector below)
// with less extensions e.g. the ability to extend and guard
//
lessSelector: function () {
return this.selector(true);
},
//
// A CSS Selector

@@ -1166,7 +1253,11 @@ //

//
selector: function () {
var sel, e, elements = [], c, extend, extendList = [];
selector: function (isLess) {
var e, elements = [], c, extend, extendList = [], when, condition;
while ((extend = $(this.extend)) || (e = $(this.element))) {
if (extend) {
while ((isLess && (extend = $(this.extend))) || (isLess && (when = $(/^when/))) || (e = $(this.element))) {
if (when) {
condition = expect(this.conditions, 'expected condition');
} else if (condition) {
error("CSS guard can only be used at the end of selector");
} else if (extend) {
extendList.push.apply(extendList, extend);

@@ -1178,15 +1269,17 @@ } else {

c = input.charAt(i);
elements.push(e)
elements.push(e);
e = null;
}
if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break }
if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {
break;
}
}
if (elements.length > 0) { return new(tree.Selector)(elements, extendList); }
if (elements.length > 0) { return new(tree.Selector)(elements, extendList, condition, i, env.currentFileInfo); }
if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
},
attribute: function () {
var attr = '', key, val, op;
var key, val, op;
if (! $('[')) return;
if (! $('[')) { return; }

@@ -1225,10 +1318,14 @@ if (!(key = $(this.entities.variableCurly))) {

if (env.dumpLineNumbers)
if (env.dumpLineNumbers) {
debugInfo = getDebugInfo(i, input, env);
}
while (s = $(this.selector)) {
while (s = $(this.lessSelector)) {
selectors.push(s);
$(this.comment);
if (! $(',')) { break }
$(this.comment);
$(this.comments);
if (! $(',')) { break; }
if (s.condition) {
error("Guards are only currently allowed on a single selector");
}
$(this.comments);
}

@@ -1238,4 +1335,5 @@

var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports);
if (env.dumpLineNumbers)
if (env.dumpLineNumbers) {
ruleset.debugInfo = debugInfo;
}
return ruleset;

@@ -1249,8 +1347,8 @@ } else {

rule: function (tryAnonymous) {
var name, value, c = input.charAt(i), important;
var name, value, c = input.charAt(i), important, merge = false;
save();
if (c === '.' || c === '#' || c === '&') { return }
if (c === '.' || c === '#' || c === '&') { return; }
if (name = $(this.variable) || $(this.property)) {
if (name = $(this.variable) || $(this.ruleProperty)) {
// prefer to try to parse first if its a variable or we are compressing

@@ -1262,6 +1360,11 @@ // but always fallback on the other one

important = $(this.important);
if (name[name.length-1] === "+") {
merge = true;
name = name.substr(0, name.length - 1);
}
if (value && $(this.end)) {
return new(tree.Rule)(name, value, important, memo, env.currentFileInfo);
return new (tree.Rule)(name, value, important, merge, memo, env.currentFileInfo);
} else {

@@ -1334,3 +1437,3 @@ furthest = i;

options[optionName] = value;
if (! $(',')) { break }
if (! $(',')) { break; }
}

@@ -1343,3 +1446,3 @@ } while (o);

importOption: function() {
var opt = $(/^(less|css|multiple|once)/);
var opt = $(/^(less|css|multiple|once|inline|reference)/);
if (opt) {

@@ -1361,3 +1464,3 @@ return opt[1];

if (p && e) {
nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true)));
nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, null, i, env.currentFileInfo, true)));
} else if (e) {

@@ -1368,3 +1471,3 @@ nodes.push(new(tree.Paren)(e));

}
} else { return null }
} else { return null; }
}

@@ -1384,6 +1487,6 @@ } while (e);

features.push(e);
if (! $(',')) { break }
if (! $(',')) { break; }
} else if (e = $(this.entities.variable)) {
features.push(e);
if (! $(',')) { break }
if (! $(',')) { break; }
}

@@ -1398,4 +1501,5 @@ } while (e);

if (env.dumpLineNumbers)
if (env.dumpLineNumbers) {
debugInfo = getDebugInfo(i, input, env);
}

@@ -1406,5 +1510,6 @@ if ($(/^@media/)) {

if (rules = $(this.block)) {
media = new(tree.Media)(rules, features);
if(env.dumpLineNumbers)
media = new(tree.Media)(rules, features, i, env.currentFileInfo);
if (env.dumpLineNumbers) {
media.debugInfo = debugInfo;
}
return media;

@@ -1421,6 +1526,6 @@ }

directive: function () {
var name, value, rules, identifier, e, nodes, nonVendorSpecificName,
var name, value, rules, nonVendorSpecificName,
hasBlock, hasIdentifier, hasExpression;
if (input.charAt(i) !== '@') return;
if (input.charAt(i) !== '@') { return; }

@@ -1435,3 +1540,3 @@ if (value = $(this['import']) || $(this.media)) {

if (!name) return;
if (!name) { return; }

@@ -1485,7 +1590,7 @@ nonVendorSpecificName = name;

if (rules = $(this.block)) {
return new(tree.Directive)(name, rules);
return new(tree.Directive)(name, rules, i, env.currentFileInfo);
}
} else {
if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) {
var directive = new(tree.Directive)(name, value);
var directive = new(tree.Directive)(name, value, i, env.currentFileInfo);
if (env.dumpLineNumbers) {

@@ -1510,7 +1615,7 @@ directive.debugInfo = getDebugInfo(i, input, env);

value: function () {
var e, expressions = [], important;
var e, expressions = [];
while (e = $(this.expression)) {
expressions.push(e);
if (! $(',')) { break }
if (! $(',')) { break; }
}

@@ -1540,3 +1645,3 @@

multiplication: function () {
var m, a, op, operation, isSpaced, expression = [];
var m, a, op, operation, isSpaced;
if (m = $(this.operand)) {

@@ -1584,3 +1689,3 @@ isSpaced = isWhitespace(input.charAt(i - 1));

if ($(/^not/)) { negate = true }
if ($(/^not/)) { negate = true; }
expect('(');

@@ -1609,3 +1714,3 @@ if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {

if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') }
if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-'); }
var o = $(this.sub) || $(this.entities.dimension) ||

@@ -1631,3 +1736,3 @@ $(this.entities.color) || $(this.entities.variable) ||

expression: function () {
var e, delim, entities = [], d;
var e, delim, entities = [];

@@ -1651,2 +1756,9 @@ while (e = $(this.addition) || $(this.entity)) {

}
},
ruleProperty: function () {
var name;
if (name = $(/^(\*?-?[_a-zA-Z0-9-]+)\s*(\+?)\s*:/)) {
return name[1] + (name[2] || "");
}
}

@@ -1657,23 +1769,1 @@ }

if (less.mode === 'browser' || less.mode === 'rhino') {
//
// Used by `@import` directives
//
less.Parser.importer = function (path, currentFileInfo, callback, env) {
if (!/^([a-z-]+:)?\//.test(path) && currentFileInfo.currentDirectory) {
path = currentFileInfo.currentDirectory + path;
}
var sheetEnv = env.toSheet(path);
sheetEnv.processImports = false;
sheetEnv.currentFileInfo = currentFileInfo;
// We pass `true` as 3rd argument, to force the reload of the import.
// This is so we can get the syntax tree as opposed to just the CSS output,
// as we need this to evaluate the current stylesheet.
loadStyleSheet(sheetEnv,
function (e, root, data, sheet, _, path) {
callback.call(null, e, root, path);
}, true);
};
}

@@ -0,3 +1,34 @@

/*jshint rhino:true, unused: false */
/*global name:true, less, loadStyleSheet */
var name;
function error(e, filename) {
var content = "Error : " + filename + "\n";
filename = e.filename || filename;
if (e.message) {
content += e.message + "\n";
}
var errorline = function (e, i, classname) {
if (e.extract[i]) {
content +=
String(parseInt(e.line, 10) + (i - 1)) +
":" + e.extract[i] + "\n";
}
};
if (e.stack) {
content += e.stack;
} else if (e.extract) {
content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n';
errorline(e, 0);
errorline(e, 1);
errorline(e, 2);
}
print(content);
}
function loadStyleSheet(sheet, callback, reload, remaining) {

@@ -64,3 +95,3 @@ var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')),

}
path = name.split("/");path.pop();path=path.join("/")
path = name.split("/");path.pop();path=path.join("/");

@@ -98,31 +129,2 @@ var input = readFile(name);

print("done");
}(arguments));
function error(e, filename) {
var content = "Error : " + filename + "\n";
filename = e.filename || filename;
if (e.message) {
content += e.message + "\n";
}
var errorline = function (e, i, classname) {
if (e.extract[i]) {
content +=
String(parseInt(e.line) + (i - 1)) +
":" + e.extract[i] + "\n";
}
};
if (e.stack) {
content += e.stack;
} else if (e.extract) {
content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n';
errorline(e, 0);
errorline(e, 1);
errorline(e, 2);
}
print(content);
}
}(arguments));
(function (tree) {
tree.debugInfo = function(env, ctx) {
tree.debugInfo = function(env, ctx, lineSeperator) {
var result="";

@@ -14,3 +14,3 @@ if (env.dumpLineNumbers && !env.compress) {

case 'all':
result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx);
result = tree.debugInfo.asComment(ctx) + (lineSeperator || "") + tree.debugInfo.asMediaQuery(ctx);
break;

@@ -28,3 +28,8 @@ }

return '@media -sass-debug-info{filename{font-family:' +
('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function(a){if(a=='\\') a = '\/'; return '\\' + a}) +
('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function (a) {
if (a == '\\') {
a = '\/';
}
return '\\' + a;
}) +
'}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n';

@@ -35,9 +40,10 @@ };

for (var i = 0, r; i < obj.length; i++) {
if (r = fun.call(obj, obj[i])) { return r }
if (r = fun.call(obj, obj[i])) { return r; }
}
return null;
};
tree.jsify = function (obj) {
if (Array.isArray(obj.value) && (obj.value.length > 1)) {
return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
return '[' + obj.value.map(function (v) { return v.toCSS(false); }).join(', ') + ']';
} else {

@@ -48,2 +54,26 @@ return obj.toCSS(false);

tree.toCSS = function (env) {
var strs = [];
this.genCSS(env, {
add: function(chunk, node) {
strs.push(chunk);
}
});
return strs.join('');
};
tree.outputRuleset = function (env, output, rules) {
output.add((env.compress ? '{' : ' {\n'));
env.tabLevel = (env.tabLevel || 0) + 1;
var tabRuleStr = env.compress ? '' : Array(env.tabLevel + 1).join(" "),
tabSetStr = env.compress ? '' : Array(env.tabLevel).join(" ");
for(var i = 0; i < rules.length; i++) {
output.add(tabRuleStr);
rules[i].genCSS(env, output);
output.add(env.compress ? '' : '\n');
}
env.tabLevel--;
output.add(tabSetStr + "}");
};
})(require('./tree'));

@@ -12,11 +12,19 @@ (function (tree) {

eval: function (env) {
if (this.value.eval) { this.value = this.value.eval(env) }
if (this.value.eval) { return new tree.Alpha(this.value.eval(env)); }
return this;
},
toCSS: function () {
return "alpha(opacity=" +
(this.value.toCSS ? this.value.toCSS() : this.value) + ")";
}
genCSS: function (env, output) {
output.add("alpha(opacity=");
if (this.value.genCSS) {
this.value.genCSS(env, output);
} else {
output.add(this.value);
}
output.add(")");
},
toCSS: tree.toCSS
};
})(require('../tree'));

@@ -8,6 +8,3 @@ (function (tree) {

type: "Anonymous",
toCSS: function () {
return this.value;
},
eval: function () { return this },
eval: function () { return this; },
compare: function (x) {

@@ -26,5 +23,9 @@ if (!x.toCSS) {

return left < right ? -1 : 1;
}
},
genCSS: function (env, output) {
output.add(this.value);
},
toCSS: tree.toCSS
};
})(require('../tree'));

@@ -12,5 +12,2 @@ (function (tree) {

},
toCSS: function () {
return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value);
},
eval: function (env) {

@@ -21,5 +18,14 @@ if (this.value.eval) {

return this;
}
},
genCSS: function (env, output) {
output.add(this.key + '=');
if (this.value.genCSS) {
this.value.genCSS(env, output);
} else {
output.add(this.value);
}
},
toCSS: tree.toCSS
};
})(require('../tree'));
})(require('../tree'));

@@ -39,2 +39,3 @@ (function (tree) {

result = func[nameLC].apply(func, args);
/*jshint eqnull:true */
if (result != null) {

@@ -50,13 +51,22 @@ return result;

}
// 2.
return new(tree.Anonymous)(this.name +
"(" + args.map(function (a) { return a.toCSS(env); }).join(', ') + ")");
return new tree.Call(this.name, args, this.index, this.currentFileInfo);
},
toCSS: function (env) {
return this.eval(env).toCSS();
}
genCSS: function (env, output) {
output.add(this.name + "(", this.currentFileInfo, this.index);
for(var i = 0; i < this.args.length; i++) {
this.args[i].genCSS(env, output);
if (i + 1 < this.args.length) {
output.add(", ");
}
}
output.add(")");
},
toCSS: tree.toCSS
};
})(require('../tree'));

@@ -27,13 +27,15 @@ (function (tree) {

type: "Color",
eval: function () { return this },
eval: function () { return this; },
luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); },
//
// If we have some transparency, the only way to represent it
// is via `rgba`. Otherwise, we use the hex representation,
// which has better compatibility with older browsers.
// Values are capped between `0` and `255`, rounded and zero-padded.
//
genCSS: function (env, output) {
output.add(this.toCSS(env));
},
toCSS: function (env, doNotCompress) {
var compress = env && env.compress && !doNotCompress;
// If we have some transparency, the only way to represent it
// is via `rgba`. Otherwise, we use the hex representation,
// which has better compatibility with older browsers.
// Values are capped between `0` and `255`, rounded and zero-padded.
if (this.alpha < 1.0) {

@@ -44,20 +46,14 @@ return "rgba(" + this.rgb.map(function (c) {

} else {
var color = this.rgb.map(function (i) {
i = Math.round(i);
i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
return i.length === 1 ? '0' + i : i;
}).join('');
var color = this.toRGB();
if (compress) {
color = color.split('');
var splitcolor = color.split('');
// Convert color to short format
if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) {
color = color[0] + color[2] + color[4];
} else {
color = color.join('');
if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) {
color = '#' + splitcolor[1] + splitcolor[3] + splitcolor[5];
}
}
return '#' + color;
return color;
}

@@ -85,2 +81,10 @@ },

toRGB: function () {
return '#' + this.rgb.map(function (i) {
i = Math.round(i);
i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
return i.length === 1 ? '0' + i : i;
}).join('');
},
toHSL: function () {

@@ -87,0 +91,0 @@ var r = this.rgb[0] / 255,

(function (tree) {
tree.Comment = function (value, silent) {
tree.Comment = function (value, silent, index, currentFileInfo) {
this.value = value;
this.silent = !!silent;
this.currentFileInfo = currentFileInfo;
};
tree.Comment.prototype = {
type: "Comment",
toCSS: function (env) {
return env.compress ? '' : this.value;
genCSS: function (env, output) {
if (this.debugInfo) {
output.add(tree.debugInfo(env, this), this.currentFileInfo, this.index);
}
output.add(this.value.trim()); //TODO shouldn't need to trim, we shouldn't grab the \n
},
eval: function () { return this }
toCSS: tree.toCSS,
isSilent: function(env) {
var isReference = (this.currentFileInfo && this.currentFileInfo.reference && !this.isReferenced),
isCompressed = env.compress && !this.value.match(/^\/\*!/);
return this.silent || isReference || isCompressed;
},
eval: function () { return this; },
markReferenced: function () {
this.isReferenced = true;
}
};
})(require('../tree'));

@@ -22,3 +22,3 @@ (function (tree) {

var result = (function (op) {
result = (function (op) {
switch (op) {

@@ -25,0 +25,0 @@ case 'and':

@@ -23,3 +23,3 @@ (function (tree) {

},
toCSS: function (env) {
genCSS: function (env, output) {
if ((env && env.strictUnits) && !this.unit.isSingular()) {

@@ -39,4 +39,5 @@ throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());

// Zero values doesn't need a unit
if (value === 0 && !this.unit.isAngle()) {
return strValue;
if (value === 0 && this.unit.isLength()) {
output.add(strValue);
return;
}

@@ -50,4 +51,6 @@

return strValue + this.unit.toCSS(env);
output.add(strValue);
this.unit.genCSS(env, output);
},
toCSS: tree.toCSS,

@@ -58,2 +61,3 @@ // In an operation between two Dimensions,

operate: function (env, op, other) {
/*jshint noempty:false */
var value = tree.operate(env, op, this.value, other.value),

@@ -66,3 +70,3 @@ unit = this.unit.clone();

unit.denominator = other.unit.denominator.slice(0);
} else if (other.unit.numerator.length == 0 && unit.denominator.length == 0) {
} else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) {
// do nothing

@@ -112,43 +116,45 @@ } else {

unify: function () {
return this.convertTo({ length: 'm', duration: 's', angle: 'rad' });
return this.convertTo({ length: 'm', duration: 's', angle: 'rad' });
},
convertTo: function (conversions) {
var value = this.value, unit = this.unit.clone(),
i, groupName, group, conversion, targetUnit, derivedConversions = {};
var value = this.value, unit = this.unit.clone(),
i, groupName, group, targetUnit, derivedConversions = {}, applyUnit;
if (typeof conversions === 'string') {
for(i in tree.UnitConversions) {
if (tree.UnitConversions[i].hasOwnProperty(conversions)) {
derivedConversions = {};
derivedConversions[i] = conversions;
}
}
conversions = derivedConversions;
}
for (groupName in conversions) {
if (conversions.hasOwnProperty(groupName)) {
targetUnit = conversions[groupName];
group = tree.UnitConversions[groupName];
unit.map(function (atomicUnit, denominator) {
if (typeof conversions === 'string') {
for(i in tree.UnitConversions) {
if (tree.UnitConversions[i].hasOwnProperty(conversions)) {
derivedConversions = {};
derivedConversions[i] = conversions;
}
}
conversions = derivedConversions;
}
applyUnit = function (atomicUnit, denominator) {
/*jshint loopfunc:true */
if (group.hasOwnProperty(atomicUnit)) {
if (denominator) {
value = value / (group[atomicUnit] / group[targetUnit]);
} else {
value = value * (group[atomicUnit] / group[targetUnit]);
}
if (denominator) {
value = value / (group[atomicUnit] / group[targetUnit]);
} else {
value = value * (group[atomicUnit] / group[targetUnit]);
}
return targetUnit;
return targetUnit;
}
return atomicUnit;
});
};
for (groupName in conversions) {
if (conversions.hasOwnProperty(groupName)) {
targetUnit = conversions[groupName];
group = tree.UnitConversions[groupName];
unit.map(applyUnit);
}
}
}
unit.cancel();
unit.cancel();
return new(tree.Dimension)(value, unit);
return new(tree.Dimension)(value, unit);
}

@@ -159,48 +165,47 @@ };

tree.UnitConversions = {
length: {
'm': 1,
'cm': 0.01,
'mm': 0.001,
'in': 0.0254,
'pt': 0.0254 / 72,
'pc': 0.0254 / 72 * 12
},
duration: {
's': 1,
'ms': 0.001
},
angle: {
'rad': 1/(2*Math.PI),
'deg': 1/360,
'grad': 1/400,
'turn': 1
}
length: {
'm': 1,
'cm': 0.01,
'mm': 0.001,
'in': 0.0254,
'pt': 0.0254 / 72,
'pc': 0.0254 / 72 * 12
},
duration: {
's': 1,
'ms': 0.001
},
angle: {
'rad': 1/(2*Math.PI),
'deg': 1/360,
'grad': 1/400,
'turn': 1
}
};
tree.Unit = function (numerator, denominator, backupUnit) {
this.numerator = numerator ? numerator.slice(0).sort() : [];
this.denominator = denominator ? denominator.slice(0).sort() : [];
this.backupUnit = backupUnit;
this.numerator = numerator ? numerator.slice(0).sort() : [];
this.denominator = denominator ? denominator.slice(0).sort() : [];
this.backupUnit = backupUnit;
};
tree.Unit.prototype = {
type: "Unit",
clone: function () {
return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit);
},
type: "Unit",
clone: function () {
return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit);
},
genCSS: function (env, output) {
if (this.numerator.length >= 1) {
output.add(this.numerator[0]);
} else
if (this.denominator.length >= 1) {
output.add(this.denominator[0]);
} else
if ((!env || !env.strictUnits) && this.backupUnit) {
output.add(this.backupUnit);
}
},
toCSS: tree.toCSS,
toCSS: function (env) {
if (this.numerator.length >= 1) {
return this.numerator[0];
}
if (this.denominator.length >= 1) {
return this.denominator[0];
}
if ((!env || !env.strictUnits) && this.backupUnit) {
return this.backupUnit;
}
return "";
},
toString: function () {
toString: function () {
var i, returnStr = this.numerator.join("*");

@@ -211,103 +216,106 @@ for (i = 0; i < this.denominator.length; i++) {

return returnStr;
},
compare: function (other) {
return this.is(other.toString()) ? 0 : -1;
},
},
is: function (unitString) {
return this.toString() === unitString;
},
compare: function (other) {
return this.is(other.toString()) ? 0 : -1;
},
isAngle: function () {
return tree.UnitConversions.angle.hasOwnProperty(this.toCSS());
},
is: function (unitString) {
return this.toString() === unitString;
},
isEmpty: function () {
return this.numerator.length == 0 && this.denominator.length == 0;
},
isLength: function () {
return Boolean(this.toCSS().match(/px|em|%|in|cm|mm|pc|pt|ex/));
},
isSingular: function() {
return this.numerator.length <= 1 && this.denominator.length == 0;
},
isEmpty: function () {
return this.numerator.length === 0 && this.denominator.length === 0;
},
map: function(callback) {
var i;
isSingular: function() {
return this.numerator.length <= 1 && this.denominator.length === 0;
},
for (i = 0; i < this.numerator.length; i++) {
this.numerator[i] = callback(this.numerator[i], false);
}
map: function(callback) {
var i;
for (i = 0; i < this.denominator.length; i++) {
this.denominator[i] = callback(this.denominator[i], true);
}
},
for (i = 0; i < this.numerator.length; i++) {
this.numerator[i] = callback(this.numerator[i], false);
}
usedUnits: function() {
var group, groupName, result = {};
for (i = 0; i < this.denominator.length; i++) {
this.denominator[i] = callback(this.denominator[i], true);
}
},
for (groupName in tree.UnitConversions) {
if (tree.UnitConversions.hasOwnProperty(groupName)) {
group = tree.UnitConversions[groupName];
usedUnits: function() {
var group, result = {}, mapUnit;
this.map(function (atomicUnit) {
if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
result[groupName] = atomicUnit;
}
mapUnit = function (atomicUnit) {
/*jshint loopfunc:true */
if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
result[groupName] = atomicUnit;
}
return atomicUnit;
});
}
}
return atomicUnit;
};
return result;
},
for (var groupName in tree.UnitConversions) {
if (tree.UnitConversions.hasOwnProperty(groupName)) {
group = tree.UnitConversions[groupName];
cancel: function () {
var counter = {}, atomicUnit, i, backup;
this.map(mapUnit);
}
}
for (i = 0; i < this.numerator.length; i++) {
atomicUnit = this.numerator[i];
if (!backup) {
backup = atomicUnit;
return result;
},
cancel: function () {
var counter = {}, atomicUnit, i, backup;
for (i = 0; i < this.numerator.length; i++) {
atomicUnit = this.numerator[i];
if (!backup) {
backup = atomicUnit;
}
counter[atomicUnit] = (counter[atomicUnit] || 0) + 1;
}
counter[atomicUnit] = (counter[atomicUnit] || 0) + 1;
}
for (i = 0; i < this.denominator.length; i++) {
atomicUnit = this.denominator[i];
if (!backup) {
backup = atomicUnit;
for (i = 0; i < this.denominator.length; i++) {
atomicUnit = this.denominator[i];
if (!backup) {
backup = atomicUnit;
}
counter[atomicUnit] = (counter[atomicUnit] || 0) - 1;
}
counter[atomicUnit] = (counter[atomicUnit] || 0) - 1;
}
this.numerator = [];
this.denominator = [];
this.numerator = [];
this.denominator = [];
for (atomicUnit in counter) {
if (counter.hasOwnProperty(atomicUnit)) {
var count = counter[atomicUnit];
for (atomicUnit in counter) {
if (counter.hasOwnProperty(atomicUnit)) {
var count = counter[atomicUnit];
if (count > 0) {
for (i = 0; i < count; i++) {
this.numerator.push(atomicUnit);
}
} else if (count < 0) {
for (i = 0; i < -count; i++) {
this.denominator.push(atomicUnit);
}
if (count > 0) {
for (i = 0; i < count; i++) {
this.numerator.push(atomicUnit);
}
} else if (count < 0) {
for (i = 0; i < -count; i++) {
this.denominator.push(atomicUnit);
}
}
}
}
}
}
if (this.numerator.length === 0 && this.denominator.length === 0 && backup) {
this.backupUnit = backup;
if (this.numerator.length === 0 && this.denominator.length === 0 && backup) {
this.backupUnit = backup;
}
this.numerator.sort();
this.denominator.sort();
}
this.numerator.sort();
this.denominator.sort();
}
};
})(require('../tree'));
(function (tree) {
tree.Directive = function (name, value) {
tree.Directive = function (name, value, index, currentFileInfo) {
this.name = name;
if (Array.isArray(value)) {
this.ruleset = new(tree.Ruleset)([], value);
this.ruleset.allowImports = true;
this.rules = [new(tree.Ruleset)([], value)];
this.rules[0].allowImports = true;
} else {
this.value = value;
}
this.currentFileInfo = currentFileInfo;
};

@@ -16,21 +18,23 @@ tree.Directive.prototype = {

accept: function (visitor) {
this.ruleset = visitor.visit(this.ruleset);
this.rules = visitor.visit(this.rules);
this.value = visitor.visit(this.value);
},
toCSS: function (env) {
if (this.ruleset) {
this.ruleset.root = true;
return this.name + (env.compress ? '{' : ' {\n ') +
this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') +
(env.compress ? '}': '\n}\n');
genCSS: function (env, output) {
output.add(this.name, this.currentFileInfo, this.index);
if (this.rules) {
tree.outputRuleset(env, output, this.rules);
} else {
return this.name + ' ' + this.value.toCSS() + ';\n';
output.add(' ');
this.value.genCSS(env, output);
output.add(';');
}
},
toCSS: tree.toCSS,
eval: function (env) {
var evaldDirective = this;
if (this.ruleset) {
if (this.rules) {
env.frames.unshift(this);
evaldDirective = new(tree.Directive)(this.name);
evaldDirective.ruleset = this.ruleset.eval(env);
evaldDirective = new(tree.Directive)(this.name, null, this.index, this.currentFileInfo);
evaldDirective.rules = [this.rules[0].eval(env)];
evaldDirective.rules[0].root = true;
env.frames.shift();

@@ -40,7 +44,19 @@ }

},
variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
variable: function (name) { return tree.Ruleset.prototype.variable.call(this.rules[0], name); },
find: function () { return tree.Ruleset.prototype.find.apply(this.rules[0], arguments); },
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.rules[0]); },
markReferenced: function () {
var i, rules;
this.isReferenced = true;
if (this.rules) {
rules = this.rules[0].rules;
for (i = 0; i < rules.length; i++) {
if (rules[i].markReferenced) {
rules[i].markReferenced();
}
}
}
}
};
})(require('../tree'));
(function (tree) {
tree.Element = function (combinator, value, index) {
tree.Element = function (combinator, value, index, currentFileInfo) {
this.combinator = combinator instanceof tree.Combinator ?

@@ -15,2 +15,3 @@ combinator : new(tree.Combinator)(combinator);

this.index = index;
this.currentFileInfo = currentFileInfo;
};

@@ -26,7 +27,11 @@ tree.Element.prototype = {

this.value.eval ? this.value.eval(env) : this.value,
this.index);
this.index,
this.currentFileInfo);
},
genCSS: function (env, output) {
output.add(this.toCSS(env), this.currentFileInfo, this.index);
},
toCSS: function (env) {
var value = (this.value.toCSS ? this.value.toCSS(env) : this.value);
if (value == '' && this.combinator.value.charAt(0) == '&') {
if (value === '' && this.combinator.value.charAt(0) === '&') {
return '';

@@ -53,2 +58,5 @@ } else {

},
genCSS: function (env, output) {
output.add(this.toCSS(env));
},
toCSS: function (env) {

@@ -75,15 +83,26 @@ var value = this.key.toCSS ? this.key.toCSS(env) : this.key;

type: "Combinator",
toCSS: function (env) {
return {
'' : '',
' ' : ' ',
':' : ' :',
'+' : env.compress ? '+' : ' + ',
'~' : env.compress ? '~' : ' ~ ',
'>' : env.compress ? '>' : ' > ',
'|' : env.compress ? '|' : ' | '
}[this.value];
}
_outputMap: {
'' : '',
' ' : ' ',
':' : ' :',
'+' : ' + ',
'~' : ' ~ ',
'>' : ' > ',
'|' : '|'
},
_outputMapCompressed: {
'' : '',
' ' : ' ',
':' : ' :',
'+' : '+',
'~' : '~',
'>' : '>',
'|' : '|'
},
genCSS: function (env, output) {
output.add((env.compress ? this._outputMapCompressed : this._outputMap)[this.value]);
},
toCSS: tree.toCSS
};
})(require('../tree'));

@@ -36,7 +36,11 @@ (function (tree) {

},
toCSS: function (env) {
return this.value.map(function (e) {
return e.toCSS ? e.toCSS(env) : '';
}).join(' ');
genCSS: function (env, output) {
for(var i = 0; i < this.value.length; i++) {
this.value[i].genCSS(env, output);
if (i + 1 < this.value.length) {
output.add(" ");
}
}
},
toCSS: tree.toCSS,
throwAwayComments: function () {

@@ -43,0 +47,0 @@ this.value = this.value.filter(function(v) {

@@ -15,4 +15,2 @@ (function (tree) {

tree.Import = function (path, features, options, index, currentFileInfo) {
var that = this;
this.options = options;

@@ -24,4 +22,4 @@ this.index = index;

if (this.options.less !== undefined) {
this.css = !this.options.less;
if (this.options.less !== undefined || this.options.inline) {
this.css = !this.options.less || this.options.inline;
} else {

@@ -49,13 +47,18 @@ var pathValue = this.getPath();

this.path = visitor.visit(this.path);
this.root = visitor.visit(this.root);
if (!this.options.inline) {
this.root = visitor.visit(this.root);
}
},
toCSS: function (env) {
var features = this.features ? ' ' + this.features.toCSS(env) : '';
genCSS: function (env, output) {
if (this.css) {
return "@import " + this.path.toCSS() + features + ';\n';
} else {
return "";
output.add("@import ", this.currentFileInfo, this.index);
this.path.genCSS(env, output);
if (this.features) {
output.add(" ");
this.features.genCSS(env, output);
}
output.add(';');
}
},
toCSS: tree.toCSS,
getPath: function () {

@@ -76,9 +79,14 @@ if (this.path instanceof tree.Quoted) {

var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
if (rootpath && !(path instanceof tree.URL)) {
var pathValue = path.value;
// Add the base path if the import is relative
if (pathValue && env.isPathRelative(pathValue)) {
path.value = rootpath + pathValue;
if (!(path instanceof tree.URL)) {
if (rootpath) {
var pathValue = path.value;
// Add the base path if the import is relative
if (pathValue && env.isPathRelative(pathValue)) {
path.value = rootpath + pathValue;
}
}
path.value = env.normalizePath(path.value);
}
return path;

@@ -91,3 +99,6 @@ },

if (this.css) {
if (this.options.inline) {
var contents = new(tree.Anonymous)(this.root);
return this.features ? new(tree.Media)([contents], this.features.value) : [contents];
} else if (this.css) {
var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index);

@@ -94,0 +105,0 @@ if (!newImport.css && this.error) {

@@ -22,3 +22,3 @@ (function (tree) {

} catch (e) {
throw { message: "JavaScript evaluation error: `" + expression + "`" ,
throw { message: "JavaScript evaluation error: " + e.message + " from `" + expression + "`" ,
index: this.index };

@@ -28,2 +28,3 @@ }

for (var k in env.frames[0].variables()) {
/*jshint loopfunc:true */
context[k.slice(1)] = {

@@ -30,0 +31,0 @@ value: env.frames[0].variables()[k].value,

(function (tree) {
tree.Keyword = function (value) { this.value = value };
tree.Keyword = function (value) { this.value = value; };
tree.Keyword.prototype = {
type: "Keyword",
eval: function () { return this; },
toCSS: function () { return this.value; },
genCSS: function (env, output) {
output.add(this.value);
},
toCSS: tree.toCSS,
compare: function (other) {

@@ -9,0 +12,0 @@ if (other instanceof tree.Keyword) {

(function (tree) {
tree.Media = function (value, features) {
tree.Media = function (value, features, index, currentFileInfo) {
this.index = index;
this.currentFileInfo = currentFileInfo;
var selectors = this.emptySelectors();
this.features = new(tree.Value)(features);
this.ruleset = new(tree.Ruleset)(selectors, value);
this.ruleset.allowImports = true;
this.rules = [new(tree.Ruleset)(selectors, value)];
this.rules[0].allowImports = true;
};

@@ -14,11 +17,10 @@ tree.Media.prototype = {

this.features = visitor.visit(this.features);
this.ruleset = visitor.visit(this.ruleset);
this.rules = visitor.visit(this.rules);
},
toCSS: function (env) {
var features = this.features.toCSS(env);
return '@media ' + features + (env.compress ? '{' : ' {\n ') +
this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') +
(env.compress ? '}': '\n}\n');
genCSS: function (env, output) {
output.add('@media ', this.currentFileInfo, this.index);
this.features.genCSS(env, output);
tree.outputRuleset(env, output, this.rules);
},
toCSS: tree.toCSS,
eval: function (env) {

@@ -30,5 +32,5 @@ if (!env.mediaBlocks) {

var media = new(tree.Media)([], []);
var media = new(tree.Media)([], [], this.index, this.currentFileInfo);
if(this.debugInfo) {
this.ruleset.debugInfo = this.debugInfo;
this.rules[0].debugInfo = this.debugInfo;
media.debugInfo = this.debugInfo;

@@ -53,4 +55,4 @@ }

env.frames.unshift(this.ruleset);
media.ruleset = this.ruleset.eval(env);
env.frames.unshift(this.rules[0]);
media.rules = [this.rules[0].eval(env)];
env.frames.shift();

@@ -61,11 +63,20 @@

return env.mediaPath.length === 0 ? media.evalTop(env) :
media.evalNested(env)
media.evalNested(env);
},
variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) },
variable: function (name) { return tree.Ruleset.prototype.variable.call(this.rules[0], name); },
find: function () { return tree.Ruleset.prototype.find.apply(this.rules[0], arguments); },
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.rules[0]); },
emptySelectors: function() {
var el = new(tree.Element)('', '&', 0);
return [new(tree.Selector)([el])];
var el = new(tree.Element)('', '&', this.index, this.currentFileInfo);
return [new(tree.Selector)([el], null, null, this.index, this.currentFileInfo)];
},
markReferenced: function () {
var i, rules = this.rules[0].rules;
this.isReferenced = true;
for (i = 0; i < rules.length; i++) {
if (rules[i].markReferenced) {
rules[i].markReferenced();
}
}
},

@@ -137,3 +148,3 @@ evalTop: function (env) {

bubbleSelectors: function (selectors) {
this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]);
this.rules = [new(tree.Ruleset)(selectors.slice(0), [this.rules[0]])];
}

@@ -140,0 +151,0 @@ };

@@ -18,3 +18,3 @@ (function (tree) {

eval: function (env) {
var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound;
var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule;

@@ -43,2 +43,5 @@ args = this.arguments && this.arguments.map(function (a) {

try {
if (!(mixin instanceof tree.mixin.Definition)) {
mixin = new tree.mixin.Definition("", [], mixin.rules, null, false);
}
Array.prototype.push.apply(

@@ -54,2 +57,10 @@ rules, mixin.eval(env, args, this.important).rules);

if (match) {
if (!this.currentFileInfo || !this.currentFileInfo.reference) {
for (i = 0; i < rules.length; i++) {
rule = rules[i];
if (rule.markReferenced) {
rule.markReferenced();
}
}
}
return rules;

@@ -86,3 +97,3 @@ }

this.name = name;
this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
this.selectors = [new(tree.Selector)([new(tree.Element)(null, name, this.index, this.currentFileInfo)])];
this.params = params;

@@ -95,4 +106,4 @@ this.condition = condition;

this.required = params.reduce(function (count, p) {
if (!p.name || (p.name && !p.value)) { return count + 1 }
else { return count }
if (!p.name || (p.name && !p.value)) { return count + 1; }
else { return count; }
}, 0);

@@ -109,3 +120,2 @@ this.parent = tree.Ruleset.prototype;

},
toCSS: function () { return ""; },
variable: function (name) { return this.parent.variable.call(this, name); },

@@ -117,2 +127,3 @@ variables: function () { return this.parent.variables.call(this); },

evalParams: function (env, mixinEnv, args, evaldArguments) {
/*jshint boss:true */
var frame = new(tree.Ruleset)(null, []),

@@ -153,3 +164,3 @@ varargs, arg,

for (i = 0; i < params.length; i++) {
if (evaldArguments[i]) continue;
if (evaldArguments[i]) { continue; }

@@ -196,3 +207,3 @@ arg = args && args[argIndex];

frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments),
context, rules, start, ruleset;
rules, ruleset;

@@ -220,8 +231,8 @@ frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));

matchArgs: function (args, env) {
var argsLength = (args && args.length) || 0, len, frame;
var argsLength = (args && args.length) || 0, len;
if (! this.variadic) {
if (argsLength < this.required) { return false }
if (argsLength > this.params.length) { return false }
if ((this.required > 0) && (argsLength > this.params.length)) { return false }
if (argsLength < this.required) { return false; }
if (argsLength > this.params.length) { return false; }
if ((this.required > 0) && (argsLength > this.params.length)) { return false; }
}

@@ -228,0 +239,0 @@

@@ -11,5 +11,7 @@ (function (tree) {

},
toCSS: function (env) {
return '-' + this.value.toCSS(env);
genCSS: function (env, output) {
output.add('-');
this.value.genCSS(env, output);
},
toCSS: tree.toCSS,
eval: function (env) {

@@ -16,0 +18,0 @@ if (env.isMathOn()) {

@@ -37,6 +37,14 @@ (function (tree) {

},
toCSS: function (env) {
var separator = this.isSpaced ? " " : "";
return this.operands[0].toCSS() + separator + this.op + separator + this.operands[1].toCSS();
}
genCSS: function (env, output) {
this.operands[0].genCSS(env, output);
if (this.isSpaced) {
output.add(" ");
}
output.add(this.op);
if (this.isSpaced) {
output.add(" ");
}
this.operands[1].genCSS(env, output);
},
toCSS: tree.toCSS
};

@@ -43,0 +51,0 @@

@@ -12,5 +12,8 @@

},
toCSS: function (env) {
return '(' + this.value.toCSS(env).trim() + ')';
genCSS: function (env, output) {
output.add('(');
this.value.genCSS(env, output);
output.add(')');
},
toCSS: tree.toCSS,
eval: function (env) {

@@ -17,0 +20,0 @@ return new(tree.Paren)(this.value.eval(env));

@@ -12,9 +12,12 @@ (function (tree) {

type: "Quoted",
toCSS: function () {
if (this.escaped) {
return this.value;
} else {
return this.quote + this.value + this.quote;
genCSS: function (env, output) {
if (!this.escaped) {
output.add(this.quote, this.currentFileInfo, this.index);
}
output.add(this.value);
if (!this.escaped) {
output.add(this.quote);
}
},
toCSS: tree.toCSS,
eval: function (env) {

@@ -21,0 +24,0 @@ var that = this;

(function (tree) {
tree.Rule = function (name, value, important, index, currentFileInfo, inline) {
tree.Rule = function (name, value, important, merge, index, currentFileInfo, inline) {
this.name = name;
this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
this.important = important ? ' ' + important.trim() : '';
this.merge = merge;
this.index = index;
this.currentFileInfo = currentFileInfo;
this.inline = inline || false;
if (name.charAt(0) === '@') {
this.variable = true;
} else { this.variable = false }
this.variable = (name.charAt(0) === '@');
};

@@ -21,17 +19,15 @@

},
toCSS: function (env) {
if (this.variable) { return "" }
else {
try {
return this.name + (env.compress ? ':' : ': ') +
this.value.toCSS(env) +
this.important + (this.inline ? "" : ";");
}
catch(e) {
e.index = this.index;
e.filename = this.currentFileInfo.filename;
throw e;
}
genCSS: function (env, output) {
output.add(this.name + (env.compress ? ':' : ': '), this.currentFileInfo, this.index);
try {
this.value.genCSS(env, output);
}
catch(e) {
e.index = this.index;
e.filename = this.currentFileInfo.filename;
throw e;
}
output.add(this.important + ((this.inline || (env.lastRule && env.compress)) ? "" : ";"), this.currentFileInfo, this.index);
},
toCSS: tree.toCSS,
eval: function (env) {

@@ -47,2 +43,3 @@ var strictMathBypass = false;

this.important,
this.merge,
this.index, this.currentFileInfo, this.inline);

@@ -60,2 +57,3 @@ }

"!important",
this.merge,
this.index, this.currentFileInfo, this.inline);

@@ -62,0 +60,0 @@ }

@@ -12,9 +12,17 @@ (function (tree) {

accept: function (visitor) {
this.selectors = visitor.visit(this.selectors);
if (this.paths) {
for(var i = 0; i < this.paths.length; i++) {
this.paths[i] = visitor.visit(this.paths[i]);
}
} else {
this.selectors = visitor.visit(this.selectors);
}
this.rules = visitor.visit(this.rules);
},
eval: function (env) {
var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env); });
var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
var rules;
var rule;
var i;

@@ -46,3 +54,3 @@ ruleset.originalRuleset = this;

// so they can be evaluated like closures when the time comes.
for (var i = 0; i < ruleset.rules.length; i++) {
for (i = 0; i < ruleset.rules.length; i++) {
if (ruleset.rules[i] instanceof tree.mixin.Definition) {

@@ -56,4 +64,5 @@ ruleset.rules[i].frames = env.frames.slice(0);

// Evaluate mixin calls.
for (var i = 0; i < ruleset.rules.length; i++) {
for (i = 0; i < ruleset.rules.length; i++) {
if (ruleset.rules[i] instanceof tree.mixin.Call) {
/*jshint loopfunc:true */
rules = ruleset.rules[i].eval(env).filter(function(r) {

@@ -75,3 +84,3 @@ if ((r instanceof tree.Rule) && r.variable) {

// Evaluate everything else
for (var i = 0, rule; i < ruleset.rules.length; i++) {
for (i = 0; i < ruleset.rules.length; i++) {
rule = ruleset.rules[i];

@@ -89,3 +98,3 @@

if (env.mediaBlocks) {
for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
for (i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
env.mediaBlocks[i].bubbleSelectors(selectors);

@@ -124,2 +133,12 @@ }

},
matchCondition: function (args, env) {
var lastSelector = this.selectors[this.selectors.length-1];
if (lastSelector.condition &&
!lastSelector.condition.eval(
new(tree.evalEnv)(env,
env.frames))) {
return false;
}
return true;
},
resetCache: function () {

@@ -131,3 +150,3 @@ this._rulesets = null;

variables: function () {
if (this._variables) { return this._variables }
if (this._variables) { return this._variables; }
else {

@@ -152,6 +171,6 @@ return this._variables = this.rules.reduce(function (hash, r) {

self = self || this;
var rules = [], rule, match,
var rules = [], match,
key = selector.toCSS();
if (key in this._lookups) { return this._lookups[key] }
if (key in this._lookups) { return this._lookups[key]; }

@@ -175,104 +194,102 @@ this.rulesets().forEach(function (rule) {

},
//
// Entry point for code generation
//
// `context` holds an array of arrays.
//
toCSS: function (env) {
var css = [], // The CSS output
rules = [], // node.Rule instances
_rules = [], //
rulesets = [], // node.Ruleset instances
selector, // The fully rendered selector
genCSS: function (env, output) {
var i, j,
ruleNodes = [],
rulesetNodes = [],
debugInfo, // Line number debugging
rule;
rule,
firstRuleset = true,
path;
// Compile rules and rulesets
for (var i = 0; i < this.rules.length; i++) {
env.tabLevel = (env.tabLevel || 0);
if (!this.root) {
env.tabLevel++;
}
var tabRuleStr = env.compress ? '' : Array(env.tabLevel + 1).join(" "),
tabSetStr = env.compress ? '' : Array(env.tabLevel).join(" ");
for (i = 0; i < this.rules.length; i++) {
rule = this.rules[i];
if (rule.rules || (rule instanceof tree.Media) || rule instanceof tree.Directive || (this.root && rule instanceof tree.Comment)) {
rulesetNodes.push(rule);
} else {
ruleNodes.push(rule);
}
}
if (rule.rules || (rule instanceof tree.Media)) {
rulesets.push(rule.toCSS(env));
} else if (rule instanceof tree.Directive) {
var cssValue = rule.toCSS(env);
// Output only the first @charset definition as such - convert the others
// to comments in case debug is enabled
if (rule.name === "@charset") {
// Only output the debug info together with subsequent @charset definitions
// a comment (or @media statement) before the actual @charset directive would
// be considered illegal css as it has to be on the first line
if (env.charset) {
if (rule.debugInfo) {
rulesets.push(tree.debugInfo(env, rule));
rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env));
}
continue;
}
env.charset = true;
// If this is the root node, we don't render
// a selector, or {}.
if (!this.root) {
debugInfo = tree.debugInfo(env, this, tabSetStr);
if (debugInfo) {
output.add(debugInfo);
output.add(tabSetStr);
}
for(i = 0; i < this.paths.length; i++) {
path = this.paths[i];
env.firstSelector = true;
for(j = 0; j < path.length; j++) {
output.add(path[j].genCSS(env, output));
env.firstSelector = false;
}
rulesets.push(cssValue);
} else if (rule instanceof tree.Comment) {
if (!rule.silent) {
if (this.root) {
rulesets.push(rule.toCSS(env));
} else {
rules.push(rule.toCSS(env));
}
if (i + 1 < this.paths.length) {
output.add(env.compress ? ',' : (',\n' + tabSetStr));
}
} else {
if (rule.toCSS && !rule.variable) {
if (this.firstRoot && rule instanceof tree.Rule) {
throw { message: "properties must be inside selector blocks, they cannot be in the root.",
index: rule.index, filename: rule.currentFileInfo ? rule.currentFileInfo.filename : null};
}
rules.push(rule.toCSS(env));
} else if (rule.value && !rule.variable) {
rules.push(rule.value.toString());
}
}
}
// Remove last semicolon
if (env.compress && rules.length) {
rule = rules[rules.length - 1];
if (rule.charAt(rule.length - 1) === ';') {
rules[rules.length - 1] = rule.substring(0, rule.length - 1);
}
output.add((env.compress ? '{' : ' {\n') + tabRuleStr);
}
rulesets = rulesets.join('');
// Compile rules and rulesets
for (i = 0; i < ruleNodes.length; i++) {
rule = ruleNodes[i];
// If this is the root node, we don't render
// a selector, or {}.
// Otherwise, only output if this ruleset has rules.
if (this.root) {
css.push(rules.join(env.compress ? '' : '\n'));
} else {
if (rules.length > 0) {
debugInfo = tree.debugInfo(env, this);
selector = this.paths.map(function (p) {
return p.map(function (s) {
return s.toCSS(env);
}).join('').trim();
}).join(env.compress ? ',' : ',\n');
if (i + 1 === ruleNodes.length) {
env.lastRule = true;
}
// Remove duplicates
for (var i = rules.length - 1; i >= 0; i--) {
if (rules[i].slice(0, 2) === "/*" || _rules.indexOf(rules[i]) === -1) {
_rules.unshift(rules[i]);
}
}
rules = _rules;
if (rule.toCSS) {
output.add(rule.genCSS(env, output));
} else if (rule.value) {
output.add(rule.value.toString());
}
css.push(debugInfo + selector +
(env.compress ? '{' : ' {\n ') +
rules.join(env.compress ? '' : '\n ') +
(env.compress ? '}' : '\n}\n'));
if (!env.lastRule) {
output.add(env.compress ? '' : ('\n' + tabRuleStr));
} else {
env.lastRule = false;
}
}
css.push(rulesets);
return css.join('') + (env.compress ? '\n' : '');
if (!this.root) {
output.add((env.compress ? '}' : '\n' + tabSetStr + '}'));
env.tabLevel--;
}
for (i = 0; i < rulesetNodes.length; i++) {
if (ruleNodes.length && firstRuleset) {
output.add("\n" + (this.root ? tabRuleStr : tabSetStr));
}
if (!firstRuleset) {
output.add('\n' + (this.root ? tabRuleStr : tabSetStr));
}
firstRuleset = false;
output.add(rulesetNodes[i].genCSS(env, output));
}
output.add(!env.compress && this.firstRoot ? '\n' : '');
},
toCSS: tree.toCSS,
markReferenced: function () {
for (var s = 0; s < this.selectors.length; s++) {
this.selectors[s].markReferenced();
}
},
joinSelectors: function (paths, context, selectors) {

@@ -301,3 +318,3 @@ for (var s = 0; s < selectors.length; s++) {

if (context.length > 0) {
for(i = 0; i < context.length; i++) {
for (i = 0; i < context.length; i++) {
paths.push(context[i].concat(selector));

@@ -346,7 +363,7 @@ }

// loop through our current selectors
for(j = 0; j < newSelectors.length; j++) {
for (j = 0; j < newSelectors.length; j++) {
sel = newSelectors[j];
// if we don't have any parent paths, the & might be in a mixin so that it can be used
// whether there are parents or not
if (context.length == 0) {
if (context.length === 0) {
// the combinator used on el should now be applied to the next element instead so that

@@ -356,3 +373,3 @@ // it is not lost

sel[0].elements = sel[0].elements.slice(0);
sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, ""));
sel[0].elements.push(new(tree.Element)(el.combinator, '', 0, el.index, el.currentFileInfo));
}

@@ -363,3 +380,3 @@ selectorsMultiplied.push(sel);

// and the parent selectors
for(k = 0; k < context.length; k++) {
for (k = 0; k < context.length; k++) {
parentSel = context[k];

@@ -380,7 +397,7 @@ // We need to put the current selectors

lastSelector = newSelectorPath.pop();
newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0), selector.extendList);
newJoinedSelector = selector.createDerived(lastSelector.elements.slice(0));
newJoinedSelectorEmpty = false;
}
else {
newJoinedSelector = new(tree.Selector)([], selector.extendList);
newJoinedSelector = selector.createDerived([]);
}

@@ -397,3 +414,3 @@

// join the elements so far with the first part of the parent
newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0));
newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, el.index, el.currentFileInfo));
newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));

@@ -428,3 +445,3 @@ }

for(i = 0; i < newSelectors.length; i++) {
for (i = 0; i < newSelectors.length; i++) {
if (newSelectors[i].length > 0) {

@@ -437,5 +454,5 @@ paths.push(newSelectors[i]);

mergeElementsOnToSelectors: function(elements, selectors) {
var i, sel, extendList;
var i, sel;
if (selectors.length == 0) {
if (selectors.length === 0) {
selectors.push([ new(tree.Selector)(elements) ]);

@@ -445,3 +462,3 @@ return;

for(i = 0; i < selectors.length; i++) {
for (i = 0; i < selectors.length; i++) {
sel = selectors[i];

@@ -451,3 +468,3 @@

if (sel.length > 0) {
sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements), sel[sel.length - 1].extendList);
sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
}

@@ -454,0 +471,0 @@ else {

(function (tree) {
tree.Selector = function (elements, extendList) {
tree.Selector = function (elements, extendList, condition, index, currentFileInfo, isReferenced) {
this.elements = elements;
this.extendList = extendList || [];
this.condition = condition;
this.currentFileInfo = currentFileInfo || {};
this.isReferenced = isReferenced;
if (!condition) {
this.evaldCondition = true;
}
};

@@ -11,4 +17,12 @@ tree.Selector.prototype = {

this.elements = visitor.visit(this.elements);
this.extendList = visitor.visit(this.extendList)
this.extendList = visitor.visit(this.extendList);
this.condition = visitor.visit(this.condition);
},
createDerived: function(elements, extendList, evaldCondition) {
/*jshint eqnull:true */
evaldCondition = evaldCondition != null ? evaldCondition : this.evaldCondition;
var newSelector = new(tree.Selector)(elements, extendList || this.extendList, this.condition, this.index, this.currentFileInfo, this.isReferenced);
newSelector.evaldCondition = evaldCondition;
return newSelector;
},
match: function (other) {

@@ -36,26 +50,32 @@ var elements = this.elements,

eval: function (env) {
return new(tree.Selector)(this.elements.map(function (e) {
var evaldCondition = this.condition && this.condition.eval(env);
return this.createDerived(this.elements.map(function (e) {
return e.eval(env);
}), this.extendList.map(function(extend) {
return extend.eval(env);
}));
}), evaldCondition);
},
toCSS: function (env) {
if (this._css) { return this._css }
if (this.elements[0].combinator.value === "") {
this._css = ' ';
} else {
this._css = '';
genCSS: function (env, output) {
var i, element;
if ((!env || !env.firstSelector) && this.elements[0].combinator.value === "") {
output.add(' ', this.currentFileInfo, this.index);
}
this._css += this.elements.map(function (e) {
if (typeof(e) === 'string') {
return ' ' + e.trim();
} else {
return e.toCSS(env);
if (!this._css) {
//TODO caching? speed comparison?
for(i = 0; i < this.elements.length; i++) {
element = this.elements[i];
element.genCSS(env, output);
}
}).join('');
return this._css;
}
},
toCSS: tree.toCSS,
markReferenced: function () {
this.isReferenced = true;
},
getIsReferenced: function() {
return !this.currentFileInfo.reference || this.isReferenced;
},
getIsOutput: function() {
return this.evaldCondition;
}

@@ -62,0 +82,0 @@ };

@@ -8,8 +8,9 @@ (function (tree) {

type: "UnicodeDescriptor",
toCSS: function (env) {
return this.value;
genCSS: function (env, output) {
output.add(this.value);
},
eval: function () { return this }
toCSS: tree.toCSS,
eval: function () { return this; }
};
})(require('../tree'));

@@ -12,5 +12,8 @@ (function (tree) {

},
toCSS: function () {
return "url(" + this.value.toCSS() + ")";
genCSS: function (env, output) {
output.add("url(");
this.value.genCSS(env, output);
output.add(")");
},
toCSS: tree.toCSS,
eval: function (ctx) {

@@ -28,2 +31,4 @@ var val = this.value.eval(ctx), rootpath;

val.value = ctx.normalizePath(val.value);
return new(tree.URL)(val, null);

@@ -30,0 +35,0 @@ }

@@ -20,9 +20,14 @@ (function (tree) {

},
toCSS: function (env) {
return this.value.map(function (e) {
return e.toCSS(env);
}).join(env.compress ? ',' : ', ');
}
genCSS: function (env, output) {
var i;
for(i = 0; i < this.value.length; i++) {
this.value[i].genCSS(env, output);
if (i+1 < this.value.length) {
output.add((env && env.compress) ? ',' : ', ');
}
}
},
toCSS: tree.toCSS
};
})(require('../tree'));
(function (tree) {
tree.Variable = function (name, index, currentFileInfo) { this.name = name, this.index = index, this.currentFileInfo = currentFileInfo };
tree.Variable = function (name, index, currentFileInfo) {
this.name = name;
this.index = index;
this.currentFileInfo = currentFileInfo;
};
tree.Variable.prototype = {

@@ -9,3 +13,3 @@ type: "Variable",

if (name.indexOf('@@') == 0) {
if (name.indexOf('@@') === 0) {
name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;

@@ -12,0 +16,0 @@ }

@@ -42,2 +42,3 @@ (function (tree) {

if (evald instanceof Array) {
evald = this.flatten(evald);
newNodes = newNodes.concat(evald);

@@ -52,2 +53,16 @@ } else {

return nodes;
},
doAccept: function (node) {
node.accept(this);
},
flatten: function(arr, master) {
return arr.reduce(this.flattenReduce.bind(this), master || []);
},
flattenReduce: function(sum, element) {
if (element instanceof Array) {
sum = this.flatten(element, sum);
} else {
sum.push(element);
}
return sum;
}

@@ -54,0 +69,0 @@ };

{
"name": "less",
"version": "1.4.2",
"version": "1.5.0-b1",
"description": "Leaner CSS",

@@ -25,3 +25,3 @@ "homepage": "http://lesscss.org",

"jam": {
"main": "./dist/less-1.4.1.js"
"main": "./dist/less-1.4.2.js"
},

@@ -32,2 +32,3 @@ "engines": {

"scripts": {
"pretest": "make jshint",
"test": "make test"

@@ -39,6 +40,9 @@ },

"mkdirp": "~0.3.4",
"ycssmin": ">=1.0.1"
"clean-css": "1.0.x",
"source-map": "0.1.x"
},
"devDependencies": {
"diff": "~1.0"
"diff": "~1.0",
"jshint": "~2.1.4",
"http-server": "~0.5.5"
},

@@ -45,0 +49,0 @@ "keywords": [

var path = require('path'),
fs = require('fs'),
sys = require('util');
fs = require('fs');

@@ -10,3 +9,3 @@ var readDirFilesSync = function(dir, regex, callback) {

});
}
};

@@ -19,7 +18,7 @@ var createTestRunnerPage = function(dir, exclude, testSuiteName, dir2) {

id = (dir ? dir + '-' : "") + 'less-' + (dir2 ? dir2 + "-" : "") + name;
if (exclude && name.match(exclude)) { return; }
output += '<link id="original-less:' + id + '" rel="stylesheet/less" type="text/css" href="/' + path.join(dir, 'less', dir2 || "", name) + '.less' +'">\n';
output += '<link id="expected-less:' + id + '" rel="stylesheet" type="text/css" href="/' + path.join(dir, 'css', dir2 || "", name) + '.css' + '">\n';
output += '<link id="original-less:' + id + '" rel="stylesheet/less" type="text/css" href="/' + path.join(dir, 'less', dir2 || "", name).replace("\\", "/") + '.less' +'" />\n';
output += '<link id="expected-less:' + id + '" rel="stylesheet" type="text/css" href="/' + path.join(dir, 'css', dir2 || "", name).replace("\\", "/") + '.css' + '" />\n';
});

@@ -38,3 +37,3 @@

});
}
};

@@ -45,2 +44,4 @@ removeFiles("test/browser", /test-runner-[a-zA-Z-]*\.htm$/);

createTestRunnerPage("", /javascript/, "errors", "errors");
createTestRunnerPage("", null, "no-js-errors", "no-js-errors");
createTestRunnerPage("browser", null, "console-errors", "console-errors");
createTestRunnerPage("browser", null, "browser");

@@ -50,2 +51,3 @@ createTestRunnerPage("browser", null, "relative-urls", "relative-urls");

createTestRunnerPage("browser", null, "rootpath-relative", "rootpath-relative");
createTestRunnerPage("browser", null, "production");
createTestRunnerPage("browser", null, "production");
createTestRunnerPage("browser", null, "modify-vars", "modify-vars");

@@ -16,4 +16,4 @@ /*if not async then phantomjs fails to run the webserver and the test concurrently*/

var testLessErrorsInDocument = function() {
testLessInDocument(testErrorSheet);
var testLessErrorsInDocument = function(isConsole) {
testLessInDocument(isConsole ? testErrorSheetConsole : testErrorSheet);
};

@@ -47,3 +47,3 @@

// use sheet to do testing
expect(lessOutput).toEqual(expectedOutput.text);
expect(expectedOutput.text).toEqual(lessOutput);
});

@@ -81,3 +81,3 @@ });

.replace("{404status}", " (404)");
expect(actualErrorMsg).toEqual(errorTxt);
expect(errorTxt).toEqual(actualErrorMsg);
if (errorTxt == actualErrorMsg) {

@@ -90,2 +90,37 @@ actualErrorElement.style.display = "none";

var testErrorSheetConsole = function(sheet) {
it(sheet.id + " should match an error", function() {
var lessHref = sheet.href,
id = sheet.id.replace(/^original-less:/, "less-error-message:"),
errorHref = lessHref.replace(/.less$/, ".txt"),
errorFile = loadFile(errorHref),
actualErrorElement = document.getElementById(id),
actualErrorMsg = logMessages[logMessages.length - 1];
describe("the error", function() {
expect(actualErrorElement).toBe(null);
});
/*actualErrorMsg = actualErrorElement.innerText
.replace(/\n\d+/g, function(lineNo) { return lineNo + " "; })
.replace(/\n\s*in /g, " in ")
.replace("\n\n", "\n");*/
waitsFor(function() {
return errorFile.loaded;
}, "failed to load expected outout", 10000);
runs(function() {
var errorTxt = errorFile.text
.replace("{path}", "")
.replace("{pathrel}", "")
.replace("{pathhref}", "http://localhost:8081/browser/less/")
.replace("{404status}", " (404)")
.trim();
expect(errorTxt).toEqual(actualErrorMsg);
});
});
};
var loadFile = function(href) {

@@ -92,0 +127,0 @@ var request = new XMLHttpRequest(),

describe("less.js browser behaviour", function() {
testLessEqualsInDocument();
it("has some log messages", function() {
expect(logMessages.length).toBeGreaterThan(0);
});
// test inline less in style tags by grabbing an assortment of less files and doing `@import`s
var testFiles = ['charsets', 'colors', 'comments', 'css-3', 'strings', 'media', 'mixins'],
testSheets = [];
// setup style tags with less and link tags pointing to expected css output
for (var i = 0; i < testFiles.length; i++) {
var file = testFiles[i],
lessPath = '/less/' + file + '.less',
cssPath = '/css/' + file + '.css',
lessStyle = document.createElement('style'),
cssLink = document.createElement('link'),
lessText = '@import "' + lessPath + '";';
lessStyle.type = 'text/less';
lessStyle.id = file;
if (lessStyle.styleSheet) {
lessStyle.styleSheet.cssText = lessText;
} else {
lessStyle.innerHTML = lessText;
}
cssLink.rel = 'stylesheet';
cssLink.type = 'text/css';
cssLink.href = cssPath;
cssLink.id = 'expected-' + file;
var head = document.getElementsByTagName('head')[0];
head.appendChild(lessStyle);
head.appendChild(cssLink);
testSheets[i] = lessStyle;
}
for (var i = 0; i < testFiles.length; i++) {
var sheet = testSheets[i];
testSheet(sheet);
}
});

@@ -0,1 +1,2 @@

/*jshint latedef: nofunc */
var path = require('path'),

@@ -12,2 +13,4 @@ fs = require('fs'),

var isVerbose = process.env.npm_config_loglevel === 'verbose';
var totalTests = 0,

@@ -24,3 +27,3 @@ failedTests = 0,

less.tree.functions._color = function (str) {
if (str.value === "evil red") { return new(less.tree.Color)("600") }
if (str.value === "evil red") { return new(less.tree.Color)("600"); }
};

@@ -31,4 +34,50 @@

runTestSet({strictMath: true, relativeUrls: true, silent: true});
runTestSet({strictMath: true, strictUnits: true}, "errors/",
testErrors, null, getErrorPathReplacementFunction("errors"));
runTestSet({strictMath: true, strictUnits: true, javascriptEnabled: false}, "no-js-errors/",
testErrors, null, getErrorPathReplacementFunction("no-js-errors"));
runTestSet({strictMath: true, dumpLineNumbers: 'comments'}, "debug/", null,
function(name) { return name + '-comments'; });
runTestSet({strictMath: true, dumpLineNumbers: 'mediaquery'}, "debug/", null,
function(name) { return name + '-mediaquery'; });
runTestSet({strictMath: true, dumpLineNumbers: 'all'}, "debug/", null,
function(name) { return name + '-all'; });
runTestSet({strictMath: true, relativeUrls: false, rootpath: "folder (1)/"}, "static-urls/");
runTestSet({strictMath: true, compress: true}, "compression/");
runTestSet({}, "legacy/");
runTestSet({strictMath: true, strictUnits: true, sourceMap: true }, "sourcemaps/",
testSourcemap, null, null, function(filename) { return path.join('test/sourcemaps', filename) + '.json'; });
runTestSet({strictMath: true, strictUnits: true}, "errors/", function(name, err, compiledLess, doReplacements) {
testNoOptions();
function getErrorPathReplacementFunction(dir) {
return function(input) {
return input.replace(
"{path}", path.join(process.cwd(), "/test/less/" + dir + "/"))
.replace("{pathrel}", path.join("test", "less", dir + "/"))
.replace("{pathhref}", "")
.replace("{404status}", "")
.replace(/\r\n/g, '\n');
};
}
function testSourcemap(name, err, compiledLess, doReplacements, sourcemap) {
fs.readFile(path.join('test/', name) + '.json', 'utf8', function (e, expectedSourcemap) {
sys.print("- " + name + ": ");
if (sourcemap === expectedSourcemap) {
ok('OK');
} else if (err) {
fail("ERROR: " + (err && err.message));
if (isVerbose) {
console.error();
console.error(err.stack);
}
} else {
difference("FAIL", expectedSourcemap, sourcemap);
}
sys.puts("");
});
}
function testErrors(name, err, compiledLess, doReplacements) {
fs.readFile(path.join('test/less/', name) + '.txt', 'utf8', function (e, expectedErr) {

@@ -46,3 +95,3 @@ sys.print("- " + name + ": ");

if (errMessage === expectedErr) {
ok('OK');
ok('OK');
} else {

@@ -53,22 +102,5 @@ difference("FAIL", expectedErr, errMessage);

sys.puts("");
});}, null, function(input, directory) {
return input.replace(
"{path}", path.join(process.cwd(), "/test/less/errors/"))
.replace("{pathrel}", path.join("test", "less", "errors/"))
.replace("{pathhref}", "")
.replace("{404status}", "")
.replace(/\r\n/g, '\n');
});
}
runTestSet({strictMath: true, dumpLineNumbers: 'comments'}, "debug/", null,
function(name) { return name + '-comments'; });
runTestSet({strictMath: true, dumpLineNumbers: 'mediaquery'}, "debug/", null,
function(name) { return name + '-mediaquery'; });
runTestSet({strictMath: true, dumpLineNumbers: 'all'}, "debug/", null,
function(name) { return name + '-all'; });
runTestSet({strictMath: true, relativeUrls: false, rootpath: "folder (1)/"}, "static-urls/");
runTestSet({strictMath: true, compress: true}, "compression/");
runTestSet({ }, "legacy/");
testNoOptions();
function globalReplacements(input, directory) {

@@ -93,3 +125,3 @@ var p = path.join(process.cwd(), directory),

function runTestSet(options, foldername, verifyFunction, nameModifier, doReplacements) {
function runTestSet(options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
foldername = foldername || "";

@@ -101,3 +133,3 @@

fs.readdirSync(path.join('test/less/', foldername)).forEach(function (file) {
if (! /\.less/.test(file)) { return }
if (! /\.less/.test(file)) { return; }

@@ -110,11 +142,21 @@ var name = foldername + path.basename(file, '.less');

if (options.sourceMap) {
var sourceMapOutput;
options.writeSourceMap = function(output) {
sourceMapOutput = output;
};
options.sourceMapOutputFilename = name + ".css";
options.sourceMapBasepath = path.join(process.cwd(), "test/less");
options.sourceMapRootpath = "testweb/";
}
toCSS(options, path.join('test/less/', foldername + file), function (err, less) {
if (verifyFunction) {
return verifyFunction(name, err, less, doReplacements);
return verifyFunction(name, err, less, doReplacements, sourceMapOutput);
}
var css_name = name;
if(nameModifier) css_name=nameModifier(name);
if(nameModifier) { css_name = nameModifier(name); }
fs.readFile(path.join('test/css', css_name) + '.css', 'utf8', function (e, css) {
sys.print("- " + css_name + ": ")
sys.print("- " + css_name + ": ");

@@ -125,2 +167,6 @@ css = css && doReplacements(css, 'test/less/' + foldername);

fail("ERROR: " + (err && err.message));
if (isVerbose) {
console.error();
console.error(err.stack);
}
} else {

@@ -139,3 +185,4 @@ difference("FAIL", css, less);

if(item.added || item.removed) {
sys.print(stylize(item.value, item.added ? 'green' : 'red'));
var text = item.value.replace("\n", String.fromCharCode(182) + "\n");
sys.print(stylize(text, item.added ? 'green' : 'red'));
} else {

@@ -190,6 +237,6 @@ sys.print(item.value);

function toCSS(options, path, callback) {
var tree, css;
var css;
options = options || {};
fs.readFile(path, 'utf8', function (e, str) {
if (e) { return callback(e) }
if (e) { return callback(e); }

@@ -219,3 +266,3 @@ options.paths = [require('path').dirname(path)];

sys.print("- Integration - creating parser without options: ");
new(less.Parser);
new(less.Parser)();
} catch(e) {

@@ -222,0 +269,0 @@ fail(stylize("FAIL\n", "red"));

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc