2 * Less - Leaner CSS v2.7.3
5 * Copyright (c) 2009-2017, Alexis Sellier <self@cloudhead.net>
6 * Licensed under the Apache-2.0 License.
10 /** * @license Apache-2.0
13 (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.less = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
14 var addDataAttr = require("./utils").addDataAttr,
15 browser = require("./browser");
17 module.exports = function(window, options) {
19 // use options from the current script tag data attribues
20 addDataAttr(options, browser.currentScript(window));
22 if (options.isFileProtocol === undefined) {
23 options.isFileProtocol = /^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(window.location.protocol);
26 // Load styles asynchronously (default: false)
28 // This is set to `false` by default, so that the body
29 // doesn't start loading before the stylesheets are parsed.
30 // Setting this to `true` can result in flickering.
32 options.async = options.async || false;
33 options.fileAsync = options.fileAsync || false;
35 // Interval between watch polls
36 options.poll = options.poll || (options.isFileProtocol ? 1000 : 1500);
38 options.env = options.env || (window.location.hostname == '127.0.0.1' ||
39 window.location.hostname == '0.0.0.0' ||
40 window.location.hostname == 'localhost' ||
41 (window.location.port &&
42 window.location.port.length > 0) ||
43 options.isFileProtocol ? 'development'
46 var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(window.location.hash);
47 if (dumpLineNumbers) {
48 options.dumpLineNumbers = dumpLineNumbers[1];
51 if (options.useFileCache === undefined) {
52 options.useFileCache = true;
55 if (options.onReady === undefined) {
56 options.onReady = true;
61 },{"./browser":3,"./utils":10}],2:[function(require,module,exports){
63 * Kicks off less and compiles any stylesheets
64 * used in the browser distributed version of less
65 * to kick-start less using the browser api
67 /*global window, document */
69 // shim Promise if required
70 require('promise/polyfill.js');
72 var options = window.less || {};
73 require("./add-default-options")(window, options);
75 var less = module.exports = require("./index")(window, options);
81 // Always restore page visibility
82 function resolveOrReject(data) {
87 head.removeChild(style);
91 if (options.onReady) {
92 if (/!watch/.test(window.location.hash)) {
95 // Simulate synchronous stylesheet loading by blocking page rendering
97 css = 'body { display: none !important }';
98 head = document.head || document.getElementsByTagName('head')[0];
99 style = document.createElement('style');
101 style.type = 'text/css';
102 if (style.styleSheet) {
103 style.styleSheet.cssText = css;
105 style.appendChild(document.createTextNode(css));
108 head.appendChild(style);
110 less.registerStylesheetsImmediately();
111 less.pageLoadFinished = less.refresh(less.env === 'development').then(resolveOrReject, resolveOrReject);
114 },{"./add-default-options":1,"./index":8,"promise/polyfill.js":97}],3:[function(require,module,exports){
115 var utils = require("./utils");
117 createCSS: function (document, styles, sheet) {
118 // Strip the query-string
119 var href = sheet.href || '';
121 // If there is no title set, use the filename, minus the extension
122 var id = 'less:' + (sheet.title || utils.extractId(href));
124 // If this has already been inserted into the DOM, we may need to replace it
125 var oldStyleNode = document.getElementById(id);
126 var keepOldStyleNode = false;
128 // Create a new stylesheet node for insertion or (if necessary) replacement
129 var styleNode = document.createElement('style');
130 styleNode.setAttribute('type', 'text/css');
132 styleNode.setAttribute('media', sheet.media);
136 if (!styleNode.styleSheet) {
137 styleNode.appendChild(document.createTextNode(styles));
139 // If new contents match contents of oldStyleNode, don't replace oldStyleNode
140 keepOldStyleNode = (oldStyleNode !== null && oldStyleNode.childNodes.length > 0 && styleNode.childNodes.length > 0 &&
141 oldStyleNode.firstChild.nodeValue === styleNode.firstChild.nodeValue);
144 var head = document.getElementsByTagName('head')[0];
146 // If there is no oldStyleNode, just append; otherwise, only append if we need
147 // to replace oldStyleNode with an updated stylesheet
148 if (oldStyleNode === null || keepOldStyleNode === false) {
149 var nextEl = sheet && sheet.nextSibling || null;
151 nextEl.parentNode.insertBefore(styleNode, nextEl);
153 head.appendChild(styleNode);
156 if (oldStyleNode && keepOldStyleNode === false) {
157 oldStyleNode.parentNode.removeChild(oldStyleNode);
161 // This needs to happen *after* the style element is added to the DOM, otherwise IE 7 and 8 may crash.
162 // See http://social.msdn.microsoft.com/Forums/en-US/7e081b65-878a-4c22-8e68-c10d39c2ed32/internet-explorer-crashes-appending-style-element-to-head
163 if (styleNode.styleSheet) {
165 styleNode.styleSheet.cssText = styles;
167 throw new Error("Couldn't reassign styleSheet.cssText.");
171 currentScript: function(window) {
172 var document = window.document;
173 return document.currentScript || (function() {
174 var scripts = document.getElementsByTagName("script");
175 return scripts[scripts.length - 1];
180 },{"./utils":10}],4:[function(require,module,exports){
181 // Cache system is a bit outdated and could do with work
183 module.exports = function(window, options, logger) {
185 if (options.env !== 'development') {
187 cache = (typeof window.localStorage === 'undefined') ? null : window.localStorage;
191 setCSS: function(path, lastModified, modifyVars, styles) {
193 logger.info('saving ' + path + ' to cache.');
195 cache.setItem(path, styles);
196 cache.setItem(path + ':timestamp', lastModified);
198 cache.setItem(path + ':vars', JSON.stringify(modifyVars));
201 //TODO - could do with adding more robust error handling
202 logger.error('failed to save "' + path + '" to local storage for caching.');
206 getCSS: function(path, webInfo, modifyVars) {
207 var css = cache && cache.getItem(path),
208 timestamp = cache && cache.getItem(path + ':timestamp'),
209 vars = cache && cache.getItem(path + ':vars');
211 modifyVars = modifyVars || {};
213 if (timestamp && webInfo.lastModified &&
214 (new Date(webInfo.lastModified).valueOf() ===
215 new Date(timestamp).valueOf()) &&
216 (!modifyVars && !vars || JSON.stringify(modifyVars) === vars)) {
224 },{}],5:[function(require,module,exports){
225 var utils = require("./utils"),
226 browser = require("./browser");
228 module.exports = function(window, less, options) {
230 function errorHTML(e, rootHref) {
231 var id = 'less-error-message:' + utils.extractId(rootHref || "");
232 var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
233 var elem = window.document.createElement('div'), timer, content, errors = [];
234 var filename = e.filename || rootHref;
235 var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
238 elem.className = "less-error-message";
240 content = '<h3>' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
241 '</h3>' + '<p>in <a href="' + filename + '">' + filenameNoPath + "</a> ";
243 var errorline = function (e, i, classname) {
244 if (e.extract[i] !== undefined) {
245 errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
246 .replace(/\{class\}/, classname)
247 .replace(/\{content\}/, e.extract[i]));
253 errorline(e, 1, 'line');
255 content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
256 '<ul>' + errors.join('') + '</ul>';
258 if (e.stack && (e.extract || options.logLevel >= 4)) {
259 content += '<br/>Stack Trace</br />' + e.stack.split('\n').slice(1).join('<br/>');
261 elem.innerHTML = content;
263 // CSS for error messages
264 browser.createCSS(window.document, [
265 '.less-error-message ul, .less-error-message li {',
266 'list-style-type: none;',
267 'margin-right: 15px;',
271 '.less-error-message label {',
273 'margin-right: 15px;',
277 '.less-error-message pre {',
281 'display: inline-block;',
283 '.less-error-message pre.line {',
286 '.less-error-message h3 {',
288 'font-weight: bold;',
289 'padding: 15px 0 5px 0;',
292 '.less-error-message a {',
295 '.less-error-message .error {',
297 'font-weight: bold;',
298 'padding-bottom: 2px;',
299 'border-bottom: 1px dashed red;',
301 ].join('\n'), { title: 'error-message' });
303 elem.style.cssText = [
304 "font-family: Arial, sans-serif",
305 "border: 1px solid #e00",
306 "background-color: #eee",
307 "border-radius: 5px",
308 "-webkit-border-radius: 5px",
309 "-moz-border-radius: 5px",
312 "margin-bottom: 15px"
315 if (options.env === 'development') {
316 timer = setInterval(function () {
317 var document = window.document,
318 body = document.body;
320 if (document.getElementById(id)) {
321 body.replaceChild(elem, document.getElementById(id));
323 body.insertBefore(elem, body.firstChild);
325 clearInterval(timer);
331 function removeErrorHTML(path) {
332 var node = window.document.getElementById('less-error-message:' + utils.extractId(path));
334 node.parentNode.removeChild(node);
338 function removeErrorConsole(path) {
342 function removeError(path) {
343 if (!options.errorReporting || options.errorReporting === "html") {
344 removeErrorHTML(path);
345 } else if (options.errorReporting === "console") {
346 removeErrorConsole(path);
347 } else if (typeof options.errorReporting === 'function') {
348 options.errorReporting("remove", path);
352 function errorConsole(e, rootHref) {
353 var template = '{line} {content}';
354 var filename = e.filename || rootHref;
356 var content = (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
357 " in " + filename + " ";
359 var errorline = function (e, i, classname) {
360 if (e.extract[i] !== undefined) {
361 errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
362 .replace(/\{class\}/, classname)
363 .replace(/\{content\}/, e.extract[i]));
369 errorline(e, 1, 'line');
371 content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n' +
374 if (e.stack && (e.extract || options.logLevel >= 4)) {
375 content += '\nStack Trace\n' + e.stack;
377 less.logger.error(content);
380 function error(e, rootHref) {
381 if (!options.errorReporting || options.errorReporting === "html") {
382 errorHTML(e, rootHref);
383 } else if (options.errorReporting === "console") {
384 errorConsole(e, rootHref);
385 } else if (typeof options.errorReporting === 'function') {
386 options.errorReporting("add", e, rootHref);
396 },{"./browser":3,"./utils":10}],6:[function(require,module,exports){
397 /*global window, XMLHttpRequest */
399 module.exports = function(options, logger) {
401 var AbstractFileManager = require("../less/environment/abstract-file-manager.js");
405 //TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load
407 function getXMLHttpRequest() {
408 if (window.XMLHttpRequest && (window.location.protocol !== "file:" || !("ActiveXObject" in window))) {
409 return new XMLHttpRequest();
412 /*global ActiveXObject */
413 return new ActiveXObject("Microsoft.XMLHTTP");
415 logger.error("browser doesn't support AJAX.");
421 var FileManager = function() {
424 FileManager.prototype = new AbstractFileManager();
426 FileManager.prototype.alwaysMakePathsAbsolute = function alwaysMakePathsAbsolute() {
429 FileManager.prototype.join = function join(basePath, laterPath) {
433 return this.extractUrlParts(laterPath, basePath).path;
435 FileManager.prototype.doXHR = function doXHR(url, type, callback, errback) {
437 var xhr = getXMLHttpRequest();
438 var async = options.isFileProtocol ? options.fileAsync : true;
440 if (typeof xhr.overrideMimeType === 'function') {
441 xhr.overrideMimeType('text/css');
443 logger.debug("XHR: Getting '" + url + "'");
444 xhr.open('GET', url, async);
445 xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
448 function handleResponse(xhr, callback, errback) {
449 if (xhr.status >= 200 && xhr.status < 300) {
450 callback(xhr.responseText,
451 xhr.getResponseHeader("Last-Modified"));
452 } else if (typeof errback === 'function') {
453 errback(xhr.status, url);
457 if (options.isFileProtocol && !options.fileAsync) {
458 if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
459 callback(xhr.responseText);
461 errback(xhr.status, url);
464 xhr.onreadystatechange = function () {
465 if (xhr.readyState == 4) {
466 handleResponse(xhr, callback, errback);
470 handleResponse(xhr, callback, errback);
473 FileManager.prototype.supports = function(filename, currentDirectory, options, environment) {
477 FileManager.prototype.clearFileCache = function() {
481 FileManager.prototype.loadFile = function loadFile(filename, currentDirectory, options, environment, callback) {
482 if (currentDirectory && !this.isPathAbsolute(filename)) {
483 filename = currentDirectory + filename;
486 options = options || {};
488 // sheet may be set to the stylesheet for the initial load or a collection of properties including
489 // some context variables for imports
490 var hrefParts = this.extractUrlParts(filename, window.location.href);
491 var href = hrefParts.url;
493 if (options.useFileCache && fileCache[href]) {
495 var lessText = fileCache[href];
496 callback(null, { contents: lessText, filename: href, webInfo: { lastModified: new Date() }});
498 callback({filename: href, message: "Error loading file " + href + " error was " + e.message});
503 this.doXHR(href, options.mime, function doXHRCallback(data, lastModified) {
505 fileCache[href] = data;
507 // Use remote copy (re-parse)
508 callback(null, { contents: data, filename: href, webInfo: { lastModified: lastModified }});
509 }, function doXHRError(status, url) {
510 callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")", href: href });
517 },{"../less/environment/abstract-file-manager.js":15}],7:[function(require,module,exports){
518 module.exports = function() {
520 var functionRegistry = require("./../less/functions/function-registry");
522 function imageSize() {
525 message: "Image size functions are not supported in browser version of less"
529 var imageFunctions = {
530 "image-size": function(filePathNode) {
531 imageSize(this, filePathNode);
534 "image-width": function(filePathNode) {
535 imageSize(this, filePathNode);
538 "image-height": function(filePathNode) {
539 imageSize(this, filePathNode);
544 functionRegistry.addMultiple(imageFunctions);
547 },{"./../less/functions/function-registry":22}],8:[function(require,module,exports){
550 // Should expose the additional browser functions on to the less object
552 var addDataAttr = require("./utils").addDataAttr,
553 browser = require("./browser");
555 module.exports = function(window, options) {
556 var document = window.document;
557 var less = require('../less')();
559 //module.exports = less;
560 less.options = options;
561 var environment = less.environment,
562 FileManager = require("./file-manager")(options, less.logger),
563 fileManager = new FileManager();
564 environment.addFileManager(fileManager);
565 less.FileManager = FileManager;
567 require("./log-listener")(less, options);
568 var errors = require("./error-reporting")(window, less, options);
569 var cache = less.cache = options.cache || require("./cache")(window, options, less.logger);
570 require('./image-size')(less.environment);
572 //Setup user functions
573 if (options.functions) {
574 less.functions.functionRegistry.addMultiple(options.functions);
577 var typePattern = /^text\/(x-)?less$/;
579 function postProcessCSS(styles) { // deprecated, use a plugin for postprocesstasks
580 if (options.postProcessor && typeof options.postProcessor === 'function') {
581 styles = options.postProcessor.call(styles, styles) || styles;
586 function clone(obj) {
588 for (var prop in obj) {
589 if (obj.hasOwnProperty(prop)) {
590 cloned[prop] = obj[prop];
596 // only really needed for phantom
597 function bind(func, thisArg) {
598 var curryArgs = Array.prototype.slice.call(arguments, 2);
600 var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0));
601 return func.apply(thisArg, args);
605 function loadStyles(modifyVars) {
606 var styles = document.getElementsByTagName('style'),
609 for (var i = 0; i < styles.length; i++) {
611 if (style.type.match(typePattern)) {
612 var instanceOptions = clone(options);
613 instanceOptions.modifyVars = modifyVars;
614 var lessText = style.innerHTML || '';
615 instanceOptions.filename = document.location.href.replace(/#.*$/, '');
617 /*jshint loopfunc:true */
618 // use closure to store current style
619 less.render(lessText, instanceOptions,
620 bind(function(style, e, result) {
622 errors.add(e, "inline");
624 style.type = 'text/css';
625 if (style.styleSheet) {
626 style.styleSheet.cssText = result.css;
628 style.innerHTML = result.css;
636 function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
638 var instanceOptions = clone(options);
639 addDataAttr(instanceOptions, sheet);
640 instanceOptions.mime = sheet.type;
643 instanceOptions.modifyVars = modifyVars;
646 function loadInitialFileCallback(loadedFile) {
648 var data = loadedFile.contents,
649 path = loadedFile.filename,
650 webInfo = loadedFile.webInfo;
653 currentDirectory: fileManager.getPath(path),
656 relativeUrls: instanceOptions.relativeUrls};
658 newFileInfo.entryPath = newFileInfo.currentDirectory;
659 newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory;
662 webInfo.remaining = remaining;
664 var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars);
665 if (!reload && css) {
666 webInfo.local = true;
667 callback(null, css, data, sheet, webInfo, path);
673 //TODO add tests around how this behaves when reloading
676 instanceOptions.rootFileInfo = newFileInfo;
677 less.render(data, instanceOptions, function(e, result) {
682 result.css = postProcessCSS(result.css);
683 cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css);
684 callback(null, result.css, data, sheet, webInfo, path);
689 fileManager.loadFile(sheet.href, null, instanceOptions, environment, function(e, loadedFile) {
694 loadInitialFileCallback(loadedFile);
698 function loadStyleSheets(callback, reload, modifyVars) {
699 for (var i = 0; i < less.sheets.length; i++) {
700 loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars);
704 function initRunningMode() {
705 if (less.env === 'development') {
706 less.watchTimer = setInterval(function () {
707 if (less.watchMode) {
708 fileManager.clearFileCache();
709 loadStyleSheets(function (e, css, _, sheet, webInfo) {
711 errors.add(e, e.href || sheet.href);
713 browser.createCSS(window.document, css, sheet);
724 less.watch = function () {
725 if (!less.watchMode ) {
726 less.env = 'development';
729 this.watchMode = true;
733 less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; };
736 // Synchronously get all <link> tags with the 'rel' attribute set to
737 // "stylesheet/less".
739 less.registerStylesheetsImmediately = function() {
740 var links = document.getElementsByTagName('link');
743 for (var i = 0; i < links.length; i++) {
744 if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
745 (links[i].type.match(typePattern)))) {
746 less.sheets.push(links[i]);
752 // Asynchronously get all <link> tags with the 'rel' attribute set to
753 // "stylesheet/less", returning a Promise.
755 less.registerStylesheets = function() {
756 return new Promise(function(resolve, reject) {
757 less.registerStylesheetsImmediately();
763 // With this function, it's possible to alter variables and re-render
764 // CSS without reloading less-files
766 less.modifyVars = function(record) {
767 return less.refresh(true, record, false);
770 less.refresh = function (reload, modifyVars, clearFileCache) {
771 if ((reload || clearFileCache) && clearFileCache !== false) {
772 fileManager.clearFileCache();
774 return new Promise(function (resolve, reject) {
775 var startTime, endTime, totalMilliseconds, remainingSheets;
776 startTime = endTime = new Date();
778 // Set counter for remaining unprocessed sheets
779 remainingSheets = less.sheets.length;
781 if (remainingSheets === 0) {
783 endTime = new Date();
784 totalMilliseconds = endTime - startTime;
785 less.logger.info("Less has finished and no sheets were loaded.");
787 startTime: startTime,
789 totalMilliseconds: totalMilliseconds,
790 sheets: less.sheets.length
794 // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array
795 loadStyleSheets(function (e, css, _, sheet, webInfo) {
797 errors.add(e, e.href || sheet.href);
802 less.logger.info("Loading " + sheet.href + " from cache.");
804 less.logger.info("Rendered " + sheet.href + " successfully.");
806 browser.createCSS(window.document, css, sheet);
807 less.logger.info("CSS for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms');
809 // Count completed sheet
812 // Check if the last remaining sheet was processed and then call the promise
813 if (remainingSheets === 0) {
814 totalMilliseconds = new Date() - startTime;
815 less.logger.info("Less has finished. CSS generated in " + totalMilliseconds + 'ms');
817 startTime: startTime,
819 totalMilliseconds: totalMilliseconds,
820 sheets: less.sheets.length
823 endTime = new Date();
824 }, reload, modifyVars);
827 loadStyles(modifyVars);
831 less.refreshStyles = loadStyles;
835 },{"../less":31,"./browser":3,"./cache":4,"./error-reporting":5,"./file-manager":6,"./image-size":7,"./log-listener":9,"./utils":10}],9:[function(require,module,exports){
836 module.exports = function(less, options) {
838 var logLevel_debug = 4,
843 // The amount of logging in the javascript console.
844 // 3 - Debug, information and errors
845 // 2 - Information and errors
849 options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : (options.env === 'development' ? logLevel_info : logLevel_error);
851 if (!options.loggers) {
853 debug: function(msg) {
854 if (options.logLevel >= logLevel_debug) {
858 info: function(msg) {
859 if (options.logLevel >= logLevel_info) {
863 warn: function(msg) {
864 if (options.logLevel >= logLevel_warn) {
868 error: function(msg) {
869 if (options.logLevel >= logLevel_error) {
875 for (var i = 0; i < options.loggers.length; i++) {
876 less.logger.addListener(options.loggers[i]);
880 },{}],10:[function(require,module,exports){
882 extractId: function(href) {
883 return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain
884 .replace(/[\?\&]livereload=\w+/, '') // Remove LiveReload cachebuster
885 .replace(/^\//, '') // Remove root /
886 .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension
887 .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
888 .replace(/\./g, ':'); // Replace dots with colons(for valid id)
890 addDataAttr: function(options, tag) {
891 for (var opt in tag.dataset) {
892 if (tag.dataset.hasOwnProperty(opt)) {
893 if (opt === "env" || opt === "dumpLineNumbers" || opt === "rootpath" || opt === "errorReporting") {
894 options[opt] = tag.dataset[opt];
897 options[opt] = JSON.parse(tag.dataset[opt]);
906 },{}],11:[function(require,module,exports){
908 module.exports = contexts;
910 var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) {
911 if (!original) { return; }
913 for (var i = 0; i < propertiesToCopy.length; i++) {
914 if (original.hasOwnProperty(propertiesToCopy[i])) {
915 destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
921 parse is used whilst parsing
923 var parseCopyProperties = [
925 'paths', // option - unmodified - paths to search for imports on
926 'relativeUrls', // option - whether to adjust URL's to be relative
927 'rootpath', // option - rootpath to append to URL's
928 'strictImports', // option -
929 'insecure', // option - whether to allow imports from insecure ssl hosts
930 'dumpLineNumbers', // option - whether to dump line numbers
931 'compress', // option - whether to compress
932 'syncImport', // option - whether to import synchronously
933 'chunkInput', // option - whether to chunk input. more performant but causes parse issues.
934 'mime', // browser only - mime type for sheet import
935 'useFileCache', // browser only - whether to use the per file session cache
937 'processImports', // option & context - whether to process imports. if false then imports will not be imported.
938 // Used by the import manager to stop multiple import visitors being created.
939 'pluginManager' // Used as the plugin manager for the session
942 contexts.Parse = function(options) {
943 copyFromOriginal(options, this, parseCopyProperties);
945 if (typeof this.paths === "string") { this.paths = [this.paths]; }
948 var evalCopyProperties = [
949 'paths', // additional include paths
950 'compress', // whether to compress
951 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
952 'strictMath', // whether math has to be within parenthesis
953 'strictUnits', // whether units need to evaluate correctly
954 'sourceMap', // whether to output a source map
955 'importMultiple', // whether we are currently importing multiple copies
956 'urlArgs', // whether to add args into url tokens
957 'javascriptEnabled',// option - whether JavaScript is enabled. if undefined, defaults to true
958 'pluginManager', // Used as the plugin manager for the session
959 'importantScope' // used to bubble up !important statements
962 contexts.Eval = function(options, frames) {
963 copyFromOriginal(options, this, evalCopyProperties);
965 if (typeof this.paths === "string") { this.paths = [this.paths]; }
967 this.frames = frames || [];
968 this.importantScope = this.importantScope || [];
971 contexts.Eval.prototype.inParenthesis = function () {
972 if (!this.parensStack) {
973 this.parensStack = [];
975 this.parensStack.push(true);
978 contexts.Eval.prototype.outOfParenthesis = function () {
979 this.parensStack.pop();
982 contexts.Eval.prototype.isMathOn = function () {
983 return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
986 contexts.Eval.prototype.isPathRelative = function (path) {
987 return !/^(?:[a-z-]+:|\/|#)/i.test(path);
990 contexts.Eval.prototype.normalizePath = function( path ) {
992 segments = path.split("/").reverse(),
996 while (segments.length !== 0 ) {
997 segment = segments.pop();
1002 if ((path.length === 0) || (path[path.length - 1] === "..")) {
1003 path.push( segment );
1009 path.push( segment );
1014 return path.join("/");
1017 //todo - do the same for the toCSS ?
1019 },{}],12:[function(require,module,exports){
1021 'aliceblue':'#f0f8ff',
1022 'antiquewhite':'#faebd7',
1024 'aquamarine':'#7fffd4',
1029 'blanchedalmond':'#ffebcd',
1031 'blueviolet':'#8a2be2',
1033 'burlywood':'#deb887',
1034 'cadetblue':'#5f9ea0',
1035 'chartreuse':'#7fff00',
1036 'chocolate':'#d2691e',
1038 'cornflowerblue':'#6495ed',
1039 'cornsilk':'#fff8dc',
1040 'crimson':'#dc143c',
1042 'darkblue':'#00008b',
1043 'darkcyan':'#008b8b',
1044 'darkgoldenrod':'#b8860b',
1045 'darkgray':'#a9a9a9',
1046 'darkgrey':'#a9a9a9',
1047 'darkgreen':'#006400',
1048 'darkkhaki':'#bdb76b',
1049 'darkmagenta':'#8b008b',
1050 'darkolivegreen':'#556b2f',
1051 'darkorange':'#ff8c00',
1052 'darkorchid':'#9932cc',
1053 'darkred':'#8b0000',
1054 'darksalmon':'#e9967a',
1055 'darkseagreen':'#8fbc8f',
1056 'darkslateblue':'#483d8b',
1057 'darkslategray':'#2f4f4f',
1058 'darkslategrey':'#2f4f4f',
1059 'darkturquoise':'#00ced1',
1060 'darkviolet':'#9400d3',
1061 'deeppink':'#ff1493',
1062 'deepskyblue':'#00bfff',
1063 'dimgray':'#696969',
1064 'dimgrey':'#696969',
1065 'dodgerblue':'#1e90ff',
1066 'firebrick':'#b22222',
1067 'floralwhite':'#fffaf0',
1068 'forestgreen':'#228b22',
1069 'fuchsia':'#ff00ff',
1070 'gainsboro':'#dcdcdc',
1071 'ghostwhite':'#f8f8ff',
1073 'goldenrod':'#daa520',
1077 'greenyellow':'#adff2f',
1078 'honeydew':'#f0fff0',
1079 'hotpink':'#ff69b4',
1080 'indianred':'#cd5c5c',
1084 'lavender':'#e6e6fa',
1085 'lavenderblush':'#fff0f5',
1086 'lawngreen':'#7cfc00',
1087 'lemonchiffon':'#fffacd',
1088 'lightblue':'#add8e6',
1089 'lightcoral':'#f08080',
1090 'lightcyan':'#e0ffff',
1091 'lightgoldenrodyellow':'#fafad2',
1092 'lightgray':'#d3d3d3',
1093 'lightgrey':'#d3d3d3',
1094 'lightgreen':'#90ee90',
1095 'lightpink':'#ffb6c1',
1096 'lightsalmon':'#ffa07a',
1097 'lightseagreen':'#20b2aa',
1098 'lightskyblue':'#87cefa',
1099 'lightslategray':'#778899',
1100 'lightslategrey':'#778899',
1101 'lightsteelblue':'#b0c4de',
1102 'lightyellow':'#ffffe0',
1104 'limegreen':'#32cd32',
1106 'magenta':'#ff00ff',
1108 'mediumaquamarine':'#66cdaa',
1109 'mediumblue':'#0000cd',
1110 'mediumorchid':'#ba55d3',
1111 'mediumpurple':'#9370d8',
1112 'mediumseagreen':'#3cb371',
1113 'mediumslateblue':'#7b68ee',
1114 'mediumspringgreen':'#00fa9a',
1115 'mediumturquoise':'#48d1cc',
1116 'mediumvioletred':'#c71585',
1117 'midnightblue':'#191970',
1118 'mintcream':'#f5fffa',
1119 'mistyrose':'#ffe4e1',
1120 'moccasin':'#ffe4b5',
1121 'navajowhite':'#ffdead',
1123 'oldlace':'#fdf5e6',
1125 'olivedrab':'#6b8e23',
1127 'orangered':'#ff4500',
1129 'palegoldenrod':'#eee8aa',
1130 'palegreen':'#98fb98',
1131 'paleturquoise':'#afeeee',
1132 'palevioletred':'#d87093',
1133 'papayawhip':'#ffefd5',
1134 'peachpuff':'#ffdab9',
1138 'powderblue':'#b0e0e6',
1140 'rebeccapurple':'#663399',
1142 'rosybrown':'#bc8f8f',
1143 'royalblue':'#4169e1',
1144 'saddlebrown':'#8b4513',
1146 'sandybrown':'#f4a460',
1147 'seagreen':'#2e8b57',
1148 'seashell':'#fff5ee',
1151 'skyblue':'#87ceeb',
1152 'slateblue':'#6a5acd',
1153 'slategray':'#708090',
1154 'slategrey':'#708090',
1156 'springgreen':'#00ff7f',
1157 'steelblue':'#4682b4',
1160 'thistle':'#d8bfd8',
1162 'turquoise':'#40e0d0',
1166 'whitesmoke':'#f5f5f5',
1168 'yellowgreen':'#9acd32'
1170 },{}],13:[function(require,module,exports){
1172 colors: require("./colors"),
1173 unitConversions: require("./unit-conversions")
1176 },{"./colors":12,"./unit-conversions":14}],14:[function(require,module,exports){
1185 'pc': 0.0254 / 72 * 12
1192 'rad': 1 / (2 * Math.PI),
1198 },{}],15:[function(require,module,exports){
1199 var abstractFileManager = function() {
1202 abstractFileManager.prototype.getPath = function (filename) {
1203 var j = filename.lastIndexOf('?');
1205 filename = filename.slice(0, j);
1207 j = filename.lastIndexOf('/');
1209 j = filename.lastIndexOf('\\');
1214 return filename.slice(0, j + 1);
1217 abstractFileManager.prototype.tryAppendExtension = function(path, ext) {
1218 return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext;
1221 abstractFileManager.prototype.tryAppendLessExtension = function(path) {
1222 return this.tryAppendExtension(path, '.less');
1225 abstractFileManager.prototype.supportsSync = function() {
1229 abstractFileManager.prototype.alwaysMakePathsAbsolute = function() {
1233 abstractFileManager.prototype.isPathAbsolute = function(filename) {
1234 return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename);
1237 abstractFileManager.prototype.join = function(basePath, laterPath) {
1241 return basePath + laterPath;
1243 abstractFileManager.prototype.pathDiff = function pathDiff(url, baseUrl) {
1244 // diff between two paths to create a relative path
1246 var urlParts = this.extractUrlParts(url),
1247 baseUrlParts = this.extractUrlParts(baseUrl),
1248 i, max, urlDirectories, baseUrlDirectories, diff = "";
1249 if (urlParts.hostPart !== baseUrlParts.hostPart) {
1252 max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
1253 for (i = 0; i < max; i++) {
1254 if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
1256 baseUrlDirectories = baseUrlParts.directories.slice(i);
1257 urlDirectories = urlParts.directories.slice(i);
1258 for (i = 0; i < baseUrlDirectories.length - 1; i++) {
1261 for (i = 0; i < urlDirectories.length - 1; i++) {
1262 diff += urlDirectories[i] + "/";
1266 // helper function, not part of API
1267 abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, baseUrl) {
1268 // urlParts[1] = protocol://hostname/ OR /
1269 // urlParts[2] = / if path relative to host base
1270 // urlParts[3] = directories
1271 // urlParts[4] = filename
1272 // urlParts[5] = parameters
1274 var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
1275 urlParts = url.match(urlPartsRegex),
1276 returner = {}, directories = [], i, baseUrlParts;
1279 throw new Error("Could not parse sheet href - '" + url + "'");
1282 // Stylesheets in IE don't always return the full path
1283 if (baseUrl && (!urlParts[1] || urlParts[2])) {
1284 baseUrlParts = baseUrl.match(urlPartsRegex);
1285 if (!baseUrlParts) {
1286 throw new Error("Could not parse page url - '" + baseUrl + "'");
1288 urlParts[1] = urlParts[1] || baseUrlParts[1] || "";
1290 urlParts[3] = baseUrlParts[3] + urlParts[3];
1295 directories = urlParts[3].replace(/\\/g, "/").split("/");
1297 // extract out . before .. so .. doesn't absorb a non-directory
1298 for (i = 0; i < directories.length; i++) {
1299 if (directories[i] === ".") {
1300 directories.splice(i, 1);
1305 for (i = 0; i < directories.length; i++) {
1306 if (directories[i] === ".." && i > 0) {
1307 directories.splice(i - 1, 2);
1313 returner.hostPart = urlParts[1];
1314 returner.directories = directories;
1315 returner.path = (urlParts[1] || "") + directories.join("/");
1316 returner.fileUrl = returner.path + (urlParts[4] || "");
1317 returner.url = returner.fileUrl + (urlParts[5] || "");
1321 module.exports = abstractFileManager;
1323 },{}],16:[function(require,module,exports){
1324 var logger = require("../logger");
1325 var environment = function(externalEnvironment, fileManagers) {
1326 this.fileManagers = fileManagers || [];
1327 externalEnvironment = externalEnvironment || {};
1329 var optionalFunctions = ["encodeBase64", "mimeLookup", "charsetLookup", "getSourceMapGenerator"],
1330 requiredFunctions = [],
1331 functions = requiredFunctions.concat(optionalFunctions);
1333 for (var i = 0; i < functions.length; i++) {
1334 var propName = functions[i],
1335 environmentFunc = externalEnvironment[propName];
1336 if (environmentFunc) {
1337 this[propName] = environmentFunc.bind(externalEnvironment);
1338 } else if (i < requiredFunctions.length) {
1339 this.warn("missing required function in environment - " + propName);
1344 environment.prototype.getFileManager = function (filename, currentDirectory, options, environment, isSync) {
1347 logger.warn("getFileManager called with no filename.. Please report this issue. continuing.");
1349 if (currentDirectory == null) {
1350 logger.warn("getFileManager called with null directory.. Please report this issue. continuing.");
1353 var fileManagers = this.fileManagers;
1354 if (options.pluginManager) {
1355 fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers());
1357 for (var i = fileManagers.length - 1; i >= 0 ; i--) {
1358 var fileManager = fileManagers[i];
1359 if (fileManager[isSync ? "supportsSync" : "supports"](filename, currentDirectory, options, environment)) {
1366 environment.prototype.addFileManager = function (fileManager) {
1367 this.fileManagers.push(fileManager);
1370 environment.prototype.clearFileManagers = function () {
1371 this.fileManagers = [];
1374 module.exports = environment;
1376 },{"../logger":33}],17:[function(require,module,exports){
1377 var Color = require("../tree/color"),
1378 functionRegistry = require("./function-registry");
1381 // ref: http://www.w3.org/TR/compositing-1
1383 function colorBlend(mode, color1, color2) {
1384 var ab = color1.alpha, cb, // backdrop
1385 as = color2.alpha, cs, // source
1386 ar, cr, r = []; // result
1388 ar = as + ab * (1 - as);
1389 for (var i = 0; i < 3; i++) {
1390 cb = color1.rgb[i] / 255;
1391 cs = color2.rgb[i] / 255;
1394 cr = (as * cs + ab * (cb -
1395 as * (cb + cs - cr))) / ar;
1400 return new Color(r, ar);
1403 var colorBlendModeFunctions = {
1404 multiply: function(cb, cs) {
1407 screen: function(cb, cs) {
1408 return cb + cs - cb * cs;
1410 overlay: function(cb, cs) {
1413 colorBlendModeFunctions.multiply(cb, cs) :
1414 colorBlendModeFunctions.screen(cb - 1, cs);
1416 softlight: function(cb, cs) {
1420 d = (cb > 0.25) ? Math.sqrt(cb)
1421 : ((16 * cb - 12) * cb + 4) * cb;
1423 return cb - (1 - 2 * cs) * e * (d - cb);
1425 hardlight: function(cb, cs) {
1426 return colorBlendModeFunctions.overlay(cs, cb);
1428 difference: function(cb, cs) {
1429 return Math.abs(cb - cs);
1431 exclusion: function(cb, cs) {
1432 return cb + cs - 2 * cb * cs;
1435 // non-w3c functions:
1436 average: function(cb, cs) {
1437 return (cb + cs) / 2;
1439 negation: function(cb, cs) {
1440 return 1 - Math.abs(cb + cs - 1);
1444 for (var f in colorBlendModeFunctions) {
1445 if (colorBlendModeFunctions.hasOwnProperty(f)) {
1446 colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]);
1450 functionRegistry.addMultiple(colorBlend);
1452 },{"../tree/color":50,"./function-registry":22}],18:[function(require,module,exports){
1453 var Dimension = require("../tree/dimension"),
1454 Color = require("../tree/color"),
1455 Quoted = require("../tree/quoted"),
1456 Anonymous = require("../tree/anonymous"),
1457 functionRegistry = require("./function-registry"),
1460 function clamp(val) {
1461 return Math.min(1, Math.max(0, val));
1463 function hsla(color) {
1464 return colorFunctions.hsla(color.h, color.s, color.l, color.a);
1466 function number(n) {
1467 if (n instanceof Dimension) {
1468 return parseFloat(n.unit.is('%') ? n.value / 100 : n.value);
1469 } else if (typeof n === 'number') {
1474 message: "color functions take numbers as parameters"
1478 function scaled(n, size) {
1479 if (n instanceof Dimension && n.unit.is('%')) {
1480 return parseFloat(n.value * size / 100);
1486 rgb: function (r, g, b) {
1487 return colorFunctions.rgba(r, g, b, 1.0);
1489 rgba: function (r, g, b, a) {
1490 var rgb = [r, g, b].map(function (c) { return scaled(c, 255); });
1492 return new Color(rgb, a);
1494 hsl: function (h, s, l) {
1495 return colorFunctions.hsla(h, s, l, 1.0);
1497 hsla: function (h, s, l, a) {
1502 h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
1504 return m1 + (m2 - m1) * h * 6;
1506 else if (h * 2 < 1) {
1509 else if (h * 3 < 2) {
1510 return m1 + (m2 - m1) * (2 / 3 - h) * 6;
1517 h = (number(h) % 360) / 360;
1518 s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a));
1520 m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
1523 return colorFunctions.rgba(hue(h + 1 / 3) * 255,
1525 hue(h - 1 / 3) * 255,
1529 hsv: function(h, s, v) {
1530 return colorFunctions.hsva(h, s, v, 1.0);
1533 hsva: function(h, s, v, a) {
1534 h = ((number(h) % 360) / 360) * 360;
1535 s = number(s); v = number(v); a = number(a);
1538 i = Math.floor((h / 60) % 6);
1544 v * (1 - (1 - f) * s)];
1545 var perm = [[0, 3, 1],
1552 return colorFunctions.rgba(vs[perm[i][0]] * 255,
1553 vs[perm[i][1]] * 255,
1554 vs[perm[i][2]] * 255,
1558 hue: function (color) {
1559 return new Dimension(color.toHSL().h);
1561 saturation: function (color) {
1562 return new Dimension(color.toHSL().s * 100, '%');
1564 lightness: function (color) {
1565 return new Dimension(color.toHSL().l * 100, '%');
1567 hsvhue: function(color) {
1568 return new Dimension(color.toHSV().h);
1570 hsvsaturation: function (color) {
1571 return new Dimension(color.toHSV().s * 100, '%');
1573 hsvvalue: function (color) {
1574 return new Dimension(color.toHSV().v * 100, '%');
1576 red: function (color) {
1577 return new Dimension(color.rgb[0]);
1579 green: function (color) {
1580 return new Dimension(color.rgb[1]);
1582 blue: function (color) {
1583 return new Dimension(color.rgb[2]);
1585 alpha: function (color) {
1586 return new Dimension(color.toHSL().a);
1588 luma: function (color) {
1589 return new Dimension(color.luma() * color.alpha * 100, '%');
1591 luminance: function (color) {
1593 (0.2126 * color.rgb[0] / 255) +
1594 (0.7152 * color.rgb[1] / 255) +
1595 (0.0722 * color.rgb[2] / 255);
1597 return new Dimension(luminance * color.alpha * 100, '%');
1599 saturate: function (color, amount, method) {
1600 // filter: saturate(3.2);
1601 // should be kept as is, so check for color
1605 var hsl = color.toHSL();
1607 if (typeof method !== "undefined" && method.value === "relative") {
1608 hsl.s += hsl.s * amount.value / 100;
1611 hsl.s += amount.value / 100;
1613 hsl.s = clamp(hsl.s);
1616 desaturate: function (color, amount, method) {
1617 var hsl = color.toHSL();
1619 if (typeof method !== "undefined" && method.value === "relative") {
1620 hsl.s -= hsl.s * amount.value / 100;
1623 hsl.s -= amount.value / 100;
1625 hsl.s = clamp(hsl.s);
1628 lighten: function (color, amount, method) {
1629 var hsl = color.toHSL();
1631 if (typeof method !== "undefined" && method.value === "relative") {
1632 hsl.l += hsl.l * amount.value / 100;
1635 hsl.l += amount.value / 100;
1637 hsl.l = clamp(hsl.l);
1640 darken: function (color, amount, method) {
1641 var hsl = color.toHSL();
1643 if (typeof method !== "undefined" && method.value === "relative") {
1644 hsl.l -= hsl.l * amount.value / 100;
1647 hsl.l -= amount.value / 100;
1649 hsl.l = clamp(hsl.l);
1652 fadein: function (color, amount, method) {
1653 var hsl = color.toHSL();
1655 if (typeof method !== "undefined" && method.value === "relative") {
1656 hsl.a += hsl.a * amount.value / 100;
1659 hsl.a += amount.value / 100;
1661 hsl.a = clamp(hsl.a);
1664 fadeout: function (color, amount, method) {
1665 var hsl = color.toHSL();
1667 if (typeof method !== "undefined" && method.value === "relative") {
1668 hsl.a -= hsl.a * amount.value / 100;
1671 hsl.a -= amount.value / 100;
1673 hsl.a = clamp(hsl.a);
1676 fade: function (color, amount) {
1677 var hsl = color.toHSL();
1679 hsl.a = amount.value / 100;
1680 hsl.a = clamp(hsl.a);
1683 spin: function (color, amount) {
1684 var hsl = color.toHSL();
1685 var hue = (hsl.h + amount.value) % 360;
1687 hsl.h = hue < 0 ? 360 + hue : hue;
1692 // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein
1693 // http://sass-lang.com
1695 mix: function (color1, color2, weight) {
1696 if (!color1.toHSL || !color2.toHSL) {
1697 console.log(color2.type);
1698 console.dir(color2);
1701 weight = new Dimension(50);
1703 var p = weight.value / 100.0;
1705 var a = color1.toHSL().a - color2.toHSL().a;
1707 var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
1710 var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
1711 color1.rgb[1] * w1 + color2.rgb[1] * w2,
1712 color1.rgb[2] * w1 + color2.rgb[2] * w2];
1714 var alpha = color1.alpha * p + color2.alpha * (1 - p);
1716 return new Color(rgb, alpha);
1718 greyscale: function (color) {
1719 return colorFunctions.desaturate(color, new Dimension(100));
1721 contrast: function (color, dark, light, threshold) {
1722 // filter: contrast(3.2);
1723 // should be kept as is, so check for color
1727 if (typeof light === 'undefined') {
1728 light = colorFunctions.rgba(255, 255, 255, 1.0);
1730 if (typeof dark === 'undefined') {
1731 dark = colorFunctions.rgba(0, 0, 0, 1.0);
1733 //Figure out which is actually light and dark!
1734 if (dark.luma() > light.luma()) {
1739 if (typeof threshold === 'undefined') {
1742 threshold = number(threshold);
1744 if (color.luma() < threshold) {
1750 argb: function (color) {
1751 return new Anonymous(color.toARGB());
1753 color: function(c) {
1754 if ((c instanceof Quoted) &&
1755 (/^#([a-f0-9]{6}|[a-f0-9]{3})$/i.test(c.value))) {
1756 return new Color(c.value.slice(1));
1758 if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) {
1759 c.value = undefined;
1764 message: "argument must be a color keyword or 3/6 digit hex e.g. #FFF"
1767 tint: function(color, amount) {
1768 return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount);
1770 shade: function(color, amount) {
1771 return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount);
1774 functionRegistry.addMultiple(colorFunctions);
1776 },{"../tree/anonymous":46,"../tree/color":50,"../tree/dimension":56,"../tree/quoted":73,"./function-registry":22}],19:[function(require,module,exports){
1777 module.exports = function(environment) {
1778 var Quoted = require("../tree/quoted"),
1779 URL = require("../tree/url"),
1780 functionRegistry = require("./function-registry"),
1781 fallback = function(functionThis, node) {
1782 return new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context);
1784 logger = require('../logger');
1786 functionRegistry.add("data-uri", function(mimetypeNode, filePathNode) {
1788 if (!filePathNode) {
1789 filePathNode = mimetypeNode;
1790 mimetypeNode = null;
1793 var mimetype = mimetypeNode && mimetypeNode.value;
1794 var filePath = filePathNode.value;
1795 var currentFileInfo = this.currentFileInfo;
1796 var currentDirectory = currentFileInfo.relativeUrls ?
1797 currentFileInfo.currentDirectory : currentFileInfo.entryPath;
1799 var fragmentStart = filePath.indexOf('#');
1801 if (fragmentStart !== -1) {
1802 fragment = filePath.slice(fragmentStart);
1803 filePath = filePath.slice(0, fragmentStart);
1806 var fileManager = environment.getFileManager(filePath, currentDirectory, this.context, environment, true);
1809 return fallback(this, filePathNode);
1812 var useBase64 = false;
1814 // detect the mimetype if not given
1815 if (!mimetypeNode) {
1817 mimetype = environment.mimeLookup(filePath);
1819 if (mimetype === "image/svg+xml") {
1822 // use base 64 unless it's an ASCII or UTF-8 format
1823 var charset = environment.charsetLookup(mimetype);
1824 useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
1826 if (useBase64) { mimetype += ';base64'; }
1829 useBase64 = /;base64$/.test(mimetype);
1832 var fileSync = fileManager.loadFileSync(filePath, currentDirectory, this.context, environment);
1833 if (!fileSync.contents) {
1834 logger.warn("Skipped data-uri embedding of " + filePath + " because file not found");
1835 return fallback(this, filePathNode || mimetypeNode);
1837 var buf = fileSync.contents;
1838 if (useBase64 && !environment.encodeBase64) {
1839 return fallback(this, filePathNode);
1842 buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf);
1844 var uri = "data:" + mimetype + ',' + buf + fragment;
1846 // IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded
1847 // and the --ieCompat flag is enabled, return a normal url() instead.
1848 var DATA_URI_MAX = 32768;
1849 if (uri.length >= DATA_URI_MAX) {
1851 if (this.context.ieCompat !== false) {
1852 logger.warn("Skipped data-uri embedding of " + filePath + " because its size (" + uri.length +
1853 " characters) exceeds IE8-safe " + DATA_URI_MAX + " characters!");
1855 return fallback(this, filePathNode || mimetypeNode);
1859 return new URL(new Quoted('"' + uri + '"', uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
1863 },{"../logger":33,"../tree/quoted":73,"../tree/url":80,"./function-registry":22}],20:[function(require,module,exports){
1864 var Keyword = require("../tree/keyword"),
1865 functionRegistry = require("./function-registry");
1869 var v = this.value_, e = this.error_;
1874 return v ? Keyword.True : Keyword.False;
1877 value: function (v) {
1880 error: function (e) {
1883 reset: function () {
1884 this.value_ = this.error_ = null;
1888 functionRegistry.add("default", defaultFunc.eval.bind(defaultFunc));
1890 module.exports = defaultFunc;
1892 },{"../tree/keyword":65,"./function-registry":22}],21:[function(require,module,exports){
1893 var Expression = require("../tree/expression");
1895 var functionCaller = function(name, context, index, currentFileInfo) {
1896 this.name = name.toLowerCase();
1898 this.context = context;
1899 this.currentFileInfo = currentFileInfo;
1901 this.func = context.frames[0].functionRegistry.get(this.name);
1903 functionCaller.prototype.isValid = function() {
1904 return Boolean(this.func);
1906 functionCaller.prototype.call = function(args) {
1908 // This code is terrible and should be replaced as per this issue...
1909 // https://github.com/less/less.js/issues/2477
1910 if (Array.isArray(args)) {
1911 args = args.filter(function (item) {
1912 if (item.type === "Comment") {
1917 .map(function(item) {
1918 if (item.type === "Expression") {
1919 var subNodes = item.value.filter(function (item) {
1920 if (item.type === "Comment") {
1925 if (subNodes.length === 1) {
1928 return new Expression(subNodes);
1935 return this.func.apply(this, args);
1938 module.exports = functionCaller;
1940 },{"../tree/expression":59}],22:[function(require,module,exports){
1941 function makeRegistry( base ) {
1944 add: function(name, func) {
1945 // precautionary case conversion, as later querying of
1946 // the registry by function-caller uses lower case as well.
1947 name = name.toLowerCase();
1949 if (this._data.hasOwnProperty(name)) {
1952 this._data[name] = func;
1954 addMultiple: function(functions) {
1955 Object.keys(functions).forEach(
1957 this.add(name, functions[name]);
1960 get: function(name) {
1961 return this._data[name] || ( base && base.get( name ));
1963 inherit : function() {
1964 return makeRegistry( this );
1969 module.exports = makeRegistry( null );
1970 },{}],23:[function(require,module,exports){
1971 module.exports = function(environment) {
1973 functionRegistry: require("./function-registry"),
1974 functionCaller: require("./function-caller")
1977 //register functions
1978 require("./default");
1980 require("./color-blending");
1981 require("./data-uri")(environment);
1983 require("./number");
1984 require("./string");
1985 require("./svg")(environment);
1991 },{"./color":18,"./color-blending":17,"./data-uri":19,"./default":20,"./function-caller":21,"./function-registry":22,"./math":25,"./number":26,"./string":27,"./svg":28,"./types":29}],24:[function(require,module,exports){
1992 var Dimension = require("../tree/dimension");
1994 var MathHelper = function() {
1996 MathHelper._math = function (fn, unit, n) {
1997 if (!(n instanceof Dimension)) {
1998 throw { type: "Argument", message: "argument must be a number" };
2005 return new Dimension(fn(parseFloat(n.value)), unit);
2007 module.exports = MathHelper;
2008 },{"../tree/dimension":56}],25:[function(require,module,exports){
2009 var functionRegistry = require("./function-registry"),
2010 mathHelper = require("./math-helper.js");
2012 var mathFunctions = {
2026 for (var f in mathFunctions) {
2027 if (mathFunctions.hasOwnProperty(f)) {
2028 mathFunctions[f] = mathHelper._math.bind(null, Math[f], mathFunctions[f]);
2032 mathFunctions.round = function (n, f) {
2033 var fraction = typeof f === "undefined" ? 0 : f.value;
2034 return mathHelper._math(function(num) { return num.toFixed(fraction); }, null, n);
2037 functionRegistry.addMultiple(mathFunctions);
2039 },{"./function-registry":22,"./math-helper.js":24}],26:[function(require,module,exports){
2040 var Dimension = require("../tree/dimension"),
2041 Anonymous = require("../tree/anonymous"),
2042 functionRegistry = require("./function-registry"),
2043 mathHelper = require("./math-helper.js");
2045 var minMax = function (isMin, args) {
2046 args = Array.prototype.slice.call(args);
2047 switch(args.length) {
2048 case 0: throw { type: "Argument", message: "one or more arguments required" };
2050 var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone,
2051 order = [], // elems only contains original argument values.
2052 values = {}; // key is the unit.toString() for unified Dimension values,
2053 // value is the index into the order array.
2054 for (i = 0; i < args.length; i++) {
2056 if (!(current instanceof Dimension)) {
2057 if (Array.isArray(args[i].value)) {
2058 Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value));
2062 currentUnified = current.unit.toString() === "" && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify();
2063 unit = currentUnified.unit.toString() === "" && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString();
2064 unitStatic = unit !== "" && unitStatic === undefined || unit !== "" && order[0].unify().unit.toString() === "" ? unit : unitStatic;
2065 unitClone = unit !== "" && unitClone === undefined ? current.unit.toString() : unitClone;
2066 j = values[""] !== undefined && unit !== "" && unit === unitStatic ? values[""] : values[unit];
2067 if (j === undefined) {
2068 if (unitStatic !== undefined && unit !== unitStatic) {
2069 throw{ type: "Argument", message: "incompatible types" };
2071 values[unit] = order.length;
2072 order.push(current);
2075 referenceUnified = order[j].unit.toString() === "" && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify();
2076 if ( isMin && currentUnified.value < referenceUnified.value ||
2077 !isMin && currentUnified.value > referenceUnified.value) {
2081 if (order.length == 1) {
2084 args = order.map(function (a) { return a.toCSS(this.context); }).join(this.context.compress ? "," : ", ");
2085 return new Anonymous((isMin ? "min" : "max") + "(" + args + ")");
2087 functionRegistry.addMultiple({
2089 return minMax(true, arguments);
2092 return minMax(false, arguments);
2094 convert: function (val, unit) {
2095 return val.convertTo(unit.value);
2098 return new Dimension(Math.PI);
2100 mod: function(a, b) {
2101 return new Dimension(a.value % b.value, a.unit);
2103 pow: function(x, y) {
2104 if (typeof x === "number" && typeof y === "number") {
2105 x = new Dimension(x);
2106 y = new Dimension(y);
2107 } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) {
2108 throw { type: "Argument", message: "arguments must be numbers" };
2111 return new Dimension(Math.pow(x.value, y.value), x.unit);
2113 percentage: function (n) {
2114 var result = mathHelper._math(function(num) {
2122 },{"../tree/anonymous":46,"../tree/dimension":56,"./function-registry":22,"./math-helper.js":24}],27:[function(require,module,exports){
2123 var Quoted = require("../tree/quoted"),
2124 Anonymous = require("../tree/anonymous"),
2125 JavaScript = require("../tree/javascript"),
2126 functionRegistry = require("./function-registry");
2128 functionRegistry.addMultiple({
2130 return new Anonymous(str instanceof JavaScript ? str.evaluated : str.value);
2132 escape: function (str) {
2133 return new Anonymous(
2134 encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B")
2135 .replace(/\(/g, "%28").replace(/\)/g, "%29"));
2137 replace: function (string, pattern, replacement, flags) {
2138 var result = string.value;
2139 replacement = (replacement.type === "Quoted") ?
2140 replacement.value : replacement.toCSS();
2141 result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement);
2142 return new Quoted(string.quote || '', result, string.escaped);
2144 '%': function (string /* arg, arg, ...*/) {
2145 var args = Array.prototype.slice.call(arguments, 1),
2146 result = string.value;
2148 for (var i = 0; i < args.length; i++) {
2149 /*jshint loopfunc:true */
2150 result = result.replace(/%[sda]/i, function(token) {
2151 var value = ((args[i].type === "Quoted") &&
2152 token.match(/s/i)) ? args[i].value : args[i].toCSS();
2153 return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
2156 result = result.replace(/%%/g, '%');
2157 return new Quoted(string.quote || '', result, string.escaped);
2161 },{"../tree/anonymous":46,"../tree/javascript":63,"../tree/quoted":73,"./function-registry":22}],28:[function(require,module,exports){
2162 module.exports = function(environment) {
2163 var Dimension = require("../tree/dimension"),
2164 Color = require("../tree/color"),
2165 Expression = require("../tree/expression"),
2166 Quoted = require("../tree/quoted"),
2167 URL = require("../tree/url"),
2168 functionRegistry = require("./function-registry");
2170 functionRegistry.add("svg-gradient", function(direction) {
2173 gradientDirectionSvg,
2174 gradientType = "linear",
2175 rectangleDimension = 'x="0" y="0" width="1" height="1"',
2176 renderEnv = {compress: false},
2178 directionValue = direction.toCSS(renderEnv),
2179 i, color, position, positionValue, alpha;
2181 function throwArgumentDescriptor() {
2182 throw { type: "Argument",
2183 message: "svg-gradient expects direction, start_color [start_position], [color position,]...," +
2184 " end_color [end_position] or direction, color list" };
2187 if (arguments.length == 2) {
2188 if (arguments[1].value.length < 2) {
2189 throwArgumentDescriptor();
2191 stops = arguments[1].value;
2192 } else if (arguments.length < 3) {
2193 throwArgumentDescriptor();
2195 stops = Array.prototype.slice.call(arguments, 1);
2198 switch (directionValue) {
2200 gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
2203 gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
2205 case "to bottom right":
2206 gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
2208 case "to top right":
2209 gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
2212 case "ellipse at center":
2213 gradientType = "radial";
2214 gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
2215 rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
2218 throw { type: "Argument", message: "svg-gradient direction must be 'to bottom', 'to right'," +
2219 " 'to bottom right', 'to top right' or 'ellipse at center'" };
2221 returner = '<?xml version="1.0" ?>' +
2222 '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' +
2223 '<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>';
2225 for (i = 0; i < stops.length; i+= 1) {
2226 if (stops[i] instanceof Expression) {
2227 color = stops[i].value[0];
2228 position = stops[i].value[1];
2231 position = undefined;
2234 if (!(color instanceof Color) || (!((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension))) {
2235 throwArgumentDescriptor();
2237 positionValue = position ? position.toCSS(renderEnv) : i === 0 ? "0%" : "100%";
2238 alpha = color.alpha;
2239 returner += '<stop offset="' + positionValue + '" stop-color="' + color.toRGB() + '"' + (alpha < 1 ? ' stop-opacity="' + alpha + '"' : '') + '/>';
2241 returner += '</' + gradientType + 'Gradient>' +
2242 '<rect ' + rectangleDimension + ' fill="url(#gradient)" /></svg>';
2244 returner = encodeURIComponent(returner);
2246 returner = "data:image/svg+xml," + returner;
2247 return new URL(new Quoted("'" + returner + "'", returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
2251 },{"../tree/color":50,"../tree/dimension":56,"../tree/expression":59,"../tree/quoted":73,"../tree/url":80,"./function-registry":22}],29:[function(require,module,exports){
2252 var Keyword = require("../tree/keyword"),
2253 DetachedRuleset = require("../tree/detached-ruleset"),
2254 Dimension = require("../tree/dimension"),
2255 Color = require("../tree/color"),
2256 Quoted = require("../tree/quoted"),
2257 Anonymous = require("../tree/anonymous"),
2258 URL = require("../tree/url"),
2259 Operation = require("../tree/operation"),
2260 functionRegistry = require("./function-registry");
2262 var isa = function (n, Type) {
2263 return (n instanceof Type) ? Keyword.True : Keyword.False;
2265 isunit = function (n, unit) {
2266 if (unit === undefined) {
2267 throw { type: "Argument", message: "missing the required second argument to isunit." };
2269 unit = typeof unit.value === "string" ? unit.value : unit;
2270 if (typeof unit !== "string") {
2271 throw { type: "Argument", message: "Second argument to isunit should be a unit or a string." };
2273 return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False;
2275 getItemsFromNode = function(node) {
2276 // handle non-array values as an array of length 1
2277 // return 'undefined' if index is invalid
2278 var items = Array.isArray(node.value) ?
2279 node.value : Array(node);
2283 functionRegistry.addMultiple({
2284 isruleset: function (n) {
2285 return isa(n, DetachedRuleset);
2287 iscolor: function (n) {
2288 return isa(n, Color);
2290 isnumber: function (n) {
2291 return isa(n, Dimension);
2293 isstring: function (n) {
2294 return isa(n, Quoted);
2296 iskeyword: function (n) {
2297 return isa(n, Keyword);
2299 isurl: function (n) {
2302 ispixel: function (n) {
2303 return isunit(n, 'px');
2305 ispercentage: function (n) {
2306 return isunit(n, '%');
2308 isem: function (n) {
2309 return isunit(n, 'em');
2312 unit: function (val, unit) {
2313 if (!(val instanceof Dimension)) {
2314 throw { type: "Argument",
2315 message: "the first argument to unit must be a number" +
2316 (val instanceof Operation ? ". Have you forgotten parenthesis?" : "") };
2319 if (unit instanceof Keyword) {
2322 unit = unit.toCSS();
2327 return new Dimension(val.value, unit);
2329 "get-unit": function (n) {
2330 return new Anonymous(n.unit);
2332 extract: function(values, index) {
2333 index = index.value - 1; // (1-based index)
2335 return getItemsFromNode(values)[index];
2337 length: function(values) {
2338 return new Dimension(getItemsFromNode(values).length);
2342 },{"../tree/anonymous":46,"../tree/color":50,"../tree/detached-ruleset":55,"../tree/dimension":56,"../tree/keyword":65,"../tree/operation":71,"../tree/quoted":73,"../tree/url":80,"./function-registry":22}],30:[function(require,module,exports){
2343 var contexts = require("./contexts"),
2344 Parser = require('./parser/parser'),
2345 FunctionImporter = require('./plugins/function-importer');
2347 module.exports = function(environment) {
2350 // 'relativeUrls' - option - whether to adjust URL's to be relative
2351 // 'filename' - full resolved filename of current file
2352 // 'rootpath' - path to append to normal URLs for this node
2353 // 'currentDirectory' - path to the current file, absolute
2354 // 'rootFilename' - filename of the base file
2355 // 'entryPath' - absolute path to the entry file
2356 // 'reference' - whether the file should not be output and only output parts that are referenced
2358 var ImportManager = function(context, rootFileInfo) {
2359 this.rootFilename = rootFileInfo.filename;
2360 this.paths = context.paths || []; // Search paths, when importing
2361 this.contents = {}; // map - filename to contents of all the files
2362 this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore
2363 this.mime = context.mime;
2365 this.context = context;
2366 // Deprecated? Unused outside of here, could be useful.
2367 this.queue = []; // Files which haven't been imported yet
2368 this.files = {}; // Holds the imported parse trees.
2371 * Add an import to be imported
2372 * @param path - the raw path
2373 * @param tryAppendLessExtension - whether to try appending the less extension (if the path has no extension)
2374 * @param currentFileInfo - the current file info (used for instance to work out relative paths)
2375 * @param importOptions - import options
2376 * @param callback - callback for when it is imported
2378 ImportManager.prototype.push = function (path, tryAppendLessExtension, currentFileInfo, importOptions, callback) {
2379 var importManager = this;
2380 this.queue.push(path);
2382 var fileParsedFunc = function (e, root, fullPath) {
2383 importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue
2385 var importedEqualsRoot = fullPath === importManager.rootFilename;
2386 if (importOptions.optional && e) {
2387 callback(null, {rules:[]}, false, null);
2390 importManager.files[fullPath] = root;
2391 if (e && !importManager.error) { importManager.error = e; }
2392 callback(e, root, importedEqualsRoot, fullPath);
2397 relativeUrls: this.context.relativeUrls,
2398 entryPath: currentFileInfo.entryPath,
2399 rootpath: currentFileInfo.rootpath,
2400 rootFilename: currentFileInfo.rootFilename
2403 var fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment);
2406 fileParsedFunc({ message: "Could not find a file-manager for " + path });
2410 if (tryAppendLessExtension) {
2411 path = fileManager.tryAppendExtension(path, importOptions.plugin ? ".js" : ".less");
2414 var loadFileCallback = function(loadedFile) {
2415 var resolvedFilename = loadedFile.filename,
2416 contents = loadedFile.contents.replace(/^\uFEFF/, '');
2418 // Pass on an updated rootpath if path of imported file is relative and file
2419 // is in a (sub|sup) directory
2422 // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/',
2423 // then rootpath should become 'less/module/nav/'
2424 // - If path of imported file is '../mixins.less' and rootpath is 'less/',
2425 // then rootpath should become 'less/../'
2426 newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename);
2427 if (newFileInfo.relativeUrls) {
2428 newFileInfo.rootpath = fileManager.join(
2429 (importManager.context.rootpath || ""),
2430 fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath));
2432 if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) {
2433 newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath);
2436 newFileInfo.filename = resolvedFilename;
2438 var newEnv = new contexts.Parse(importManager.context);
2440 newEnv.processImports = false;
2441 importManager.contents[resolvedFilename] = contents;
2443 if (currentFileInfo.reference || importOptions.reference) {
2444 newFileInfo.reference = true;
2447 if (importOptions.plugin) {
2448 new FunctionImporter(newEnv, newFileInfo).eval(contents, function (e, root) {
2449 fileParsedFunc(e, root, resolvedFilename);
2451 } else if (importOptions.inline) {
2452 fileParsedFunc(null, contents, resolvedFilename);
2454 new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) {
2455 fileParsedFunc(e, root, resolvedFilename);
2460 var promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, this.context, environment,
2461 function(err, loadedFile) {
2463 fileParsedFunc(err);
2465 loadFileCallback(loadedFile);
2469 promise.then(loadFileCallback, fileParsedFunc);
2472 return ImportManager;
2475 },{"./contexts":11,"./parser/parser":38,"./plugins/function-importer":40}],31:[function(require,module,exports){
2476 module.exports = function(environment, fileManagers) {
2477 var SourceMapOutput, SourceMapBuilder, ParseTree, ImportManager, Environment;
2481 data: require('./data'),
2482 tree: require('./tree'),
2483 Environment: (Environment = require("./environment/environment")),
2484 AbstractFileManager: require("./environment/abstract-file-manager"),
2485 environment: (environment = new Environment(environment, fileManagers)),
2486 visitors: require('./visitors'),
2487 Parser: require('./parser/parser'),
2488 functions: require('./functions')(environment),
2489 contexts: require("./contexts"),
2490 SourceMapOutput: (SourceMapOutput = require('./source-map-output')(environment)),
2491 SourceMapBuilder: (SourceMapBuilder = require('./source-map-builder')(SourceMapOutput, environment)),
2492 ParseTree: (ParseTree = require('./parse-tree')(SourceMapBuilder)),
2493 ImportManager: (ImportManager = require('./import-manager')(environment)),
2494 render: require("./render")(environment, ParseTree, ImportManager),
2495 parse: require("./parse")(environment, ParseTree, ImportManager),
2496 LessError: require('./less-error'),
2497 transformTree: require('./transform-tree'),
2498 utils: require('./utils'),
2499 PluginManager: require('./plugin-manager'),
2500 logger: require('./logger')
2506 },{"./contexts":11,"./data":13,"./environment/abstract-file-manager":15,"./environment/environment":16,"./functions":23,"./import-manager":30,"./less-error":32,"./logger":33,"./parse":35,"./parse-tree":34,"./parser/parser":38,"./plugin-manager":39,"./render":41,"./source-map-builder":42,"./source-map-output":43,"./transform-tree":44,"./tree":62,"./utils":83,"./visitors":87}],32:[function(require,module,exports){
2507 var utils = require("./utils");
2509 var LessError = module.exports = function LessError(e, importManager, currentFilename) {
2513 var filename = e.filename || currentFilename;
2515 if (importManager && filename) {
2516 var input = importManager.contents[filename],
2517 loc = utils.getLocation(e.index, input),
2520 callLine = e.call && utils.getLocation(e.call, input).line,
2521 lines = input.split('\n');
2523 this.type = e.type || 'Syntax';
2524 this.filename = filename;
2525 this.index = e.index;
2526 this.line = typeof line === 'number' ? line + 1 : null;
2527 this.callLine = callLine + 1;
2528 this.callExtract = lines[callLine];
2536 this.message = e.message;
2537 this.stack = e.stack;
2540 if (typeof Object.create === 'undefined') {
2541 var F = function () {};
2542 F.prototype = Error.prototype;
2543 LessError.prototype = new F();
2545 LessError.prototype = Object.create(Error.prototype);
2548 LessError.prototype.constructor = LessError;
2550 },{"./utils":83}],33:[function(require,module,exports){
2552 error: function(msg) {
2553 this._fireEvent("error", msg);
2555 warn: function(msg) {
2556 this._fireEvent("warn", msg);
2558 info: function(msg) {
2559 this._fireEvent("info", msg);
2561 debug: function(msg) {
2562 this._fireEvent("debug", msg);
2564 addListener: function(listener) {
2565 this._listeners.push(listener);
2567 removeListener: function(listener) {
2568 for (var i = 0; i < this._listeners.length; i++) {
2569 if (this._listeners[i] === listener) {
2570 this._listeners.splice(i, 1);
2575 _fireEvent: function(type, msg) {
2576 for (var i = 0; i < this._listeners.length; i++) {
2577 var logFunction = this._listeners[i][type];
2586 },{}],34:[function(require,module,exports){
2587 var LessError = require('./less-error'),
2588 transformTree = require("./transform-tree"),
2589 logger = require("./logger");
2591 module.exports = function(SourceMapBuilder) {
2592 var ParseTree = function(root, imports) {
2594 this.imports = imports;
2597 ParseTree.prototype.toCSS = function(options) {
2598 var evaldRoot, result = {}, sourceMapBuilder;
2600 evaldRoot = transformTree(this.root, options);
2602 throw new LessError(e, this.imports);
2606 var compress = Boolean(options.compress);
2608 logger.warn("The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.");
2611 var toCSSOptions = {
2613 dumpLineNumbers: options.dumpLineNumbers,
2614 strictUnits: Boolean(options.strictUnits),
2617 if (options.sourceMap) {
2618 sourceMapBuilder = new SourceMapBuilder(options.sourceMap);
2619 result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports);
2621 result.css = evaldRoot.toCSS(toCSSOptions);
2624 throw new LessError(e, this.imports);
2627 if (options.pluginManager) {
2628 var postProcessors = options.pluginManager.getPostProcessors();
2629 for (var i = 0; i < postProcessors.length; i++) {
2630 result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options: options, imports: this.imports });
2633 if (options.sourceMap) {
2634 result.map = sourceMapBuilder.getExternalSourceMap();
2637 result.imports = [];
2638 for (var file in this.imports.files) {
2639 if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) {
2640 result.imports.push(file);
2648 },{"./less-error":32,"./logger":33,"./transform-tree":44}],35:[function(require,module,exports){
2649 var PromiseConstructor,
2650 contexts = require("./contexts"),
2651 Parser = require('./parser/parser'),
2652 PluginManager = require('./plugin-manager');
2654 module.exports = function(environment, ParseTree, ImportManager) {
2655 var parse = function (input, options, callback) {
2656 options = options || {};
2658 if (typeof options === 'function') {
2664 if (!PromiseConstructor) {
2665 PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
2668 return new PromiseConstructor(function (resolve, reject) {
2669 parse.call(self, input, options, function(err, output) {
2680 pluginManager = new PluginManager(this);
2682 pluginManager.addPlugins(options.plugins);
2683 options.pluginManager = pluginManager;
2685 context = new contexts.Parse(options);
2687 if (options.rootFileInfo) {
2688 rootFileInfo = options.rootFileInfo;
2690 var filename = options.filename || "input";
2691 var entryPath = filename.replace(/[^\/\\]*$/, "");
2694 relativeUrls: context.relativeUrls,
2695 rootpath: context.rootpath || "",
2696 currentDirectory: entryPath,
2697 entryPath: entryPath,
2698 rootFilename: filename
2700 // add in a missing trailing slash
2701 if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== "/") {
2702 rootFileInfo.rootpath += "/";
2706 var imports = new ImportManager(context, rootFileInfo);
2708 new Parser(context, imports, rootFileInfo)
2709 .parse(input, function (e, root) {
2710 if (e) { return callback(e); }
2711 callback(null, root, imports, options);
2718 },{"./contexts":11,"./parser/parser":38,"./plugin-manager":39,"promise":undefined}],36:[function(require,module,exports){
2719 // Split the input into chunks.
2720 module.exports = function (input, fail) {
2721 var len = input.length, level = 0, parenLevel = 0,
2722 lastOpening, lastOpeningParen, lastMultiComment, lastMultiCommentEndBrace,
2723 chunks = [], emitFrom = 0,
2724 chunkerCurrentIndex, currentChunkStartIndex, cc, cc2, matched;
2726 function emitChunk(force) {
2727 var len = chunkerCurrentIndex - emitFrom;
2728 if (((len < 512) && !force) || !len) {
2731 chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1));
2732 emitFrom = chunkerCurrentIndex + 1;
2735 for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
2736 cc = input.charCodeAt(chunkerCurrentIndex);
2737 if (((cc >= 97) && (cc <= 122)) || (cc < 34)) {
2738 // a-z or whitespace
2745 lastOpeningParen = chunkerCurrentIndex;
2748 if (--parenLevel < 0) {
2749 return fail("missing opening `(`", chunkerCurrentIndex);
2753 if (!parenLevel) { emitChunk(); }
2757 lastOpening = chunkerCurrentIndex;
2761 return fail("missing opening `{`", chunkerCurrentIndex);
2763 if (!level && !parenLevel) { emitChunk(); }
2766 if (chunkerCurrentIndex < len - 1) { chunkerCurrentIndex++; continue; }
2767 return fail("unescaped `\\`", chunkerCurrentIndex);
2770 case 96: // ", ' and `
2772 currentChunkStartIndex = chunkerCurrentIndex;
2773 for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
2774 cc2 = input.charCodeAt(chunkerCurrentIndex);
2775 if (cc2 > 96) { continue; }
2776 if (cc2 == cc) { matched = 1; break; }
2777 if (cc2 == 92) { // \
2778 if (chunkerCurrentIndex == len - 1) {
2779 return fail("unescaped `\\`", chunkerCurrentIndex);
2781 chunkerCurrentIndex++;
2784 if (matched) { continue; }
2785 return fail("unmatched `" + String.fromCharCode(cc) + "`", currentChunkStartIndex);
2786 case 47: // /, check for comment
2787 if (parenLevel || (chunkerCurrentIndex == len - 1)) { continue; }
2788 cc2 = input.charCodeAt(chunkerCurrentIndex + 1);
2791 for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
2792 cc2 = input.charCodeAt(chunkerCurrentIndex);
2793 if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { break; }
2795 } else if (cc2 == 42) {
2797 lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex;
2798 for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) {
2799 cc2 = input.charCodeAt(chunkerCurrentIndex);
2800 if (cc2 == 125) { lastMultiCommentEndBrace = chunkerCurrentIndex; }
2801 if (cc2 != 42) { continue; }
2802 if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { break; }
2804 if (chunkerCurrentIndex == len - 1) {
2805 return fail("missing closing `*/`", currentChunkStartIndex);
2807 chunkerCurrentIndex++;
2810 case 42: // *, check for unmatched */
2811 if ((chunkerCurrentIndex < len - 1) && (input.charCodeAt(chunkerCurrentIndex + 1) == 47)) {
2812 return fail("unmatched `/*`", chunkerCurrentIndex);
2819 if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {
2820 return fail("missing closing `}` or `*/`", lastOpening);
2822 return fail("missing closing `}`", lastOpening);
2824 } else if (parenLevel !== 0) {
2825 return fail("missing closing `)`", lastOpeningParen);
2832 },{}],37:[function(require,module,exports){
2833 var chunker = require('./chunker');
2835 module.exports = function() {
2836 var input, // LeSS input string
2838 saveStack = [], // holds state for backtracking
2839 furthest, // furthest index the parser has gone to
2840 furthestPossibleErrorMessage,// if this is furthest we got to, this is the probably cause
2841 chunks, // chunkified input
2842 current, // current chunk
2843 currentPos, // index of current chunk, in `input`
2846 var CHARCODE_SPACE = 32,
2851 CHARCODE_COMMA = 44,
2852 CHARCODE_FORWARD_SLASH = 47,
2855 function skipWhitespace(length) {
2856 var oldi = parserInput.i, oldj = j,
2857 curr = parserInput.i - currentPos,
2858 endIndex = parserInput.i + current.length - curr,
2859 mem = (parserInput.i += length),
2861 c, nextChar, comment;
2863 for (; parserInput.i < endIndex; parserInput.i++) {
2864 c = inp.charCodeAt(parserInput.i);
2866 if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) {
2867 nextChar = inp.charAt(parserInput.i + 1);
2868 if (nextChar === '/') {
2869 comment = {index: parserInput.i, isLineComment: true};
2870 var nextNewLine = inp.indexOf("\n", parserInput.i + 2);
2871 if (nextNewLine < 0) {
2872 nextNewLine = endIndex;
2874 parserInput.i = nextNewLine;
2875 comment.text = inp.substr(comment.index, parserInput.i - comment.index);
2876 parserInput.commentStore.push(comment);
2878 } else if (nextChar === '*') {
2879 var nextStarSlash = inp.indexOf("*/", parserInput.i + 2);
2880 if (nextStarSlash >= 0) {
2882 index: parserInput.i,
2883 text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i),
2884 isLineComment: false
2886 parserInput.i += comment.text.length - 1;
2887 parserInput.commentStore.push(comment);
2894 if ((c !== CHARCODE_SPACE) && (c !== CHARCODE_LF) && (c !== CHARCODE_TAB) && (c !== CHARCODE_CR)) {
2899 current = current.slice(length + parserInput.i - mem + curr);
2900 currentPos = parserInput.i;
2902 if (!current.length) {
2903 if (j < chunks.length - 1) {
2904 current = chunks[++j];
2905 skipWhitespace(0); // skip space at the beginning of a chunk
2906 return true; // things changed
2908 parserInput.finished = true;
2911 return oldi !== parserInput.i || oldj !== j;
2914 parserInput.save = function() {
2915 currentPos = parserInput.i;
2916 saveStack.push( { current: current, i: parserInput.i, j: j });
2918 parserInput.restore = function(possibleErrorMessage) {
2920 if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) {
2921 furthest = parserInput.i;
2922 furthestPossibleErrorMessage = possibleErrorMessage;
2924 var state = saveStack.pop();
2925 current = state.current;
2926 currentPos = parserInput.i = state.i;
2929 parserInput.forget = function() {
2932 parserInput.isWhitespace = function (offset) {
2933 var pos = parserInput.i + (offset || 0),
2934 code = input.charCodeAt(pos);
2935 return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF);
2938 // Specialization of $(tok)
2939 parserInput.$re = function(tok) {
2940 if (parserInput.i > currentPos) {
2941 current = current.slice(parserInput.i - currentPos);
2942 currentPos = parserInput.i;
2945 var m = tok.exec(current);
2950 skipWhitespace(m[0].length);
2951 if (typeof m === "string") {
2955 return m.length === 1 ? m[0] : m;
2958 parserInput.$char = function(tok) {
2959 if (input.charAt(parserInput.i) !== tok) {
2966 parserInput.$str = function(tok) {
2967 var tokLength = tok.length;
2969 // https://jsperf.com/string-startswith/21
2970 for (var i = 0; i < tokLength; i++) {
2971 if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {
2976 skipWhitespace(tokLength);
2980 parserInput.$quoted = function() {
2982 var startChar = input.charAt(parserInput.i);
2983 if (startChar !== "'" && startChar !== '"') {
2986 var length = input.length,
2987 currentPosition = parserInput.i;
2989 for (var i = 1; i + currentPosition < length; i++) {
2990 var nextChar = input.charAt(i + currentPosition);
2999 var str = input.substr(currentPosition, i + 1);
3000 skipWhitespace(i + 1);
3008 parserInput.autoCommentAbsorb = true;
3009 parserInput.commentStore = [];
3010 parserInput.finished = false;
3012 // Same as $(), but don't change the state of the parser,
3013 // just return the match.
3014 parserInput.peek = function(tok) {
3015 if (typeof tok === 'string') {
3016 // https://jsperf.com/string-startswith/21
3017 for (var i = 0; i < tok.length; i++) {
3018 if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {
3024 return tok.test(current);
3028 // Specialization of peek()
3029 // TODO remove or change some currentChar calls to peekChar
3030 parserInput.peekChar = function(tok) {
3031 return input.charAt(parserInput.i) === tok;
3034 parserInput.currentChar = function() {
3035 return input.charAt(parserInput.i);
3038 parserInput.getInput = function() {
3042 parserInput.peekNotNumeric = function() {
3043 var c = input.charCodeAt(parserInput.i);
3044 //Is the first char of the dimension 0-9, '.', '+' or '-'
3045 return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA;
3048 parserInput.start = function(str, chunkInput, failFunction) {
3050 parserInput.i = j = currentPos = furthest = 0;
3052 // chunking apparently makes things quicker (but my tests indicate
3053 // it might actually make things slower in node at least)
3054 // and it is a non-perfect parse - it can't recognise
3055 // unquoted urls, meaning it can't distinguish comments
3056 // meaning comments with quotes or {}() in them get 'counted'
3057 // and then lead to parse errors.
3058 // In addition if the chunking chunks in the wrong place we might
3059 // not be able to parse a parser statement in one go
3060 // this is officially deprecated but can be switched on via an option
3061 // in the case it causes too much performance issues.
3063 chunks = chunker(str, failFunction);
3068 current = chunks[0];
3073 parserInput.end = function() {
3075 isFinished = parserInput.i >= input.length;
3077 if (parserInput.i < furthest) {
3078 message = furthestPossibleErrorMessage;
3079 parserInput.i = furthest;
3082 isFinished: isFinished,
3083 furthest: parserInput.i,
3084 furthestPossibleErrorMessage: message,
3085 furthestReachedEnd: parserInput.i >= input.length - 1,
3086 furthestChar: input[parserInput.i]
3093 },{"./chunker":36}],38:[function(require,module,exports){
3094 var LessError = require('../less-error'),
3095 tree = require("../tree"),
3096 visitors = require("../visitors"),
3097 getParserInput = require("./parser-input"),
3098 utils = require("../utils");
3103 // A relatively straight-forward predictive parser.
3104 // There is no tokenization/lexing stage, the input is parsed
3107 // To make the parser fast enough to run in the browser, several
3108 // optimization had to be made:
3110 // - Matching and slicing on a huge input is often cause of slowdowns.
3111 // The solution is to chunkify the input into smaller strings.
3112 // The chunks are stored in the `chunks` var,
3113 // `j` holds the current chunk index, and `currentPos` holds
3114 // the index of the current chunk in relation to `input`.
3115 // This gives us an almost 4x speed-up.
3117 // - In many cases, we don't need to match individual tokens;
3118 // for example, if a value doesn't hold any variables, operations
3119 // or dynamic references, the parser can effectively 'skip' it,
3120 // treating it as a literal.
3121 // An example would be '1px solid #000' - which evaluates to itself,
3122 // we don't need to know what the individual components are.
3123 // The drawback, of course is that you don't get the benefits of
3124 // syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
3125 // and a smaller speed-up in the code-gen.
3128 // Token matching is done with the `$` function, which either takes
3129 // a terminal string or regexp, or a non-terminal function to call.
3130 // It also takes care of moving all the indices forwards.
3133 var Parser = function Parser(context, imports, fileInfo) {
3135 parserInput = getParserInput();
3137 function error(msg, type) {
3138 throw new LessError(
3140 index: parserInput.i,
3141 filename: fileInfo.filename,
3142 type: type || 'Syntax',
3149 function expect(arg, msg, index) {
3150 // some older browsers return typeof 'function' for RegExp
3151 var result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg);
3155 error(msg || (typeof arg === 'string' ? "expected '" + arg + "' got '" + parserInput.currentChar() + "'"
3156 : "unexpected token"));
3159 // Specialization of expect()
3160 function expectChar(arg, msg) {
3161 if (parserInput.$char(arg)) {
3164 error(msg || "expected '" + arg + "' got '" + parserInput.currentChar() + "'");
3167 function getDebugInfo(index) {
3168 var filename = fileInfo.filename;
3171 lineNumber: utils.getLocation(index, parserInput.getInput()).line + 1,
3182 // Parse an input string into an abstract syntax tree,
3183 // @param str A string containing 'less' markup
3184 // @param callback call `callback` when done.
3185 // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply
3187 parse: function (str, callback, additionalData) {
3188 var root, error = null, globalVars, modifyVars, ignored, preText = "";
3190 globalVars = (additionalData && additionalData.globalVars) ? Parser.serializeVars(additionalData.globalVars) + '\n' : '';
3191 modifyVars = (additionalData && additionalData.modifyVars) ? '\n' + Parser.serializeVars(additionalData.modifyVars) : '';
3193 if (context.pluginManager) {
3194 var preProcessors = context.pluginManager.getPreProcessors();
3195 for (var i = 0; i < preProcessors.length; i++) {
3196 str = preProcessors[i].process(str, { context: context, imports: imports, fileInfo: fileInfo });
3200 if (globalVars || (additionalData && additionalData.banner)) {
3201 preText = ((additionalData && additionalData.banner) ? additionalData.banner : "") + globalVars;
3202 ignored = imports.contentsIgnoredChars;
3203 ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0;
3204 ignored[fileInfo.filename] += preText.length;
3207 str = str.replace(/\r\n?/g, '\n');
3208 // Remove potential UTF Byte Order Mark
3209 str = preText + str.replace(/^\uFEFF/, '') + modifyVars;
3210 imports.contents[fileInfo.filename] = str;
3212 // Start with the primary rule.
3213 // The whole syntax tree is held under a Ruleset node,
3214 // with the `root` property set to true, so no `{}` are
3215 // output. The callback is called when the input is parsed.
3217 parserInput.start(str, context.chunkInput, function fail(msg, index) {
3218 throw new LessError({
3222 filename: fileInfo.filename
3226 root = new(tree.Ruleset)(null, this.parsers.primary());
3228 root.firstRoot = true;
3230 return callback(new LessError(e, imports, fileInfo.filename));
3233 // If `i` is smaller than the `input.length - 1`,
3234 // it means the parser wasn't able to parse the whole
3235 // string, so we've got a parsing error.
3237 // We try to extract a \n delimited string,
3238 // showing the line where the parse error occurred.
3239 // We split it up into two parts (the part which parsed,
3240 // and the part which didn't), so we can color them differently.
3241 var endInfo = parserInput.end();
3242 if (!endInfo.isFinished) {
3244 var message = endInfo.furthestPossibleErrorMessage;
3247 message = "Unrecognised input";
3248 if (endInfo.furthestChar === '}') {
3249 message += ". Possibly missing opening '{'";
3250 } else if (endInfo.furthestChar === ')') {
3251 message += ". Possibly missing opening '('";
3252 } else if (endInfo.furthestReachedEnd) {
3253 message += ". Possibly missing something";
3257 error = new LessError({
3260 index: endInfo.furthest,
3261 filename: fileInfo.filename
3265 var finish = function (e) {
3266 e = error || e || imports.error;
3269 if (!(e instanceof LessError)) {
3270 e = new LessError(e, imports, fileInfo.filename);
3276 return callback(null, root);
3280 if (context.processImports !== false) {
3281 new visitors.ImportVisitor(imports, finish)
3289 // Here in, the parsing rules/functions
3291 // The basic structure of the syntax tree generated is as follows:
3293 // Ruleset -> Rule -> Value -> Expression -> Entity
3295 // Here's some Less code:
3299 // border: 1px solid #000;
3304 // And here's what the parse tree might look like:
3306 // Ruleset (Selector '.class', [
3307 // Rule ("color", Value ([Expression [Color #fff]]))
3308 // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
3309 // Rule ("width", Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]]))
3310 // Ruleset (Selector [Element '>', '.child'], [...])
3313 // In general, most rules will try to parse a token with the `$re()` function, and if the return
3314 // value is truly, will return a new node, of the relevant type. Sometimes, we need to check
3315 // first, before parsing, that's when we use `peek()`.
3317 parsers: parsers = {
3319 // The `primary` rule is the *entry* and *exit* point of the parser.
3320 // The rules here can appear at any level of the parse tree.
3322 // The recursive nature of the grammar is an interplay between the `block`
3323 // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
3324 // as represented by this simplified grammar:
3326 // primary → (ruleset | rule)+
3327 // ruleset → selector+ block
3328 // block → '{' primary '}'
3330 // Only at one point is the primary rule not called from the
3331 // block rule: at the root level.
3333 primary: function () {
3334 var mixin = this.mixin, root = [], node;
3338 node = this.comment();
3339 if (!node) { break; }
3342 // always process comments before deciding if finished
3343 if (parserInput.finished) {
3346 if (parserInput.peek('}')) {
3350 node = this.extendRule();
3352 root = root.concat(node);
3356 node = mixin.definition() || this.rule() || this.ruleset() ||
3357 mixin.call() || this.rulesetCall() || this.entities.call() || this.directive();
3361 var foundSemiColon = false;
3362 while (parserInput.$char(";")) {
3363 foundSemiColon = true;
3365 if (!foundSemiColon) {
3374 // comments are collected by the main parsing mechanism and then assigned to nodes
3375 // where the current structure allows it
3376 comment: function () {
3377 if (parserInput.commentStore.length) {
3378 var comment = parserInput.commentStore.shift();
3379 return new(tree.Comment)(comment.text, comment.isLineComment, comment.index, fileInfo);
3384 // Entities are tokens which can be found inside an Expression
3388 // A string, which supports escaping " and '
3390 // "milky way" 'he\'s the one!'
3392 quoted: function () {
3393 var str, index = parserInput.i, isEscaped = false;
3396 if (parserInput.$char("~")) {
3399 str = parserInput.$quoted();
3401 parserInput.restore();
3404 parserInput.forget();
3406 return new(tree.Quoted)(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo);
3410 // A catch-all word, such as:
3412 // black border-collapse
3414 keyword: function () {
3415 var k = parserInput.$char("%") || parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]*/);
3417 return tree.Color.fromKeyword(k) || new(tree.Keyword)(k);
3426 // We also try to catch IE's `alpha()`, but let the `alpha` parser
3427 // deal with the details.
3429 // The arguments are parsed with the `entities.arguments` parser.
3432 var name, nameLC, args, alpha, index = parserInput.i;
3434 // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
3435 if (parserInput.peek(/^url\(/i)) {
3441 name = parserInput.$re(/^([\w-]+|%|progid:[\w\.]+)\(/);
3442 if (!name) { parserInput.forget(); return; }
3445 nameLC = name.toLowerCase();
3447 if (nameLC === 'alpha') {
3448 alpha = parsers.alpha();
3450 parserInput.forget();
3455 args = this.arguments();
3457 if (! parserInput.$char(')')) {
3458 parserInput.restore("Could not parse call arguments or missing ')'");
3462 parserInput.forget();
3463 return new(tree.Call)(name, args, index, fileInfo);
3465 arguments: function () {
3466 var argsSemiColon = [], argsComma = [],
3468 isSemiColonSeparated, value, arg;
3474 arg = parsers.detachedRuleset() || this.assignment() || parsers.expression();
3482 if (arg.value && arg.value.length == 1) {
3483 value = arg.value[0];
3487 expressions.push(value);
3490 argsComma.push(value);
3492 if (parserInput.$char(',')) {
3496 if (parserInput.$char(';') || isSemiColonSeparated) {
3498 isSemiColonSeparated = true;
3500 if (expressions.length > 1) {
3501 value = new(tree.Value)(expressions);
3503 argsSemiColon.push(value);
3509 parserInput.forget();
3510 return isSemiColonSeparated ? argsSemiColon : argsComma;
3512 literal: function () {
3513 return this.dimension() ||
3516 this.unicodeDescriptor();
3519 // Assignments are argument entities for calls.
3520 // They are present in ie filter properties as shown below.
3522 // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
3525 assignment: function () {
3528 key = parserInput.$re(/^\w+(?=\s?=)/i);
3530 parserInput.restore();
3533 if (!parserInput.$char('=')) {
3534 parserInput.restore();
3537 value = parsers.entity();
3539 parserInput.forget();
3540 return new(tree.Assignment)(key, value);
3542 parserInput.restore();
3547 // Parse url() tokens
3549 // We use a specific rule for urls, because they don't really behave like
3550 // standard function calls. The difference is that the argument doesn't have
3551 // to be enclosed within a string, so it can't be parsed as an Expression.
3554 var value, index = parserInput.i;
3556 parserInput.autoCommentAbsorb = false;
3558 if (!parserInput.$str("url(")) {
3559 parserInput.autoCommentAbsorb = true;
3563 value = this.quoted() || this.variable() ||
3564 parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
3566 parserInput.autoCommentAbsorb = true;
3570 return new(tree.URL)((value.value != null || value instanceof tree.Variable) ?
3571 value : new(tree.Anonymous)(value), index, fileInfo);
3575 // A Variable entity, such as `@fink`, in
3577 // width: @fink + 2px
3579 // We use a different parser for variable definitions,
3580 // see `parsers.variable`.
3582 variable: function () {
3583 var name, index = parserInput.i;
3585 if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) {
3586 return new(tree.Variable)(name, index, fileInfo);
3590 // A variable entity using the protective {} e.g. @{var}
3591 variableCurly: function () {
3592 var curly, index = parserInput.i;
3594 if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) {
3595 return new(tree.Variable)("@" + curly[1], index, fileInfo);
3600 // A Hexadecimal color
3604 // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
3606 color: function () {
3609 if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
3610 // strip colons, brackets, whitespaces and other characters that should not
3611 // definitely be part of color string
3612 var colorCandidateString = rgb.input.match(/^#([\w]+).*/);
3613 colorCandidateString = colorCandidateString[1];
3614 if (!colorCandidateString.match(/^[A-Fa-f0-9]+$/)) { // verify if candidate consists only of allowed HEX characters
3615 error("Invalid HEX color code");
3617 return new(tree.Color)(rgb[1], undefined, '#' + colorCandidateString);
3621 colorKeyword: function () {
3623 var autoCommentAbsorb = parserInput.autoCommentAbsorb;
3624 parserInput.autoCommentAbsorb = false;
3625 var k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/);
3626 parserInput.autoCommentAbsorb = autoCommentAbsorb;
3628 parserInput.forget();
3631 parserInput.restore();
3632 var color = tree.Color.fromKeyword(k);
3634 parserInput.$str(k);
3640 // A Dimension, that is, a number and a unit
3644 dimension: function () {
3645 if (parserInput.peekNotNumeric()) {
3649 var value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i);
3651 return new(tree.Dimension)(value[1], value[2]);
3656 // A unicode descriptor, as is used in unicode-range
3658 // U+0?? or U+00A1-00A9
3660 unicodeDescriptor: function () {
3663 ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/);
3665 return new(tree.UnicodeDescriptor)(ud[0]);
3670 // JavaScript code to be evaluated
3672 // `window.location.href`
3674 javascript: function () {
3675 var js, index = parserInput.i;
3679 var escape = parserInput.$char("~");
3680 var jsQuote = parserInput.$char("`");
3683 parserInput.restore();
3687 js = parserInput.$re(/^[^`]*`/);
3689 parserInput.forget();
3690 return new(tree.JavaScript)(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo);
3692 parserInput.restore("invalid javascript definition");
3697 // The variable part of a variable definition. Used in the `rule` parser
3701 variable: function () {
3704 if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { return name[1]; }
3708 // The variable part of a variable definition. Used in the `rule` parser
3712 rulesetCall: function () {
3715 if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\(\s*\)\s*;/))) {
3716 return new tree.RulesetCall(name[1]);
3721 // extend syntax - used to extend selectors
3723 extend: function(isRule) {
3724 var elements, e, index = parserInput.i, option, extendList, extend;
3726 if (!parserInput.$str(isRule ? "&:extend(" : ":extend(")) {
3733 while (! (option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) {
3745 option = option && option[1];
3747 error("Missing target selector for :extend().");
3749 extend = new(tree.Extend)(new(tree.Selector)(elements), option, index, fileInfo);
3751 extendList.push(extend);
3753 extendList = [ extend ];
3755 } while (parserInput.$char(","));
3767 // extendRule - used in a rule to extend all the parent selectors
3769 extendRule: function() {
3770 return this.extend(true);
3778 // A Mixin call, with an optional argument list
3780 // #mixins > .square(#fff);
3781 // .rounded(4px, black);
3784 // The `while` loop is there because mixins can be
3785 // namespaced, but we only support the child and descendant
3786 // selector for now.
3789 var s = parserInput.currentChar(), important = false, index = parserInput.i, elemIndex,
3790 elements, elem, e, c, args;
3792 if (s !== '.' && s !== '#') { return; }
3794 parserInput.save(); // stop us absorbing part of an invalid selector
3797 elemIndex = parserInput.i;
3798 e = parserInput.$re(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/);
3802 elem = new(tree.Element)(c, e, elemIndex, fileInfo);
3804 elements.push(elem);
3806 elements = [ elem ];
3808 c = parserInput.$char('>');
3812 if (parserInput.$char('(')) {
3813 args = this.args(true).args;
3817 if (parsers.important()) {
3821 if (parsers.end()) {
3822 parserInput.forget();
3823 return new(tree.mixin.Call)(elements, args, index, fileInfo, important);
3827 parserInput.restore();
3829 args: function (isCall) {
3830 var entities = parsers.entities,
3831 returner = { args:null, variadic: false },
3832 expressions = [], argsSemiColon = [], argsComma = [],
3833 isSemiColonSeparated, expressionContainsNamed, name, nameLoop,
3840 arg = parsers.detachedRuleset() || parsers.expression();
3842 parserInput.commentStore.length = 0;
3843 if (parserInput.$str("...")) {
3844 returner.variadic = true;
3845 if (parserInput.$char(";") && !isSemiColonSeparated) {
3846 isSemiColonSeparated = true;
3848 (isSemiColonSeparated ? argsSemiColon : argsComma)
3849 .push({ variadic: true });
3852 arg = entities.variable() || entities.literal() || entities.keyword();
3860 if (arg.throwAwayComments) {
3861 arg.throwAwayComments();
3868 if (arg.value && arg.value.length == 1) {
3875 if (val && val instanceof tree.Variable) {
3876 if (parserInput.$char(':')) {
3877 if (expressions.length > 0) {
3878 if (isSemiColonSeparated) {
3879 error("Cannot mix ; and , as delimiter types");
3881 expressionContainsNamed = true;
3884 value = parsers.detachedRuleset() || parsers.expression();
3888 error("could not understand value for named argument");
3890 parserInput.restore();
3895 nameLoop = (name = val.name);
3896 } else if (parserInput.$str("...")) {
3898 returner.variadic = true;
3899 if (parserInput.$char(";") && !isSemiColonSeparated) {
3900 isSemiColonSeparated = true;
3902 (isSemiColonSeparated ? argsSemiColon : argsComma)
3903 .push({ name: arg.name, variadic: true });
3908 } else if (!isCall) {
3909 name = nameLoop = val.name;
3915 expressions.push(value);
3918 argsComma.push({ name:nameLoop, value:value, expand:expand });
3920 if (parserInput.$char(',')) {
3924 if (parserInput.$char(';') || isSemiColonSeparated) {
3926 if (expressionContainsNamed) {
3927 error("Cannot mix ; and , as delimiter types");
3930 isSemiColonSeparated = true;
3932 if (expressions.length > 1) {
3933 value = new(tree.Value)(expressions);
3935 argsSemiColon.push({ name:name, value:value, expand:expand });
3939 expressionContainsNamed = false;
3943 parserInput.forget();
3944 returner.args = isSemiColonSeparated ? argsSemiColon : argsComma;
3948 // A Mixin definition, with a list of parameters
3950 // .rounded (@radius: 2px, @color) {
3954 // Until we have a finer grained state-machine, we have to
3955 // do a look-ahead, to make sure we don't have a mixin call.
3956 // See the `rule` function for more information.
3958 // We start by matching `.rounded (`, and then proceed on to
3959 // the argument list, which has optional default values.
3960 // We store the parameters in `params`, with a `value` key,
3961 // if there is a value, such as in the case of `@radius`.
3963 // Once we've got our params list, and a closing `)`, we parse
3964 // the `{...}` block.
3966 definition: function () {
3967 var name, params = [], match, ruleset, cond, variadic = false;
3968 if ((parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#') ||
3969 parserInput.peek(/^[^{]*\}/)) {
3975 match = parserInput.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/);
3979 var argInfo = this.args(false);
3980 params = argInfo.args;
3981 variadic = argInfo.variadic;
3983 // .mixincall("@{a}");
3984 // looks a bit like a mixin definition..
3986 // .mixincall(@a: {rule: set;});
3987 // so we have to be nice and restore
3988 if (!parserInput.$char(')')) {
3989 parserInput.restore("Missing closing ')'");
3993 parserInput.commentStore.length = 0;
3995 if (parserInput.$str("when")) { // Guard
3996 cond = expect(parsers.conditions, 'expected condition');
3999 ruleset = parsers.block();
4002 parserInput.forget();
4003 return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
4005 parserInput.restore();
4008 parserInput.forget();
4014 // Entities are the smallest recognized token,
4015 // and can be found inside a rule's value.
4017 entity: function () {
4018 var entities = this.entities;
4020 return this.comment() || entities.literal() || entities.variable() || entities.url() ||
4021 entities.call() || entities.keyword() || entities.javascript();
4025 // A Rule terminator. Note that we use `peek()` to check for '}',
4026 // because the `block` rule will be expecting it, but we still need to make sure
4027 // it's there, if ';' was omitted.
4030 return parserInput.$char(';') || parserInput.peek('}');
4034 // IE's alpha function
4036 // alpha(opacity=88)
4038 alpha: function () {
4041 // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
4042 if (! parserInput.$re(/^opacity=/i)) { return; }
4043 value = parserInput.$re(/^\d+/);
4045 value = expect(this.entities.variable, "Could not parse alpha");
4048 return new(tree.Alpha)(value);
4052 // A Selector Element
4057 // input[type="text"]
4059 // Elements are the building blocks for Selectors,
4060 // they are made out of a `Combinator` (see combinator rule),
4061 // and an element name, such as a tag a class, or `*`.
4063 element: function () {
4064 var e, c, v, index = parserInput.i;
4066 c = this.combinator();
4068 e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) ||
4069 parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
4070 parserInput.$char('*') || parserInput.$char('&') || this.attribute() ||
4071 parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) ||
4072 this.entities.variableCurly();
4076 if (parserInput.$char('(')) {
4077 if ((v = this.selector()) && parserInput.$char(')')) {
4078 e = new(tree.Paren)(v);
4079 parserInput.forget();
4081 parserInput.restore("Missing closing ')'");
4084 parserInput.forget();
4088 if (e) { return new(tree.Element)(c, e, index, fileInfo); }
4092 // Combinators combine elements together, in a Selector.
4094 // Because our parser isn't white-space sensitive, special care
4095 // has to be taken, when parsing the descendant combinator, ` `,
4096 // as it's an empty space. We have to check the previous character
4097 // in the input, to see if it's a ` ` character. More info on how
4098 // we deal with this in *combinator.js*.
4100 combinator: function () {
4101 var c = parserInput.currentChar();
4105 var slashedCombinator = parserInput.$re(/^\/[a-z]+\//i);
4106 if (slashedCombinator) {
4107 parserInput.forget();
4108 return new(tree.Combinator)(slashedCombinator);
4110 parserInput.restore();
4113 if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') {
4115 if (c === '^' && parserInput.currentChar() === '^') {
4119 while (parserInput.isWhitespace()) { parserInput.i++; }
4120 return new(tree.Combinator)(c);
4121 } else if (parserInput.isWhitespace(-1)) {
4122 return new(tree.Combinator)(" ");
4124 return new(tree.Combinator)(null);
4128 // A CSS selector (see selector below)
4129 // with less extensions e.g. the ability to extend and guard
4131 lessSelector: function () {
4132 return this.selector(true);
4137 // .class > div + h1
4140 // Selectors are made out of one or more Elements, see above.
4142 selector: function (isLess) {
4143 var index = parserInput.i, elements, extendList, c, e, allExtends, when, condition;
4145 while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$str("when"))) || (e = this.element())) {
4147 condition = expect(this.conditions, 'expected condition');
4148 } else if (condition) {
4149 error("CSS guard can only be used at the end of selector");
4150 } else if (extendList) {
4152 allExtends = allExtends.concat(extendList);
4154 allExtends = extendList;
4157 if (allExtends) { error("Extend can only be used at the end of selector"); }
4158 c = parserInput.currentChar();
4166 if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {
4171 if (elements) { return new(tree.Selector)(elements, allExtends, condition, index, fileInfo); }
4172 if (allExtends) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
4174 attribute: function () {
4175 if (! parserInput.$char('[')) { return; }
4177 var entities = this.entities,
4180 if (!(key = entities.variableCurly())) {
4181 key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
4184 op = parserInput.$re(/^[|~*$^]?=/);
4186 val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly();
4191 return new(tree.Attribute)(key, op, val);
4195 // The `block` rule is used by `ruleset` and `mixin.definition`.
4196 // It's a wrapper around the `primary` rule, with added `{}`.
4198 block: function () {
4200 if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) {
4205 blockRuleset: function() {
4206 var block = this.block();
4209 block = new tree.Ruleset(null, block);
4214 detachedRuleset: function() {
4215 var blockRuleset = this.blockRuleset();
4217 return new tree.DetachedRuleset(blockRuleset);
4222 // div, .class, body > p {...}
4224 ruleset: function () {
4225 var selectors, s, rules, debugInfo;
4229 if (context.dumpLineNumbers) {
4230 debugInfo = getDebugInfo(parserInput.i);
4234 s = this.lessSelector();
4243 parserInput.commentStore.length = 0;
4244 if (s.condition && selectors.length > 1) {
4245 error("Guards are only currently allowed on a single selector.");
4247 if (! parserInput.$char(',')) { break; }
4249 error("Guards are only currently allowed on a single selector.");
4251 parserInput.commentStore.length = 0;
4254 if (selectors && (rules = this.block())) {
4255 parserInput.forget();
4256 var ruleset = new(tree.Ruleset)(selectors, rules, context.strictImports);
4257 if (context.dumpLineNumbers) {
4258 ruleset.debugInfo = debugInfo;
4262 parserInput.restore();
4265 rule: function (tryAnonymous) {
4266 var name, value, startOfRule = parserInput.i, c = parserInput.currentChar(), important, merge, isVariable;
4268 if (c === '.' || c === '#' || c === '&' || c === ':') { return; }
4272 name = this.variable() || this.ruleProperty();
4274 isVariable = typeof name === "string";
4277 value = this.detachedRuleset();
4280 parserInput.commentStore.length = 0;
4282 // a name returned by this.ruleProperty() is always an array of the form:
4283 // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"]
4284 // where each item is a tree.Keyword or tree.Variable
4285 merge = !isVariable && name.length > 1 && name.pop().value;
4287 // prefer to try to parse first if its a variable or we are compressing
4288 // but always fallback on the other one
4289 var tryValueFirst = !tryAnonymous && (context.compress || isVariable);
4291 if (tryValueFirst) {
4292 value = this.value();
4295 value = this.anonymousValue();
4297 parserInput.forget();
4298 // anonymous values absorb the end ';' which is required for them to work
4299 return new (tree.Rule)(name, value, false, merge, startOfRule, fileInfo);
4302 if (!tryValueFirst && !value) {
4303 value = this.value();
4306 important = this.important();
4309 if (value && this.end()) {
4310 parserInput.forget();
4311 return new (tree.Rule)(name, value, important, merge, startOfRule, fileInfo);
4313 parserInput.restore();
4314 if (value && !tryAnonymous) {
4315 return this.rule(true);
4319 parserInput.forget();
4322 anonymousValue: function () {
4323 var match = parserInput.$re(/^([^@+\/'"*`(;{}-]*);/);
4325 return new(tree.Anonymous)(match[1]);
4330 // An @import directive
4334 // Depending on our environment, importing is done differently:
4335 // In the browser, it's an XHR request, in Node, it would be a
4336 // file-system operation. The function used for importing is
4337 // stored in `import`, which we pass to the Import constructor.
4339 "import": function () {
4340 var path, features, index = parserInput.i;
4342 var dir = parserInput.$re(/^@import?\s+/);
4345 var options = (dir ? this.importOptions() : null) || {};
4347 if ((path = this.entities.quoted() || this.entities.url())) {
4348 features = this.mediaFeatures();
4350 if (!parserInput.$char(';')) {
4351 parserInput.i = index;
4352 error("missing semi-colon or unrecognised media features on import");
4354 features = features && new(tree.Value)(features);
4355 return new(tree.Import)(path, features, options, index, fileInfo);
4358 parserInput.i = index;
4359 error("malformed import statement");
4364 importOptions: function() {
4365 var o, options = {}, optionName, value;
4367 // list of options, surrounded by parens
4368 if (! parserInput.$char('(')) { return null; }
4370 o = this.importOption();
4374 switch(optionName) {
4376 optionName = "less";
4380 optionName = "multiple";
4384 options[optionName] = value;
4385 if (! parserInput.$char(',')) { break; }
4392 importOption: function() {
4393 var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/);
4399 mediaFeature: function () {
4400 var entities = this.entities, nodes = [], e, p;
4403 e = entities.keyword() || entities.variable();
4406 } else if (parserInput.$char('(')) {
4407 p = this.property();
4409 if (parserInput.$char(')')) {
4411 nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, null, parserInput.i, fileInfo, true)));
4413 nodes.push(new(tree.Paren)(e));
4415 error("badly formed media feature definition");
4418 error("Missing closing ')'", "Parse");
4423 parserInput.forget();
4424 if (nodes.length > 0) {
4425 return new(tree.Expression)(nodes);
4429 mediaFeatures: function () {
4430 var entities = this.entities, features = [], e;
4432 e = this.mediaFeature();
4435 if (! parserInput.$char(',')) { break; }
4437 e = entities.variable();
4440 if (! parserInput.$char(',')) { break; }
4445 return features.length > 0 ? features : null;
4448 media: function () {
4449 var features, rules, media, debugInfo, index = parserInput.i;
4451 if (context.dumpLineNumbers) {
4452 debugInfo = getDebugInfo(index);
4457 if (parserInput.$str("@media")) {
4458 features = this.mediaFeatures();
4460 rules = this.block();
4463 error("media definitions require block statements after any features");
4466 parserInput.forget();
4468 media = new(tree.Media)(rules, features, index, fileInfo);
4469 if (context.dumpLineNumbers) {
4470 media.debugInfo = debugInfo;
4476 parserInput.restore();
4480 // A @plugin directive, used to import compiler extensions dynamically.
4484 // Depending on our environment, importing is done differently:
4485 // In the browser, it's an XHR request, in Node, it would be a
4486 // file-system operation. The function used for importing is
4487 // stored in `import`, which we pass to the Import constructor.
4489 plugin: function () {
4491 index = parserInput.i,
4492 dir = parserInput.$re(/^@plugin?\s+/);
4495 var options = { plugin : true };
4497 if ((path = this.entities.quoted() || this.entities.url())) {
4499 if (!parserInput.$char(';')) {
4500 parserInput.i = index;
4501 error("missing semi-colon on plugin");
4504 return new(tree.Import)(path, null, options, index, fileInfo);
4507 parserInput.i = index;
4508 error("malformed plugin statement");
4516 // @charset "utf-8";
4518 directive: function () {
4519 var index = parserInput.i, name, value, rules, nonVendorSpecificName,
4520 hasIdentifier, hasExpression, hasUnknown, hasBlock = true, isRooted = true;
4522 if (parserInput.currentChar() !== '@') { return; }
4524 value = this['import']() || this.plugin() || this.media();
4531 name = parserInput.$re(/^@[a-z-]+/);
4533 if (!name) { return; }
4535 nonVendorSpecificName = name;
4536 if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
4537 nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1);
4540 switch(nonVendorSpecificName) {
4542 hasIdentifier = true;
4546 hasExpression = true;
4550 case "@counter-style":
4551 hasIdentifier = true;
4563 parserInput.commentStore.length = 0;
4565 if (hasIdentifier) {
4566 value = this.entity();
4568 error("expected " + name + " identifier");
4570 } else if (hasExpression) {
4571 value = this.expression();
4573 error("expected " + name + " expression");
4575 } else if (hasUnknown) {
4576 value = (parserInput.$re(/^[^{;]+/) || '').trim();
4577 hasBlock = (parserInput.currentChar() == '{');
4579 value = new(tree.Anonymous)(value);
4584 rules = this.blockRuleset();
4587 if (rules || (!hasBlock && value && parserInput.$char(';'))) {
4588 parserInput.forget();
4589 return new (tree.Directive)(name, value, rules, index, fileInfo,
4590 context.dumpLineNumbers ? getDebugInfo(index) : null,
4595 parserInput.restore("directive options not recognised");
4599 // A Value is a comma-delimited list of Expressions
4601 // font-family: Baskerville, Georgia, serif;
4603 // In a Rule, a Value represents everything after the `:`,
4604 // and before the `;`.
4606 value: function () {
4607 var e, expressions = [];
4610 e = this.expression();
4612 expressions.push(e);
4613 if (! parserInput.$char(',')) { break; }
4617 if (expressions.length > 0) {
4618 return new(tree.Value)(expressions);
4621 important: function () {
4622 if (parserInput.currentChar() === '!') {
4623 return parserInput.$re(/^! *important/);
4630 if (parserInput.$char('(')) {
4631 a = this.addition();
4632 if (a && parserInput.$char(')')) {
4633 parserInput.forget();
4634 e = new(tree.Expression)([a]);
4638 parserInput.restore("Expected ')'");
4641 parserInput.restore();
4643 multiplication: function () {
4644 var m, a, op, operation, isSpaced;
4647 isSpaced = parserInput.isWhitespace(-1);
4649 if (parserInput.peek(/^\/[*\/]/)) {
4655 op = parserInput.$char('/') || parserInput.$char('*');
4657 if (!op) { parserInput.forget(); break; }
4661 if (!a) { parserInput.restore(); break; }
4662 parserInput.forget();
4664 m.parensInOp = true;
4665 a.parensInOp = true;
4666 operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
4667 isSpaced = parserInput.isWhitespace(-1);
4669 return operation || m;
4672 addition: function () {
4673 var m, a, op, operation, isSpaced;
4674 m = this.multiplication();
4676 isSpaced = parserInput.isWhitespace(-1);
4678 op = parserInput.$re(/^[-+]\s+/) || (!isSpaced && (parserInput.$char('+') || parserInput.$char('-')));
4682 a = this.multiplication();
4687 m.parensInOp = true;
4688 a.parensInOp = true;
4689 operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
4690 isSpaced = parserInput.isWhitespace(-1);
4692 return operation || m;
4695 conditions: function () {
4696 var a, b, index = parserInput.i, condition;
4698 a = this.condition();
4701 if (!parserInput.peek(/^,\s*(not\s*)?\(/) || !parserInput.$char(',')) {
4704 b = this.condition();
4708 condition = new(tree.Condition)('or', condition || a, b, index);
4710 return condition || a;
4713 condition: function () {
4714 var result, logical, next;
4716 return parserInput.$str("or");
4719 result = this.conditionAnd(this);
4725 next = this.condition();
4727 result = new(tree.Condition)(logical, result, next);
4734 conditionAnd: function () {
4735 var result, logical, next;
4736 function insideCondition(me) {
4737 return me.negatedCondition() || me.parenthesisCondition();
4740 return parserInput.$str("and");
4743 result = insideCondition(this);
4749 next = this.conditionAnd();
4751 result = new(tree.Condition)(logical, result, next);
4758 negatedCondition: function () {
4759 if (parserInput.$str("not")) {
4760 var result = this.parenthesisCondition();
4762 result.negate = !result.negate;
4767 parenthesisCondition: function () {
4768 function tryConditionFollowedByParenthesis(me) {
4771 body = me.condition();
4773 parserInput.restore();
4776 if (!parserInput.$char(')')) {
4777 parserInput.restore();
4780 parserInput.forget();
4786 if (!parserInput.$str("(")) {
4787 parserInput.restore();
4790 body = tryConditionFollowedByParenthesis(this);
4792 parserInput.forget();
4796 body = this.atomicCondition();
4798 parserInput.restore();
4801 if (!parserInput.$char(')')) {
4802 parserInput.restore("expected ')' got '" + parserInput.currentChar() + "'");
4805 parserInput.forget();
4808 atomicCondition: function () {
4809 var entities = this.entities, index = parserInput.i, a, b, c, op;
4811 a = this.addition() || entities.keyword() || entities.quoted();
4813 if (parserInput.$char('>')) {
4814 if (parserInput.$char('=')) {
4820 if (parserInput.$char('<')) {
4821 if (parserInput.$char('=')) {
4827 if (parserInput.$char('=')) {
4828 if (parserInput.$char('>')) {
4830 } else if (parserInput.$char('<')) {
4837 b = this.addition() || entities.keyword() || entities.quoted();
4839 c = new(tree.Condition)(op, a, b, index, false);
4841 error('expected expression');
4844 c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, false);
4851 // An operand is anything that can be part of an operation,
4852 // such as a Color, or a Variable
4854 operand: function () {
4855 var entities = this.entities, negate;
4857 if (parserInput.peek(/^-[@\(]/)) {
4858 negate = parserInput.$char('-');
4861 var o = this.sub() || entities.dimension() ||
4862 entities.color() || entities.variable() ||
4863 entities.call() || entities.colorKeyword();
4866 o.parensInOp = true;
4867 o = new(tree.Negative)(o);
4874 // Expressions either represent mathematical operations,
4875 // or white-space delimited Entities.
4880 expression: function () {
4881 var entities = [], e, delim;
4889 e = this.addition() || this.entity();
4892 // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
4893 if (!parserInput.peek(/^\/[\/*]/)) {
4894 delim = parserInput.$char('/');
4896 entities.push(new(tree.Anonymous)(delim));
4901 if (entities.length > 0) {
4902 return new(tree.Expression)(entities);
4905 property: function () {
4906 var name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/);
4911 ruleProperty: function () {
4912 var name = [], index = [], s, k;
4916 var simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/);
4917 if (simpleProperty) {
4918 name = [new(tree.Keyword)(simpleProperty[1])];
4919 parserInput.forget();
4923 function match(re) {
4924 var i = parserInput.i,
4925 chunk = parserInput.$re(re);
4928 return name.push(chunk[1]);
4934 if (!match(/^((?:[\w-]+)|(?:@\{[\w-]+\}))/)) {
4939 if ((name.length > 1) && match(/^((?:\+_|\+)?)\s*:/)) {
4940 parserInput.forget();
4942 // at last, we have the complete match now. move forward,
4943 // convert name particles to tree objects and return:
4944 if (name[0] === '') {
4948 for (k = 0; k < name.length; k++) {
4950 name[k] = (s.charAt(0) !== '@') ?
4951 new(tree.Keyword)(s) :
4952 new(tree.Variable)('@' + s.slice(2, -1),
4953 index[k], fileInfo);
4957 parserInput.restore();
4962 Parser.serializeVars = function(vars) {
4965 for (var name in vars) {
4966 if (Object.hasOwnProperty.call(vars, name)) {
4967 var value = vars[name];
4968 s += ((name[0] === '@') ? '' : '@') + name + ': ' + value +
4969 ((String(value).slice(-1) === ';') ? '' : ';');
4976 module.exports = Parser;
4978 },{"../less-error":32,"../tree":62,"../utils":83,"../visitors":87,"./parser-input":37}],39:[function(require,module,exports){
4982 var PluginManager = function(less) {
4985 this.preProcessors = [];
4986 this.postProcessors = [];
4987 this.installedPlugins = [];
4988 this.fileManagers = [];
4991 * Adds all the plugins in the array
4992 * @param {Array} plugins
4994 PluginManager.prototype.addPlugins = function(plugins) {
4996 for (var i = 0; i < plugins.length; i++) {
4997 this.addPlugin(plugins[i]);
5005 PluginManager.prototype.addPlugin = function(plugin) {
5006 this.installedPlugins.push(plugin);
5007 plugin.install(this.less, this);
5010 * Adds a visitor. The visitor object has options on itself to determine
5011 * when it should run.
5014 PluginManager.prototype.addVisitor = function(visitor) {
5015 this.visitors.push(visitor);
5018 * Adds a pre processor object
5019 * @param {object} preProcessor
5020 * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import
5022 PluginManager.prototype.addPreProcessor = function(preProcessor, priority) {
5023 var indexToInsertAt;
5024 for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) {
5025 if (this.preProcessors[indexToInsertAt].priority >= priority) {
5029 this.preProcessors.splice(indexToInsertAt, 0, {preProcessor: preProcessor, priority: priority});
5032 * Adds a post processor object
5033 * @param {object} postProcessor
5034 * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression
5036 PluginManager.prototype.addPostProcessor = function(postProcessor, priority) {
5037 var indexToInsertAt;
5038 for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) {
5039 if (this.postProcessors[indexToInsertAt].priority >= priority) {
5043 this.postProcessors.splice(indexToInsertAt, 0, {postProcessor: postProcessor, priority: priority});
5049 PluginManager.prototype.addFileManager = function(manager) {
5050 this.fileManagers.push(manager);
5057 PluginManager.prototype.getPreProcessors = function() {
5058 var preProcessors = [];
5059 for (var i = 0; i < this.preProcessors.length; i++) {
5060 preProcessors.push(this.preProcessors[i].preProcessor);
5062 return preProcessors;
5069 PluginManager.prototype.getPostProcessors = function() {
5070 var postProcessors = [];
5071 for (var i = 0; i < this.postProcessors.length; i++) {
5072 postProcessors.push(this.postProcessors[i].postProcessor);
5074 return postProcessors;
5081 PluginManager.prototype.getVisitors = function() {
5082 return this.visitors;
5089 PluginManager.prototype.getFileManagers = function() {
5090 return this.fileManagers;
5092 module.exports = PluginManager;
5094 },{}],40:[function(require,module,exports){
5095 var LessError = require('../less-error'),
5096 tree = require("../tree");
5098 var FunctionImporter = module.exports = function FunctionImporter(context, fileInfo) {
5099 this.fileInfo = fileInfo;
5102 FunctionImporter.prototype.eval = function(contents, callback) {
5108 add: function(name, func) {
5109 loaded[name] = func;
5111 addMultiple: function(functions) {
5112 Object.keys(functions).forEach(function(name) {
5113 loaded[name] = functions[name];
5119 loader = new Function("functions", "tree", "fileInfo", contents);
5120 loader(registry, tree, this.fileInfo);
5122 callback(new LessError({
5123 message: "Plugin evaluation error: '" + e.name + ': ' + e.message.replace(/["]/g, "'") + "'" ,
5124 filename: this.fileInfo.filename
5128 callback(null, { functions: loaded });
5131 },{"../less-error":32,"../tree":62}],41:[function(require,module,exports){
5132 var PromiseConstructor;
5134 module.exports = function(environment, ParseTree, ImportManager) {
5135 var render = function (input, options, callback) {
5136 if (typeof options === 'function') {
5142 if (!PromiseConstructor) {
5143 PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
5146 return new PromiseConstructor(function (resolve, reject) {
5147 render.call(self, input, options, function(err, output) {
5156 this.parse(input, options, function(err, root, imports, options) {
5157 if (err) { return callback(err); }
5161 var parseTree = new ParseTree(root, imports);
5162 result = parseTree.toCSS(options);
5164 catch (err) { return callback(err); }
5166 callback(null, result);
5174 },{"promise":undefined}],42:[function(require,module,exports){
5175 module.exports = function (SourceMapOutput, environment) {
5177 var SourceMapBuilder = function (options) {
5178 this.options = options;
5181 SourceMapBuilder.prototype.toCSS = function(rootNode, options, imports) {
5182 var sourceMapOutput = new SourceMapOutput(
5184 contentsIgnoredCharsMap: imports.contentsIgnoredChars,
5186 contentsMap: imports.contents,
5187 sourceMapFilename: this.options.sourceMapFilename,
5188 sourceMapURL: this.options.sourceMapURL,
5189 outputFilename: this.options.sourceMapOutputFilename,
5190 sourceMapBasepath: this.options.sourceMapBasepath,
5191 sourceMapRootpath: this.options.sourceMapRootpath,
5192 outputSourceFiles: this.options.outputSourceFiles,
5193 sourceMapGenerator: this.options.sourceMapGenerator,
5194 sourceMapFileInline: this.options.sourceMapFileInline
5197 var css = sourceMapOutput.toCSS(options);
5198 this.sourceMap = sourceMapOutput.sourceMap;
5199 this.sourceMapURL = sourceMapOutput.sourceMapURL;
5200 if (this.options.sourceMapInputFilename) {
5201 this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename);
5203 return css + this.getCSSAppendage();
5206 SourceMapBuilder.prototype.getCSSAppendage = function() {
5208 var sourceMapURL = this.sourceMapURL;
5209 if (this.options.sourceMapFileInline) {
5210 if (this.sourceMap === undefined) {
5213 sourceMapURL = "data:application/json;base64," + environment.encodeBase64(this.sourceMap);
5217 return "/*# sourceMappingURL=" + sourceMapURL + " */";
5222 SourceMapBuilder.prototype.getExternalSourceMap = function() {
5223 return this.sourceMap;
5225 SourceMapBuilder.prototype.setExternalSourceMap = function(sourceMap) {
5226 this.sourceMap = sourceMap;
5229 SourceMapBuilder.prototype.isInline = function() {
5230 return this.options.sourceMapFileInline;
5232 SourceMapBuilder.prototype.getSourceMapURL = function() {
5233 return this.sourceMapURL;
5235 SourceMapBuilder.prototype.getOutputFilename = function() {
5236 return this.options.sourceMapOutputFilename;
5238 SourceMapBuilder.prototype.getInputFilename = function() {
5239 return this.sourceMapInputFilename;
5242 return SourceMapBuilder;
5245 },{}],43:[function(require,module,exports){
5246 module.exports = function (environment) {
5248 var SourceMapOutput = function (options) {
5250 this._rootNode = options.rootNode;
5251 this._contentsMap = options.contentsMap;
5252 this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap;
5253 if (options.sourceMapFilename) {
5254 this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/');
5256 this._outputFilename = options.outputFilename;
5257 this.sourceMapURL = options.sourceMapURL;
5258 if (options.sourceMapBasepath) {
5259 this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/');
5261 if (options.sourceMapRootpath) {
5262 this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/');
5263 if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') {
5264 this._sourceMapRootpath += '/';
5267 this._sourceMapRootpath = "";
5269 this._outputSourceFiles = options.outputSourceFiles;
5270 this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator();
5272 this._lineNumber = 0;
5276 SourceMapOutput.prototype.normalizeFilename = function(filename) {
5277 filename = filename.replace(/\\/g, '/');
5279 if (this._sourceMapBasepath && filename.indexOf(this._sourceMapBasepath) === 0) {
5280 filename = filename.substring(this._sourceMapBasepath.length);
5281 if (filename.charAt(0) === '\\' || filename.charAt(0) === '/') {
5282 filename = filename.substring(1);
5285 return (this._sourceMapRootpath || "") + filename;
5288 SourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) {
5290 //ignore adding empty strings
5302 var inputSource = this._contentsMap[fileInfo.filename];
5304 // remove vars/banner added to the top of the file
5305 if (this._contentsIgnoredCharsMap[fileInfo.filename]) {
5307 index -= this._contentsIgnoredCharsMap[fileInfo.filename];
5308 if (index < 0) { index = 0; }
5309 // adjust the source
5310 inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]);
5312 inputSource = inputSource.substring(0, index);
5313 sourceLines = inputSource.split("\n");
5314 sourceColumns = sourceLines[sourceLines.length - 1];
5317 lines = chunk.split("\n");
5318 columns = lines[lines.length - 1];
5322 this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column},
5323 original: { line: sourceLines.length, column: sourceColumns.length},
5324 source: this.normalizeFilename(fileInfo.filename)});
5326 for (i = 0; i < lines.length; i++) {
5327 this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0},
5328 original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0},
5329 source: this.normalizeFilename(fileInfo.filename)});
5334 if (lines.length === 1) {
5335 this._column += columns.length;
5337 this._lineNumber += lines.length - 1;
5338 this._column = columns.length;
5341 this._css.push(chunk);
5344 SourceMapOutput.prototype.isEmpty = function() {
5345 return this._css.length === 0;
5348 SourceMapOutput.prototype.toCSS = function(context) {
5349 this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null });
5351 if (this._outputSourceFiles) {
5352 for (var filename in this._contentsMap) {
5353 if (this._contentsMap.hasOwnProperty(filename)) {
5354 var source = this._contentsMap[filename];
5355 if (this._contentsIgnoredCharsMap[filename]) {
5356 source = source.slice(this._contentsIgnoredCharsMap[filename]);
5358 this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source);
5363 this._rootNode.genCSS(context, this);
5365 if (this._css.length > 0) {
5367 sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON());
5369 if (this.sourceMapURL) {
5370 sourceMapURL = this.sourceMapURL;
5371 } else if (this._sourceMapFilename) {
5372 sourceMapURL = this._sourceMapFilename;
5374 this.sourceMapURL = sourceMapURL;
5376 this.sourceMap = sourceMapContent;
5379 return this._css.join('');
5382 return SourceMapOutput;
5385 },{}],44:[function(require,module,exports){
5386 var contexts = require("./contexts"),
5387 visitor = require("./visitors"),
5388 tree = require("./tree");
5390 module.exports = function(root, options) {
5391 options = options || {};
5393 variables = options.variables,
5394 evalEnv = new contexts.Eval(options);
5397 // Allows setting variables with a hash, so:
5399 // `{ color: new tree.Color('#f01') }` will become:
5401 // new tree.Rule('@color',
5403 // new tree.Expression([
5404 // new tree.Color('#f01')
5409 if (typeof variables === 'object' && !Array.isArray(variables)) {
5410 variables = Object.keys(variables).map(function (k) {
5411 var value = variables[k];
5413 if (! (value instanceof tree.Value)) {
5414 if (! (value instanceof tree.Expression)) {
5415 value = new tree.Expression([value]);
5417 value = new tree.Value([value]);
5419 return new tree.Rule('@' + k, value, false, null, 0);
5421 evalEnv.frames = [new tree.Ruleset(null, variables)];
5424 var preEvalVisitors = [],
5426 new visitor.JoinSelectorVisitor(),
5427 new visitor.MarkVisibleSelectorsVisitor(true),
5428 new visitor.ExtendVisitor(),
5429 new visitor.ToCSSVisitor({compress: Boolean(options.compress)})
5432 if (options.pluginManager) {
5433 var pluginVisitors = options.pluginManager.getVisitors();
5434 for (i = 0; i < pluginVisitors.length; i++) {
5435 var pluginVisitor = pluginVisitors[i];
5436 if (pluginVisitor.isPreEvalVisitor) {
5437 preEvalVisitors.push(pluginVisitor);
5439 if (pluginVisitor.isPreVisitor) {
5440 visitors.splice(0, 0, pluginVisitor);
5442 visitors.push(pluginVisitor);
5448 for (i = 0; i < preEvalVisitors.length; i++) {
5449 preEvalVisitors[i].run(root);
5452 evaldRoot = root.eval(evalEnv);
5454 for (i = 0; i < visitors.length; i++) {
5455 visitors[i].run(evaldRoot);
5461 },{"./contexts":11,"./tree":62,"./visitors":87}],45:[function(require,module,exports){
5462 var Node = require("./node");
5464 var Alpha = function (val) {
5467 Alpha.prototype = new Node();
5468 Alpha.prototype.type = "Alpha";
5470 Alpha.prototype.accept = function (visitor) {
5471 this.value = visitor.visit(this.value);
5473 Alpha.prototype.eval = function (context) {
5474 if (this.value.eval) { return new Alpha(this.value.eval(context)); }
5477 Alpha.prototype.genCSS = function (context, output) {
5478 output.add("alpha(opacity=");
5480 if (this.value.genCSS) {
5481 this.value.genCSS(context, output);
5483 output.add(this.value);
5489 module.exports = Alpha;
5491 },{"./node":70}],46:[function(require,module,exports){
5492 var Node = require("./node");
5494 var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) {
5497 this.mapLines = mapLines;
5498 this.currentFileInfo = currentFileInfo;
5499 this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : rulesetLike;
5500 this.allowRoot = true;
5501 this.copyVisibilityInfo(visibilityInfo);
5503 Anonymous.prototype = new Node();
5504 Anonymous.prototype.type = "Anonymous";
5505 Anonymous.prototype.eval = function () {
5506 return new Anonymous(this.value, this.index, this.currentFileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo());
5508 Anonymous.prototype.compare = function (other) {
5509 return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined;
5511 Anonymous.prototype.isRulesetLike = function() {
5512 return this.rulesetLike;
5514 Anonymous.prototype.genCSS = function (context, output) {
5515 output.add(this.value, this.currentFileInfo, this.index, this.mapLines);
5517 module.exports = Anonymous;
5519 },{"./node":70}],47:[function(require,module,exports){
5520 var Node = require("./node");
5522 var Assignment = function (key, val) {
5527 Assignment.prototype = new Node();
5528 Assignment.prototype.type = "Assignment";
5529 Assignment.prototype.accept = function (visitor) {
5530 this.value = visitor.visit(this.value);
5532 Assignment.prototype.eval = function (context) {
5533 if (this.value.eval) {
5534 return new Assignment(this.key, this.value.eval(context));
5538 Assignment.prototype.genCSS = function (context, output) {
5539 output.add(this.key + '=');
5540 if (this.value.genCSS) {
5541 this.value.genCSS(context, output);
5543 output.add(this.value);
5546 module.exports = Assignment;
5548 },{"./node":70}],48:[function(require,module,exports){
5549 var Node = require("./node");
5551 var Attribute = function (key, op, value) {
5556 Attribute.prototype = new Node();
5557 Attribute.prototype.type = "Attribute";
5558 Attribute.prototype.eval = function (context) {
5559 return new Attribute(this.key.eval ? this.key.eval(context) : this.key,
5560 this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value);
5562 Attribute.prototype.genCSS = function (context, output) {
5563 output.add(this.toCSS(context));
5565 Attribute.prototype.toCSS = function (context) {
5566 var value = this.key.toCSS ? this.key.toCSS(context) : this.key;
5570 value += (this.value.toCSS ? this.value.toCSS(context) : this.value);
5573 return '[' + value + ']';
5575 module.exports = Attribute;
5577 },{"./node":70}],49:[function(require,module,exports){
5578 var Node = require("./node"),
5579 FunctionCaller = require("../functions/function-caller");
5581 // A function call node.
5583 var Call = function (name, args, index, currentFileInfo) {
5587 this.currentFileInfo = currentFileInfo;
5589 Call.prototype = new Node();
5590 Call.prototype.type = "Call";
5591 Call.prototype.accept = function (visitor) {
5593 this.args = visitor.visitArray(this.args);
5597 // When evaluating a function call,
5598 // we either find the function in the functionRegistry,
5599 // in which case we call it, passing the evaluated arguments,
5600 // if this returns null or we cannot find the function, we
5601 // simply print it out as it appeared originally [2].
5603 // The reason why we evaluate the arguments, is in the case where
5604 // we try to pass a variable to a function, like: `saturate(@color)`.
5605 // The function should receive the value, not the variable.
5607 Call.prototype.eval = function (context) {
5608 var args = this.args.map(function (a) { return a.eval(context); }),
5609 result, funcCaller = new FunctionCaller(this.name, context, this.index, this.currentFileInfo);
5611 if (funcCaller.isValid()) {
5613 result = funcCaller.call(args);
5615 throw { type: e.type || "Runtime",
5616 message: "error evaluating function `" + this.name + "`" +
5617 (e.message ? ': ' + e.message : ''),
5618 index: this.index, filename: this.currentFileInfo.filename };
5621 if (result != null) {
5622 result.index = this.index;
5623 result.currentFileInfo = this.currentFileInfo;
5628 return new Call(this.name, args, this.index, this.currentFileInfo);
5630 Call.prototype.genCSS = function (context, output) {
5631 output.add(this.name + "(", this.currentFileInfo, this.index);
5633 for (var i = 0; i < this.args.length; i++) {
5634 this.args[i].genCSS(context, output);
5635 if (i + 1 < this.args.length) {
5642 module.exports = Call;
5644 },{"../functions/function-caller":21,"./node":70}],50:[function(require,module,exports){
5645 var Node = require("./node"),
5646 colors = require("../data/colors");
5649 // RGB Colors - #ff0014, #eee
5651 var Color = function (rgb, a, originalForm) {
5653 // The end goal here, is to parse the arguments
5654 // into an integer triplet, such as `128, 255, 0`
5656 // This facilitates operations and conversions.
5658 if (Array.isArray(rgb)) {
5660 } else if (rgb.length == 6) {
5661 this.rgb = rgb.match(/.{2}/g).map(function (c) {
5662 return parseInt(c, 16);
5665 this.rgb = rgb.split('').map(function (c) {
5666 return parseInt(c + c, 16);
5669 this.alpha = typeof a === 'number' ? a : 1;
5670 if (typeof originalForm !== 'undefined') {
5671 this.value = originalForm;
5675 Color.prototype = new Node();
5676 Color.prototype.type = "Color";
5678 function clamp(v, max) {
5679 return Math.min(Math.max(v, 0), max);
5683 return '#' + v.map(function (c) {
5684 c = clamp(Math.round(c), 255);
5685 return (c < 16 ? '0' : '') + c.toString(16);
5689 Color.prototype.luma = function () {
5690 var r = this.rgb[0] / 255,
5691 g = this.rgb[1] / 255,
5692 b = this.rgb[2] / 255;
5694 r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4);
5695 g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4);
5696 b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4);
5698 return 0.2126 * r + 0.7152 * g + 0.0722 * b;
5700 Color.prototype.genCSS = function (context, output) {
5701 output.add(this.toCSS(context));
5703 Color.prototype.toCSS = function (context, doNotCompress) {
5704 var compress = context && context.compress && !doNotCompress, color, alpha;
5706 // `value` is set if this color was originally
5707 // converted from a named color string so we need
5708 // to respect this and try to output named color too.
5713 // If we have some transparency, the only way to represent it
5714 // is via `rgba`. Otherwise, we use the hex representation,
5715 // which has better compatibility with older browsers.
5716 // Values are capped between `0` and `255`, rounded and zero-padded.
5717 alpha = this.fround(context, this.alpha);
5719 return "rgba(" + this.rgb.map(function (c) {
5720 return clamp(Math.round(c), 255);
5721 }).concat(clamp(alpha, 1))
5722 .join(',' + (compress ? '' : ' ')) + ")";
5725 color = this.toRGB();
5728 var splitcolor = color.split('');
5730 // Convert color to short format
5731 if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) {
5732 color = '#' + splitcolor[1] + splitcolor[3] + splitcolor[5];
5740 // Operations have to be done per-channel, if not,
5741 // channels will spill onto each other. Once we have
5742 // our result, in the form of an integer triplet,
5743 // we create a new Color node to hold the result.
5745 Color.prototype.operate = function (context, op, other) {
5747 var alpha = this.alpha * (1 - other.alpha) + other.alpha;
5748 for (var c = 0; c < 3; c++) {
5749 rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]);
5751 return new Color(rgb, alpha);
5753 Color.prototype.toRGB = function () {
5754 return toHex(this.rgb);
5756 Color.prototype.toHSL = function () {
5757 var r = this.rgb[0] / 255,
5758 g = this.rgb[1] / 255,
5759 b = this.rgb[2] / 255,
5762 var max = Math.max(r, g, b), min = Math.min(r, g, b);
5763 var h, s, l = (max + min) / 2, d = max - min;
5768 s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
5771 case r: h = (g - b) / d + (g < b ? 6 : 0); break;
5772 case g: h = (b - r) / d + 2; break;
5773 case b: h = (r - g) / d + 4; break;
5777 return { h: h * 360, s: s, l: l, a: a };
5779 //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
5780 Color.prototype.toHSV = function () {
5781 var r = this.rgb[0] / 255,
5782 g = this.rgb[1] / 255,
5783 b = this.rgb[2] / 255,
5786 var max = Math.max(r, g, b), min = Math.min(r, g, b);
5800 case r: h = (g - b) / d + (g < b ? 6 : 0); break;
5801 case g: h = (b - r) / d + 2; break;
5802 case b: h = (r - g) / d + 4; break;
5806 return { h: h * 360, s: s, v: v, a: a };
5808 Color.prototype.toARGB = function () {
5809 return toHex([this.alpha * 255].concat(this.rgb));
5811 Color.prototype.compare = function (x) {
5813 x.rgb[0] === this.rgb[0] &&
5814 x.rgb[1] === this.rgb[1] &&
5815 x.rgb[2] === this.rgb[2] &&
5816 x.alpha === this.alpha) ? 0 : undefined;
5819 Color.fromKeyword = function(keyword) {
5820 var c, key = keyword.toLowerCase();
5821 if (colors.hasOwnProperty(key)) {
5822 c = new Color(colors[key].slice(1));
5824 else if (key === "transparent") {
5825 c = new Color([0, 0, 0], 0);
5833 module.exports = Color;
5835 },{"../data/colors":12,"./node":70}],51:[function(require,module,exports){
5836 var Node = require("./node");
5838 var Combinator = function (value) {
5839 if (value === ' ') {
5841 this.emptyOrWhitespace = true;
5843 this.value = value ? value.trim() : "";
5844 this.emptyOrWhitespace = this.value === "";
5847 Combinator.prototype = new Node();
5848 Combinator.prototype.type = "Combinator";
5849 var _noSpaceCombinators = {
5854 Combinator.prototype.genCSS = function (context, output) {
5855 var spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' ';
5856 output.add(spaceOrEmpty + this.value + spaceOrEmpty);
5858 module.exports = Combinator;
5860 },{"./node":70}],52:[function(require,module,exports){
5861 var Node = require("./node"),
5862 getDebugInfo = require("./debug-info");
5864 var Comment = function (value, isLineComment, index, currentFileInfo) {
5866 this.isLineComment = isLineComment;
5868 this.currentFileInfo = currentFileInfo;
5869 this.allowRoot = true;
5871 Comment.prototype = new Node();
5872 Comment.prototype.type = "Comment";
5873 Comment.prototype.genCSS = function (context, output) {
5874 if (this.debugInfo) {
5875 output.add(getDebugInfo(context, this), this.currentFileInfo, this.index);
5877 output.add(this.value);
5879 Comment.prototype.isSilent = function(context) {
5880 var isCompressed = context.compress && this.value[2] !== "!";
5881 return this.isLineComment || isCompressed;
5883 module.exports = Comment;
5885 },{"./debug-info":54,"./node":70}],53:[function(require,module,exports){
5886 var Node = require("./node");
5888 var Condition = function (op, l, r, i, negate) {
5889 this.op = op.trim();
5893 this.negate = negate;
5895 Condition.prototype = new Node();
5896 Condition.prototype.type = "Condition";
5897 Condition.prototype.accept = function (visitor) {
5898 this.lvalue = visitor.visit(this.lvalue);
5899 this.rvalue = visitor.visit(this.rvalue);
5901 Condition.prototype.eval = function (context) {
5902 var result = (function (op, a, b) {
5904 case 'and': return a && b;
5905 case 'or': return a || b;
5907 switch (Node.compare(a, b)) {
5909 return op === '<' || op === '=<' || op === '<=';
5911 return op === '=' || op === '>=' || op === '=<' || op === '<=';
5913 return op === '>' || op === '>=';
5918 })(this.op, this.lvalue.eval(context), this.rvalue.eval(context));
5920 return this.negate ? !result : result;
5922 module.exports = Condition;
5924 },{"./node":70}],54:[function(require,module,exports){
5925 var debugInfo = function(context, ctx, lineSeparator) {
5927 if (context.dumpLineNumbers && !context.compress) {
5928 switch(context.dumpLineNumbers) {
5930 result = debugInfo.asComment(ctx);
5933 result = debugInfo.asMediaQuery(ctx);
5936 result = debugInfo.asComment(ctx) + (lineSeparator || "") + debugInfo.asMediaQuery(ctx);
5943 debugInfo.asComment = function(ctx) {
5944 return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n';
5947 debugInfo.asMediaQuery = function(ctx) {
5948 var filenameWithProtocol = ctx.debugInfo.fileName;
5949 if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) {
5950 filenameWithProtocol = 'file://' + filenameWithProtocol;
5952 return '@media -sass-debug-info{filename{font-family:' +
5953 filenameWithProtocol.replace(/([.:\/\\])/g, function (a) {
5959 '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n';
5962 module.exports = debugInfo;
5964 },{}],55:[function(require,module,exports){
5965 var Node = require("./node"),
5966 contexts = require("../contexts");
5968 var DetachedRuleset = function (ruleset, frames) {
5969 this.ruleset = ruleset;
5970 this.frames = frames;
5972 DetachedRuleset.prototype = new Node();
5973 DetachedRuleset.prototype.type = "DetachedRuleset";
5974 DetachedRuleset.prototype.evalFirst = true;
5975 DetachedRuleset.prototype.accept = function (visitor) {
5976 this.ruleset = visitor.visit(this.ruleset);
5978 DetachedRuleset.prototype.eval = function (context) {
5979 var frames = this.frames || context.frames.slice(0);
5980 return new DetachedRuleset(this.ruleset, frames);
5982 DetachedRuleset.prototype.callEval = function (context) {
5983 return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context);
5985 module.exports = DetachedRuleset;
5987 },{"../contexts":11,"./node":70}],56:[function(require,module,exports){
5988 var Node = require("./node"),
5989 unitConversions = require("../data/unit-conversions"),
5990 Unit = require("./unit"),
5991 Color = require("./color");
5994 // A number with a unit
5996 var Dimension = function (value, unit) {
5997 this.value = parseFloat(value);
5998 this.unit = (unit && unit instanceof Unit) ? unit :
5999 new Unit(unit ? [unit] : undefined);
6002 Dimension.prototype = new Node();
6003 Dimension.prototype.type = "Dimension";
6004 Dimension.prototype.accept = function (visitor) {
6005 this.unit = visitor.visit(this.unit);
6007 Dimension.prototype.eval = function (context) {
6010 Dimension.prototype.toColor = function () {
6011 return new Color([this.value, this.value, this.value]);
6013 Dimension.prototype.genCSS = function (context, output) {
6014 if ((context && context.strictUnits) && !this.unit.isSingular()) {
6015 throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: " + this.unit.toString());
6018 var value = this.fround(context, this.value),
6019 strValue = String(value);
6021 if (value !== 0 && value < 0.000001 && value > -0.000001) {
6022 // would be output 1e-6 etc.
6023 strValue = value.toFixed(20).replace(/0+$/, "");
6026 if (context && context.compress) {
6027 // Zero values doesn't need a unit
6028 if (value === 0 && this.unit.isLength()) {
6029 output.add(strValue);
6033 // Float values doesn't need a leading zero
6034 if (value > 0 && value < 1) {
6035 strValue = (strValue).substr(1);
6039 output.add(strValue);
6040 this.unit.genCSS(context, output);
6043 // In an operation between two Dimensions,
6044 // we default to the first Dimension's unit,
6045 // so `1px + 2` will yield `3px`.
6046 Dimension.prototype.operate = function (context, op, other) {
6047 /*jshint noempty:false */
6048 var value = this._operate(context, op, this.value, other.value),
6049 unit = this.unit.clone();
6051 if (op === '+' || op === '-') {
6052 if (unit.numerator.length === 0 && unit.denominator.length === 0) {
6053 unit = other.unit.clone();
6054 if (this.unit.backupUnit) {
6055 unit.backupUnit = this.unit.backupUnit;
6057 } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) {
6060 other = other.convertTo(this.unit.usedUnits());
6062 if (context.strictUnits && other.unit.toString() !== unit.toString()) {
6063 throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() +
6064 "' and '" + other.unit.toString() + "'.");
6067 value = this._operate(context, op, this.value, other.value);
6069 } else if (op === '*') {
6070 unit.numerator = unit.numerator.concat(other.unit.numerator).sort();
6071 unit.denominator = unit.denominator.concat(other.unit.denominator).sort();
6073 } else if (op === '/') {
6074 unit.numerator = unit.numerator.concat(other.unit.denominator).sort();
6075 unit.denominator = unit.denominator.concat(other.unit.numerator).sort();
6078 return new Dimension(value, unit);
6080 Dimension.prototype.compare = function (other) {
6083 if (!(other instanceof Dimension)) {
6087 if (this.unit.isEmpty() || other.unit.isEmpty()) {
6093 if (a.unit.compare(b.unit) !== 0) {
6098 return Node.numericCompare(a.value, b.value);
6100 Dimension.prototype.unify = function () {
6101 return this.convertTo({ length: 'px', duration: 's', angle: 'rad' });
6103 Dimension.prototype.convertTo = function (conversions) {
6104 var value = this.value, unit = this.unit.clone(),
6105 i, groupName, group, targetUnit, derivedConversions = {}, applyUnit;
6107 if (typeof conversions === 'string') {
6108 for (i in unitConversions) {
6109 if (unitConversions[i].hasOwnProperty(conversions)) {
6110 derivedConversions = {};
6111 derivedConversions[i] = conversions;
6114 conversions = derivedConversions;
6116 applyUnit = function (atomicUnit, denominator) {
6117 /* jshint loopfunc:true */
6118 if (group.hasOwnProperty(atomicUnit)) {
6120 value = value / (group[atomicUnit] / group[targetUnit]);
6122 value = value * (group[atomicUnit] / group[targetUnit]);
6131 for (groupName in conversions) {
6132 if (conversions.hasOwnProperty(groupName)) {
6133 targetUnit = conversions[groupName];
6134 group = unitConversions[groupName];
6136 unit.map(applyUnit);
6142 return new Dimension(value, unit);
6144 module.exports = Dimension;
6146 },{"../data/unit-conversions":14,"./color":50,"./node":70,"./unit":79}],57:[function(require,module,exports){
6147 var Node = require("./node"),
6148 Selector = require("./selector"),
6149 Ruleset = require("./ruleset");
6151 var Directive = function (name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) {
6157 if (Array.isArray(rules)) {
6160 this.rules = [rules];
6161 this.rules[0].selectors = (new Selector([], null, null, this.index, currentFileInfo)).createEmptySelectors();
6163 for (i = 0; i < this.rules.length; i++) {
6164 this.rules[i].allowImports = true;
6168 this.currentFileInfo = currentFileInfo;
6169 this.debugInfo = debugInfo;
6170 this.isRooted = isRooted || false;
6171 this.copyVisibilityInfo(visibilityInfo);
6172 this.allowRoot = true;
6175 Directive.prototype = new Node();
6176 Directive.prototype.type = "Directive";
6177 Directive.prototype.accept = function (visitor) {
6178 var value = this.value, rules = this.rules;
6180 this.rules = visitor.visitArray(rules);
6183 this.value = visitor.visit(value);
6186 Directive.prototype.isRulesetLike = function() {
6187 return this.rules || !this.isCharset();
6189 Directive.prototype.isCharset = function() {
6190 return "@charset" === this.name;
6192 Directive.prototype.genCSS = function (context, output) {
6193 var value = this.value, rules = this.rules;
6194 output.add(this.name, this.currentFileInfo, this.index);
6197 value.genCSS(context, output);
6200 this.outputRuleset(context, output, rules);
6205 Directive.prototype.eval = function (context) {
6206 var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules;
6208 //media stored inside other directive should not bubble over it
6209 //backpup media bubbling information
6210 mediaPathBackup = context.mediaPath;
6211 mediaBlocksBackup = context.mediaBlocks;
6212 //deleted media bubbling information
6213 context.mediaPath = [];
6214 context.mediaBlocks = [];
6217 value = value.eval(context);
6220 // assuming that there is only one rule at this point - that is how parser constructs the rule
6221 rules = [rules[0].eval(context)];
6222 rules[0].root = true;
6224 //restore media bubbling information
6225 context.mediaPath = mediaPathBackup;
6226 context.mediaBlocks = mediaBlocksBackup;
6228 return new Directive(this.name, value, rules,
6229 this.index, this.currentFileInfo, this.debugInfo, this.isRooted, this.visibilityInfo());
6231 Directive.prototype.variable = function (name) {
6233 // assuming that there is only one rule at this point - that is how parser constructs the rule
6234 return Ruleset.prototype.variable.call(this.rules[0], name);
6237 Directive.prototype.find = function () {
6239 // assuming that there is only one rule at this point - that is how parser constructs the rule
6240 return Ruleset.prototype.find.apply(this.rules[0], arguments);
6243 Directive.prototype.rulesets = function () {
6245 // assuming that there is only one rule at this point - that is how parser constructs the rule
6246 return Ruleset.prototype.rulesets.apply(this.rules[0]);
6249 Directive.prototype.outputRuleset = function (context, output, rules) {
6250 var ruleCnt = rules.length, i;
6251 context.tabLevel = (context.tabLevel | 0) + 1;
6254 if (context.compress) {
6256 for (i = 0; i < ruleCnt; i++) {
6257 rules[i].genCSS(context, output);
6265 var tabSetStr = '\n' + Array(context.tabLevel).join(" "), tabRuleStr = tabSetStr + " ";
6267 output.add(" {" + tabSetStr + '}');
6269 output.add(" {" + tabRuleStr);
6270 rules[0].genCSS(context, output);
6271 for (i = 1; i < ruleCnt; i++) {
6272 output.add(tabRuleStr);
6273 rules[i].genCSS(context, output);
6275 output.add(tabSetStr + '}');
6280 module.exports = Directive;
6282 },{"./node":70,"./ruleset":76,"./selector":77}],58:[function(require,module,exports){
6283 var Node = require("./node"),
6284 Paren = require("./paren"),
6285 Combinator = require("./combinator");
6287 var Element = function (combinator, value, index, currentFileInfo, info) {
6288 this.combinator = combinator instanceof Combinator ?
6289 combinator : new Combinator(combinator);
6291 if (typeof value === 'string') {
6292 this.value = value.trim();
6299 this.currentFileInfo = currentFileInfo;
6300 this.copyVisibilityInfo(info);
6302 Element.prototype = new Node();
6303 Element.prototype.type = "Element";
6304 Element.prototype.accept = function (visitor) {
6305 var value = this.value;
6306 this.combinator = visitor.visit(this.combinator);
6307 if (typeof value === "object") {
6308 this.value = visitor.visit(value);
6311 Element.prototype.eval = function (context) {
6312 return new Element(this.combinator,
6313 this.value.eval ? this.value.eval(context) : this.value,
6315 this.currentFileInfo, this.visibilityInfo());
6317 Element.prototype.clone = function () {
6318 return new Element(this.combinator,
6321 this.currentFileInfo, this.visibilityInfo());
6323 Element.prototype.genCSS = function (context, output) {
6324 output.add(this.toCSS(context), this.currentFileInfo, this.index);
6326 Element.prototype.toCSS = function (context) {
6327 context = context || {};
6328 var value = this.value, firstSelector = context.firstSelector;
6329 if (value instanceof Paren) {
6330 // selector in parens should not be affected by outer selector
6331 // flags (breaks only interpolated selectors - see #1973)
6332 context.firstSelector = true;
6334 value = value.toCSS ? value.toCSS(context) : value;
6335 context.firstSelector = firstSelector;
6336 if (value === '' && this.combinator.value.charAt(0) === '&') {
6339 return this.combinator.toCSS(context) + value;
6342 module.exports = Element;
6344 },{"./combinator":51,"./node":70,"./paren":72}],59:[function(require,module,exports){
6345 var Node = require("./node"),
6346 Paren = require("./paren"),
6347 Comment = require("./comment");
6349 var Expression = function (value) {
6352 throw new Error("Expression requires an array parameter");
6355 Expression.prototype = new Node();
6356 Expression.prototype.type = "Expression";
6357 Expression.prototype.accept = function (visitor) {
6358 this.value = visitor.visitArray(this.value);
6360 Expression.prototype.eval = function (context) {
6362 inParenthesis = this.parens && !this.parensInOp,
6363 doubleParen = false;
6364 if (inParenthesis) {
6365 context.inParenthesis();
6367 if (this.value.length > 1) {
6368 returnValue = new Expression(this.value.map(function (e) {
6369 return e.eval(context);
6371 } else if (this.value.length === 1) {
6372 if (this.value[0].parens && !this.value[0].parensInOp) {
6375 returnValue = this.value[0].eval(context);
6379 if (inParenthesis) {
6380 context.outOfParenthesis();
6382 if (this.parens && this.parensInOp && !(context.isMathOn()) && !doubleParen) {
6383 returnValue = new Paren(returnValue);
6387 Expression.prototype.genCSS = function (context, output) {
6388 for (var i = 0; i < this.value.length; i++) {
6389 this.value[i].genCSS(context, output);
6390 if (i + 1 < this.value.length) {
6395 Expression.prototype.throwAwayComments = function () {
6396 this.value = this.value.filter(function(v) {
6397 return !(v instanceof Comment);
6400 module.exports = Expression;
6402 },{"./comment":52,"./node":70,"./paren":72}],60:[function(require,module,exports){
6403 var Node = require("./node"),
6404 Selector = require("./selector");
6406 var Extend = function Extend(selector, option, index, currentFileInfo, visibilityInfo) {
6407 this.selector = selector;
6408 this.option = option;
6410 this.object_id = Extend.next_id++;
6411 this.parent_ids = [this.object_id];
6412 this.currentFileInfo = currentFileInfo || {};
6413 this.copyVisibilityInfo(visibilityInfo);
6414 this.allowRoot = true;
6418 this.allowBefore = true;
6419 this.allowAfter = true;
6422 this.allowBefore = false;
6423 this.allowAfter = false;
6429 Extend.prototype = new Node();
6430 Extend.prototype.type = "Extend";
6431 Extend.prototype.accept = function (visitor) {
6432 this.selector = visitor.visit(this.selector);
6434 Extend.prototype.eval = function (context) {
6435 return new Extend(this.selector.eval(context), this.option, this.index, this.currentFileInfo, this.visibilityInfo());
6437 Extend.prototype.clone = function (context) {
6438 return new Extend(this.selector, this.option, this.index, this.currentFileInfo, this.visibilityInfo());
6440 //it concatenates (joins) all selectors in selector array
6441 Extend.prototype.findSelfSelectors = function (selectors) {
6442 var selfElements = [],
6446 for (i = 0; i < selectors.length; i++) {
6447 selectorElements = selectors[i].elements;
6448 // duplicate the logic in genCSS function inside the selector node.
6449 // future TODO - move both logics into the selector joiner visitor
6450 if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === "") {
6451 selectorElements[0].combinator.value = ' ';
6453 selfElements = selfElements.concat(selectors[i].elements);
6456 this.selfSelectors = [new Selector(selfElements)];
6457 this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo());
6459 module.exports = Extend;
6461 },{"./node":70,"./selector":77}],61:[function(require,module,exports){
6462 var Node = require("./node"),
6463 Media = require("./media"),
6464 URL = require("./url"),
6465 Quoted = require("./quoted"),
6466 Ruleset = require("./ruleset"),
6467 Anonymous = require("./anonymous");
6472 // The general strategy here is that we don't want to wait
6473 // for the parsing to be completed, before we start importing
6474 // the file. That's because in the context of a browser,
6475 // most of the time will be spent waiting for the server to respond.
6477 // On creation, we push the import path to our import queue, though
6478 // `import,push`, we also pass it a callback, which it'll call once
6479 // the file has been fetched, and parsed.
6481 var Import = function (path, features, options, index, currentFileInfo, visibilityInfo) {
6482 this.options = options;
6485 this.features = features;
6486 this.currentFileInfo = currentFileInfo;
6487 this.allowRoot = true;
6489 if (this.options.less !== undefined || this.options.inline) {
6490 this.css = !this.options.less || this.options.inline;
6492 var pathValue = this.getPath();
6493 if (pathValue && /[#\.\&\?\/]css([\?;].*)?$/.test(pathValue)) {
6497 this.copyVisibilityInfo(visibilityInfo);
6501 // The actual import node doesn't return anything, when converted to CSS.
6502 // The reason is that it's used at the evaluation stage, so that the rules
6503 // it imports can be treated like any other rules.
6505 // In `eval`, we make sure all Import nodes get evaluated, recursively, so
6506 // we end up with a flat structure, which can easily be imported in the parent
6509 Import.prototype = new Node();
6510 Import.prototype.type = "Import";
6511 Import.prototype.accept = function (visitor) {
6512 if (this.features) {
6513 this.features = visitor.visit(this.features);
6515 this.path = visitor.visit(this.path);
6516 if (!this.options.plugin && !this.options.inline && this.root) {
6517 this.root = visitor.visit(this.root);
6520 Import.prototype.genCSS = function (context, output) {
6521 if (this.css && this.path.currentFileInfo.reference === undefined) {
6522 output.add("@import ", this.currentFileInfo, this.index);
6523 this.path.genCSS(context, output);
6524 if (this.features) {
6526 this.features.genCSS(context, output);
6531 Import.prototype.getPath = function () {
6532 return (this.path instanceof URL) ?
6533 this.path.value.value : this.path.value;
6535 Import.prototype.isVariableImport = function () {
6536 var path = this.path;
6537 if (path instanceof URL) {
6540 if (path instanceof Quoted) {
6541 return path.containsVariables();
6546 Import.prototype.evalForImport = function (context) {
6547 var path = this.path;
6549 if (path instanceof URL) {
6553 return new Import(path.eval(context), this.features, this.options, this.index, this.currentFileInfo, this.visibilityInfo());
6555 Import.prototype.evalPath = function (context) {
6556 var path = this.path.eval(context);
6557 var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
6559 if (!(path instanceof URL)) {
6561 var pathValue = path.value;
6562 // Add the base path if the import is relative
6563 if (pathValue && context.isPathRelative(pathValue)) {
6564 path.value = rootpath + pathValue;
6567 path.value = context.normalizePath(path.value);
6572 Import.prototype.eval = function (context) {
6573 var result = this.doEval(context);
6574 if (this.options.reference || this.blocksVisibility()) {
6575 if (result.length || result.length === 0) {
6576 result.forEach(function (node) {
6577 node.addVisibilityBlock();
6581 result.addVisibilityBlock();
6586 Import.prototype.doEval = function (context) {
6587 var ruleset, registry,
6588 features = this.features && this.features.eval(context);
6590 if (this.options.plugin) {
6591 registry = context.frames[0] && context.frames[0].functionRegistry;
6592 if ( registry && this.root && this.root.functions ) {
6593 registry.addMultiple( this.root.functions );
6599 if (typeof this.skip === "function") {
6600 this.skip = this.skip();
6606 if (this.options.inline) {
6607 var contents = new Anonymous(this.root, 0,
6609 filename: this.importedFilename,
6610 reference: this.path.currentFileInfo && this.path.currentFileInfo.reference
6613 return this.features ? new Media([contents], this.features.value) : [contents];
6614 } else if (this.css) {
6615 var newImport = new Import(this.evalPath(context), features, this.options, this.index);
6616 if (!newImport.css && this.error) {
6621 ruleset = new Ruleset(null, this.root.rules.slice(0));
6622 ruleset.evalImports(context);
6624 return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules;
6627 module.exports = Import;
6629 },{"./anonymous":46,"./media":66,"./node":70,"./quoted":73,"./ruleset":76,"./url":80}],62:[function(require,module,exports){
6632 tree.Node = require('./node');
6633 tree.Alpha = require('./alpha');
6634 tree.Color = require('./color');
6635 tree.Directive = require('./directive');
6636 tree.DetachedRuleset = require('./detached-ruleset');
6637 tree.Operation = require('./operation');
6638 tree.Dimension = require('./dimension');
6639 tree.Unit = require('./unit');
6640 tree.Keyword = require('./keyword');
6641 tree.Variable = require('./variable');
6642 tree.Ruleset = require('./ruleset');
6643 tree.Element = require('./element');
6644 tree.Attribute = require('./attribute');
6645 tree.Combinator = require('./combinator');
6646 tree.Selector = require('./selector');
6647 tree.Quoted = require('./quoted');
6648 tree.Expression = require('./expression');
6649 tree.Rule = require('./rule');
6650 tree.Call = require('./call');
6651 tree.URL = require('./url');
6652 tree.Import = require('./import');
6654 Call: require('./mixin-call'),
6655 Definition: require('./mixin-definition')
6657 tree.Comment = require('./comment');
6658 tree.Anonymous = require('./anonymous');
6659 tree.Value = require('./value');
6660 tree.JavaScript = require('./javascript');
6661 tree.Assignment = require('./assignment');
6662 tree.Condition = require('./condition');
6663 tree.Paren = require('./paren');
6664 tree.Media = require('./media');
6665 tree.UnicodeDescriptor = require('./unicode-descriptor');
6666 tree.Negative = require('./negative');
6667 tree.Extend = require('./extend');
6668 tree.RulesetCall = require('./ruleset-call');
6670 module.exports = tree;
6672 },{"./alpha":45,"./anonymous":46,"./assignment":47,"./attribute":48,"./call":49,"./color":50,"./combinator":51,"./comment":52,"./condition":53,"./detached-ruleset":55,"./dimension":56,"./directive":57,"./element":58,"./expression":59,"./extend":60,"./import":61,"./javascript":63,"./keyword":65,"./media":66,"./mixin-call":67,"./mixin-definition":68,"./negative":69,"./node":70,"./operation":71,"./paren":72,"./quoted":73,"./rule":74,"./ruleset":76,"./ruleset-call":75,"./selector":77,"./unicode-descriptor":78,"./unit":79,"./url":80,"./value":81,"./variable":82}],63:[function(require,module,exports){
6673 var JsEvalNode = require("./js-eval-node"),
6674 Dimension = require("./dimension"),
6675 Quoted = require("./quoted"),
6676 Anonymous = require("./anonymous");
6678 var JavaScript = function (string, escaped, index, currentFileInfo) {
6679 this.escaped = escaped;
6680 this.expression = string;
6682 this.currentFileInfo = currentFileInfo;
6684 JavaScript.prototype = new JsEvalNode();
6685 JavaScript.prototype.type = "JavaScript";
6686 JavaScript.prototype.eval = function(context) {
6687 var result = this.evaluateJavaScript(this.expression, context);
6689 if (typeof result === 'number') {
6690 return new Dimension(result);
6691 } else if (typeof result === 'string') {
6692 return new Quoted('"' + result + '"', result, this.escaped, this.index);
6693 } else if (Array.isArray(result)) {
6694 return new Anonymous(result.join(', '));
6696 return new Anonymous(result);
6700 module.exports = JavaScript;
6702 },{"./anonymous":46,"./dimension":56,"./js-eval-node":64,"./quoted":73}],64:[function(require,module,exports){
6703 var Node = require("./node"),
6704 Variable = require("./variable");
6706 var JsEvalNode = function() {
6708 JsEvalNode.prototype = new Node();
6710 JsEvalNode.prototype.evaluateJavaScript = function (expression, context) {
6715 if (context.javascriptEnabled !== undefined && !context.javascriptEnabled) {
6716 throw { message: "You are using JavaScript, which has been disabled.",
6717 filename: this.currentFileInfo.filename,
6718 index: this.index };
6721 expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
6722 return that.jsify(new Variable('@' + name, that.index, that.currentFileInfo).eval(context));
6726 expression = new Function('return (' + expression + ')');
6728 throw { message: "JavaScript evaluation error: " + e.message + " from `" + expression + "`" ,
6729 filename: this.currentFileInfo.filename,
6730 index: this.index };
6733 var variables = context.frames[0].variables();
6734 for (var k in variables) {
6735 if (variables.hasOwnProperty(k)) {
6736 /*jshint loopfunc:true */
6737 evalContext[k.slice(1)] = {
6738 value: variables[k].value,
6740 return this.value.eval(context).toCSS();
6747 result = expression.call(evalContext);
6749 throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message.replace(/["]/g, "'") + "'" ,
6750 filename: this.currentFileInfo.filename,
6751 index: this.index };
6755 JsEvalNode.prototype.jsify = function (obj) {
6756 if (Array.isArray(obj.value) && (obj.value.length > 1)) {
6757 return '[' + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + ']';
6763 module.exports = JsEvalNode;
6765 },{"./node":70,"./variable":82}],65:[function(require,module,exports){
6766 var Node = require("./node");
6768 var Keyword = function (value) { this.value = value; };
6769 Keyword.prototype = new Node();
6770 Keyword.prototype.type = "Keyword";
6771 Keyword.prototype.genCSS = function (context, output) {
6772 if (this.value === '%') { throw { type: "Syntax", message: "Invalid % without number" }; }
6773 output.add(this.value);
6776 Keyword.True = new Keyword('true');
6777 Keyword.False = new Keyword('false');
6779 module.exports = Keyword;
6781 },{"./node":70}],66:[function(require,module,exports){
6782 var Ruleset = require("./ruleset"),
6783 Value = require("./value"),
6784 Selector = require("./selector"),
6785 Anonymous = require("./anonymous"),
6786 Expression = require("./expression"),
6787 Directive = require("./directive");
6789 var Media = function (value, features, index, currentFileInfo, visibilityInfo) {
6791 this.currentFileInfo = currentFileInfo;
6793 var selectors = (new Selector([], null, null, this.index, this.currentFileInfo)).createEmptySelectors();
6795 this.features = new Value(features);
6796 this.rules = [new Ruleset(selectors, value)];
6797 this.rules[0].allowImports = true;
6798 this.copyVisibilityInfo(visibilityInfo);
6799 this.allowRoot = true;
6801 Media.prototype = new Directive();
6802 Media.prototype.type = "Media";
6803 Media.prototype.isRulesetLike = true;
6804 Media.prototype.accept = function (visitor) {
6805 if (this.features) {
6806 this.features = visitor.visit(this.features);
6809 this.rules = visitor.visitArray(this.rules);
6812 Media.prototype.genCSS = function (context, output) {
6813 output.add('@media ', this.currentFileInfo, this.index);
6814 this.features.genCSS(context, output);
6815 this.outputRuleset(context, output, this.rules);
6817 Media.prototype.eval = function (context) {
6818 if (!context.mediaBlocks) {
6819 context.mediaBlocks = [];
6820 context.mediaPath = [];
6823 var media = new Media(null, [], this.index, this.currentFileInfo, this.visibilityInfo());
6824 if (this.debugInfo) {
6825 this.rules[0].debugInfo = this.debugInfo;
6826 media.debugInfo = this.debugInfo;
6828 var strictMathBypass = false;
6829 if (!context.strictMath) {
6830 strictMathBypass = true;
6831 context.strictMath = true;
6834 media.features = this.features.eval(context);
6837 if (strictMathBypass) {
6838 context.strictMath = false;
6842 context.mediaPath.push(media);
6843 context.mediaBlocks.push(media);
6845 this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit();
6846 context.frames.unshift(this.rules[0]);
6847 media.rules = [this.rules[0].eval(context)];
6848 context.frames.shift();
6850 context.mediaPath.pop();
6852 return context.mediaPath.length === 0 ? media.evalTop(context) :
6853 media.evalNested(context);
6855 Media.prototype.evalTop = function (context) {
6858 // Render all dependent Media blocks.
6859 if (context.mediaBlocks.length > 1) {
6860 var selectors = (new Selector([], null, null, this.index, this.currentFileInfo)).createEmptySelectors();
6861 result = new Ruleset(selectors, context.mediaBlocks);
6862 result.multiMedia = true;
6863 result.copyVisibilityInfo(this.visibilityInfo());
6866 delete context.mediaBlocks;
6867 delete context.mediaPath;
6871 Media.prototype.evalNested = function (context) {
6873 path = context.mediaPath.concat([this]);
6875 // Extract the media-query conditions separated with `,` (OR).
6876 for (i = 0; i < path.length; i++) {
6877 value = path[i].features instanceof Value ?
6878 path[i].features.value : path[i].features;
6879 path[i] = Array.isArray(value) ? value : [value];
6882 // Trace all permutations to generate the resulting media-query.
6884 // (a, b and c) with nested (d, e) ->
6889 this.features = new Value(this.permute(path).map(function (path) {
6890 path = path.map(function (fragment) {
6891 return fragment.toCSS ? fragment : new Anonymous(fragment);
6894 for (i = path.length - 1; i > 0; i--) {
6895 path.splice(i, 0, new Anonymous("and"));
6898 return new Expression(path);
6901 // Fake a tree-node that doesn't output anything.
6902 return new Ruleset([], []);
6904 Media.prototype.permute = function (arr) {
6905 if (arr.length === 0) {
6907 } else if (arr.length === 1) {
6911 var rest = this.permute(arr.slice(1));
6912 for (var i = 0; i < rest.length; i++) {
6913 for (var j = 0; j < arr[0].length; j++) {
6914 result.push([arr[0][j]].concat(rest[i]));
6920 Media.prototype.bubbleSelectors = function (selectors) {
6924 this.rules = [new Ruleset(selectors.slice(0), [this.rules[0]])];
6926 module.exports = Media;
6928 },{"./anonymous":46,"./directive":57,"./expression":59,"./ruleset":76,"./selector":77,"./value":81}],67:[function(require,module,exports){
6929 var Node = require("./node"),
6930 Selector = require("./selector"),
6931 MixinDefinition = require("./mixin-definition"),
6932 defaultFunc = require("../functions/default");
6934 var MixinCall = function (elements, args, index, currentFileInfo, important) {
6935 this.selector = new Selector(elements);
6936 this.arguments = args || [];
6938 this.currentFileInfo = currentFileInfo;
6939 this.important = important;
6940 this.allowRoot = true;
6942 MixinCall.prototype = new Node();
6943 MixinCall.prototype.type = "MixinCall";
6944 MixinCall.prototype.accept = function (visitor) {
6945 if (this.selector) {
6946 this.selector = visitor.visit(this.selector);
6948 if (this.arguments.length) {
6949 this.arguments = visitor.visitArray(this.arguments);
6952 MixinCall.prototype.eval = function (context) {
6953 var mixins, mixin, mixinPath, args = [], arg, argValue,
6954 rules = [], match = false, i, m, f, isRecursive, isOneFound,
6955 candidates = [], candidate, conditionResult = [], defaultResult, defFalseEitherCase = -1,
6956 defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset, noArgumentsFilter;
6958 function calcDefGroup(mixin, mixinPath) {
6959 var f, p, namespace;
6961 for (f = 0; f < 2; f++) {
6962 conditionResult[f] = true;
6963 defaultFunc.value(f);
6964 for (p = 0; p < mixinPath.length && conditionResult[f]; p++) {
6965 namespace = mixinPath[p];
6966 if (namespace.matchCondition) {
6967 conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context);
6970 if (mixin.matchCondition) {
6971 conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context);
6974 if (conditionResult[0] || conditionResult[1]) {
6975 if (conditionResult[0] != conditionResult[1]) {
6976 return conditionResult[1] ?
6982 return defFalseEitherCase;
6985 for (i = 0; i < this.arguments.length; i++) {
6986 arg = this.arguments[i];
6987 argValue = arg.value.eval(context);
6988 if (arg.expand && Array.isArray(argValue.value)) {
6989 argValue = argValue.value;
6990 for (m = 0; m < argValue.length; m++) {
6991 args.push({value: argValue[m]});
6994 args.push({name: arg.name, value: argValue});
6998 noArgumentsFilter = function(rule) {return rule.matchArgs(null, context);};
7000 for (i = 0; i < context.frames.length; i++) {
7001 if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).length > 0) {
7004 // To make `default()` function independent of definition order we have two "subpasses" here.
7005 // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
7006 // and build candidate list with corresponding flags. Then, when we know all possible matches,
7007 // we make a final decision.
7009 for (m = 0; m < mixins.length; m++) {
7010 mixin = mixins[m].rule;
7011 mixinPath = mixins[m].path;
7012 isRecursive = false;
7013 for (f = 0; f < context.frames.length; f++) {
7014 if ((!(mixin instanceof MixinDefinition)) && mixin === (context.frames[f].originalRuleset || context.frames[f])) {
7023 if (mixin.matchArgs(args, context)) {
7024 candidate = {mixin: mixin, group: calcDefGroup(mixin, mixinPath)};
7026 if (candidate.group !== defFalseEitherCase) {
7027 candidates.push(candidate);
7034 defaultFunc.reset();
7037 for (m = 0; m < candidates.length; m++) {
7038 count[candidates[m].group]++;
7041 if (count[defNone] > 0) {
7042 defaultResult = defFalse;
7044 defaultResult = defTrue;
7045 if ((count[defTrue] + count[defFalse]) > 1) {
7046 throw { type: 'Runtime',
7047 message: 'Ambiguous use of `default()` found when matching for `' + this.format(args) + '`',
7048 index: this.index, filename: this.currentFileInfo.filename };
7052 for (m = 0; m < candidates.length; m++) {
7053 candidate = candidates[m].group;
7054 if ((candidate === defNone) || (candidate === defaultResult)) {
7056 mixin = candidates[m].mixin;
7057 if (!(mixin instanceof MixinDefinition)) {
7058 originalRuleset = mixin.originalRuleset || mixin;
7059 mixin = new MixinDefinition("", [], mixin.rules, null, false, null, originalRuleset.visibilityInfo());
7060 mixin.originalRuleset = originalRuleset;
7062 var newRules = mixin.evalCall(context, args, this.important).rules;
7063 this._setVisibilityToReplacement(newRules);
7064 Array.prototype.push.apply(rules, newRules);
7066 throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
7077 throw { type: 'Runtime',
7078 message: 'No matching definition was found for `' + this.format(args) + '`',
7079 index: this.index, filename: this.currentFileInfo.filename };
7081 throw { type: 'Name',
7082 message: this.selector.toCSS().trim() + " is undefined",
7083 index: this.index, filename: this.currentFileInfo.filename };
7087 MixinCall.prototype._setVisibilityToReplacement = function (replacement) {
7089 if (this.blocksVisibility()) {
7090 for (i = 0; i < replacement.length; i++) {
7091 rule = replacement[i];
7092 rule.addVisibilityBlock();
7096 MixinCall.prototype.format = function (args) {
7097 return this.selector.toCSS().trim() + '(' +
7098 (args ? args.map(function (a) {
7101 argValue += a.name + ":";
7103 if (a.value.toCSS) {
7104 argValue += a.value.toCSS();
7109 }).join(', ') : "") + ")";
7111 module.exports = MixinCall;
7113 },{"../functions/default":20,"./mixin-definition":68,"./node":70,"./selector":77}],68:[function(require,module,exports){
7114 var Selector = require("./selector"),
7115 Element = require("./element"),
7116 Ruleset = require("./ruleset"),
7117 Rule = require("./rule"),
7118 Expression = require("./expression"),
7119 contexts = require("../contexts");
7121 var Definition = function (name, params, rules, condition, variadic, frames, visibilityInfo) {
7123 this.selectors = [new Selector([new Element(null, name, this.index, this.currentFileInfo)])];
7124 this.params = params;
7125 this.condition = condition;
7126 this.variadic = variadic;
7127 this.arity = params.length;
7130 var optionalParameters = [];
7131 this.required = params.reduce(function (count, p) {
7132 if (!p.name || (p.name && !p.value)) {
7136 optionalParameters.push(p.name);
7140 this.optionalParameters = optionalParameters;
7141 this.frames = frames;
7142 this.copyVisibilityInfo(visibilityInfo);
7143 this.allowRoot = true;
7145 Definition.prototype = new Ruleset();
7146 Definition.prototype.type = "MixinDefinition";
7147 Definition.prototype.evalFirst = true;
7148 Definition.prototype.accept = function (visitor) {
7149 if (this.params && this.params.length) {
7150 this.params = visitor.visitArray(this.params);
7152 this.rules = visitor.visitArray(this.rules);
7153 if (this.condition) {
7154 this.condition = visitor.visit(this.condition);
7157 Definition.prototype.evalParams = function (context, mixinEnv, args, evaldArguments) {
7158 /*jshint boss:true */
7159 var frame = new Ruleset(null, null),
7161 params = this.params.slice(0),
7162 i, j, val, name, isNamedFound, argIndex, argsLength = 0;
7164 if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) {
7165 frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit();
7167 mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames));
7170 args = args.slice(0);
7171 argsLength = args.length;
7173 for (i = 0; i < argsLength; i++) {
7175 if (name = (arg && arg.name)) {
7176 isNamedFound = false;
7177 for (j = 0; j < params.length; j++) {
7178 if (!evaldArguments[j] && name === params[j].name) {
7179 evaldArguments[j] = arg.value.eval(context);
7180 frame.prependRule(new Rule(name, arg.value.eval(context)));
7181 isNamedFound = true;
7190 throw { type: 'Runtime', message: "Named argument for " + this.name +
7191 ' ' + args[i].name + ' not found' };
7197 for (i = 0; i < params.length; i++) {
7198 if (evaldArguments[i]) { continue; }
7200 arg = args && args[argIndex];
7202 if (name = params[i].name) {
7203 if (params[i].variadic) {
7205 for (j = argIndex; j < argsLength; j++) {
7206 varargs.push(args[j].value.eval(context));
7208 frame.prependRule(new Rule(name, new Expression(varargs).eval(context)));
7210 val = arg && arg.value;
7212 val = val.eval(context);
7213 } else if (params[i].value) {
7214 val = params[i].value.eval(mixinEnv);
7217 throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
7218 ' (' + argsLength + ' for ' + this.arity + ')' };
7221 frame.prependRule(new Rule(name, val));
7222 evaldArguments[i] = val;
7226 if (params[i].variadic && args) {
7227 for (j = argIndex; j < argsLength; j++) {
7228 evaldArguments[j] = args[j].value.eval(context);
7236 Definition.prototype.makeImportant = function() {
7237 var rules = !this.rules ? this.rules : this.rules.map(function (r) {
7238 if (r.makeImportant) {
7239 return r.makeImportant(true);
7244 var result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames);
7247 Definition.prototype.eval = function (context) {
7248 return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || context.frames.slice(0));
7250 Definition.prototype.evalCall = function (context, args, important) {
7251 var _arguments = [],
7252 mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames,
7253 frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments),
7256 frame.prependRule(new Rule('@arguments', new Expression(_arguments).eval(context)));
7258 rules = this.rules.slice(0);
7260 ruleset = new Ruleset(null, rules);
7261 ruleset.originalRuleset = this;
7262 ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames)));
7264 ruleset = ruleset.makeImportant();
7268 Definition.prototype.matchCondition = function (args, context) {
7269 if (this.condition && !this.condition.eval(
7270 new contexts.Eval(context,
7271 [this.evalParams(context, /* the parameter variables*/
7272 new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])]
7273 .concat(this.frames || []) // the parent namespace/mixin frames
7274 .concat(context.frames)))) { // the current environment frames
7279 Definition.prototype.matchArgs = function (args, context) {
7280 var allArgsCnt = (args && args.length) || 0, len, optionalParameters = this.optionalParameters;
7281 var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) {
7282 if (optionalParameters.indexOf(p.name) < 0) {
7289 if (! this.variadic) {
7290 if (requiredArgsCnt < this.required) {
7293 if (allArgsCnt > this.params.length) {
7297 if (requiredArgsCnt < (this.required - 1)) {
7303 len = Math.min(requiredArgsCnt, this.arity);
7305 for (var i = 0; i < len; i++) {
7306 if (!this.params[i].name && !this.params[i].variadic) {
7307 if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) {
7314 module.exports = Definition;
7316 },{"../contexts":11,"./element":58,"./expression":59,"./rule":74,"./ruleset":76,"./selector":77}],69:[function(require,module,exports){
7317 var Node = require("./node"),
7318 Operation = require("./operation"),
7319 Dimension = require("./dimension");
7321 var Negative = function (node) {
7324 Negative.prototype = new Node();
7325 Negative.prototype.type = "Negative";
7326 Negative.prototype.genCSS = function (context, output) {
7328 this.value.genCSS(context, output);
7330 Negative.prototype.eval = function (context) {
7331 if (context.isMathOn()) {
7332 return (new Operation('*', [new Dimension(-1), this.value])).eval(context);
7334 return new Negative(this.value.eval(context));
7336 module.exports = Negative;
7338 },{"./dimension":56,"./node":70,"./operation":71}],70:[function(require,module,exports){
7339 var Node = function() {
7341 Node.prototype.toCSS = function (context) {
7343 this.genCSS(context, {
7344 add: function(chunk, fileInfo, index) {
7347 isEmpty: function () {
7348 return strs.length === 0;
7351 return strs.join('');
7353 Node.prototype.genCSS = function (context, output) {
7354 output.add(this.value);
7356 Node.prototype.accept = function (visitor) {
7357 this.value = visitor.visit(this.value);
7359 Node.prototype.eval = function () { return this; };
7360 Node.prototype._operate = function (context, op, a, b) {
7362 case '+': return a + b;
7363 case '-': return a - b;
7364 case '*': return a * b;
7365 case '/': return a / b;
7368 Node.prototype.fround = function(context, value) {
7369 var precision = context && context.numPrecision;
7370 //add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999....) are properly rounded...
7371 return (precision == null) ? value : Number((value + 2e-16).toFixed(precision));
7373 Node.compare = function (a, b) {
7378 and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */
7381 // for "symmetric results" force toCSS-based comparison
7382 // of Quoted or Anonymous if either value is one of those
7383 !(b.type === "Quoted" || b.type === "Anonymous")) {
7384 return a.compare(b);
7385 } else if (b.compare) {
7386 return -b.compare(a);
7387 } else if (a.type !== b.type) {
7393 if (!Array.isArray(a)) {
7394 return a === b ? 0 : undefined;
7396 if (a.length !== b.length) {
7399 for (var i = 0; i < a.length; i++) {
7400 if (Node.compare(a[i], b[i]) !== 0) {
7407 Node.numericCompare = function (a, b) {
7410 : a > b ? 1 : undefined;
7412 // Returns true if this node represents root of ast imported by reference
7413 Node.prototype.blocksVisibility = function () {
7414 if (this.visibilityBlocks == null) {
7415 this.visibilityBlocks = 0;
7417 return this.visibilityBlocks !== 0;
7419 Node.prototype.addVisibilityBlock = function () {
7420 if (this.visibilityBlocks == null) {
7421 this.visibilityBlocks = 0;
7423 this.visibilityBlocks = this.visibilityBlocks + 1;
7425 Node.prototype.removeVisibilityBlock = function () {
7426 if (this.visibilityBlocks == null) {
7427 this.visibilityBlocks = 0;
7429 this.visibilityBlocks = this.visibilityBlocks - 1;
7431 //Turns on node visibility - if called node will be shown in output regardless
7432 //of whether it comes from import by reference or not
7433 Node.prototype.ensureVisibility = function () {
7434 this.nodeVisible = true;
7436 //Turns off node visibility - if called node will NOT be shown in output regardless
7437 //of whether it comes from import by reference or not
7438 Node.prototype.ensureInvisibility = function () {
7439 this.nodeVisible = false;
7442 // false - the node must not be visible
7443 // true - the node must be visible
7444 // undefined or null - the node has the same visibility as its parent
7445 Node.prototype.isVisible = function () {
7446 return this.nodeVisible;
7448 Node.prototype.visibilityInfo = function() {
7450 visibilityBlocks: this.visibilityBlocks,
7451 nodeVisible: this.nodeVisible
7454 Node.prototype.copyVisibilityInfo = function(info) {
7458 this.visibilityBlocks = info.visibilityBlocks;
7459 this.nodeVisible = info.nodeVisible;
7461 module.exports = Node;
7463 },{}],71:[function(require,module,exports){
7464 var Node = require("./node"),
7465 Color = require("./color"),
7466 Dimension = require("./dimension");
7468 var Operation = function (op, operands, isSpaced) {
7469 this.op = op.trim();
7470 this.operands = operands;
7471 this.isSpaced = isSpaced;
7473 Operation.prototype = new Node();
7474 Operation.prototype.type = "Operation";
7475 Operation.prototype.accept = function (visitor) {
7476 this.operands = visitor.visit(this.operands);
7478 Operation.prototype.eval = function (context) {
7479 var a = this.operands[0].eval(context),
7480 b = this.operands[1].eval(context);
7482 if (context.isMathOn()) {
7483 if (a instanceof Dimension && b instanceof Color) {
7486 if (b instanceof Dimension && a instanceof Color) {
7490 throw { type: "Operation",
7491 message: "Operation on an invalid type" };
7494 return a.operate(context, this.op, b);
7496 return new Operation(this.op, [a, b], this.isSpaced);
7499 Operation.prototype.genCSS = function (context, output) {
7500 this.operands[0].genCSS(context, output);
7501 if (this.isSpaced) {
7504 output.add(this.op);
7505 if (this.isSpaced) {
7508 this.operands[1].genCSS(context, output);
7511 module.exports = Operation;
7513 },{"./color":50,"./dimension":56,"./node":70}],72:[function(require,module,exports){
7514 var Node = require("./node");
7516 var Paren = function (node) {
7519 Paren.prototype = new Node();
7520 Paren.prototype.type = "Paren";
7521 Paren.prototype.genCSS = function (context, output) {
7523 this.value.genCSS(context, output);
7526 Paren.prototype.eval = function (context) {
7527 return new Paren(this.value.eval(context));
7529 module.exports = Paren;
7531 },{"./node":70}],73:[function(require,module,exports){
7532 var Node = require("./node"),
7533 JsEvalNode = require("./js-eval-node"),
7534 Variable = require("./variable");
7536 var Quoted = function (str, content, escaped, index, currentFileInfo) {
7537 this.escaped = (escaped == null) ? true : escaped;
7538 this.value = content || '';
7539 this.quote = str.charAt(0);
7541 this.currentFileInfo = currentFileInfo;
7543 Quoted.prototype = new JsEvalNode();
7544 Quoted.prototype.type = "Quoted";
7545 Quoted.prototype.genCSS = function (context, output) {
7546 if (!this.escaped) {
7547 output.add(this.quote, this.currentFileInfo, this.index);
7549 output.add(this.value);
7550 if (!this.escaped) {
7551 output.add(this.quote);
7554 Quoted.prototype.containsVariables = function() {
7555 return this.value.match(/(`([^`]+)`)|@\{([\w-]+)\}/);
7557 Quoted.prototype.eval = function (context) {
7558 var that = this, value = this.value;
7559 var javascriptReplacement = function (_, exp) {
7560 return String(that.evaluateJavaScript(exp, context));
7562 var interpolationReplacement = function (_, name) {
7563 var v = new Variable('@' + name, that.index, that.currentFileInfo).eval(context, true);
7564 return (v instanceof Quoted) ? v.value : v.toCSS();
7566 function iterativeReplace(value, regexp, replacementFnc) {
7567 var evaluatedValue = value;
7569 value = evaluatedValue;
7570 evaluatedValue = value.replace(regexp, replacementFnc);
7571 } while (value !== evaluatedValue);
7572 return evaluatedValue;
7574 value = iterativeReplace(value, /`([^`]+)`/g, javascriptReplacement);
7575 value = iterativeReplace(value, /@\{([\w-]+)\}/g, interpolationReplacement);
7576 return new Quoted(this.quote + value + this.quote, value, this.escaped, this.index, this.currentFileInfo);
7578 Quoted.prototype.compare = function (other) {
7579 // when comparing quoted strings allow the quote to differ
7580 if (other.type === "Quoted" && !this.escaped && !other.escaped) {
7581 return Node.numericCompare(this.value, other.value);
7583 return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined;
7586 module.exports = Quoted;
7588 },{"./js-eval-node":64,"./node":70,"./variable":82}],74:[function(require,module,exports){
7589 var Node = require("./node"),
7590 Value = require("./value"),
7591 Keyword = require("./keyword");
7593 var Rule = function (name, value, important, merge, index, currentFileInfo, inline, variable) {
7595 this.value = (value instanceof Node) ? value : new Value([value]); //value instanceof tree.Value || value instanceof tree.Ruleset ??
7596 this.important = important ? ' ' + important.trim() : '';
7599 this.currentFileInfo = currentFileInfo;
7600 this.inline = inline || false;
7601 this.variable = (variable !== undefined) ? variable
7602 : (name.charAt && (name.charAt(0) === '@'));
7603 this.allowRoot = true;
7606 function evalName(context, name) {
7607 var value = "", i, n = name.length,
7608 output = {add: function (s) {value += s;}};
7609 for (i = 0; i < n; i++) {
7610 name[i].eval(context).genCSS(context, output);
7615 Rule.prototype = new Node();
7616 Rule.prototype.type = "Rule";
7617 Rule.prototype.genCSS = function (context, output) {
7618 output.add(this.name + (context.compress ? ':' : ': '), this.currentFileInfo, this.index);
7620 this.value.genCSS(context, output);
7623 e.index = this.index;
7624 e.filename = this.currentFileInfo.filename;
7627 output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? "" : ";"), this.currentFileInfo, this.index);
7629 Rule.prototype.eval = function (context) {
7630 var strictMathBypass = false, name = this.name, evaldValue, variable = this.variable;
7631 if (typeof name !== "string") {
7632 // expand 'primitive' name directly to get
7633 // things faster (~10% for benchmark.less):
7634 name = (name.length === 1) && (name[0] instanceof Keyword) ?
7635 name[0].value : evalName(context, name);
7636 variable = false; // never treat expanded interpolation as new variable name
7638 if (name === "font" && !context.strictMath) {
7639 strictMathBypass = true;
7640 context.strictMath = true;
7643 context.importantScope.push({});
7644 evaldValue = this.value.eval(context);
7646 if (!this.variable && evaldValue.type === "DetachedRuleset") {
7647 throw { message: "Rulesets cannot be evaluated on a property.",
7648 index: this.index, filename: this.currentFileInfo.filename };
7650 var important = this.important,
7651 importantResult = context.importantScope.pop();
7652 if (!important && importantResult.important) {
7653 important = importantResult.important;
7656 return new Rule(name,
7660 this.index, this.currentFileInfo, this.inline,
7664 if (typeof e.index !== 'number') {
7665 e.index = this.index;
7666 e.filename = this.currentFileInfo.filename;
7671 if (strictMathBypass) {
7672 context.strictMath = false;
7676 Rule.prototype.makeImportant = function () {
7677 return new Rule(this.name,
7681 this.index, this.currentFileInfo, this.inline);
7684 module.exports = Rule;
7685 },{"./keyword":65,"./node":70,"./value":81}],75:[function(require,module,exports){
7686 var Node = require("./node"),
7687 Variable = require("./variable");
7689 var RulesetCall = function (variable) {
7690 this.variable = variable;
7691 this.allowRoot = true;
7693 RulesetCall.prototype = new Node();
7694 RulesetCall.prototype.type = "RulesetCall";
7695 RulesetCall.prototype.eval = function (context) {
7696 var detachedRuleset = new Variable(this.variable).eval(context);
7697 return detachedRuleset.callEval(context);
7699 module.exports = RulesetCall;
7701 },{"./node":70,"./variable":82}],76:[function(require,module,exports){
7702 var Node = require("./node"),
7703 Rule = require("./rule"),
7704 Selector = require("./selector"),
7705 Element = require("./element"),
7706 Paren = require("./paren"),
7707 contexts = require("../contexts"),
7708 globalFunctionRegistry = require("../functions/function-registry"),
7709 defaultFunc = require("../functions/default"),
7710 getDebugInfo = require("./debug-info");
7712 var Ruleset = function (selectors, rules, strictImports, visibilityInfo) {
7713 this.selectors = selectors;
7716 this.strictImports = strictImports;
7717 this.copyVisibilityInfo(visibilityInfo);
7718 this.allowRoot = true;
7720 Ruleset.prototype = new Node();
7721 Ruleset.prototype.type = "Ruleset";
7722 Ruleset.prototype.isRuleset = true;
7723 Ruleset.prototype.isRulesetLike = true;
7724 Ruleset.prototype.accept = function (visitor) {
7726 this.paths = visitor.visitArray(this.paths, true);
7727 } else if (this.selectors) {
7728 this.selectors = visitor.visitArray(this.selectors);
7730 if (this.rules && this.rules.length) {
7731 this.rules = visitor.visitArray(this.rules);
7734 Ruleset.prototype.eval = function (context) {
7735 var thisSelectors = this.selectors, selectors,
7736 selCnt, selector, i, hasOnePassingSelector = false;
7738 if (thisSelectors && (selCnt = thisSelectors.length)) {
7742 message: "it is currently only allowed in parametric mixin guards,"
7744 for (i = 0; i < selCnt; i++) {
7745 selector = thisSelectors[i].eval(context);
7746 selectors.push(selector);
7747 if (selector.evaldCondition) {
7748 hasOnePassingSelector = true;
7751 defaultFunc.reset();
7753 hasOnePassingSelector = true;
7756 var rules = this.rules ? this.rules.slice(0) : null,
7757 ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()),
7760 ruleset.originalRuleset = this;
7761 ruleset.root = this.root;
7762 ruleset.firstRoot = this.firstRoot;
7763 ruleset.allowImports = this.allowImports;
7765 if (this.debugInfo) {
7766 ruleset.debugInfo = this.debugInfo;
7769 if (!hasOnePassingSelector) {
7773 // inherit a function registry from the frames stack when possible;
7774 // otherwise from the global registry
7775 ruleset.functionRegistry = (function (frames) {
7779 for ( ; i !== n ; ++i ) {
7780 found = frames[ i ].functionRegistry;
7781 if ( found ) { return found; }
7783 return globalFunctionRegistry;
7784 }(context.frames)).inherit();
7786 // push the current ruleset to the frames stack
7787 var ctxFrames = context.frames;
7788 ctxFrames.unshift(ruleset);
7790 // currrent selectors
7791 var ctxSelectors = context.selectors;
7792 if (!ctxSelectors) {
7793 context.selectors = ctxSelectors = [];
7795 ctxSelectors.unshift(this.selectors);
7798 if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
7799 ruleset.evalImports(context);
7802 // Store the frames around mixin definitions,
7803 // so they can be evaluated like closures when the time comes.
7804 var rsRules = ruleset.rules, rsRuleCnt = rsRules ? rsRules.length : 0;
7805 for (i = 0; i < rsRuleCnt; i++) {
7806 if (rsRules[i].evalFirst) {
7807 rsRules[i] = rsRules[i].eval(context);
7811 var mediaBlockCount = (context.mediaBlocks && context.mediaBlocks.length) || 0;
7813 // Evaluate mixin calls.
7814 for (i = 0; i < rsRuleCnt; i++) {
7815 if (rsRules[i].type === "MixinCall") {
7816 /*jshint loopfunc:true */
7817 rules = rsRules[i].eval(context).filter(function(r) {
7818 if ((r instanceof Rule) && r.variable) {
7819 // do not pollute the scope if the variable is
7820 // already there. consider returning false here
7821 // but we need a way to "return" variable from mixins
7822 return !(ruleset.variable(r.name));
7826 rsRules.splice.apply(rsRules, [i, 1].concat(rules));
7827 rsRuleCnt += rules.length - 1;
7828 i += rules.length - 1;
7829 ruleset.resetCache();
7830 } else if (rsRules[i].type === "RulesetCall") {
7831 /*jshint loopfunc:true */
7832 rules = rsRules[i].eval(context).rules.filter(function(r) {
7833 if ((r instanceof Rule) && r.variable) {
7834 // do not pollute the scope at all
7839 rsRules.splice.apply(rsRules, [i, 1].concat(rules));
7840 rsRuleCnt += rules.length - 1;
7841 i += rules.length - 1;
7842 ruleset.resetCache();
7846 // Evaluate everything else
7847 for (i = 0; i < rsRules.length; i++) {
7849 if (!rule.evalFirst) {
7850 rsRules[i] = rule = rule.eval ? rule.eval(context) : rule;
7854 // Evaluate everything else
7855 for (i = 0; i < rsRules.length; i++) {
7857 // for rulesets, check if it is a css guard and can be removed
7858 if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) {
7859 // check if it can be folded in (e.g. & where)
7860 if (rule.selectors[0].isJustParentSelector()) {
7861 rsRules.splice(i--, 1);
7863 for (var j = 0; j < rule.rules.length; j++) {
7864 subRule = rule.rules[j];
7865 subRule.copyVisibilityInfo(rule.visibilityInfo());
7866 if (!(subRule instanceof Rule) || !subRule.variable) {
7867 rsRules.splice(++i, 0, subRule);
7876 ctxSelectors.shift();
7878 if (context.mediaBlocks) {
7879 for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) {
7880 context.mediaBlocks[i].bubbleSelectors(selectors);
7886 Ruleset.prototype.evalImports = function(context) {
7887 var rules = this.rules, i, importRules;
7888 if (!rules) { return; }
7890 for (i = 0; i < rules.length; i++) {
7891 if (rules[i].type === "Import") {
7892 importRules = rules[i].eval(context);
7893 if (importRules && (importRules.length || importRules.length === 0)) {
7894 rules.splice.apply(rules, [i, 1].concat(importRules));
7895 i+= importRules.length - 1;
7897 rules.splice(i, 1, importRules);
7903 Ruleset.prototype.makeImportant = function() {
7904 var result = new Ruleset(this.selectors, this.rules.map(function (r) {
7905 if (r.makeImportant) {
7906 return r.makeImportant();
7910 }), this.strictImports, this.visibilityInfo());
7914 Ruleset.prototype.matchArgs = function (args) {
7915 return !args || args.length === 0;
7917 // lets you call a css selector with a guard
7918 Ruleset.prototype.matchCondition = function (args, context) {
7919 var lastSelector = this.selectors[this.selectors.length - 1];
7920 if (!lastSelector.evaldCondition) {
7923 if (lastSelector.condition &&
7924 !lastSelector.condition.eval(
7925 new contexts.Eval(context,
7931 Ruleset.prototype.resetCache = function () {
7932 this._rulesets = null;
7933 this._variables = null;
7936 Ruleset.prototype.variables = function () {
7937 if (!this._variables) {
7938 this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) {
7939 if (r instanceof Rule && r.variable === true) {
7942 // when evaluating variables in an import statement, imports have not been eval'd
7943 // so we need to go inside import statements.
7944 // guard against root being a string (in the case of inlined less)
7945 if (r.type === "Import" && r.root && r.root.variables) {
7946 var vars = r.root.variables();
7947 for (var name in vars) {
7948 if (vars.hasOwnProperty(name)) {
7949 hash[name] = vars[name];
7956 return this._variables;
7958 Ruleset.prototype.variable = function (name) {
7959 return this.variables()[name];
7961 Ruleset.prototype.rulesets = function () {
7962 if (!this.rules) { return []; }
7964 var filtRules = [], rules = this.rules, cnt = rules.length,
7967 for (i = 0; i < cnt; i++) {
7969 if (rule.isRuleset) {
7970 filtRules.push(rule);
7976 Ruleset.prototype.prependRule = function (rule) {
7977 var rules = this.rules;
7979 rules.unshift(rule);
7981 this.rules = [ rule ];
7984 Ruleset.prototype.find = function (selector, self, filter) {
7985 self = self || this;
7986 var rules = [], match, foundMixins,
7987 key = selector.toCSS();
7989 if (key in this._lookups) { return this._lookups[key]; }
7991 this.rulesets().forEach(function (rule) {
7992 if (rule !== self) {
7993 for (var j = 0; j < rule.selectors.length; j++) {
7994 match = selector.match(rule.selectors[j]);
7996 if (selector.elements.length > match) {
7997 if (!filter || filter(rule)) {
7998 foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter);
7999 for (var i = 0; i < foundMixins.length; ++i) {
8000 foundMixins[i].path.push(rule);
8002 Array.prototype.push.apply(rules, foundMixins);
8005 rules.push({ rule: rule, path: []});
8012 this._lookups[key] = rules;
8015 Ruleset.prototype.genCSS = function (context, output) {
8017 charsetRuleNodes = [],
8019 debugInfo, // Line number debugging
8023 context.tabLevel = (context.tabLevel || 0);
8029 var tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(" "),
8030 tabSetStr = context.compress ? '' : Array(context.tabLevel).join(" "),
8033 function isRulesetLikeNode(rule) {
8034 // if it has nested rules, then it should be treated like a ruleset
8035 // medias and comments do not have nested rules, but should be treated like rulesets anyway
8036 // some directives and anonymous nodes are ruleset like, others are not
8037 if (typeof rule.isRulesetLike === "boolean") {
8038 return rule.isRulesetLike;
8039 } else if (typeof rule.isRulesetLike === "function") {
8040 return rule.isRulesetLike();
8043 //anything else is assumed to be a rule
8047 var charsetNodeIndex = 0;
8048 var importNodeIndex = 0;
8049 for (i = 0; i < this.rules.length; i++) {
8050 rule = this.rules[i];
8051 if (rule.type === "Comment") {
8052 if (importNodeIndex === i) {
8055 ruleNodes.push(rule);
8056 } else if (rule.isCharset && rule.isCharset()) {
8057 ruleNodes.splice(charsetNodeIndex, 0, rule);
8060 } else if (rule.type === "Import") {
8061 ruleNodes.splice(importNodeIndex, 0, rule);
8064 ruleNodes.push(rule);
8067 ruleNodes = charsetRuleNodes.concat(ruleNodes);
8069 // If this is the root node, we don't render
8070 // a selector, or {}.
8072 debugInfo = getDebugInfo(context, this, tabSetStr);
8075 output.add(debugInfo);
8076 output.add(tabSetStr);
8079 var paths = this.paths, pathCnt = paths.length,
8082 sep = context.compress ? ',' : (',\n' + tabSetStr);
8084 for (i = 0; i < pathCnt; i++) {
8086 if (!(pathSubCnt = path.length)) { continue; }
8087 if (i > 0) { output.add(sep); }
8089 context.firstSelector = true;
8090 path[0].genCSS(context, output);
8092 context.firstSelector = false;
8093 for (j = 1; j < pathSubCnt; j++) {
8094 path[j].genCSS(context, output);
8098 output.add((context.compress ? '{' : ' {\n') + tabRuleStr);
8101 // Compile rules and rulesets
8102 for (i = 0; i < ruleNodes.length; i++) {
8103 rule = ruleNodes[i];
8105 if (i + 1 === ruleNodes.length) {
8106 context.lastRule = true;
8109 var currentLastRule = context.lastRule;
8110 if (isRulesetLikeNode(rule)) {
8111 context.lastRule = false;
8115 rule.genCSS(context, output);
8116 } else if (rule.value) {
8117 output.add(rule.value.toString());
8120 context.lastRule = currentLastRule;
8122 if (!context.lastRule) {
8123 output.add(context.compress ? '' : ('\n' + tabRuleStr));
8125 context.lastRule = false;
8130 output.add((context.compress ? '}' : '\n' + tabSetStr + '}'));
8134 if (!output.isEmpty() && !context.compress && this.firstRoot) {
8139 Ruleset.prototype.joinSelectors = function (paths, context, selectors) {
8140 for (var s = 0; s < selectors.length; s++) {
8141 this.joinSelector(paths, context, selectors[s]);
8145 Ruleset.prototype.joinSelector = function (paths, context, selector) {
8147 function createParenthesis(elementsToPak, originalElement) {
8148 var replacementParen, j;
8149 if (elementsToPak.length === 0) {
8150 replacementParen = new Paren(elementsToPak[0]);
8152 var insideParent = [];
8153 for (j = 0; j < elementsToPak.length; j++) {
8154 insideParent.push(new Element(null, elementsToPak[j], originalElement.index, originalElement.currentFileInfo));
8156 replacementParen = new Paren(new Selector(insideParent));
8158 return replacementParen;
8161 function createSelector(containedElement, originalElement) {
8162 var element, selector;
8163 element = new Element(null, containedElement, originalElement.index, originalElement.currentFileInfo);
8164 selector = new Selector([element]);
8168 // joins selector path from `beginningPath` with selector path in `addPath`
8169 // `replacedElement` contains element that is being replaced by `addPath`
8170 // returns concatenated path
8171 function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) {
8172 var newSelectorPath, lastSelector, newJoinedSelector;
8173 // our new selector path
8174 newSelectorPath = [];
8176 //construct the joined selector - if & is the first thing this will be empty,
8177 // if not newJoinedSelector will be the last set of elements in the selector
8178 if (beginningPath.length > 0) {
8179 newSelectorPath = beginningPath.slice(0);
8180 lastSelector = newSelectorPath.pop();
8181 newJoinedSelector = originalSelector.createDerived(lastSelector.elements.slice(0));
8184 newJoinedSelector = originalSelector.createDerived([]);
8187 if (addPath.length > 0) {
8188 // /deep/ is a combinator that is valid without anything in front of it
8189 // so if the & does not have a combinator that is "" or " " then
8190 // and there is a combinator on the parent, then grab that.
8191 // this also allows + a { & .b { .a & { ... though not sure why you would want to do that
8192 var combinator = replacedElement.combinator, parentEl = addPath[0].elements[0];
8193 if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
8194 combinator = parentEl.combinator;
8196 // join the elements so far with the first part of the parent
8197 newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement.index, replacedElement.currentFileInfo));
8198 newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1));
8201 // now add the joined selector - but only if it is not empty
8202 if (newJoinedSelector.elements.length !== 0) {
8203 newSelectorPath.push(newJoinedSelector);
8206 //put together the parent selectors after the join (e.g. the rest of the parent)
8207 if (addPath.length > 1) {
8208 var restOfPath = addPath.slice(1);
8209 restOfPath = restOfPath.map(function (selector) {
8210 return selector.createDerived(selector.elements, []);
8212 newSelectorPath = newSelectorPath.concat(restOfPath);
8214 return newSelectorPath;
8217 // joins selector path from `beginningPath` with every selector path in `addPaths` array
8218 // `replacedElement` contains element that is being replaced by `addPath`
8219 // returns array with all concatenated paths
8220 function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) {
8222 for (j = 0; j < beginningPath.length; j++) {
8223 var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector);
8224 result.push(newSelectorPath);
8229 function mergeElementsOnToSelectors(elements, selectors) {
8232 if (elements.length === 0) {
8235 if (selectors.length === 0) {
8236 selectors.push([ new Selector(elements) ]);
8240 for (i = 0; i < selectors.length; i++) {
8243 // if the previous thing in sel is a parent this needs to join on to it
8244 if (sel.length > 0) {
8245 sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
8248 sel.push(new Selector(elements));
8253 // replace all parent selectors inside `inSelector` by content of `context` array
8254 // resulting selectors are returned inside `paths` array
8255 // returns true if `inSelector` contained at least one parent selector
8256 function replaceParentSelector(paths, context, inSelector) {
8257 // The paths are [[Selector]]
8258 // The first list is a list of comma separated selectors
8259 // The inner list is a list of inheritance separated selectors
8265 // == [[.a] [.c]] [[.b] [.c]]
8267 var i, j, k, currentElements, newSelectors, selectorsMultiplied, sel, el, hadParentSelector = false, length, lastSelector;
8268 function findNestedSelector(element) {
8270 if (element.value.type !== 'Paren') {
8274 maybeSelector = element.value.value;
8275 if (maybeSelector.type !== 'Selector') {
8279 return maybeSelector;
8282 // the elements from the current selector so far
8283 currentElements = [];
8284 // the current list of new selectors to add to the path.
8285 // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
8291 for (i = 0; i < inSelector.elements.length; i++) {
8292 el = inSelector.elements[i];
8293 // non parent reference elements just get added
8294 if (el.value !== "&") {
8295 var nestedSelector = findNestedSelector(el);
8296 if (nestedSelector != null) {
8297 // merge the current list of non parent selector elements
8298 // on to the current list of selectors to add
8299 mergeElementsOnToSelectors(currentElements, newSelectors);
8301 var nestedPaths = [], replaced, replacedNewSelectors = [];
8302 replaced = replaceParentSelector(nestedPaths, context, nestedSelector);
8303 hadParentSelector = hadParentSelector || replaced;
8304 //the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors
8305 for (k = 0; k < nestedPaths.length; k++) {
8306 var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el);
8307 addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);
8309 newSelectors = replacedNewSelectors;
8310 currentElements = [];
8313 currentElements.push(el);
8317 hadParentSelector = true;
8318 // the new list of selectors to add
8319 selectorsMultiplied = [];
8321 // merge the current list of non parent selector elements
8322 // on to the current list of selectors to add
8323 mergeElementsOnToSelectors(currentElements, newSelectors);
8325 // loop through our current selectors
8326 for (j = 0; j < newSelectors.length; j++) {
8327 sel = newSelectors[j];
8328 // if we don't have any parent paths, the & might be in a mixin so that it can be used
8329 // whether there are parents or not
8330 if (context.length === 0) {
8331 // the combinator used on el should now be applied to the next element instead so that
8333 if (sel.length > 0) {
8334 sel[0].elements.push(new Element(el.combinator, '', el.index, el.currentFileInfo));
8336 selectorsMultiplied.push(sel);
8339 // and the parent selectors
8340 for (k = 0; k < context.length; k++) {
8341 // We need to put the current selectors
8342 // then join the last selector's elements on to the parents selectors
8343 var newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector);
8344 // add that to our new set of selectors
8345 selectorsMultiplied.push(newSelectorPath);
8350 // our new selectors has been multiplied, so reset the state
8351 newSelectors = selectorsMultiplied;
8352 currentElements = [];
8356 // if we have any elements left over (e.g. .a& .b == .b)
8357 // add them on to all the current selectors
8358 mergeElementsOnToSelectors(currentElements, newSelectors);
8360 for (i = 0; i < newSelectors.length; i++) {
8361 length = newSelectors[i].length;
8363 paths.push(newSelectors[i]);
8364 lastSelector = newSelectors[i][length - 1];
8365 newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList);
8366 //newSelectors[i][length - 1].copyVisibilityInfo(inSelector.visibilityInfo());
8370 return hadParentSelector;
8373 function deriveSelector(visibilityInfo, deriveFrom) {
8374 var newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition);
8375 newSelector.copyVisibilityInfo(visibilityInfo);
8379 // joinSelector code follows
8380 var i, newPaths, hadParentSelector;
8383 hadParentSelector = replaceParentSelector(newPaths, context, selector);
8385 if (!hadParentSelector) {
8386 if (context.length > 0) {
8388 for (i = 0; i < context.length; i++) {
8389 //var concatenated = [];
8390 //context[i].forEach(function(entry) {
8391 // var newEntry = entry.createDerived(entry.elements, entry.extendList, entry.evaldCondition);
8392 // newEntry.copyVisibilityInfo(selector.visibilityInfo());
8393 // concatenated.push(newEntry);
8395 var concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo()));
8397 concatenated.push(selector);
8398 newPaths.push(concatenated);
8402 newPaths = [[selector]];
8406 for (i = 0; i < newPaths.length; i++) {
8407 paths.push(newPaths[i]);
8411 module.exports = Ruleset;
8413 },{"../contexts":11,"../functions/default":20,"../functions/function-registry":22,"./debug-info":54,"./element":58,"./node":70,"./paren":72,"./rule":74,"./selector":77}],77:[function(require,module,exports){
8414 var Node = require("./node"),
8415 Element = require("./element");
8417 var Selector = function (elements, extendList, condition, index, currentFileInfo, visibilityInfo) {
8418 this.elements = elements;
8419 this.extendList = extendList;
8420 this.condition = condition;
8421 this.currentFileInfo = currentFileInfo || {};
8423 this.evaldCondition = true;
8425 this.copyVisibilityInfo(visibilityInfo);
8427 Selector.prototype = new Node();
8428 Selector.prototype.type = "Selector";
8429 Selector.prototype.accept = function (visitor) {
8430 if (this.elements) {
8431 this.elements = visitor.visitArray(this.elements);
8433 if (this.extendList) {
8434 this.extendList = visitor.visitArray(this.extendList);
8436 if (this.condition) {
8437 this.condition = visitor.visit(this.condition);
8440 Selector.prototype.createDerived = function(elements, extendList, evaldCondition) {
8441 var info = this.visibilityInfo();
8442 evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition;
8443 var newSelector = new Selector(elements, extendList || this.extendList, null, this.index, this.currentFileInfo, info);
8444 newSelector.evaldCondition = evaldCondition;
8445 newSelector.mediaEmpty = this.mediaEmpty;
8448 Selector.prototype.createEmptySelectors = function() {
8449 var el = new Element('', '&', this.index, this.currentFileInfo),
8450 sels = [new Selector([el], null, null, this.index, this.currentFileInfo)];
8451 sels[0].mediaEmpty = true;
8454 Selector.prototype.match = function (other) {
8455 var elements = this.elements,
8456 len = elements.length,
8459 other.CacheElements();
8461 olen = other._elements.length;
8462 if (olen === 0 || len < olen) {
8465 for (i = 0; i < olen; i++) {
8466 if (elements[i].value !== other._elements[i]) {
8472 return olen; // return number of matched elements
8474 Selector.prototype.CacheElements = function() {
8475 if (this._elements) {
8479 var elements = this.elements.map( function(v) {
8480 return v.combinator.value + (v.value.value || v.value);
8481 }).join("").match(/[,&#\*\.\w-]([\w-]|(\\.))*/g);
8484 if (elements[0] === "&") {
8491 this._elements = elements;
8493 Selector.prototype.isJustParentSelector = function() {
8494 return !this.mediaEmpty &&
8495 this.elements.length === 1 &&
8496 this.elements[0].value === '&' &&
8497 (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === '');
8499 Selector.prototype.eval = function (context) {
8500 var evaldCondition = this.condition && this.condition.eval(context),
8501 elements = this.elements, extendList = this.extendList;
8503 elements = elements && elements.map(function (e) { return e.eval(context); });
8504 extendList = extendList && extendList.map(function(extend) { return extend.eval(context); });
8506 return this.createDerived(elements, extendList, evaldCondition);
8508 Selector.prototype.genCSS = function (context, output) {
8510 if ((!context || !context.firstSelector) && this.elements[0].combinator.value === "") {
8511 output.add(' ', this.currentFileInfo, this.index);
8514 //TODO caching? speed comparison?
8515 for (i = 0; i < this.elements.length; i++) {
8516 element = this.elements[i];
8517 element.genCSS(context, output);
8521 Selector.prototype.getIsOutput = function() {
8522 return this.evaldCondition;
8524 module.exports = Selector;
8526 },{"./element":58,"./node":70}],78:[function(require,module,exports){
8527 var Node = require("./node");
8529 var UnicodeDescriptor = function (value) {
8532 UnicodeDescriptor.prototype = new Node();
8533 UnicodeDescriptor.prototype.type = "UnicodeDescriptor";
8535 module.exports = UnicodeDescriptor;
8537 },{"./node":70}],79:[function(require,module,exports){
8538 var Node = require("./node"),
8539 unitConversions = require("../data/unit-conversions");
8541 var Unit = function (numerator, denominator, backupUnit) {
8542 this.numerator = numerator ? numerator.slice(0).sort() : [];
8543 this.denominator = denominator ? denominator.slice(0).sort() : [];
8545 this.backupUnit = backupUnit;
8546 } else if (numerator && numerator.length) {
8547 this.backupUnit = numerator[0];
8551 Unit.prototype = new Node();
8552 Unit.prototype.type = "Unit";
8553 Unit.prototype.clone = function () {
8554 return new Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit);
8556 Unit.prototype.genCSS = function (context, output) {
8557 // Dimension checks the unit is singular and throws an error if in strict math mode.
8558 var strictUnits = context && context.strictUnits;
8559 if (this.numerator.length === 1) {
8560 output.add(this.numerator[0]); // the ideal situation
8561 } else if (!strictUnits && this.backupUnit) {
8562 output.add(this.backupUnit);
8563 } else if (!strictUnits && this.denominator.length) {
8564 output.add(this.denominator[0]);
8567 Unit.prototype.toString = function () {
8568 var i, returnStr = this.numerator.join("*");
8569 for (i = 0; i < this.denominator.length; i++) {
8570 returnStr += "/" + this.denominator[i];
8574 Unit.prototype.compare = function (other) {
8575 return this.is(other.toString()) ? 0 : undefined;
8577 Unit.prototype.is = function (unitString) {
8578 return this.toString().toUpperCase() === unitString.toUpperCase();
8580 Unit.prototype.isLength = function () {
8581 return Boolean(this.toCSS().match(/px|em|%|in|cm|mm|pc|pt|ex/));
8583 Unit.prototype.isEmpty = function () {
8584 return this.numerator.length === 0 && this.denominator.length === 0;
8586 Unit.prototype.isSingular = function() {
8587 return this.numerator.length <= 1 && this.denominator.length === 0;
8589 Unit.prototype.map = function(callback) {
8592 for (i = 0; i < this.numerator.length; i++) {
8593 this.numerator[i] = callback(this.numerator[i], false);
8596 for (i = 0; i < this.denominator.length; i++) {
8597 this.denominator[i] = callback(this.denominator[i], true);
8600 Unit.prototype.usedUnits = function() {
8601 var group, result = {}, mapUnit, groupName;
8603 mapUnit = function (atomicUnit) {
8604 /*jshint loopfunc:true */
8605 if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
8606 result[groupName] = atomicUnit;
8612 for (groupName in unitConversions) {
8613 if (unitConversions.hasOwnProperty(groupName)) {
8614 group = unitConversions[groupName];
8622 Unit.prototype.cancel = function () {
8623 var counter = {}, atomicUnit, i;
8625 for (i = 0; i < this.numerator.length; i++) {
8626 atomicUnit = this.numerator[i];
8627 counter[atomicUnit] = (counter[atomicUnit] || 0) + 1;
8630 for (i = 0; i < this.denominator.length; i++) {
8631 atomicUnit = this.denominator[i];
8632 counter[atomicUnit] = (counter[atomicUnit] || 0) - 1;
8635 this.numerator = [];
8636 this.denominator = [];
8638 for (atomicUnit in counter) {
8639 if (counter.hasOwnProperty(atomicUnit)) {
8640 var count = counter[atomicUnit];
8643 for (i = 0; i < count; i++) {
8644 this.numerator.push(atomicUnit);
8646 } else if (count < 0) {
8647 for (i = 0; i < -count; i++) {
8648 this.denominator.push(atomicUnit);
8654 this.numerator.sort();
8655 this.denominator.sort();
8657 module.exports = Unit;
8659 },{"../data/unit-conversions":14,"./node":70}],80:[function(require,module,exports){
8660 var Node = require("./node");
8662 var URL = function (val, index, currentFileInfo, isEvald) {
8664 this.currentFileInfo = currentFileInfo;
8666 this.isEvald = isEvald;
8668 URL.prototype = new Node();
8669 URL.prototype.type = "Url";
8670 URL.prototype.accept = function (visitor) {
8671 this.value = visitor.visit(this.value);
8673 URL.prototype.genCSS = function (context, output) {
8675 this.value.genCSS(context, output);
8678 URL.prototype.eval = function (context) {
8679 var val = this.value.eval(context),
8682 if (!this.isEvald) {
8683 // Add the base path if the URL is relative
8684 rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
8686 typeof val.value === "string" &&
8687 context.isPathRelative(val.value)) {
8690 rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\" + match; });
8692 val.value = rootpath + val.value;
8695 val.value = context.normalizePath(val.value);
8697 // Add url args if enabled
8698 if (context.urlArgs) {
8699 if (!val.value.match(/^\s*data:/)) {
8700 var delimiter = val.value.indexOf('?') === -1 ? '?' : '&';
8701 var urlArgs = delimiter + context.urlArgs;
8702 if (val.value.indexOf('#') !== -1) {
8703 val.value = val.value.replace('#', urlArgs + '#');
8705 val.value += urlArgs;
8711 return new URL(val, this.index, this.currentFileInfo, true);
8713 module.exports = URL;
8715 },{"./node":70}],81:[function(require,module,exports){
8716 var Node = require("./node");
8718 var Value = function (value) {
8721 throw new Error("Value requires an array argument");
8724 Value.prototype = new Node();
8725 Value.prototype.type = "Value";
8726 Value.prototype.accept = function (visitor) {
8728 this.value = visitor.visitArray(this.value);
8731 Value.prototype.eval = function (context) {
8732 if (this.value.length === 1) {
8733 return this.value[0].eval(context);
8735 return new Value(this.value.map(function (v) {
8736 return v.eval(context);
8740 Value.prototype.genCSS = function (context, output) {
8742 for (i = 0; i < this.value.length; i++) {
8743 this.value[i].genCSS(context, output);
8744 if (i + 1 < this.value.length) {
8745 output.add((context && context.compress) ? ',' : ', ');
8749 module.exports = Value;
8751 },{"./node":70}],82:[function(require,module,exports){
8752 var Node = require("./node");
8754 var Variable = function (name, index, currentFileInfo) {
8757 this.currentFileInfo = currentFileInfo || {};
8759 Variable.prototype = new Node();
8760 Variable.prototype.type = "Variable";
8761 Variable.prototype.eval = function (context) {
8762 var variable, name = this.name;
8764 if (name.indexOf('@@') === 0) {
8765 name = '@' + new Variable(name.slice(1), this.index, this.currentFileInfo).eval(context).value;
8768 if (this.evaluating) {
8769 throw { type: 'Name',
8770 message: "Recursive variable definition for " + name,
8771 filename: this.currentFileInfo.filename,
8772 index: this.index };
8775 this.evaluating = true;
8777 variable = this.find(context.frames, function (frame) {
8778 var v = frame.variable(name);
8781 var importantScope = context.importantScope[context.importantScope.length - 1];
8782 importantScope.important = v.important;
8784 return v.value.eval(context);
8788 this.evaluating = false;
8791 throw { type: 'Name',
8792 message: "variable " + name + " is undefined",
8793 filename: this.currentFileInfo.filename,
8794 index: this.index };
8797 Variable.prototype.find = function (obj, fun) {
8798 for (var i = 0, r; i < obj.length; i++) {
8799 r = fun.call(obj, obj[i]);
8800 if (r) { return r; }
8804 module.exports = Variable;
8806 },{"./node":70}],83:[function(require,module,exports){
8808 getLocation: function(index, inputStream) {
8813 while (--n >= 0 && inputStream.charAt(n) !== '\n') {
8817 if (typeof index === 'number') {
8818 line = (inputStream.slice(0, index).match(/\n/g) || "").length;
8828 },{}],84:[function(require,module,exports){
8829 var tree = require("../tree"),
8830 Visitor = require("./visitor"),
8831 logger = require("../logger");
8833 /*jshint loopfunc:true */
8835 var ExtendFinderVisitor = function() {
8836 this._visitor = new Visitor(this);
8838 this.allExtendsStack = [[]];
8841 ExtendFinderVisitor.prototype = {
8842 run: function (root) {
8843 root = this._visitor.visit(root);
8844 root.allExtends = this.allExtendsStack[0];
8847 visitRule: function (ruleNode, visitArgs) {
8848 visitArgs.visitDeeper = false;
8850 visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
8851 visitArgs.visitDeeper = false;
8853 visitRuleset: function (rulesetNode, visitArgs) {
8854 if (rulesetNode.root) {
8858 var i, j, extend, allSelectorsExtendList = [], extendList;
8860 // get &:extend(.a); rules which apply to all selectors in this ruleset
8861 var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0;
8862 for (i = 0; i < ruleCnt; i++) {
8863 if (rulesetNode.rules[i] instanceof tree.Extend) {
8864 allSelectorsExtendList.push(rules[i]);
8865 rulesetNode.extendOnEveryPath = true;
8869 // now find every selector and apply the extends that apply to all extends
8870 // and the ones which apply to an individual extend
8871 var paths = rulesetNode.paths;
8872 for (i = 0; i < paths.length; i++) {
8873 var selectorPath = paths[i],
8874 selector = selectorPath[selectorPath.length - 1],
8875 selExtendList = selector.extendList;
8877 extendList = selExtendList ? selExtendList.slice(0).concat(allSelectorsExtendList)
8878 : allSelectorsExtendList;
8881 extendList = extendList.map(function(allSelectorsExtend) {
8882 return allSelectorsExtend.clone();
8886 for (j = 0; j < extendList.length; j++) {
8887 this.foundExtends = true;
8888 extend = extendList[j];
8889 extend.findSelfSelectors(selectorPath);
8890 extend.ruleset = rulesetNode;
8891 if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
8892 this.allExtendsStack[this.allExtendsStack.length - 1].push(extend);
8896 this.contexts.push(rulesetNode.selectors);
8898 visitRulesetOut: function (rulesetNode) {
8899 if (!rulesetNode.root) {
8900 this.contexts.length = this.contexts.length - 1;
8903 visitMedia: function (mediaNode, visitArgs) {
8904 mediaNode.allExtends = [];
8905 this.allExtendsStack.push(mediaNode.allExtends);
8907 visitMediaOut: function (mediaNode) {
8908 this.allExtendsStack.length = this.allExtendsStack.length - 1;
8910 visitDirective: function (directiveNode, visitArgs) {
8911 directiveNode.allExtends = [];
8912 this.allExtendsStack.push(directiveNode.allExtends);
8914 visitDirectiveOut: function (directiveNode) {
8915 this.allExtendsStack.length = this.allExtendsStack.length - 1;
8919 var ProcessExtendsVisitor = function() {
8920 this._visitor = new Visitor(this);
8923 ProcessExtendsVisitor.prototype = {
8924 run: function(root) {
8925 var extendFinder = new ExtendFinderVisitor();
8926 this.extendIndices = {};
8927 extendFinder.run(root);
8928 if (!extendFinder.foundExtends) { return root; }
8929 root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
8930 this.allExtendsStack = [root.allExtends];
8931 var newRoot = this._visitor.visit(root);
8932 this.checkExtendsForNonMatched(root.allExtends);
8935 checkExtendsForNonMatched: function(extendList) {
8936 var indices = this.extendIndices;
8937 extendList.filter(function(extend) {
8938 return !extend.hasFoundMatches && extend.parent_ids.length == 1;
8939 }).forEach(function(extend) {
8940 var selector = "_unknown_";
8942 selector = extend.selector.toCSS({});
8946 if (!indices[extend.index + ' ' + selector]) {
8947 indices[extend.index + ' ' + selector] = true;
8948 logger.warn("extend '" + selector + "' has no matches");
8952 doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
8954 // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering
8955 // and pasting the selector we would do normally, but we are also adding an extend with the same target selector
8956 // this means this new extend can then go and alter other extends
8958 // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
8959 // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already
8960 // processed if we look at each selector at a time, as is done in visitRuleset
8962 var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath,
8963 extend, targetExtend, newExtend;
8965 iterationCount = iterationCount || 0;
8967 //loop through comparing every extend with every target extend.
8968 // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
8969 // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
8970 // and the second is the target.
8971 // the separation into two lists allows us to process a subset of chains with a bigger set, as is the
8972 // case when processing media queries
8973 for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) {
8974 for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) {
8976 extend = extendsList[extendIndex];
8977 targetExtend = extendsListTarget[targetExtendIndex];
8979 // look for circular references
8980 if ( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ) { continue; }
8982 // find a match in the target extends self selector (the bit before :extend)
8983 selectorPath = [targetExtend.selfSelectors[0]];
8984 matches = extendVisitor.findMatch(extend, selectorPath);
8986 if (matches.length) {
8987 extend.hasFoundMatches = true;
8989 // we found a match, so for each self selector..
8990 extend.selfSelectors.forEach(function(selfSelector) {
8991 var info = targetExtend.visibilityInfo();
8993 // process the extend as usual
8994 newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible());
8996 // but now we create a new extend from it
8997 newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0, targetExtend.currentFileInfo, info);
8998 newExtend.selfSelectors = newSelector;
9000 // add the extend onto the list of extends for that selector
9001 newSelector[newSelector.length - 1].extendList = [newExtend];
9003 // record that we need to add it.
9004 extendsToAdd.push(newExtend);
9005 newExtend.ruleset = targetExtend.ruleset;
9007 //remember its parents for circular references
9008 newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids);
9010 // only process the selector once.. if we have :extend(.a,.b) then multiple
9011 // extends will look at the same selector path, so when extending
9012 // we know that any others will be duplicates in terms of what is added to the css
9013 if (targetExtend.firstExtendOnThisSelectorPath) {
9014 newExtend.firstExtendOnThisSelectorPath = true;
9015 targetExtend.ruleset.paths.push(newSelector);
9022 if (extendsToAdd.length) {
9023 // try to detect circular references to stop a stack overflow.
9024 // may no longer be needed.
9025 this.extendChainCount++;
9026 if (iterationCount > 100) {
9027 var selectorOne = "{unable to calculate}";
9028 var selectorTwo = "{unable to calculate}";
9030 selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
9031 selectorTwo = extendsToAdd[0].selector.toCSS();
9034 throw { message: "extend circular reference detected. One of the circular extends is currently:" +
9035 selectorOne + ":extend(" + selectorTwo + ")"};
9038 // now process the new extends on the existing rules so that we can handle a extending b extending c extending
9040 return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1));
9042 return extendsToAdd;
9045 visitRule: function (ruleNode, visitArgs) {
9046 visitArgs.visitDeeper = false;
9048 visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
9049 visitArgs.visitDeeper = false;
9051 visitSelector: function (selectorNode, visitArgs) {
9052 visitArgs.visitDeeper = false;
9054 visitRuleset: function (rulesetNode, visitArgs) {
9055 if (rulesetNode.root) {
9058 var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length - 1],
9059 selectorsToAdd = [], extendVisitor = this, selectorPath;
9061 // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
9063 for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
9064 for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
9065 selectorPath = rulesetNode.paths[pathIndex];
9067 // extending extends happens initially, before the main pass
9068 if (rulesetNode.extendOnEveryPath) { continue; }
9069 var extendList = selectorPath[selectorPath.length - 1].extendList;
9070 if (extendList && extendList.length) { continue; }
9072 matches = this.findMatch(allExtends[extendIndex], selectorPath);
9074 if (matches.length) {
9075 allExtends[extendIndex].hasFoundMatches = true;
9077 allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
9078 var extendedSelectors;
9079 extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible());
9080 selectorsToAdd.push(extendedSelectors);
9085 rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
9087 findMatch: function (extend, haystackSelectorPath) {
9089 // look through the haystack selector path to try and find the needle - extend.selector
9090 // returns an array of selector matches that can then be replaced
9092 var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement,
9093 targetCombinator, i,
9094 extendVisitor = this,
9095 needleElements = extend.selector.elements,
9096 potentialMatches = [], potentialMatch, matches = [];
9098 // loop through the haystack elements
9099 for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
9100 hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
9102 for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
9104 haystackElement = hackstackSelector.elements[hackstackElementIndex];
9106 // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
9107 if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
9108 potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0,
9109 initialCombinator: haystackElement.combinator});
9112 for (i = 0; i < potentialMatches.length; i++) {
9113 potentialMatch = potentialMatches[i];
9115 // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
9116 // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to
9117 // work out what the resulting combinator will be
9118 targetCombinator = haystackElement.combinator.value;
9119 if (targetCombinator === '' && hackstackElementIndex === 0) {
9120 targetCombinator = ' ';
9123 // if we don't match, null our match to indicate failure
9124 if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) ||
9125 (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {
9126 potentialMatch = null;
9128 potentialMatch.matched++;
9131 // if we are still valid and have finished, test whether we have elements after and whether these are allowed
9132 if (potentialMatch) {
9133 potentialMatch.finished = potentialMatch.matched === needleElements.length;
9134 if (potentialMatch.finished &&
9135 (!extend.allowAfter &&
9136 (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length))) {
9137 potentialMatch = null;
9140 // if null we remove, if not, we are still valid, so either push as a valid match or continue
9141 if (potentialMatch) {
9142 if (potentialMatch.finished) {
9143 potentialMatch.length = needleElements.length;
9144 potentialMatch.endPathIndex = haystackSelectorIndex;
9145 potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match
9146 potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again
9147 matches.push(potentialMatch);
9150 potentialMatches.splice(i, 1);
9158 isElementValuesEqual: function(elementValue1, elementValue2) {
9159 if (typeof elementValue1 === "string" || typeof elementValue2 === "string") {
9160 return elementValue1 === elementValue2;
9162 if (elementValue1 instanceof tree.Attribute) {
9163 if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {
9166 if (!elementValue1.value || !elementValue2.value) {
9167 if (elementValue1.value || elementValue2.value) {
9172 elementValue1 = elementValue1.value.value || elementValue1.value;
9173 elementValue2 = elementValue2.value.value || elementValue2.value;
9174 return elementValue1 === elementValue2;
9176 elementValue1 = elementValue1.value;
9177 elementValue2 = elementValue2.value;
9178 if (elementValue1 instanceof tree.Selector) {
9179 if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
9182 for (var i = 0; i < elementValue1.elements.length; i++) {
9183 if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {
9184 if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {
9188 if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) {
9196 extendSelector:function (matches, selectorPath, replacementSelector, isVisible) {
9198 //for a set of matches, replace each match with the replacement selector
9200 var currentSelectorPathIndex = 0,
9201 currentSelectorPathElementIndex = 0,
9209 for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {
9210 match = matches[matchIndex];
9211 selector = selectorPath[match.pathIndex];
9212 firstElement = new tree.Element(
9213 match.initialCombinator,
9214 replacementSelector.elements[0].value,
9215 replacementSelector.elements[0].index,
9216 replacementSelector.elements[0].currentFileInfo
9219 if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
9220 path[path.length - 1].elements = path[path.length - 1]
9221 .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
9222 currentSelectorPathElementIndex = 0;
9223 currentSelectorPathIndex++;
9226 newElements = selector.elements
9227 .slice(currentSelectorPathElementIndex, match.index)
9228 .concat([firstElement])
9229 .concat(replacementSelector.elements.slice(1));
9231 if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {
9232 path[path.length - 1].elements =
9233 path[path.length - 1].elements.concat(newElements);
9235 path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
9237 path.push(new tree.Selector(
9241 currentSelectorPathIndex = match.endPathIndex;
9242 currentSelectorPathElementIndex = match.endPathElementIndex;
9243 if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {
9244 currentSelectorPathElementIndex = 0;
9245 currentSelectorPathIndex++;
9249 if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
9250 path[path.length - 1].elements = path[path.length - 1]
9251 .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
9252 currentSelectorPathIndex++;
9255 path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
9256 path = path.map(function (currentValue) {
9257 // we can re-use elements here, because the visibility property matters only for selectors
9258 var derived = currentValue.createDerived(currentValue.elements);
9260 derived.ensureVisibility();
9262 derived.ensureInvisibility();
9268 visitMedia: function (mediaNode, visitArgs) {
9269 var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
9270 newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
9271 this.allExtendsStack.push(newAllExtends);
9273 visitMediaOut: function (mediaNode) {
9274 var lastIndex = this.allExtendsStack.length - 1;
9275 this.allExtendsStack.length = lastIndex;
9277 visitDirective: function (directiveNode, visitArgs) {
9278 var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
9279 newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
9280 this.allExtendsStack.push(newAllExtends);
9282 visitDirectiveOut: function (directiveNode) {
9283 var lastIndex = this.allExtendsStack.length - 1;
9284 this.allExtendsStack.length = lastIndex;
9288 module.exports = ProcessExtendsVisitor;
9290 },{"../logger":33,"../tree":62,"./visitor":91}],85:[function(require,module,exports){
9291 function ImportSequencer(onSequencerEmpty) {
9293 this.variableImports = [];
9294 this._onSequencerEmpty = onSequencerEmpty;
9295 this._currentDepth = 0;
9298 ImportSequencer.prototype.addImport = function(callback) {
9299 var importSequencer = this,
9305 this.imports.push(importItem);
9307 importItem.args = Array.prototype.slice.call(arguments, 0);
9308 importItem.isReady = true;
9309 importSequencer.tryRun();
9313 ImportSequencer.prototype.addVariableImport = function(callback) {
9314 this.variableImports.push(callback);
9317 ImportSequencer.prototype.tryRun = function() {
9318 this._currentDepth++;
9321 while (this.imports.length > 0) {
9322 var importItem = this.imports[0];
9323 if (!importItem.isReady) {
9326 this.imports = this.imports.slice(1);
9327 importItem.callback.apply(null, importItem.args);
9329 if (this.variableImports.length === 0) {
9332 var variableImport = this.variableImports[0];
9333 this.variableImports = this.variableImports.slice(1);
9337 this._currentDepth--;
9339 if (this._currentDepth === 0 && this._onSequencerEmpty) {
9340 this._onSequencerEmpty();
9344 module.exports = ImportSequencer;
9346 },{}],86:[function(require,module,exports){
9347 var contexts = require("../contexts"),
9348 Visitor = require("./visitor"),
9349 ImportSequencer = require("./import-sequencer");
9351 var ImportVisitor = function(importer, finish) {
9353 this._visitor = new Visitor(this);
9354 this._importer = importer;
9355 this._finish = finish;
9356 this.context = new contexts.Eval();
9357 this.importCount = 0;
9358 this.onceFileDetectionMap = {};
9359 this.recursionDetector = {};
9360 this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this));
9363 ImportVisitor.prototype = {
9365 run: function (root) {
9367 // process the contents
9368 this._visitor.visit(root);
9374 this.isFinished = true;
9375 this._sequencer.tryRun();
9377 _onSequencerEmpty: function() {
9378 if (!this.isFinished) {
9381 this._finish(this.error);
9383 visitImport: function (importNode, visitArgs) {
9384 var inlineCSS = importNode.options.inline;
9386 if (!importNode.css || inlineCSS) {
9388 var context = new contexts.Eval(this.context, this.context.frames.slice(0));
9389 var importParent = context.frames[0];
9392 if (importNode.isVariableImport()) {
9393 this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent));
9395 this.processImportNode(importNode, context, importParent);
9398 visitArgs.visitDeeper = false;
9400 processImportNode: function(importNode, context, importParent) {
9401 var evaldImportNode,
9402 inlineCSS = importNode.options.inline;
9405 evaldImportNode = importNode.evalForImport(context);
9407 if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
9408 // attempt to eval properly and treat as css
9409 importNode.css = true;
9410 // if that fails, this error will be thrown
9411 importNode.error = e;
9414 if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {
9416 if (evaldImportNode.options.multiple) {
9417 context.importMultiple = true;
9420 // try appending if we haven't determined if it is css or not
9421 var tryAppendLessExtension = evaldImportNode.css === undefined;
9423 for (var i = 0; i < importParent.rules.length; i++) {
9424 if (importParent.rules[i] === importNode) {
9425 importParent.rules[i] = evaldImportNode;
9430 var onImported = this.onImported.bind(this, evaldImportNode, context),
9431 sequencedOnImported = this._sequencer.addImport(onImported);
9433 this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.currentFileInfo,
9434 evaldImportNode.options, sequencedOnImported);
9437 if (this.isFinished) {
9438 this._sequencer.tryRun();
9442 onImported: function (importNode, context, e, root, importedAtRoot, fullPath) {
9445 e.index = importNode.index; e.filename = importNode.currentFileInfo.filename;
9450 var importVisitor = this,
9451 inlineCSS = importNode.options.inline,
9452 isPlugin = importNode.options.plugin,
9453 isOptional = importNode.options.optional,
9454 duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector;
9456 if (!context.importMultiple) {
9457 if (duplicateImport) {
9458 importNode.skip = true;
9460 importNode.skip = function() {
9461 if (fullPath in importVisitor.onceFileDetectionMap) {
9464 importVisitor.onceFileDetectionMap[fullPath] = true;
9470 if (!fullPath && isOptional) {
9471 importNode.skip = true;
9475 importNode.root = root;
9476 importNode.importedFilename = fullPath;
9478 if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) {
9479 importVisitor.recursionDetector[fullPath] = true;
9481 var oldContext = this.context;
9482 this.context = context;
9484 this._visitor.visit(root);
9488 this.context = oldContext;
9492 importVisitor.importCount--;
9494 if (importVisitor.isFinished) {
9495 importVisitor._sequencer.tryRun();
9498 visitRule: function (ruleNode, visitArgs) {
9499 if (ruleNode.value.type === "DetachedRuleset") {
9500 this.context.frames.unshift(ruleNode);
9502 visitArgs.visitDeeper = false;
9505 visitRuleOut : function(ruleNode) {
9506 if (ruleNode.value.type === "DetachedRuleset") {
9507 this.context.frames.shift();
9510 visitDirective: function (directiveNode, visitArgs) {
9511 this.context.frames.unshift(directiveNode);
9513 visitDirectiveOut: function (directiveNode) {
9514 this.context.frames.shift();
9516 visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
9517 this.context.frames.unshift(mixinDefinitionNode);
9519 visitMixinDefinitionOut: function (mixinDefinitionNode) {
9520 this.context.frames.shift();
9522 visitRuleset: function (rulesetNode, visitArgs) {
9523 this.context.frames.unshift(rulesetNode);
9525 visitRulesetOut: function (rulesetNode) {
9526 this.context.frames.shift();
9528 visitMedia: function (mediaNode, visitArgs) {
9529 this.context.frames.unshift(mediaNode.rules[0]);
9531 visitMediaOut: function (mediaNode) {
9532 this.context.frames.shift();
9535 module.exports = ImportVisitor;
9537 },{"../contexts":11,"./import-sequencer":85,"./visitor":91}],87:[function(require,module,exports){
9539 Visitor: require("./visitor"),
9540 ImportVisitor: require('./import-visitor'),
9541 MarkVisibleSelectorsVisitor: require("./set-tree-visibility-visitor"),
9542 ExtendVisitor: require('./extend-visitor'),
9543 JoinSelectorVisitor: require('./join-selector-visitor'),
9544 ToCSSVisitor: require('./to-css-visitor')
9547 module.exports = visitors;
9549 },{"./extend-visitor":84,"./import-visitor":86,"./join-selector-visitor":88,"./set-tree-visibility-visitor":89,"./to-css-visitor":90,"./visitor":91}],88:[function(require,module,exports){
9550 var Visitor = require("./visitor");
9552 var JoinSelectorVisitor = function() {
9553 this.contexts = [[]];
9554 this._visitor = new Visitor(this);
9557 JoinSelectorVisitor.prototype = {
9558 run: function (root) {
9559 return this._visitor.visit(root);
9561 visitRule: function (ruleNode, visitArgs) {
9562 visitArgs.visitDeeper = false;
9564 visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
9565 visitArgs.visitDeeper = false;
9568 visitRuleset: function (rulesetNode, visitArgs) {
9569 var context = this.contexts[this.contexts.length - 1],
9570 paths = [], selectors;
9572 this.contexts.push(paths);
9574 if (! rulesetNode.root) {
9575 selectors = rulesetNode.selectors;
9577 selectors = selectors.filter(function(selector) { return selector.getIsOutput(); });
9578 rulesetNode.selectors = selectors.length ? selectors : (selectors = null);
9579 if (selectors) { rulesetNode.joinSelectors(paths, context, selectors); }
9581 if (!selectors) { rulesetNode.rules = null; }
9582 rulesetNode.paths = paths;
9585 visitRulesetOut: function (rulesetNode) {
9586 this.contexts.length = this.contexts.length - 1;
9588 visitMedia: function (mediaNode, visitArgs) {
9589 var context = this.contexts[this.contexts.length - 1];
9590 mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);
9592 visitDirective: function (directiveNode, visitArgs) {
9593 var context = this.contexts[this.contexts.length - 1];
9594 if (directiveNode.rules && directiveNode.rules.length) {
9595 directiveNode.rules[0].root = (directiveNode.isRooted || context.length === 0 || null);
9600 module.exports = JoinSelectorVisitor;
9602 },{"./visitor":91}],89:[function(require,module,exports){
9603 var SetTreeVisibilityVisitor = function(visible) {
9604 this.visible = visible;
9606 SetTreeVisibilityVisitor.prototype.run = function(root) {
9609 SetTreeVisibilityVisitor.prototype.visitArray = function(nodes) {
9614 var cnt = nodes.length, i;
9615 for (i = 0; i < cnt; i++) {
9616 this.visit(nodes[i]);
9620 SetTreeVisibilityVisitor.prototype.visit = function(node) {
9624 if (node.constructor === Array) {
9625 return this.visitArray(node);
9628 if (!node.blocksVisibility || node.blocksVisibility()) {
9632 node.ensureVisibility();
9634 node.ensureInvisibility();
9640 module.exports = SetTreeVisibilityVisitor;
9641 },{}],90:[function(require,module,exports){
9642 var tree = require("../tree"),
9643 Visitor = require("./visitor");
9645 var CSSVisitorUtils = function(context) {
9646 this._visitor = new Visitor(this);
9647 this._context = context;
9650 CSSVisitorUtils.prototype = {
9651 containsSilentNonBlockedChild: function(bodyRules) {
9653 if (bodyRules == null) {
9656 for (var r = 0; r < bodyRules.length; r++) {
9657 rule = bodyRules[r];
9658 if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) {
9659 //the directive contains something that was referenced (likely by extend)
9660 //therefore it needs to be shown in output too
9667 keepOnlyVisibleChilds: function(owner) {
9668 if (owner == null || owner.rules == null) {
9672 owner.rules = owner.rules.filter(function(thing) {
9673 return thing.isVisible();
9678 isEmpty: function(owner) {
9679 if (owner == null || owner.rules == null) {
9682 return owner.rules.length === 0;
9685 hasVisibleSelector: function(rulesetNode) {
9686 if (rulesetNode == null || rulesetNode.paths == null) {
9689 return rulesetNode.paths.length > 0;
9692 resolveVisibility: function (node, originalRules) {
9693 if (!node.blocksVisibility()) {
9694 if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) {
9701 var compiledRulesBody = node.rules[0];
9702 this.keepOnlyVisibleChilds(compiledRulesBody);
9704 if (this.isEmpty(compiledRulesBody)) {
9708 node.ensureVisibility();
9709 node.removeVisibilityBlock();
9714 isVisibleRuleset: function(rulesetNode) {
9715 if (rulesetNode.firstRoot) {
9719 if (this.isEmpty(rulesetNode)) {
9723 if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) {
9732 var ToCSSVisitor = function(context) {
9733 this._visitor = new Visitor(this);
9734 this._context = context;
9735 this.utils = new CSSVisitorUtils(context);
9738 ToCSSVisitor.prototype = {
9740 run: function (root) {
9741 return this._visitor.visit(root);
9744 visitRule: function (ruleNode, visitArgs) {
9745 if (ruleNode.blocksVisibility() || ruleNode.variable) {
9751 visitMixinDefinition: function (mixinNode, visitArgs) {
9752 // mixin definitions do not get eval'd - this means they keep state
9753 // so we have to clear that state here so it isn't used if toCSS is called twice
9754 mixinNode.frames = [];
9757 visitExtend: function (extendNode, visitArgs) {
9760 visitComment: function (commentNode, visitArgs) {
9761 if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) {
9767 visitMedia: function(mediaNode, visitArgs) {
9768 var originalRules = mediaNode.rules[0].rules;
9769 mediaNode.accept(this._visitor);
9770 visitArgs.visitDeeper = false;
9772 return this.utils.resolveVisibility(mediaNode, originalRules);
9775 visitImport: function (importNode, visitArgs) {
9776 if (importNode.blocksVisibility()) {
9782 visitDirective: function(directiveNode, visitArgs) {
9783 if (directiveNode.rules && directiveNode.rules.length) {
9784 return this.visitDirectiveWithBody(directiveNode, visitArgs);
9786 return this.visitDirectiveWithoutBody(directiveNode, visitArgs);
9790 visitDirectiveWithBody: function(directiveNode, visitArgs) {
9791 //if there is only one nested ruleset and that one has no path, then it is
9793 function hasFakeRuleset(directiveNode) {
9794 var bodyRules = directiveNode.rules;
9795 return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0);
9797 function getBodyRules(directiveNode) {
9798 var nodeRules = directiveNode.rules;
9799 if (hasFakeRuleset(directiveNode)) {
9800 return nodeRules[0].rules;
9805 //it is still true that it is only one ruleset in array
9806 //this is last such moment
9808 var originalRules = getBodyRules(directiveNode);
9809 directiveNode.accept(this._visitor);
9810 visitArgs.visitDeeper = false;
9812 if (!this.utils.isEmpty(directiveNode)) {
9813 this._mergeRules(directiveNode.rules[0].rules);
9816 return this.utils.resolveVisibility(directiveNode, originalRules);
9819 visitDirectiveWithoutBody: function(directiveNode, visitArgs) {
9820 if (directiveNode.blocksVisibility()) {
9824 if (directiveNode.name === "@charset") {
9825 // Only output the debug info together with subsequent @charset definitions
9826 // a comment (or @media statement) before the actual @charset directive would
9827 // be considered illegal css as it has to be on the first line
9829 if (directiveNode.debugInfo) {
9830 var comment = new tree.Comment("/* " + directiveNode.toCSS(this._context).replace(/\n/g, "") + " */\n");
9831 comment.debugInfo = directiveNode.debugInfo;
9832 return this._visitor.visit(comment);
9836 this.charset = true;
9839 return directiveNode;
9842 checkValidNodes: function(rules, isRoot) {
9847 for (var i = 0; i < rules.length; i++) {
9848 var ruleNode = rules[i];
9849 if (isRoot && ruleNode instanceof tree.Rule && !ruleNode.variable) {
9850 throw { message: "Properties must be inside selector blocks. They cannot be in the root",
9851 index: ruleNode.index, filename: ruleNode.currentFileInfo && ruleNode.currentFileInfo.filename};
9853 if (ruleNode instanceof tree.Call) {
9854 throw { message: "Function '" + ruleNode.name + "' is undefined",
9855 index: ruleNode.index, filename: ruleNode.currentFileInfo && ruleNode.currentFileInfo.filename};
9857 if (ruleNode.type && !ruleNode.allowRoot) {
9858 throw { message: ruleNode.type + " node returned by a function is not valid here",
9859 index: ruleNode.index, filename: ruleNode.currentFileInfo && ruleNode.currentFileInfo.filename};
9864 visitRuleset: function (rulesetNode, visitArgs) {
9865 //at this point rulesets are nested into each other
9866 var rule, rulesets = [];
9868 this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot);
9870 if (! rulesetNode.root) {
9871 //remove invisible paths
9872 this._compileRulesetPaths(rulesetNode);
9874 // remove rulesets from this ruleset body and compile them separately
9875 var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0;
9876 for (var i = 0; i < nodeRuleCnt; ) {
9877 rule = nodeRules[i];
9878 if (rule && rule.rules) {
9879 // visit because we are moving them out from being a child
9880 rulesets.push(this._visitor.visit(rule));
9881 nodeRules.splice(i, 1);
9887 // accept the visitor to remove rules and refactor itself
9888 // then we can decide nogw whether we want it or not
9890 if (nodeRuleCnt > 0) {
9891 rulesetNode.accept(this._visitor);
9893 rulesetNode.rules = null;
9895 visitArgs.visitDeeper = false;
9897 } else { //if (! rulesetNode.root) {
9898 rulesetNode.accept(this._visitor);
9899 visitArgs.visitDeeper = false;
9902 if (rulesetNode.rules) {
9903 this._mergeRules(rulesetNode.rules);
9904 this._removeDuplicateRules(rulesetNode.rules);
9907 //now decide whether we keep the ruleset
9908 if (this.utils.isVisibleRuleset(rulesetNode)) {
9909 rulesetNode.ensureVisibility();
9910 rulesets.splice(0, 0, rulesetNode);
9913 if (rulesets.length === 1) {
9919 _compileRulesetPaths: function(rulesetNode) {
9920 if (rulesetNode.paths) {
9921 rulesetNode.paths = rulesetNode.paths
9922 .filter(function(p) {
9924 if (p[0].elements[0].combinator.value === ' ') {
9925 p[0].elements[0].combinator = new(tree.Combinator)('');
9927 for (i = 0; i < p.length; i++) {
9928 if (p[i].isVisible() && p[i].getIsOutput()) {
9937 _removeDuplicateRules: function(rules) {
9938 if (!rules) { return; }
9940 // remove duplicates
9944 for (i = rules.length - 1; i >= 0 ; i--) {
9946 if (rule instanceof tree.Rule) {
9947 if (!ruleCache[rule.name]) {
9948 ruleCache[rule.name] = rule;
9950 ruleList = ruleCache[rule.name];
9951 if (ruleList instanceof tree.Rule) {
9952 ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)];
9954 var ruleCSS = rule.toCSS(this._context);
9955 if (ruleList.indexOf(ruleCSS) !== -1) {
9958 ruleList.push(ruleCSS);
9965 _mergeRules: function (rules) {
9966 if (!rules) { return; }
9973 for (var i = 0; i < rules.length; i++) {
9976 if ((rule instanceof tree.Rule) && rule.merge) {
9978 rule.important ? "!" : ""].join(",");
9983 rules.splice(i--, 1);
9986 groups[key].push(rule);
9990 Object.keys(groups).map(function (k) {
9992 function toExpression(values) {
9993 return new (tree.Expression)(values.map(function (p) {
9998 function toValue(values) {
9999 return new (tree.Value)(values.map(function (p) {
10006 if (parts.length > 1) {
10008 var spacedGroups = [];
10009 var lastSpacedGroup = [];
10010 parts.map(function (p) {
10011 if (p.merge === "+") {
10012 if (lastSpacedGroup.length > 0) {
10013 spacedGroups.push(toExpression(lastSpacedGroup));
10015 lastSpacedGroup = [];
10017 lastSpacedGroup.push(p);
10019 spacedGroups.push(toExpression(lastSpacedGroup));
10020 rule.value = toValue(spacedGroups);
10025 visitAnonymous: function(anonymousNode, visitArgs) {
10026 if (anonymousNode.blocksVisibility()) {
10029 anonymousNode.accept(this._visitor);
10030 return anonymousNode;
10034 module.exports = ToCSSVisitor;
10036 },{"../tree":62,"./visitor":91}],91:[function(require,module,exports){
10037 var tree = require("../tree");
10039 var _visitArgs = { visitDeeper: true },
10040 _hasIndexed = false;
10042 function _noop(node) {
10046 function indexNodeTypes(parent, ticker) {
10047 // add .typeIndex to tree node types for lookup table
10049 for (key in parent) {
10050 if (parent.hasOwnProperty(key)) {
10051 child = parent[key];
10052 switch (typeof child) {
10054 // ignore bound functions directly on tree which do not have a prototype
10056 if (child.prototype && child.prototype.type) {
10057 child.prototype.typeIndex = ticker++;
10061 ticker = indexNodeTypes(child, ticker);
10069 var Visitor = function(implementation) {
10070 this._implementation = implementation;
10071 this._visitFnCache = [];
10073 if (!_hasIndexed) {
10074 indexNodeTypes(tree, 1);
10075 _hasIndexed = true;
10079 Visitor.prototype = {
10080 visit: function(node) {
10085 var nodeTypeIndex = node.typeIndex;
10086 if (!nodeTypeIndex) {
10090 var visitFnCache = this._visitFnCache,
10091 impl = this._implementation,
10092 aryIndx = nodeTypeIndex << 1,
10093 outAryIndex = aryIndx | 1,
10094 func = visitFnCache[aryIndx],
10095 funcOut = visitFnCache[outAryIndex],
10096 visitArgs = _visitArgs,
10099 visitArgs.visitDeeper = true;
10102 fnName = "visit" + node.type;
10103 func = impl[fnName] || _noop;
10104 funcOut = impl[fnName + "Out"] || _noop;
10105 visitFnCache[aryIndx] = func;
10106 visitFnCache[outAryIndex] = funcOut;
10109 if (func !== _noop) {
10110 var newNode = func.call(impl, node, visitArgs);
10111 if (impl.isReplacing) {
10116 if (visitArgs.visitDeeper && node && node.accept) {
10120 if (funcOut != _noop) {
10121 funcOut.call(impl, node);
10126 visitArray: function(nodes, nonReplacing) {
10131 var cnt = nodes.length, i;
10134 if (nonReplacing || !this._implementation.isReplacing) {
10135 for (i = 0; i < cnt; i++) {
10136 this.visit(nodes[i]);
10143 for (i = 0; i < cnt; i++) {
10144 var evald = this.visit(nodes[i]);
10145 if (evald === undefined) { continue; }
10146 if (!evald.splice) {
10148 } else if (evald.length) {
10149 this.flatten(evald, out);
10154 flatten: function(arr, out) {
10160 nestedCnt, j, nestedItem;
10162 for (i = 0, cnt = arr.length; i < cnt; i++) {
10164 if (item === undefined) {
10167 if (!item.splice) {
10172 for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) {
10173 nestedItem = item[j];
10174 if (nestedItem === undefined) {
10177 if (!nestedItem.splice) {
10178 out.push(nestedItem);
10179 } else if (nestedItem.length) {
10180 this.flatten(nestedItem, out);
10188 module.exports = Visitor;
10190 },{"../tree":62}],92:[function(require,module,exports){
10193 // rawAsap provides everything we need except exception management.
10194 var rawAsap = require("./raw");
10195 // RawTasks are recycled to reduce GC churn.
10196 var freeTasks = [];
10197 // We queue errors to ensure they are thrown in right order (FIFO).
10198 // Array-as-queue is good enough here, since we are just dealing with exceptions.
10199 var pendingErrors = [];
10200 var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
10202 function throwFirstError() {
10203 if (pendingErrors.length) {
10204 throw pendingErrors.shift();
10209 * Calls a task as soon as possible after returning, in its own event, with priority
10210 * over other events like animation, reflow, and repaint. An error thrown from an
10211 * event will not interrupt, nor even substantially slow down the processing of
10212 * other events, but will be rather postponed to a lower priority event.
10213 * @param {{call}} task A callable object, typically a function that takes no
10216 module.exports = asap;
10217 function asap(task) {
10219 if (freeTasks.length) {
10220 rawTask = freeTasks.pop();
10222 rawTask = new RawTask();
10224 rawTask.task = task;
10228 // We wrap tasks with recyclable task objects. A task object implements
10229 // `call`, just like a function.
10230 function RawTask() {
10234 // The sole purpose of wrapping the task is to catch the exception and recycle
10235 // the task object after its single use.
10236 RawTask.prototype.call = function () {
10240 if (asap.onerror) {
10241 // This hook exists purely for testing purposes.
10242 // Its name will be periodically randomized to break any code that
10243 // depends on its existence.
10244 asap.onerror(error);
10246 // In a web browser, exceptions are not fatal. However, to avoid
10247 // slowing down the queue of pending tasks, we rethrow the error in a
10248 // lower priority turn.
10249 pendingErrors.push(error);
10250 requestErrorThrow();
10254 freeTasks[freeTasks.length] = this;
10258 },{"./raw":93}],93:[function(require,module,exports){
10259 (function (global){
10262 // Use the fastest means possible to execute a task in its own turn, with
10263 // priority over other events including IO, animation, reflow, and redraw
10264 // events in browsers.
10266 // An exception thrown by a task will permanently interrupt the processing of
10267 // subsequent tasks. The higher level `asap` function ensures that if an
10268 // exception is thrown by a task, that the task queue will continue flushing as
10269 // soon as possible, but if you use `rawAsap` directly, you are responsible to
10270 // either ensure that no exceptions are thrown from your task, or to manually
10271 // call `rawAsap.requestFlush` if an exception is thrown.
10272 module.exports = rawAsap;
10273 function rawAsap(task) {
10274 if (!queue.length) {
10278 // Equivalent to push, but avoids a function call.
10279 queue[queue.length] = task;
10283 // Once a flush has been requested, no further calls to `requestFlush` are
10284 // necessary until the next `flush` completes.
10285 var flushing = false;
10286 // `requestFlush` is an implementation-specific method that attempts to kick
10287 // off a `flush` event as quickly as possible. `flush` will attempt to exhaust
10288 // the event queue before yielding to the browser's own event loop.
10290 // The position of the next task to execute in the task queue. This is
10291 // preserved between calls to `flush` so that it can be resumed if
10292 // a task throws an exception.
10294 // If a task schedules additional tasks recursively, the task queue can grow
10295 // unbounded. To prevent memory exhaustion, the task queue will periodically
10296 // truncate already-completed tasks.
10297 var capacity = 1024;
10299 // The flush function processes all tasks that have been scheduled with
10300 // `rawAsap` unless and until one of those tasks throws an exception.
10301 // If a task throws an exception, `flush` ensures that its state will remain
10302 // consistent and will resume where it left off when called again.
10303 // However, `flush` does not make any arrangements to be called again if an
10304 // exception is thrown.
10306 while (index < queue.length) {
10307 var currentIndex = index;
10308 // Advance the index before calling the task. This ensures that we will
10309 // begin flushing on the next task the task throws an error.
10311 queue[currentIndex].call();
10312 // Prevent leaking memory for long chains of recursive calls to `asap`.
10313 // If we call `asap` within tasks scheduled by `asap`, the queue will
10314 // grow, but to avoid an O(n) walk for every task we execute, we don't
10315 // shift tasks off the queue after they have been executed.
10316 // Instead, we periodically shift 1024 tasks off the queue.
10317 if (index > capacity) {
10318 // Manually shift all values starting at the index back to the
10319 // beginning of the queue.
10320 for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
10321 queue[scan] = queue[scan + index];
10323 queue.length -= index;
10332 // `requestFlush` is implemented using a strategy based on data collected from
10333 // every available SauceLabs Selenium web driver worker at time of writing.
10334 // https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
10336 // Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
10337 // have WebKitMutationObserver but not un-prefixed MutationObserver.
10338 // Must use `global` or `self` instead of `window` to work in both frames and web
10339 // workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
10342 var scope = typeof global !== "undefined" ? global : self;
10343 var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver;
10345 // MutationObservers are desirable because they have high priority and work
10346 // reliably everywhere they are implemented.
10347 // They are implemented in all modern browsers.
10352 // - Internet Explorer 11
10353 // - iPad Safari 6-7.1
10354 // - iPhone Safari 7-7.1
10356 if (typeof BrowserMutationObserver === "function") {
10357 requestFlush = makeRequestCallFromMutationObserver(flush);
10359 // MessageChannels are desirable because they give direct access to the HTML
10360 // task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera
10361 // 11-12, and in web workers in many engines.
10362 // Although message channels yield to any queued rendering and IO tasks, they
10363 // would be better than imposing the 4ms delay of timers.
10364 // However, they do not work reliably in Internet Explorer or Safari.
10366 // Internet Explorer 10 is the only browser that has setImmediate but does
10367 // not have MutationObservers.
10368 // Although setImmediate yields to the browser's renderer, it would be
10369 // preferrable to falling back to setTimeout since it does not have
10370 // the minimum 4ms penalty.
10371 // Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and
10372 // Desktop to a lesser extent) that renders both setImmediate and
10373 // MessageChannel useless for the purposes of ASAP.
10374 // https://github.com/kriskowal/q/issues/396
10376 // Timers are implemented universally.
10377 // We fall back to timers in workers in most engines, and in foreground
10378 // contexts in the following browsers.
10379 // However, note that even this simple case requires nuances to operate in a
10380 // broad spectrum of browsers.
10383 // - Internet Explorer 6-9
10384 // - iPad Safari 4.3
10387 requestFlush = makeRequestCallFromTimer(flush);
10390 // `requestFlush` requests that the high priority event queue be flushed as
10391 // soon as possible.
10392 // This is useful to prevent an error thrown in a task from stalling the event
10393 // queue if the exception handled by Node.js’s
10394 // `process.on("uncaughtException")` or by a domain.
10395 rawAsap.requestFlush = requestFlush;
10397 // To request a high priority event, we induce a mutation observer by toggling
10398 // the text of a text node between "1" and "-1".
10399 function makeRequestCallFromMutationObserver(callback) {
10401 var observer = new BrowserMutationObserver(callback);
10402 var node = document.createTextNode("");
10403 observer.observe(node, {characterData: true});
10404 return function requestCall() {
10406 node.data = toggle;
10410 // The message channel technique was discovered by Malte Ubl and was the
10411 // original foundation for this library.
10412 // http://www.nonblocking.io/2011/06/windownexttick.html
10414 // Safari 6.0.5 (at least) intermittently fails to create message ports on a
10415 // page's first load. Thankfully, this version of Safari supports
10416 // MutationObservers, so we don't need to fall back in that case.
10418 // function makeRequestCallFromMessageChannel(callback) {
10419 // var channel = new MessageChannel();
10420 // channel.port1.onmessage = callback;
10421 // return function requestCall() {
10422 // channel.port2.postMessage(0);
10426 // For reasons explained above, we are also unable to use `setImmediate`
10427 // under any circumstances.
10428 // Even if we were, there is another bug in Internet Explorer 10.
10429 // It is not sufficient to assign `setImmediate` to `requestFlush` because
10430 // `setImmediate` must be called *by name* and therefore must be wrapped in a
10434 // function makeRequestCallFromSetImmediate(callback) {
10435 // return function requestCall() {
10436 // setImmediate(callback);
10440 // Safari 6.0 has a problem where timers will get lost while the user is
10441 // scrolling. This problem does not impact ASAP because Safari 6.0 supports
10442 // mutation observers, so that implementation is used instead.
10443 // However, if we ever elect to use timers in Safari, the prevalent work-around
10444 // is to add a scroll event listener that calls for a flush.
10446 // `setTimeout` does not call the passed callback if the delay is less than
10447 // approximately 7 in web workers in Firefox 8 through 18, and sometimes not
10450 function makeRequestCallFromTimer(callback) {
10451 return function requestCall() {
10452 // We dispatch a timeout with a specified delay of 0 for engines that
10453 // can reliably accommodate that request. This will usually be snapped
10454 // to a 4 milisecond delay, but once we're flushing, there's no delay
10456 var timeoutHandle = setTimeout(handleTimer, 0);
10457 // However, since this timer gets frequently dropped in Firefox
10458 // workers, we enlist an interval handle that will try to fire
10459 // an event 20 times per second until it succeeds.
10460 var intervalHandle = setInterval(handleTimer, 50);
10462 function handleTimer() {
10463 // Whichever timer succeeds will cancel both timers and
10464 // execute the callback.
10465 clearTimeout(timeoutHandle);
10466 clearInterval(intervalHandle);
10472 // This is for `asap.js` only.
10473 // Its name will be periodically randomized to break any code that depends on
10475 rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer;
10477 // ASAP was originally a nextTick shim included in Q. This was factored out
10478 // into this ASAP package. It was later adapted to RSVP which made further
10479 // amendments. These decisions, particularly to marginalize MessageChannel and
10480 // to capture the MutationObserver implementation in a closure, were integrated
10481 // back into ASAP proper.
10482 // https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
10484 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
10485 },{}],94:[function(require,module,exports){
10488 var asap = require('asap/raw');
10495 // 1 - fulfilled with _value
10496 // 2 - rejected with _value
10497 // 3 - adopted the state of another promise, _value
10499 // once the state is no longer pending (0) it is immutable
10501 // All `_` prefixed properties will be reduced to `_{random number}`
10502 // at build time to obfuscate them and discourage their use.
10503 // We don't use symbols or Object.defineProperty to fully hide them
10504 // because the performance isn't good enough.
10507 // to avoid using try/catch inside critical functions, we
10508 // extract them to here.
10509 var LAST_ERROR = null;
10511 function getThen(obj) {
10520 function tryCallOne(fn, a) {
10528 function tryCallTwo(fn, a, b) {
10537 module.exports = Promise;
10539 function Promise(fn) {
10540 if (typeof this !== 'object') {
10541 throw new TypeError('Promises must be constructed via new');
10543 if (typeof fn !== 'function') {
10544 throw new TypeError('Promise constructor\'s argument is not a function');
10550 if (fn === noop) return;
10551 doResolve(fn, this);
10553 Promise._37 = null;
10554 Promise._87 = null;
10555 Promise._61 = noop;
10557 Promise.prototype.then = function(onFulfilled, onRejected) {
10558 if (this.constructor !== Promise) {
10559 return safeThen(this, onFulfilled, onRejected);
10561 var res = new Promise(noop);
10562 handle(this, new Handler(onFulfilled, onRejected, res));
10566 function safeThen(self, onFulfilled, onRejected) {
10567 return new self.constructor(function (resolve, reject) {
10568 var res = new Promise(noop);
10569 res.then(resolve, reject);
10570 handle(self, new Handler(onFulfilled, onRejected, res));
10573 function handle(self, deferred) {
10574 while (self._65 === 3) {
10580 if (self._65 === 0) {
10581 if (self._40 === 0) {
10583 self._72 = deferred;
10586 if (self._40 === 1) {
10588 self._72 = [self._72, deferred];
10591 self._72.push(deferred);
10594 handleResolved(self, deferred);
10597 function handleResolved(self, deferred) {
10599 var cb = self._65 === 1 ? deferred.onFulfilled : deferred.onRejected;
10601 if (self._65 === 1) {
10602 resolve(deferred.promise, self._55);
10604 reject(deferred.promise, self._55);
10608 var ret = tryCallOne(cb, self._55);
10609 if (ret === IS_ERROR) {
10610 reject(deferred.promise, LAST_ERROR);
10612 resolve(deferred.promise, ret);
10616 function resolve(self, newValue) {
10617 // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
10618 if (newValue === self) {
10621 new TypeError('A promise cannot be resolved with itself.')
10626 (typeof newValue === 'object' || typeof newValue === 'function')
10628 var then = getThen(newValue);
10629 if (then === IS_ERROR) {
10630 return reject(self, LAST_ERROR);
10633 then === self.then &&
10634 newValue instanceof Promise
10637 self._55 = newValue;
10640 } else if (typeof then === 'function') {
10641 doResolve(then.bind(newValue), self);
10646 self._55 = newValue;
10650 function reject(self, newValue) {
10652 self._55 = newValue;
10654 Promise._87(self, newValue);
10658 function finale(self) {
10659 if (self._40 === 1) {
10660 handle(self, self._72);
10663 if (self._40 === 2) {
10664 for (var i = 0; i < self._72.length; i++) {
10665 handle(self, self._72[i]);
10671 function Handler(onFulfilled, onRejected, promise){
10672 this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
10673 this.onRejected = typeof onRejected === 'function' ? onRejected : null;
10674 this.promise = promise;
10678 * Take a potentially misbehaving resolver function and make sure
10679 * onFulfilled and onRejected are only called once.
10681 * Makes no guarantees about asynchrony.
10683 function doResolve(fn, promise) {
10685 var res = tryCallTwo(fn, function (value) {
10688 resolve(promise, value);
10689 }, function (reason) {
10692 reject(promise, reason);
10694 if (!done && res === IS_ERROR) {
10696 reject(promise, LAST_ERROR);
10700 },{"asap/raw":93}],95:[function(require,module,exports){
10703 //This file contains the ES6 extensions to the core Promises/A+ API
10705 var Promise = require('./core.js');
10707 module.exports = Promise;
10709 /* Static Functions */
10711 var TRUE = valuePromise(true);
10712 var FALSE = valuePromise(false);
10713 var NULL = valuePromise(null);
10714 var UNDEFINED = valuePromise(undefined);
10715 var ZERO = valuePromise(0);
10716 var EMPTYSTRING = valuePromise('');
10718 function valuePromise(value) {
10719 var p = new Promise(Promise._61);
10724 Promise.resolve = function (value) {
10725 if (value instanceof Promise) return value;
10727 if (value === null) return NULL;
10728 if (value === undefined) return UNDEFINED;
10729 if (value === true) return TRUE;
10730 if (value === false) return FALSE;
10731 if (value === 0) return ZERO;
10732 if (value === '') return EMPTYSTRING;
10734 if (typeof value === 'object' || typeof value === 'function') {
10736 var then = value.then;
10737 if (typeof then === 'function') {
10738 return new Promise(then.bind(value));
10741 return new Promise(function (resolve, reject) {
10746 return valuePromise(value);
10749 Promise.all = function (arr) {
10750 var args = Array.prototype.slice.call(arr);
10752 return new Promise(function (resolve, reject) {
10753 if (args.length === 0) return resolve([]);
10754 var remaining = args.length;
10755 function res(i, val) {
10756 if (val && (typeof val === 'object' || typeof val === 'function')) {
10757 if (val instanceof Promise && val.then === Promise.prototype.then) {
10758 while (val._65 === 3) {
10761 if (val._65 === 1) return res(i, val._55);
10762 if (val._65 === 2) reject(val._55);
10763 val.then(function (val) {
10768 var then = val.then;
10769 if (typeof then === 'function') {
10770 var p = new Promise(then.bind(val));
10771 p.then(function (val) {
10779 if (--remaining === 0) {
10783 for (var i = 0; i < args.length; i++) {
10789 Promise.reject = function (value) {
10790 return new Promise(function (resolve, reject) {
10795 Promise.race = function (values) {
10796 return new Promise(function (resolve, reject) {
10797 values.forEach(function(value){
10798 Promise.resolve(value).then(resolve, reject);
10803 /* Prototype Methods */
10805 Promise.prototype['catch'] = function (onRejected) {
10806 return this.then(null, onRejected);
10809 },{"./core.js":94}],96:[function(require,module,exports){
10810 // should work in any browser without browserify
10812 if (typeof Promise.prototype.done !== 'function') {
10813 Promise.prototype.done = function (onFulfilled, onRejected) {
10814 var self = arguments.length ? this.then.apply(this, arguments) : this
10815 self.then(null, function (err) {
10816 setTimeout(function () {
10822 },{}],97:[function(require,module,exports){
10823 // not "use strict" so we can declare global "Promise"
10825 var asap = require('asap');
10827 if (typeof Promise === 'undefined') {
10828 Promise = require('./lib/core.js')
10829 require('./lib/es6-extensions.js')
10832 require('./polyfill-done.js');
10834 },{"./lib/core.js":94,"./lib/es6-extensions.js":95,"./polyfill-done.js":96,"asap":92}]},{},[2])(2)