1/*! 2 * Less - Leaner CSS v3.5.0-beta 3 * http://lesscss.org 4 * 5 * Copyright (c) 2009-2018, Alexis Sellier <[email protected]> 6 * Licensed under the Apache-2.0 License. 7 * 8 */ 9 10 /** * @license Apache-2.0 11 */ 12 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){ 14var addDataAttr = require('./utils').addDataAttr, 15 browser = require('./browser'); 16 17module.exports = function(window, options) { 18 19 // use options from the current script tag data attribues 20 addDataAttr(options, browser.currentScript(window)); 21 22 if (options.isFileProtocol === undefined) { 23 options.isFileProtocol = /^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(window.location.protocol); 24 } 25 26 // Load styles asynchronously (default: false) 27 // 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. 31 // 32 options.async = options.async || false; 33 options.fileAsync = options.fileAsync || false; 34 35 // Interval between watch polls 36 options.poll = options.poll || (options.isFileProtocol ? 1000 : 1500); 37 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' 44 : 'production'); 45 46 var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(window.location.hash); 47 if (dumpLineNumbers) { 48 options.dumpLineNumbers = dumpLineNumbers[1]; 49 } 50 51 if (options.useFileCache === undefined) { 52 options.useFileCache = true; 53 } 54 55 if (options.onReady === undefined) { 56 options.onReady = true; 57 } 58 59 // TODO: deprecate and remove 'inlineJavaScript' thing - where it came from at all? 60 options.javascriptEnabled = (options.javascriptEnabled || options.inlineJavaScript) ? true : false; 61 62}; 63 64},{"./browser":3,"./utils":11}],2:[function(require,module,exports){ 65/** 66 * Kicks off less and compiles any stylesheets 67 * used in the browser distributed version of less 68 * to kick-start less using the browser api 69 */ 70/* global window, document */ 71 72// TODO - consider switching this out for a recommendation for this polyfill? 73// <script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script> 74// Browsers have good Promise support 75require('promise/polyfill'); 76 77var options = require('../less/default-options')(); 78 79if (window.less) { 80 for (key in window.less) { 81 if (window.less.hasOwnProperty(key)) { 82 options[key] = window.less[key]; 83 } 84 } 85} 86require('./add-default-options')(window, options); 87 88options.plugins = options.plugins || []; 89 90if (window.LESS_PLUGINS) { 91 options.plugins = options.plugins.concat(window.LESS_PLUGINS); 92} 93 94var less = module.exports = require('./index')(window, options); 95 96window.less = less; 97 98var css, head, style; 99 100// Always restore page visibility 101function resolveOrReject(data) { 102 if (data.filename) { 103 console.warn(data); 104 } 105 if (!options.async) { 106 head.removeChild(style); 107 } 108} 109 110if (options.onReady) { 111 if (/!watch/.test(window.location.hash)) { 112 less.watch(); 113 } 114 // Simulate synchronous stylesheet loading by hiding page rendering 115 if (!options.async) { 116 css = 'body { display: none !important }'; 117 head = document.head || document.getElementsByTagName('head')[0]; 118 style = document.createElement('style'); 119 120 style.type = 'text/css'; 121 if (style.styleSheet) { 122 style.styleSheet.cssText = css; 123 } else { 124 style.appendChild(document.createTextNode(css)); 125 } 126 127 head.appendChild(style); 128 } 129 less.registerStylesheetsImmediately(); 130 less.pageLoadFinished = less.refresh(less.env === 'development').then(resolveOrReject, resolveOrReject); 131} 132 133},{"../less/default-options":16,"./add-default-options":1,"./index":8,"promise/polyfill":100}],3:[function(require,module,exports){ 134var utils = require('./utils'); 135module.exports = { 136 createCSS: function (document, styles, sheet) { 137 // Strip the query-string 138 var href = sheet.href || ''; 139 140 // If there is no title set, use the filename, minus the extension 141 var id = 'less:' + (sheet.title || utils.extractId(href)); 142 143 // If this has already been inserted into the DOM, we may
143need to replace it 144 var oldStyleNode = document.getElementById(id); 145 var keepOldStyleNode = false; 146 147 // Create a new stylesheet node for insertion or (if necessary) replacement 148 var styleNode = document.createElement('style'); 149 styleNode.setAttribute('type', 'text/css'); 150 if (sheet.media) { 151 styleNode.setAttribute('media', sheet.media); 152 } 153 styleNode.id = id; 154 155 if (!styleNode.styleSheet) { 156 styleNode.appendChild(document.createTextNode(styles)); 157 158 // If new contents match contents of oldStyleNode, don't replace oldStyleNode 159 keepOldStyleNode = (oldStyleNode !== null && oldStyleNode.childNodes.length > 0 && styleNode.childNodes.length > 0 && 160 oldStyleNode.firstChild.nodeValue === styleNode.firstChild.nodeValue); 161 } 162 163 var head = document.getElementsByTagName('head')[0]; 164 165 // If there is no oldStyleNode, just append; otherwise, only append if we need 166 // to replace oldStyleNode with an updated stylesheet 167 if (oldStyleNode === null || keepOldStyleNode === false) { 168 var nextEl = sheet && sheet.nextSibling || null; 169 if (nextEl) { 170 nextEl.parentNode.insertBefore(styleNode, nextEl); 171 } else { 172 head.appendChild(styleNode); 173 } 174 } 175 if (oldStyleNode && keepOldStyleNode === false) { 176 oldStyleNode.parentNode.removeChild(oldStyleNode); 177 } 178 179 // For IE. 180 // This needs to happen *after* the style element is added to the DOM, otherwise IE 7 and 8 may crash. 181 // See http://social.msdn.microsoft.com/Forums/en-US/7e081b65-878a-4c22-8e68-c10d39c2ed32/internet-explorer-crashes-appending-style-element-to-head 182 if (styleNode.styleSheet) { 183 try { 184 styleNode.styleSheet.cssText = styles; 185 } catch (e) { 186 throw new Error('Couldn\'t reassign styleSheet.cssText.'); 187 } 188 } 189 }, 190 currentScript: function(window) { 191 var document = window.document; 192 return document.currentScript || (function() { 193 var scripts = document.getElementsByTagName('script'); 194 return scripts[scripts.length - 1]; 195 })(); 196 } 197}; 198 199},{"./utils":11}],4:[function(require,module,exports){ 200// Cache system is a bit outdated and could do with work 201 202module.exports = function(window, options, logger) { 203 var cache = null; 204 if (options.env !== 'development') { 205 try { 206 cache = (typeof window.localStorage === 'undefined') ? null : window.localStorage; 207 } catch (_) {} 208 } 209 return { 210 setCSS: function(path, lastModified, modifyVars, styles) { 211 if (cache) { 212 logger.info('saving ' + path + ' to cache.'); 213 try { 214 cache.setItem(path, styles); 215 cache.setItem(path + ':timestamp', lastModified); 216 if (modifyVars) { 217 cache.setItem(path + ':vars', JSON.stringify(modifyVars)); 218 } 219 } catch (e) { 220 // TODO - could do with adding more robust error handling 221 logger.error('failed to save "' + path + '" to local storage for caching.'); 222 } 223 } 224 }, 225 getCSS: function(path, webInfo, modifyVars) { 226 var css = cache && cache.getItem(path), 227 timestamp = cache && cache.getItem(path + ':timestamp'), 228 vars = cache && cache.getItem(path + ':vars'); 229 230 modifyVars = modifyVars || {}; 231 232 if (timestamp && webInfo.lastModified && 233 (new Date(webInfo.lastModified).valueOf() === 234 new Date(timestamp).valueOf()) && 235 (!modifyVars && !vars || JSON.stringify(modifyVars) === vars)) { 236 // Use local copy 237 return css; 238 } 239 } 240 }; 241}; 242 243},{}],5:[function(require,module,exports){ 244var utils = require('./utils'), 245 browser = require('./browser'); 246 247module.exports = function(window, less, options) { 248 249 function errorHTML(e, rootHref) { 250 var id = 'less-error-message:' + utils.extractId(rootHref || ''); 251 var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>'; 252 var elem = window.document.createElement('div'), timer, content, errors = []; 253 var filename = e.filename || rootHref; 254 var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; 255 256 elem.id = id; 257 elem.className = 'less-error-message';
258 259 content = '<h3>' + (e.type || 'Syntax') + 'Error: ' + (e.message || 'There is an error in your .less file') + 260 '</h3>' + '<p>in <a href="' + filename + '">' + filenameNoPath + '</a> '; 261 262 var errorline = function (e, i, classname) { 263 if (e.extract[i] !== undefined) { 264 errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1)) 265 .replace(/\{class\}/, classname) 266 .replace(/\{content\}/, e.extract[i])); 267 } 268 }; 269 270 if (e.line) { 271 errorline(e, 0, ''); 272 errorline(e, 1, 'line'); 273 errorline(e, 2, ''); 274 content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' + 275 '<ul>' + errors.join('') + '</ul>'; 276 } 277 if (e.stack && (e.extract || options.logLevel >= 4)) { 278 content += '<br/>Stack Trace</br />' + e.stack.split('\n').slice(1).join('<br/>'); 279 } 280 elem.innerHTML = content; 281 282 // CSS for error messages 283 browser.createCSS(window.document, [ 284 '.less-error-message ul, .less-error-message li {', 285 'list-style-type: none;', 286 'margin-right: 15px;', 287 'padding: 4px 0;', 288 'margin: 0;', 289 '}', 290 '.less-error-message label {', 291 'font-size: 12px;', 292 'margin-right: 15px;', 293 'padding: 4px 0;', 294 'color: #cc7777;', 295 '}', 296 '.less-error-message pre {', 297 'color: #dd6666;', 298 'padding: 4px 0;', 299 'margin: 0;', 300 'display: inline-block;', 301 '}', 302 '.less-error-message pre.line {', 303 'color: #ff0000;', 304 '}', 305 '.less-error-message h3 {', 306 'font-size: 20px;', 307 'font-weight: bold;', 308 'padding: 15px 0 5px 0;', 309 'margin: 0;', 310 '}', 311 '.less-error-message a {', 312 'color: #10a', 313 '}', 314 '.less-error-message .error {', 315 'color: red;', 316 'font-weight: bold;', 317 'padding-bottom: 2px;', 318 'border-bottom: 1px dashed red;', 319 '}' 320 ].join('\n'), { title: 'error-message' }); 321 322 elem.style.cssText = [ 323 'font-family: Arial, sans-serif', 324 'border: 1px solid #e00', 325 'background-color: #eee', 326 'border-radius: 5px', 327 '-webkit-border-radius: 5px', 328 '-moz-border-radius: 5px', 329 'color: #e00', 330 'padding: 15px', 331 'margin-bottom: 15px' 332 ].join(';'); 333 334 if (options.env === 'development') { 335 timer = setInterval(function () { 336 var document = window.document, 337 body = document.body; 338 if (body) { 339 if (document.getElementById(id)) { 340 body.replaceChild(elem, document.getElementById(id)); 341 } else { 342 body.insertBefore(elem, body.firstChild); 343 } 344 clearInterval(timer); 345 } 346 }, 10); 347 } 348 } 349 350 function removeErrorHTML(path) { 351 var node = window.document.getElementById('less-error-message:' + utils.extractId(path)); 352 if (node) { 353 node.parentNode.removeChild(node); 354 } 355 } 356 357 function removeErrorConsole(path) { 358 // no action 359 } 360 361 function removeError(path) { 362 if (!options.errorReporting || options.errorReporting === 'html') { 363 removeErrorHTML(path); 364 } else if (options.errorReporting === 'console') { 365 removeErrorConsole(path); 366 } else if (typeof options.errorReporting === 'function') { 367 options.errorReporting('remove', path); 368 } 369 } 370 371 function errorConsole(e, rootHref) { 372 var template = '{line} {content}'; 373 var filename = e.filename || rootHref; 374 var errors = []; 375 var content = (e.type || 'Syntax') + 'Error: ' + (e.message || 'There is an error in your .less file') + 376 ' in ' + filename; 377 378 var errorline = function (e, i, classname) { 379 if (e.extract[i] !== undefined) { 380 errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
381 .replace(/\{class\}/, classname) 382 .replace(/\{content\}/, e.extract[i])); 383 } 384 }; 385 386 if (e.line) { 387 errorline(e, 0, ''); 388 errorline(e, 1, 'line'); 389 errorline(e, 2, ''); 390 content += ' on line ' + e.line + ', column ' + (e.column + 1) + ':\n' + 391 errors.join('\n'); 392 } 393 if (e.stack && (e.extract || options.logLevel >= 4)) { 394 content += '\nStack Trace\n' + e.stack; 395 } 396 less.logger.error(content); 397 } 398 399 function error(e, rootHref) { 400 if (!options.errorReporting || options.errorReporting === 'html') { 401 errorHTML(e, rootHref); 402 } else if (options.errorReporting === 'console') { 403 errorConsole(e, rootHref); 404 } else if (typeof options.errorReporting === 'function') { 405 options.errorReporting('add', e, rootHref); 406 } 407 } 408 409 return { 410 add: error, 411 remove: removeError 412 }; 413}; 414 415},{"./browser":3,"./utils":11}],6:[function(require,module,exports){ 416/* global window, XMLHttpRequest */ 417 418module.exports = function(options, logger) { 419 420 var AbstractFileManager = require('../less/environment/abstract-file-manager.js'); 421 422 var fileCache = {}; 423 424 // TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load 425 var FileManager = function() { 426 }; 427 428 FileManager.prototype = new AbstractFileManager(); 429 430 FileManager.prototype.alwaysMakePathsAbsolute = function alwaysMakePathsAbsolute() { 431 return true; 432 }; 433 FileManager.prototype.join = function join(basePath, laterPath) { 434 if (!basePath) { 435 return laterPath; 436 } 437 return this.extractUrlParts(laterPath, basePath).path; 438 }; 439 FileManager.prototype.doXHR = function doXHR(url, type, callback, errback) { 440 441 var xhr = new XMLHttpRequest(); 442 var async = options.isFileProtocol ? options.fileAsync : true; 443 444 if (typeof xhr.overrideMimeType === 'function') { 445 xhr.overrideMimeType('text/css'); 446 } 447 logger.debug('XHR: Getting \'' + url + '\''); 448 xhr.open('GET', url, async); 449 xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); 450 xhr.send(null); 451 452 function handleResponse(xhr, callback, errback) { 453 if (xhr.status >= 200 && xhr.status < 300) { 454 callback(xhr.responseText, 455 xhr.getResponseHeader('Last-Modified')); 456 } else if (typeof errback === 'function') { 457 errback(xhr.status, url); 458 } 459 } 460 461 if (options.isFileProtocol && !options.fileAsync) { 462 if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { 463 callback(xhr.responseText); 464 } else { 465 errback(xhr.status, url); 466 } 467 } else if (async) { 468 xhr.onreadystatechange = function () { 469 if (xhr.readyState == 4) { 470 handleResponse(xhr, callback, errback); 471 } 472 }; 473 } else { 474 handleResponse(xhr, callback, errback); 475 } 476 }; 477 FileManager.prototype.supports = function(filename, currentDirectory, options, environment) { 478 return true; 479 }; 480 481 FileManager.prototype.clearFileCache = function() { 482 fileCache = {}; 483 }; 484 485 FileManager.prototype.loadFile = function loadFile(filename, currentDirectory, options, environment) { 486 // TODO: Add prefix support like less-node? 487 // What about multiple paths? 488 489 if (currentDirectory && !this.isPathAbsolute(filename)) { 490 filename = currentDirectory + filename; 491 } 492 493 filename = options.ext ? this.tryAppendExtension(filename, options.ext) : filename; 494 495 options = options || {}; 496 497 // sheet may be set to the stylesheet for the initial load or a collection of properties including 498 // some context variables for imports 499 var hrefParts = this.extractUrlParts(filename, window.location.href); 500 var href = hrefParts.url; 501 var self = this; 502 503 return new Promise(function(resolve, reject) { 504 if (options.useFileCache && fileCache[href]) { 505 try { 506 var lessText = fileCache[href]; 507 return resolve({ contents: lessText, filename: href, webInfo: { lastModified: new Date() }}); 508 } catch (e) { 509 return reject({ filename: href, message: 'Error loading file ' + href + ' error was ' + e.message }); 510 } 511 } 512 513 self.doXHR(href, options.mime, function doXHRCallback(data, lastModified) { 514 // per file cache 515 fileCache[href] = data; 516 517 // Use remote copy (re-parse) 518 resolve({ contents: data, filename: href, webInfo: { lastModified: lastModified }}); 519 }, function doXHRError(status, url) { 520 reject({ type: 'File', message: '\'' + url + '\' wasn\'t found (' + status + ')', href: href }); 521 }); 522 }); 523 }; 524 525 return FileManager; 526}; 527 528},{"../less/environment/abstract-file-manager.js":17}],7:[function(require,module,exports){ 529module.exports = function() { 530 531 var functionRegistry = require('./../less/functions/function-registry'); 532 533 function imageSize() { 534 throw { 535 type: 'Runtime', 536 message: 'Image size functions are not supported in browser version of less' 537 }; 538 } 539 540 var imageFunctions = { 541 'image-size': function(filePathNode) { 542 imageSize(this, filePathNode); 543 return -1; 544 }, 545 'image-width': function(filePathNode) { 546 imageSize(this, filePathNode); 547 return -1; 548 }, 549 'image-height': function(filePathNode) { 550 imageSize(this, filePathNode); 551 return -1; 552 } 553 }; 554 555 functionRegistry.addMultiple(imageFunctions); 556}; 557 558},{"./../less/functions/function-registry":26}],8:[function(require,module,exports){ 559// 560// index.js 561// Should expose the additional browser functions on to the less object 562//
563var addDataAttr = require('./utils').addDataAttr, 564 browser = require('./browser'); 565 566module.exports = function(window, options) { 567 var document = window.document; 568 var less = require('../less')(); 569 570 less.options = options; 571 var environment = less.environment, 572 FileManager = require('./file-manager')(options, less.logger), 573 fileManager = new FileManager(); 574 environment.addFileManager(fileManager); 575 less.FileManager = FileManager; 576 less.PluginLoader = require('./plugin-loader'); 577 578 require('./log-listener')(less, options); 579 var errors = require('./error-reporting')(window, less, options); 580 var cache = less.cache = options.cache || require('./cache')(window, options, less.logger); 581 require('./image-size')(less.environment); 582 583 // Setup user functions - Deprecate? 584 if (options.functions) { 585 less.functions.functionRegistry.addMultiple(options.functions); 586 } 587 588 var typePattern = /^text\/(x-)?less$/; 589 590 function clone(obj) { 591 return JSON.parse(JSON.stringify(obj || {})); 592 } 593 594 // only really needed for phantom 595 function bind(func, thisArg) { 596 var curryArgs = Array.prototype.slice.call(arguments, 2); 597 return function() { 598 var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0)); 599 return func.apply(thisArg, args); 600 }; 601 } 602 603 function loadStyles(modifyVars) { 604 var styles = document.getElementsByTagName('style'), 605 style; 606 607 for (var i = 0; i < styles.length; i++) { 608 style = styles[i]; 609 if (style.type.match(typePattern)) { 610 var instanceOptions = clone(options); 611 instanceOptions.modifyVars = modifyVars; 612 var lessText = style.innerHTML || ''; 613 instanceOptions.filename = document.location.href.replace(/#.*$/, ''); 614 615 /* jshint loopfunc:true */ 616 // use closure to store current style 617 less.render(lessText, instanceOptions, 618 bind(function(style, e, result) { 619 if (e) { 620 errors.add(e, 'inline'); 621 } else { 622 style.type = 'text/css'; 623 if (style.styleSheet) { 624 style.styleSheet.cssText = result.css; 625 } else { 626 style.innerHTML = result.css; 627 } 628 } 629 }, null, style)); 630 } 631 } 632 } 633 634 function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) { 635 636 var instanceOptions = clone(options); 637 addDataAttr(instanceOptions, sheet); 638 instanceOptions.mime = sheet.type; 639 640 if (modifyVars) { 641 instanceOptions.modifyVars = modifyVars; 642 } 643 644 function loadInitialFileCallback(loadedFile) { 645 646 var data = loadedFile.contents, 647 path = loadedFile.filename, 648 webInfo = loadedFile.webInfo; 649 650 var newFileInfo = { 651 currentDirectory: fileManager.getPath(path), 652 filename: path, 653 rootFilename: path, 654 relativeUrls: instanceOptions.relativeUrls}; 655 656 newFileInfo.entryPath = newFileInfo.currentDirectory; 657 newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory; 658 659 if (webInfo) { 660 webInfo.remaining = remaining; 661 662 var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars); 663 if (!reload && css) { 664 webInfo.local = true; 665 callback(null, css, data, sheet, webInfo, path); 666 return; 667 } 668 669 } 670 671 // TODO add tests around how this behaves when reloading 672 errors.remove(path); 673 674 instanceOptions.rootFileInfo = newFileInfo; 675 less.render(data, instanceOptions, function(e, result) { 676 if (e) { 677 e.href = path; 678 callback(e); 679 } else { 680 cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css); 681 callback(null, result.css, data, sheet, webInfo, path); 682 } 683 }); 684 } 685 686 fileManager.loadFile(sheet.href, null, instanceOptions, environment) 687 .then(function(loadedFile) { 688 loadInitialFileCallback(loadedFile); 689 }).catch(function(err) { 690 console.log(err); 691 callback(err); 692 }); 693 694 } 695 696 function loadStyleSheets(callback, reload, modifyVars) { 697 for (var i = 0; i < less.sheets.length; i++) { 698 loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars); 699 } 700 } 701 702 function initRunningMode() { 703 if (less.env === 'development') { 704 less.watchTimer = setInterval(function () { 705 if (less.watchMode) { 706 fileManager.clearFileCache(); 707 loadStyleSheets(function (e, css, _, sheet, webInfo) { 708 if (e) { 709 errors.add(e, e.href || sheet.href); 710 } else if (css) { 711 browser.createCSS(window.document, css, sheet); 712 } 713 }); 714 } 715 }, options.poll); 716 } 717 } 718 719 // 720 // Watch mode 721 // 722 less.watch = function () { 723 if (!less.watchMode ) { 724 less.env = 'development'; 725 initRunningMode(); 726 } 727 this.watchMode = true; 728 return true; 729 }; 730 731 less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; }; 732 733 // 734 // Synchronously get all <link> tags with the 'rel' attribute set to 735 // "stylesheet/less". 736 // 737 less.registerStylesheetsImmediately = function() { 738 var links = document.getElementsByTagName('link'); 739 less.sheets = []; 740 741 for (var i = 0; i < links.length; i++) { 742 if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && 743 (links[i].type.match(typePattern)))) { 744 less.sheets.push(links[i]); 745 } 746 } 747 }; 748 749 // 750 // Asynchronously get all <link> tags with the 'rel' attribute set to 751 // "stylesheet/less", returning a Promise. 752 // 753 less.registerStylesheets = function() { 754 return new Promise(function(resolve, reject) { 755 less.registerStylesheetsImmediately(); 756 resolve(); 757 }); 758 }; 759 760 // 761 // With this function, it's possible to alter variables and re-render 762 // CSS without reloading less-files 763 // 764 less.modifyVars = function(record) { 765 return less.refresh(true, record, false); 766 }; 767 768 less.refresh = function (reload, modifyVars, clearFileCache) { 769 if ((reload || clearFileCache) && clearFileCache !== false) { 770 fileManager.clearFileCache(); 771 } 772 return new Promise(function (resolve, reject) { 773 var startTime, endTime, totalMilliseconds, remainingSheets; 774 startTime = endTime = new Date(); 775 776 // Set counter for remaining unprocessed sheets 777 remainingSheets = less.sheets.length; 778 779 if (remainingSheets === 0) { 780 781 endTime = new Date(); 782 totalMilliseconds = endTime - startTime; 783 less.logger.info('Less has finished and no sheets were loaded.'); 784 resolve({ 785 startTime: startTime, 786 endTime: endTime, 787 totalMilliseconds: totalMilliseconds, 788 sheets: less.sheets.length 789 }); 790 791 } else { 792 // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array 793 loadStyleSheets(function (e, css, _, sheet, webInfo) { 794 if (e) { 795 errors.add(e, e.href || sheet.href); 796 reject(e); 797 return; 798 } 799 if (webInfo.local) { 800 less.logger.info('Loading ' + sheet.href + ' from cache.'); 801 } else { 802 less.logger.info('Rendered ' + sheet.href + ' successfully.'); 803 } 804 browser.createCSS(window.document, css, sheet); 805 less.logger.info('CSS for ' + sheet.href + ' generated in ' + (ne
805w Date() - endTime) + 'ms'); 806 807 // Count completed sheet 808 remainingSheets--; 809 810 // Check if the last remaining sheet was processed and then call the promise 811 if (remainingSheets === 0) { 812 totalMilliseconds = new Date() - startTime; 813 less.logger.info('Less has finished. CSS generated in ' + totalMilliseconds + 'ms'); 814 resolve({ 815 startTime: startTime, 816 endTime: endTime, 817 totalMilliseconds: totalMilliseconds, 818 sheets: less.sheets.length 819 }); 820 } 821 endTime = new Date(); 822 }, reload, modifyVars); 823 } 824 825 loadStyles(modifyVars); 826 }); 827 }; 828 829 less.refreshStyles = loadStyles; 830 return less; 831}; 832 833},{"../less":35,"./browser":3,"./cache":4,"./error-reporting":5,"./file-manager":6,"./image-size":7,"./log-listener":9,"./plugin-loader":10,"./utils":11}],9:[function(require,module,exports){ 834module.exports = function(less, options) { 835 836 var logLevel_debug = 4, 837 logLevel_info = 3, 838 logLevel_warn = 2, 839 logLevel_error = 1; 840 841 // The amount of logging in the javascript console. 842 // 3 - Debug, information and errors 843 // 2 - Information and errors 844 // 1 - Errors 845 // 0 - None 846 // Defaults to 2 847 options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : (options.env === 'development' ? logLevel_info : logLevel_error); 848 849 if (!options.loggers) { 850 options.loggers = [{ 851 debug: function(msg) { 852 if (options.logLevel >= logLevel_debug) { 853 console.log(msg); 854 } 855 }, 856 info: function(msg) { 857 if (options.logLevel >= logLevel_info) { 858 console.log(msg); 859 } 860 }, 861 warn: function(msg) { 862 if (options.logLevel >= logLevel_warn) { 863 console.warn(msg); 864 } 865 }, 866 error: function(msg) { 867 if (options.logLevel >= logLevel_error) { 868 console.error(msg); 869 } 870 } 871 }]; 872 } 873 for (var i = 0; i < options.loggers.length; i++) { 874 less.logger.addListener(options.loggers[i]); 875 } 876}; 877 878},{}],10:[function(require,module,exports){ 879// TODO: Add tests for browser @plugin 880/* global window */ 881 882var AbstractPluginLoader = require('../less/environment/abstract-plugin-loader.js'); 883 884/** 885 * Browser Plugin Loader 886 */ 887var PluginLoader = function(less) { 888 this.less = less; 889 // shim for browser require? 890 this.require = require; 891}; 892 893PluginLoader.prototype = new AbstractPluginLoader(); 894 895PluginLoader.prototype.loadPlugin = function(filename, basePath, context, environment, fileManager) { 896 return new Promise(function(fulfill, reject) { 897 fileManager.loadFile(filename, basePath, context, environment) 898 .then(fulfill).catch(reject); 899 }); 900}; 901 902module.exports = PluginLoader; 903 904 905},{"../less/environment/abstract-plugin-loader.js":18}],11:[function(require,module,exports){ 906module.exports = { 907 extractId: function(href) { 908 return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain 909 .replace(/[\?\&]livereload=\w+/, '') // Remove LiveReload cachebuster 910 .replace(/^\//, '') // Remove root / 911 .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension 912 .replace(/[^\.\w-]+/g, '-') // Replace illegal characters 913 .replace(/\./g, ':');
913 // Replace dots with colons(for valid id) 914 }, 915 addDataAttr: function(options, tag) { 916 for (var opt in tag.dataset) { 917 if (tag.dataset.hasOwnProperty(opt)) { 918 if (opt === 'env' || opt === 'dumpLineNumbers' || opt === 'rootpath' || opt === 'errorReporting') { 919 options[opt] = tag.dataset[opt]; 920 } else { 921 try { 922 options[opt] = JSON.parse(tag.dataset[opt]); 923 } 924 catch (_) {} 925 } 926 } 927 } 928 } 929}; 930 931},{}],12:[function(require,module,exports){ 932var contexts = {}; 933module.exports = contexts; 934 935var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) { 936 if (!original) { return; } 937 938 for (var i = 0; i < propertiesToCopy.length; i++) { 939 if (original.hasOwnProperty(propertiesToCopy[i])) { 940 destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; 941 } 942 } 943}; 944 945/* 946 parse is used whilst parsing 947 */ 948var parseCopyProperties = [ 949 // options 950 'paths', // option - unmodified - paths to search for imports on 951 'relativeUrls', // option - whether to adjust URL's to be relative 952 'rootpath', // option - rootpath to append to URL's 953 'strictImports', // option - 954 'insecure', // option - whether to allow imports from insecure ssl hosts 955 'dumpLineNumbers', // option - whether to dump line numbers 956 'compress', // option - whether to compress 957 'syncImport', // option - whether to import synchronously 958 'chunkInput', // option - whether to chunk input. more performant but causes parse issues. 959 'mime', // browser only - mime type for sheet import 960 'useFileCache', // browser only - whether to use the per file session cache 961 // context 962 'processImports', // option & context - whether to process imports. if false then imports will not be imported. 963 // Used by the import manager to stop multiple import visitors being created. 964 'pluginManager' // Used as the plugin manager for the session 965]; 966 967contexts.Parse = function(options) { 968 copyFromOriginal(options, this, parseCopyProperties); 969 970 if (typeof this.paths === 'string') { this.paths = [this.paths]; } 971}; 972 973var evalCopyProperties = [ 974 'paths', // additional include paths 975 'compress', // whether to compress 976 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri) 977 'strictMath', // whether math has to be within parenthesis 978 'strictUnits', // whether units need to evaluate correctly 979 'sourceMap', // whether to output a source map 980 'importMultiple', // whether we are currently importing multiple copies 981 'urlArgs', // whether to add args into url tokens 982 'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false 983 'pluginManager', // Used as the plugin manager for the session 984 'importantScope' // used to bubble up !important statements 985]; 986 987contexts.Eval = function(options, frames) { 988 copyFromOriginal(options, this, evalCopyProperties); 989 990 if (typeof this.paths === 'string') { this.paths = [this.paths]; } 991 992 this.frames = frames || []; 993 this.importantScope = this.importantScope || []; 994}; 995 996contexts.Eval.prototype.inParenthesis = function () { 997 if (!this.parensStack) { 998 this.parensStack = []; 999 } 1000 this.parensStack.push(true); 1001}; 1002 1003contexts.Eval.prototype.outOfParenthesis = function () { 1004 this.parensStack.pop(); 1005}; 1006 1007contexts.Eval.prototype.mathOn = true; 1008contexts.Eval.prototype.isMathOn = function () { 1009 if (!this.mathOn) { 1010 return false; 1011 } 1012 return this.strictMath ? (this.parensStack && this.parensStack.length) : true; 1013}; 1014 1015contexts.Eval.prototype.isPathRelative = function (path) { 1016 return !/^(?:[a-z-]+:|\/|#)/i.test(path); 1017}; 1018 1019contexts.Eval.prototype.normalizePath = function( path ) { 1020 var 1021 segments = path.split('/').reverse(), 1022 segment; 1023 1024 path = []; 1025 while (segments.length !== 0 ) { 1026 segment = segments.pop(); 1027 switch ( segment ) { 1028 case '.': 1029 break; 1030 case '..': 1031 if ((path.length === 0) || (path[path.length - 1] === '..')) { 1032 path.push( segment ); 1033 } else { 1034 path.pop(); 1035 } 1036 break; 1037 default: 1038 path.push( segment ); 1039 break; 1040 } 1041 } 1042 1043 return path.join('/'); 1044}; 1045 1046// todo - do the same for the toCSS ? 1047 1048},{}],13:[function(require,module,exports){ 1049module.exports = { 1050 'aliceblue':'#f0f8ff', 1051 'antiquewhite':'#faebd7', 1052 'aqua':'#00ffff', 1053 'aquamarine':'#7fffd4', 1054 'azure':'#f0ffff', 1055 'beige':'#f5f5dc', 1056 'bisque':'#ffe4c4', 1057 'black':'#000000', 1058 'blanchedalmond':'#ffebcd', 1059 'blue':'#0000ff', 1060 'blueviolet':'#8a2be2', 1061 'brown':'#a52a2a', 1062 'burlywood':'#deb887', 1063 'cadetblue':'#5f9ea0', 1064 'chartreuse':'#7fff00', 1065 'chocolate':'#d2691e', 1066 'coral':'#ff7f50', 1067 'cornflowerblue':'#6495ed', 1068 'cornsilk':'#fff8dc', 1069 'crimson':'#dc143c', 1070 'cyan':'#00ffff', 1071 'darkblue':'#00008b', 1072 'darkcyan':'#008b8b', 1073 'darkgoldenrod':'#b8860b', 1074 'darkgray':'#a9a9a9', 1075 'darkgrey':'#a9a9a9', 1076 'darkgreen':'#006400', 1077 'darkkhaki':'#bdb76b', 1078 'darkmagenta':'#8b008b', 1079 'darkolivegreen':'#556b2f', 1080 'darkorange':'#ff8c00', 1081 'darkorchid':'#9932cc', 1082 'darkred':'#8b0000', 1083 'darksalmon':'#e9967a', 1084 'darkseagreen':'#8fbc8f', 1085 'darkslateblue':'#483d8b', 1086 'darkslategray':'#2f4f4f', 1087 'darkslategrey':'#2f4f4f', 1088 'darkturquoise':'#00ced1', 1089 'darkviolet':'#9400d3', 1090 'deeppink':'#ff1493', 1091 'deepskyblue':'#00bfff', 1092 'dimgray':'#696969', 1093 'dimgrey':'#696969', 1094 'dodgerblue':'#1e90ff', 1095 'firebrick':'#b22222', 1096 'floralwhite':'#fffaf0', 1097 'forestgreen':'#228b22', 1098 'fuchsia':'#ff00ff', 1099 'gainsboro':'#dcdcdc', 1100 'ghostwhite':'#f8f8ff', 1101 'gold':'#ffd700', 1102 'goldenrod':'#daa520', 1103 'gray':'#808080', 1104 'grey':'#808080', 1105 'green':'#008000', 1106 'greenyellow':'#adff2f', 1107 'honeydew':'#f0fff0', 1108 'hotpink':'#ff69b4', 1109 'indianred':'#cd5c5c', 1110 'indigo':'#4b0082', 1111 'ivory':'#fffff0', 1112 'khaki':'#f0e68c', 1113 'lavender':'#e6e6fa', 1114 'lavenderblush':'#fff0f5', 1115 'lawngreen':'#7cfc00', 1116 'lemonchiffon':'#fffacd', 1117 'lightblue':'#add8e6', 1118 'lightcoral':'#f08080', 1119 'lightcyan':'#e0ffff', 1120 'lightgoldenrodyellow':'#fafad2', 1121 'lightgray':'#d3d3d3', 1122 'lightgrey':'#d3d3d3', 1123 'lightgreen':'#90ee90', 1124 'lightpink':'#ffb6c1', 1125 'lightsalmon':'#ffa07a', 1126 'lightseagreen':'#20b2aa', 1127 'lightskyblue':'#87cefa', 1128 'lightslategray':'#778899', 1129 'lightslategrey':'#778899', 1130 'lightsteelblue':'#b0c4de', 1131 'lightyellow':'#ffffe0', 1132 'lime':'#00ff00', 1133 'limegreen':'#32cd32', 1134 'linen':'#faf0e6', 1135 'magenta':'#ff00ff', 1136 'maroon':'#800000', 1137 'mediumaquamarine':'#66cdaa', 1138 'mediumblue':'#0000cd', 1139 'mediumorchid':'#ba55d3', 1140 'mediumpurple':'#9370d8', 1141 'mediumseagreen':'#3cb371', 1142 'mediumslateblue':'#7b68ee', 1143 'mediumspringgreen':'#00fa9a', 1144 'mediumturquoise':'#48d1cc', 1145 'mediumvioletred':'#c71585', 1146 'midnightblue':'#191970', 1147 'mintcream':'#f5fffa', 1148 'mistyrose':'#ffe4e1', 1149 'moccasin':'#ffe4b5',
1150 'navajowhite':'#ffdead', 1151 'navy':'#000080', 1152 'oldlace':'#fdf5e6', 1153 'olive':'#808000', 1154 'olivedrab':'#6b8e23', 1155 'orange':'#ffa500', 1156 'orangered':'#ff4500', 1157 'orchid':'#da70d6', 1158 'palegoldenrod':'#eee8aa', 1159 'palegreen':'#98fb98', 1160 'paleturquoise':'#afeeee', 1161 'palevioletred':'#d87093', 1162 'papayawhip':'#ffefd5', 1163 'peachpuff':'#ffdab9', 1164 'peru':'#cd853f', 1165 'pink':'#ffc0cb', 1166 'plum':'#dda0dd', 1167 'powderblue':'#b0e0e6', 1168 'purple':'#800080', 1169 'rebeccapurple':'#663399', 1170 'red':'#ff0000', 1171 'rosybrown':'#bc8f8f', 1172 'royalblue':'#4169e1', 1173 'saddlebrown':'#8b4513', 1174 'salmon':'#fa8072', 1175 'sandybrown':'#f4a460', 1176 'seagreen':'#2e8b57', 1177 'seashell':'#fff5ee', 1178 'sienna':'#a0522d', 1179 'silver':'#c0c0c0', 1180 'skyblue':'#87ceeb', 1181 'slateblue':'#6a5acd', 1182 'slategray':'#708090', 1183 'slategrey':'#708090', 1184 'snow':'#fffafa', 1185 'springgreen':'#00ff7f', 1186 'steelblue':'#4682b4', 1187 'tan':'#d2b48c', 1188 'teal':'#008080', 1189 'thistle':'#d8bfd8', 1190 'tomato':'#ff6347', 1191 'turquoise':'#40e0d0', 1192 'violet':'#ee82ee', 1193 'wheat':'#f5deb3', 1194 'white':'#ffffff', 1195 'whitesmoke':'#f5f5f5', 1196 'yellow':'#ffff00', 1197 'yellowgreen':'#9acd32' 1198}; 1199},{}],14:[function(require,module,exports){ 1200module.exports = { 1201 colors: require('./colors'), 1202 unitConversions: require('./unit-conversions') 1203}; 1204 1205},{"./colors":13,"./unit-conversions":15}],15:[function(require,module,exports){ 1206module.exports = { 1207 length: { 1208 'm': 1, 1209 'cm': 0.01, 1210 'mm': 0.001, 1211 'in': 0.0254, 1212 'px': 0.0254 / 96, 1213 'pt': 0.0254 / 72, 1214 'pc': 0.0254 / 72 * 12 1215 }, 1216 duration: { 1217 's': 1, 1218 'ms': 0.001 1219 }, 1220 angle: { 1221 'rad': 1 / (2 * Math.PI), 1222 'deg': 1 / 360, 1223 'grad': 1 / 400, 1224 'turn': 1 1225 } 1226}; 1227},{}],16:[function(require,module,exports){ 1228// Export a new default each time 1229module.exports = function() { 1230 return { 1231 /* Outputs a makefile import dependency list to stdout. */ 1232 depends: false, 1233 1234 /* Compress using less built-in compression. 1235 * This does an okay job but does not utilise all the tricks of 1236 * dedicated css compression. */ 1237 compress: false, 1238 1239 /* Runs the less parser and just reports errors without any output. */ 1240 lint: false, 1241 1242 /* Sets available include paths. 1243 * If the file in an @import rule does not exist at that exact location, 1244 * less will look for it at the location(s) passed to this option. 1245 * You might use this for instance to specify a path to a library which 1246 * you want to be referenced simply and relatively in the less files. */ 1247 paths: [], 1248 1249 /* color output in the terminal */ 1250 color: true, 1251 1252 /* The strictImports controls whether the compiler will allow an @import inside of either 1253 * @media blocks or (a later addition) other selector blocks. 1254 * See: https://github.com/less/less.js/issues/656 */ 1255 strictImports: false, 1256 1257 /* Allow Imports from Insecure HTTPS Hosts */ 1258 insecure: false, 1259 1260 /* Allows you to add a path to every generated import and url in your css. 1261 * This does not affect less import statements that are processed, just ones 1262 * that are left in the output css. */ 1263 rootpath: '', 1264 1265 /* By default URLs are kept as-is, so if you import a file in a sub-directory 1266 * that references an image, exactly the same URL will be output in the css. 1267 * This option allows you to re-write URL's in imported files so that the 1268 * URL is always relative to the base imported file */ 1269 relativeUrls: false, 1270 1271 /* Compatibility with IE8. Used for limiting data-uri length */ 1272 ieCompat: false, // true until 3.0 1273 1274 /* Without this option on, Less will try and process all math in your css */ 1275 strictMath: false, 1276 1277 /* Without this option, less attempts to guess at the output unit when it does maths. */ 1278 strictUnits: false, 1279 1280 /* Effectively the declaration is put at the top of your base Less file, 1281 * meaning it can be used but it also can be overridden if this variable 1282 * is defined in the file. */ 1283 globalVars: null, 1284 1285 /* As opposed to the global variable option, this puts the declaration at the 1286 * end of your base file, meaning it will override anything defined in your Less file. */ 1287 modifyVars: null, 1288 1289 /* This option allows you to specify a argument to go on to every URL. */ 1290 urlArgs: '' 1291 } 1292} 1293},{}],17:[function(require,module,exports){ 1294var abstractFileManager = function() { 1295}; 1296 1297abstractFileManager.prototype.getPath = function (filename) { 1298 var j = filename.lastIndexOf('?'); 1299 if (j > 0) { 1300 filename = filename.slice(0, j); 1301 } 1302 j = filename.lastIndexOf('/'); 1303 if (j < 0) { 1304 j = filename.lastIndexOf('\\'); 1305 } 1306 if (j < 0) { 1307 return ''; 1308 } 1309 return filename.slice(0, j + 1); 1310}; 1311 1312abstractFileManager.prototype.tryAppendExtension = function(path, ext) { 1313 return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext; 1314}; 1315 1316abstractFileManager.prototype.tryAppendLessExtension = function(path) { 1317 return this.tryAppendExtension(path, '.less'); 1318}; 1319 1320abstractFileManager.prototype.supportsSync = function() { 1321 return false;
1322}; 1323 1324abstractFileManager.prototype.alwaysMakePathsAbsolute = function() { 1325 return false; 1326}; 1327 1328abstractFileManager.prototype.isPathAbsolute = function(filename) { 1329 return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename); 1330}; 1331// TODO: pull out / replace? 1332abstractFileManager.prototype.join = function(basePath, laterPath) { 1333 if (!basePath) { 1334 return laterPath; 1335 } 1336 return basePath + laterPath; 1337}; 1338 1339abstractFileManager.prototype.pathDiff = function pathDiff(url, baseUrl) { 1340 // diff between two paths to create a relative path 1341 1342 var urlParts = this.extractUrlParts(url), 1343 baseUrlParts = this.extractUrlParts(baseUrl), 1344 i, max, urlDirectories, baseUrlDirectories, diff = ''; 1345 if (urlParts.hostPart !== baseUrlParts.hostPart) { 1346 return ''; 1347 } 1348 max = Math.max(baseUrlParts.directories.length, urlParts.directories.length); 1349 for (i = 0; i < max; i++) { 1350 if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; } 1351 } 1352 baseUrlDirectories = baseUrlParts.directories.slice(i); 1353 urlDirectories = urlParts.directories.slice(i); 1354 for (i = 0; i < baseUrlDirectories.length - 1; i++) { 1355 diff += '../'; 1356 } 1357 for (i = 0; i < urlDirectories.length - 1; i++) { 1358 diff += urlDirectories[i] + '/'; 1359 } 1360 return diff; 1361}; 1362// helper function, not part of API 1363abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, baseUrl) { 1364 // urlParts[1] = protocol://hostname/ OR / 1365 // urlParts[2] = / if path relative to host base 1366 // urlParts[3] = directories 1367 // urlParts[4] = filename 1368 // urlParts[5] = parameters 1369 1370 var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i, 1371 urlParts = url.match(urlPartsRegex), 1372 returner = {}, rawDirectories = [], directories = [], i, baseUrlParts; 1373 1374 if (!urlParts) { 1375 throw new Error('Could not parse sheet href - \'' + url + '\''); 1376 } 1377 1378 // Stylesheets in IE don't always return the full path 1379 if (baseUrl && (!urlParts[1] || urlParts[2])) { 1380 baseUrlParts = baseUrl.match(urlPartsRegex); 1381 if (!baseUrlParts) { 1382 throw new Error('Could not parse page url - \'' + baseUrl + '\''); 1383 } 1384 urlParts[1] = urlParts[1] || baseUrlParts[1] || ''; 1385 if (!urlParts[2]) { 1386 urlParts[3] = baseUrlParts[3] + urlParts[3]; 1387 } 1388 } 1389 1390 if (urlParts[3]) { 1391 rawDirectories = urlParts[3].replace(/\\/g, '/').split('/'); 1392 1393 // collapse '..' and skip '.' 1394 for (i = 0; i < rawDirectories.length; i++) { 1395 1396 if (rawDirectories[i] === '..') { 1397 directories.pop(); 1398 } 1399 else if (rawDirectories[i] !== '.') { 1400 directories.push(rawDirectories[i]); 1401 } 1402 1403 } 1404 } 1405 1406 returner.hostPart = urlParts[1]; 1407 returner.directories = directories; 1408 returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/'); 1409 returner.path = (urlParts[1] || '') + directories.join('/'); 1410 returner.filename = urlParts[4]; 1411 returner.fileUrl = returner.path + (urlParts[4] || ''); 1412 returner.url = returner.fileUrl + (urlParts[5] || ''); 1413 return returner; 1414}; 1415 1416module.exports = abstractFileManager; 1417 1418},{}],18:[function(require,module,exports){ 1419var functionRegistry = require('../functions/function-registry'), 1420 LessError = require('../less-error'); 1421 1422var AbstractPluginLoader = function() { 1423}; 1424 1425function error(msg, type) { 1426 throw new LessError( 1427 { 1428 type: type || 'Syntax', 1429 message: msg 1430 } 1431 ); 1432} 1433AbstractPluginLoader.prototype.evalPlugin = function(contents, context, imports, pluginOptions, fileInfo) { 1434 1435 var loader, 1436 registry, 1437 pluginObj, 1438 localModule, 1439 pluginManager, 1440 filename; 1441 1442 pluginManager = context.pluginManager; 1443 1444 if (fileInfo) { 1445 if (typeof fileInfo === 'string') { 1446 filename = fileInfo; 1447 } 1448 else { 1449 filename = fileInfo.filename; 1450 } 1451 } 1452 var shortname = (new this.less.FileManager()).extractUrlParts(filename).filename; 1453 1454 if (filename) { 1455 pluginObj = pluginManager.get(filename); 1456 1457 if (pluginObj) { 1458 this.trySetOptions(pluginObj, filename, shortname, pluginOptions); 1459 try { 1460 if (pluginObj.use) { 1461 pluginObj.use.call(this.context, pluginObj); 1462 } 1463 } 1464 catch (e) { 1465 e.message = 'Error during @plugin call'; 1466 return new this.less.LessError(e, imports, filename); 1467 } 1468 return pluginObj; 1469 } 1470 } 1471 localModule = { 1472 exports: {}, 1473 pluginManager: pluginManager, 1474 fileInfo: fileInfo 1475 }; 1476 registry = functionRegistry.create(); 1477 1478 var registerPlugin = function(obj) { 1479 pluginObj = obj; 1480 }; 1481 1482 try { 1483 loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents); 1484 loader(localModule, this.require, registerPlugin, registry, this.less.tree, this.less, fileInfo); 1485 } catch (e) { 1486 return new this.less.LessError(e, imports, filename); 1487 } 1488 1489 if (!pluginObj) { 1490 pluginObj = localModule.exports; 1491 } 1492 pluginObj = this.validatePlugin(pluginObj, filename, shortname); 1493 1494 if (pluginObj) { 1495 // Run on first load 1496 pluginManager.addPlugin(pluginObj, fileInfo.filename, registry); 1497 pluginObj.functions = registry.getLocalFunctions(); 1498 pluginObj.imports = imports; 1499 pluginObj.filename = filename; 1500 1501 this.trySetOptions(pluginObj, filename, shortname, pluginOptions); 1502 1503 // Run every @plugin call 1504 try { 1505 if (pluginObj.use) { 1506 pluginObj.use.call(this.context, pluginObj); 1507 } 1508 } 1509 catch (e) { 1510 e.message = 'Error during @plugin call'; 1511 return new this.less.LessError(e, imports, filename); 1512 } 1513 1514 } 1515 else { 1516 return new this.less.LessError({ message: 'Not a valid plugin' }); 1517 } 1518 1519 return pluginObj; 1520 1521}; 1522 1523AbstractPluginLoader.prototype.trySetOptions = function(plugin, filename, name, options) { 1524 if (options) { 1525 if (!plugin.setOptions) { 1526 error('Options have been provided but the plugin ' + n
1526ame + ' does not support any options.'); 1527 return null; 1528 } 1529 try { 1530 plugin.setOptions(options); 1531 } 1532 catch (e) { 1533 error('Error setting options on plugin ' + name + '\n' + e.message); 1534 return null; 1535 } 1536 } 1537}; 1538 1539AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename, name) { 1540 if (plugin) { 1541 // support plugins being a function 1542 // so that the plugin can be more usable programmatically 1543 if (typeof plugin === 'function') { 1544 plugin = new plugin(); 1545 } 1546 1547 if (plugin.minVersion) { 1548 if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { 1549 error('Plugin ' + name + ' requires version ' + this.versionToString(plugin.minVersion)); 1550 return null; 1551 } 1552 } 1553 return plugin; 1554 } 1555 return null; 1556}; 1557 1558AbstractPluginLoader.prototype.compareVersion = function(aVersion, bVersion) { 1559 if (typeof aVersion === 'string') { 1560 aVersion = aVersion.match(/^(\d+)\.?(\d+)?\.?(\d+)?/); 1561 aVersion.shift(); 1562 } 1563 for (var i = 0; i < aVersion.length; i++) { 1564 if (aVersion[i] !== bVersion[i]) { 1565 return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1; 1566 } 1567 } 1568 return 0; 1569}; 1570AbstractPluginLoader.prototype.versionToString = function(version) { 1571 var versionString = ''; 1572 for (var i = 0; i < version.length; i++) { 1573 versionString += (versionString ? '.' : '') + version[i]; 1574 } 1575 return versionString; 1576}; 1577AbstractPluginLoader.prototype.printUsage = function(plugins) { 1578 for (var i = 0; i < plugins.length; i++) { 1579 var plugin = plugins[i]; 1580 if (plugin.printUsage) { 1581 plugin.printUsage(); 1582 } 1583 } 1584}; 1585 1586module.exports = AbstractPluginLoader; 1587 1588 1589},{"../functions/function-registry":26,"../less-error":36}],19:[function(require,module,exports){ 1590/** 1591 * @todo Document why this abstraction exists, and the relationship between 1592 * environment, file managers, and plugin manager 1593 */ 1594 1595var logger = require('../logger'); 1596var environment = function(externalEnvironment, fileManagers) { 1597 this.fileManagers = fileManagers || []; 1598 externalEnvironment = externalEnvironment || {}; 1599 1600 var optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator'], 1601 requiredFunctions = [], 1602 functions = requiredFunctions.concat(optionalFunctions); 1603 1604 for (var i = 0; i < functions.length; i++) { 1605 var propName = functions[i], 1606 environmentFunc = externalEnvironment[propName]; 1607 if (environmentFunc) { 1608 this[propName] = environmentFunc.bind(externalEnvironment); 1609 } else if (i < requiredFunctions.length) { 1610 this.warn('missing required function in environment - ' + propName); 1611 } 1612 } 1613}; 1614 1615environment.prototype.getFileManager = function (filename, currentDirectory, options, environment, isSync) { 1616 1617 if (!filename) { 1618 logger.warn('getFileManager called with no filename.. Please report this issue. continuing.'); 1619 } 1620 if (currentDirectory == null) { 1621 logger.warn('getFileManager called with null directory.. Please report this issue. continuing.'); 1622 } 1623 1624 var fileManagers = this.fileManagers; 1625 if (options.pluginManager) { 1626 fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers()); 1627 } 1628 for (var i = fileManagers.length - 1; i >= 0 ; i--) { 1629 var fileManager = fileManagers[i];
1630 if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) { 1631 return fileManager; 1632 } 1633 } 1634 return null; 1635}; 1636 1637environment.prototype.addFileManager = function (fileManager) { 1638 this.fileManagers.push(fileManager); 1639}; 1640 1641environment.prototype.clearFileManagers = function () { 1642 this.fileManagers = []; 1643}; 1644 1645module.exports = environment; 1646 1647},{"../logger":37}],20:[function(require,module,exports){ 1648 1649var functionRegistry = require('./function-registry'), 1650 Anonymous = require('../tree/anonymous'), 1651 Keyword = require('../tree/keyword'); 1652 1653functionRegistry.addMultiple({ 1654 boolean: function(condition) { 1655 return condition ? Keyword.True : Keyword.False; 1656 }, 1657 1658 'if': function(condition, trueValue, falseValue) { 1659 return condition ? trueValue 1660 : (falseValue || new Anonymous); 1661 } 1662}); 1663 1664},{"../tree/anonymous":48,"../tree/keyword":68,"./function-registry":26}],21:[function(require,module,exports){ 1665var Color = require('../tree/color'), 1666 functionRegistry = require('./function-registry'); 1667 1668// Color Blending 1669// ref: http://www.w3.org/TR/compositing-1 1670 1671function colorBlend(mode, color1, color2) { 1672 var ab = color1.alpha, cb, // backdrop 1673 as = color2.alpha, cs, // source 1674 ar, cr, r = []; // result 1675 1676 ar = as + ab * (1 - as); 1677 for (var i = 0; i < 3; i++) { 1678 cb = color1.rgb[i] / 255; 1679 cs = color2.rgb[i] / 255; 1680 cr = mode(cb, cs); 1681 if (ar) { 1682 cr = (as * cs + ab * (cb - 1683 as * (cb + cs - cr))) / ar; 1684 } 1685 r[i] = cr * 255; 1686 } 1687 1688 return new Color(r, ar); 1689} 1690 1691var colorBlendModeFunctions = { 1692 multiply: function(cb, cs) { 1693 return cb * cs; 1694 }, 1695 screen: function(cb, cs) { 1696 return cb + cs - cb * cs; 1697 }, 1698 overlay: function(cb, cs) { 1699 cb *= 2; 1700 return (cb <= 1) ? 1701 colorBlendModeFunctions.multiply(cb, cs) : 1702 colorBlendModeFunctions.screen(cb - 1, cs); 1703 }, 1704 softlight: function(cb, cs) { 1705 var d = 1, e = cb; 1706 if (cs > 0.5) { 1707 e = 1; 1708 d = (cb > 0.25) ? Math.sqrt(cb) 1709 : ((16 * cb - 12) * cb + 4) * cb; 1710 } 1711 return cb - (1 - 2 * cs) * e * (d - cb); 1712 }, 1713 hardlight: function(cb, cs) { 1714 return colorBlendModeFunctions.overlay(cs, cb); 1715 }, 1716 difference: function(cb, cs) { 1717 return Math.abs(cb - cs); 1718 }, 1719 exclusion: function(cb, cs) { 1720 return cb + cs - 2 * cb * cs; 1721 }, 1722 1723 // non-w3c functions: 1724 average: function(cb, cs) { 1725 return (cb + cs) / 2; 1726 }, 1727 negation: function(cb, cs) { 1728 return 1 - Math.abs(cb + cs - 1); 1729 } 1730}; 1731 1732for (var f in colorBlendModeFunctions) { 1733 if (colorBlendModeFunctions.hasOwnProperty(f)) { 1734 colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]); 1735 } 1736} 1737 1738functionRegistry.addMultiple(colorBlend); 1739 1740},{"../tree/color":53,"./function-registry":26}],22:[function(require,module,exports){ 1741var Dimension = require('../tree/dimension'), 1742 Color = require('../tree/color'), 1743 Quoted = require('../tree/quoted'), 1744 Anonymous = require('../tree/anonymous'), 1745 functionRegistry = require('./function-registry'), 1746 colorFunctions; 1747 1748function clamp(val) { 1749 return Math.min(1, Math.max(0, val)); 1750} 1751function hsla(color) { 1752 return colorFunctions.hsla(color.h, color.s, color.l, color.a); 1753} 1754function number(n) { 1755 if (n instanceof Dimension) { 1756 return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); 1757 } else if (typeof n === 'number') { 1758 return n; 1759 } else { 1760 throw { 1761 type: 'Argument', 1762 message: 'color functions take numbers as parameters' 1763 }; 1764 } 1765} 1766function scaled(n, size) { 1767 if (n instanceof Dimension && n.unit.is('%')) { 1768 return parseFloat(n.value * size / 100); 1769 } else { 1770 return number(n); 1771 } 1772} 1773colorFunctions = { 1774 rgb: function (r, g, b) { 1775 return colorFunctions.rgba(r, g, b, 1.0); 1776 }, 1777 rgba: function (r, g, b, a) { 1778 var rgb = [r, g, b].map(function (c) { return scaled(c, 255); }); 1779 a = number(a); 1780 return new Color(rgb, a); 1781 }, 1782 hsl: function (h, s, l) { 1783 return colorFunctions.hsla(h, s, l, 1.0); 1784 }, 1785 hsla: function (h, s, l, a) { 1786 1787 var m1, m2; 1788 1789 function hue(h) { 1790 h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); 1791 if (h * 6 < 1) { 1792 return m1 + (m2 - m1) * h * 6; 1793 } 1794 else if (h * 2 < 1) { 1795 return m2; 1796 } 1797 else if (h * 3 < 2) { 1798 return m1 + (m2 - m1) * (2 / 3 - h) * 6; 1799 } 1800 else { 1801 return m1; 1802 } 1803 } 1804 1805 h = (number(h) % 360) / 360; 1806 s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); 1807 1808 m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; 1809 m1 = l * 2 - m2; 1810 1811 return colorFunctions.rgba(hue(h + 1 / 3) * 255, 1812 hue(h) * 255, 1813 hue(h - 1 / 3) * 255, 1814 a); 1815 }, 1816 1817 hsv: function(h, s, v) { 1818 return colorFunctions.hsva(h, s, v, 1.0); 1819 }, 1820 1821 hsva: function(h, s, v, a) { 1822 h = ((number(h) % 360) / 360) * 360; 1823 s = number(s); v = number(v); a = number(a); 1824 1825 var i, f; 1826 i = Math.floor((h / 60) % 6); 1827 f = (h / 60) - i; 1828 1829 var vs = [v, 1830 v * (1 - s), 1831 v * (1 - f * s), 1832 v * (1 - (1 - f) * s)]; 1833 var perm = [[0, 3, 1], 1834 [2, 0, 1], 1835 [1, 0, 3], 1836 [1, 2, 0], 1837 [3, 1, 0], 1838 [0, 1, 2]]; 1839 1840 return colorFunctions.rgba(vs[perm[i][0]] * 255, 1841 vs[perm[i][1]] * 255, 1842 vs[perm[i][2]] * 255, 1843 a); 1844 }, 1845 1846 hue: function (color) { 1847 return new Dimension(color.toHSL().h); 1848 }, 1849 saturation: function (color) { 1850 return new Dimension(color.toHSL().s * 100, '%'); 1851 }, 1852 lightness: function (color) { 1853 return new Dimension(color.toHSL().l * 100, '%'); 1854 }, 1855 hsvhue: function(color) { 1856 return new Dimension(color.toHSV().h); 1857 }, 1858 hsvsaturation: function (color) { 1859 return new Dimension(color.toHSV().s * 100, '%'); 1860 }, 1861 hsvvalue: function (color) { 1862 return new Dimension(color.toHSV().v * 100, '%'); 1863 }, 1864 red: function (color) { 1865 return new Dimension(color.rgb[0]); 1866 }, 1867 green: function (color) { 1868 return new Dimension(color.rgb[1]); 1869 }, 1870 blue: function (color) { 1871 return new Dimension(color.rgb[2]); 1872 },
1873 alpha: function (color) { 1874 return new Dimension(color.toHSL().a); 1875 }, 1876 luma: function (color) { 1877 return new Dimension(color.luma() * color.alpha * 100, '%'); 1878 }, 1879 luminance: function (color) { 1880 var luminance = 1881 (0.2126 * color.rgb[0] / 255) + 1882 (0.7152 * color.rgb[1] / 255) + 1883 (0.0722 * color.rgb[2] / 255); 1884 1885 return new Dimension(luminance * color.alpha * 100, '%'); 1886 }, 1887 saturate: function (color, amount, method) { 1888 // filter: saturate(3.2); 1889 // should be kept as is, so check for color 1890 if (!color.rgb) { 1891 return null; 1892 } 1893 var hsl = color.toHSL(); 1894 1895 if (typeof method !== 'undefined' && method.value === 'relative') { 1896 hsl.s += hsl.s * amount.value / 100; 1897 } 1898 else { 1899 hsl.s += amount.value / 100; 1900 } 1901 hsl.s = clamp(hsl.s); 1902 return hsla(hsl); 1903 }, 1904 desaturate: function (color, amount, method) { 1905 var hsl = color.toHSL(); 1906 1907 if (typeof method !== 'undefined' && method.value === 'relative') { 1908 hsl.s -= hsl.s * amount.value / 100; 1909 } 1910 else { 1911 hsl.s -= amount.value / 100; 1912 } 1913 hsl.s = clamp(hsl.s); 1914 return hsla(hsl); 1915 }, 1916 lighten: function (color, amount, method) { 1917 var hsl = color.toHSL(); 1918 1919 if (typeof method !== 'undefined' && method.value === 'relative') { 1920 hsl.l += hsl.l * amount.value / 100; 1921 } 1922 else { 1923 hsl.l += amount.value / 100; 1924 } 1925 hsl.l = clamp(hsl.l); 1926 return hsla(hsl); 1927 }, 1928 darken: function (color, amount, method) { 1929 var hsl = color.toHSL(); 1930 1931 if (typeof method !== 'undefined' && method.value === 'relative') { 1932 hsl.l -= hsl.l * amount.value / 100; 1933 } 1934 else { 1935 hsl.l -= amount.value / 100; 1936 } 1937 hsl.l = clamp(hsl.l); 1938 return hsla(hsl); 1939 }, 1940 fadein: function (color, amount, method) { 1941 var hsl = color.toHSL(); 1942 1943 if (typeof method !== 'undefined' && method.value === 'relative') { 1944 hsl.a += hsl.a * amount.value / 100; 1945 } 1946 else { 1947 hsl.a += amount.value / 100; 1948 } 1949 hsl.a = clamp(hsl.a); 1950 return hsla(hsl); 1951 }, 1952 fadeout: function (color, amount, method) { 1953 var hsl = color.toHSL(); 1954 1955 if (typeof method !== 'undefined' && method.value === 'relative') { 1956 hsl.a -= hsl.a * amount.value / 100; 1957 } 1958 else { 1959 hsl.a -= amount.value / 100; 1960 } 1961 hsl.a = clamp(hsl.a); 1962 return hsla(hsl); 1963 }, 1964 fade: function (color, amount) { 1965 var hsl = color.toHSL(); 1966 1967 hsl.a = amount.value / 100; 1968 hsl.a = clamp(hsl.a); 1969 return hsla(hsl); 1970 }, 1971 spin: function (color, amount) { 1972 var hsl = color.toHSL(); 1973 var hue = (hsl.h + amount.value) % 360; 1974 1975 hsl.h = hue < 0 ? 360 + hue : hue; 1976 1977 return hsla(hsl); 1978 }, 1979 // 1980 // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein 1981 // http://sass-lang.com 1982 // 1983 mix: function (color1, color2, weight) { 1984 if (!color1.toHSL || !color2.toHSL) { 1985 console.log(color2.type); 1986 console.dir(color2); 1987 } 1988 if (!weight) { 1989 weight = new Dimension(50); 1990 } 1991 var p = weight.value / 100.0; 1992 var w = p * 2 - 1; 1993 var a = color1.toHSL().a - color2.toHSL().a; 1994 1995 var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; 1996 var w2 = 1 - w1; 1997 1998 var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, 1999 color1.rgb[1] * w1 + color2.rgb[1] * w2, 2000 color1.rgb[2] * w1 + color2.rgb[2] * w2]; 2001 2002 var alpha = color1.alpha * p + color2.alpha * (1 - p); 2003 2004 return new Color(rgb, alpha); 2005 }, 2006 greyscale: function (color) { 2007 return colorFunctions.desaturate(color, new Dimension(100)); 2008 }, 2009 contrast: function (color, dark, light, threshold) { 2010 // filter: contrast(3.2);
2011 // should be kept as is, so check for color 2012 if (!color.rgb) { 2013 return null; 2014 } 2015 if (typeof light === 'undefined') { 2016 light = colorFunctions.rgba(255, 255, 255, 1.0); 2017 } 2018 if (typeof dark === 'undefined') { 2019 dark = colorFunctions.rgba(0, 0, 0, 1.0); 2020 } 2021 // Figure out which is actually light and dark: 2022 if (dark.luma() > light.luma()) { 2023 var t = light; 2024 light = dark; 2025 dark = t; 2026 } 2027 if (typeof threshold === 'undefined') { 2028 threshold = 0.43; 2029 } else { 2030 threshold = number(threshold); 2031 } 2032 if (color.luma() < threshold) { 2033 return light; 2034 } else { 2035 return dark; 2036 } 2037 }, 2038 // Changes made in 2.7.0 - Reverted in 3.0.0 2039 // contrast: function (color, color1, color2, threshold) { 2040 // // Return which of `color1` and `color2` has the greatest contrast with `color` 2041 // // according to the standard WCAG contrast ratio calculation. 2042 // // http://www.w3.org/TR/WCAG20/#contrast-ratiodef 2043 // // The threshold param is no longer used, in line with SASS. 2044 // // filter: contrast(3.2);
2045 // // should be kept as is, so check for color 2046 // if (!color.rgb) { 2047 // return null; 2048 // } 2049 // if (typeof color1 === 'undefined') { 2050 // color1 = colorFunctions.rgba(0, 0, 0, 1.0); 2051 // } 2052 // if (typeof color2 === 'undefined') { 2053 // color2 = colorFunctions.rgba(255, 255, 255, 1.0); 2054 // } 2055 // var contrast1, contrast2; 2056 // var luma = color.luma(); 2057 // var luma1 = color1.luma(); 2058 // var luma2 = color2.luma(); 2059 // // Calculate contrast ratios for each color 2060 // if (luma > luma1) { 2061 // contrast1 = (luma + 0.05) / (luma1 + 0.05); 2062 // } else { 2063 // contrast1 = (luma1 + 0.05) / (luma + 0.05); 2064 // } 2065 // if (luma > luma2) { 2066 // contrast2 = (luma + 0.05) / (luma2 + 0.05); 2067 // } else { 2068 // contrast2 = (luma2 + 0.05) / (luma + 0.05); 2069 // } 2070 // if (contrast1 > contrast2) { 2071 // return color1; 2072 // } else { 2073 // return color2; 2074 // } 2075 // }, 2076 argb: function (color) { 2077 return new Anonymous(color.toARGB()); 2078 }, 2079 color: function(c) { 2080 if ((c instanceof Quoted) && 2081 (/^#([a-f0-9]{6}|[a-f0-9]{3})$/i.test(c.value))) { 2082 return new Color(c.value.slice(1)); 2083 } 2084 if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) { 2085 c.value = undefined; 2086 return c; 2087 } 2088 throw { 2089 type: 'Argument', 2090 message: 'argument must be a color keyword or 3/6 digit hex e.g. #FFF' 2091 }; 2092 }, 2093 tint: function(color, amount) { 2094 return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount); 2095 }, 2096 shade: function(color, amount) { 2097 return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount); 2098 } 2099}; 2100functionRegistry.addMultiple(colorFunctions); 2101 2102},{"../tree/anonymous":48,"../tree/color":53,"../tree/dimension":60,"../tree/quoted":77,"./function-registry":26}],23:[function(require,module,exports){ 2103module.exports = function(environment) { 2104 var Quoted = require('../tree/quoted'), 2105 URL = require('../tree/url'), 2106 utils = require('../utils'), 2107 functionRegistry = require('./function-registry'), 2108 fallback = function(functionThis, node) { 2109 return new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context); 2110 }, 2111 logger = require('../logger'); 2112 2113 functionRegistry.add('data-uri', function(mimetypeNode, filePathNode) { 2114 2115 if (!filePathNode) { 2116 filePathNode = mimetypeNode; 2117 mimetypeNode = null; 2118 } 2119 2120 var mimetype = mimetypeNode && mimetypeNode.value; 2121 var filePath = filePathNode.value; 2122 var currentFileInfo = this.currentFileInfo; 2123 var currentDirectory = currentFileInfo.relativeUrls ? 2124 currentFileInfo.currentDirectory : currentFileInfo.entryPath; 2125 2126 var fragmentStart = filePath.indexOf('#'); 2127 var fragment = ''; 2128 if (fragmentStart !== -1) { 2129 fragment = filePath.slice(fragmentStart); 2130 filePath = filePath.slice(0, fragmentStart); 2131 } 2132 var context = utils.clone(this.context); 2133 context.rawBuffer = true; 2134 2135 var fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true); 2136 2137 if (!fileManager) { 2138 return fallback(this, filePathNode); 2139 } 2140 2141 var useBase64 = false; 2142 2143 // detect the mimetype if not given 2144 if (!mimetypeNode) { 2145 2146 mimetype = environment.mimeLookup(filePath); 2147 2148 if (mimetype === 'image/svg+xml') { 2149 useBase64 = false; 2150 } else { 2151 // use base 64 unless it's an ASCII or UTF-8 format 2152 var charset = environment.charsetLookup(mimetype); 2153 useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; 2154 } 2155 if (useBase64) { mimetype += ';base64'; } 2156 } 2157 else { 2158 useBase64 = /;base64$/.test(mimetype); 2159 } 2160 2161 var fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment); 2162 if (!fileSync.contents) { 2163 logger.warn('Skipped data-uri embedding of ' + filePath + ' because file not found'); 2164 return fallback(this, filePathNode || mimetypeNode); 2165 } 2166 var buf = fileSync.contents; 2167 if (useBase64 && !environment.encodeBase64) { 2168 return fallback(this, filePathNode); 2169 } 2170 2171 buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf); 2172 2173 var uri = 'data:' + mimetype + ',' + buf + fragment; 2174 2175 // IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded 2176 // and the --ieCompat flag is enabled, return a normal url() instead. 2177 var DATA_URI_MAX = 32768; 2178 if (uri.length >= DATA_URI_MAX) { 2179
2180 if (this.context.ieCompat !== false) { 2181 logger.warn('Skipped data-uri embedding of ' + filePath + ' because its size (' + uri.length + 2182 ' characters) exceeds IE8-safe ' + DATA_URI_MAX + ' characters!'); 2183 2184 return fallback(this, filePathNode || mimetypeNode); 2185 } 2186 } 2187 2188 return new URL(new Quoted('"' + uri + '"', uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); 2189 }); 2190}; 2191 2192},{"../logger":37,"../tree/quoted":77,"../tree/url":82,"../utils":86,"./function-registry":26}],24:[function(require,module,exports){ 2193var Keyword = require('../tree/keyword'), 2194 functionRegistry = require('./function-registry'); 2195 2196var defaultFunc = { 2197 eval: function () { 2198 var v = this.value_, e = this.error_; 2199 if (e) { 2200 throw e; 2201 } 2202 if (v != null) { 2203 return v ? Keyword.True : Keyword.False; 2204 } 2205 }, 2206 value: function (v) { 2207 this.value_ = v; 2208 }, 2209 error: function (e) { 2210 this.error_ = e; 2211 }, 2212 reset: function () { 2213 this.value_ = this.error_ = null; 2214 } 2215}; 2216 2217functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc)); 2218 2219module.exports = defaultFunc; 2220 2221},{"../tree/keyword":68,"./function-registry":26}],25:[function(require,module,exports){ 2222var Expression = require('../tree/expression'); 2223 2224var functionCaller = function(name, context, index, currentFileInfo) { 2225 this.name = name.toLowerCase(); 2226 this.index = index; 2227 this.context = context; 2228 this.currentFileInfo = currentFileInfo; 2229 2230 this.func = context.frames[0].functionRegistry.get(this.name); 2231}; 2232functionCaller.prototype.isValid = function() { 2233 return Boolean(this.func); 2234}; 2235 2236functionCaller.prototype.call = function(args) { 2237 // This code is terrible and should be replaced as per this issue... 2238 // https://github.com/less/less.js/issues/2477 2239 if (Array.isArray(args)) { 2240 args = args.filter(function (item) { 2241 if (item.type === 'Comment') { 2242 return false; 2243 } 2244 return true; 2245 }) 2246 .map(function(item) { 2247 if (item.type === 'Expression') { 2248 var subNodes = item.value.filter(function (item) { 2249 if (item.type === 'Comment') { 2250 return false; 2251 } 2252 return true; 2253 }); 2254 if (subNodes.length === 1) { 2255 return subNodes[0]; 2256 } else { 2257 return new Expression(subNodes); 2258 } 2259 } 2260 return item; 2261 }); 2262 } 2263 2264 return this.func.apply(this, args); 2265}; 2266 2267module.exports = functionCaller; 2268 2269},{"../tree/expression":62}],26:[function(require,module,exports){ 2270function makeRegistry( base ) { 2271 return { 2272 _data: {}, 2273 add: function(name, func) { 2274 // precautionary case conversion, as later querying of 2275 // the registry by function-caller uses lower case as well. 2276 name = name.toLowerCase(); 2277 2278 if (this._data.hasOwnProperty(name)) { 2279 // TODO warn 2280 } 2281 this._data[name] = func; 2282 }, 2283 addMultiple: function(functions) { 2284 Object.keys(functions).forEach( 2285 function(name) { 2286 this.add(name, functions[name]); 2287 }.bind(this)); 2288 }, 2289 get: function(name) { 2290 return this._data[name] || ( base && base.get( name )); 2291 }, 2292 getLocalFunctions: function() { 2293 return this._data; 2294 }, 2295 inherit: function() { 2296 return makeRegistry( this ); 2297 }, 2298 create: function(base) { 2299 return makeRegistry(base); 2300 } 2301 }; 2302} 2303 2304module.exports = makeRegistry( null ); 2305},{}],27:[function(require,module,exports){ 2306module.exports = function(environment) { 2307 var functions = { 2308 functionRegistry: require('./function-registry'), 2309 functionCaller: require('./function-caller') 2310 }; 2311 2312 // register functions 2313 require('./boolean'); 2314 require('./default'); 2315 require('./color'); 2316 require('./color-blending'); 2317 require('./data-uri')(environment); 2318 require('./math'); 2319 require('./number'); 2320 require('./string'); 2321 require('./svg')(environment); 2322 require('./types'); 2323 2324 return functions; 2325}; 2326 2327},{"./boolean":20,"./color":22,"./color-blending":21,"./data-uri":23,"./default":24,"./function-caller":25,"./function-registry":26,"./math":29,"./number":30,"./string":31,"./svg":32,"./types":33}],28:[function(require,module,exports){ 2328var Dimension = require('../tree/dimension'); 2329 2330var MathHelper = function() { 2331}; 2332MathHelper._math = function (fn, unit, n) { 2333 if (!(n instanceof Dimension)) { 2334 throw { type: 'Argument', message: 'argument must be a number' }; 2335 } 2336 if (unit == null) { 2337 unit = n.unit; 2338 } else { 2339 n = n.unify(); 2340 } 2341 return new Dimension(fn(parseFloat(n.value)), unit); 2342}; 2343module.exports = MathHelper; 2344},{"../tree/dimension":60}],29:[function(require,module,exports){ 2345var functionRegistry = require('./function-registry'), 2346 mathHelper = require('./math-helper.js'); 2347 2348var mathFunctions = { 2349 // name, unit 2350 ceil: null, 2351 floor: null, 2352 sqrt: null, 2353 abs: null, 2354 tan: '', 2355 sin: '', 2356 cos: '', 2357 atan: 'rad', 2358 asin: 'rad', 2359 acos: 'rad' 2360}; 2361 2362for (var f in mathFunctions) { 2363 if (mathFunctions.hasOwnProperty(f)) { 2364 mathFunctions[f] = mathHelper._math.bind(null, Math[f], mathFunctions[f]); 2365 } 2366} 2367 2368mathFunctions.round = function (n, f) { 2369 var fraction = typeof f === 'undefined' ? 0 : f.value; 2370 return mathHelper._math(function(num) { return num.toFixed(fraction); }, null, n); 2371}; 2372 2373functionRegistry.addMultiple(mathFunctions); 2374 2375},{"./function-registry":26,"./math-helper.js":28}],30:[function(require,module,exports){ 2376var Dimension = require('../tree/dimension'), 2377 Anonymous = require('../tree/anonymous'), 2378 functionRegistry = require('./function-registry'), 2379 mathHelper = require('./math-helper.js'); 2380 2381var minMax = function (isMin, args) { 2382 args = Array.prototype.slice.call(args); 2383 switch (args.length) { 2384 case 0: throw { type: 'Argument', message: 'one or more arguments required' }; 2385 } 2386 var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone, 2387 order = [], // elems only contains original argument values. 2388 values = {}; // key is the unit.toString() for unified Dimension values, 2389 // value is the index into the order array. 2390 for (i = 0; i < args.length; i++) { 2391 current = args[i]; 2392 if (!(current instanceof Dimension)) { 2393 if (Array.isArray(args[i].value)) { 2394 Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value)); 2395 } 2396 continue; 2397 } 2398 currentUnified = current.unit.toString() === '' && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify(); 2399 unit = currentUnified.unit.toString() === '' && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString(); 2400 unitStatic = unit !== '' && unitStatic === undefined || unit !== '' && order[0].unify().unit.toString() === '' ? unit : unitStatic; 2401 unitClone = unit !== '' && unitClone === undefined ? current.unit.toString() : unitClone; 2402 j = values[''] !== undefined && unit !== '' && unit === unitStatic ? values[''] : values[unit]; 2403 if (j === undefined) { 2404 if (unitStatic !== undefined && unit !== unitStatic) { 2405 throw { type: 'Argument', message: 'incompatible types' }; 2406 } 2407 values[unit] = order.length; 2408 order.push(current); 2409 continue; 2410 } 2411 referenceUnified = order[j].unit.toString() === '' && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify(); 2412 if ( isMin && currentUnified.value < referenceUnified.value || 2413 !isMin && currentUnified.value > referenceUnified.value) { 2414 order[j] = current; 2415 } 2416 } 2417 if (order.length == 1) { 2418 return order[0]; 2419 } 2420 args = order.map(function (a) { return a.toCSS(this.context); }).join(this.context.compress ? ',' : ', '); 2421 return new Anonymous((isMin ? 'min' : 'max') + '(' + args + ')'); 2422}; 2423functionRegistry.addMultiple({ 2424 min: function () { 2425 return minMax(true, arguments); 2426 }, 2427 max: function () { 2428 return minMax(false, arguments); 2429 }, 2430 convert: function (val, unit) { 2431 return val.convertTo(unit.value); 2432 }, 2433 pi: function () { 2434 return new Dimension(Math.PI); 2435 }, 2436 mod: function(a, b) { 2437 return new Dimension(a.value % b.value, a.unit); 2438 }, 2439 pow: function(x, y) { 2440 if (typeof x === 'number' && typeof y === 'number') { 2441 x = new Dimension(x); 2442 y = new Dimension(y); 2443 } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) { 2444 throw { type: 'Argument', message: 'arguments must be numbers' }; 2445 } 2446 2447 return new Dimension(Math.pow(x.value, y.value), x.unit); 2448 }, 2449 percentage: function (n) { 2450 var result = mathHelper._math(function(num) { 2451 return num * 100; 2452 }, '%', n); 2453 2454 return result; 2455 } 2456}); 2457 2458},{"../tree/anonymous":48,"../tree/dimension":60,"./function-registry":26,"./math-helper.js":28}],31:[function(require,module,exports){ 2459var Quoted = require('../tree/quoted'), 2460 Anonymous = require('../tree/anonymous'), 2461 JavaScript = require('../tree/javascript'), 2462 functionRegistry = require('./function-registry'); 2463 2464functionRegistry.addMultiple({ 2465 e: function (str) { 2466 return new Anonymous(str instanceof JavaScript ? str.evaluated : str.value); 2467 }, 2468 escape: function (str) { 2469 return new Anonymous( 2470 encodeURI(str.value).replace(/=/g, '%3D').replace(/:/g, '%3A').replace(/#/g, '%23').replace(/;/g, '%3B') 2471 .replace(/\(/g, '%28').replace(/\)/g, '%29')); 2472 }, 2473 replace: function (string, pattern, replacement, flags) { 2474 var result = string.value; 2475 replacement = (replacement.type === 'Quoted') ? 2476 replacement.value : replacement.toCSS(); 2477 result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement); 2478 return new Quoted(string.quote || '', result, string.escaped); 2479 }, 2480 '%': function (string /* arg, arg, ... */) { 2481 var args = Array.prototype.slice.call(arguments, 1), 2482 result = string.value; 2483 2484 for (var i = 0; i < args.length; i++) { 2485 /* jshint loopfunc:true */ 2486 result = result.replace(/%[sda]/i, function(token) { 2487 var value = ((args[i].type === 'Quoted') && 2488 token.match(/s/i)) ? args[i].value : args[i].toCSS(); 2489 return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; 2490 }); 2491 } 2492 result = result.replace(/%%/g, '%'); 2493 return new Quoted(string.quote || '', result, string.escaped); 2494 } 2495}); 2496 2497},{"../tree/anonymous":48,"../tree/javascript":66,"../tree/quoted":77,"./function-registry":26}],32:[function(require,module,exports){ 2498module.exports = function(environment) { 2499 var Dimension = require('../tree/dimension'), 2500 Color = require('../tree/color'), 2501 Expression = require('../tree/expression'), 2502 Quoted = require('../tree/quoted'), 2503 URL = require('../tree/url'), 2504 functionRegistry = require('./function-registry'); 2505 2506 functionRegistry.add('svg-gradient', function(direction) { 2507 2508 var stops, 2509 gradientDirectionSvg, 2510 gradientType = 'linear', 2511 rectangleDimension = 'x="0" y="0" width="1" height="1"', 2512 renderEnv = {compress: false}, 2513 returner, 2514 directionValue = direction.toCSS(renderEnv), 2515 i, color, position, positionValue, alpha; 2516 2517 function throwArgumentDescriptor() { 2518 throw { type: 'Argument', 2519 message: 'svg-gradient expects direction, start_color [start_position], [color position,]...,' + 2520 ' end_color [end_position] or direction, color list' }; 2521 } 2522 2523 if (arguments.length == 2) { 2524 if (arguments[1].value.length < 2) { 2525 throwArgumentDescriptor(); 2526 } 2527 stops = arguments[1].value; 2528 } else if (arguments.length < 3) { 2529 throwArgumentDescriptor(); 2530 } else { 2531 stops = Array.prototype.slice.call(arguments, 1); 2532 } 2533 2534 switch (directionValue) { 2535 case 'to bottom': 2536 gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="
2536100%"'; 2537 break; 2538 case 'to right': 2539 gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; 2540 break; 2541 case 'to bottom right': 2542 gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; 2543 break; 2544 case 'to top right': 2545 gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; 2546 break; 2547 case 'ellipse': 2548 case 'ellipse at center': 2549 gradientType = 'radial'; 2550 gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; 2551 rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; 2552 break; 2553 default: 2554 throw { type: 'Argument', message: 'svg-gradient direction must be \'to bottom\', \'to right\',' + 2555 ' \'to bottom right\', \'to top right\' or \'ellipse at center\'' }; 2556 } 2557 returner = '<?xml version="1.0" ?>' + 2558 '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' + 2559 '<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>'; 2560 2561 for (i = 0; i < stops.length; i += 1) { 2562 if (stops[i] instanceof Expression) { 2563 color = stops[i].value[0]; 2564 position = stops[i].value[1]; 2565 } else { 2566 color = stops[i]; 2567 position = undefined; 2568 } 2569 2570 if (!(color instanceof Color) || (!((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension))) { 2571 throwArgumentDescriptor(); 2572 } 2573 positionValue = position ? position.toCSS(renderEnv) : i === 0 ? '0%' : '100%'; 2574 alpha = color.alpha; 2575 returner += '<stop offset="' + positionValue + '" stop-color="' + color.toRGB() + '"' + (alpha < 1 ? ' stop-opacity="' + alpha + '"' : '') + '/>'; 2576 } 2577 returner += '</' + gradientType + 'Gradient>' + 2578 '<rect ' + rectangleDimension + ' fill="url(#gradient)" /></svg>'; 2579 2580 returner = encodeURIComponent(returner); 2581 2582 returner = 'data:image/svg+xml,' + returner; 2583 return new URL(new Quoted('\'' + returner + '\'', returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); 2584 }); 2585}; 2586 2587},{"../tree/color":53,"../tree/dimension":60,"../tree/expression":62,"../tree/quoted":77,"../tree/url":82,"./function-registry":26}],33:[function(require,module,exports){ 2588var Keyword = require('../tree/keyword'), 2589 DetachedRuleset = require('../tree/detached-ruleset'), 2590 Dimension = require('../tree/dimension'), 2591 Color = require('../tree/color'), 2592 Quoted = require('../tree/quoted'), 2593 Anonymous = require('../tree/anonymous'), 2594 URL = require('../tree/url'), 2595 Operation = require('../tree/operation'), 2596 functionRegistry = require('./function-registry'); 2597 2598var isa = function (n, Type) { 2599 return (n instanceof Type) ? Keyword.True : Keyword.False; 2600 }, 2601 isunit = function (n, unit) { 2602 if (unit === undefined) { 2603 throw { type: 'Argument', message: 'missing the required second argument to isunit.' }; 2604 } 2605 unit = typeof unit.value === 'string' ? unit.value : unit; 2606 if (typeof unit !== 'string') { 2607 throw { type: 'Argument', message: 'Second argument to isunit should be a unit or a string.' }; 2608 } 2609 return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False; 2610 }, 2611 getItemsFromNode = function(node) { 2612 // handle non-array values as an array of length 1 2613 // return 'undefined' if index is invalid 2614 var items = Array.isArray(node.value) ? 2615 node.value : Array(node); 2616 2617 return items; 2618 }; 2619functionRegistry.addMultiple({ 2620 isruleset: function (n) { 2621 return isa(n, DetachedRuleset); 2622 }, 2623 iscolor: function (n) { 2624 return isa(n, Color); 2625 }, 2626 isnumber: function (n) { 2627 return isa(n, Dimension); 2628 }, 2629 isstring: function (n) { 2630 return isa(n, Quoted); 2631 }, 2632 iskeyword: function (n) { 2633 return isa(n, Keyword); 2634 }, 2635 isurl: function (n) { 2636 return isa(n, URL); 2637 }, 2638 ispixel: function (n) { 2639 return isunit(n, 'px'); 2640 }, 2641 ispercentage: function (n) { 2642 return isunit(n, '%'); 2643 }, 2644 isem: function (n) { 2645 return isunit(n, 'em'); 2646 },
2647 isunit: isunit, 2648 unit: function (val, unit) { 2649 if (!(val instanceof Dimension)) { 2650 throw { type: 'Argument', 2651 message: 'the first argument to unit must be a number' + 2652 (val instanceof Operation ? '. Have you forgotten parenthesis?' : '') }; 2653 } 2654 if (unit) { 2655 if (unit instanceof Keyword) { 2656 unit = unit.value; 2657 } else { 2658 unit = unit.toCSS(); 2659 } 2660 } else { 2661 unit = ''; 2662 } 2663 return new Dimension(val.value, unit); 2664 }, 2665 'get-unit': function (n) { 2666 return new Anonymous(n.unit); 2667 }, 2668 extract: function(values, index) { 2669 index = index.value - 1; // (1-based index) 2670 2671 return getItemsFromNode(values)[index]; 2672 }, 2673 length: function(values) { 2674 return new Dimension(getItemsFromNode(values).length); 2675 } 2676}); 2677 2678},{"../tree/anonymous":48,"../tree/color":53,"../tree/detached-ruleset":59,"../tree/dimension":60,"../tree/keyword":68,"../tree/operation":74,"../tree/quoted":77,"../tree/url":82,"./function-registry":26}],34:[function(require,module,exports){ 2679var contexts = require('./contexts'), 2680 Parser = require('./parser/parser'), 2681 LessError = require('./less-error'), 2682 utils = require('./utils'), 2683 PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise, 2684 logger = require('./logger'); 2685 2686module.exports = function(environment) { 2687 2688 // FileInfo = { 2689 // 'relativeUrls' - option - whether to adjust URL's to be relative 2690 // 'filename' - full resolved filename of current file 2691 // 'rootpath' - path to append to normal URLs for this node 2692 // 'currentDirectory' - path to the current file, absolute 2693 // 'rootFilename' - filename of the base file 2694 // 'entryPath' - absolute path to the entry file 2695 // 'reference' - whether the file should not be output and only output parts that are referenced 2696 2697 var ImportManager = function(less, context, rootFileInfo) { 2698 this.less = less; 2699 this.rootFilename = rootFileInfo.filename; 2700 this.paths = context.paths || []; // Search paths, when importing 2701 this.contents = {}; // map - filename to contents of all the files 2702 this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore 2703 this.mime = context.mime; 2704 this.error = null; 2705 this.context = context; 2706 // Deprecated? Unused outside of here, could be useful. 2707 this.queue = []; // Files which haven't been imported yet 2708 this.files = {}; // Holds the imported parse trees. 2709 }; 2710 2711 /** 2712 * Add an import to be imported 2713 * @param path - the raw path 2714 * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension) 2715 * @param currentFileInfo - the current file info (used for instance to work out relative paths) 2716 * @param importOptions - import options 2717 * @param callback - callback for when it is imported 2718 */ 2719 ImportManager.prototype.push = function (path, tryAppendExtension, currentFileInfo, importOptions, callback) { 2720 var importManager = this, 2721 pluginLoader = this.context.pluginManager.Loader; 2722 2723 this.queue.push(path); 2724 2725 var fileParsedFunc = function (e, root, fullPath) { 2726 importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue 2727 2728 var importedEqualsRoot = fullPath === importManager.rootFilename; 2729 if (importOptions.optional && e) { 2730 callback(null, {rules:[]}, false, null); 2731 logger.info('The file ' + fullPath + ' was skipped because it was not found and the import was marked optional.'); 2732 } 2733 else { 2734 // Inline imports aren't cached here. 2735 // If we start to cache them, please make sure they won't conflict with non-inline imports of the 2736 // same name as they used to do before this comment and the condition below have been added.
2737 if (!importManager.files[fullPath] && !importOptions.inline) { 2738 importManager.files[fullPath] = { root: root, options: importOptions }; 2739 } 2740 if (e && !importManager.error) { importManager.error = e; } 2741 callback(e, root, importedEqualsRoot, fullPath); 2742 } 2743 }; 2744 2745 var newFileInfo = { 2746 relativeUrls: this.context.relativeUrls, 2747 entryPath: currentFileInfo.entryPath, 2748 rootpath: currentFileInfo.rootpath, 2749 rootFilename: currentFileInfo.rootFilename 2750 }; 2751 2752 var fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment); 2753 2754 if (!fileManager) { 2755 fileParsedFunc({ message: 'Could not find a file-manager for ' + path }); 2756 return; 2757 } 2758 2759 var loadFileCallback = function(loadedFile) { 2760 var plugin, 2761 resolvedFilename = loadedFile.filename, 2762 contents = loadedFile.contents.replace(/^\uFEFF/, ''); 2763 2764 // Pass on an updated rootpath if path of imported file is relative and file 2765 // is in a (sub|sup) directory 2766 // 2767 // Examples: 2768 // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/', 2769 // then rootpath should become 'less/module/nav/' 2770 // - If path of imported file is '../mixins.less' and rootpath is 'less/', 2771 // then rootpath should become 'less/../' 2772 newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename); 2773 if (newFileInfo.relativeUrls) { 2774 newFileInfo.rootpath = fileManager.join( 2775 (importManager.context.rootpath || ''), 2776 fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath)); 2777 2778 if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) { 2779 newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath); 2780 } 2781 } 2782 newFileInfo.filename = resolvedFilename; 2783 2784 var newEnv = new contexts.Parse(importManager.context); 2785 2786 newEnv.processImports = false; 2787 importManager.contents[resolvedFilename] = contents; 2788 2789 if (currentFileInfo.reference || importOptions.reference) { 2790 newFileInfo.reference = true; 2791 } 2792 2793 if (importOptions.isPlugin) { 2794 plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo); 2795 if (plugin instanceof LessError) { 2796 fileParsedFunc(plugin, null, resolvedFilename); 2797 } 2798 else { 2799 fileParsedFunc(null, plugin, resolvedFilename); 2800 } 2801 } else if (importOptions.inline) { 2802 fileParsedFunc(null, contents, resolvedFilename); 2803 } else { 2804 2805 // import (multiple) parse trees apparently get altered and can't be cached. 2806 // TODO: investigate why this is 2807 if (importManager.files[resolvedFilename] 2808 && !importManager.files[resolvedFilename].options.multiple 2809 && !importOptions.multiple) { 2810 2811 fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename); 2812 } 2813 else { 2814 new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) { 2815 fileParsedFunc(e, root, resolvedFilename); 2816 }); 2817 } 2818 } 2819 }; 2820 var promise, context = utils.clone(this.context); 2821 2822 if (tryAppendExtension) { 2823 context.ext = importOptions.isPlugin ? '.js' : '.less'; 2824 } 2825 2826 if (importOptions.isPlugin) { 2827 promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager); 2828 } 2829 else { 2830 promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment, 2831 function(err, loadedFile) { 2832 if (err) { 2833 fileParsedFunc(err); 2834 } else { 2835 loadFileCallback(loadedFile); 2836 } 2837 }); 2838 } 2839 if (promise) { 2840 promise.then(loadFileCallback, fileParsedFunc); 2841 } 2842 2843 }; 2844 return ImportManager; 2845}; 2846 2847},{"./contexts":12,"./less-error":36,"./logger":37,"./parser/parser":42,"./utils":86,"promise":undefined}],35:[function(require,module,exports){ 2848module.exports = function(environment, fileManagers) { 2849 var SourceMapOutput, SourceMapBuilder, ParseTree, ImportManager, Environment; 2850 2851 var initial = { 2852 version: [3, 5, 0], 2853 data: require('./data'), 2854 tree: require('./tree'), 2855 Environment: (Environment = require('./environment/environment')), 2856 AbstractFileManager: require('./environment/abstract-file-manager'), 2857 AbstractPluginLoader: require('./environment/abstract-plugin-loader'), 2858 environment: (environment = new Environment(environment, fileManagers)), 2859 visitors: require('./visitors'), 2860 Parser: require('./parser/parser'), 2861 functions: require('./functions')(environment), 2862 contexts: require('./contexts'), 2863 SourceMapOutput: (SourceMapOutput = require('./source-map-output')(environment)), 2864 SourceMapBuilder: (SourceMapBuilder = require('./source-map-builder')(SourceMapOutput, environment)), 2865 ParseTree: (ParseTree = require('./parse-tree')(SourceMapBuilder)), 2866 ImportManager: (ImportManager = require('./import-manager')(environment)), 2867 render: require('./render')(environment, ParseTree, ImportManager), 2868 parse: require('./parse')(environment, ParseTree, ImportManager), 2869 LessError: require('./less-error'), 2870 transformTree: require('./transform-tree'), 2871 utils: require('./utils'), 2872 PluginManager: require('./plugin-manager'), 2873 logger: require('./logger') 2874 }; 2875 2876 // Create a public API 2877 2878 var ctor = function(t) { 2879 return function() { 2880 var obj = Object.create(t.prototype); 2881 t.apply(obj, Array.prototype.slice.call(arguments, 0)); 2882 return obj; 2883 }; 2884 }; 2885 var t, api = Object.create(initial); 2886 for (var n in initial.tree) { 2887 /* eslint guard-for-in: 0 */ 2888 t = initial.tree[n]; 2889 if (typeof t === 'function') { 2890 api[n.toLowerCase()] = ctor(t); 2891 } 2892 else { 2893 api[n] = Object.create(null); 2894 for (var o in t) { 2895 /* eslint guard-for-in: 0 */ 2896 api[n][o.toLowerCase()] = ctor(t[o]); 2897 } 2898 } 2899 } 2900 2901 return api; 2902}; 2903 2904},{"./contexts":12,"./data":14,"./environment/abstract-file-manager"
2904:17,"./environment/abstract-plugin-loader":18,"./environment/environment":19,"./functions":27,"./import-manager":34,"./less-error":36,"./logger":37,"./parse":39,"./parse-tree":38,"./parser/parser":42,"./plugin-manager":43,"./render":44,"./source-map-builder":45,"./source-map-output":46,"./transform-tree":47,"./tree":65,"./utils":86,"./visitors":90}],36:[function(require,module,exports){ 2905var utils = require('./utils'); 2906/** 2907 * This is a centralized class of any error that could be thrown internally (mostly by the parser). 2908 * Besides standard .message it keeps some additional data like a path to the file where the error 2909 * occurred along with line and column numbers. 2910 * 2911 * @class 2912 * @extends Error 2913 * @type {module.LessError} 2914 * 2915 * @prop {string} type 2916 * @prop {string} filename 2917 * @prop {number} index 2918 * @prop {number} line 2919 * @prop {number} column 2920 * @prop {number} callLine 2921 * @prop {number} callExtract 2922 * @prop {string[]} extract 2923 * 2924 * @param {Object} e - An error object to wrap around or just a descriptive object 2925 * @param {Object} fileContentMap - An object with file contents in 'contents' property (like importManager) @todo - move to fileManager? 2926 * @param {string} [currentFilename] 2927 */ 2928var LessError = module.exports = function LessError(e, fileContentMap, currentFilename) { 2929 Error.call(this); 2930 2931 var filename = e.filename || currentFilename; 2932 2933 this.message = e.message; 2934 this.stack = e.stack; 2935 2936 if (fileContentMap && filename) { 2937 var input = fileContentMap.contents[filename], 2938 loc = utils.getLocation(e.index, input), 2939 line = loc.line, 2940 col = loc.column, 2941 callLine = e.call && utils.getLocation(e.call, input).line, 2942 lines = input ? input.split('\n') : ''; 2943 2944 this.type = e.type || 'Syntax'; 2945 this.filename = filename; 2946 this.index = e.index; 2947 this.line = typeof line === 'number' ? line + 1 : null; 2948 this.column = col; 2949 2950 if (!this.line && this.stack) { 2951 var found = this.stack.match(/(<anonymous>|Function):(\d+):(\d+)/); 2952 2953 if (found) { 2954 if (found[2]) { 2955 this.line = parseInt(found[2]) - 2; 2956 } 2957 if (found[3]) { 2958 this.column = parseInt(found[3]); 2959 } 2960 } 2961 } 2962 2963 this.callLine = callLine + 1; 2964 this.callExtract = lines[callLine]; 2965 2966 this.extract = [ 2967 lines[this.line - 2], 2968 lines[this.line - 1], 2969 lines[this.line] 2970 ]; 2971 2972 } 2973 2974}; 2975 2976if (typeof Object.create === 'undefined') { 2977 var F = function () {}; 2978 F.prototype = Error.prototype; 2979 LessError.prototype = new F(); 2980} else { 2981 LessError.prototype = Object.create(Error.prototype); 2982} 2983 2984LessError.prototype.constructor = LessError; 2985 2986/** 2987 * An overridden version of the default Object.prototype.toString 2988 * which uses additional information to create a helpful message. 2989 * 2990 * @param {Object} options 2991 * @returns {string} 2992 */ 2993LessError.prototype.toString = function(options) { 2994 options = options || {}; 2995 2996 var message = ''; 2997 var extract = this.extract || []; 2998 var error = []; 2999 var stylize = function (str) { return str; }; 3000 if (options.stylize) { 3001 var type = typeof options.stylize; 3002 if (type !== 'function') { 3003 throw Error('options.stylize should be a function, got a ' + type + '!'); 3004 } 3005 stylize = options.stylize; 3006 } 3007 3008 if (this.line !== null) { 3009 if (typeof extract[0] === 'string') { 3010 error.push(stylize((this.line - 1) + ' ' + extract[0], 'grey')); 3011 } 3012 3013 if (typeof extract[1] === 'string') { 3014 var errorTxt = this.line + ' '; 3015 if (extract[1]) { 3016 errorTxt += extract[1].slice(0, this.column) + 3017 stylize(stylize(stylize(extract[1].substr(this.column, 1), 'bold') + 3018 extract[1].slice(this.column + 1), 'red'), 'inverse'); 3019 } 3020 error.push(errorTxt); 3021 } 3022 3023 if (typeof extract[2] === 'string') { 3024 error.push(stylize((this.line + 1) + ' ' + extract[2], 'grey')); 3025 } 3026 error = error.join('\n') + stylize('', 'reset') + '\n'; 3027 } 3028
3029 message += stylize(this.type + 'Error: ' + this.message, 'red'); 3030 if (this.filename) { 3031 message += stylize(' in ', 'red') + this.filename; 3032 } 3033 if (this.line) { 3034 message += stylize(' on line ' + this.line + ', column ' + (this.column + 1) + ':', 'grey'); 3035 } 3036 3037 message += '\n' + error; 3038 3039 if (this.callLine) { 3040 message += stylize('from ', 'red') + (this.filename || '') + '/n'; 3041 message += stylize(this.callLine, 'grey') + ' ' + this.callExtract + '/n'; 3042 } 3043 3044 return message; 3045}; 3046 3047},{"./utils":86}],37:[function(require,module,exports){ 3048module.exports = { 3049 error: function(msg) { 3050 this._fireEvent('error', msg); 3051 }, 3052 warn: function(msg) { 3053 this._fireEvent('warn', msg); 3054 }, 3055 info: function(msg) { 3056 this._fireEvent('info', msg); 3057 }, 3058 debug: function(msg) { 3059 this._fireEvent('debug', msg); 3060 }, 3061 addListener: function(listener) { 3062 this._listeners.push(listener); 3063 }, 3064 removeListener: function(listener) { 3065 for (var i = 0; i < this._listeners.length; i++) { 3066 if (this._listeners[i] === listener) { 3067 this._listeners.splice(i, 1); 3068 return; 3069 } 3070 } 3071 }, 3072 _fireEvent: function(type, msg) { 3073 for (var i = 0; i < this._listeners.length; i++) { 3074 var logFunction = this._listeners[i][type]; 3075 if (logFunction) { 3076 logFunction(msg); 3077 } 3078 } 3079 }, 3080 _listeners: [] 3081}; 3082 3083},{}],38:[function(require,module,exports){ 3084var LessError = require('./less-error'), 3085 transformTree = require('./transform-tree'), 3086 logger = require('./logger'); 3087 3088module.exports = function(SourceMapBuilder) { 3089 var ParseTree = function(root, imports) { 3090 this.root = root; 3091 this.imports = imports; 3092 }; 3093 3094 ParseTree.prototype.toCSS = function(options) { 3095 var evaldRoot, result = {}, sourceMapBuilder; 3096 try { 3097 evaldRoot = transformTree(this.root, options); 3098 } catch (e) { 3099 throw new LessError(e, this.imports); 3100 } 3101 3102 try { 3103 var compress = Boolean(options.compress); 3104 if (compress) { 3105 logger.warn('The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.'); 3106 } 3107 3108 var toCSSOptions = { 3109 compress: compress, 3110 dumpLineNumbers: options.dumpLineNumbers, 3111 strictUnits: Boolean(options.strictUnits), 3112 numPrecision: 8}; 3113 3114 if (options.sourceMap) { 3115 sourceMapBuilder = new SourceMapBuilder(options.sourceMap); 3116 result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports); 3117 } else { 3118 result.css = evaldRoot.toCSS(toCSSOptions); 3119 } 3120 } catch (e) { 3121 throw new LessError(e, this.imports); 3122 } 3123 3124 if (options.pluginManager) { 3125 var postProcessors = options.pluginManager.getPostProcessors(); 3126 for (var i = 0; i < postProcessors.length; i++) { 3127 result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options: options, imports: this.imports }); 3128 } 3129 } 3130 if (options.sourceMap) { 3131 result.map = sourceMapBuilder.getExternalSourceMap(); 3132 } 3133 3134 result.imports = []; 3135 for (var file in this.imports.files) { 3136 if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) { 3137 result.imports.push(file); 3138 } 3139 } 3140 return result; 3141 }; 3142 return ParseTree; 3143}; 3144 3145},{"./less-error":36,"./logger":37,"./transform-tree":47}],39:[function(require,module,exports){ 3146var PromiseConstructor, 3147 contexts = require('./contexts'), 3148 Parser = require('./parser/parser'), 3149 PluginManager = require('./plugin-manager'), 3150 LessError = require('./less-error'), 3151 utils = require('./utils'); 3152 3153module.exports = function(environment, ParseTree, ImportManager) { 3154 var parse = function (input, options, callback) { 3155 3156 if (typeof options === 'function') { 3157 callback = options; 3158 options = utils.defaults(this.options, {}); 3159 } 3160 else { 3161 options = utils.defaults(this.options, options || {}); 3162 } 3163 3164 if (!callback) { 3165 if (!PromiseConstructor) { 3166 PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise; 3167 } 3168 var self = this; 3169 return new PromiseConstructor(function (resolve, reject) { 3170 parse.call(self, input, options, function(err, output) { 3171 if (err) { 3172 reject(err); 3173 } else { 3174 resolve(output); 3175 } 3176 }); 3177 }); 3178 } else { 3179 var context, 3180 rootFileInfo, 3181 pluginManager = new PluginManager(this, !options.reUsePluginManager); 3182 3183 options.pluginManager = pluginManager; 3184 3185 context = new contexts.Parse(options); 3186 3187 if (options.rootFileInfo) { 3188 rootFileInfo = options.rootFileInfo; 3189 } else { 3190 var filename = options.filename || 'input'; 3191 var entryPath = filename.replace(/[^\/\\]*$/, ''); 3192 rootFileInfo = { 3193 filename: filename, 3194 relativeUrls: context.relativeUrls, 3195 rootpath: context.rootpath || '', 3196 currentDirectory: entryPath, 3197 entryPath: entryPath, 3198 rootFilename: filename 3199 }; 3200 // add in a missing trailing slash 3201 if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== '/') { 3202 rootFileInfo.rootpath += '/'; 3203 } 3204 } 3205 3206 var imports = new ImportManager(this, context, rootFileInfo); 3207 this.importManager = imports; 3208 3209 // TODO: allow the plugins to be just a list of paths or names 3210 // Do an async plugin queue like lessc 3211 3212 if (options.plugins) { 3213 options.plugins.forEach(function(plugin) { 3214 var evalResult, contents; 3215 if (plugin.fileContent) { 3216 contents = plugin.fileContent.replace(/^\uFEFF/, ''); 3217 evalResult = pluginManager.Loader.evalPlugin(contents, context, imports, plugin.options, plugin.filename); 3218 if (evalResult instanceof LessError) { 3219 return callback(evalResult); 3220 } 3221 } 3222 else { 3223 pluginManager.addPlugin(plugin); 3224 } 3225 }); 3226 } 3227 3228 new Parser(context, imports, rootFileInfo) 3229 .parse(input, function (e, root) { 3230 if (e) { return callback(e); } 3231 callback(null, root, imports, options); 3232 }, options); 3233 } 3234 }; 3235 return parse; 3236}; 3237 3238},{"./contexts":12,"./less-error":36,"./parser/parser":42,"./plugin-manager"
3238:43,"./utils":86,"promise":undefined}],40:[function(require,module,exports){ 3239// Split the input into chunks. 3240module.exports = function (input, fail) { 3241 var len = input.length, level = 0, parenLevel = 0, 3242 lastOpening, lastOpeningParen, lastMultiComment, lastMultiCommentEndBrace, 3243 chunks = [], emitFrom = 0, 3244 chunkerCurrentIndex, currentChunkStartIndex, cc, cc2, matched; 3245 3246 function emitChunk(force) { 3247 var len = chunkerCurrentIndex - emitFrom; 3248 if (((len < 512) && !force) || !len) { 3249 return; 3250 } 3251 chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1)); 3252 emitFrom = chunkerCurrentIndex + 1; 3253 } 3254 3255 for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) { 3256 cc = input.charCodeAt(chunkerCurrentIndex); 3257 if (((cc >= 97) && (cc <= 122)) || (cc < 34)) { 3258 // a-z or whitespace 3259 continue; 3260 } 3261 3262 switch (cc) { 3263 case 40: // ( 3264 parenLevel++; 3265 lastOpeningParen = chunkerCurrentIndex; 3266 continue; 3267 case 41: // ) 3268 if (--parenLevel < 0) { 3269 return fail('missing opening `(`', chunkerCurrentIndex); 3270 } 3271 continue; 3272 case 59: // ; 3273 if (!parenLevel) { emitChunk(); } 3274 continue; 3275 case 123: // { 3276 level++; 3277 lastOpening = chunkerCurrentIndex; 3278 continue; 3279 case 125: // } 3280 if (--level < 0) { 3281 return fail('missing opening `{`', chunkerCurrentIndex); 3282 } 3283 if (!level && !parenLevel) { emitChunk(); } 3284 continue; 3285 case 92: // \ 3286 if (chunkerCurrentIndex < len - 1) { chunkerCurrentIndex++; continue; } 3287 return fail('unescaped `\\`', chunkerCurrentIndex); 3288 case 34: 3289 case 39: 3290 case 96: // ", ' and ` 3291 matched = 0; 3292 currentChunkStartIndex = chunkerCurrentIndex; 3293 for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) { 3294 cc2 = input.charCodeAt(chunkerCurrentIndex); 3295 if (cc2 > 96) { continue; } 3296 if (cc2 == cc) { matched = 1; break; } 3297 if (cc2 == 92) { // \ 3298 if (chunkerCurrentIndex == len - 1) { 3299 return fail('unescaped `\\`', chunkerCurrentIndex); 3300 } 3301 chunkerCurrentIndex++; 3302 } 3303 } 3304 if (matched) { continue; } 3305 return fail('unmatched `' + String.fromCharCode(cc) + '`', currentChunkStartIndex); 3306 case 47: // /, check for comment 3307 if (parenLevel || (chunkerCurrentIndex == len - 1)) { continue; } 3308 cc2 = input.charCodeAt(chunkerCurrentIndex + 1); 3309 if (cc2 == 47) { 3310 // //, find lnfeed 3311 for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) { 3312 cc2 = input.charCodeAt(chunkerCurrentIndex); 3313 if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { break; } 3314 } 3315 } else if (cc2 == 42) { 3316 // /*, find */ 3317 lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex; 3318 for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) { 3319 cc2 = input.charCodeAt(chunkerCurrentIndex); 3320 if (cc2 == 125) { lastMultiCommentEndBrace = chunkerCurrentIndex; } 3321 if (cc2 != 42) { continue; } 3322 if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { break; } 3323 } 3324 if (chunkerCurrentIndex == len - 1) { 3325 return fail('missing closing `*/`', currentChunkStartIndex); 3326 } 3327 chunkerCurrentIndex++; 3328 } 3329 continue; 3330 case 42: // *, check for unmatched */ 3331 if ((chunkerCurrentIndex < len - 1) && (input.charCodeAt(chunkerCurrentIndex + 1) == 47)) { 3332 return fail('unmatched `/*`', chunkerCurrentIndex); 3333 } 3334 continue; 3335 } 3336 } 3337 3338 if (level !== 0) { 3339 if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) { 3340 return fail('missing closing `}` or `*/`', lastOpening); 3341 } else { 3342 return fail('missing closing `}`', lastOpening); 3343 } 3344 } else if (parenLevel !== 0) { 3345 return fail('missing closing `)`', lastOpeningParen); 3346 } 3347 3348 emitChunk(true); 3349 return chunks; 3350}; 3351 3352},{}],41:[function(require,module,exports){ 3353var chunker = require('./chunker'); 3354 3355module.exports = function() { 3356 var input, // Less input string 3357 j, // current chunk 3358 saveStack = [], // holds state for backtracking 3359 furthest, // furthest index the parser has gone to 3360 furthestPossibleErrorMessage, // if this is furthest we got to, this is the probably cause 3361 chunks, // chunkified input 3362 current, // current chunk 3363 currentPos, // index of current chunk, in `input` 3364 parserInput = {}; 3365 3366 var CHARCODE_SPACE = 32, 3367 CHARCODE_TAB = 9, 3368 CHARCODE_LF = 10, 3369 CHARCODE_CR = 13, 3370 CHARCODE_PLUS = 43, 3371 CHARCODE_COMMA = 44, 3372 CHARCODE_FORWARD_SLASH = 47, 3373 CHARCODE_9 = 57; 3374 3375 function skipWhitespace(length) { 3376 var oldi = parserInput.i, oldj = j, 3377 curr = parserInput.i - currentPos, 3378 endIndex = parserInput.i + current.length - curr, 3379 mem = (parserInput.i += length), 3380 inp = input, 3381 c, nextChar, comment; 3382 3383 for (; parserInput.i < endIndex; parserInput.i++) {
3384 c = inp.charCodeAt(parserInput.i); 3385 3386 if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) { 3387 nextChar = inp.charAt(parserInput.i + 1); 3388 if (nextChar === '/') { 3389 comment = {index: parserInput.i, isLineComment: true}; 3390 var nextNewLine = inp.indexOf('\n', parserInput.i + 2); 3391 if (nextNewLine < 0) { 3392 nextNewLine = endIndex; 3393 } 3394 parserInput.i = nextNewLine; 3395 comment.text = inp.substr(comment.index, parserInput.i - comment.index); 3396 parserInput.commentStore.push(comment); 3397 continue; 3398 } else if (nextChar === '*') { 3399 var nextStarSlash = inp.indexOf('*/', parserInput.i + 2); 3400 if (nextStarSlash >= 0) { 3401 comment = { 3402 index: parserInput.i, 3403 text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i), 3404 isLineComment: false 3405 }; 3406 parserInput.i += comment.text.length - 1; 3407 parserInput.commentStore.push(comment); 3408 continue; 3409 } 3410 } 3411 break; 3412 } 3413 3414 if ((c !== CHARCODE_SPACE) && (c !== CHARCODE_LF) && (c !== CHARCODE_TAB) && (c !== CHARCODE_CR)) { 3415 break; 3416 } 3417 } 3418 3419 current = current.slice(length + parserInput.i - mem + curr); 3420 currentPos = parserInput.i; 3421 3422 if (!current.length) { 3423 if (j < chunks.length - 1) { 3424 current = chunks[++j]; 3425 skipWhitespace(0); // skip space at the beginning of a chunk 3426 return true; // things changed 3427 } 3428 parserInput.finished = true; 3429 } 3430 3431 return oldi !== parserInput.i || oldj !== j; 3432 } 3433 3434 parserInput.save = function() { 3435 currentPos = parserInput.i; 3436 saveStack.push( { current: current, i: parserInput.i, j: j }); 3437 }; 3438 parserInput.restore = function(possibleErrorMessage) { 3439 3440 if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) { 3441 furthest = parserInput.i; 3442 furthestPossibleErrorMessage = possibleErrorMessage; 3443 } 3444 var state = saveStack.pop(); 3445 current = state.current; 3446 currentPos = parserInput.i = state.i; 3447 j = state.j; 3448 }; 3449 parserInput.forget = function() { 3450 saveStack.pop(); 3451 }; 3452 parserInput.isWhitespace = function (offset) { 3453 var pos = parserInput.i + (offset || 0), 3454 code = input.charCodeAt(pos); 3455 return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF); 3456 }; 3457 3458 // Specialization of $(tok) 3459 parserInput.$re = function(tok) { 3460 if (parserInput.i > currentPos) { 3461 current = current.slice(parserInput.i - currentPos); 3462 currentPos = parserInput.i; 3463 } 3464 3465 var m = tok.exec(current); 3466 if (!m) { 3467 return null; 3468 } 3469 3470 skipWhitespace(m[0].length); 3471 if (typeof m === 'string') { 3472 return m; 3473 } 3474 3475 return m.length === 1 ? m[0] : m; 3476 }; 3477 3478 parserInput.$char = function(tok) { 3479 if (input.charAt(parserInput.i) !== tok) { 3480 return null; 3481 } 3482 skipWhitespace(1); 3483 return tok; 3484 }; 3485 3486 parserInput.$str = function(tok) { 3487 var tokLength = tok.length; 3488 3489 // https://jsperf.com/string-startswith/21 3490 for (var i = 0; i < tokLength; i++) { 3491 if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { 3492 return null; 3493 } 3494 } 3495 3496 skipWhitespace(tokLength); 3497 return tok; 3498 }; 3499 3500 parserInput.$quoted = function(loc) { 3501 var pos = loc || parserInput.i, 3502 startChar = input.charAt(pos); 3503 3504 if (startChar !== '\'' && startChar !== '"') { 3505 return; 3506 } 3507 var length = input.length, 3508 currentPosition = pos; 3509 3510 for (var i = 1; i + currentPosition < length; i++) { 3511 var nextChar = input.charAt(i + currentPosition); 3512 switch (nextChar) { 3513 case '\\': 3514 i++; 3515 continue; 3516 case '\r': 3517 case '\n': 3518 break; 3519 case startChar: 3520 var str = input.substr(currentPosition, i + 1); 3521 if (!loc && loc !== 0) { 3522 skipWhitespace(i + 1); 3523 return str 3524 } 3525 return [startChar, str]; 3526 default: 3527 } 3528 } 3529 return null; 3530 }; 3531 3532 /** 3533 * Permissive parsing. Ignores everything except matching {} [] () and quotes 3534 * until matching token (outside of blocks) 3535 */ 3536 parserInput.$parseUntil = function(tok) { 3537 var quote = '', 3538 returnVal = null, 3539 inComment = false, 3540 blockDepth = 0, 3541 blockStack = [], 3542 parseGroups = [], 3543 length = input.length, 3544 startPos = parserInput.i,
3545 lastPos = parserInput.i, 3546 i = parserInput.i, 3547 loop = true, 3548 testChar; 3549 3550 if (typeof tok === 'string') { 3551 testChar = function(char) { 3552 return char === tok; 3553 } 3554 } else { 3555 testChar = function(char) { 3556 return tok.test(char); 3557 } 3558 } 3559 3560 do { 3561 var prevChar, nextChar = input.charAt(i); 3562 if (blockDepth === 0 && testChar(nextChar)) { 3563 returnVal = input.substr(lastPos, i - lastPos); 3564 if (returnVal) { 3565 parseGroups.push(returnVal); 3566 returnVal = parseGroups; 3567 } 3568 else { 3569 returnVal = [' ']; 3570 } 3571 skipWhitespace(i - startPos); 3572 loop = false 3573 } else { 3574 if (inComment) { 3575 if (nextChar === '*' && 3576 input.charAt(i + 1) === '/') { 3577 i++; 3578 blockDepth--; 3579 inComment = false; 3580 } 3581 i++; 3582 continue; 3583 } 3584 switch (nextChar) { 3585 case '\\': 3586 i++; 3587 nextChar = input.charAt(i); 3588 parseGroups.push(input.substr(lastPos, i - lastPos + 1)); 3589 lastPos = i + 1; 3590 break; 3591 case '/': 3592 if (input.charAt(i + 1) === '*') { 3593 i++; 3594 console.log(input.substr(lastPos, i - lastPos)); 3595 inComment = true; 3596 blockDepth++; 3597 } 3598 break; 3599 case '\'': 3600 case '"': 3601 quote = parserInput.$quoted(i); 3602 if (quote) { 3603 parseGroups.push(input.substr(lastPos, i - lastPos), quote); 3604 i += quote[1].length - 1; 3605 lastPos = i + 1; 3606 } 3607 else { 3608 skipWhitespace(i - startPos); 3609 returnVal = nextChar; 3610 loop = false; 3611 } 3612 break; 3613 case '{': 3614 blockStack.push('}'); 3615 blockDepth++; 3616 break; 3617 case '(': 3618 blockStack.push(')'); 3619 blockDepth++; 3620 break; 3621 case '[': 3622 blockStack.push(']'); 3623 blockDepth++; 3624 break; 3625 case '}': 3626 case ')': 3627 case ']': 3628 var expected = blockStack.pop(); 3629 if (nextChar === expected) { 3630 blockDepth--; 3631 } else { 3632 // move the parser to the error and return expected 3633 skipWhitespace(i - startPos); 3634 returnVal = expected; 3635 loop = false; 3636 } 3637 } 3638 i++; 3639 if (i > length) { 3640 loop = false; 3641 } 3642 } 3643 prevChar = nextChar; 3644 } while (loop); 3645 3646 return returnVal ? returnVal : null; 3647 } 3648 3649 parserInput.autoCommentAbsorb = true; 3650 parserInput.commentStore = []; 3651 parserInput.finished = false; 3652 3653 // Same as $(), but don't change the state of the parser, 3654 // just return the match. 3655 parserInput.peek = function(tok) { 3656 if (typeof tok === 'string') { 3657 // https://jsperf.com/string-startswith/21 3658 for (var i = 0; i < tok.length; i++) { 3659 if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { 3660 return false;
3661 } 3662 } 3663 return true; 3664 } else { 3665 return tok.test(current); 3666 } 3667 }; 3668 3669 // Specialization of peek() 3670 // TODO remove or change some currentChar calls to peekChar 3671 parserInput.peekChar = function(tok) { 3672 return input.charAt(parserInput.i) === tok; 3673 }; 3674 3675 parserInput.currentChar = function() { 3676 return input.charAt(parserInput.i); 3677 }; 3678 3679 parserInput.getInput = function() { 3680 return input; 3681 }; 3682 3683 parserInput.peekNotNumeric = function() { 3684 var c = input.charCodeAt(parserInput.i); 3685 // Is the first char of the dimension 0-9, '.', '+' or '-' 3686 return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA; 3687 }; 3688 3689 parserInput.start = function(str, chunkInput, failFunction) { 3690 input = str; 3691 parserInput.i = j = currentPos = furthest = 0; 3692 3693 // chunking apparently makes things quicker (but my tests indicate 3694 // it might actually make things slower in node at least) 3695 // and it is a non-perfect parse - it can't recognise 3696 // unquoted urls, meaning it can't distinguish comments 3697 // meaning comments with quotes or {}() in them get 'counted' 3698 // and then lead to parse errors. 3699 // In addition if the chunking chunks in the wrong place we might 3700 // not be able to parse a parser statement in one go 3701 // this is officially deprecated but can be switched on via an option 3702 // in the case it causes too much performance issues. 3703 if (chunkInput) { 3704 chunks = chunker(str, failFunction); 3705 } else { 3706 chunks = [str]; 3707 } 3708 3709 current = chunks[0]; 3710 3711 skipWhitespace(0); 3712 }; 3713 3714 parserInput.end = function() { 3715 var message, 3716 isFinished = parserInput.i >= input.length; 3717 3718 if (parserInput.i < furthest) { 3719 message = furthestPossibleErrorMessage; 3720 parserInput.i = furthest; 3721 } 3722 return { 3723 isFinished: isFinished, 3724 furthest: parserInput.i, 3725 furthestPossibleErrorMessage: message, 3726 furthestReachedEnd: parserInput.i >= input.length - 1, 3727 furthestChar: input[parserInput.i] 3728 }; 3729 }; 3730 3731 return parserInput; 3732}; 3733 3734},{"./chunker":40}],42:[function(require,module,exports){ 3735var LessError = require('../less-error'), 3736 tree = require('../tree'), 3737 visitors = require('../visitors'), 3738 getParserInput = require('./parser-input'), 3739 utils = require('../utils'), 3740 functionRegistry = require('../functions/function-registry'); 3741 3742// 3743// less.js - parser 3744// 3745// A relatively straight-forward predictive parser. 3746// There is no tokenization/lexing stage, the input is parsed 3747// in one sweep. 3748// 3749// To make the parser fast enough to run in the browser, several 3750// optimization had to be made: 3751// 3752// - Matching and slicing on a huge input is often cause of slowdowns. 3753// The solution is to chunkify the input into smaller strings. 3754// The chunks are stored in the `chunks` var, 3755// `j` holds the current chunk index, and `currentPos` holds 3756// the index of the current chunk in relation to `input`. 3757// This gives us an almost 4x speed-up. 3758// 3759// - In many cases, we don't need to match individual tokens; 3760// for example, if a value doesn't hold any variables, operations 3761// or dynamic references, the parser can effectively 'skip' it, 3762// treating it as a literal. 3763// An example would be '1px solid #000' - which evaluates to itself, 3764// we don't need to know what the individual components are. 3765// The drawback, of course is that you don't get the benefits of 3766// syntax-checking on the CSS. This gives us a 50% speed-up in the parser, 3767// and a smaller speed-up in the code-gen. 3768// 3769// 3770// Token matching is done with the `$` function, which either takes 3771// a terminal string or regexp, or a non-terminal function to call. 3772// It also takes care of moving all the indices forwards. 3773// 3774 3775var Parser = function Parser(context, imports, fileInfo) { 3776 var parsers, 3777 parserInput = getParserInput(); 3778 3779 function error(msg, type) { 3780 throw new LessError( 3781 { 3782 index: parserInput.i, 3783 filename: fileInfo.filename, 3784 type: type || 'Syntax', 3785 message: msg 3786 }, 3787 imports 3788 ); 3789 } 3790 3791 function expect(arg, msg, index) { 3792 // some older browsers return typeof 'function' for RegExp 3793 var result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg); 3794 if (result) { 3795 return result; 3796 } 3797 error(msg || (typeof arg === 'string' ? 'expected \'' + arg + '\' got \'' + parserInput.currentChar() + '\'' 3798 : 'unexpected token')); 3799 } 3800 3801 // Specialization of expect() 3802 function expectChar(arg, msg) { 3803 if (parserInput.$char(arg)) { 3804 return arg; 3805 } 3806 error(msg || 'expected \'' + arg + '\' got \'' + parserInput.currentChar() + '\''); 3807 } 3808 3809 function getDebugInfo(index) { 3810 var filename = fileInfo.filename; 3811 3812 return { 3813 lineNumber: utils.getLocation(index, parserInput.getInput()).line + 1, 3814 fileName: filename 3815 }; 3816 } 3817 3818 /** 3819 * Used after initial parsing to create nodes on the fly 3820 * 3821 * @param {String} str - string to parse 3822 * @param {Array} parseList - array of parsers to run input through e.g. ["value", "important"] 3823 * @param {Number} currentIndex - start number to begin indexing 3824 * @param {Object} fileInfo - fileInfo to attach to created nodes 3825 */ 3826 function parseNode(str, parseList, currentIndex, fileInfo, callback) { 3827 var result, returnNodes = []; 3828 var parser = parserInput; 3829 3830 try { 3831 parser.start(str, false, function fail(msg, index) { 3832 callback({ 3833 message: msg, 3834 index: index + currentIndex 3835 }); 3836 }); 3837 for (var x = 0, p, i; (p = parseList[x]); x++) { 3838 i = parser.i; 3839 result = parsers[p](); 3840 if (result) { 3841 result._index = i + currentIndex; 3842 result._fileInfo = fileInfo; 3843 returnNodes.push(result); 3844 } 3845 else { 3846 returnNodes.push(null); 3847 } 3848 } 3849 3850 var endInfo = parser.end(); 3851 if (endInfo.isFinished) { 3852 callback(null, returnNodes); 3853 } 3854 else { 3855 callback(true, null); 3856 } 3857 } catch (e) { 3858 throw new LessError({ 3859 index: e.index + currentIndex, 3860 message: e.message 3861 }, imports, fileInfo.filename); 3862 } 3863 } 3864 3865 // 3866 // The Parser 3867 // 3868 return { 3869 parserInput: parserInput, 3870 imports: imports, 3871 fileInfo: fileInfo, 3872 parseNode: parseNode, 3873 // 3874 // Parse an input string into an abstract syntax tree, 3875 // @param str A string containing 'less' markup 3876 // @param callback call `callback` when done. 3877 // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply 3878 // 3879 parse: function (str, callback, additionalData) { 3880 var root, error = null, globalVars, modifyVars, ignored, preText = ''; 3881 3882 globalVars = (additionalData && additionalData.globalVars) ? Parser.serializeVars(additionalData.globalVars) + '\n' : ''; 3883 modifyVars = (additionalData && additionalData.modifyVars) ? '\n' + Parser.serializeVars(additionalData.modifyVars) : ''; 3884 3885 if (context.pluginManager) { 3886 var preProcessors = context.pluginManager.getPreProcessors(); 3887 for (var i = 0; i < preProcessors.length; i++) { 3888 str = preProcessors[i].process(str, { context: context, imports: imports, fileInfo: fileInfo }); 3889 } 3890 } 3891 3892 if (globalVars || (additionalData && additionalData.banner)) { 3893 preText = ((additionalData && additionalData.banner) ? additionalData.banner : '') + globalVars; 3894 ignored = imports.contentsIgnoredChars; 3895 ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0; 3896 ignored[fileInfo.filename] += preText.length; 3897 } 3898 3899 str = str.replace(/\r\n?/g, '\n'); 3900 // Remove potential UTF Byte Order Mark 3901 str = preText + str.replace(/^\uFEFF/, '') + modifyVars; 3902 imports.contents[fileInfo.filename] = str; 3903 3904 // Start with the primary rule. 3905 // The whole syntax tree is held under a Ruleset node, 3906 // with the `root` property set to true, so no `{}` are 3907 // output. The callback is called when the input is parsed. 3908 try { 3909 parserInput.start(str, context.chunkInput, function fail(msg, index) { 3910 throw new LessError({ 3911 index: index, 3912 type: 'Parse', 3913 message: msg, 3914 filename: fileInfo.filename 3915 }, imports); 3916 }); 3917 3918 tree.Node.prototype.parse = this; 3919 root = new tree.Ruleset(null, this.parsers.primary()); 3920 tree.Node.prototype.rootNode = root; 3921 root.root = true; 3922 root.firstRoot = true; 3923 root.functionRegistry = functionRegistry.inherit(); 3924 3925 } catch (e) { 3926 return callback(new LessError(e, imports, fileInfo.filename)); 3927 } 3928 3929 // If `i` is smaller than the `input.length - 1`, 3930 // it means the parser wasn't able to parse the whole 3931 // string, so we've got a parsing error. 3932 // 3933 // We try to extract a \n delimited string, 3934 // showing the line where the parse error occurred. 3935 // We split it up into two parts (the part which parsed, 3936 // and the part which didn't), so we can color them differently. 3937 var endInfo = parserInput.end(); 3938 if (!endInfo.isFinished) { 3939 3940 var message = endInfo.furthestPossibleErrorMessage; 3941 3942 if (!message) { 3943 message = 'Unrecognised input'; 3944 if (endInfo.furthestChar === '}') { 3945 message += '. Possibly missing opening \'{\''; 3946 } else if (endInfo.furthestChar === ')') { 3947 message += '. Possibly missing opening \'(\''; 3948 } else if (endInfo.furthestReachedEnd) { 3949 message += '. Possibly missing something'; 3950 } 3951 } 3952 3953 error = new LessError({ 3954 type: 'Parse', 3955 message: message, 3956 index: endInfo.furthest, 3957 filename: fileInfo.filename 3958 }, imports); 3959 } 3960 3961 var finish = function (e) { 3962 e = error || e || imports.error; 3963 3964 if (e) { 3965 if (!(e instanceof LessError)) { 3966 e = new LessError(e, imports, fileInfo.filename); 3967 } 3968 3969 return callback(e); 3970 } 3971 else { 3972 return callback(null, root); 3973 } 3974 }; 3975 3976 if (context.processImports !== false) { 3977 new visitors.ImportVisitor(imports, finish) 3978 .run(root); 3979 } else { 3980 return finish(); 3981 } 3982 }, 3983 3984 // 3985 // Here in, the parsing rules/functions 3986 // 3987 // The basic structure of the syntax tree generated is as follows: 3988 // 3989 // Ruleset -> Declaration -> Value -> Expression -> Entity 3990 // 3991 // Here's some Less code: 3992 // 3993 // .class { 3994 // color: #fff; 3995 // border: 1px solid #000; 3996 // width: @w + 4px; 3997 // > .child {...} 3998 // } 3999 // 4000 // And here's what the parse tree might look like: 4001 // 4002 // Ruleset (Selector '.class', [ 4003 // Declaration ("color", Value ([Expression [Color #fff]])) 4004 // Declaration ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) 4005 // Declaration ("width", Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]])) 4006 // Ruleset (Selector [Element '>', '.child'], [...]) 4007 // ]) 4008 // 4009 // In general, most rules will try to parse a token with the `$re()` function, and if the return 4010 // value is truly, will return a new node, of the relevant type. Sometimes, we need to check 4011 // first, before parsing, that's when we use `peek()`. 4012 // 4013 parsers: parsers = { 4014 // 4015 // The `primary` rule is the *entry* and *exit* point of the parser. 4016 // The rules here can appear at any level of the parse tree. 4017 // 4018 // The recursive nature of the grammar is an interplay between the `block` 4019 // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
4020 // as represented by this simplified grammar: 4021 // 4022 // primary â (ruleset | declaration)+ 4023 // ruleset â selector+ block 4024 // block â '{' primary '}' 4025 // 4026 // Only at one point is the primary rule not called from the 4027 // block rule: at the root level. 4028 // 4029 primary: function () { 4030 var mixin = this.mixin, root = [], node; 4031 4032 while (true) { 4033 while (true) { 4034 node = this.comment(); 4035 if (!node) { break; } 4036 root.push(node); 4037 } 4038 // always process comments before deciding if finished 4039 if (parserInput.finished) { 4040 break; 4041 } 4042 if (parserInput.peek('}')) { 4043 break; 4044 } 4045 4046 node = this.extendRule(); 4047 if (node) { 4048 root = root.concat(node); 4049 continue; 4050 } 4051 4052 node = mixin.definition() || this.declaration() || this.ruleset() || 4053 mixin.call() || this.variableCall() || this.entities.call() || this.atrule(); 4054 if (node) { 4055 root.push(node); 4056 } else { 4057 var foundSemiColon = false; 4058 while (parserInput.$char(';')) { 4059 foundSemiColon = true; 4060 } 4061 if (!foundSemiColon) { 4062 break; 4063 } 4064 } 4065 } 4066 4067 return root; 4068 }, 4069 4070 // comments are collected by the main parsing mechanism and then assigned to nodes 4071 // where the current structure allows it 4072 comment: function () { 4073 if (parserInput.commentStore.length) { 4074 var comment = parserInput.commentStore.shift(); 4075 return new(tree.Comment)(comment.text, comment.isLineComment, comment.index, fileInfo); 4076 } 4077 }, 4078 4079 // 4080 // Entities are tokens which can be found inside an Expression 4081 // 4082 entities: { 4083 // 4084 // A string, which supports escaping " and ' 4085 // 4086 // "milky way" 'he\'s the one!' 4087 // 4088 quoted: function () { 4089 var str, index = parserInput.i, isEscaped = false; 4090 4091 parserInput.save(); 4092 if (parserInput.$char('~')) { 4093 isEscaped = true; 4094 } 4095 str = parserInput.$quoted(); 4096 if (!str) { 4097 parserInput.restore(); 4098 return; 4099 } 4100 parserInput.forget(); 4101 4102 return new(tree.Quoted)(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo); 4103 }, 4104 4105 // 4106 // A catch-all word, such as: 4107 // 4108 // black border-collapse 4109 // 4110 keyword: function () { 4111 var k = parserInput.$char('%') || parserInput.$re(/^\[?[_A-Za-z-][_A-Za-z0-9-]*\]?/); 4112 if (k) { 4113 return tree.Color.fromKeyword(k) || new(tree.Keyword)(k); 4114 } 4115 }, 4116 4117 // 4118 // A function call 4119 // 4120 // rgb(255, 0, 255) 4121 // 4122 // The arguments are parsed with the `entities.arguments` parser. 4123 // 4124 call: function () { 4125 var name, args, func, index = parserInput.i; 4126 4127 // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 4128 if (parserInput.peek(/^url\(/i)) { 4129 return; 4130 } 4131 4132 parserInput.save(); 4133 4134 name = parserInput.$re(/^([\w-]+|%|progid:[\w\.]+)\(/); 4135 if (!name) { 4136 parserInput.forget(); 4137 return; 4138 } 4139 4140 name = name[1]; 4141 func = this.customFuncCall(name); 4142 if (func) { 4143 args = func.parse(); 4144 if (args && func.stop) { 4145 parserInput.forget(); 4146 return args; 4147 } 4148 } 4149 4150 args = this.arguments(args); 4151 4152 if (!parserInput.$char(')')) { 4153 parserInput.restore('Could not parse call arguments or missing \')\''); 4154 return; 4155 } 4156 4157 parserInput.forget(); 4158 4159 return new(tree.Call)(name, args, index, fileInfo); 4160 }, 4161 4162 //
4163 // Parsing rules for functions with non-standard args, e.g.: 4164 // 4165 // boolean(not(2 > 1)) 4166 // 4167 // This is a quick prototype, to be modified/improved when 4168 // more custom-parsed funcs come (e.g. `selector(...)`) 4169 // 4170 4171 customFuncCall: function (name) { 4172 /* Ideally the table is to be moved out of here for faster perf., 4173 but it's quite tricky since it relies on all these `parsers` 4174 and `expect` available only here */ 4175 return { 4176 alpha: f(parsers.ieAlpha, true), 4177 boolean: f(condition), 4178 'if': f(condition) 4179 }[name.toLowerCase()]; 4180 4181 function f(parse, stop) { 4182 return { 4183 parse: parse, // parsing function 4184 stop: stop // when true - stop after parse() and return its result, 4185 // otherwise continue for plain args 4186 }; 4187 } 4188 4189 function condition() { 4190 return [expect(parsers.condition, 'expected condition')]; 4191 } 4192 }, 4193 4194 arguments: function (prevArgs) { 4195 var argsComma = prevArgs || [], 4196 argsSemiColon = [], 4197 isSemiColonSeparated, value; 4198 4199 parserInput.save(); 4200 4201 while (true) { 4202 if (prevArgs) { 4203 prevArgs = false; 4204 } else { 4205 value = parsers.detachedRuleset() || this.assignment() || parsers.expression(); 4206 if (!value) { 4207 break; 4208 } 4209 4210 if (value.value && value.value.length == 1) { 4211 value = value.value[0]; 4212 } 4213 4214 argsComma.push(value); 4215 } 4216 4217 if (parserInput.$char(',')) { 4218 continue; 4219 } 4220 4221 if (parserInput.$char(';') || isSemiColonSeparated) { 4222 isSemiColonSeparated = true; 4223 value = (argsComma.length < 1) ? argsComma[0] 4224 : new tree.Value(argsComma); 4225 argsSemiColon.push(value); 4226 argsComma = []; 4227 } 4228 } 4229 4230 parserInput.forget(); 4231 return isSemiColonSeparated ? argsSemiColon : argsComma; 4232 }, 4233 literal: function () { 4234 return this.dimension() || 4235 this.color() || 4236 this.quoted() || 4237 this.unicodeDescriptor(); 4238 }, 4239 4240 // Assignments are argument entities for calls. 4241 // They are present in ie filter properties as shown below. 4242 // 4243 // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) 4244 // 4245 4246 assignment: function () { 4247 var key, value; 4248 parserInput.save(); 4249 key = parserInput.$re(/^\w+(?=\s?=)/i); 4250 if (!key) { 4251 parserInput.restore(); 4252 return; 4253 } 4254 if (!parserInput.$char('=')) { 4255 parserInput.restore(); 4256 return; 4257 } 4258 value = parsers.entity(); 4259 if (value) { 4260 parserInput.forget(); 4261 return new(tree.Assignment)(key, value); 4262 } else {
4263 parserInput.restore(); 4264 } 4265 }, 4266 4267 // 4268 // Parse url() tokens 4269 // 4270 // We use a specific rule for urls, because they don't really behave like 4271 // standard function calls. The difference is that the argument doesn't have 4272 // to be enclosed within a string, so it can't be parsed as an Expression. 4273 // 4274 url: function () { 4275 var value, index = parserInput.i; 4276 4277 parserInput.autoCommentAbsorb = false; 4278 4279 if (!parserInput.$str('url(')) { 4280 parserInput.autoCommentAbsorb = true; 4281 return; 4282 } 4283 4284 value = this.quoted() || this.variable() || this.property() || 4285 parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ''; 4286 4287 parserInput.autoCommentAbsorb = true; 4288 4289 expectChar(')'); 4290 4291 return new(tree.URL)((value.value != null || 4292 value instanceof tree.Variable || 4293 value instanceof tree.Property) ? 4294 value : new(tree.Anonymous)(value, index), index, fileInfo); 4295 }, 4296 4297 // 4298 // A Variable entity, such as `@fink`, in 4299 // 4300 // width: @fink + 2px 4301 // 4302 // We use a different parser for variable definitions, 4303 // see `parsers.variable`. 4304 // 4305 variable: function () { 4306 var name, index = parserInput.i; 4307 4308 if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) { 4309 return new(tree.Variable)(name, index, fileInfo); 4310 } 4311 }, 4312 4313 // A variable entity using the protective {} e.g. @{var} 4314 variableCurly: function () { 4315 var curly, index = parserInput.i; 4316 4317 if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) { 4318 return new(tree.Variable)('@' + curly[1], index, fileInfo); 4319 } 4320 }, 4321 // 4322 // A Property accessor, such as `$color`, in 4323 // 4324 // background-color: $color 4325 // 4326 property: function () { 4327 var name, index = parserInput.i; 4328 4329 if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) { 4330 return new(tree.Property)(name, index, fileInfo); 4331 } 4332 }, 4333 4334 // A property entity useing the protective {} e.g. ${prop} 4335 propertyCurly: function () { 4336 var curly, index = parserInput.i; 4337 4338 if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) { 4339 return new(tree.Property)('$' + curly[1], index, fileInfo); 4340 } 4341 }, 4342 // 4343 // A Hexadecimal color 4344 // 4345 // #4F3C2F 4346 // 4347 // `rgb` and `hsl` colors are parsed through the `entities.call` parser. 4348 // 4349 color: function () { 4350 var rgb; 4351 4352 if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { 4353 // strip colons, brackets, whitespaces and other characters that should not 4354 // definitely be part of color string 4355 var colorCandidateString = rgb.input.match(/^#([\w]+).*/); 4356 colorCandidateString = colorCandidateString[1]; 4357 if (!colorCandidateString.match(/^[A-Fa-f0-9]+$/)) { // verify if candidate consists only of allowed HEX characters 4358 error('Invalid HEX color code'); 4359 } 4360 return new(tree.Color)(rgb[1], undefined, '#' + colorCandidateString); 4361 } 4362 }, 4363 4364 colorKeyword: function () { 4365 parserInput.save(); 4366 var autoCommentAbsorb = parserInput.autoCommentAbsorb; 4367 parserInput.autoCommentAbsorb = false;
4368 var k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/); 4369 parserInput.autoCommentAbsorb = autoCommentAbsorb; 4370 if (!k) { 4371 parserInput.forget(); 4372 return; 4373 } 4374 parserInput.restore(); 4375 var color = tree.Color.fromKeyword(k); 4376 if (color) { 4377 parserInput.$str(k); 4378 return color; 4379 } 4380 }, 4381 4382 // 4383 // A Dimension, that is, a number and a unit 4384 // 4385 // 0.5em 95% 4386 // 4387 dimension: function () { 4388 if (parserInput.peekNotNumeric()) { 4389 return; 4390 } 4391 4392 var value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i); 4393 if (value) { 4394 return new(tree.Dimension)(value[1], value[2]); 4395 } 4396 }, 4397 4398 // 4399 // A unicode descriptor, as is used in unicode-range 4400 // 4401 // U+0?? or U+00A1-00A9 4402 // 4403 unicodeDescriptor: function () { 4404 var ud; 4405 4406 ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/); 4407 if (ud) { 4408 return new(tree.UnicodeDescriptor)(ud[0]); 4409 } 4410 }, 4411 4412 // 4413 // JavaScript code to be evaluated 4414 // 4415 // `window.location.href` 4416 // 4417 javascript: function () { 4418 var js, index = parserInput.i; 4419 4420 parserInput.save(); 4421 4422 var escape = parserInput.$char('~'); 4423 var jsQuote = parserInput.$char('`'); 4424 4425 if (!jsQuote) { 4426 parserInput.restore(); 4427 return; 4428 } 4429 4430 js = parserInput.$re(/^[^`]*`/); 4431 if (js) { 4432 parserInput.forget(); 4433 return new(tree.JavaScript)(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo); 4434 } 4435 parserInput.restore('invalid javascript definition'); 4436 } 4437 }, 4438 4439 // 4440 // The variable part of a variable definition. Used in the `rule` parser 4441 // 4442 // @fink: 4443 // 4444 variable: function () { 4445 var name; 4446 4447 if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { return name[1]; } 4448 }, 4449 4450 // 4451 // Call a variable value 4452 // 4453 // @fink() 4454 // 4455 variableCall: function () { 4456 var name; 4457 4458 if (parserInput.currentChar() === '@' 4459 && (name = parserInput.$re(/^(@[\w-]+)\(\s*\)/)) 4460 && parsers.end()) { 4461 return new tree.VariableCall(name[1]); 4462 } 4463 }, 4464 4465 // 4466 // extend syntax - used to extend selectors 4467 // 4468 extend: function(isRule) { 4469 var elements, e, index = parserInput.i, option, extendList, extend; 4470 4471 if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) { 4472 return; 4473 } 4474 4475 do { 4476 option = null; 4477 elements = null; 4478 while (!(option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) { 4479 e = this.element(); 4480 if (!e) { 4481 break; 4482 } 4483 if (elements) { 4484 elements.push(e); 4485 } else { 4486 elements = [ e ]; 4487 } 4488 } 4489 4490 option = option && option[1]; 4491 if (!elements) { 4492 error('Missing target selector for :extend().'); 4493 } 4494 extend = new(tree.Extend)(new(tree.Selector)(elements), option, index, fileInfo); 4495 if (extendList) { 4496 extendList.push(extend); 4497 } else { 4498 extendList = [ extend ]; 4499 } 4500 } while (parserInput.$char(',')); 4501 4502 expect(/^\)/); 4503 4504 if (isRule) { 4505 expect(/^;/); 4506 } 4507 4508 return extendList; 4509 }, 4510 4511 // 4512 // extendRule - used in a rule to extend all the parent selectors 4513 // 4514 extendRule: function() { 4515 return this.extend(true); 4516 }, 4517 4518 // 4519 // Mixins 4520 // 4521 mixin: { 4522 // 4523 // A Mixin call, with an optional argument list 4524 // 4525 // #mixins > .square(#fff); 4526 // .rounded(4px, black); 4527 // .button; 4528 // 4529 // The `while` loop is there because mixins can be 4530 // namespaced, but we only support the child and desce
4530ndant 4531 // selector for now. 4532 // 4533 call: function () { 4534 var s = parserInput.currentChar(), important = false, index = parserInput.i, elemIndex, 4535 elements, elem, e, c, args; 4536 4537 if (s !== '.' && s !== '#') { return; } 4538 4539 parserInput.save(); // stop us absorbing part of an invalid selector 4540 4541 while (true) { 4542 elemIndex = parserInput.i; 4543 e = parserInput.$re(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/); 4544 if (!e) { 4545 break; 4546 } 4547 elem = new(tree.Element)(c, e, elemIndex, fileInfo); 4548 if (elements) { 4549 elements.push(elem); 4550 } else { 4551 elements = [ elem ]; 4552 } 4553 c = parserInput.$char('>'); 4554 } 4555 4556 if (elements) { 4557 if (parserInput.$char('(')) { 4558 args = this.args(true).args; 4559 expectChar(')'); 4560 } 4561 4562 if (parsers.important()) { 4563 important = true; 4564 } 4565 4566 if (parsers.end()) { 4567 parserInput.forget(); 4568 return new(tree.mixin.Call)(elements, args, index, fileInfo, important); 4569 } 4570 } 4571 4572 parserInput.restore(); 4573 }, 4574 args: function (isCall) { 4575 var entities = parsers.entities, 4576 returner = { args:null, variadic: false }, 4577 expressions = [], argsSemiColon = [], argsComma = [], 4578 isSemiColonSeparated, expressionContainsNamed, name, nameLoop, 4579 value, arg, expand; 4580 4581 parserInput.save(); 4582 4583 while (true) { 4584 if (isCall) { 4585 arg = parsers.detachedRuleset() || parsers.expression(); 4586 } else { 4587 parserInput.commentStore.length = 0; 4588 if (parserInput.$str('...')) { 4589 returner.variadic = true; 4590 if (parserInput.$char(';') && !isSemiColonSeparated) { 4591 isSemiColonSeparated = true; 4592 } 4593 (isSemiColonSeparated ? argsSemiColon : argsComma) 4594 .push({ variadic: true }); 4595 break; 4596 } 4597 arg = entities.variable() || entities.property() || entities.literal() || entities.keyword(); 4598 } 4599 4600 if (!arg) { 4601 break; 4602 } 4603 4604 nameLoop = null; 4605 if (arg.throwAwayComments) { 4606 arg.throwAwayComments(); 4607 } 4608 value = arg; 4609 var val = null; 4610 4611 if (isCall) { 4612 // Variable 4613 if (arg.value && arg.value.length == 1) { 4614 val = arg.value[0]; 4615 } 4616 } else { 4617 val = arg; 4618 } 4619 4620 if (val && (val instanceof tree.Variable || val instanceof tree.Property)) { 4621 if (parserInput.$char(':')) { 4622 if (expressions.length > 0) { 4623 if (isSemiColonSeparated) { 4624 error('Cannot mix ; and , as delimiter types'); 4625 } 4626 expressionContainsNamed = true; 4627 } 4628 4629 value = parsers.detachedRuleset() || parsers.expression(); 4630 4631 if (!value) { 4632 if (isCall) { 4633 error('could not understand value for named argument'); 4634 } else {
4635 parserInput.restore(); 4636 returner.args = []; 4637 return returner; 4638 } 4639 } 4640 nameLoop = (name = val.name); 4641 } else if (parserInput.$str('...')) { 4642 if (!isCall) { 4643 returner.variadic = true; 4644 if (parserInput.$char(';') && !isSemiColonSeparated) { 4645 isSemiColonSeparated = true; 4646 } 4647 (isSemiColonSeparated ? argsSemiColon : argsComma) 4648 .push({ name: arg.name, variadic: true }); 4649 break; 4650 } else { 4651 expand = true; 4652 } 4653 } else if (!isCall) { 4654 name = nameLoop = val.name; 4655 value = null; 4656 } 4657 } 4658 4659 if (value) { 4660 expressions.push(value); 4661 } 4662 4663 argsComma.push({ name:nameLoop, value:value, expand:expand }); 4664 4665 if (parserInput.$char(',')) { 4666 continue; 4667 } 4668 4669 if (parserInput.$char(';') || isSemiColonSeparated) { 4670 4671 if (expressionContainsNamed) { 4672 error('Cannot mix ; and , as delimiter types'); 4673 } 4674 4675 isSemiColonSeparated = true; 4676 4677 if (expressions.length > 1) { 4678 value = new(tree.Value)(expressions); 4679 } 4680 argsSemiColon.push({ name:name, value:value, expand:expand }); 4681 4682 name = null; 4683 expressions = []; 4684 expressionContainsNamed = false; 4685 } 4686 } 4687 4688 parserInput.forget(); 4689 returner.args = isSemiColonSeparated ? argsSemiColon : argsComma; 4690 return returner; 4691 }, 4692 // 4693 // A Mixin definition, with a list of parameters 4694 // 4695 // .rounded (@radius: 2px, @color) { 4696 // ... 4697 // } 4698 // 4699 // Until we have a finer grained state-machine, we have to 4700 // do a look-ahead, to make sure we don't have a mixin call. 4701 // See the `rule` function for more information. 4702 // 4703 // We start by matching `.rounded (`, and then proceed on to 4704 // the argument list, which has optional default values. 4705 // We store the parameters in `params`, with a `value` key, 4706 // if there is a value, such as in the case of `@radius`. 4707 // 4708 // Once we've got our params list, and a closing `)`, we parse 4709 // the `{...}` block. 4710 // 4711 definition: function () { 4712 var name, params = [], match, ruleset, cond, variadic = false; 4713 if ((parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#') || 4714 parserInput.peek(/^[^{]*\}/)) { 4715 return; 4716 } 4717 4718 parserInput.save(); 4719 4720 match = parserInput.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/); 4721 if (match) { 4722 name = match[1]; 4723 4724 var argInfo = this.args(false); 4725 params = argInfo.args; 4726 variadic = argInfo.variadic; 4727 4728 // .mixincall("@{a}"); 4729 // looks a bit like a mixin definition.. 4730 // also 4731 // .mixincall(@a: {rule: set;}); 4732 // so we have to be nice and restore 4733 if (!parserInput.$char(')')) { 4734 parserInput.restore('Missing closing \')\''); 4735 return; 4736 } 4737 4738 parserInput.commentStore.length = 0; 4739 4740 if (parserInput.$str('when')) { // Guard 4741 cond = expect(parsers.conditions, 'expected condition'); 4742 } 4743 4744 ruleset = parsers.block(); 4745 4746 if (ruleset) { 4747 parserInput.forget(); 4748 return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); 4749 } else {
4750 parserInput.restore(); 4751 } 4752 } else { 4753 parserInput.forget(); 4754 } 4755 } 4756 }, 4757 4758 // 4759 // Entities are the smallest recognized token, 4760 // and can be found inside a rule's value. 4761 // 4762 entity: function () { 4763 var entities = this.entities; 4764 4765 return this.comment() || entities.literal() || entities.variable() || entities.url() || 4766 entities.property() || entities.call() || entities.keyword() || entities.javascript(); 4767 }, 4768 4769 // 4770 // A Declaration terminator. Note that we use `peek()` to check for '}', 4771 // because the `block` rule will be expecting it, but we still need to make sure 4772 // it's there, if ';' was omitted. 4773 // 4774 end: function () { 4775 return parserInput.$char(';') || parserInput.peek('}'); 4776 }, 4777 4778 // 4779 // IE's alpha function 4780 // 4781 // alpha(opacity=88) 4782 // 4783 ieAlpha: function () { 4784 var value; 4785 4786 // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 4787 if (!parserInput.$re(/^opacity=/i)) { return; } 4788 value = parserInput.$re(/^\d+/); 4789 if (!value) { 4790 value = expect(parsers.entities.variable, 'Could not parse alpha'); 4791 value = '@{' + value.name.slice(1) + '}'; 4792 } 4793 expectChar(')'); 4794 return new tree.Quoted('', 'alpha(opacity=' + value + ')'); 4795 }, 4796 4797 // 4798 // A Selector Element 4799 // 4800 // div 4801 // + h1 4802 // #socks 4803 // input[type="text"] 4804 // 4805 // Elements are the building blocks for Selectors, 4806 // they are made out of a `Combinator` (see combinator rule), 4807 // and an element name, such as a tag a class, or `*`. 4808 // 4809 element: function () { 4810 var e, c, v, index = parserInput.i; 4811 4812 c = this.combinator(); 4813 4814 e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) || 4815 parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || 4816 parserInput.$char('*') || parserInput.$char('&') || this.attribute() || 4817 parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) || 4818 this.entities.variableCurly(); 4819 4820 if (!e) { 4821 parserInput.save(); 4822 if (parserInput.$char('(')) { 4823 if ((v = this.selector(false)) && parserInput.$char(')')) { 4824 e = new(tree.Paren)(v); 4825 parserInput.forget(); 4826 } else { 4827 parserInput.restore('Missing closing \')\''); 4828 } 4829 } else { 4830 parserInput.forget(); 4831 } 4832 } 4833 4834 if (e) { return new(tree.Element)(c, e, index, fileInfo); } 4835 }, 4836 4837 // 4838 // Combinators combine elements together, in a Selector. 4839 // 4840 // Because our parser isn't white-space sensitive, special care 4841 // has to be taken, when parsing the descendant combinator, ` `, 4842 // as it's an empty space. We have to check the previous character 4843 // in the input, to see if it's a ` ` character. More info on how 4844 // we deal with this in *combinator.js*. 4845 // 4846 combinator: function () { 4847 var c = parserInput.currentChar(); 4848 4849 if (c === '/') { 4850 parserInput.save(); 4851 var slashedCombinator = parserInput.$re(/^\/[a-z]+\//i); 4852 if (slashedCombinator) { 4853 parserInput.forget(); 4854 return new(tree.Combinator)(slashedCombinator); 4855 }
4856 parserInput.restore(); 4857 } 4858 4859 if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') { 4860 parserInput.i++; 4861 if (c === '^' && parserInput.currentChar() === '^') { 4862 c = '^^'; 4863 parserInput.i++; 4864 } 4865 while (parserInput.isWhitespace()) { parserInput.i++; } 4866 return new(tree.Combinator)(c); 4867 } else if (parserInput.isWhitespace(-1)) { 4868 return new(tree.Combinator)(' '); 4869 } else { 4870 return new(tree.Combinator)(null); 4871 } 4872 }, 4873 // 4874 // A CSS Selector 4875 // with less extensions e.g. the ability to extend and guard 4876 // 4877 // .class > div + h1 4878 // li a:hover 4879 // 4880 // Selectors are made out of one or more Elements, see above. 4881 // 4882 selector: function (isLess) { 4883 var index = parserInput.i, elements, extendList, c, e, allExtends, when, condition; 4884 isLess = isLess !== false; 4885 while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$str('when'))) || (e = this.element())) { 4886 if (when) { 4887 condition = expect(this.conditions, 'expected condition'); 4888 } else if (condition) { 4889 error('CSS guard can only be used at the end of selector'); 4890 } else if (extendList) { 4891 if (allExtends) { 4892 allExtends = allExtends.concat(extendList); 4893 } else { 4894 allExtends = extendList; 4895 } 4896 } else { 4897 if (allExtends) { error('Extend can only be used at the end of selector'); } 4898 c = parserInput.currentChar(); 4899 if (elements) { 4900 elements.push(e); 4901 } else { 4902 elements = [ e ]; 4903 } 4904 e = null; 4905 } 4906 if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { 4907 break; 4908 } 4909 } 4910 4911 if (elements) { return new(tree.Selector)(elements, allExtends, condition, index, fileInfo); } 4912 if (allExtends) { error('Extend must be used to extend a selector, it cannot be used on its own'); } 4913 }, 4914 attribute: function () { 4915 if (!parserInput.$char('[')) { return; } 4916 4917 var entities = this.entities, 4918 key, val, op; 4919 4920 if (!(key = entities.variableCurly())) { 4921 key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); 4922 } 4923 4924 op = parserInput.$re(/^[|~*$^]?=/); 4925 if (op) { 4926 val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly(); 4927 } 4928 4929 expectChar(']'); 4930 4931 return new(tree.Attribute)(key, op, val); 4932 }, 4933 4934 // 4935 // The `block` rule is used by `ruleset` and `mixin.definition`. 4936 // It's a wrapper around the `primary` rule, with added `{}`. 4937 // 4938 block: function () { 4939 var content; 4940 if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) { 4941 return content; 4942 } 4943 }, 4944 4945 blockRuleset: function() { 4946 var block = this.block(); 4947 4948 if (block) { 4949 block = new tree.Ruleset(null, block); 4950 } 4951 return block; 4952 }, 4953 4954 detachedRuleset: function() { 4955 var blockRuleset = this.blockRuleset(); 4956 if (blockRuleset) { 4957 return new tree.DetachedRuleset(blockRuleset); 4958 } 4959 }, 4960 4961 // 4962 // div, .class, body > p {...} 4963 // 4964 ruleset: function () { 4965 var selectors, s, rules, debugInfo; 4966 4967 parserInput.save(); 4968 4969 if (context.dumpLineNumbers) { 4970 debugInfo = getDebugInfo(parserInput.i); 4971 } 4972 4973 while (true) { 4974 s = this.selector(); 4975 if (!s) { 4976 break; 4977 } 4978 if (selectors) { 4979 selectors.push(s); 4980 } else { 4981 selectors = [ s ]; 4982 } 4983 parserInput.commentStore.length = 0; 4984 if (s.condition && selectors.length > 1) { 4985 error('Guards are only currently allowed on a single selector.'); 4986 } 4987 if (!parserInput.$char(',')) { break; } 4988 if (s.condition) { 4989 error('Guards are only currently allowed on a single selector.'); 4990 } 4991 parserInput.commentStore.length = 0; 4992 } 4993 4994 if (selectors && (rules = this.block())) { 4995 parserInput.forget(); 4996 var ruleset = new(tree.Ruleset)(selectors, rules, context.strictImports); 4997 if (context.dumpLineNumbers) { 4998 ruleset.debugInfo = debugInfo; 4999 } 5000 return ruleset; 5001 } else {
5002 parserInput.restore(); 5003 } 5004 }, 5005 declaration: function () { 5006 var name, value, index = parserInput.i, 5007 c = parserInput.currentChar(), important, merge, isVariable; 5008 5009 if (c === '.' || c === '#' || c === '&' || c === ':') { return; } 5010 5011 parserInput.save(); 5012 5013 name = this.variable() || this.ruleProperty(); 5014 if (name) { 5015 isVariable = typeof name === 'string'; 5016 5017 if (isVariable) { 5018 value = this.detachedRuleset(); 5019 } 5020 5021 parserInput.commentStore.length = 0; 5022 if (!value) { 5023 // a name returned by this.ruleProperty() is always an array of the form: 5024 // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"] 5025 // where each item is a tree.Keyword or tree.Variable 5026 merge = !isVariable && name.length > 1 && name.pop().value; 5027 5028 // Custom property values get permissive parsing 5029 if (name[0].value && name[0].value.slice(0, 2) === '--') { 5030 value = this.permissiveValue(';'); 5031 } 5032 // Try to store values as anonymous 5033 // If we need the value later we'll re-parse it in ruleset.parseValue 5034 else { 5035 value = this.anonymousValue(); 5036 } 5037 if (value) { 5038 parserInput.forget(); 5039 // anonymous values absorb the end ';' which is required for them to work 5040 return new (tree.Declaration)(name, value, false, merge, index, fileInfo); 5041 } 5042 5043 if (!value) { 5044 value = this.value(); 5045 } 5046 5047 important = this.important(); 5048 5049 // As a last resort, let a variable try to be parsed as a permissive value 5050 if (!value && isVariable) { 5051 value = this.permissiveValue(';'); 5052 } 5053 } 5054 5055 if (value && this.end()) { 5056 parserInput.forget(); 5057 return new (tree.Declaration)(name, value, important, merge, index, fileInfo); 5058 } 5059 else { 5060 parserInput.restore(); 5061 } 5062 } else { 5063 parserInput.restore(); 5064 } 5065 }, 5066 anonymousValue: function () { 5067 var index = parserInput.i; 5068 var match = parserInput.$re(/^([^@\$+\/'"*`(;{}-]*);/); 5069 if (match) { 5070 return new(tree.Anonymous)(match[1], index); 5071 } 5072 }, 5073 /** 5074 * Used for custom properties and custom at-rules 5075 * Parses almost anything inside of {} [] () "" blocks 5076 * until it reaches outer-most tokens. 5077 */ 5078 permissiveValue: function (untilTokens) { 5079 var i, index = parserInput.i, 5080 value = parserInput.$parseUntil(untilTokens); 5081 5082 if (value) { 5083 if (typeof value === 'string') { 5084 error('Expected \'' + value + '\'', 'Parse'); 5085 } 5086 if (value.length === 1 && value[0] === ' ') { 5087 return new tree.Anonymous('', index); 5088 } 5089 var item, args = []; 5090 for (i = 0; i < value.length; i++) { 5091 item = value[i]; 5092 if (Array.isArray(item)) { 5093 // Treat actual quotes as normal quoted values 5094 args.push(new tree.Quoted(item[0], item[1], true, index, fileInfo)); 5095 } 5096 else { 5097 if (i === value.length - 1) { 5098 item = item.trim(); 5099 } 5100 // Treat like quoted values, but replace vars like unquoted expressions 5101 var quote = new tree.Quoted('\'', item, true, index, fileInfo); 5102 quote.variableRegex = /@([\w-]+)/g; 5103 quote.propRegex = /\$([\w-]+)/g; 5104 quote.reparse = true; 5105 args.push(quote); 5106 } 5107 } 5108 return new tree.Expression(args, true); 5109 } 5110 }, 5111 5112 // 5113 // An @import atrule 5114 // 5115 // @import "lib"; 5116 // 5117 // Depending on our environment, importing is done differently: 5118 // In the browser, it's an XHR request, in Node, it would be a 5119 // file-system operation. The function used for importing is 5120 // stored in `import`, which we pass to the Import constructor. 5121 // 5122 'import': function () { 5123 var path, features, index = parserInput.i; 5124 5125 var dir = parserInput.$re(/^@import?\s+/); 5126 5127 if (dir) { 5128 var options = (dir ? this.importOptions() : null) || {}; 5129 5130 if ((path = this.entities.quoted() || this.entities.url())) { 5131 features = this.mediaFeatures(); 5132 5133 if (!parserInput.$char(';')) { 5134 parserInput.i = index; 5135 error('missing semi-colon or unrecognised media features on import'); 5136 } 5137 features = features && new(tree.Value)(features); 5138 return new(tree.Import)(path, features, options, index, fileInfo); 5139 } 5140 else { 5141 parserInput.i = index; 5142 error('malformed import statement'); 5143 } 5144 } 5145 }, 5146 5147 importOptions: function() { 5148 var o, options = {}, optionName, value; 5149 5150 // list of options, surrounded by parens 5151 if (!parserInput.$char('(')) { return null; } 5152 do { 5153 o = this.importOption(); 5154 if (o) { 5155 optionName = o; 5156 value = true; 5157 switch (optionName) { 5158 case 'css': 5159 optionName = 'less'; 5160 value = false;
5161 break; 5162 case 'once': 5163 optionName = 'multiple'; 5164 value = false; 5165 break; 5166 } 5167 options[optionName] = value; 5168 if (!parserInput.$char(',')) { break; } 5169 } 5170 } while (o); 5171 expectChar(')'); 5172 return options; 5173 }, 5174 5175 importOption: function() { 5176 var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/); 5177 if (opt) { 5178 return opt[1]; 5179 } 5180 }, 5181 5182 mediaFeature: function () { 5183 var entities = this.entities, nodes = [], e, p; 5184 parserInput.save(); 5185 do { 5186 e = entities.keyword() || entities.variable(); 5187 if (e) { 5188 nodes.push(e); 5189 } else if (parserInput.$char('(')) { 5190 p = this.property(); 5191 e = this.value(); 5192 if (parserInput.$char(')')) { 5193 if (p && e) { 5194 nodes.push(new(tree.Paren)(new(tree.Declaration)(p, e, null, null, parserInput.i, fileInfo, true))); 5195 } else if (e) { 5196 nodes.push(new(tree.Paren)(e)); 5197 } else { 5198 error('badly formed media feature definition'); 5199 } 5200 } else { 5201 error('Missing closing \')\'', 'Parse'); 5202 } 5203 } 5204 } while (e); 5205 5206 parserInput.forget(); 5207 if (nodes.length > 0) { 5208 return new(tree.Expression)(nodes); 5209 } 5210 }, 5211 5212 mediaFeatures: function () { 5213 var entities = this.entities, features = [], e; 5214 do { 5215 e = this.mediaFeature(); 5216 if (e) { 5217 features.push(e); 5218 if (!parserInput.$char(',')) { break; } 5219 } else { 5220 e = entities.variable(); 5221 if (e) { 5222 features.push(e); 5223 if (!parserInput.$char(',')) { break; } 5224 } 5225 } 5226 } while (e); 5227 5228 return features.length > 0 ? features : null; 5229 }, 5230 5231 media: function () { 5232 var features, rules, media, debugInfo, index = parserInput.i; 5233 5234 if (context.dumpLineNumbers) { 5235 debugInfo = getDebugInfo(index); 5236 } 5237 5238 parserInput.save(); 5239 5240 if (parserInput.$str('@media')) { 5241 features = this.mediaFeatures(); 5242 5243 rules = this.block(); 5244 5245 if (!rules) { 5246 error('media definitions require block statements after any features'); 5247 } 5248 5249 parserInput.forget(); 5250 5251 media = new(tree.Media)(rules, features, index, fileInfo); 5252 if (context.dumpLineNumbers) { 5253 media.debugInfo = debugInfo; 5254 } 5255 5256 return media; 5257 } 5258 5259 parserInput.restore(); 5260 }, 5261 5262 // 5263 5264 // A @plugin directive, used to import plugins dynamically. 5265 // 5266 // @plugin (args) "lib"; 5267 // 5268 plugin: function () { 5269 var path, args, options, 5270 index = parserInput.i, 5271 dir = parserInput.$re(/^@plugin?\s+/); 5272 5273 if (dir) { 5274 args = this.pluginArgs(); 5275 5276 if (args) { 5277 options = { 5278 pluginArgs: args, 5279 isPlugin: true 5280 }; 5281 } 5282 else { 5283 options = { isPlugin: true }; 5284 } 5285 5286 if ((path = this.entities.quoted() || this.entities.url())) { 5287 5288 if (!parserInput.$char(';')) { 5289 parserInput.i = index; 5290 error('missing semi-colon on @plugin'); 5291 } 5292 return new(tree.Import)(path, null, options, index, fileInfo); 5293 } 5294 else { 5295 parserInput.i = index; 5296 error('malformed @plugin statement'); 5297 } 5298 } 5299 }, 5300 5301 pluginArgs: function() { 5302 // list of options, surrounded by parens 5303 parserInput.save(); 5304 if (!parserInput.$char('(')) {
5305 parserInput.restore(); 5306 return null; 5307 } 5308 var args = parserInput.$re(/^\s*([^\);]+)\)\s*/); 5309 if (args[1]) { 5310 parserInput.forget(); 5311 return args[1].trim(); 5312 } 5313 else { 5314 parserInput.restore(); 5315 return null; 5316 } 5317 }, 5318 5319 // 5320 // A CSS AtRule 5321 // 5322 // @charset "utf-8"; 5323 // 5324 atrule: function () { 5325 var index = parserInput.i, name, value, rules, nonVendorSpecificName, 5326 hasIdentifier, hasExpression, hasUnknown, hasBlock = true, isRooted = true; 5327 5328 if (parserInput.currentChar() !== '@') { return; } 5329 5330 value = this['import']() || this.plugin() || this.media(); 5331 if (value) { 5332 return value; 5333 } 5334 5335 parserInput.save(); 5336 5337 name = parserInput.$re(/^@[a-z-]+/); 5338 5339 if (!name) { return; } 5340 5341 nonVendorSpecificName = name; 5342 if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { 5343 nonVendorSpecificName = '@' + name.slice(name.indexOf('-', 2) + 1); 5344 } 5345 5346 switch (nonVendorSpecificName) { 5347 case '@charset': 5348 hasIdentifier = true; 5349 hasBlock = false; 5350 break; 5351 case '@namespace': 5352 hasExpression = true; 5353 hasBlock = false; 5354 break; 5355 case '@keyframes': 5356 case '@counter-style': 5357 hasIdentifier = true; 5358 break; 5359 case '@document': 5360 case '@supports': 5361 hasUnknown = true; 5362 isRooted = false; 5363 break; 5364 default: 5365 hasUnknown = true; 5366 break; 5367 } 5368 5369 parserInput.commentStore.length = 0; 5370 5371 if (hasIdentifier) { 5372 value = this.entity(); 5373 if (!value) { 5374 error('expected ' + name + ' identifier'); 5375 } 5376 } else if (hasExpression) { 5377 value = this.expression(); 5378 if (!value) { 5379 error('expected ' + name + ' expression'); 5380 } 5381 } else if (hasUnknown) { 5382 value = this.permissiveValue(/^[{;]/); 5383 hasBlock = (parserInput.currentChar() === '{'); 5384 if (!value) { 5385 if (!hasBlock && parserInput.currentChar() !== ';') { 5386 error(name + ' rule is missing block or ending semi-colon'); 5387 } 5388 } 5389 else if (!value.value) { 5390 value = null; 5391 } 5392 } 5393 5394 if (hasBlock) { 5395 rules = this.blockRuleset(); 5396 } 5397 5398 if (rules || (!hasBlock && value && parserInput.$char(';'))) { 5399 parserInput.forget(); 5400 return new (tree.AtRule)(name, value, rules, index, fileInfo, 5401 context.dumpLineNumbers ? getDebugInfo(index) : null, 5402 isRooted 5403 ); 5404 } 5405 5406 parserInput.restore('at-rule options not recognised'); 5407 }, 5408 5409 // 5410 // A Value is a comma-delimited list of Expressions 5411 // 5412 // font-family: Baskerville, Georgia, serif; 5413 // 5414 // In a Rule, a Value represents everything after the `:`, 5415 // and before the `;`. 5416 // 5417 value: function () { 5418 var e, expressions = [], index = parserInput.i; 5419 5420 do { 5421 e = this.expression(); 5422 if (e) { 5423 expressions.push(e); 5424 if (!parserInput.$char(',')) { break; } 5425 } 5426 } while (e); 5427 5428 if (expressions.length > 0) { 5429 return new(tree.Value)(expressions, index); 5430 } 5431 }, 5432 important: function () { 5433 if (parserInput.currentChar() === '!') { 5434 return parserInput.$re(/^! *important/); 5435 } 5436 }, 5437 sub: function () { 5438 var a, e; 5439 5440 parserInput.save(); 5441 if (parserInput.$char('(')) { 5442 a = this.addition(); 5443 if (a && parserInput.$char(')')) { 5444 parserInput.forget(); 5445 e = new(tree.Expression)([a]); 5446 e.parens = true; 5447 return e; 5448 } 5449 parserInput.restore('Expected \')\''); 5450 return; 5451 }
5452 parserInput.restore(); 5453 }, 5454 multiplication: function () { 5455 var m, a, op, operation, isSpaced; 5456 m = this.operand(); 5457 if (m) { 5458 isSpaced = parserInput.isWhitespace(-1); 5459 while (true) { 5460 if (parserInput.peek(/^\/[*\/]/)) { 5461 break; 5462 } 5463 5464 parserInput.save(); 5465 5466 op = parserInput.$char('/') || parserInput.$char('*'); 5467 5468 if (!op) { parserInput.forget(); break; } 5469 5470 a = this.operand(); 5471 5472 if (!a) { parserInput.restore(); break; } 5473 parserInput.forget(); 5474 5475 m.parensInOp = true; 5476 a.parensInOp = true; 5477 operation = new(tree.Operation)(op, [operation || m, a], isSpaced); 5478 isSpaced = parserInput.isWhitespace(-1); 5479 } 5480 return operation || m; 5481 } 5482 }, 5483 addition: function () { 5484 var m, a, op, operation, isSpaced; 5485 m = this.multiplication(); 5486 if (m) { 5487 isSpaced = parserInput.isWhitespace(-1); 5488 while (true) { 5489 op = parserInput.$re(/^[-+]\s+/) || (!isSpaced && (parserInput.$char('+') || parserInput.$char('-'))); 5490 if (!op) { 5491 break; 5492 } 5493 a = this.multiplication(); 5494 if (!a) { 5495 break; 5496 } 5497 5498 m.parensInOp = true; 5499 a.parensInOp = true; 5500 operation = new(tree.Operation)(op, [operation || m, a], isSpaced); 5501 isSpaced = parserInput.isWhitespace(-1); 5502 } 5503 return operation || m; 5504 } 5505 }, 5506 conditions: function () { 5507 var a, b, index = parserInput.i, condition; 5508 5509 a = this.condition(); 5510 if (a) { 5511 while (true) { 5512 if (!parserInput.peek(/^,\s*(not\s*)?\(/) || !parserInput.$char(',')) { 5513 break; 5514 } 5515 b = this.condition(); 5516 if (!b) { 5517 break; 5518 } 5519 condition = new(tree.Condition)('or', condition || a, b, index); 5520 } 5521 return condition || a; 5522 } 5523 }, 5524 condition: function () { 5525 var result, logical, next; 5526 function or() { 5527 return parserInput.$str('or'); 5528 } 5529 5530 result = this.conditionAnd(this); 5531 if (!result) { 5532 return ; 5533 } 5534 logical = or(); 5535 if (logical) { 5536 next = this.condition(); 5537 if (next) { 5538 result = new(tree.Condition)(logical, result, next); 5539 } else { 5540 return ; 5541 } 5542 } 5543 return result; 5544 }, 5545 conditionAnd: function () { 5546 var result, logical, next; 5547 function insideCondition(me) { 5548 return me.negatedCondition() || me.parenthesisCondition(); 5549 } 5550 function and() { 5551 return parserInput.$str('and'); 5552 } 5553 5554 result = insideCondition(this); 5555 if (!result) { 5556 return ; 5557 } 5558 logical = and(); 5559 if (logical) { 5560 next = this.conditionAnd(); 5561 if (next) { 5562 result = new(tree.Condition)(logical, result, next); 5563 } else { 5564 return ; 5565 } 5566 } 5567 return result; 5568 }, 5569 negatedCondition: function () { 5570 if (parserInput.$str('not')) { 5571 var result = this.parenthesisCondition(); 5572 if (result) { 5573 result.negate = !result.negate; 5574 } 5575 return result; 5576 } 5577 }, 5578 parenthesisCondition: function () { 5579 function tryConditionFollowedByParenthesis(me) { 5580 var body; 5581 parserInput.save(); 5582 body = me.condition(); 5583 if (!body) {
5584 parserInput.restore(); 5585 return ; 5586 } 5587 if (!parserInput.$char(')')) { 5588 parserInput.restore(); 5589 return ; 5590 } 5591 parserInput.forget(); 5592 return body; 5593 } 5594 5595 var body; 5596 parserInput.save(); 5597 if (!parserInput.$str('(')) { 5598 parserInput.restore(); 5599 return ; 5600 } 5601 body = tryConditionFollowedByParenthesis(this); 5602 if (body) { 5603 parserInput.forget(); 5604 return body; 5605 } 5606 5607 body = this.atomicCondition(); 5608 if (!body) { 5609 parserInput.restore(); 5610 return ; 5611 } 5612 if (!parserInput.$char(')')) { 5613 parserInput.restore('expected \')\' got \'' + parserInput.currentChar() + '\''); 5614 return ; 5615 } 5616 parserInput.forget(); 5617 return body; 5618 }, 5619 atomicCondition: function () { 5620 var entities = this.entities, index = parserInput.i, a, b, c, op; 5621 5622 a = this.addition() || entities.keyword() || entities.quoted(); 5623 if (a) { 5624 if (parserInput.$char('>')) { 5625 if (parserInput.$char('=')) { 5626 op = '>='; 5627 } else { 5628 op = '>'; 5629 } 5630 } else 5631 if (parserInput.$char('<')) { 5632 if (parserInput.$char('=')) { 5633 op = '<='; 5634 } else { 5635 op = '<'; 5636 } 5637 } else 5638 if (parserInput.$char('=')) { 5639 if (parserInput.$char('>')) { 5640 op = '=>'; 5641 } else if (parserInput.$char('<')) { 5642 op = '=<'; 5643 } else { 5644 op = '='; 5645 } 5646 } 5647 if (op) { 5648 b = this.addition() || entities.keyword() || entities.quoted(); 5649 if (b) { 5650 c = new(tree.Condition)(op, a, b, index, false); 5651 } else { 5652 error('expected expression'); 5653 } 5654 } else { 5655 c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, false); 5656 } 5657 return c; 5658 } 5659 }, 5660 5661 // 5662 // An operand is anything that can be part of an operation, 5663 // such as a Color, or a Variable 5664 // 5665 operand: function () { 5666 var entities = this.entities, negate; 5667 5668 if (parserInput.peek(/^-[@\$\(]/)) { 5669 negate = parserInput.$char('-'); 5670 } 5671 5672 var o = this.sub() || entities.dimension() || 5673 entities.color() || entities.variable() || 5674 entities.property() || entities.call() || 5675 entities.colorKeyword(); 5676 5677 if (negate) { 5678 o.parensInOp = true; 5679 o = new(tree.Negative)(o); 5680 } 5681 5682 return o; 5683 }, 5684 5685 // 5686 // Expressions either represent mathematical operations, 5687 // or white-space delimited Entities. 5688 // 5689 // 1px solid black 5690 // @var * 2 5691 // 5692 expression: function () { 5693 var entities = [], e, delim, index = parserInput.i; 5694 5695 do { 5696 e = this.comment(); 5697 if (e) { 5698 entities.push(e); 5699 continue; 5700 } 5701 e = this.addition() || this.entity(); 5702 if (e) { 5703 entities.push(e); 5704 // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here 5705 if (!parserInput.peek(/^\/[\/*]/)) { 5706 delim = parserInput.$char('/'); 5707 if (delim) { 5708 entities.push(new(tree.Anonymous)(delim, index)); 5709 } 5710 } 5711 } 5712 } while (e); 5713 if (entities.length > 0) { 5714 return new(tree.Expression)(entities); 5715 } 5716 }, 5717 property: function () { 5718 var name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/); 5719 if (name) { 5720 return name[1]; 5721 } 5722 }, 5723 ruleProperty: function () { 5724 var name = [], index = [], s, k; 5725 5726 parserInput.save(); 5727 5728 var simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/); 5729 if (simpleProperty) { 5730 name = [new(tree.Keyword)(simpleProperty[1])]; 5731 parserInput.forget(); 5732 return name; 5733 } 5734 5735 function match(re) { 5736 var i = parserInput.i, 5737 chunk = parserInput.$re(re); 5738 if (chunk) { 5739 index.push(i); 5740 return name.push(chunk[1]); 5741 } 5742 } 5743 5744 match(/^(\*?)/); 5745 while (true) { 5746 if (!match(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/)) { 5747 break; 5748 } 5749 } 5750 5751 if ((name.length > 1) && match(/^((?:\+_|\+)?)\s*:/)) { 5752 parserInput.forget(); 5753 5754 // at last, we have the complete match now. move forward, 5755 // convert name particles to tree objects and return: 5756 if (name[0] === '') { 5757 name.shift(); 5758 index.shift(); 5759 } 5760 for (k = 0; k < name.length; k++) { 5761 s = name[k]; 5762 name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ? 5763 new(tree.Keyword)(s) : 5764 (s.charAt(0) === '@' ? 5765 new(tree.Variable)('@' + s.slice(2, -1), index[k], fileInfo) : 5766 new(tree.Property)('$' + s.slice(2, -1), index[k], fileInfo)); 5767 } 5768 return name; 5769 }
5770 parserInput.restore(); 5771 } 5772 } 5773 }; 5774}; 5775Parser.serializeVars = function(vars) { 5776 var s = ''; 5777 5778 for (var name in vars) { 5779 if (Object.hasOwnProperty.call(vars, name)) { 5780 var value = vars[name]; 5781 s += ((name[0] === '@') ? '' : '@') + name + ': ' + value + 5782 ((String(value).slice(-1) === ';') ? '' : ';'); 5783 } 5784 } 5785 5786 return s; 5787}; 5788 5789module.exports = Parser; 5790 5791},{"../functions/function-registry":26,"../less-error":36,"../tree":65,"../utils":86,"../visitors":90,"./parser-input":41}],43:[function(require,module,exports){ 5792/** 5793 * Plugin Manager 5794 */ 5795var PluginManager = function(less) { 5796 this.less = less; 5797 this.visitors = []; 5798 this.preProcessors = []; 5799 this.postProcessors = []; 5800 this.installedPlugins = []; 5801 this.fileManagers = []; 5802 this.iterator = -1; 5803 this.pluginCache = {}; 5804 this.Loader = new less.PluginLoader(less); 5805}; 5806 5807var pm, PluginManagerFactory = function(less, newFactory) { 5808 if (newFactory || !pm) { 5809 pm = new PluginManager(less); 5810 } 5811 return pm; 5812 }; 5813 5814/** 5815 * Adds all the plugins in the array 5816 * @param {Array} plugins 5817 */ 5818PluginManager.prototype.addPlugins = function(plugins) { 5819 if (plugins) { 5820 for (var i = 0; i < plugins.length; i++) { 5821 this.addPlugin(plugins[i]); 5822 } 5823 } 5824}; 5825/** 5826 * 5827 * @param plugin 5828 * @param {String} filename 5829 */ 5830PluginManager.prototype.addPlugin = function(plugin, filename, functionRegistry) { 5831 this.installedPlugins.push(plugin); 5832 if (filename) { 5833 this.pluginCache[filename] = plugin; 5834 } 5835 if (plugin.install) { 5836 plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry); 5837 } 5838}; 5839/** 5840 * 5841 * @param filename 5842 */ 5843PluginManager.prototype.get = function(filename) { 5844 return this.pluginCache[filename]; 5845}; 5846 5847/** 5848 * Adds a visitor. The visitor object has options on itself to determine 5849 * when it should run. 5850 * @param visitor 5851 */ 5852PluginManager.prototype.addVisitor = function(visitor) { 5853 this.visitors.push(visitor); 5854}; 5855/** 5856 * Adds a pre processor object 5857 * @param {object} preProcessor 5858 * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import 5859 */ 5860PluginManager.prototype.addPreProcessor = function(preProcessor, priority) { 5861 var indexToInsertAt; 5862 for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) { 5863 if (this.preProcessors[indexToInsertAt].priority >= priority) { 5864 break; 5865 } 5866 } 5867 this.preProcessors.splice(indexToInsertAt, 0, {preProcessor: preProcessor, priority: priority}); 5868}; 5869/** 5870 * Adds a post processor object 5871 * @param {object} postProcessor 5872 * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression 5873 */ 5874PluginManager.prototype.addPostProcessor = function(postProcessor, priority) { 5875 var indexToInsertAt; 5876 for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) { 5877 if (this.postProcessors[indexToInsertAt].priority >= priority) { 5878 break; 5879 } 5880 } 5881 this.postProcessors.splice(indexToInsertAt, 0, {postProcessor: postProcessor, priority: priority}); 5882}; 5883/** 5884 * 5885 * @param manager 5886 */ 5887PluginManager.prototype.addFileManager = function(manager) { 5888 this.fileManagers.push(manager); 5889}; 5890/** 5891 * 5892 * @returns {Array} 5893 * @private 5894 */ 5895PluginManager.prototype.getPreProcessors = function() { 5896 var preProcessors = []; 5897 for (var i = 0; i < this.preProcessors.length; i++) { 5898 preProcessors.push(this.preProcessors[i].preProcessor); 5899 } 5900 return preProcessors; 5901}; 5902/** 5903 * 5904 * @returns {Array} 5905 * @private 5906 */ 5907PluginManager.prototype.getPostProcessors = function() { 5908 var postProcessors = []; 5909 for (var i = 0; i < this.postProcessors.length; i++) { 5910 postProcessors.push(this.postProcessors[i].postProcessor); 5911 } 5912 return postProcessors; 5913}; 5914/** 5915 * 5916 * @returns {Array} 5917 * @private 5918 */ 5919PluginManager.prototype.getVisitors = function() { 5920 return this.visitors; 5921}; 5922 5923PluginManager.prototype.visitor = function() { 5924 var self = this; 5925 return { 5926 first: function() { 5927 self.iterator = -1; 5928 return self.visitors[self.iterator]; 5929 }, 5930 get: function() { 5931 self.iterator += 1; 5932 return self.visitors[self.iterator]; 5933 } 5934 }; 5935}; 5936/** 5937 * 5938 * @returns {Array} 5939 * @private 5940 */ 5941PluginManager.prototype.getFileManagers = function() { 5942 return this.fileManagers; 5943}; 5944 5945// 5946module.exports = PluginManagerFactory; 5947 5948},{}],44:[function(require,module,exports){ 5949var PromiseConstructor, 5950 utils = require('./utils'); 5951 5952module.exports = function(environment, ParseTree, ImportManager) { 5953 var render = function (input, options, callback) { 5954 if (typeof options === 'function') { 5955 callback = options; 5956 options = utils.defaults(this.options, {}); 5957 } 5958 else { 5959 options = utils.defaults(this.options, options || {}); 5960 } 5961 5962 if (!callback) { 5963 if (!PromiseConstructor) { 5964 PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise; 5965 } 5966 var self = this; 5967 return new PromiseConstructor(function (resolve, reject) { 5968 render.call(self, input, options, function(err, output) { 5969 if (err) { 5970 reject(err); 5971 } else { 5972 resolve(output); 5973 } 5974 }); 5975 }); 5976 } else { 5977 this.parse(input, options, function(err, root, imports, options) { 5978 if (err) { return callback(err); } 5979 5980 var result; 5981 try { 5982 var parseTree = new ParseTree(root, imports); 5983 result = parseTree.toCSS(options); 5984 } 5985 catch (err) { return callback(err); } 5986 5987 callback(null, result); 5988 }); 5989 } 5990 }; 5991 5992 return render; 5993}; 5994 5995},{"./utils":86,"promise":undefined}],45:[function(require,module,exports){ 5996module.exports = function (SourceMapOutput, environment) { 5997 5998 var SourceMapBuilder = function (options) { 5999 this.options = options; 6000 }; 6001 6002 SourceMapBuilder.prototype.toCSS = function(rootNode, options, imports) { 6003 var sourceMapOutput = new SourceMapOutput( 6004 { 6005 contentsIgnoredCharsMap: imports.contentsIgnoredChars, 6006 rootNode: rootNode, 6007 contentsMap: imports.contents, 6008 sourceMapFilename: this.options.sourceMapFilename, 6009 sourceMapURL: this.options.sourceMapURL, 6010 outputFilename: this.options.sourceMapOutputFilename, 6011 sourceMapBasepath: this.options.sourceMapBasepath, 6012 sourceMapRootpath: this.options.sourceMapRootpath, 6013 outputSourceFiles: this.options.outputSourceFiles, 6014 sourceMapGenerator: this.options.sourceMapGenerator, 6015 sourceMapFileInline: this.options.sourceMapFileInline 6016 }); 6017 6018 var css = sourceMapOutput.toCSS(options); 6019 this.sourceMap = sourceMapOutput.sourceMap; 6020 this.sourceMapURL = sourceMapOutput.sourceMapURL; 6021 if (this.options.sourceMapInputFilename) { 6022 this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename); 6023 } 6024 if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) { 6025 this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL); 6026 } 6027 return css + this.getCSSAppendage(); 6028 }; 6029 6030 SourceMapBuilder.prototype.getCSSAppendage = function() { 6031 6032 var sourceMapURL = this.sourceMapURL; 6033 if (this.options.sourceMapFileInline) { 6034 if (this.sourceMap === undefined) { 6035 return ''; 6036 } 6037 sourceMapURL = 'data:application/json;base64,' + environment.encodeBase64(this.sourceMap); 6038 } 6039 6040 if (sourceMapURL) { 6041 return '/*# sourceMappingURL=' + sourceMapURL + ' */'; 6042 } 6043 return ''; 6044 }; 6045 6046 SourceMapBuilder.prototype.getExternalSourceMap = function() { 6047 return this.sourceMap; 6048 }; 6049 SourceMapBuilder.prototype.setExternalSourceMap = function(sourceMap) { 6050 this.sourceMap = sourceMap; 6051 }; 6052 6053 SourceMapBuilder.prototype.isInline = function() { 6054 return this.options.sourceMapFileInline; 6055 }; 6056 SourceMapBuilder.prototype.getSourceMapURL = function() { 6057 return this.sourceMapURL; 6058 }; 6059 SourceMapBuilder.prototype.getOutputFilename = function() { 6060 return this.options.sourceMapOutputFilename; 6061 }; 6062 SourceMapBuilder.prototype.getInputFilename = function() { 6063 return this.sourceMapInputFilename; 6064 }; 6065 6066 return SourceMapBuilder; 6067}; 6068 6069},{}],46:[function(require,module,exports){ 6070module.exports = function (environment) { 6071 6072 var SourceMapOutput = function (options) { 6073 this._css = []; 6074 this._rootNode = options.rootNode; 6075 this._contentsMap = options.contentsMap; 6076 this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap; 6077 if (options.sourceMapFilename) { 6078 this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/'); 6079 } 6080 this._outputFilename = options.outputFilename; 6081 this.sourceMapURL = options.sourceMapURL; 6082 if (options.sourceMapBasepath) { 6083 this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/'); 6084 } 6085 if (options.sourceMapRootpath) { 6086 this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/'); 6087 if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') { 6088 this._sourceMapRootpath += '/'; 6089 } 6090 } else { 6091 this._sourceMapRootpath = ''; 6092 } 6093 this._outputSourceFiles = options.outputSourceFiles; 6094 this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator(); 6095 6096 this._lineNumber = 0; 6097 this._column = 0; 6098 }; 6099 6100 SourceMapOutput.prototype.removeBasepath = function(path) { 6101 if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) { 6102 path = path.substring(this._sourceMapBasepath.length);
6103 if (path.charAt(0) === '\\' || path.charAt(0) === '/') { 6104 path = path.substring(1); 6105 } 6106 } 6107 6108 return path; 6109 }; 6110 6111 SourceMapOutput.prototype.normalizeFilename = function(filename) { 6112 filename = filename.replace(/\\/g, '/'); 6113 filename = this.removeBasepath(filename); 6114 return (this._sourceMapRootpath || '') + filename; 6115 }; 6116 6117 SourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) { 6118 6119 // ignore adding empty strings 6120 if (!chunk) { 6121 return; 6122 } 6123 6124 var lines, 6125 sourceLines, 6126 columns, 6127 sourceColumns, 6128 i; 6129 6130 if (fileInfo) { 6131 var inputSource = this._contentsMap[fileInfo.filename]; 6132 6133 // remove vars/banner added to the top of the file 6134 if (this._contentsIgnoredCharsMap[fileInfo.filename]) { 6135 // adjust the index 6136 index -= this._contentsIgnoredCharsMap[fileInfo.filename]; 6137 if (index < 0) { index = 0; } 6138 // adjust the source 6139 inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]); 6140 } 6141 inputSource = inputSource.substring(0, index); 6142 sourceLines = inputSource.split('\n'); 6143 sourceColumns = sourceLines[sourceLines.length - 1]; 6144 } 6145 6146 lines = chunk.split('\n'); 6147 columns = lines[lines.length - 1]; 6148 6149 if (fileInfo) { 6150 if (!mapLines) { 6151 this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column}, 6152 original: { line: sourceLines.length, column: sourceColumns.length}, 6153 source: this.normalizeFilename(fileInfo.filename)}); 6154 } else { 6155 for (i = 0; i < lines.length; i++) { 6156 this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0}, 6157 original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0}, 6158 source: this.normalizeFilename(fileInfo.filename)}); 6159 } 6160 } 6161 } 6162 6163 if (lines.length === 1) { 6164 this._column += columns.length; 6165 } else { 6166 this._lineNumber += lines.length - 1; 6167 this._column = columns.length; 6168 } 6169 6170 this._css.push(chunk); 6171 }; 6172 6173 SourceMapOutput.prototype.isEmpty = function() { 6174 return this._css.length === 0; 6175 }; 6176 6177 SourceMapOutput.prototype.toCSS = function(context) { 6178 this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null }); 6179 6180 if (this._outputSourceFiles) { 6181 for (var filename in this._contentsMap) { 6182 if (this._contentsMap.hasOwnProperty(filename)) { 6183 var source = this._contentsMap[filename]; 6184 if (this._contentsIgnoredCharsMap[filename]) { 6185 source = source.slice(this._contentsIgnoredCharsMap[filename]); 6186 } 6187 this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source); 6188 } 6189 } 6190 } 6191 6192 this._rootNode.genCSS(context, this); 6193 6194 if (this._css.length > 0) { 6195 var sourceMapURL, 6196 sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON()); 6197 6198 if (this.sourceMapURL) { 6199 sourceMapURL = this.sourceMapURL; 6200 } else if (this._sourceMapFilename) { 6201 sourceMapURL = this._sourceMapFilename; 6202 } 6203 this.sourceMapURL = sourceMapURL; 6204 6205 this.sourceMap = sourceMapContent; 6206 } 6207 6208 return this._css.join(''); 6209 }; 6210 6211 return SourceMapOutput; 6212}; 6213 6214},{}],47:[function(require,module,exports){ 6215var contexts = require('./contexts'), 6216 visitor = require('./visitors'), 6217 tree = require('./tree'); 6218 6219module.exports = function(root, options) { 6220 options = options || {}; 6221 var evaldRoot, 6222 variables = options.variables, 6223 evalEnv = new contexts.Eval(options); 6224 6225 // 6226 // Allows setting variables with a hash, so: 6227 // 6228 // `{ color: new tree.Color('#f01') }` will become: 6229 // 6230 // new tree.Declaration('@color', 6231 // new tree.Value([ 6232 // new tree.Expression([ 6233 // new tree.Color('#f01') 6234 // ]) 6235 // ]) 6236 // ) 6237 // 6238 if (typeof variables === 'object' && !Array.isArray(variables)) { 6239 variables = Object.keys(variables).map(function (k) { 6240 var value = variables[k]; 6241 6242 if (!(value instanceof tree.Value)) { 6243 if (!(value instanceof tree.Expression)) { 6244 value = new tree.Expression([value]); 6245 } 6246 value = new tree.Value([value]); 6247 } 6248 return new tree.Declaration('@' + k, value, false, null, 0); 6249 }); 6250 evalEnv.frames = [new tree.Ruleset(null, variables)]; 6251 } 6252 6253 var visitors = [ 6254 new visitor.JoinSelectorVisitor(), 6255 new visitor.MarkVisibleSelectorsVisitor(true), 6256 new visitor.ExtendVisitor(), 6257 new visitor.ToCSSVisitor({compress: Boolean(options.compress)}) 6258 ], v, visitorIterator; 6259 6260 // first() / get() allows visitors to be added while visiting 6261 if (options.pluginManager) { 6262 visitorIterator = options.pluginManager.visitor(); 6263 visitorIterator.first(); 6264 while ((v = visitorIterator.get())) { 6265 if (v.isPreEvalVisitor) { 6266 v.run(root); 6267 } 6268 } 6269 } 6270 6271 evaldRoot = root.eval(evalEnv); 6272 6273 for (var i = 0; i < visitors.length; i++) { 6274 visitors[i].run(evaldRoot); 6275 } 6276 6277 if (options.pluginManager) { 6278 visitorIterator.first(); 6279 while ((v = visitorIterator.get())) { 6280 if (!v.isPreEvalVisitor) { 6281 v.run(evaldRoot); 6282 } 6283 } 6284 } 6285 6286 return evaldRoot; 6287}; 6288 6289},{"./contexts":12,"./tree":65,"./visitors":90}],48:[function(require,module,exports){ 6290var Node = require('./node'); 6291 6292var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) { 6293 this.value = value; 6294 this._index = index; 6295 this._fileInfo = currentFileInfo; 6296 this.mapLines = mapLines; 6297 this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : ruleset
6297Like; 6298 this.allowRoot = true; 6299 this.copyVisibilityInfo(visibilityInfo); 6300}; 6301Anonymous.prototype = new Node(); 6302Anonymous.prototype.type = 'Anonymous'; 6303Anonymous.prototype.eval = function () { 6304 return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo()); 6305}; 6306Anonymous.prototype.compare = function (other) { 6307 return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; 6308}; 6309Anonymous.prototype.isRulesetLike = function() { 6310 return this.rulesetLike; 6311}; 6312Anonymous.prototype.genCSS = function (context, output) { 6313 this.nodeVisible = Boolean(this.value); 6314 if (this.nodeVisible) { 6315 output.add(this.value, this._fileInfo, this._index, this.mapLines); 6316 } 6317}; 6318module.exports = Anonymous; 6319 6320},{"./node":73}],49:[function(require,module,exports){ 6321var Node = require('./node'); 6322 6323var Assignment = function (key, val) { 6324 this.key = key; 6325 this.value = val; 6326}; 6327 6328Assignment.prototype = new Node(); 6329Assignment.prototype.type = 'Assignment'; 6330Assignment.prototype.accept = function (visitor) { 6331 this.value = visitor.visit(this.value); 6332}; 6333Assignment.prototype.eval = function (context) { 6334 if (this.value.eval) { 6335 return new Assignment(this.key, this.value.eval(context)); 6336 } 6337 return this; 6338}; 6339Assignment.prototype.genCSS = function (context, output) { 6340 output.add(this.key + '='); 6341 if (this.value.genCSS) { 6342 this.value.genCSS(context, output); 6343 } else { 6344 output.add(this.value); 6345 } 6346}; 6347module.exports = Assignment; 6348 6349},{"./node":73}],50:[function(require,module,exports){ 6350var Node = require('./node'), 6351 Selector = require('./selector'), 6352 Ruleset = require('./ruleset'), 6353 Anonymous = require('./anonymous'); 6354 6355var AtRule = function (name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) { 6356 var i; 6357 6358 this.name = name; 6359 this.value = (value instanceof Node) ? value : (value ? new Anonymous(value) : value); 6360 if (rules) { 6361 if (Array.isArray(rules)) { 6362 this.rules = rules; 6363 } else { 6364 this.rules = [rules]; 6365 this.rules[0].selectors = (new Selector([], null, null, index, currentFileInfo)).createEmptySelectors(); 6366 } 6367 for (i = 0; i < this.rules.length; i++) { 6368 this.rules[i].allowImports = true; 6369 } 6370 this.setParent(this.rules, this); 6371 } 6372 this._index = index; 6373 this._fileInfo = currentFileInfo; 6374 this.debugInfo = debugInfo; 6375 this.isRooted = isRooted || false; 6376 this.copyVisibilityInfo(visibilityInfo); 6377 this.allowRoot = true; 6378}; 6379 6380AtRule.prototype = new Node(); 6381AtRule.prototype.type = 'AtRule'; 6382AtRule.prototype.accept = function (visitor) { 6383 var value = this.value, rules = this.rules; 6384 if (rules) { 6385 this.rules = visitor.visitArray(rules); 6386 } 6387 if (value) { 6388 this.value = visitor.visit(value); 6389 } 6390}; 6391AtRule.prototype.isRulesetLike = function() { 6392 return this.rules || !this.isCharset(); 6393}; 6394AtRule.prototype.isCharset = function() { 6395 return '@charset' === this.name; 6396}; 6397AtRule.prototype.genCSS = function (context, output) { 6398 var value = this.value, rules = this.rules; 6399 output.add(this.name, this.fileInfo(), this.getIndex()); 6400 if (value) { 6401 output.add(' '); 6402 value.genCSS(context, output); 6403 } 6404 if (rules) { 6405 this.outputRuleset(context, output, rules); 6406 } else { 6407 output.add(';'); 6408 } 6409}; 6410AtRule.prototype.eval = function (context) { 6411 var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules; 6412 6413 // media stored inside other atrule should not bubble over it 6414 // backpup media bubbling information 6415 mediaPathBackup = context.mediaPath; 6416 mediaBlocksBackup = context.mediaBlocks; 6417 // deleted media bubbling information 6418 context.mediaPath = []; 6419 context.mediaBlocks = []; 6420 6421 if (value) { 6422 value = value.eval(context); 6423 } 6424 if (rules) { 6425 // assuming that there is only one rule at this point - that is how parser constructs the rule 6426 rules = [rules[0].eval(context)]; 6427 rules[0].root = true; 6428 } 6429 // restore media bubbling information 6430 context.mediaPath = mediaPathBackup; 6431 context.mediaBlocks = mediaBlocksBackup; 6432 6433 return new AtRule(this.name, value, rules, 6434 this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo()); 6435}; 6436AtRule.prototype.variable = function (name) { 6437 if (this.rules) { 6438 // assuming that there is only one rule at this point - that is how parser constructs the rule 6439 return Ruleset.prototype.variable.call(this.rules[0], name); 6440 } 6441}; 6442AtRule.prototype.find = function () { 6443 if (this.rules) { 6444 // assuming that there is only one rule at this point - that is how parser constructs the rule 6445 return Ruleset.prototype.find.apply(this.rules[0], arguments); 6446 } 6447}; 6448AtRule.prototype.rulesets = function () { 6449 if (this.rules) { 6450 // assuming that there is only one rule at this point - that is how parser constructs the rule 6451 return Ruleset.prototype.rulesets.apply(this.rules[0]); 6452 } 6453}; 6454AtRule.prototype.outputRuleset = function (context, output, rules) { 6455 var ruleCnt = rules.length, i; 6456 context.tabLevel = (context.tabLevel | 0) + 1; 6457 6458 // Compressed 6459 if (context.compress) { 6460 output.add('{'); 6461 for (i = 0; i < ruleCnt; i++) { 6462 rules[i].genCSS(context, output); 6463 } 6464 output.add('}'); 6465 context.tabLevel--; 6466 return; 6467 } 6468 6469 // Non-compressed 6470 var tabSetStr = '\n' + Array(context.tabLevel).join(' '), tabRuleStr = tabSetStr + ' '; 6471 if (!ruleCnt) { 6472 output.add(' {' + tabSetStr + '}'); 6473 } else { 6474 output.add(' {' + tabRuleStr); 6475 rules[0].genCSS(context, output); 6476 for (i = 1; i < ruleCnt; i++) { 6477 output.add(tabRuleStr); 6478 rules[i].genCSS(context, output); 6479 } 6480 output.add(tabSetStr + '}'); 6481 } 6482 6483 context.tabLevel--; 6484}; 6485module.exports = AtRule; 6486 6487},{"./anonymous":48,"./node":73,"./ruleset":78,"./selector":79}],51:[function(require,module,exports){ 6488var Node = require('./node'); 6489 6490var Attribute = function (key, op, value) { 6491 this.key = key; 6492 this.op = op; 6493 this.value = value; 6494}; 6495Attribute.prototype = new Node(); 6496Attribute.prototype.type = 'Attribute'; 6497Attribute.prototype.eval = function (context) { 6498 return new Attribute(this.key.eval ? this.key.eval(context) : this.key, 6499 this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value); 6500}; 6501Attribute.prototype.genCSS = function (context, output) { 6502 output.add(this.toCSS(context)); 6503}; 6504Attribute.prototype.toCSS = function (context) { 6505 var value = this.key.toCSS ? this.key.toCSS(context) : this.key; 6506 6507 if (this.op) { 6508 value += this.op; 6509 value += (this.value.toCSS ? this.value.toCSS(context) : this.value); 6510 } 6511 6512 return '[' + value + ']'; 6513}; 6514module.exports = Attribute; 6515 6516},{"./node":73}],52:[function(require,module,exports){ 6517var Node = require('./node'), 6518 Anonymous = require('./anonymous'), 6519 FunctionCaller = require('../functions/function-caller'); 6520// 6521// A function call node. 6522// 6523var Call = function (name, args, index, currentFileInfo) { 6524 this.name = name; 6525 this.args = args; 6526 this.mathOn = name === 'calc' ? false : true; 6527 this._index = index; 6528 this._fileInfo = currentFileInfo; 6529}; 6530Call.prototype = new Node(); 6531Call.prototype.type = 'Call'; 6532Call.prototype.accept = function (visitor) { 6533 if (this.args) { 6534 this.args = visitor.visitArray(this.args); 6535 } 6536}; 6537// 6538// When evaluating a function call, 6539// we either find the function in the functionRegistry, 6540// in which case we call it, passing the evaluated arguments, 6541// if this returns null or we cannot find the function, we 6542// simply print it out as it appeared originally [2]. 6543// 6544// The reason why we evaluate the arguments, is in the case where 6545// we try to pass a variable to a function, like: `saturate(@color)`. 6546// The function should receive the value, not the variable. 6547// 6548Call.prototype.eval = function (context) { 6549 6550 /** 6551 * Turn off math for calc(), and switch back on for evaluating nested functions 6552 */ 6553 var currentMathContext = context.mathOn; 6554 context.mathOn = this.mathOn; 6555 var args = this.args.map(function (a) { return a.eval(context); }); 6556 context.mathOn = currentMathContext; 6557 6558 var result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo()); 6559 6560 if (funcCaller.isValid()) { 6561 try { 6562 result = funcCaller.call(args); 6563 } catch (e) { 6564 throw { 6565 type: e.type || 'Runtime', 6566 message: 'error evaluating function `' + this.name + '`' + 6567 (e.message ? ': ' + e.message : ''), 6568 index: this.getIndex(), 6569 filename: this.fileInfo().filename, 6570 line: e.lineNumber, 6571 column: e.columnNumber 6572 }; 6573 } 6574 6575 if (result !== null && result !== undefined) { 6576 // Results that that are not nodes are cast as Anonymous nodes 6577 // Falsy values or booleans are returned as empty nodes 6578 if (!(result instanceof Node)) { 6579 if (!result || result === true) { 6580 result = new Anonymous(null); 6581 } 6582 else { 6583 result = new Anonymous(result.toString()); 6584 } 6585 6586 } 6587 result._index = this._index; 6588 result._fileInfo = this._fileInfo; 6589 return result; 6590 } 6591 6592 } 6593 6594 return new Call(this.name, args, this.getIndex(), this.fileInfo()); 6595}; 6596Call.prototype.genCSS = function (context, output) { 6597 output.add(this.name + '(', this.fileInfo(), this.getIndex()); 6598 6599 for (var i = 0; i < this.args.length; i++) { 6600 this.args[i].genCSS(context, output); 6601 if (i + 1 < this.args.length) { 6602 output.add(', '); 6603 } 6604 } 6605 6606 output.add(')'); 6607}; 6608module.exports = Call; 6609 6610},{"../functions/function-caller":25,"./anonymous":48,"./node":73}],53:[function(require,module,exports){ 6611var Node = require('./node'), 6612 colors = require('../data/colors'); 6613 6614// 6615// RGB Colors - #ff0014, #eee 6616// 6617var Color = function (rgb, a, originalForm) { 6618 // 6619 // The end goal here, is to parse the arguments 6620 // into an integer triplet, such as `128, 255, 0` 6621 // 6622 // This facilitates operations and conversions. 6623 // 6624 if (Array.isArray(rgb)) { 6625 this.rgb = rgb; 6626 } else if (rgb.length == 6) { 6627 this.rgb = rgb.match(/.{2}/g).map(function (c) { 6628 return parseInt(c, 16); 6629 }); 6630 } else { 6631 this.rgb = rgb.split('').map(function (c) { 6632 return parseInt(c + c, 16); 6633 }); 6634 } 6635 this.alpha = typeof a === 'number' ? a : 1; 6636 if (typeof originalForm !== 'undefined') { 6637 this.value = originalForm; 6638 } 6639}; 6640 6641Color.prototype = new Node(); 6642Color.prototype.type = 'Color'; 6643 6644function clamp(v, max) { 6645 return Math.min(Math.max(v, 0), max); 6646} 6647 6648function toHex(v) { 6649 return '#' + v.map(function (c) { 6650 c = clamp(Math.round(c), 255); 6651 return (c < 16 ? '0' : '') + c.toString(16); 6652 }).join(''); 6653} 6654 6655Color.prototype.luma = function () {
6656 var r = this.rgb[0] / 255, 6657 g = this.rgb[1] / 255, 6658 b = this.rgb[2] / 255; 6659 6660 r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4); 6661 g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4); 6662 b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4); 6663 6664 return 0.2126 * r + 0.7152 * g + 0.0722 * b; 6665}; 6666Color.prototype.genCSS = function (context, output) { 6667 output.add(this.toCSS(context)); 6668}; 6669Color.prototype.toCSS = function (context, doNotCompress) { 6670 var compress = context && context.compress && !doNotCompress, color, alpha; 6671 6672 // `value` is set if this color was originally 6673 // converted from a named color string so we need 6674 // to respect this and try to output named color too. 6675 if (this.value) { 6676 return this.value; 6677 } 6678 6679 // If we have some transparency, the only way to represent it 6680 // is via `rgba`. Otherwise, we use the hex representation, 6681 // which has better compatibility with older browsers. 6682 // Values are capped between `0` and `255`, rounded and zero-padded.
6683 alpha = this.fround(context, this.alpha); 6684 if (alpha < 1) { 6685 return 'rgba(' + this.rgb.map(function (c) { 6686 return clamp(Math.round(c), 255); 6687 }).concat(clamp(alpha, 1)) 6688 .join(',' + (compress ? '' : ' ')) + ')'; 6689 } 6690 6691 color = this.toRGB(); 6692 6693 if (compress) { 6694 var splitcolor = color.split(''); 6695 6696 // Convert color to short format 6697 if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) { 6698 color = '#' + splitcolor[1] + splitcolor[3] + splitcolor[5]; 6699 } 6700 } 6701 6702 return color; 6703}; 6704 6705// 6706// Operations have to be done per-channel, if not, 6707// channels will spill onto each other. Once we have 6708// our result, in the form of an integer triplet, 6709// we create a new Color node to hold the result. 6710// 6711Color.prototype.operate = function (context, op, other) { 6712 var rgb = new Array(3); 6713 var alpha = this.alpha * (1 - other.alpha) + other.alpha; 6714 for (var c = 0; c < 3; c++) { 6715 rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]); 6716 } 6717 return new Color(rgb, alpha); 6718}; 6719Color.prototype.toRGB = function () { 6720 return toHex(this.rgb); 6721}; 6722Color.prototype.toHSL = function () {
6723 var r = this.rgb[0] / 255, 6724 g = this.rgb[1] / 255, 6725 b = this.rgb[2] / 255, 6726 a = this.alpha; 6727 6728 var max = Math.max(r, g, b), min = Math.min(r, g, b); 6729 var h, s, l = (max + min) / 2, d = max - min; 6730 6731 if (max === min) { 6732 h = s = 0; 6733 } else { 6734 s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 6735 6736 switch (max) { 6737 case r: h = (g - b) / d + (g < b ? 6 : 0); break; 6738 case g: h = (b - r) / d + 2; break; 6739 case b: h = (r - g) / d + 4; break; 6740 } 6741 h /= 6; 6742 } 6743 return { h: h * 360, s: s, l: l, a: a }; 6744}; 6745// Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript 6746Color.prototype.toHSV = function () { 6747 var r = this.rgb[0] / 255, 6748 g = this.rgb[1] / 255, 6749 b = this.rgb[2] / 255, 6750 a = this.alpha; 6751 6752 var max = Math.max(r, g, b), min = Math.min(r, g, b); 6753 var h, s, v = max; 6754 6755 var d = max - min; 6756 if (max === 0) { 6757 s = 0; 6758 } else { 6759 s = d / max; 6760 } 6761 6762 if (max === min) { 6763 h = 0; 6764 } else { 6765 switch (max) { 6766 case r: h = (g - b) / d + (g < b ? 6 : 0); break; 6767 case g: h = (b - r) / d + 2; break; 6768 case b: h = (r - g) / d + 4; break; 6769 } 6770 h /= 6; 6771 } 6772 return { h: h * 360, s: s, v: v, a: a }; 6773}; 6774Color.prototype.toARGB = function () { 6775 return toHex([this.alpha * 255].concat(this.rgb)); 6776}; 6777Color.prototype.compare = function (x) { 6778 return (x.rgb && 6779 x.rgb[0] === this.rgb[0] && 6780 x.rgb[1] === this.rgb[1] && 6781 x.rgb[2] === this.rgb[2] && 6782 x.alpha === this.alpha) ? 0 : undefined; 6783}; 6784 6785Color.fromKeyword = function(keyword) { 6786 var c, key = keyword.toLowerCase(); 6787 if (colors.hasOwnProperty(key)) { 6788 c = new Color(colors[key].slice(1)); 6789 } 6790 else if (key === 'transparent') { 6791 c = new Color([0, 0, 0], 0); 6792 } 6793 6794 if (c) { 6795 c.value = keyword; 6796 return c; 6797 } 6798}; 6799module.exports = Color; 6800 6801},{"../data/colors":13,"./node":73}],54:[function(require,module,exports){ 6802var Node = require('./node'); 6803 6804var Combinator = function (value) { 6805 if (value === ' ') { 6806 this.value = ' '; 6807 this.emptyOrWhitespace = true; 6808 } else { 6809 this.value = value ? value.trim() : ''; 6810 this.emptyOrWhitespace = this.value === ''; 6811 } 6812}; 6813Combinator.prototype = new Node(); 6814Combinator.prototype.type = 'Combinator'; 6815var _noSpaceCombinators = { 6816 '': true, 6817 ' ': true, 6818 '|': true 6819}; 6820Combinator.prototype.genCSS = function (context, output) { 6821 var spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' '; 6822 output.add(spaceOrEmpty + this.value + spaceOrEmpty); 6823}; 6824module.exports = Combinator; 6825 6826},{"./node":73}],55:[function(require,module,exports){ 6827var Node = require('./node'), 6828 getDebugInfo = require('./debug-info'); 6829 6830var Comment = function (value, isLineComment, index, currentFileInfo) { 6831 this.value = value; 6832 this.isLineComment = isLineComment; 6833 this._index = index; 6834 this._fileInfo = currentFileInfo; 6835 this.allowRoot = true; 6836}; 6837Comment.prototype = new Node(); 6838Comment.prototype.type = 'Comment'; 6839Comment.prototype.genCSS = function (context, output) { 6840 if (this.debugInfo) { 6841 output.add(getDebugInfo(context, this), this.fileInfo(), this.getIndex()); 6842 } 6843 output.add(this.value); 6844}; 6845Comment.prototype.isSilent = function(context) { 6846 var isCompressed = context.compress && this.value[2] !== '!'; 6847 return this.isLineComment || isCompressed; 6848}; 6849module.exports = Comment; 6850 6851},{"./debug-info":57,"./node":73}],56:[function(require,module,exports){ 6852var Node = require('./node'); 6853 6854var Condition = function (op, l, r, i, negate) { 6855 this.op = op.trim(); 6856 this.lvalue = l; 6857 this.rvalue = r; 6858 this._index = i; 6859 this.negate = negate; 6860}; 6861Condition.prototype = new Node(); 6862Condition.prototype.type = 'Condition'; 6863Condition.prototype.accept = function (visitor) { 6864 this.lvalue = visitor.visit(this.lvalue); 6865 this.rvalue = visitor.visit(this.rvalue); 6866}; 6867Condition.prototype.eval = function (context) { 6868 var result = (function (op, a, b) { 6869 switch (op) { 6870 case 'and': return a && b; 6871 case 'or': return a || b; 6872 default: 6873 switch (Node.compare(a, b)) { 6874 case -1: 6875 return op === '<' || op === '=<' || op === '<='; 6876 case 0: 6877 return op === '=' || op === '>=' || op === '=<' || op === '<='; 6878 case 1: 6879 return op === '>' || op === '>='; 6880 default: 6881 return false;
6882 } 6883 } 6884 })(this.op, this.lvalue.eval(context), this.rvalue.eval(context)); 6885 6886 return this.negate ? !result : result; 6887}; 6888module.exports = Condition; 6889 6890},{"./node":73}],57:[function(require,module,exports){ 6891var debugInfo = function(context, ctx, lineSeparator) { 6892 var result = ''; 6893 if (context.dumpLineNumbers && !context.compress) { 6894 switch (context.dumpLineNumbers) { 6895 case 'comments': 6896 result = debugInfo.asComment(ctx); 6897 break; 6898 case 'mediaquery': 6899 result = debugInfo.asMediaQuery(ctx); 6900 break; 6901 case 'all': 6902 result = debugInfo.asComment(ctx) + (lineSeparator || '') + debugInfo.asMediaQuery(ctx); 6903 break; 6904 } 6905 } 6906 return result; 6907}; 6908 6909debugInfo.asComment = function(ctx) { 6910 return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; 6911}; 6912 6913debugInfo.asMediaQuery = function(ctx) { 6914 var filenameWithProtocol = ctx.debugInfo.fileName; 6915 if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) { 6916 filenameWithProtocol = 'file://' + filenameWithProtocol; 6917 } 6918 return '@media -sass-debug-info{filename{font-family:' + 6919 filenameWithProtocol.replace(/([.:\/\\])/g, function (a) { 6920 if (a == '\\') { 6921 a = '\/'; 6922 } 6923 return '\\' + a; 6924 }) + 6925 '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; 6926}; 6927 6928module.exports = debugInfo; 6929 6930},{}],58:[function(require,module,exports){ 6931var Node = require('./node'), 6932 Value = require('./value'), 6933 Keyword = require('./keyword'), 6934 Anonymous = require('./anonymous'); 6935 6936var Declaration = function (name, value, important, merge, index, currentFileInfo, inline, variable) { 6937 this.name = name; 6938 this.value = (value instanceof Node) ? value : new Value([value ? new Anonymous(value) : null]); 6939 this.important = important ? ' ' + important.trim() : ''; 6940 this.merge = merge; 6941 this._index = index; 6942 this._fileInfo = currentFileInfo; 6943 this.inline = inline || false; 6944 this.variable = (variable !== undefined) ? variable 6945 : (name.charAt && (name.charAt(0) === '@')); 6946 this.allowRoot = true; 6947 this.setParent(this.value, this); 6948}; 6949 6950function evalName(context, name) { 6951 var value = '', i, n = name.length, 6952 output = {add: function (s) {value += s;}}; 6953 for (i = 0; i < n; i++) { 6954 name[i].eval(context).genCSS(context, output); 6955 } 6956 return value; 6957} 6958 6959Declaration.prototype = new Node(); 6960Declaration.prototype.type = 'Declaration'; 6961Declaration.prototype.genCSS = function (context, output) { 6962 output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex()); 6963 try { 6964 this.value.genCSS(context, output); 6965 } 6966 catch (e) { 6967 e.index = this._index; 6968 e.filename = this._fileInfo.filename; 6969 throw e; 6970 } 6971 output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? '' : ';'), this._fileInfo, this._index); 6972}; 6973Declaration.prototype.eval = function (context) { 6974 var strictMathBypass = false, name = this.name, evaldValue, variable = this.variable; 6975 if (typeof name !== 'string') { 6976 // expand 'primitive' name directly to get 6977 // things faster (~10% for benchmark.less): 6978 name = (name.length === 1) && (name[0] instanceof Keyword) ? 6979 name[0].value : evalName(context, name); 6980 variable = false; // never treat expanded interpolation as new variable name 6981 } 6982 if (name === 'font' && !context.strictMath) { 6983 strictMathBypass = true; 6984 context.strictMath = true; 6985 } 6986 try { 6987 context.importantScope.push({}); 6988 evaldValue = this.value.eval(context); 6989 6990 if (!this.variable && evaldValue.type === 'DetachedRuleset') { 6991 throw { message: 'Rulesets cannot be evaluated on a property.', 6992 index: this.getIndex(), filename: this.fileInfo().filename }; 6993 } 6994 var important = this.important,
6995 importantResult = context.importantScope.pop(); 6996 if (!important && importantResult.important) { 6997 important = importantResult.important; 6998 } 6999 7000 return new Declaration(name, 7001 evaldValue, 7002 important, 7003 this.merge, 7004 this.getIndex(), this.fileInfo(), this.inline, 7005 variable); 7006 } 7007 catch (e) { 7008 if (typeof e.index !== 'number') { 7009 e.index = this.getIndex(); 7010 e.filename = this.fileInfo().filename; 7011 } 7012 throw e; 7013 } 7014 finally { 7015 if (strictMathBypass) { 7016 context.strictMath = false; 7017 } 7018 } 7019}; 7020Declaration.prototype.makeImportant = function () { 7021 return new Declaration(this.name, 7022 this.value, 7023 '!important', 7024 this.merge, 7025 this.getIndex(), this.fileInfo(), this.inline); 7026}; 7027 7028module.exports = Declaration; 7029},{"./anonymous":48,"./keyword":68,"./node":73,"./value":83}],59:[function(require,module,exports){ 7030var Node = require('./node'), 7031 contexts = require('../contexts'), 7032 utils = require('../utils'); 7033 7034var DetachedRuleset = function (ruleset, frames) { 7035 this.ruleset = ruleset; 7036 this.frames = frames; 7037 this.setParent(this.ruleset, this); 7038}; 7039DetachedRuleset.prototype = new Node(); 7040DetachedRuleset.prototype.type = 'DetachedRuleset'; 7041DetachedRuleset.prototype.evalFirst = true; 7042DetachedRuleset.prototype.accept = function (visitor) { 7043 this.ruleset = visitor.visit(this.ruleset); 7044}; 7045DetachedRuleset.prototype.eval = function (context) { 7046 var frames = this.frames || utils.copyArray(context.frames); 7047 return new DetachedRuleset(this.ruleset, frames); 7048}; 7049DetachedRuleset.prototype.callEval = function (context) { 7050 return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context); 7051}; 7052module.exports = DetachedRuleset; 7053 7054},{"../contexts":12,"../utils":86,"./node":73}],60:[function(require,module,exports){ 7055var Node = require('./node'), 7056 unitConversions = require('../data/unit-conversions'), 7057 Unit = require('./unit'), 7058 Color = require('./color'); 7059 7060// 7061// A number with a unit 7062// 7063var Dimension = function (value, unit) { 7064 this.value = parseFloat(value); 7065 if (isNaN(this.value)) { 7066 throw new Error('Dimension is not a number.'); 7067 } 7068 this.unit = (unit && unit instanceof Unit) ? unit : 7069 new Unit(unit ? [unit] : undefined); 7070 this.setParent(this.unit, this); 7071}; 7072 7073Dimension.prototype = new Node(); 7074Dimension.prototype.type = 'Dimension'; 7075Dimension.prototype.accept = function (visitor) { 7076 this.unit = visitor.visit(this.unit); 7077}; 7078Dimension.prototype.eval = function (context) { 7079 return this; 7080}; 7081Dimension.prototype.toColor = function () { 7082 return new Color([this.value, this.value, this.value]); 7083}; 7084Dimension.prototype.genCSS = function (context, output) { 7085 if ((context && context.strictUnits) && !this.unit.isSingular()) { 7086 throw new Error('Multiple units in dimension. Correct the units or use the unit function. Bad unit: ' + this.unit.toString()); 7087 } 7088 7089 var value = this.fround(context, this.value), 7090 strValue = String(value); 7091 7092 if (value !== 0 && value < 0.000001 && value > -0.000001) { 7093 // would be output 1e-6 etc. 7094 strValue = value.toFixed(20).replace(/0+$/, ''); 7095 } 7096 7097 if (context && context.compress) { 7098 // Zero values doesn't need a unit 7099 if (value === 0 && this.unit.isLength()) { 7100 output.add(strValue); 7101 return; 7102 } 7103 7104 // Float values doesn't need a leading zero 7105 if (value > 0 && value < 1) { 7106 strValue = (strValue).substr(1); 7107 } 7108 } 7109 7110 output.add(strValue); 7111 this.unit.genCSS(context, output); 7112}; 7113 7114// In an operation between two Dimensions, 7115// we default to the first Dimension's unit, 7116// so `1px + 2` will yield `3px`. 7117Dimension.prototype.operate = function (context, op, other) { 7118 /* jshint noempty:false */ 7119 var value = this._operate(context, op, this.value, other.value), 7120 unit = this.unit.clone(); 7121 7122 if (op === '+' || op === '-') { 7123 if (unit.numerator.length === 0 && unit.denominator.length === 0) { 7124 unit = other.unit.clone(); 7125 if (this.unit.backupUnit) { 7126 unit.backupUnit = this.unit.backupUnit; 7127 } 7128 } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) { 7129 // do nothing 7130 } else { 7131 other = other.convertTo(this.unit.usedUnits()); 7132 7133 if (context.strictUnits && other.unit.toString() !== unit.toString()) { 7134 throw new Error('Incompatible units. Change the units or use the unit function. Bad units: \'' + unit.toString() + 7135 '\' and \'' + other.unit.toString() + '\'.'); 7136 } 7137 7138 value = this._operate(context, op, this.value, other.value); 7139 } 7140 } else if (op === '*') { 7141 unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); 7142 unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); 7143 unit.cancel(); 7144 } else if (op === '/') { 7145 unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); 7146 unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); 7147 unit.cancel(); 7148 } 7149 return new Dimension(value, unit); 7150}; 7151Dimension.prototype.compare = function (other) { 7152 var a, b; 7153 7154 if (!(other instanceof Dimension)) { 7155 return undefined; 7156 } 7157 7158 if (this.unit.isEmpty() || other.unit.isEmpty()) { 7159 a = this; 7160 b = other; 7161 } else { 7162 a = this.unify(); 7163 b = other.unify(); 7164 if (a.unit.compare(b.unit) !== 0) { 7165 return undefined; 7166 } 7167 } 7168 7169 return Node.numericCompare(a.value, b.value); 7170}; 7171Dimension.prototype.unify = function () { 7172 return this.convertTo({ length: 'px', duration: 's', angle: 'rad' }); 7173}; 7174Dimension.prototype.convertTo = function (conversions) { 7175 var value = this.value, unit = this.unit.clone(), 7176 i, groupName, group, targetUnit, derivedConversions = {}, applyUnit; 7177 7178 if (typeof conversions === 'string') { 7179 for (i in unitConversions) { 7180 if (unitConversions[i].hasOwnProperty(conversions)) { 7181 derivedConversions = {}; 7182 derivedConversions[i] = conversions; 7183 } 7184 } 7185 conversions = derivedConversions; 7186 } 7187 applyUnit = function (atomicUnit, denominator) { 7188 /* jshint loopfunc:true */ 7189 if (group.hasOwnProperty(atomicUnit)) { 7190 if (denominator) { 7191 value = value / (group[atomicUnit] / group[targetUnit]); 7192 } else { 7193 value = value * (group[atomicUnit] / group[targetUnit]); 7194 } 7195 7196 return targetUnit; 7197 } 7198 7199 return atomicUnit; 7200 }; 7201 7202 for (groupName in conversions) { 7203 if (conversions.hasOwnProperty(groupName)) { 7204 targetUnit = conversions[groupName]; 7205 group = unitConversions[groupName]; 7206 7207 unit.map(applyUnit); 7208 } 7209 } 7210 7211 unit.cancel(); 7212 7213 return new Dimension(value, unit); 7214}; 7215module.exports = Dimension; 7216 7217},{"../data/unit-conversions":15,"./color":53,"./node":73,"./unit":81}],61:[function(require,module,exports){ 7218var Node = require('./node'), 7219 Paren = require('./paren'), 7220 Combinator = require('./combinator'); 7221 7222var Element = function (combinator, value, index, currentFileInfo, visibilityInfo) { 7223 this.combinator = combinator instanceof Combinator ? 7224 combinator : new Combinator(combinator); 7225 7226 if (typeof value === 'string') { 7227 this.value = value.trim(); 7228 } else if (value) { 7229 this.value = value; 7230 } else { 7231 this.value = ''; 7232 } 7233 this._index = index; 7234 this._fileInfo = currentFileInfo; 7235 this.copyVisibilityInfo(visibilityInfo); 7236 this.setParent(this.combinator, this); 7237}; 7238Element.prototype = new Node(); 7239Element.prototype.type = 'Element'; 7240Element.prototype.accept = function (visitor) { 7241 var value = this.value; 7242 this.combinator = visitor.visit(this.combinator); 7243 if (typeof value === 'object') { 7244 this.value = visitor.visit(value); 7245 } 7246}; 7247Element.prototype.eval = function (context) { 7248 return new Element(this.combinator, 7249 this.value.eval ? this.value.eval(context) : this.value, 7250 this.getIndex(), 7251 this.fileInfo(), this.visibilityInfo()); 7252}; 7253Element.prototype.clone = function () { 7254 return new Element(this.combinator, 7255 this.value, 7256 this.getIndex(), 7257 this.fileInfo(), this.visibilityInfo()); 7258}; 7259Element.prototype.genCSS = function (context, output) { 7260 output.add(this.toCSS(context), this.fileInfo(), this.getIndex()); 7261}; 7262Element.prototype.toCSS = function (context) { 7263 context = context || {}; 7264 var value = this.value, firstSelector = context.firstSelector; 7265 if (value instanceof Paren) { 7266 // selector in parens should not be affected by outer selector 7267 // flags (breaks only interpolated selectors - see #1973) 7268 context.firstSelector = true; 7269 } 7270 value = value.toCSS ? value.toCSS(context) : value; 7271 context.firstSelector = firstSelector; 7272 if (value === '' && this.combinator.value.charAt(0) === '&') { 7273 return ''; 7274 } else { 7275 return this.combinator.toCSS(context) + value; 7276 } 7277}; 7278module.exports = Element; 7279 7280},{"./combinator":54,"./node":73,"./paren":75}],62:[function(require,module,exports){ 7281var Node = require('./node'), 7282 Paren = require('./paren'), 7283 Comment = require('./comment'); 7284
7285var Expression = function (value, noSpacing) { 7286 this.value = value; 7287 this.noSpacing = noSpacing; 7288 if (!value) { 7289 throw new Error('Expression requires an array parameter'); 7290 } 7291}; 7292Expression.prototype = new Node(); 7293Expression.prototype.type = 'Expression'; 7294Expression.prototype.accept = function (visitor) { 7295 this.value = visitor.visitArray(this.value); 7296}; 7297Expression.prototype.eval = function (context) { 7298 var returnValue, 7299 inParenthesis = this.parens && !this.parensInOp, 7300 doubleParen = false; 7301 if (inParenthesis) { 7302 context.inParenthesis(); 7303 } 7304 if (this.value.length > 1) { 7305 returnValue = new Expression(this.value.map(function (e) { 7306 return e.eval(context); 7307 }), this.noSpacing); 7308 } else if (this.value.length === 1) { 7309 if (this.value[0].parens && !this.value[0].parensInOp) { 7310 doubleParen = true; 7311 } 7312 returnValue = this.value[0].eval(context); 7313 } else { 7314 returnValue = this; 7315 } 7316 if (inParenthesis) { 7317 context.outOfParenthesis(); 7318 } 7319 if (this.parens && this.parensInOp && !(context.isMathOn()) && !doubleParen) { 7320 returnValue = new Paren(returnValue); 7321 } 7322 return returnValue; 7323}; 7324Expression.prototype.genCSS = function (context, output) { 7325 for (var i = 0; i < this.value.length; i++) { 7326 this.value[i].genCSS(context, output); 7327 if (!this.noSpacing && i + 1 < this.value.length) { 7328 output.add(' '); 7329 } 7330 } 7331}; 7332Expression.prototype.throwAwayComments = function () { 7333 this.value = this.value.filter(function(v) { 7334 return !(v instanceof Comment); 7335 }); 7336}; 7337module.exports = Expression; 7338 7339},{"./comment":55,"./node":73,"./paren":75}],63:[function(require,module,exports){ 7340var Node = require('./node'), 7341 Selector = require('./selector'); 7342 7343var Extend = function Extend(selector, option, index, currentFileInfo, visibilityInfo) { 7344 this.selector = selector; 7345 this.option = option; 7346 this.object_id = Extend.next_id++; 7347 this.parent_ids = [this.object_id]; 7348 this._index = index; 7349 this._fileInfo = currentFileInfo; 7350 this.copyVisibilityInfo(visibilityInfo); 7351 this.allowRoot = true; 7352 7353 switch (option) { 7354 case 'all': 7355 this.allowBefore = true; 7356 this.allowAfter = true; 7357 break; 7358 default: 7359 this.allowBefore = false; 7360 this.allowAfter = false; 7361 break; 7362 } 7363 this.setParent(this.selector, this); 7364}; 7365Extend.next_id = 0; 7366 7367Extend.prototype = new Node(); 7368Extend.prototype.type = 'Extend'; 7369Extend.prototype.accept = function (visitor) { 7370 this.selector = visitor.visit(this.selector); 7371}; 7372Extend.prototype.eval = function (context) { 7373 return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); 7374}; 7375Extend.prototype.clone = function (context) { 7376 return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); 7377}; 7378// it concatenates (joins) all selectors in selector array 7379Extend.prototype.findSelfSelectors = function (selectors) { 7380 var selfElements = [], 7381 i, 7382 selectorElements; 7383 7384 for (i = 0; i < selectors.length; i++) { 7385 selectorElements = selectors[i].elements; 7386 // duplicate the logic in genCSS function inside the selector node. 7387 // future TODO - move both logics into the selector joiner visitor 7388 if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') { 7389 selectorElements[0].combinator.value = ' '; 7390 } 7391 selfElements = selfElements.concat(selectors[i].elements); 7392 } 7393 7394 this.selfSelectors = [new Selector(selfElements)]; 7395 this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo()); 7396}; 7397module.exports = Extend; 7398 7399},{"./node":73,"./selector":79}],64:[function(require,module,exports){ 7400var Node = require('./node'), 7401 Media = require('./media'), 7402 URL = require('./url'), 7403 Quoted = require('./quoted'), 7404 Ruleset = require('./ruleset'), 7405 Anonymous = require('./anonymous'), 7406 utils = require('../utils'), 7407 LessError = require('../less-error'); 7408 7409// 7410// CSS @import node 7411// 7412// The general strategy here is that we don't want to wait 7413// for the parsing to be completed, before we start importing 7414// the file. That's because in the context of a browser, 7415// most of the time will be spent waiting for the server to respond. 7416// 7417// On creation, we push the import path to our import queue, though 7418// `import,push`, we also pass it a callback, which it'll call once 7419// the file has been fetched, and parsed. 7420// 7421var Import = function (path, features, options, index, currentFileInfo, visibilityInfo) { 7422 this.options = options; 7423 this._index = index; 7424 this._fileInfo = currentFileInfo; 7425 this.path = path; 7426 this.features = features; 7427 this.allowRoot = true; 7428 7429 if (this.options.less !== undefined || this.options.inline) { 7430 this.css = !this.options.less || this.options.inline; 7431 } else { 7432 var pathValue = this.getPath(); 7433 if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) { 7434 this.css = true; 7435 } 7436 } 7437 this.copyVisibilityInfo(visibilityInfo); 7438 this.setParent(this.features, this); 7439 this.setParent(this.path, this); 7440}; 7441 7442// 7443// The actual import node doesn't return anything, when converted to CSS. 7444// The reason is that it's used at the evaluation stage, so that the rules 7445// it imports can be treated like any other rules. 7446// 7447// In `eval`, we make sure all Import nodes get evaluated, recursively, so 7448// we end up with a flat structure, which can easily be imported in the parent 7449// ruleset. 7450// 7451Import.prototype = new Node(); 7452Import.prototype.type = 'Import'; 7453Import.prototype.accept = function (visitor) { 7454 if (this.features) { 7455 this.features = visitor.visit(this.features); 7456 } 7457 this.path = visitor.visit(this.path); 7458 if (!this.options.isPlugin && !this.options.inline && this.root) { 7459 this.root = visitor.visit(this.root); 7460 } 7461}; 7462Import.prototype.genCSS = function (context, output) { 7463 if (this.css && this.path._fileInfo.reference === undefined) { 7464 output.add('@import ', this._fileInfo, this._index); 7465 this.path.genCSS(context, output); 7466 if (this.features) { 7467 output.add(' '); 7468 this.features.genCSS(context, output); 7469 } 7470 output.add(';'); 7471 } 7472}; 7473Import.prototype.getPath = function () { 7474 return (this.path instanceof URL) ? 7475 this.path.value.value : this.path.value; 7476}; 7477Import.prototype.isVariableImport = function () { 7478 var path = this.path; 7479 if (path instanceof URL) { 7480 path = path.value; 7481 } 7482 if (path instanceof Quoted) { 7483 return path.containsVariables(); 7484 } 7485 7486 return true; 7487}; 7488Import.prototype.evalForImport = function (context) { 7489 var path = this.path; 7490 7491 if (path instanceof URL) { 7492 path = path.value; 7493 } 7494 7495 return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo()); 7496}; 7497Import.prototype.evalPath = function (context) { 7498 var path = this.path.eval(context); 7499 var rootpath = this._fileInfo && this._fileInfo.rootpath; 7500 7501 if (!(path instanceof URL)) { 7502 if (rootpath) { 7503 var pathValue = path.value; 7504 // Add the base path if the import is relative
7505 if (pathValue && context.isPathRelative(pathValue)) { 7506 path.value = rootpath + pathValue; 7507 } 7508 } 7509 path.value = context.normalizePath(path.value); 7510 } 7511 7512 return path; 7513}; 7514Import.prototype.eval = function (context) { 7515 var result = this.doEval(context); 7516 if (this.options.reference || this.blocksVisibility()) { 7517 if (result.length || result.length === 0) { 7518 result.forEach(function (node) { 7519 node.addVisibilityBlock(); 7520 } 7521 ); 7522 } else { 7523 result.addVisibilityBlock(); 7524 } 7525 } 7526 return result; 7527}; 7528Import.prototype.doEval = function (context) { 7529 var ruleset, registry, 7530 features = this.features && this.features.eval(context); 7531 7532 if (this.options.isPlugin) { 7533 if (this.root && this.root.eval) { 7534 try { 7535 this.root.eval(context); 7536 } 7537 catch (e) { 7538 e.message = 'Plugin error during evaluation'; 7539 throw new LessError(e, this.root.imports, this.root.filename); 7540 } 7541 } 7542 registry = context.frames[0] && context.frames[0].functionRegistry; 7543 if ( registry && this.root && this.root.functions ) { 7544 registry.addMultiple( this.root.functions ); 7545 } 7546 7547 return []; 7548 } 7549 7550 if (this.skip) { 7551 if (typeof this.skip === 'function') { 7552 this.skip = this.skip(); 7553 } 7554 if (this.skip) { 7555 return []; 7556 } 7557 } 7558 if (this.options.inline) { 7559 var contents = new Anonymous(this.root, 0, 7560 { 7561 filename: this.importedFilename, 7562 reference: this.path._fileInfo && this.path._fileInfo.reference 7563 }, true, true); 7564 7565 return this.features ? new Media([contents], this.features.value) : [contents]; 7566 } else if (this.css) { 7567 var newImport = new Import(this.evalPath(context), features, this.options, this._index); 7568 if (!newImport.css && this.error) { 7569 throw this.error; 7570 } 7571 return newImport; 7572 } else { 7573 ruleset = new Ruleset(null, utils.copyArray(this.root.rules)); 7574 ruleset.evalImports(context); 7575 7576 return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules; 7577 } 7578}; 7579module.exports = Import; 7580 7581},{"../less-error":36,"../utils":86,"./anonymous":48,"./media":69,"./node":73,"./quoted":77,"./ruleset":78,"./url":82}],65:[function(require,module,exports){ 7582var tree = Object.create(null); 7583 7584tree.Node = require('./node'); 7585tree.Color = require('./color'); 7586tree.AtRule = require('./atrule'); 7587tree.DetachedRuleset = require('./detached-ruleset'); 7588tree.Operation = require('./operation'); 7589tree.Dimension = require('./dimension'); 7590tree.Unit = require('./unit'); 7591tree.Keyword = require('./keyword'); 7592tree.Variable = require('./variable'); 7593tree.Property = require('./property'); 7594tree.Ruleset = require('./ruleset'); 7595tree.Element = require('./element'); 7596tree.Attribute = require('./attribute'); 7597tree.Combinator = require('./combinator'); 7598tree.Selector = require('./selector'); 7599tree.Quoted = require('./quoted'); 7600tree.Expression = require('./expression'); 7601tree.Declaration = require('./declaration'); 7602tree.Call = require('./call'); 7603tree.URL = require('./url'); 7604tree.Import = require('./import'); 7605tree.mixin = { 7606 Call: require('./mixin-call'), 7607 Definition: require('./mixin-definition') 7608}; 7609tree.Comment = require('./comment'); 7610tree.Anonymous = require('./anonymous'); 7611tree.Value = require('./value'); 7612tree.JavaScript = require('./javascript'); 7613tree.Assignment = require('./assignment'); 7614tree.Condition = require('./condition'); 7615tree.Paren = require('./paren'); 7616tree.Media = require('./media'); 7617tree.UnicodeDescriptor = require('./unicode-descriptor'); 7618tree.Negative = require('./negative'); 7619tree.Extend = require('./extend'); 7620tree.VariableCall = require('./variable-call'); 7621 7622module.exports = tree; 7623 7624},{"./anonymous":48,"./assignment":49,"./atrule":50,"./attribute":51,"./call":52,"./color":53,"./combinator":54,"./comment":55,"./condition":56,"./declaration":58,"./detached-ruleset":59,"./dimension":60,"./element":61,"./expression":62,"./extend":63,"./import":64,"./javascript":66,"./keyword":68,"./media":69,"./mixin-call":70,"./mixin-definition":71,"./negative":72,"./node":73,"./operation":74,"./paren":75,"./property":76,"./quoted":77,"./ruleset":78,"./selector":79,"./unicode-descriptor":80,"./unit":81,"./url":82,"./value":83,"./variable":85,"./variable-call":84}],66:[function(require,module,exports){ 7625var JsEvalNode = require('./js-eval-node'), 7626 Dimension = require('./dimension'), 7627 Quoted = require('./quoted'), 7628 Anonymous = require('./anonymous'); 7629 7630var JavaScript = function (string, escaped, index, currentFileInfo) { 7631 this.escaped = escaped; 7632 this.expression = string; 7633 this._index = index; 7634 this._fileInfo = currentFileInfo; 7635}; 7636JavaScript.prototype = new JsEvalNode(); 7637JavaScript.prototype.type = 'JavaScript'; 7638JavaScript.prototype.eval = function(context) { 7639 var result = this.evaluateJavaScript(this.expression, context); 7640 7641 if (typeof result === 'number') { 7642 return new Dimension(result); 7643 } else if (typeof result === 'string') { 7644 return new Quoted('"' + result + '"', result, this.escaped, this._index); 7645 } else if (Array.isArray(result)) { 7646 return new Anonymous(result.join(', ')); 7647 } else { 7648 return new Anonymous(result); 7649 } 7650}; 7651 7652module.exports = JavaScript; 7653 7654},{"./anonymous":48,"./dimension":60,"./js-eval-node":67,"./quoted":77}],67:[function(require,module,exports){ 7655var Node = require('./node'), 7656 Variable = require('./variable'); 7657 7658var JsEvalNode = function() { 7659}; 7660JsEvalNode.prototype = new Node(); 7661 7662JsEvalNode.prototype.evaluateJavaScript = function (expression, context) { 7663 var result, 7664 that = this, 7665 evalContext = {}; 7666 7667 if (!context.javascriptEnabled) { 7668 throw { message: 'Inline JavaScript is not enabled. Is it set in your options?', 7669 filename: this.fileInfo().filename, 7670 index: this.getIndex() }; 7671 } 7672 7673 expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) { 7674 return that.jsify(new Variable('@' + name, that.getIndex(), that.fileInfo()).eval(context)); 7675 }); 7676 7677 try { 7678 expression = new Function('return (' + expression + ')'); 7679 } catch (e) { 7680 throw { message: 'JavaScript evaluation error: ' + e.message + ' from `' + expression + '`' , 7681 filename: this.fileInfo().filename, 7682 index: this.getIndex() }; 7683 } 7684 7685 var variables = context.frames[0].variables(); 7686 for (var k in variables) { 7687 if (variables.hasOwnProperty(k)) { 7688 /* jshint loopfunc:true */ 7689 evalContext[k.slice(1)] = { 7690 value: variables[k].value, 7691 toJS: function () { 7692 return this.value.eval(context).toCSS(); 7693 } 7694 }; 7695 } 7696 } 7697 7698 try { 7699 result = expression.call(evalContext); 7700 } catch (e) { 7701 throw { message: 'JavaScript evaluation error: \'' + e.name + ': ' + e.message.replace(/["]/g, '\'') + '\'' , 7702 filename: this.fileInfo().filename, 7703 index: this.getIndex() }; 7704 } 7705 return result; 7706}; 7707JsEvalNode.prototype.jsify = function (obj) { 7708 if (Array.isArray(obj.value) && (obj.value.length > 1)) { 7709 return '[' + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + ']'; 7710 } else { 7711 return obj.toCSS(); 7712 } 7713}; 7714 7715module.exports = JsEvalNode; 7716 7717},{"./node":73,"./variable":85}],68:[function(require,module,exports){ 7718var Node = require('./node'); 7719 7720var Keyword = function (value) { this.value = value; }; 7721Keyword.prototype = new Node(); 7722Keyword.prototype.type = 'Keyword'; 7723Keyword.prototype.genCSS = function (context, output) { 7724 if (this.value === '%') { throw { type: 'Syntax', message: 'Invalid % without number' }; } 7725 output.add(this.value); 7726}; 7727 7728Keyword.True = new Keyword('true'); 7729Keyword.False = new Keyword('false'); 7730 7731module.exports = Keyword; 7732 7733},{"./node":73}],69:[function(require,module,exports){ 7734var Ruleset = require('./ruleset'), 7735 Value = require('./value'), 7736 Selector = require('./selector'), 7737 Anonymous = require('./anonymous'), 7738 Expression = require('./expression'), 7739 AtRule = require('./atrule'), 7740 utils = require('../utils'); 7741 7742var Media = function (value, features, index, currentFileInfo, visibilityInfo) { 7743 this._index = index; 7744 this._fileInfo = currentFileInfo; 7745 7746 var selectors = (new Selector([], null, null, this._index, this._fileInfo)).createEmptySelectors(); 7747 7748 this.features = new Value(features); 7749 this.rules = [new Ruleset(selectors, value)]; 7750 this.rules[0].allowImports = true; 7751 this.copyVisibilityInfo(visibilityInfo); 7752 this.allowRoot = true; 7753 this.setParent(selectors, this); 7754 this.setParent(this.features, this); 7755 this.setParent(this.rules, this); 7756}; 7757Media.prototype = new AtRule(); 7758Media.prototype.type = 'Media'; 7759Media.prototype.isRulesetLike = function() { return true; }; 7760Media.prototype.accept = function (visitor) { 7761 if (this.features) { 7762 this.features = visitor.visit(this.features); 7763 } 7764 if (this.rules) { 7765 this.rules = visitor.visitArray(this.rules); 7766 } 7767}; 7768Media.prototype.genCSS = function (context, output) { 7769 output.add('@media ', this._fileInfo, this._index); 7770 this.features.genCSS(context, output); 7771 this.outputRuleset(context, output, this.rules); 7772}; 7773Media.prototype.eval = function (context) { 7774 if (!context.mediaBlocks) { 7775 context.mediaBlocks = []; 7776 context.mediaPath = []; 7777 } 7778 7779 var media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo()); 7780 if (this.debugInfo) { 7781 this.rules[0].debugInfo = this.debugInfo; 7782 media.debugInfo = this.debugInfo; 7783 } 7784 7785 media.features = this.features.eval(context); 7786 7787 context.mediaPath.push(media); 7788 context.mediaBlocks.push(media); 7789 7790 this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit(); 7791 context.frames.unshift(this.rules[0]); 7792 media.rules = [this.rules[0].eval(context)]; 7793 context.frames.shift(); 7794 7795 context.mediaPath.pop(); 7796 7797 return context.mediaPath.length === 0 ? media.evalTop(context) : 7798 media.evalNested(context); 7799}; 7800Media.prototype.evalTop = function (context) { 7801 var result = this; 7802 7803 // Render all dependent Media blocks. 7804 if (context.mediaBlocks.length > 1) { 7805 var selectors = (new Selector([], null, null, this.getIndex(), this.fileInfo())).createEmptySelectors(); 7806 result = new Ruleset(selectors, context.mediaBlocks); 7807 result.multiMedia = true; 7808 result.copyVisibilityInfo(this.visibilityInfo()); 7809 this.setParent(result, this); 7810 } 7811 7812 delete context.mediaBlocks; 7813 delete context.mediaPath; 7814 7815 return result; 7816}; 7817Media.prototype.evalNested = function (context) { 7818 var i, value, 7819 path = context.mediaPath.concat([this]); 7820 7821 // Extract the media-query conditions separated with `,` (OR). 7822 for (i = 0; i < path.length; i++) { 7823 value = path[i].features instanceof Value ? 7824 path[i].features.value : path[i].features; 7825 path[i] = Array.isArray(value) ? value : [value]; 7826 } 7827 7828 // Trace all permutations to generate the resulting media-query. 7829 // 7830 // (a, b and c) with nested (d, e) -> 7831 // a and d 7832 // a and e 7833 // b and c and d 7834 // b and c and e 7835 this.features = new Value(this.permute(path).map(function (path) { 7836 path = path.map(function (fragment) { 7837 return fragment.toCSS ? fragment : new Anonymous(fragment); 7838 }); 7839 7840 for (i = path.length - 1; i > 0; i--) { 7841 path.splice(i, 0, new Anonymous('and')); 7842 } 7843 7844 return new Expression(path); 7845 })); 7846 this.setParent(this.features, this); 7847 7848 // Fake a tree-node that doesn't output anything. 7849 return new Ruleset([], []); 7850}; 7851Media.prototype.permute = function (arr) { 7852 if (arr.length === 0) { 7853 return []; 7854 } else if (arr.length === 1) { 7855 return arr[0]; 7856 } else { 7857 var result = []; 7858 var rest = this.permute(arr.slice(1)); 7859 for (var i = 0; i < rest.length; i++) { 7860 for (var j = 0; j < arr[0].length; j++) { 7861 result.push([arr[0][j]].concat(rest[i])); 7862 } 7863 } 7864 return result; 7865 } 7866}; 7867Media.prototype.bubbleSelectors = function (selectors) { 7868 if (!selectors) { 7869 return; 7870 } 7871 this.rules = [new Ruleset(utils.copyArray(selectors), [this.rules[0]])]; 7872 this.setParent(this.rules, this); 7873}; 7874module.exports = Media; 7875 7876},{"../utils":86,"./anonymous":48,"./atrule":50,"./expression":62,"./ruleset":78,"./selector":79,"./value":83}],70:[function(require,module,exports){ 7877var Node = require('./node'), 7878 Selector = require('./selector'), 7879 MixinDefinition = require('./mixin-definition'), 7880 defaultFunc = require('../functions/default'); 7881 7882var MixinCall = function (elements, args, index, currentFileInfo, important) { 7883 this.selector = new Selector(elements); 7884 this.arguments = args || []; 7885 this._index = index; 7886 this._fileInfo = currentFileInfo; 7887 this.important = important; 7888 this.allowRoot = true; 7889 this.setParent(this.selector, this); 7890}; 7891MixinCall.prototype = new Node(); 7892MixinCall.prototype.type = 'MixinCall'; 7893MixinCall.prototype.accept = function (visitor) { 7894 if (this.selector) { 7895 this.selector = visitor.visit(this.selector); 7896 } 7897 if (this.arguments.length) { 7898 this.arguments = visitor.visitArray(this.arguments); 7899 } 7900}; 7901MixinCall.prototype.eval = function (context) { 7902 var mixins, mixin, mixinPath, args = [], arg, argValue, 7903 rules = [], match = false, i, m, f, isRecursive, isOneFound, 7904 candidates = [], candidate, conditionResult = [], defaultResult, defFalseEitherCase = -1, 7905 defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset, noArgumentsFilter; 7906 7907 function calcDefGroup(mixin, mixinPath) { 7908 var f, p, namespace; 7909 7910 for (f = 0; f < 2; f++) { 7911 conditionResult[f] = true; 7912 defaultFunc.value(f); 7913 for (p = 0; p < mixinPath.length && conditionResult[f]; p++) { 7914 namespace = mixinPath[p]; 7915 if (namespace.matchCondition) { 7916 conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context); 7917 } 7918 } 7919 if (mixin.matchCondition) { 7920 conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context); 7921 } 7922 } 7923 if (conditionResult[0] || conditionResult[1]) { 7924 if (conditionResult[0] != conditionResult[1]) { 7925 return conditionResult[1] ? 7926 defTrue : defFalse; 7927 } 7928 7929 return defNone; 7930 } 7931 return defFalseEitherCase; 7932 } 7933 7934 for (i = 0; i < this.arguments.length; i++) { 7935 arg = this.arguments[i]; 7936 argValue = arg.value.eval(context); 7937 if (arg.expand && Array.isArray(argValue.value)) { 7938 argValue = argValue.value; 7939 for (m = 0; m < argValue.length; m++) { 7940 args.push({value: argValue[m]}); 7941 } 7942 } else { 7943 args.push({name: arg.name, value: argValue}); 7944 } 7945 } 7946 7947 noArgumentsFilter = function(rule) {return rule.matchArgs(null, context);}; 7948 7949 for (i = 0; i < context.frames.length; i++) { 7950 if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).length > 0) { 7951 isOneFound = true; 7952 7953 // To make `default()` function independent of definition order we have two "subpasses" here. 7954 // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`), 7955 // and build candidate list with corresponding flags. Then, when we know all possible matches, 7956 // we make a final decision. 7957 7958 for (m = 0; m < mixins.length; m++) { 7959 mixin = mixins[m].rule; 7960 mixinPath = mixins[m].path; 7961 isRecursive = false;
7962 for (f = 0; f < context.frames.length; f++) { 7963 if ((!(mixin instanceof MixinDefinition)) && mixin === (context.frames[f].originalRuleset || context.frames[f])) { 7964 isRecursive = true; 7965 break; 7966 } 7967 } 7968 if (isRecursive) { 7969 continue; 7970 } 7971 7972 if (mixin.matchArgs(args, context)) { 7973 candidate = {mixin: mixin, group: calcDefGroup(mixin, mixinPath)}; 7974 7975 if (candidate.group !== defFalseEitherCase) { 7976 candidates.push(candidate); 7977 } 7978 7979 match = true; 7980 } 7981 } 7982 7983 defaultFunc.reset(); 7984 7985 count = [0, 0, 0]; 7986 for (m = 0; m < candidates.length; m++) { 7987 count[candidates[m].group]++; 7988 } 7989 7990 if (count[defNone] > 0) { 7991 defaultResult = defFalse; 7992 } else { 7993 defaultResult = defTrue; 7994 if ((count[defTrue] + count[defFalse]) > 1) { 7995 throw { type: 'Runtime', 7996 message: 'Ambiguous use of `default()` found when matching for `' + this.format(args) + '`', 7997 index: this.getIndex(), filename: this.fileInfo().filename }; 7998 } 7999 } 8000 8001 for (m = 0; m < candidates.length; m++) { 8002 candidate = candidates[m].group; 8003 if ((candidate === defNone) || (candidate === defaultResult)) { 8004 try { 8005 mixin = candidates[m].mixin; 8006 if (!(mixin instanceof MixinDefinition)) { 8007 originalRuleset = mixin.originalRuleset || mixin; 8008 mixin = new MixinDefinition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo()); 8009 mixin.originalRuleset = originalRuleset; 8010 } 8011 var newRules = mixin.evalCall(context, args, this.important).rules; 8012 this._setVisibilityToReplacement(newRules); 8013 Array.prototype.push.apply(rules, newRules); 8014 } catch (e) { 8015 throw { message: e.message, index: this.getIndex(), filename: this.fileInfo().filename, stack: e.stack }; 8016 } 8017 } 8018 } 8019 8020 if (match) { 8021 return rules; 8022 } 8023 } 8024 } 8025 if (isOneFound) { 8026 throw { type: 'Runtime', 8027 message: 'No matching definition was found for `' + this.format(args) + '`', 8028 index: this.getIndex(), filename: this.fileInfo().filename }; 8029 } else { 8030 throw { type: 'Name', 8031 message: this.selector.toCSS().trim() + ' is undefined', 8032 index: this.getIndex(), filename: this.fileInfo().filename }; 8033 } 8034}; 8035 8036MixinCall.prototype._setVisibilityToReplacement = function (replacement) { 8037 var i, rule; 8038 if (this.blocksVisibility()) { 8039 for (i = 0; i < replacement.length; i++) { 8040 rule = replacement[i]; 8041 rule.addVisibilityBlock(); 8042 } 8043 } 8044}; 8045MixinCall.prototype.format = function (args) { 8046 return this.selector.toCSS().trim() + '(' + 8047 (args ? args.map(function (a) { 8048 var argValue = ''; 8049 if (a.name) { 8050 argValue += a.name + ':'; 8051 } 8052 if (a.value.toCSS) { 8053 argValue += a.value.toCSS(); 8054 } else { 8055 argValue += '???'; 8056 } 8057 return argValue; 8058 }).join(', ') : '') + ')'; 8059}; 8060module.exports = MixinCall; 8061 8062},{"../functions/default":24,"./mixin-definition":71,"./node":73,"./selector":79}],71:[function(require,module,exports){ 8063var Selector = require('./selector'), 8064 Element = require('./element'), 8065 Ruleset = require('./ruleset'), 8066 Declaration = require('./declaration'), 8067 Expression = require('./expression'), 8068 contexts = require('../contexts'), 8069 utils = require('../utils'); 8070 8071var Definition = function (name, params, rules, condition, variadic, frames, visibilityInfo) { 8072 this.name = name; 8073 this.selectors = [new Selector([new Element(null, name, this._index, this._fileInfo)])]; 8074 this.params = params; 8075 this.condition = condition; 8076 this.variadic = variadic; 8077 this.arity = params.length; 8078 this.rules = rules; 8079 this._lookups = {}; 8080 var optionalParameters = []; 8081 this.required = params.reduce(function (count, p) { 8082 if (!p.name || (p.name && !p.value)) { 8083 return count + 1; 8084 } 8085 else { 8086 optionalParameters.push(p.name); 8087 return count; 8088 } 8089 }, 0); 8090 this.optionalParameters = optionalParameters; 8091 this.frames = frames; 8092 this.copyVisibilityInfo(visibilityInfo); 8093 this.allowRoot = true; 8094}; 8095Definition.prototype = new Ruleset(); 8096Definition.prototype.type = 'MixinDefinition'; 8097Definition.prototype.evalFirst = true; 8098Definition.prototype.accept = function (visitor) { 8099 if (this.params && this.params.length) { 8100 this.params = visitor.visitArray(this.params); 8101 } 8102 this.rules = visitor.visitArray(this.rules); 8103 if (this.condition) { 8104 this.condition = visitor.visit(this.condition); 8105 } 8106}; 8107Definition.prototype.evalParams = function (context, mixinEnv, args, evaldArguments) { 8108 /* jshint boss:true */ 8109 var frame = new Ruleset(null, null), 8110 varargs, arg, 8111 params = utils.copyArray(this.params), 8112 i, j, val, name, isNamedFound, argIndex, argsLength = 0; 8113 8114 if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) { 8115 frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit(); 8116 }
8117 mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames)); 8118 8119 if (args) { 8120 args = utils.copyArray(args); 8121 argsLength = args.length; 8122 8123 for (i = 0; i < argsLength; i++) { 8124 arg = args[i]; 8125 if (name = (arg && arg.name)) { 8126 isNamedFound = false; 8127 for (j = 0; j < params.length; j++) { 8128 if (!evaldArguments[j] && name === params[j].name) { 8129 evaldArguments[j] = arg.value.eval(context); 8130 frame.prependRule(new Declaration(name, arg.value.eval(context))); 8131 isNamedFound = true; 8132 break; 8133 } 8134 } 8135 if (isNamedFound) { 8136 args.splice(i, 1); 8137 i--; 8138 continue; 8139 } else { 8140 throw { type: 'Runtime', message: 'Named argument for ' + this.name + 8141 ' ' + args[i].name + ' not found' }; 8142 } 8143 } 8144 } 8145 } 8146 argIndex = 0; 8147 for (i = 0; i < params.length; i++) { 8148 if (evaldArguments[i]) { continue; } 8149 8150 arg = args && args[argIndex]; 8151 8152 if (name = params[i].name) { 8153 if (params[i].variadic) { 8154 varargs = []; 8155 for (j = argIndex; j < argsLength; j++) { 8156 varargs.push(args[j].value.eval(context)); 8157 } 8158 frame.prependRule(new Declaration(name, new Expression(varargs).eval(context))); 8159 } else { 8160 val = arg && arg.value; 8161 if (val) { 8162 val = val.eval(context); 8163 } else if (params[i].value) { 8164 val = params[i].value.eval(mixinEnv); 8165 frame.resetCache(); 8166 } else { 8167 throw { type: 'Runtime', message: 'wrong number of arguments for ' + this.name + 8168 ' (' + argsLength + ' for ' + this.arity + ')' }; 8169 } 8170 8171 frame.prependRule(new Declaration(name, val)); 8172 evaldArguments[i] = val; 8173 } 8174 } 8175 8176 if (params[i].variadic && args) { 8177 for (j = argIndex; j < argsLength; j++) { 8178 evaldArguments[j] = args[j].value.eval(context); 8179 } 8180 } 8181 argIndex++; 8182 } 8183 8184 return frame; 8185}; 8186Definition.prototype.makeImportant = function() { 8187 var rules = !this.rules ? this.rules : this.rules.map(function (r) { 8188 if (r.makeImportant) { 8189 return r.makeImportant(true); 8190 } else { 8191 return r; 8192 } 8193 }); 8194 var result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames); 8195 return result; 8196}; 8197Definition.prototype.eval = function (context) { 8198 return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || utils.copyArray(context.frames)); 8199}; 8200Definition.prototype.evalCall = function (context, args, important) { 8201 var _arguments = [], 8202 mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames, 8203 frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments), 8204 rules, ruleset; 8205 8206 frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context))); 8207 8208 rules = utils.copyArray(this.rules); 8209 8210 ruleset = new Ruleset(null, rules); 8211 ruleset.originalRuleset = this; 8212 ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames))); 8213 if (important) { 8214 ruleset = ruleset.makeImportant(); 8215 } 8216 return ruleset; 8217}; 8218Definition.prototype.matchCondition = function (args, context) { 8219 if (this.condition && !this.condition.eval( 8220 new contexts.Eval(context, 8221 [this.evalParams(context, /* the parameter variables */ 8222 new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])] 8223 .concat(this.frames || []) // the parent namespace/mixin frames 8224 .concat(context.frames)))) { // the current environment frames 8225 return false;
8226 } 8227 return true; 8228}; 8229Definition.prototype.matchArgs = function (args, context) { 8230 var allArgsCnt = (args && args.length) || 0, len, optionalParameters = this.optionalParameters; 8231 var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) { 8232 if (optionalParameters.indexOf(p.name) < 0) { 8233 return count + 1; 8234 } else { 8235 return count; 8236 } 8237 }, 0); 8238 8239 if (!this.variadic) { 8240 if (requiredArgsCnt < this.required) { 8241 return false; 8242 } 8243 if (allArgsCnt > this.params.length) { 8244 return false; 8245 } 8246 } else { 8247 if (requiredArgsCnt < (this.required - 1)) { 8248 return false; 8249 } 8250 } 8251 8252 // check patterns 8253 len = Math.min(requiredArgsCnt, this.arity); 8254 8255 for (var i = 0; i < len; i++) { 8256 if (!this.params[i].name && !this.params[i].variadic) { 8257 if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) { 8258 return false; 8259 } 8260 } 8261 } 8262 return true; 8263}; 8264module.exports = Definition; 8265 8266},{"../contexts":12,"../utils":86,"./declaration":58,"./element":61,"./expression":62,"./ruleset":78,"./selector":79}],72:[function(require,module,exports){ 8267var Node = require('./node'), 8268 Operation = require('./operation'), 8269 Dimension = require('./dimension'); 8270 8271var Negative = function (node) { 8272 this.value = node; 8273}; 8274Negative.prototype = new Node(); 8275Negative.prototype.type = 'Negative'; 8276Negative.prototype.genCSS = function (context, output) { 8277 output.add('-'); 8278 this.value.genCSS(context, output); 8279}; 8280Negative.prototype.eval = function (context) { 8281 if (context.isMathOn()) { 8282 return (new Operation('*', [new Dimension(-1), this.value])).eval(context); 8283 } 8284 return new Negative(this.value.eval(context)); 8285}; 8286module.exports = Negative; 8287 8288},{"./dimension":60,"./node":73,"./operation":74}],73:[function(require,module,exports){ 8289var Node = function() { 8290 this.parent = null; 8291 this.visibilityBlocks = undefined; 8292 this.nodeVisible = undefined; 8293 this.rootNode = null; 8294 this.parsed = null; 8295 8296 var self = this; 8297 Object.defineProperty(this, 'currentFileInfo', { 8298 get: function() { return self.fileInfo(); } 8299 }); 8300 Object.defineProperty(this, 'index', { 8301 get: function() { return self.getIndex(); } 8302 }); 8303 8304}; 8305Node.prototype.setParent = function(nodes, parent) { 8306 function set(node) { 8307 if (node && node instanceof Node) { 8308 node.parent = parent; 8309 } 8310 } 8311 if (Array.isArray(nodes)) { 8312 nodes.forEach(set); 8313 } 8314 else { 8315 set(nodes); 8316 } 8317}; 8318Node.prototype.getIndex = function() { 8319 return this._index || (this.parent && this.parent.getIndex()) || 0; 8320}; 8321Node.prototype.fileInfo = function() { 8322 return this._fileInfo || (this.parent && this.parent.fileInfo()) || {}; 8323}; 8324Node.prototype.isRulesetLike = function() { return false; }; 8325Node.prototype.toCSS = function (context) { 8326 var strs = []; 8327 this.genCSS(context, { 8328 add: function(chunk, fileInfo, index) { 8329 strs.push(chunk); 8330 }, 8331 isEmpty: function () { 8332 return strs.length === 0; 8333 } 8334 }); 8335 return strs.join(''); 8336}; 8337Node.prototype.genCSS = function (context, output) { 8338 output.add(this.value); 8339}; 8340Node.prototype.accept = function (visitor) { 8341 this.value = visitor.visit(this.value); 8342}; 8343Node.prototype.eval = function () { return this; }; 8344Node.prototype._operate = function (context, op, a, b) { 8345 switch (op) { 8346 case '+': return a + b; 8347 case '-': return a - b; 8348 case '*': return a * b; 8349 case '/': return a / b; 8350 } 8351}; 8352Node.prototype.fround = function(context, value) { 8353 var precision = context && context.numPrecision; 8354 // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded: 8355 return (precision) ? Number((value + 2e-16).toFixed(precision)) : value; 8356}; 8357Node.compare = function (a, b) { 8358 /* returns: 8359 -1: a < b 8360 0: a = b 8361 1: a > b 8362 and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */ 8363 8364 if ((a.compare) && 8365 // for "symmetric results" force toCSS-based comparison 8366 // of Quoted or Anonymous if either value is one of those 8367 !(b.type === 'Quoted' || b.type === 'Anonymous')) { 8368 return a.compare(b); 8369 } else if (b.compare) { 8370 return -b.compare(a); 8371 } else if (a.type !== b.type) { 8372 return undefined; 8373 } 8374 8375 a = a.value; 8376 b = b.value; 8377 if (!Array.isArray(a)) { 8378 return a === b ? 0 : undefined; 8379 } 8380 if (a.length !== b.length) { 8381 return undefined; 8382 } 8383 for (var i = 0; i < a.length; i++) { 8384 if (Node.compare(a[i], b[i]) !== 0) { 8385 return undefined; 8386 } 8387 } 8388 return 0; 8389}; 8390 8391Node.numericCompare = function (a, b) { 8392 return a < b ? -1 8393 : a === b ? 0 8394 : a > b ? 1 : undefined; 8395}; 8396// Returns true if this node represents root of ast imported by reference 8397Node.prototype.blocksVisibility = function () { 8398 if (this.visibilityBlocks == null) { 8399 this.visibilityBlocks = 0; 8400 } 8401 return this.visibilityBlocks !== 0; 8402}; 8403Node.prototype.addVisibilityBlock = function () { 8404 if (this.visibilityBlocks == null) { 8405 this.visibilityBlocks = 0; 8406 } 8407 this.visibilityBlocks = this.visibilityBlocks + 1; 8408}; 8409Node.prototype.removeVisibilityBlock = function () { 8410 if (this.visibilityBlocks == null) { 8411 this.visibilityBlocks = 0; 8412 } 8413 this.visibilityBlocks = this.visibilityBlocks - 1; 8414}; 8415// Turns on node visibility - if called node will be shown in output regardless
8416// of whether it comes from import by reference or not 8417Node.prototype.ensureVisibility = function () { 8418 this.nodeVisible = true; 8419}; 8420// Turns off node visibility - if called node will NOT be shown in output regardless 8421// of whether it comes from import by reference or not 8422Node.prototype.ensureInvisibility = function () { 8423 this.nodeVisible = false; 8424}; 8425// return values: 8426// false - the node must not be visible 8427// true - the node must be visible 8428// undefined or null - the node has the same visibility as its parent 8429Node.prototype.isVisible = function () { 8430 return this.nodeVisible; 8431}; 8432Node.prototype.visibilityInfo = function() { 8433 return { 8434 visibilityBlocks: this.visibilityBlocks, 8435 nodeVisible: this.nodeVisible 8436 }; 8437}; 8438Node.prototype.copyVisibilityInfo = function(info) { 8439 if (!info) { 8440 return; 8441 } 8442 this.visibilityBlocks = info.visibilityBlocks; 8443 this.nodeVisible = info.nodeVisible; 8444}; 8445module.exports = Node; 8446 8447},{}],74:[function(require,module,exports){ 8448var Node = require('./node'), 8449 Color = require('./color'), 8450 Dimension = require('./dimension'); 8451 8452var Operation = function (op, operands, isSpaced) { 8453 this.op = op.trim(); 8454 this.operands = operands; 8455 this.isSpaced = isSpaced; 8456}; 8457Operation.prototype = new Node(); 8458Operation.prototype.type = 'Operation'; 8459Operation.prototype.accept = function (visitor) { 8460 this.operands = visitor.visit(this.operands); 8461}; 8462Operation.prototype.eval = function (context) { 8463 var a = this.operands[0].eval(context), 8464 b = this.operands[1].eval(context); 8465 8466 if (context.isMathOn()) { 8467 if (a instanceof Dimension && b instanceof Color) { 8468 a = a.toColor(); 8469 } 8470 if (b instanceof Dimension && a instanceof Color) { 8471 b = b.toColor(); 8472 } 8473 if (!a.operate) { 8474 throw { type: 'Operation', 8475 message: 'Operation on an invalid type' }; 8476 } 8477 8478 return a.operate(context, this.op, b); 8479 } else { 8480 return new Operation(this.op, [a, b], this.isSpaced); 8481 } 8482}; 8483Operation.prototype.genCSS = function (context, output) { 8484 this.operands[0].genCSS(context, output); 8485 if (this.isSpaced) { 8486 output.add(' '); 8487 } 8488 output.add(this.op); 8489 if (this.isSpaced) { 8490 output.add(' '); 8491 } 8492 this.operands[1].genCSS(context, output); 8493}; 8494 8495module.exports = Operation; 8496 8497},{"./color":53,"./dimension":60,"./node":73}],75:[function(require,module,exports){ 8498var Node = require('./node'); 8499 8500var Paren = function (node) { 8501 this.value = node; 8502}; 8503Paren.prototype = new Node(); 8504Paren.prototype.type = 'Paren'; 8505Paren.prototype.genCSS = function (context, output) { 8506 output.add('('); 8507 this.value.genCSS(context, output); 8508 output.add(')'); 8509}; 8510Paren.prototype.eval = function (context) { 8511 return new Paren(this.value.eval(context)); 8512}; 8513module.exports = Paren; 8514 8515},{"./node":73}],76:[function(require,module,exports){ 8516var Node = require('./node'), 8517 Declaration = require('./declaration'); 8518 8519var Property = function (name, index, currentFileInfo) { 8520 this.name = name; 8521 this._index = index; 8522 this._fileInfo = currentFileInfo; 8523}; 8524Property.prototype = new Node(); 8525Property.prototype.type = 'Property'; 8526Property.prototype.eval = function (context) { 8527 var property, name = this.name; 8528 // TODO: shorten this reference 8529 var mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules; 8530 8531 if (this.evaluating) { 8532 throw { type: 'Name', 8533 message: 'Recursive property reference for ' + name, 8534 filename: this.fileInfo().filename, 8535 index: this.getIndex() }; 8536 } 8537 8538 this.evaluating = true; 8539 8540 property = this.find(context.frames, function (frame) { 8541 8542 var v, vArr = frame.property(name); 8543 if (vArr) { 8544 for (var i = 0; i < vArr.length; i++) { 8545 v = vArr[i]; 8546 8547 vArr[i] = new Declaration(v.name, 8548 v.value, 8549 v.important, 8550 v.merge, 8551 v.index, 8552 v.currentFileInfo, 8553 v.inline, 8554 v.variable 8555 ); 8556 } 8557 mergeRules(vArr); 8558 8559 v = vArr[vArr.length - 1]; 8560 if (v.important) {
8561 var importantScope = context.importantScope[context.importantScope.length - 1]; 8562 importantScope.important = v.important; 8563 } 8564 v = v.value.eval(context); 8565 return v; 8566 } 8567 }); 8568 if (property) { 8569 this.evaluating = false; 8570 return property; 8571 } else { 8572 throw { type: 'Name', 8573 message: 'Property \'' + name + '\' is undefined', 8574 filename: this.currentFileInfo.filename, 8575 index: this.index }; 8576 } 8577}; 8578Property.prototype.find = function (obj, fun) { 8579 for (var i = 0, r; i < obj.length; i++) { 8580 r = fun.call(obj, obj[i]); 8581 if (r) { return r; } 8582 } 8583 return null; 8584}; 8585module.exports = Property; 8586 8587},{"./declaration":58,"./node":73}],77:[function(require,module,exports){ 8588var Node = require('./node'), 8589 Variable = require('./variable'), 8590 Property = require('./property'); 8591 8592var Quoted = function (str, content, escaped, index, currentFileInfo) { 8593 this.escaped = (escaped == null) ? true : escaped; 8594 this.value = content || ''; 8595 this.quote = str.charAt(0); 8596 this._index = index; 8597 this._fileInfo = currentFileInfo; 8598 this.variableRegex = /@\{([\w-]+)\}/g; 8599 this.propRegex = /\$\{([\w-]+)\}/g; 8600}; 8601Quoted.prototype = new Node(); 8602Quoted.prototype.type = 'Quoted'; 8603Quoted.prototype.genCSS = function (context, output) { 8604 if (!this.escaped) { 8605 output.add(this.quote, this.fileInfo(), this.getIndex()); 8606 } 8607 output.add(this.value); 8608 if (!this.escaped) { 8609 output.add(this.quote); 8610 } 8611}; 8612Quoted.prototype.containsVariables = function() { 8613 return this.value.match(this.variableRegex); 8614}; 8615Quoted.prototype.eval = function (context) { 8616 var that = this, value = this.value; 8617 var variableReplacement = function (_, name) { 8618 var v = new Variable('@' + name, that.getIndex(), that.fileInfo()).eval(context, true); 8619 return (v instanceof Quoted) ? v.value : v.toCSS(); 8620 }; 8621 var propertyReplacement = function (_, name) { 8622 var v = new Property('$' + name, that.getIndex(), that.fileInfo()).eval(context, true); 8623 return (v instanceof Quoted) ? v.value : v.toCSS(); 8624 }; 8625 function iterativeReplace(value, regexp, replacementFnc) { 8626 var evaluatedValue = value; 8627 do { 8628 value = evaluatedValue; 8629 evaluatedValue = value.replace(regexp, replacementFnc); 8630 } while (value !== evaluatedValue); 8631 return evaluatedValue; 8632 } 8633 value = iterativeReplace(value, this.variableRegex, variableReplacement); 8634 value = iterativeReplace(value, this.propRegex, propertyReplacement); 8635 return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo()); 8636}; 8637Quoted.prototype.compare = function (other) { 8638 // when comparing quoted strings allow the quote to differ 8639 if (other.type === 'Quoted' && !this.escaped && !other.escaped) { 8640 return Node.numericCompare(this.value, other.value); 8641 } else { 8642 return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; 8643 } 8644}; 8645module.exports = Quoted; 8646 8647},{"./node":73,"./property":76,"./variable":85}],78:[function(require,module,exports){ 8648var Node = require('./node'), 8649 Declaration = require('./declaration'), 8650 Keyword = require('./keyword'), 8651 Comment = require('./comment'), 8652 Paren = require('./paren'), 8653 Selector = require('./selector'), 8654 Element = require('./element'), 8655 Anonymous = require('./anonymous'), 8656 contexts = require('../contexts'), 8657 globalFunctionRegistry = require('../functions/function-registry'), 8658 defaultFunc = require('../functions/default'), 8659 getDebugInfo = require('./debug-info'), 8660 utils = require('../utils'); 8661 8662var Ruleset = function (selectors, rules, strictImports, visibilityInfo) { 8663 this.selectors = selectors; 8664 this.rules = rules; 8665 this._lookups = {}; 8666 this._variables = null; 8667 this._properties = null; 8668 this.strictImports = strictImports; 8669 this.copyVisibilityInfo(visibilityInfo); 8670 this.allowRoot = true; 8671 8672 this.setParent(this.selectors, this); 8673 this.setParent(this.rules, this); 8674 8675}; 8676Ruleset.prototype = new Node(); 8677Ruleset.prototype.type = 'Ruleset'; 8678Ruleset.prototype.isRuleset = true; 8679Ruleset.prototype.isRulesetLike = function() { return true; }; 8680Ruleset.prototype.accept = function (visitor) { 8681 if (this.paths) { 8682 this.paths = visitor.visitArray(this.paths, true); 8683 } else if (this.selectors) { 8684 this.selectors = visitor.visitArray(this.selectors); 8685 } 8686 if (this.rules && this.rules.length) { 8687 this.rules = visitor.visitArray(this.rules); 8688 } 8689}; 8690Ruleset.prototype.eval = function (context) { 8691 var thisSelectors = this.selectors, selectors, 8692 selCnt, selector, i, hasOnePassingSelector = false;
8693 8694 if (thisSelectors && (selCnt = thisSelectors.length)) { 8695 selectors = new Array(selCnt); 8696 defaultFunc.error({ 8697 type: 'Syntax', 8698 message: 'it is currently only allowed in parametric mixin guards,' 8699 }); 8700 for (i = 0; i < selCnt; i++) { 8701 selector = thisSelectors[i].eval(context); 8702 selectors[i] = selector; 8703 if (selector.evaldCondition) { 8704 hasOnePassingSelector = true; 8705 } 8706 } 8707 defaultFunc.reset(); 8708 } else { 8709 hasOnePassingSelector = true; 8710 } 8711 8712 var rules = this.rules ? utils.copyArray(this.rules) : null, 8713 ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()), 8714 rule, subRule; 8715 8716 ruleset.originalRuleset = this; 8717 ruleset.root = this.root; 8718 ruleset.firstRoot = this.firstRoot; 8719 ruleset.allowImports = this.allowImports; 8720 8721 if (this.debugInfo) { 8722 ruleset.debugInfo = this.debugInfo; 8723 } 8724 8725 if (!hasOnePassingSelector) { 8726 rules.length = 0; 8727 } 8728 8729 // inherit a function registry from the frames stack when possible; 8730 // otherwise from the global registry 8731 ruleset.functionRegistry = (function (frames) { 8732 var i = 0, 8733 n = frames.length, 8734 found; 8735 for ( ; i !== n ; ++i ) { 8736 found = frames[ i ].functionRegistry; 8737 if ( found ) { return found; } 8738 } 8739 return globalFunctionRegistry; 8740 }(context.frames)).inherit(); 8741 8742 // push the current ruleset to the frames stack 8743 var ctxFrames = context.frames; 8744 ctxFrames.unshift(ruleset); 8745 8746 // currrent selectors 8747 var ctxSelectors = context.selectors; 8748 if (!ctxSelectors) { 8749 context.selectors = ctxSelectors = []; 8750 } 8751 ctxSelectors.unshift(this.selectors); 8752 8753 // Evaluate imports 8754 if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { 8755 ruleset.evalImports(context); 8756 } 8757 8758 // Store the frames around mixin definitions, 8759 // so they can be evaluated like closures when the time comes. 8760 var rsRules = ruleset.rules; 8761 for (i = 0; (rule = rsRules[i]); i++) { 8762 if (rule.evalFirst) { 8763 rsRules[i] = rule.eval(context); 8764 } 8765 } 8766 8767 var mediaBlockCount = (context.mediaBlocks && context.mediaBlocks.length) || 0; 8768 8769 // Evaluate mixin calls. 8770 for (i = 0; (rule = rsRules[i]); i++) { 8771 if (rule.type === 'MixinCall') { 8772 /* jshint loopfunc:true */ 8773 rules = rule.eval(context).filter(function(r) { 8774 if ((r instanceof Declaration) && r.variable) { 8775 // do not pollute the scope if the variable is 8776 // already there. consider returning false here 8777 // but we need a way to "return" variable from mixins 8778 return !(ruleset.variable(r.name)); 8779 } 8780 return true; 8781 }); 8782 rsRules.splice.apply(rsRules, [i, 1].concat(rules)); 8783 i += rules.length - 1; 8784 ruleset.resetCache(); 8785 } else if (rule.type === 'VariableCall') { 8786 /* jshint loopfunc:true */ 8787 rules = rule.eval(context).rules.filter(function(r) { 8788 if ((r instanceof Declaration) && r.variable) { 8789 // do not pollute the scope at all 8790 return false; 8791 } 8792 return true; 8793 }); 8794 rsRules.splice.apply(rsRules, [i, 1].concat(rules)); 8795 i += rules.length - 1; 8796 ruleset.resetCache(); 8797 } 8798 } 8799 8800 // Evaluate everything else 8801 for (i = 0; (rule = rsRules[i]); i++) { 8802 if (!rule.evalFirst) { 8803 rsRules[i] = rule = rule.eval ? rule.eval(context) : rule; 8804 } 8805 } 8806 8807 // Evaluate everything else 8808 for (i = 0; (rule = rsRules[i]); i++) { 8809 // for rulesets, check if it is a css guard and can be removed 8810 if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) { 8811 // check if it can be folded in (e.g. & where) 8812 if (rule.selectors[0].isJustParentSelector()) { 8813 rsRules.splice(i--, 1); 8814 8815 for (var j = 0; (subRule = rule.rules[j]); j++) { 8816 if (subRule instanceof Node) { 8817 subRule.copyVisibilityInfo(rule.visibilityInfo()); 8818 if (!(subRule instanceof Declaration) || !subRule.variable) { 8819 rsRules.splice(++i, 0, subRule); 8820 } 8821 } 8822 } 8823 } 8824 } 8825 } 8826 8827 // Pop the stack 8828 ctxFrames.shift(); 8829 ctxSelectors.shift(); 8830 8831 if (context.mediaBlocks) { 8832 for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) { 8833 context.mediaBlocks[i].bubbleSelectors(selectors); 8834 } 8835 } 8836 8837 return ruleset; 8838}; 8839Ruleset.prototype.evalImports = function(context) { 8840 var rules = this.rules, i, importRules; 8841 if (!rules) { return; } 8842 8843 for (i = 0; i < rules.length; i++) { 8844 if (rules[i].type === 'Import') { 8845 importRules = rules[i].eval(context); 8846 if (importRules && (importRules.length || importRules.length === 0)) { 8847 rules.splice.apply(rules, [i, 1].concat(importRules)); 8848 i += importRules.length - 1; 8849 } else { 8850 rules.splice(i, 1, importRules); 8851 } 8852 this.resetCache(); 8853 } 8854 } 8855}; 8856Ruleset.prototype.makeImportant = function() { 8857 var result = new Ruleset(this.selectors, this.rules.map(function (r) { 8858 if (r.makeImportant) { 8859 return r.makeImportant(); 8860 } else { 8861 return r; 8862 } 8863 }), this.strictImports, this.visibilityInfo()); 8864 8865 return result; 8866}; 8867Ruleset.prototype.matchArgs = function (args) { 8868 return !args || args.length === 0; 8869}; 8870// lets you call a css selector with a guard 8871Ruleset.prototype.matchCondition = function (args, context) { 8872 var lastSelector = this.selectors[this.selectors.length - 1]; 8873 if (!lastSelector.evaldCondition) { 8874 return false;
8875 } 8876 if (lastSelector.condition && 8877 !lastSelector.condition.eval( 8878 new contexts.Eval(context, 8879 context.frames))) { 8880 return false; 8881 } 8882 return true; 8883}; 8884Ruleset.prototype.resetCache = function () { 8885 this._rulesets = null; 8886 this._variables = null; 8887 this._properties = null; 8888 this._lookups = {}; 8889}; 8890Ruleset.prototype.variables = function () { 8891 if (!this._variables) { 8892 this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) { 8893 if (r instanceof Declaration && r.variable === true) { 8894 hash[r.name] = r; 8895 } 8896 // when evaluating variables in an import statement, imports have not been eval'd 8897 // so we need to go inside import statements. 8898 // guard against root being a string (in the case of inlined less) 8899 if (r.type === 'Import' && r.root && r.root.variables) { 8900 var vars = r.root.variables(); 8901 for (var name in vars) { 8902 if (vars.hasOwnProperty(name)) { 8903 hash[name] = vars[name]; 8904 } 8905 } 8906 } 8907 return hash; 8908 }, {}); 8909 } 8910 return this._variables; 8911}; 8912Ruleset.prototype.properties = function () { 8913 if (!this._properties) { 8914 this._properties = !this.rules ? {} : this.rules.reduce(function (hash, r) { 8915 if (r instanceof Declaration && r.variable !== true) { 8916 var name = (r.name.length === 1) && (r.name[0] instanceof Keyword) ? 8917 r.name[0].value : r.name; 8918 // Properties don't overwrite as they can merge 8919 if (!hash['$' + name]) { 8920 hash['$' + name] = [ r ]; 8921 } 8922 else { 8923 hash['$' + name].push(r); 8924 } 8925 } 8926 return hash; 8927 }, {}); 8928 } 8929 return this._properties; 8930}; 8931Ruleset.prototype.variable = function (name) { 8932 var decl = this.variables()[name]; 8933 if (decl) { 8934 return this.parseValue(decl); 8935 } 8936}; 8937Ruleset.prototype.property = function (name) { 8938 var decl = this.properties()[name]; 8939 if (decl) { 8940 return this.parseValue(decl); 8941 } 8942}; 8943Ruleset.prototype.parseValue = function(toParse) { 8944 var self = this; 8945 function transformDeclaration(decl) { 8946 if (decl.value instanceof Anonymous && !decl.parsed) { 8947 if (typeof decl.value.value === 'string') { 8948 this.parse.parseNode( 8949 decl.value.value, 8950 ['value', 'important'], 8951 decl.value.getIndex(), 8952 decl.fileInfo(), 8953 function(err, result) { 8954 if (err) { 8955 decl.parsed = true; 8956 } 8957 if (result) { 8958 decl.value = result[0]; 8959 decl.important = result[1] || ''; 8960 decl.parsed = true; 8961 } 8962 }); 8963 } else { 8964 decl.parsed = true; 8965 } 8966 8967 return decl; 8968 } 8969 else { 8970 return decl; 8971 } 8972 } 8973 if (!Array.isArray(toParse)) { 8974 return transformDeclaration.call(self, toParse); 8975 } 8976 else { 8977 var nodes = []; 8978 toParse.forEach(function(n) { 8979 nodes.push(transformDeclaration.call(self, n)); 8980 }); 8981 return nodes; 8982 } 8983}; 8984Ruleset.prototype.rulesets = function () { 8985 if (!this.rules) { return []; } 8986 8987 var filtRules = [], rules = this.rules, 8988 i, rule; 8989 8990 for (i = 0; (rule = rules[i]); i++) { 8991 if (rule.isRuleset) { 8992 filtRules.push(rule); 8993 } 8994 } 8995 8996 return filtRules; 8997}; 8998Ruleset.prototype.prependRule = function (rule) { 8999 var rules = this.rules; 9000 if (rules) { 9001 rules.unshift(rule); 9002 } else { 9003 this.rules = [ rule ]; 9004 } 9005 this.setParent(rule, this); 9006}; 9007Ruleset.prototype.find = function (selector, self, filter) { 9008 self = self || this; 9009 var rules = [], match, foundMixins, 9010 key = selector.toCSS(); 9011 9012 if (key in this._lookups) { return this._lookups[key]; } 9013
9014 this.rulesets().forEach(function (rule) { 9015 if (rule !== self) { 9016 for (var j = 0; j < rule.selectors.length; j++) { 9017 match = selector.match(rule.selectors[j]); 9018 if (match) { 9019 if (selector.elements.length > match) { 9020 if (!filter || filter(rule)) { 9021 foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter); 9022 for (var i = 0; i < foundMixins.length; ++i) { 9023 foundMixins[i].path.push(rule); 9024 } 9025 Array.prototype.push.apply(rules, foundMixins); 9026 } 9027 } else { 9028 rules.push({ rule: rule, path: []}); 9029 } 9030 break; 9031 } 9032 } 9033 } 9034 }); 9035 this._lookups[key] = rules; 9036 return rules; 9037}; 9038Ruleset.prototype.genCSS = function (context, output) { 9039 var i, j, 9040 charsetRuleNodes = [], 9041 ruleNodes = [], 9042 debugInfo, // Line number debugging 9043 rule, 9044 path; 9045 9046 context.tabLevel = (context.tabLevel || 0); 9047 9048 if (!this.root) { 9049 context.tabLevel++; 9050 } 9051 9052 var tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' '), 9053 tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' '), 9054 sep; 9055 9056 var charsetNodeIndex = 0; 9057 var importNodeIndex = 0; 9058 for (i = 0; (rule = this.rules[i]); i++) { 9059 if (rule instanceof Comment) { 9060 if (importNodeIndex === i) { 9061 importNodeIndex++; 9062 } 9063 ruleNodes.push(rule); 9064 } else if (rule.isCharset && rule.isCharset()) { 9065 ruleNodes.splice(charsetNodeIndex, 0, rule); 9066 charsetNodeIndex++; 9067 importNodeIndex++; 9068 } else if (rule.type === 'Import') { 9069 ruleNodes.splice(importNodeIndex, 0, rule); 9070 importNodeIndex++; 9071 } else { 9072 ruleNodes.push(rule); 9073 } 9074 } 9075 ruleNodes = charsetRuleNodes.concat(ruleNodes); 9076 9077 // If this is the root node, we don't render 9078 // a selector, or {}. 9079 if (!this.root) { 9080 debugInfo = getDebugInfo(context, this, tabSetStr); 9081 9082 if (debugInfo) { 9083 output.add(debugInfo); 9084 output.add(tabSetStr); 9085 } 9086 9087 var paths = this.paths, pathCnt = paths.length, 9088 pathSubCnt; 9089 9090 sep = context.compress ? ',' : (',\n' + tabSetStr); 9091 9092 for (i = 0; i < pathCnt; i++) { 9093 path = paths[i]; 9094 if (!(pathSubCnt = path.length)) { continue; } 9095 if (i > 0) { output.add(sep); } 9096 9097 context.firstSelector = true; 9098 path[0].genCSS(context, output); 9099 9100 context.firstSelector = false; 9101 for (j = 1; j < pathSubCnt; j++) { 9102 path[j].genCSS(context, output); 9103 } 9104 } 9105 9106 output.add((context.compress ? '{' : ' {\n') + tabRuleStr); 9107 } 9108 9109 // Compile rules and rulesets 9110 for (i = 0; (rule = ruleNodes[i]); i++) { 9111 9112 if (i + 1 === ruleNodes.length) { 9113 context.lastRule = true; 9114 } 9115 9116 var currentLastRule = context.lastRule; 9117 if (rule.isRulesetLike(rule)) { 9118 context.lastRule = false; 9119 } 9120 9121 if (rule.genCSS) { 9122 rule.genCSS(context, output); 9123 } else if (rule.value) { 9124 output.add(rule.value.toString()); 9125 } 9126 9127 context.lastRule = currentLastRule; 9128 9129 if (!context.lastRule && rule.isVisible()) { 9130 output.add(context.compress ? '' : ('\n' + tabRuleStr)); 9131 } else { 9132 context.lastRule = false; 9133 } 9134 } 9135 9136 if (!this.root) { 9137 output.add((context.compress ? '}' : '\n' + tabSetStr + '}')); 9138 context.tabLevel--; 9139 } 9140 9141 if (!output.isEmpty() && !context.compress && this.firstRoot) { 9142 output.add('\n'); 9143 } 9144}; 9145
9146Ruleset.prototype.joinSelectors = function (paths, context, selectors) { 9147 for (var s = 0; s < selectors.length; s++) { 9148 this.joinSelector(paths, context, selectors[s]); 9149 } 9150}; 9151 9152Ruleset.prototype.joinSelector = function (paths, context, selector) { 9153 9154 function createParenthesis(elementsToPak, originalElement) { 9155 var replacementParen, j; 9156 if (elementsToPak.length === 0) { 9157 replacementParen = new Paren(elementsToPak[0]); 9158 } else { 9159 var insideParent = new Array(elementsToPak.length); 9160 for (j = 0; j < elementsToPak.length; j++) { 9161 insideParent[j] = new Element(null, elementsToPak[j], originalElement._index, originalElement._fileInfo); 9162 } 9163 replacementParen = new Paren(new Selector(insideParent)); 9164 } 9165 return replacementParen; 9166 } 9167 9168 function createSelector(containedElement, originalElement) { 9169 var element, selector; 9170 element = new Element(null, containedElement, originalElement._index, originalElement._fileInfo); 9171 selector = new Selector([element]); 9172 return selector; 9173 } 9174 9175 // joins selector path from `beginningPath` with selector path in `addPath` 9176 // `replacedElement` contains element that is being replaced by `addPath` 9177 // returns concatenated path 9178 function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) { 9179 var newSelectorPath, lastSelector, newJoinedSelector; 9180 // our new selector path 9181 newSelectorPath = []; 9182 9183 // construct the joined selector - if & is the first thing this will be empty, 9184 // if not newJoinedSelector will be the last set of elements in the selector 9185 if (beginningPath.length > 0) { 9186 newSelectorPath = utils.copyArray(beginningPath); 9187 lastSelector = newSelectorPath.pop(); 9188 newJoinedSelector = originalSelector.createDerived(utils.copyArray(lastSelector.elements)); 9189 } 9190 else { 9191 newJoinedSelector = originalSelector.createDerived([]); 9192 } 9193 9194 if (addPath.length > 0) { 9195 // /deep/ is a combinator that is valid without anything in front of it 9196 // so if the & does not have a combinator that is "" or " " then 9197 // and there is a combinator on the parent, then grab that. 9198 // this also allows + a { & .b { .a & { ... though not sure why you would want to do that 9199 var combinator = replacedElement.combinator, parentEl = addPath[0].elements[0]; 9200 if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) { 9201 combinator = parentEl.combinator; 9202 } 9203 // join the elements so far with the first part of the parent 9204 newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement._index, replacedElement._fileInfo)); 9205 newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1)); 9206 } 9207 9208 // now add the joined selector - but only if it is not empty 9209 if (newJoinedSelector.elements.length !== 0) { 9210 newSelectorPath.push(newJoinedSelector); 9211 } 9212 9213 // put together the parent selectors after the join (e.g. the rest of the parent) 9214 if (addPath.length > 1) { 9215 var restOfPath = addPath.slice(1); 9216 restOfPath = restOfPath.map(function (selector) { 9217 return selector.createDerived(selector.elements, []); 9218 }); 9219 newSelectorPath = newSelectorPath.concat(restOfPath); 9220 } 9221 return newSelectorPath; 9222 } 9223 9224 // joins selector path from `beginningPath` with every selector path in `addPaths` array 9225 // `replacedElement` contains element that is being replaced by `addPath` 9226 // returns array with all concatenated paths 9227 function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) { 9228 var j; 9229 for (j = 0; j < beginningPath.length; j++) { 9230 var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector); 9231 result.push(newSelectorPath); 9232 } 9233 return result; 9234 } 9235 9236 function mergeElementsOnToSelectors(elements, selectors) { 9237 var i, sel; 9238 9239 if (elements.length === 0) { 9240 return ; 9241 } 9242 if (selectors.length === 0) { 9243 selectors.push([ new Selector(elements) ]); 9244 return; 9245 } 9246 9247 for (i = 0; (sel = selectors[i]); i++) { 9248 // if the previous thing in sel is a parent this needs to join on to it 9249 if (sel.length > 0) { 9250 sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements)); 9251 } 9252 else { 9253 sel.push(new Selector(elements)); 9254 } 9255 } 9256 } 9257 9258 // replace all parent selectors inside `inSelector` by content of `context` array 9259 // resulting selectors are returned inside `paths` array 9260 // returns true if `inSelector` contained at least one parent selector
9261 function replaceParentSelector(paths, context, inSelector) { 9262 // The paths are [[Selector]] 9263 // The first list is a list of comma separated selectors 9264 // The inner list is a list of inheritance separated selectors 9265 // e.g. 9266 // .a, .b { 9267 // .c { 9268 // } 9269 // } 9270 // == [[.a] [.c]] [[.b] [.c]] 9271 // 9272 var i, j, k, currentElements, newSelectors, selectorsMultiplied, sel, el, hadParentSelector = false, length, lastSelector; 9273 function findNestedSelector(element) { 9274 var maybeSelector; 9275 if (!(element.value instanceof Paren)) { 9276 return null; 9277 } 9278 9279 maybeSelector = element.value.value; 9280 if (!(maybeSelector instanceof Selector)) { 9281 return null; 9282 } 9283 9284 return maybeSelector; 9285 } 9286 9287 // the elements from the current selector so far 9288 currentElements = []; 9289 // the current list of new selectors to add to the path. 9290 // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors 9291 // by the parents 9292 newSelectors = [ 9293 [] 9294 ]; 9295 9296 for (i = 0; (el = inSelector.elements[i]); i++) { 9297 // non parent reference elements just get added 9298 if (el.value !== '&') { 9299 var nestedSelector = findNestedSelector(el); 9300 if (nestedSelector != null) { 9301 // merge the current list of non parent selector elements 9302 // on to the current list of selectors to add 9303 mergeElementsOnToSelectors(currentElements, newSelectors); 9304 9305 var nestedPaths = [], replaced, replacedNewSelectors = []; 9306 replaced = replaceParentSelector(nestedPaths, context, nestedSelector); 9307 hadParentSelector = hadParentSelector || replaced; 9308 // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors 9309 for (k = 0; k < nestedPaths.length; k++) { 9310 var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el); 9311 addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors); 9312 } 9313 newSelectors = replacedNewSelectors; 9314 currentElements = []; 9315 9316 } else { 9317 currentElements.push(el); 9318 } 9319 9320 } else { 9321 hadParentSelector = true; 9322 // the new list of selectors to add 9323 selectorsMultiplied = []; 9324 9325 // merge the current list of non parent selector elements 9326 // on to the current list of selectors to add 9327 mergeElementsOnToSelectors(currentElements, newSelectors); 9328 9329 // loop through our current selectors 9330 for (j = 0; j < newSelectors.length; j++) { 9331 sel = newSelectors[j]; 9332 // if we don't have any parent paths, the & might be in a mixin so that it can be used 9333 // whether there are parents or not 9334 if (context.length === 0) { 9335 // the combinator used on el should now be applied to the next element instead so that 9336 // it is not lost 9337 if (sel.length > 0) { 9338 sel[0].elements.push(new Element(el.combinator, '', el._index, el._fileInfo)); 9339 } 9340 selectorsMultiplied.push(sel); 9341 } 9342 else { 9343 // and the parent selectors 9344 for (k = 0; k < context.length; k++) { 9345 // We need to put the current selectors 9346 // then join the last selector's elements on to the parents selectors 9347 var newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector); 9348 // add that to our new set of selectors 9349 selectorsMultiplied.push(newSelectorPath); 9350 } 9351 } 9352 } 9353 9354 // our new selectors has been multiplied, so reset the state 9355 newSelectors = selectorsMultiplied; 9356 currentElements = []; 9357 } 9358 } 9359 9360 // if we have any elements left over (e.g. .a& .b == .b) 9361 // add them on to all the current selectors 9362 mergeElementsOnToSelectors(currentElements, newSelectors); 9363 9364 for (i = 0; i < newSelectors.length; i++) { 9365 length = newSelectors[i].length; 9366 if (length > 0) { 9367 paths.push(newSelectors[i]); 9368 lastSelector = newSelectors[i][length - 1]; 9369 newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList); 9370 } 9371 } 9372 9373 return hadParentSelector; 9374 } 9375 9376 function deriveSelector(visibilityInfo, deriveFrom) { 9377 var newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition); 9378 newSelector.copyVisibilityInfo(visibilityInfo); 9379 return newSelector; 9380 } 9381 9382 // joinSelector code follows 9383 var i, newPaths, hadParentSelector; 9384 9385 newPaths = []; 9386 hadParentSelector = replaceParentSelector(newPaths, context, selector); 9387 9388 if (!hadParentSelector) { 9389 if (context.length > 0) { 9390 newPaths = []; 9391 for (i = 0; i < context.length; i++) { 9392 9393 var concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo())); 9394 9395 concatenated.push(selector); 9396 newPaths.push(concatenated); 9397 } 9398 } 9399 else { 9400 newPaths = [[selector]]; 9401 } 9402 } 9403 9404 for (i = 0; i < newPaths.length; i++) { 9405 paths.push(newPaths[i]); 9406 } 9407 9408}; 9409module.exports = Ruleset; 9410 9411},{"../contexts":12,"../functions/default":24,"../functions/function-registry":26,"../utils":86,"./anonymous":48,"./comment":55,"./debug-info":57,"./declaration":58,"./element":61,"./keyword":68,"./node":73,"./paren":75,"./selector":79}],79:[function(require,module,exports){ 9412var Node = require('./node'), 9413 Element = require('./element'), 9414 LessError = require('../less-error'); 9415 9416var Selector = function (elements, extendList, condition, index, currentFileInfo, visibilityInfo) { 9417 this.extendList = extendList; 9418 this.condition = condition; 9419 this.evaldCondition = !condition; 9420 this._index = index; 9421 this._fileInfo = currentFileInfo; 9422 this.elements = this.getElements(elements); 9423 this.mixinElements_ = undefined; 9424 this.copyVisibilityInfo(visibilityInfo); 9425 this.setParent(this.elements, this); 9426}; 9427Selector.prototype = new Node(); 9428Selector.prototype.type = 'Selector'; 9429Selector.prototype.accept = function (visitor) { 9430 if (this.elements) { 9431 this.elements = visitor.visitArray(this.elements); 9432 } 9433 if (this.extendList) { 9434 this.extendList = visitor.visitArray(this.extendList); 9435 } 9436 if (this.condition) { 9437 this.condition = visitor.visit(this.condition); 9438 } 9439}; 9440Selector.prototype.createDerived = function(elements, extendList, evaldCondition) { 9441 elements = this.getElements(elements); 9442 var newSelector = new Selector(elements, extendList || this.extendList, 9443 null, this.getIndex(), this.fileInfo(), this.visibilityInfo()); 9444 newSelector.evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition; 9445 newSelector.mediaEmpty = this.mediaEmpty; 9446 return newSelector; 9447}; 9448Selector.prototype.getElements = function(els) { 9449 if (typeof els === 'string') { 9450 this.parse.parseNode( 9451 els, 9452 ['selector'], 9453 this._index, 9454 this._fileInfo, 9455 function(err, result) { 9456 if (err) { 9457 throw new LessError({ 9458 index: err.index, 9459 message: err.message 9460 }, this.parse.imports, this._fileInfo.filename); 9461 } 9462 els = result[0].elements; 9463 }); 9464 } 9465 return els; 9466}; 9467Selector.prototype.createEmptySelectors = function() { 9468 var el = new Element('', '&', this._index, this._fileInfo), 9469 sels = [new Selector([el], null, null, this._index, this._fileInfo)]; 9470 sels[0].mediaEmpty = true; 9471 return sels; 9472}; 9473Selector.prototype.match = function (other) { 9474 var elements = this.elements, 9475 len = elements.length, 9476 olen, i; 9477 9478 other = other.mixinElements(); 9479 olen = other.length; 9480 if (olen === 0 || len < olen) { 9481 return 0; 9482 } else { 9483 for (i = 0; i < olen; i++) { 9484 if (elements[i].value !== other[i]) { 9485 return 0; 9486 } 9487 } 9488 } 9489 9490 return olen; // return number of matched elements 9491}; 9492Selector.prototype.mixinElements = function() { 9493 if (this.mixinElements_) { 9494 return this.mixinElements_; 9495 } 9496 9497 var elements = this.elements.map( function(v) { 9498 return v.combinator.value + (v.value.value || v.value); 9499 }).join('').match(/[,&#\*\.\w-]([\w-]|(\\.))*/g); 9500 9501 if (elements) { 9502 if (elements[0] === '&') { 9503 elements.shift(); 9504 } 9505 } else { 9506 elements = []; 9507 } 9508 9509 return (this.mixinElements_ = elements); 9510}; 9511Selector.prototype.isJustParentSelector = function() { 9512 return !this.mediaEmpty && 9513 this.elements.length === 1 && 9514 this.elements[0].value === '&' && 9515 (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === ''); 9516}; 9517Selector.prototype.eval = function (context) { 9518 var evaldCondition = this.condition && this.condition.eval(context), 9519 elements = this.elements, extendList = this.extendList; 9520 9521 elements = elements && elements.map(function (e) { return e.eval(context); }); 9522 extendList = extendList && extendList.map(function(extend) { return extend.eval(context); }); 9523 9524 return this.createDerived(elements, extendList, evaldCondition); 9525}; 9526Selector.prototype.genCSS = function (context, output) { 9527 var i, element; 9528 if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') { 9529 output.add(' ', this.fileInfo(), this.getIndex()); 9530 } 9531 for (i = 0; i < this.elements.length; i++) { 9532 element = this.elements[i]; 9533 element.genCSS(context, output); 9534 } 9535}; 9536Selector.prototype.getIsOutput = function() { 9537 return this.evaldCondition; 9538}; 9539module.exports = Selector; 9540 9541},{"../less-error":36,"./element":61,"./node":73}],80:[function(require,module,exports){ 9542var Node = require('./node'); 9543
9544var UnicodeDescriptor = function (value) { 9545 this.value = value; 9546}; 9547UnicodeDescriptor.prototype = new Node(); 9548UnicodeDescriptor.prototype.type = 'UnicodeDescriptor'; 9549 9550module.exports = UnicodeDescriptor; 9551 9552},{"./node":73}],81:[function(require,module,exports){ 9553var Node = require('./node'), 9554 unitConversions = require('../data/unit-conversions'), 9555 utils = require('../utils'); 9556 9557var Unit = function (numerator, denominator, backupUnit) { 9558 this.numerator = numerator ? utils.copyArray(numerator).sort() : []; 9559 this.denominator = denominator ? utils.copyArray(denominator).sort() : []; 9560 if (backupUnit) { 9561 this.backupUnit = backupUnit; 9562 } else if (numerator && numerator.length) { 9563 this.backupUnit = numerator[0]; 9564 } 9565}; 9566 9567Unit.prototype = new Node(); 9568Unit.prototype.type = 'Unit'; 9569Unit.prototype.clone = function () { 9570 return new Unit(utils.copyArray(this.numerator), utils.copyArray(this.denominator), this.backupUnit); 9571}; 9572Unit.prototype.genCSS = function (context, output) { 9573 // Dimension checks the unit is singular and throws an error if in strict math mode. 9574 var strictUnits = context && context.strictUnits; 9575 if (this.numerator.length === 1) { 9576 output.add(this.numerator[0]); // the ideal situation 9577 } else if (!strictUnits && this.backupUnit) { 9578 output.add(this.backupUnit); 9579 } else if (!strictUnits && this.denominator.length) { 9580 output.add(this.denominator[0]); 9581 } 9582}; 9583Unit.prototype.toString = function () { 9584 var i, returnStr = this.numerator.join('*'); 9585 for (i = 0; i < this.denominator.length; i++) { 9586 returnStr += '/' + this.denominator[i]; 9587 } 9588 return returnStr; 9589}; 9590Unit.prototype.compare = function (other) { 9591 return this.is(other.toString()) ? 0 : undefined; 9592}; 9593Unit.prototype.is = function (unitString) { 9594 return this.toString().toUpperCase() === unitString.toUpperCase(); 9595}; 9596Unit.prototype.isLength = function () { 9597 return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS()); 9598}; 9599Unit.prototype.isEmpty = function () { 9600 return this.numerator.length === 0 && this.denominator.length === 0; 9601}; 9602Unit.prototype.isSingular = function() { 9603 return this.numerator.length <= 1 && this.denominator.length === 0; 9604}; 9605Unit.prototype.map = function(callback) { 9606 var i; 9607 9608 for (i = 0; i < this.numerator.length; i++) { 9609 this.numerator[i] = callback(this.numerator[i], false); 9610 } 9611 9612 for (i = 0; i < this.denominator.length; i++) { 9613 this.denominator[i] = callback(this.denominator[i], true); 9614 } 9615}; 9616Unit.prototype.usedUnits = function() { 9617 var group, result = {}, mapUnit, groupName; 9618 9619 mapUnit = function (atomicUnit) { 9620 /* jshint loopfunc:true */ 9621 if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { 9622 result[groupName] = atomicUnit; 9623 } 9624 9625 return atomicUnit; 9626 }; 9627 9628 for (groupName in unitConversions) { 9629 if (unitConversions.hasOwnProperty(groupName)) { 9630 group = unitConversions[groupName]; 9631 9632 this.map(mapUnit); 9633 } 9634 } 9635 9636 return result; 9637}; 9638Unit.prototype.cancel = function () { 9639 var counter = {}, atomicUnit, i; 9640 9641 for (i = 0; i < this.numerator.length; i++) { 9642 atomicUnit = this.numerator[i]; 9643 counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; 9644 } 9645 9646 for (i = 0; i < this.denominator.length; i++) { 9647 atomicUnit = this.denominator[i]; 9648 counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; 9649 } 9650 9651 this.numerator = []; 9652 this.denominator = []; 9653 9654 for (atomicUnit in counter) { 9655 if (counter.hasOwnProperty(atomicUnit)) { 9656 var count = counter[atomicUnit]; 9657 9658 if (count > 0) { 9659 for (i = 0; i < count; i++) { 9660 this.numerator.push(atomicUnit); 9661 } 9662 } else if (count < 0) { 9663 for (i = 0; i < -count; i++) { 9664 this.denominator.push(atomicUnit); 9665 } 9666 } 9667 } 9668 } 9669 9670 this.numerator.sort(); 9671 this.denominator.sort(); 9672}; 9673module.exports = Unit; 9674 9675},{"../data/unit-conversions":15,"../utils":86,"./node":73}],82:[function(require,module,exports){ 9676var Node = require('./node'); 9677 9678var URL = function (val, index, currentFileInfo, isEvald) { 9679 this.value = val; 9680 this._index = index; 9681 this._fileInfo = currentFileInfo; 9682 this.isEvald = isEvald; 9683}; 9684URL.prototype = new Node(); 9685URL.prototype.type = 'Url'; 9686URL.prototype.accept = function (visitor) { 9687 this.value = visitor.visit(this.value); 9688}; 9689URL.prototype.genCSS = function (context, output) { 9690 output.add('url('); 9691 this.value.genCSS(context, output); 9692 output.add(')'); 9693}; 9694URL.prototype.eval = function (context) { 9695 var val = this.value.eval(context), 9696 rootpath; 9697 9698 if (!this.isEvald) { 9699 // Add the base path if the URL is relative 9700 rootpath = this.fileInfo() && this.fileInfo().rootpath; 9701 if (rootpath && 9702 typeof val.value === 'string' &&
9703 context.isPathRelative(val.value)) { 9704 9705 if (!val.quote) { 9706 rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return '\\' + match; }); 9707 } 9708 val.value = rootpath + val.value; 9709 } 9710 9711 val.value = context.normalizePath(val.value); 9712 9713 // Add url args if enabled 9714 if (context.urlArgs) { 9715 if (!val.value.match(/^\s*data:/)) { 9716 var delimiter = val.value.indexOf('?') === -1 ? '?' : '&'; 9717 var urlArgs = delimiter + context.urlArgs; 9718 if (val.value.indexOf('#') !== -1) { 9719 val.value = val.value.replace('#', urlArgs + '#'); 9720 } else { 9721 val.value += urlArgs; 9722 } 9723 } 9724 } 9725 } 9726 9727 return new URL(val, this.getIndex(), this.fileInfo(), true); 9728}; 9729module.exports = URL; 9730 9731},{"./node":73}],83:[function(require,module,exports){ 9732var Node = require('./node'); 9733 9734var Value = function (value) { 9735 if (!value) { 9736 throw new Error('Value requires an array argument'); 9737 } 9738 if (!Array.isArray(value)) { 9739 this.value = [ value ]; 9740 } 9741 else { 9742 this.value = value; 9743 } 9744}; 9745Value.prototype = new Node(); 9746Value.prototype.type = 'Value'; 9747Value.prototype.accept = function (visitor) { 9748 if (this.value) { 9749 this.value = visitor.visitArray(this.value); 9750 } 9751}; 9752Value.prototype.eval = function (context) { 9753 if (this.value.length === 1) { 9754 return this.value[0].eval(context); 9755 } else { 9756 return new Value(this.value.map(function (v) { 9757 return v.eval(context); 9758 })); 9759 } 9760}; 9761Value.prototype.genCSS = function (context, output) { 9762 var i; 9763 for (i = 0; i < this.value.length; i++) { 9764 this.value[i].genCSS(context, output); 9765 if (i + 1 < this.value.length) { 9766 output.add((context && context.compress) ? ',' : ', '); 9767 } 9768 } 9769}; 9770module.exports = Value; 9771 9772},{"./node":73}],84:[function(require,module,exports){ 9773var Node = require('./node'), 9774 Variable = require('./variable'); 9775 9776var VariableCall = function (variable) { 9777 this.variable = variable; 9778 this.allowRoot = true; 9779}; 9780VariableCall.prototype = new Node(); 9781VariableCall.prototype.type = 'VariableCall'; 9782VariableCall.prototype.eval = function (context) { 9783 var detachedRuleset = new Variable(this.variable).eval(context); 9784 return detachedRuleset.callEval(context); 9785}; 9786module.exports = VariableCall; 9787 9788},{"./node":73,"./variable":85}],85:[function(require,module,exports){ 9789var Node = require('./node'); 9790 9791var Variable = function (name, index, currentFileInfo) { 9792 this.name = name; 9793 this._index = index; 9794 this._fileInfo = currentFileInfo; 9795}; 9796Variable.prototype = new Node(); 9797Variable.prototype.type = 'Variable'; 9798Variable.prototype.eval = function (context) { 9799 var variable, name = this.name; 9800 9801 if (name.indexOf('@@') === 0) { 9802 name = '@' + new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value; 9803 } 9804 9805 if (this.evaluating) { 9806 throw { type: 'Name', 9807 message: 'Recursive variable definition for ' + name, 9808 filename: this.fileInfo().filename, 9809 index: this.getIndex() }; 9810 } 9811 9812 this.evaluating = true; 9813 9814 variable = this.find(context.frames, function (frame) { 9815 var v = frame.variable(name); 9816 if (v) { 9817 if (v.important) { 9818 var importantScope = context.importantScope[context.importantScope.length - 1]; 9819 importantScope.important = v.important; 9820 } 9821 return v.value.eval(context); 9822 } 9823 }); 9824 if (variable) { 9825 this.evaluating = false; 9826 return variable; 9827 } else { 9828 throw { type: 'Name', 9829 message: 'variable ' + name + ' is undefined', 9830 filename: this.fileInfo().filename, 9831 index: this.getIndex() }; 9832 } 9833}; 9834Variable.prototype.find = function (obj, fun) { 9835 for (var i = 0, r; i < obj.length; i++) { 9836 r = fun.call(obj, obj[i]); 9837 if (r) { return r; } 9838 } 9839 return null; 9840}; 9841module.exports = Variable; 9842 9843},{"./node":73}],86:[function(require,module,exports){ 9844/* jshint proto: true */ 9845module.exports = { 9846 getLocation: function(index, inputStream) { 9847 var n = index + 1, 9848 line = null, 9849 column = -1; 9850 9851 while (--n >= 0 && inputStream.charAt(n) !== '\n') { 9852 column++; 9853 } 9854 9855 if (typeof index === 'number') { 9856 line = (inputStream.slice(0, index).match(/\n/g) || '').length; 9857 } 9858 9859 return { 9860 line: line, 9861 column: column 9862 }; 9863 }, 9864 copyArray: function(arr) { 9865 var i, length = arr.length, 9866 copy = new Array(length); 9867 9868 for (i = 0; i < length; i++) { 9869 copy[i] = arr[i]; 9870 } 9871 return copy; 9872 }, 9873 clone: function (obj) { 9874 var cloned = {}; 9875 for (var prop in obj) { 9876 if (obj.hasOwnProperty(prop)) { 9877 cloned[prop] = obj[prop]; 9878 } 9879 } 9880 return cloned; 9881 }, 9882 defaults: function(obj1, obj2) { 9883 if (!obj2._defaults || obj2._defaults !== obj1) { 9884 for (var prop in obj1) { 9885 if (obj1.hasOwnProperty(prop)) { 9886 if (!obj2.hasOwnProperty(prop)) { 9887 obj2[prop] = obj1[prop]; 9888 } 9889 else if (Array.isArray(obj1[prop]) 9890 && Array.isArray(obj2[prop])) { 9891
9892 obj1[prop].forEach(function(p) { 9893 if (obj2[prop].indexOf(p) === -1) { 9894 obj2[prop].push(p); 9895 } 9896 }); 9897 } 9898 } 9899 } 9900 } 9901 obj2._defaults = obj1; 9902 return obj2; 9903 }, 9904 merge: function(obj1, obj2) { 9905 for (var prop in obj2) { 9906 if (obj2.hasOwnProperty(prop)) { 9907 obj1[prop] = obj2[prop]; 9908 } 9909 } 9910 return obj1; 9911 } 9912}; 9913 9914},{}],87:[function(require,module,exports){ 9915var tree = require('../tree'), 9916 Visitor = require('./visitor'), 9917 logger = require('../logger'), 9918 utils = require('../utils'); 9919 9920/* jshint loopfunc:true */ 9921 9922var ExtendFinderVisitor = function() { 9923 this._visitor = new Visitor(this); 9924 this.contexts = []; 9925 this.allExtendsStack = [[]]; 9926}; 9927 9928ExtendFinderVisitor.prototype = { 9929 run: function (root) { 9930 root = this._visitor.visit(root); 9931 root.allExtends = this.allExtendsStack[0]; 9932 return root; 9933 }, 9934 visitDeclaration: function (declNode, visitArgs) { 9935 visitArgs.visitDeeper = false; 9936 }, 9937 visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { 9938 visitArgs.visitDeeper = false; 9939 }, 9940 visitRuleset: function (rulesetNode, visitArgs) { 9941 if (rulesetNode.root) { 9942 return; 9943 } 9944 9945 var i, j, extend, allSelectorsExtendList = [], extendList; 9946 9947 // get &:extend(.a); rules which apply to all selectors in this ruleset 9948 var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0; 9949 for (i = 0; i < ruleCnt; i++) { 9950 if (rulesetNode.rules[i] instanceof tree.Extend) { 9951 allSelectorsExtendList.push(rules[i]); 9952 rulesetNode.extendOnEveryPath = true; 9953 } 9954 } 9955 9956 // now find every selector and apply the extends that apply to all extends 9957 // and the ones which apply to an individual extend 9958 var paths = rulesetNode.paths; 9959 for (i = 0; i < paths.length; i++) { 9960 var selectorPath = paths[i], 9961 selector = selectorPath[selectorPath.length - 1], 9962 selExtendList = selector.extendList; 9963 9964 extendList = selExtendList ? utils.copyArray(selExtendList).concat(allSelectorsExtendList) 9965 : allSelectorsExtendList; 9966 9967 if (extendList) { 9968 extendList = extendList.map(function(allSelectorsExtend) { 9969 return allSelectorsExtend.clone(); 9970 }); 9971 } 9972 9973 for (j = 0; j < extendList.length; j++) { 9974 this.foundExtends = true; 9975 extend = extendList[j]; 9976 extend.findSelfSelectors(selectorPath); 9977 extend.ruleset = rulesetNode; 9978 if (j === 0) { extend.firstExtendOnThisSelectorPath = true; } 9979 this.allExtendsStack[this.allExtendsStack.length - 1].push(extend); 9980 } 9981 } 9982 9983 this.contexts.push(rulesetNode.selectors); 9984 }, 9985 visitRulesetOut: function (rulesetNode) { 9986 if (!rulesetNode.root) { 9987 this.contexts.length = this.contexts.length - 1; 9988 } 9989 }, 9990 visitMedia: function (mediaNode, visitArgs) { 9991 mediaNode.allExtends = []; 9992 this.allExtendsStack.push(mediaNode.allExtends); 9993 }, 9994 visitMediaOut: function (mediaNode) { 9995 this.allExtendsStack.length = this.allExtendsStack.length - 1; 9996 }, 9997 visitAtRule: function (atRuleNode, visitArgs) { 9998 atRuleNode.allExtends = []; 9999 this.allExtendsStack.push(atRuleNode.allExtends); 10000 }, 10001 visitAtRuleOut: function (atRuleNode) { 10002 this.allExtendsStack.length = this.allExtendsStack.length - 1; 10003 } 10004}; 10005 10006var ProcessExtendsVisitor = function() { 10007 this._visitor = new Visitor(this); 10008}; 10009 10010ProcessExtendsVisitor.prototype = { 10011 run: function(root) { 10012 var extendFinder = new ExtendFinderVisitor(); 10013 this.extendIndices = {}; 10014 extendFinder.run(root); 10015 if (!extendFinder.foundExtends) { return root; } 10016 root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); 10017 this.allExtendsStack = [root.allExtends]; 10018 var newRoot = this._visitor.visit(root); 10019 this.checkExtendsForNonMatched(root.allExtends); 10020 return newRoot; 10021 }, 10022 checkExtendsForNonMatched: function(extendList) { 10023 var indices = this.extendIndices; 10024 extendList.filter(function(extend) { 10025 return !extend.hasFoundMatches && extend.parent_ids.length == 1; 10026 }
10026).forEach(function(extend) { 10027 var selector = '_unknown_'; 10028 try { 10029 selector = extend.selector.toCSS({}); 10030 } 10031 catch (_) {} 10032 10033 if (!indices[extend.index + ' ' + selector]) { 10034 indices[extend.index + ' ' + selector] = true; 10035 logger.warn('extend \'' + selector + '\' has no matches'); 10036 } 10037 }); 10038 }, 10039 doExtendChaining: function (extendsList, extendsListTarget, iterationCount) { 10040 // 10041 // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering 10042 // and pasting the selector we would do normally, but we are also adding an extend with the same target selector 10043 // this means this new extend can then go and alter other extends 10044 // 10045 // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors 10046 // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already 10047 // processed if we look at each selector at a time, as is done in visitRuleset 10048 10049 var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, 10050 extend, targetExtend, newExtend; 10051 10052 iterationCount = iterationCount || 0; 10053 10054 // loop through comparing every extend with every target extend. 10055 // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place 10056 // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one 10057 // and the second is the target. 10058 // the separation into two lists allows us to process a subset of chains with a bigger set, as is the 10059 // case when processing media queries 10060 for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) { 10061 for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) { 10062 10063 extend = extendsList[extendIndex]; 10064 targetExtend = extendsListTarget[targetExtendIndex]; 10065 10066 // look for circular references 10067 if ( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ) { continue; } 10068 10069 // find a match in the target extends self selector (the bit before :extend) 10070 selectorPath = [targetExtend.selfSelectors[0]]; 10071 matches = extendVisitor.findMatch(extend, selectorPath); 10072 10073 if (matches.length) { 10074 extend.hasFoundMatches = true; 10075 10076 // we found a match, so for each self selector.. 10077 extend.selfSelectors.forEach(function(selfSelector) { 10078 var info = targetExtend.visibilityInfo(); 10079 10080 // process the extend as usual 10081 newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible()); 10082 10083 // but now we create a new extend from it 10084 newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0, targetExtend.fileInfo(), info); 10085 newExtend.selfSelectors = newSelector; 10086 10087 // add the extend onto the list of extends for that selector 10088 newSelector[newSelector.length - 1].extendList = [newExtend]; 10089 10090 // record that we need to add it. 10091 extendsToAdd.push(newExtend); 10092 newExtend.ruleset = targetExtend.ruleset; 10093 10094 // remember its parents for circular references 10095 newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids); 10096 10097 // only process the selector once.. if we have :extend(.a,.b) then multiple 10098 // extends will look at the same selector path, so when extending 10099 // we know that any others will be duplicates in terms of what is added to the css 10100 if (targetExtend.firstExtendOnThisSelectorPath) { 10101 newExtend.firstExtendOnThisSelectorPath = true; 10102 targetExtend.ruleset.paths.push(newSelector); 10103 } 10104 }); 10105 } 10106 } 10107 } 10108 10109 if (extendsToAdd.length) { 10110 // try to detect circular references to stop a stack overflow. 10111 // may no longer be needed. 10112 this.extendChainCount++; 10113 if (iterationCount > 100) { 10114 var selectorOne = '{unable to calculate}'; 10115 var selectorTwo = '{unable to calculate}'; 10116 try { 10117 selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); 10118 selectorTwo = extendsToAdd[0].selector.toCSS(); 10119 } 10120 catch (e) {} 10121 throw { message: 'extend circular reference detected. One of the circular extends is currently:' + 10122 selectorOne + ':extend(' + selectorTwo + ')'}; 10123 } 10124 10125 // now process the new extends on the existing rules so that we can handle a extending b extending c extending 10126 // d extending e... 10127 return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1)); 10128 } else { 10129 return extendsToAdd; 10130 } 10131 }, 10132 visitDeclaration: function (ruleNode, visitArgs) { 10133 visitArgs.visitDeeper = false;
10134 }, 10135 visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { 10136 visitArgs.visitDeeper = false; 10137 }, 10138 visitSelector: function (selectorNode, visitArgs) { 10139 visitArgs.visitDeeper = false; 10140 }, 10141 visitRuleset: function (rulesetNode, visitArgs) { 10142 if (rulesetNode.root) { 10143 return; 10144 } 10145 var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length - 1], 10146 selectorsToAdd = [], extendVisitor = this, selectorPath; 10147 10148 // look at each selector path in the ruleset, find any extend matches and then copy, find and replace 10149 10150 for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { 10151 for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { 10152 selectorPath = rulesetNode.paths[pathIndex]; 10153 10154 // extending extends happens initially, before the main pass 10155 if (rulesetNode.extendOnEveryPath) { continue; } 10156 var extendList = selectorPath[selectorPath.length - 1].extendList; 10157 if (extendList && extendList.length) { continue; } 10158 10159 matches = this.findMatch(allExtends[extendIndex], selectorPath); 10160 10161 if (matches.length) { 10162 allExtends[extendIndex].hasFoundMatches = true; 10163 10164 allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) { 10165 var extendedSelectors; 10166 extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible()); 10167 selectorsToAdd.push(extendedSelectors); 10168 }); 10169 } 10170 } 10171 } 10172 rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); 10173 }, 10174 findMatch: function (extend, haystackSelectorPath) { 10175 // 10176 // look through the haystack selector path to try and find the needle - extend.selector 10177 // returns an array of selector matches that can then be replaced 10178 // 10179 var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement, 10180 targetCombinator, i, 10181 extendVisitor = this, 10182 needleElements = extend.selector.elements, 10183 potentialMatches = [], potentialMatch, matches = []; 10184 10185 // loop through the haystack elements 10186 for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { 10187 hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; 10188 10189 for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { 10190 10191 haystackElement = hackstackSelector.elements[hackstackElementIndex]; 10192 10193 // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. 10194 if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) { 10195 potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, 10196 initialCombinator: haystackElement.combinator}); 10197 } 10198 10199 for (i = 0; i < potentialMatches.length; i++) { 10200 potentialMatch = potentialMatches[i]; 10201 10202 // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't 10203 // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to 10204 // work out what the resulting combinator will be 10205 targetCombinator = haystackElement.combinator.value; 10206 if (targetCombinator === '' && hackstackElementIndex === 0) { 10207 targetCombinator = ' '; 10208 } 10209 10210 // if we don't match, null our match to indicate failure 10211 if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || 10212 (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) { 10213 potentialMatch = null; 10214 } else { 10215 potentialMatch.matched++; 10216 } 10217 10218 // if we are still valid and have finished, test whether we have elements after and whether these are allowed 10219 if (potentialMatch) { 10220 potentialMatch.finished = potentialMatch.matched === needleElements.length; 10221 if (potentialMatch.finished && 10222 (!extend.allowAfter && 10223 (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length))) { 10224 potentialMatch = null; 10225 } 10226 } 10227 // if null we remove, if not, we are still valid, so either push as a valid match or continue 10228 if (potentialMatch) { 10229 if (potentialMatch.finished) { 10230 potentialMatch.length = needleElements.length; 10231 potentialMatch.endPathIndex = haystackSelectorIndex; 10232 potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match 10233 potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again 10234 matches.push(potentialMatch); 10235 } 10236 } else { 10237 potentialMatches.splice(i, 1); 10238 i--; 10239 } 10240 } 10241 } 10242 } 10243 return matches; 10244 }, 10245 isElementValuesEqual: function(elementValue1, elementValue2) { 10246 if (typeof elementValue1 === 'string' || typeof elementValue2 === 'string') { 10247 return elementValue1 === elementValue2; 10248 } 10249 if (elementValue1 instanceof tree.Attribute) { 10250 if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { 10251 return false;
10252 } 10253 if (!elementValue1.value || !elementValue2.value) { 10254 if (elementValue1.value || elementValue2.value) { 10255 return false; 10256 } 10257 return true; 10258 } 10259 elementValue1 = elementValue1.value.value || elementValue1.value; 10260 elementValue2 = elementValue2.value.value || elementValue2.value; 10261 return elementValue1 === elementValue2; 10262 } 10263 elementValue1 = elementValue1.value; 10264 elementValue2 = elementValue2.value; 10265 if (elementValue1 instanceof tree.Selector) { 10266 if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) { 10267 return false; 10268 } 10269 for (var i = 0; i < elementValue1.elements.length; i++) { 10270 if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) { 10271 if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) { 10272 return false; 10273 } 10274 } 10275 if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) { 10276 return false; 10277 } 10278 } 10279 return true; 10280 } 10281 return false; 10282 }, 10283 extendSelector:function (matches, selectorPath, replacementSelector, isVisible) { 10284 10285 // for a set of matches, replace each match with the replacement selector 10286 10287 var currentSelectorPathIndex = 0, 10288 currentSelectorPathElementIndex = 0, 10289 path = [], 10290 matchIndex, 10291 selector, 10292 firstElement, 10293 match, 10294 newElements; 10295 10296 for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { 10297 match = matches[matchIndex]; 10298 selector = selectorPath[match.pathIndex]; 10299 firstElement = new tree.Element( 10300 match.initialCombinator, 10301 replacementSelector.elements[0].value, 10302 replacementSelector.elements[0].getIndex(), 10303 replacementSelector.elements[0].fileInfo() 10304 ); 10305 10306 if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { 10307 path[path.length - 1].elements = path[path.length - 1] 10308 .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); 10309 currentSelectorPathElementIndex = 0; 10310 currentSelectorPathIndex++; 10311 } 10312 10313 newElements = selector.elements 10314 .slice(currentSelectorPathElementIndex, match.index) 10315 .concat([firstElement]) 10316 .concat(replacementSelector.elements.slice(1)); 10317 10318 if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) { 10319 path[path.length - 1].elements = 10320 path[path.length - 1].elements.concat(newElements); 10321 } else { 10322 path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); 10323 10324 path.push(new tree.Selector( 10325 newElements 10326 )); 10327 } 10328 currentSelectorPathIndex = match.endPathIndex; 10329 currentSelectorPathElementIndex = match.endPathElementIndex; 10330 if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) { 10331 currentSelectorPathElementIndex = 0; 10332 currentSelectorPathIndex++; 10333 } 10334 } 10335 10336 if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { 10337 path[path.length - 1].elements = path[path.length - 1] 10338 .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); 10339 currentSelectorPathIndex++; 10340 } 10341 10342 path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); 10343 path = path.map(function (currentValue) { 10344 // we can re-use elements here, because the visibility property matters only for selectors 10345 var derived = currentValue.createDerived(currentValue.elements); 10346 if (isVisible) { 10347 derived.ensureVisibility(); 10348 } else { 10349 derived.ensureInvisibility(); 10350 } 10351 return derived; 10352 }); 10353 return path; 10354 }, 10355 visitMedia: function (mediaNode, visitArgs) { 10356 var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); 10357 newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); 10358 this.allExtendsStack.push(newAllExtends); 10359 }, 10360 visitMediaOut: function (mediaNode) { 10361 var lastIndex = this.allExtendsStack.length - 1; 10362 this.allExtendsStack.length = lastIndex; 10363 }, 10364 visitAtRule: function (atRuleNode, visitArgs) { 10365 var newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); 10366 newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, atRuleNode.allExtends)); 10367 this.allExtendsStack.push(newAllExtends); 10368 }, 10369 visitAtRuleOut: function (atRuleNode) { 10370 var lastIndex = this.allExtendsStack.length - 1; 10371 this.allExtendsStack.length = lastIndex; 10372 } 10373}; 10374 10375module.exports = ProcessExtendsVisitor; 10376 10377},{"../logger":37,"../tree":65,"../utils":86,"./visitor":94}],88:[function(require,module,exports){ 10378function ImportSequencer(onSequencerEmpty) { 10379 this.imports = []; 10380 this.variableImports = []; 10381 this._onSequencerEmpty = onSequencerEmpty; 10382 this._currentDepth = 0; 10383} 10384 10385ImportSequencer.prototype.addImport = function(callback) { 10386 var importSequencer = this, 10387 importItem = { 10388 callback: callback, 10389 args: null, 10390 isReady: false 10391 }; 10392 this.imports.push(importItem); 10393 return function() { 10394 importItem.args = Array.prototype.slice.call(arguments, 0); 10395 importItem.isReady = true; 10396 importSequencer.tryRun(); 10397 }; 10398}; 10399 10400ImportSequencer.prototype.addVariableImport = function(callback) { 10401 this.variableImports.push(callback); 10402}; 10403 10404ImportSequencer.prototype.tryRun = function() { 10405 this._currentDepth++; 10406 try { 10407 while (true) { 10408 while (this.imports.length > 0) { 10409 var importItem = this.imports[0]; 10410 if (!importItem.isReady) { 10411 return; 10412 } 10413 this.imports = this.imports.slice(1); 10414 importItem.callback.apply(null, importItem.args); 10415 } 10416 if (this.variableImports.length === 0) { 10417 break; 10418 } 10419 var variableImport = this.variableImports[0]; 10420 this.variableImports = this.variableImports.slice(1); 10421 variableImport(); 10422 } 10423 } finally { 10424 this._currentDepth--; 10425 } 10426 if (this._currentDepth === 0 && this._onSequencerEmpty) { 10427 this._onSequencerEmpty(); 10428 } 10429}; 10430 10431module.exports = ImportSequencer; 10432 10433},{}],89:[function(require,module,exports){ 10434var contexts = require('../contexts'), 10435 Visitor = require('./visitor'), 10436 ImportSequencer = require('./import-sequencer'), 10437 utils = require('../utils'); 10438 10439var ImportVisitor = function(importer, finish) { 10440 10441 this._visitor = new Visitor(this); 10442 this._importer = importer; 10443 this._finish = finish; 10444 this.context = new contexts.Eval(); 10445 this.importCount = 0; 10446 this.onceFileDetectionMap = {}; 10447 this.recursionDetector = {}; 10448 this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this)); 10449}; 10450 10451ImportVisitor.prototype = { 10452 isReplacing: false, 10453 run: function (root) { 10454 try { 10455 // process the contents 10456 this._visitor.visit(root); 10457 } 10458 catch (e) { 10459 this.error = e; 10460 } 10461 10462 this.isFinished = true; 10463 this._sequencer.tryRun(); 10464 }, 10465 _onSequencerEmpty: function() { 10466 if (!this.isFinished) { 10467 return; 10468 } 10469 this._finish(this.error); 10470 }, 10471 visitImport: function (importNode, visitArgs) { 10472 var inlineCSS = importNode.options.inline; 10473 10474 if (!importNode.css || inlineCSS) { 10475 10476 var context = new contexts.Eval(this.context, utils.copyArray(this.context.frames)); 10477 var importParent = context.frames[0]; 10478 10479 this.importCount++; 10480 if (importNode.isVariableImport()) { 10481 this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent)); 10482 } else { 10483 this.processImportNode(importNode, context, importParent); 10484 } 10485 } 10486 visitArgs.visitDeeper = false;
10487 }, 10488 processImportNode: function(importNode, context, importParent) { 10489 var evaldImportNode, 10490 inlineCSS = importNode.options.inline; 10491 10492 try { 10493 evaldImportNode = importNode.evalForImport(context); 10494 } catch (e) { 10495 if (!e.filename) { e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename; } 10496 // attempt to eval properly and treat as css 10497 importNode.css = true; 10498 // if that fails, this error will be thrown 10499 importNode.error = e; 10500 } 10501 10502 if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) { 10503 10504 if (evaldImportNode.options.multiple) { 10505 context.importMultiple = true; 10506 } 10507 10508 // try appending if we haven't determined if it is css or not 10509 var tryAppendLessExtension = evaldImportNode.css === undefined; 10510 10511 for (var i = 0; i < importParent.rules.length; i++) { 10512 if (importParent.rules[i] === importNode) { 10513 importParent.rules[i] = evaldImportNode; 10514 break; 10515 } 10516 } 10517 10518 var onImported = this.onImported.bind(this, evaldImportNode, context), 10519 sequencedOnImported = this._sequencer.addImport(onImported); 10520 10521 this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(), 10522 evaldImportNode.options, sequencedOnImported); 10523 } else { 10524 this.importCount--; 10525 if (this.isFinished) { 10526 this._sequencer.tryRun(); 10527 } 10528 } 10529 }, 10530 onImported: function (importNode, context, e, root, importedAtRoot, fullPath) { 10531 if (e) { 10532 if (!e.filename) { 10533 e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename; 10534 } 10535 this.error = e; 10536 } 10537 10538 var importVisitor = this, 10539 inlineCSS = importNode.options.inline, 10540 isPlugin = importNode.options.isPlugin, 10541 isOptional = importNode.options.optional, 10542 duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector; 10543 10544 if (!context.importMultiple) { 10545 if (duplicateImport) { 10546 importNode.skip = true; 10547 } else { 10548 importNode.skip = function() { 10549 if (fullPath in importVisitor.onceFileDetectionMap) { 10550 return true; 10551 } 10552 importVisitor.onceFileDetectionMap[fullPath] = true; 10553 return false; 10554 }; 10555 } 10556 } 10557 10558 if (!fullPath && isOptional) { 10559 importNode.skip = true; 10560 } 10561 10562 if (root) { 10563 importNode.root = root; 10564 importNode.importedFilename = fullPath; 10565 10566 if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) { 10567 importVisitor.recursionDetector[fullPath] = true; 10568 10569 var oldContext = this.context; 10570 this.context = context; 10571 try { 10572 this._visitor.visit(root); 10573 } catch (e) { 10574 this.error = e; 10575 } 10576 this.context = oldContext; 10577 } 10578 } 10579 10580 importVisitor.importCount--; 10581 10582 if (importVisitor.isFinished) { 10583 importVisitor._sequencer.tryRun(); 10584 } 10585 }, 10586 visitDeclaration: function (declNode, visitArgs) { 10587 if (declNode.value.type === 'DetachedRuleset') { 10588 this.context.frames.unshift(declNode); 10589 } else { 10590 visitArgs.visitDeeper = false; 10591 } 10592 }, 10593 visitDeclarationOut: function(declNode) { 10594 if (declNode.value.type === 'DetachedRuleset') { 10595 this.context.frames.shift(); 10596 } 10597 }, 10598 visitAtRule: function (atRuleNode, visitArgs) { 10599 this.context.frames.unshift(atRuleNode); 10600 }, 10601 visitAtRuleOut: function (atRuleNode) { 10602 this.context.frames.shift(); 10603 }, 10604 visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { 10605 this.context.frames.unshift(mixinDefinitionNode); 10606 }, 10607 visitMixinDefinitionOut: function (mixinDefinitionNode) { 10608 this.context.frames.shift(); 10609 },
10610 visitRuleset: function (rulesetNode, visitArgs) { 10611 this.context.frames.unshift(rulesetNode); 10612 }, 10613 visitRulesetOut: function (rulesetNode) { 10614 this.context.frames.shift(); 10615 }, 10616 visitMedia: function (mediaNode, visitArgs) { 10617 this.context.frames.unshift(mediaNode.rules[0]); 10618 }, 10619 visitMediaOut: function (mediaNode) { 10620 this.context.frames.shift(); 10621 } 10622}; 10623module.exports = ImportVisitor; 10624 10625},{"../contexts":12,"../utils":86,"./import-sequencer":88,"./visitor":94}],90:[function(require,module,exports){ 10626var visitors = { 10627 Visitor: require('./visitor'), 10628 ImportVisitor: require('./import-visitor'), 10629 MarkVisibleSelectorsVisitor: require('./set-tree-visibility-visitor'), 10630 ExtendVisitor: require('./extend-visitor'), 10631 JoinSelectorVisitor: require('./join-selector-visitor'), 10632 ToCSSVisitor: require('./to-css-visitor') 10633}; 10634 10635module.exports = visitors; 10636 10637},{"./extend-visitor":87,"./import-visitor":89,"./join-selector-visitor":91,"./set-tree-visibility-visitor":92,"./to-css-visitor":93,"./visitor":94}],91:[function(require,module,exports){ 10638var Visitor = require('./visitor'); 10639 10640var JoinSelectorVisitor = function() { 10641 this.contexts = [[]]; 10642 this._visitor = new Visitor(this); 10643}; 10644 10645JoinSelectorVisitor.prototype = { 10646 run: function (root) { 10647 return this._visitor.visit(root); 10648 }, 10649 visitDeclaration: function (declNode, visitArgs) { 10650 visitArgs.visitDeeper = false; 10651 }, 10652 visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { 10653 visitArgs.visitDeeper = false; 10654 }, 10655 10656 visitRuleset: function (rulesetNode, visitArgs) { 10657 var context = this.contexts[this.contexts.length - 1], 10658 paths = [], selectors; 10659 10660 this.contexts.push(paths); 10661 10662 if (!rulesetNode.root) { 10663 selectors = rulesetNode.selectors; 10664 if (selectors) { 10665 selectors = selectors.filter(function(selector) { return selector.getIsOutput(); }); 10666 rulesetNode.selectors = selectors.length ? selectors : (selectors = null); 10667 if (selectors) { rulesetNode.joinSelectors(paths, context, selectors); } 10668 } 10669 if (!selectors) { rulesetNode.rules = null; } 10670 rulesetNode.paths = paths; 10671 } 10672 }, 10673 visitRulesetOut: function (rulesetNode) { 10674 this.contexts.length = this.contexts.length - 1; 10675 }, 10676 visitMedia: function (mediaNode, visitArgs) { 10677 var context = this.contexts[this.contexts.length - 1]; 10678 mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia); 10679 }, 10680 visitAtRule: function (atRuleNode, visitArgs) { 10681 var context = this.contexts[this.contexts.length - 1]; 10682 if (atRuleNode.rules && atRuleNode.rules.length) { 10683 atRuleNode.rules[0].root = (atRuleNode.isRooted || context.length === 0 || null); 10684 } 10685 } 10686}; 10687 10688module.exports = JoinSelectorVisitor; 10689 10690},{"./visitor":94}],92:[function(require,module,exports){ 10691var SetTreeVisibilityVisitor = function(visible) { 10692 this.visible = visible; 10693}; 10694SetTreeVisibilityVisitor.prototype.run = function(root) { 10695 this.visit(root); 10696}; 10697SetTreeVisibilityVisitor.prototype.visitArray = function(nodes) { 10698 if (!nodes) { 10699 return nodes; 10700 } 10701 10702 var cnt = nodes.length, i; 10703 for (i = 0; i < cnt; i++) { 10704 this.visit(nodes[i]); 10705 } 10706 return nodes; 10707}; 10708SetTreeVisibilityVisitor.prototype.visit = function(node) { 10709 if (!node) { 10710 return node; 10711 } 10712 if (node.constructor === Array) { 10713 return this.visitArray(node); 10714 } 10715 10716 if (!node.blocksVisibility || node.blocksVisibility()) { 10717 return node; 10718 } 10719 if (this.visible) { 10720 node.ensureVisibility(); 10721 } else { 10722 node.ensureInvisibility(); 10723 } 10724 10725 node.accept(this); 10726 return node; 10727}; 10728module.exports = SetTreeVisibilityVisitor; 10729},{}],93:[function(require,module,exports){ 10730var tree = require('../tree'), 10731 Visitor = require('./visitor'); 10732 10733var CSSVisitorUtils = function(context) { 10734 this._visitor = new Visitor(this); 10735 this._context = context; 10736}; 10737 10738CSSVisitorUtils.prototype = { 10739 containsSilentNonBlockedChild: function(bodyRules) { 10740 var rule; 10741 if (!bodyRules) { 10742 return false;
10743 } 10744 for (var r = 0; r < bodyRules.length; r++) { 10745 rule = bodyRules[r]; 10746 if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) { 10747 // the atrule contains something that was referenced (likely by extend) 10748 // therefore it needs to be shown in output too 10749 return true; 10750 } 10751 } 10752 return false; 10753 }, 10754 10755 keepOnlyVisibleChilds: function(owner) { 10756 if (owner && owner.rules) { 10757 owner.rules = owner.rules.filter(function(thing) { 10758 return thing.isVisible(); 10759 }); 10760 } 10761 }, 10762 10763 isEmpty: function(owner) { 10764 return (owner && owner.rules) 10765 ? (owner.rules.length === 0) : true; 10766 }, 10767 10768 hasVisibleSelector: function(rulesetNode) { 10769 return (rulesetNode && rulesetNode.paths) 10770 ? (rulesetNode.paths.length > 0) : false; 10771 }, 10772 10773 resolveVisibility: function (node, originalRules) { 10774 if (!node.blocksVisibility()) { 10775 if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) { 10776 return ; 10777 } 10778 10779 return node; 10780 } 10781 10782 var compiledRulesBody = node.rules[0]; 10783 this.keepOnlyVisibleChilds(compiledRulesBody); 10784 10785 if (this.isEmpty(compiledRulesBody)) { 10786 return ; 10787 } 10788 10789 node.ensureVisibility(); 10790 node.removeVisibilityBlock(); 10791 10792 return node; 10793 }, 10794
10795 isVisibleRuleset: function(rulesetNode) { 10796 if (rulesetNode.firstRoot) { 10797 return true; 10798 } 10799 10800 if (this.isEmpty(rulesetNode)) { 10801 return false; 10802 } 10803 10804 if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) { 10805 return false; 10806 } 10807 10808 return true; 10809 } 10810 10811}; 10812 10813var ToCSSVisitor = function(context) { 10814 this._visitor = new Visitor(this); 10815 this._context = context; 10816 this.utils = new CSSVisitorUtils(context); 10817}; 10818 10819ToCSSVisitor.prototype = { 10820 isReplacing: true, 10821 run: function (root) { 10822 return this._visitor.visit(root); 10823 }, 10824 10825 visitDeclaration: function (declNode, visitArgs) { 10826 if (declNode.blocksVisibility() || declNode.variable) { 10827 return; 10828 } 10829 return declNode; 10830 }, 10831 10832 visitMixinDefinition: function (mixinNode, visitArgs) { 10833 // mixin definitions do not get eval'd - this means they keep state 10834 // so we have to clear that state here so it isn't used if toCSS is called twice 10835 mixinNode.frames = []; 10836 }, 10837 10838 visitExtend: function (extendNode, visitArgs) { 10839 }, 10840 10841 visitComment: function (commentNode, visitArgs) { 10842 if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) { 10843 return; 10844 } 10845 return commentNode; 10846 }, 10847 10848 visitMedia: function(mediaNode, visitArgs) { 10849 var originalRules = mediaNode.rules[0].rules; 10850 mediaNode.accept(this._visitor); 10851 visitArgs.visitDeeper = false; 10852 10853 return this.utils.resolveVisibility(mediaNode, originalRules); 10854 }, 10855 10856 visitImport: function (importNode, visitArgs) { 10857 if (importNode.blocksVisibility()) { 10858 return ; 10859 } 10860 return importNode; 10861 }, 10862 10863 visitAtRule: function(atRuleNode, visitArgs) { 10864 if (atRuleNode.rules && atRuleNode.rules.length) { 10865 return this.visitAtRuleWithBody(atRuleNode, visitArgs); 10866 } else { 10867 return this.visitAtRuleWithoutBody(atRuleNode, visitArgs); 10868 } 10869 }, 10870 10871 visitAnonymous: function(anonymousNode, visitArgs) { 10872 if (!anonymousNode.blocksVisibility()) { 10873 anonymousNode.accept(this._visitor); 10874 return anonymousNode; 10875 } 10876 }, 10877 10878 visitAtRuleWithBody: function(atRuleNode, visitArgs) { 10879 // if there is only one nested ruleset and that one has no path, then it is 10880 // just fake ruleset 10881 function hasFakeRuleset(atRuleNode) { 10882 var bodyRules = atRuleNode.rules; 10883 return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0); 10884 } 10885 function getBodyRules(atRuleNode) { 10886 var nodeRules = atRuleNode.rules; 10887 if (hasFakeRuleset(atRuleNode)) { 10888 return nodeRules[0].rules; 10889 } 10890 10891 return nodeRules; 10892 } 10893 // it is still true that it is only one ruleset in array 10894 // this is last such moment 10895 // process childs 10896 var originalRules = getBodyRules(atRuleNode); 10897 atRuleNode.accept(this._visitor); 10898 visitArgs.visitDeeper = false; 10899 10900 if (!this.utils.isEmpty(atRuleNode)) { 10901 this._mergeRules(atRuleNode.rules[0].rules); 10902 } 10903 10904 return this.utils.resolveVisibility(atRuleNode, originalRules); 10905 }, 10906 10907 visitAtRuleWithoutBody: function(atRuleNode, visitArgs) { 10908 if (atRuleNode.blocksVisibility()) { 10909 return; 10910 } 10911 10912 if (atRuleNode.name === '@charset') { 10913 // Only output the debug info together with subsequent @charset definitions 10914 // a comment (or @media statement) before the actual @charset atrule would 10915 // be considered illegal css as it has to be on the first line 10916 if (this.charset) { 10917 if (atRuleNode.debugInfo) { 10918 var comment = new tree.Comment('/* ' + atRuleNode.toCSS(this._context).replace(/\n/g, '') + ' */\n'); 10919 comment.debugInfo = atRuleNode.debugInfo; 10920 return this._visitor.visit(comment); 10921 } 10922 return; 10923 } 10924 this.charset = true; 10925 } 10926 10927 return atRuleNode; 10928 }, 10929 10930 checkValidNodes: function(rules, isRoot) { 10931 if (!rules) { 10932 return; 10933 } 10934 10935 for (var i = 0; i < rules.length; i++) { 10936 var ruleNode = rules[i]; 10937 if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) { 10938 throw { message: 'Properties must be inside selector blocks. They cannot be in the root', 10939 index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename}; 10940 } 10941 if (ruleNode instanceof tree.Call) {
10942 throw { message: 'Function \'' + ruleNode.name + '\' is undefined', 10943 index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename}; 10944 } 10945 if (ruleNode.type && !ruleNode.allowRoot) { 10946 throw { message: ruleNode.type + ' node returned by a function is not valid here', 10947 index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename}; 10948 } 10949 } 10950 }, 10951 10952 visitRuleset: function (rulesetNode, visitArgs) { 10953 // at this point rulesets are nested into each other 10954 var rule, rulesets = []; 10955 10956 this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot); 10957 10958 if (!rulesetNode.root) { 10959 // remove invisible paths 10960 this._compileRulesetPaths(rulesetNode); 10961 10962 // remove rulesets from this ruleset body and compile them separately 10963 var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0; 10964 for (var i = 0; i < nodeRuleCnt; ) { 10965 rule = nodeRules[i]; 10966 if (rule && rule.rules) { 10967 // visit because we are moving them out from being a child 10968 rulesets.push(this._visitor.visit(rule)); 10969 nodeRules.splice(i, 1); 10970 nodeRuleCnt--; 10971 continue; 10972 } 10973 i++; 10974 } 10975 // accept the visitor to remove rules and refactor itself 10976 // then we can decide nogw whether we want it or not 10977 // compile body 10978 if (nodeRuleCnt > 0) { 10979 rulesetNode.accept(this._visitor); 10980 } else { 10981 rulesetNode.rules = null; 10982 } 10983 visitArgs.visitDeeper = false; 10984 10985 } else { // if (! rulesetNode.root) { 10986 rulesetNode.accept(this._visitor); 10987 visitArgs.visitDeeper = false; 10988 } 10989 10990 if (rulesetNode.rules) { 10991 this._mergeRules(rulesetNode.rules); 10992 this._removeDuplicateRules(rulesetNode.rules); 10993 } 10994 10995 // now decide whether we keep the ruleset 10996 if (this.utils.isVisibleRuleset(rulesetNode)) { 10997 rulesetNode.ensureVisibility(); 10998 rulesets.splice(0, 0, rulesetNode); 10999 } 11000 11001 if (rulesets.length === 1) { 11002 return rulesets[0]; 11003 } 11004 return rulesets; 11005 }, 11006 11007 _compileRulesetPaths: function(rulesetNode) { 11008 if (rulesetNode.paths) { 11009 rulesetNode.paths = rulesetNode.paths 11010 .filter(function(p) { 11011 var i; 11012 if (p[0].elements[0].combinator.value === ' ') { 11013 p[0].elements[0].combinator = new(tree.Combinator)(''); 11014 } 11015 for (i = 0; i < p.length; i++) { 11016 if (p[i].isVisible() && p[i].getIsOutput()) { 11017 return true; 11018 } 11019 } 11020 return false; 11021 }); 11022 } 11023 }, 11024 11025 _removeDuplicateRules: function(rules) { 11026 if (!rules) { return; } 11027 11028 // remove duplicates 11029 var ruleCache = {}, 11030 ruleList, rule, i; 11031 11032 for (i = rules.length - 1; i >= 0 ; i--) { 11033 rule = rules[i]; 11034 if (rule instanceof tree.Declaration) { 11035 if (!ruleCache[rule.name]) { 11036 ruleCache[rule.name] = rule; 11037 } else { 11038 ruleList = ruleCache[rule.name]; 11039 if (ruleList instanceof tree.Declaration) { 11040 ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)]; 11041 } 11042 var ruleCSS = rule.toCSS(this._context); 11043 if (ruleList.indexOf(ruleCSS) !== -1) { 11044 rules.splice(i, 1); 11045 } else { 11046 ruleList.push(ruleCSS); 11047 } 11048 } 11049 } 11050 } 11051 }, 11052 11053 _mergeRules: function(rules) { 11054 if (!rules) { 11055 return; 11056 } 11057 11058 var groups = {}, 11059 groupsArr = []; 11060 11061 for (var i = 0; i < rules.length; i++) { 11062 var rule = rules[i]; 11063 if (rule.merge) { 11064 var key = rule.name; 11065 groups[key] ? rules.splice(i--, 1) : 11066 groupsArr.push(groups[key] = []); 11067 groups[key].push(rule); 11068 } 11069 } 11070 11071 groupsArr.forEach(function(group) { 11072 if (group.length > 0) { 11073 var result = group[0], 11074 space = [], 11075 comma = [new tree.Expression(space)]; 11076 group.forEach(function(rule) { 11077 if ((rule.merge === '+') && (space.length > 0)) { 11078 comma.push(new tree.Expression(space = [])); 11079 } 11080 space.push(rule.value); 11081 result.important = result.important || rule.important; 11082 }); 11083 result.value = new tree.Value(comma); 11084 } 11085 }); 11086 } 11087}; 11088 11089module.exports = ToCSSVisitor; 11090 11091},{"../tree":65,"./visitor":94}],94:[function(require,module,exports){ 11092var tree = require('../tree'); 11093 11094var _visitArgs = { visitDeeper: true }, 11095 _hasIndexed = false;
11096 11097function _noop(node) { 11098 return node; 11099} 11100 11101function indexNodeTypes(parent, ticker) { 11102 // add .typeIndex to tree node types for lookup table 11103 var key, child; 11104 for (key in parent) { 11105 /* eslint guard-for-in: 0 */ 11106 child = parent[key]; 11107 switch (typeof child) { 11108 case 'function': 11109 // ignore bound functions directly on tree which do not have a prototype 11110 // or aren't nodes 11111 if (child.prototype && child.prototype.type) { 11112 child.prototype.typeIndex = ticker++; 11113 } 11114 break; 11115 case 'object': 11116 ticker = indexNodeTypes(child, ticker); 11117 break; 11118 11119 } 11120 } 11121 return ticker; 11122} 11123 11124var Visitor = function(implementation) { 11125 this._implementation = implementation; 11126 this._visitFnCache = []; 11127 11128 if (!_hasIndexed) { 11129 indexNodeTypes(tree, 1); 11130 _hasIndexed = true; 11131 } 11132}; 11133 11134Visitor.prototype = { 11135 visit: function(node) { 11136 if (!node) { 11137 return node; 11138 } 11139 11140 var nodeTypeIndex = node.typeIndex; 11141 if (!nodeTypeIndex) { 11142 return node; 11143 } 11144 11145 var visitFnCache = this._visitFnCache, 11146 impl = this._implementation, 11147 aryIndx = nodeTypeIndex << 1, 11148 outAryIndex = aryIndx | 1, 11149 func = visitFnCache[aryIndx], 11150 funcOut = visitFnCache[outAryIndex], 11151 visitArgs = _visitArgs, 11152 fnName; 11153 11154 visitArgs.visitDeeper = true; 11155 11156 if (!func) { 11157 fnName = 'visit' + node.type; 11158 func = impl[fnName] || _noop; 11159 funcOut = impl[fnName + 'Out'] || _noop; 11160 visitFnCache[aryIndx] = func; 11161 visitFnCache[outAryIndex] = funcOut; 11162 } 11163 11164 if (func !== _noop) { 11165 var newNode = func.call(impl, node, visitArgs); 11166 if (impl.isReplacing) { 11167 node = newNode; 11168 } 11169 } 11170 11171 if (visitArgs.visitDeeper && node && node.accept) { 11172 node.accept(this); 11173 } 11174 11175 if (funcOut != _noop) { 11176 funcOut.call(impl, node); 11177 } 11178 11179 return node; 11180 }, 11181 visitArray: function(nodes, nonReplacing) { 11182 if (!nodes) { 11183 return nodes; 11184 } 11185 11186 var cnt = nodes.length, i; 11187 11188 // Non-replacing 11189 if (nonReplacing || !this._implementation.isReplacing) { 11190 for (i = 0; i < cnt; i++) { 11191 this.visit(nodes[i]); 11192 } 11193 return nodes; 11194 } 11195 11196 // Replacing 11197 var out = []; 11198 for (i = 0; i < cnt; i++) { 11199 var evald = this.visit(nodes[i]); 11200 if (evald === undefined) { continue; } 11201 if (!evald.splice) { 11202 out.push(evald); 11203 } else if (evald.length) { 11204 this.flatten(evald, out); 11205 } 11206 } 11207 return out; 11208 }, 11209 flatten: function(arr, out) { 11210 if (!out) { 11211 out = []; 11212 } 11213 11214 var cnt, i, item, 11215 nestedCnt, j, nestedItem; 11216 11217 for (i = 0, cnt = arr.length; i < cnt; i++) { 11218 item = arr[i]; 11219 if (item === undefined) { 11220 continue; 11221 } 11222 if (!item.splice) { 11223 out.push(item); 11224 continue; 11225 } 11226 11227 for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) { 11228 nestedItem = item[j]; 11229 if (nestedItem === undefined) { 11230 continue; 11231 } 11232 if (!nestedItem.splice) { 11233 out.push(nestedItem); 11234 } else if (nestedItem.length) { 11235 this.flatten(nestedItem, out); 11236 } 11237 } 11238 } 11239 11240 return out; 11241 } 11242}; 11243module.exports = Visitor; 11244 11245},{"../tree":65}],95:[function(require,module,exports){ 11246"use strict"; 11247 11248// rawAsap provides everything we need except exception management. 11249var rawAsap = require("./raw"); 11250// RawTasks are recycled to reduce GC churn. 11251var freeTasks = []; 11252// We queue errors to ensure they are thrown in right order (FIFO). 11253// Array-as-queue is good enough here, since we are just dealing with exceptions. 11254var pendingErrors = []; 11255var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError); 11256 11257function throwFirstError() { 11258 if (pendingErrors.length) {
11259 throw pendingErrors.shift(); 11260 } 11261} 11262 11263/** 11264 * Calls a task as soon as possible after returning, in its own event, with priority 11265 * over other events like animation, reflow, and repaint. An error thrown from an 11266 * event will not interrupt, nor even substantially slow down the processing of 11267 * other events, but will be rather postponed to a lower priority event. 11268 * @param {{call}} task A callable object, typically a function that takes no 11269 * arguments. 11270 */ 11271module.exports = asap; 11272function asap(task) { 11273 var rawTask; 11274 if (freeTasks.length) { 11275 rawTask = freeTasks.pop(); 11276 } else { 11277 rawTask = new RawTask(); 11278 } 11279 rawTask.task = task; 11280 rawAsap(rawTask); 11281} 11282 11283// We wrap tasks with recyclable task objects. A task object implements 11284// `call`, just like a function. 11285function RawTask() { 11286 this.task = null; 11287} 11288 11289// The sole purpose of wrapping the task is to catch the exception and recycle 11290// the task object after its single use. 11291RawTask.prototype.call = function () { 11292 try { 11293 this.task.call(); 11294 } catch (error) { 11295 if (asap.onerror) { 11296 // This hook exists purely for testing purposes. 11297 // Its name will be periodically randomized to break any code that 11298 // depends on its existence. 11299 asap.onerror(error); 11300 } else { 11301 // In a web browser, exceptions are not fatal. However, to avoid 11302 // slowing down the queue of pending tasks, we rethrow the error in a 11303 // lower priority turn. 11304 pendingErrors.push(error); 11305 requestErrorThrow(); 11306 } 11307 } finally { 11308 this.task = null; 11309 freeTasks[freeTasks.length] = this; 11310 } 11311}; 11312 11313},{"./raw":96}],96:[function(require,module,exports){ 11314(function (global){ 11315"use strict"; 11316 11317// Use the fastest means possible to execute a task in its own turn, with 11318// priority over other events including IO, animation, reflow, and redraw 11319// events in browsers. 11320// 11321// An exception thrown by a task will permanently interrupt the processing of 11322// subsequent tasks. The higher level `asap` function ensures that if an 11323// exception is thrown by a task, that the task queue will continue flushing as 11324// soon as possible, but if you use `rawAsap` directly, you are responsible to 11325// either ensure that no exceptions are thrown from your task, or to manually 11326// call `rawAsap.requestFlush` if an exception is thrown. 11327module.exports = rawAsap; 11328function rawAsap(task) { 11329 if (!queue.length) { 11330 requestFlush(); 11331 flushing = true; 11332 } 11333 // Equivalent to push, but avoids a function call. 11334 queue[queue.length] = task; 11335} 11336 11337var queue = []; 11338// Once a flush has been requested, no further calls to `requestFlush` are 11339// necessary until the next `flush` completes. 11340var flushing = false; 11341// `requestFlush` is an implementation-specific method that attempts to kick 11342// off a `flush` event as quickly as possible. `flush` will attempt to exhaust 11343// the event queue before yielding to the browser's own event loop. 11344var requestFlush; 11345// The position of the next task to execute in the task queue. This is 11346// preserved between calls to `flush` so that it can be resumed if 11347// a task throws an exception. 11348var index = 0; 11349// If a task schedules additional tasks recursively, the task queue can grow 11350// unbounded. To prevent memory exhaustion, the task queue will periodically 11351// truncate already-completed tasks. 11352var capacity = 1024; 11353 11354// The flush function processes all tasks that have been scheduled with 11355// `rawAsap` unless and until one of those tasks throws an exception. 11356// If a task throws an exception, `flush` ensures that its state will remain 11357// consistent and will resume where it left off when called again. 11358// However, `flush` does not make any arrangements to be called again if an 11359// exception is thrown. 11360function flush() { 11361 while (index < queue.length) { 11362 var currentIndex = index; 11363 // Advance the index before calling the task. This ensures that we will 11364 // begin flushing on the next task the task throws an error. 11365 index = index + 1;
11366 queue[currentIndex].call(); 11367 // Prevent leaking memory for long chains of recursive calls to `asap`. 11368 // If we call `asap` within tasks scheduled by `asap`, the queue will 11369 // grow, but to avoid an O(n) walk for every task we execute, we don't 11370 // shift tasks off the queue after they have been executed. 11371 // Instead, we periodically shift 1024 tasks off the queue. 11372 if (index > capacity) { 11373 // Manually shift all values starting at the index back to the 11374 // beginning of the queue. 11375 for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { 11376 queue[scan] = queue[scan + index]; 11377 } 11378 queue.length -= index; 11379 index = 0; 11380 } 11381 } 11382 queue.length = 0; 11383 index = 0; 11384 flushing = false; 11385} 11386 11387// `requestFlush` is implemented using a strategy based on data collected from 11388// every available SauceLabs Selenium web driver worker at time of writing. 11389// https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593 11390 11391// Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that 11392// have WebKitMutationObserver but not un-prefixed MutationObserver. 11393// Must use `global` or `self` instead of `window` to work in both frames and web 11394// workers. `global` is a provision of Browserify, Mr, Mrs, or Mop. 11395 11396/* globals self */ 11397var scope = typeof global !== "undefined" ? global : self; 11398var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver; 11399 11400// MutationObservers are desirable because they have high priority and work 11401// reliably everywhere they are implemented. 11402// They are implemented in all modern browsers. 11403// 11404// - Android 4-4.3 11405// - Chrome 26-34 11406// - Firefox 14-29 11407// - Internet Explorer 11 11408// - iPad Safari 6-7.1 11409// - iPhone Safari 7-7.1 11410// - Safari 6-7 11411if (typeof BrowserMutationObserver === "function") { 11412 requestFlush = makeRequestCallFromMutationObserver(flush); 11413 11414// MessageChannels are desirable because they give direct access to the HTML 11415// task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera 11416// 11-12, and in web workers in many engines. 11417// Although message channels yield to any queued rendering and IO tasks, they 11418// would be better than imposing the 4ms delay of timers. 11419// However, they do not work reliably in Internet Explorer or Safari. 11420 11421// Internet Explorer 10 is the only browser that has setImmediate but does 11422// not have MutationObservers. 11423// Although setImmediate yields to the browser's renderer, it would be 11424// preferrable to falling back to setTimeout since it does not have 11425// the minimum 4ms penalty. 11426// Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (
11426and 11427// Desktop to a lesser extent) that renders both setImmediate and 11428// MessageChannel useless for the purposes of ASAP. 11429// https://github.com/kriskowal/q/issues/396 11430 11431// Timers are implemented universally. 11432// We fall back to timers in workers in most engines, and in foreground 11433// contexts in the following browsers. 11434// However, note that even this simple case requires nuances to operate in a 11435// broad spectrum of browsers. 11436// 11437// - Firefox 3-13 11438// - Internet Explorer 6-9 11439// - iPad Safari 4.3 11440// - Lynx 2.8.7 11441} else { 11442 requestFlush = makeRequestCallFromTimer(flush); 11443} 11444 11445// `requestFlush` requests that the high priority event queue be flushed as 11446// soon as possible. 11447// This is useful to prevent an error thrown in a task from stalling the event 11448// queue if the exception handled by Node.jsâs 11449// `process.on("uncaughtException")` or by a domain. 11450rawAsap.requestFlush = requestFlush; 11451 11452// To request a high priority event, we induce a mutation observer by toggling 11453// the text of a text node between "1" and "-1". 11454function makeRequestCallFromMutationObserver(callback) { 11455 var toggle = 1; 11456 var observer = new BrowserMutationObserver(callback); 11457 var node = document.createTextNode(""); 11458 observer.observe(node, {characterData: true}); 11459 return function requestCall() { 11460 toggle = -toggle; 11461 node.data = toggle; 11462 }; 11463} 11464 11465// The message channel technique was discovered by Malte Ubl and was the 11466// original foundation for this library. 11467// http://www.nonblocking.io/2011/06/windownexttick.html 11468 11469// Safari 6.0.5 (at least) intermittently fails to create message ports on a 11470// page's first load. Thankfully, this version of Safari supports 11471// MutationObservers, so we don't need to fall back in that case. 11472 11473// function makeRequestCallFromMessageChannel(callback) { 11474// var channel = new MessageChannel(); 11475// channel.port1.onmessage = callback; 11476// return function requestCall() { 11477// channel.port2.postMessage(0); 11478// }; 11479// } 11480 11481// For reasons explained above, we are also unable to use `setImmediate` 11482// under any circumstances. 11483// Even if we were, there is another bug in Internet Explorer 10. 11484// It is not sufficient to assign `setImmediate` to `requestFlush` because 11485// `setImmediate` must be called *by name* and therefore must be wrapped in a 11486// closure. 11487// Never forget. 11488 11489// function makeRequestCallFromSetImmediate(callback) { 11490// return function requestCall() { 11491// setImmediate(callback); 11492// }; 11493// } 11494 11495// Safari 6.0 has a problem where timers will get lost while the user is 11496// scrolling. This problem does not impact ASAP because Safari 6.0 supports 11497// mutation observers, so that implementation is used instead. 11498// However, if we ever elect to use timers in Safari, the prevalent work-around 11499// is to add a scroll event listener that calls for a flush. 11500 11501// `setTimeout` does not call the passed callback if the delay is less than 11502// approximately 7 in web workers in Firefox 8 through 18, and sometimes not 11503// even then. 11504 11505function makeRequestCallFromTimer(callback) { 11506 return function requestCall() { 11507 // We dispatch a timeout with a specified delay of 0 for engines that 11508 // can reliably accommodate that request. This will usually be snapped 11509 // to a 4 milisecond delay, but once we're flushing, there's no delay 11510 // between events. 11511 var timeoutHandle = setTimeout(handleTimer, 0); 11512 // However, since this timer gets frequently dropped in Firefox 11513 // workers, we enlist an interval handle that will try to fire 11514 // an event 20 times per second until it succeeds. 11515 var intervalHandle = setInterval(handleTimer, 50); 11516 11517 function handleTimer() { 11518 // Whichever timer succeeds will cancel both timers and 11519 // execute the callback. 11520 clearTimeout(timeoutHandle); 11521 clearInterval(intervalHandle); 11522 callback(); 11523 } 11524 }; 11525} 11526 11527// This is for `asap.js` only. 11528// Its name will be periodically randomized to break any code that depends on 11529// its existence. 11530rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer; 11531 11532// ASAP was originally a nextTick shim included in Q. This was factored out 11533// into this ASAP package. It was later adapted to RSVP which made further 11534// amendments. These decisions, particularly to marginalize MessageChannel and 11535// to capture the MutationObserver implementation in a closure, were integrated 11536// back into ASAP proper. 11537// https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js 11538 11539}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 11540},{}],97:[function(require,module,exports){ 11541'use strict'; 11542 11543var asap = require('asap/raw'); 11544 11545function noop() {} 11546 11547// States: 11548// 11549// 0 - pending 11550// 1 - fulfilled with _value 11551// 2 - rejected with _value 11552// 3 - adopted the state of another promise, _value 11553// 11554// once the state is no longer pending (0) it is immutable 11555 11556// All `_` prefixed properties will be reduced to `_{random number}` 11557// at build time to obfuscate them and discourage their use. 11558// We don't use symbols or Object.defineProperty to fully hide them
11559// because the performance isn't good enough. 11560 11561 11562// to avoid using try/catch inside critical functions, we 11563// extract them to here. 11564var LAST_ERROR = null; 11565var IS_ERROR = {}; 11566function getThen(obj) { 11567 try { 11568 return obj.then; 11569 } catch (ex) { 11570 LAST_ERROR = ex; 11571 return IS_ERROR; 11572 } 11573} 11574 11575function tryCallOne(fn, a) { 11576 try { 11577 return fn(a); 11578 } catch (ex) { 11579 LAST_ERROR = ex; 11580 return IS_ERROR; 11581 } 11582} 11583function tryCallTwo(fn, a, b) { 11584 try { 11585 fn(a, b); 11586 } catch (ex) { 11587 LAST_ERROR = ex; 11588 return IS_ERROR; 11589 } 11590} 11591 11592module.exports = Promise; 11593 11594function Promise(fn) { 11595 if (typeof this !== 'object') { 11596 throw new TypeError('Promises must be constructed via new'); 11597 } 11598 if (typeof fn !== 'function') { 11599 throw new TypeError('Promise constructor\'s argument is not a function'); 11600 } 11601 this._40 = 0; 11602 this._65 = 0; 11603 this._55 = null; 11604 this._72 = null; 11605 if (fn === noop) return; 11606 doResolve(fn, this); 11607} 11608Promise._37 = null; 11609Promise._87 = null; 11610Promise._61 = noop; 11611 11612Promise.prototype.then = function(onFulfilled, onRejected) { 11613 if (this.constructor !== Promise) { 11614 return safeThen(this, onFulfilled, onRejected); 11615 } 11616 var res = new Promise(noop); 11617 handle(this, new Handler(onFulfilled, onRejected, res)); 11618 return res; 11619}; 11620 11621function safeThen(self, onFulfilled, onRejected) { 11622 return new self.constructor(function (resolve, reject) { 11623 var res = new Promise(noop); 11624 res.then(resolve, reject); 11625 handle(self, new Handler(onFulfilled, onRejected, res)); 11626 }); 11627} 11628function handle(self, deferred) { 11629 while (self._65 === 3) { 11630 self = self._55; 11631 } 11632 if (Promise._37) { 11633 Promise._37(self); 11634 } 11635 if (self._65 === 0) { 11636 if (self._40 === 0) { 11637 self._40 = 1; 11638 self._72 = deferred; 11639 return; 11640 } 11641 if (self._40 === 1) { 11642 self._40 = 2; 11643 self._72 = [self._72, deferred]; 11644 return; 11645 } 11646 self._72.push(deferred); 11647 return; 11648 } 11649 handleResolved(self, deferred); 11650} 11651 11652function handleResolved(self, deferred) { 11653 asap(function() { 11654 var cb = self._65 === 1 ? deferred.onFulfilled : deferred.onRejected; 11655 if (cb === null) { 11656 if (self._65 === 1) { 11657 resolve(deferred.promise, self._55); 11658 } else { 11659 reject(deferred.promise, self._55); 11660 } 11661 return; 11662 } 11663 var ret = tryCallOne(cb, self._55); 11664 if (ret === IS_ERROR) { 11665 reject(deferred.promise, LAST_ERROR); 11666 } else { 11667 resolve(deferred.promise, ret); 11668 } 11669 }); 11670} 11671function resolve(self, newValue) { 11672 // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure 11673 if (newValue === self) { 11674 return reject( 11675 self, 11676 new TypeError('A promise cannot be resolved with itself.') 11677 ); 11678 } 11679 if ( 11680 newValue && 11681 (typeof newValue === 'object' || typeof newValue === 'function') 11682 ) { 11683 var then = getThen(newValue); 11684 if (then === IS_ERROR) { 11685 return reject(self, LAST_ERROR); 11686 } 11687 if ( 11688 then === self.then && 11689 newValue instanceof Promise 11690 ) { 11691 self._65 = 3; 11692 self._55 = newValue; 11693 finale(self); 11694 return; 11695 } else if (typeof then === 'function') { 11696 doResolve(then.bind(newValue), self); 11697 return; 11698 } 11699 } 11700 self._65 = 1; 11701 self._55 = newValue; 11702 finale(self); 11703} 11704 11705function reject(self, newValue) { 11706 self._65 = 2; 11707 self._55 = newValue; 11708 if (Promise._87) { 11709 Promise._87(self, newValue); 11710 } 11711 finale(self); 11712} 11713function finale(self) { 11714 if (self._40 === 1) { 11715 handle(self, self._72); 11716 self._72 = null; 11717 } 11718 if (self._40 === 2) { 11719 for (var i = 0; i < self._72.length; i++) { 11720 handle(self, self._72[i]); 11721 } 11722 self._72 = null; 11723 } 11724} 11725 11726function Handler(onFulfilled, onRejected, promise){ 11727 this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; 11728 this.onRejected = typeof onRejected === 'function' ? onRejected : null; 11729 this.promise = promise; 11730} 11731 11732/** 11733 * Take a potentially misbehaving resolver function and make sure 11734 * onFulfilled and onRejected are only called once. 11735 * 11736 * Makes no guarantees about asynchrony. 11737 */ 11738function doResolve(fn, promise) { 11739 var done = false; 11740 var res = tryCallTwo(fn, function (value) { 11741 if (done) return; 11742 done = true; 11743 resolve(promise, value); 11744 }, function (reason) { 11745 if (done) return; 11746 done = true; 11747 reject(promise, reason); 11748 }); 11749 if (!done && res === IS_ERROR) { 11750 done = true; 11751 reject(promise, LAST_ERROR); 11752 } 11753} 11754 11755},{"asap/raw":96}],98:[function(require,module,exports){ 11756'use strict'; 11757 11758//This file contains the ES6 extensions to the core Promises/A+ API 11759 11760var Promise = require('./core.js'); 11761 11762module.exports = Promise; 11763 11764/* Static Functions */ 11765 11766var TRUE = valuePromise(true); 11767var FALSE = valuePromise(false); 11768var NULL = valuePromise(null); 11769var UNDEFINED = valuePromise(undefined); 11770var ZERO = valuePromise(0); 11771var EMPTYSTRING = valuePromise(''); 11772 11773function valuePromise(value) { 11774 var p = new Promise(Promise._61); 11775 p._65 = 1; 11776 p._55 = value; 11777 return p; 11778} 11779Promise.resolve = function (value) { 11780 if (value instanceof Promise) return value; 11781 11782 if (value === null) return NULL; 11783 if (value === undefined) return UNDEFINED; 11784 if (value === true) return TRUE; 11785 if (value === false) return FALSE; 11786 if (value === 0) return ZERO; 11787 if (value === '') return EMPTYSTRING; 11788 11789 if (typeof value === 'object' || typeof value === 'function') { 11790 try { 11791 var then = value.then; 11792 if (typeof then === 'function') { 11793 return new Promise(then.bind(value)); 11794 } 11795 } catch (ex) { 11796 return new Promise(function (resolve, reject) { 11797 reject(ex); 11798 }); 11799 } 11800 } 11801 return valuePromise(value); 11802}; 11803 11804Promise.all = function (arr) { 11805 var args = Array.prototype.slice.call(arr); 11806 11807 return new Promise(function (resolve, reject) { 11808 if (args.length === 0) return resolve([]); 11809 var remaining = args.length; 11810 function res(i, val) { 11811 if (val && (typeof val === 'object' || typeof val === 'function')) { 11812 if (val instanceof Promise && val.then === Promise.prototype.then) { 11813 while (val._65 === 3) { 11814 val = val._55; 11815 } 11816 if (val._65 === 1) return res(i, val._55); 11817 if (val._65 === 2) reject(val._55); 11818 val.then(function (val) { 11819 res(i, val); 11820 }, reject); 11821 return; 11822 } else { 11823 var then = val.then; 11824 if (typeof then === 'function') { 11825 var p = new Promise(then.bind(val)); 11826 p.then(function (val) { 11827 res(i, val); 11828 }, reject); 11829 return; 11830 } 11831 } 11832 } 11833 args[i] = val; 11834 if (--remaining === 0) { 11835 resolve(args); 11836 } 11837 } 11838 for (var i = 0; i < args.length; i++) { 11839 res(i, args[i]); 11840 } 11841 }); 11842}; 11843 11844Promise.reject = function (value) { 11845 return new Promise(function (resolve, reject) { 11846 reject(value); 11847 }); 11848}; 11849 11850Promise.race = function (values) { 11851 return new Promise(function (resolve, reject) {
11852 values.forEach(function(value){ 11853 Promise.resolve(value).then(resolve, reject); 11854 }); 11855 }); 11856}; 11857 11858/* Prototype Methods */ 11859 11860Promise.prototype['catch'] = function (onRejected) { 11861 return this.then(null, onRejected); 11862}; 11863 11864},{"./core.js":97}],99:[function(require,module,exports){ 11865// should work in any browser without browserify 11866 11867if (typeof Promise.prototype.done !== 'function') { 11868 Promise.prototype.done = function (onFulfilled, onRejected) { 11869 var self = arguments.length ? this.then.apply(this, arguments) : this 11870 self.then(null, function (err) { 11871 setTimeout(function () { 11872 throw err 11873 }, 0) 11874 }) 11875 } 11876} 11877},{}],100:[function(require,module,exports){ 11878// not "use strict" so we can declare global "Promise" 11879 11880var asap = require('asap'); 11881 11882if (typeof Promise === 'undefined') { 11883 Promise = require('./lib/core.js') 11884 require('./lib/es6-extensions.js') 11885} 11886 11887require('./polyfill-done.js'); 11888 11889},{"./lib/core.js":97,"./lib/es6-extensions.js":98,"./polyfill-done.js":99,"asap":95}]},{},[2])(2) 11890});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.