From f81bd551d43331b281d287dc07adde339b385b01 Mon Sep 17 00:00:00 2001
From: Sean Gilligan
Date: Mon, 26 Mar 2012 20:38:50 -0700
Subject: [PATCH 01/72] Add "Building from Source" section and note about
binaries being in Maven Central repo
---
README.md | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/README.md b/README.md
index 0b31932..e217059 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,8 @@ Maven users should add the library using the following dependency:
1.3.0
+(lesscss-java is in the Maven Central repository.)
+
Non-Maven users should download the latest version and add it to the project's classpath. Also the following dependencies are required:
+ Apache Commons IO 2.1
@@ -52,6 +54,18 @@ Support
Have a question, or found an issue? Just create a issue: https://github.com/marceloverdijk/lesscss-java/issues
+Building From Source
+--------------------
+
+Can be built with [Maven 2.2.x](http://maven.apache.org) (or later?) by using the following commands:
+
+ mvn package
+
+or, to install into your local Maven repository:
+
+ mvn install
+
+
Authors
-------
From 08524e4c4bc5063a8e07500ca39af3c5c551873e Mon Sep 17 00:00:00 2001
From: Sean Gilligan
Date: Fri, 13 Apr 2012 00:01:47 -0700
Subject: [PATCH 02/72] Add command for making JavaDocs
---
README.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/README.md b/README.md
index e217059..54577cc 100644
--- a/README.md
+++ b/README.md
@@ -64,7 +64,10 @@ Can be built with [Maven 2.2.x](http://maven.apache.org) (or later?) by using th
or, to install into your local Maven repository:
mvn install
+
+You may also wish to build API Documentation:
+ mvn javadoc:javadoc
Authors
-------
From 3485097dc0d992bae1cf726d2df89802f1631e53 Mon Sep 17 00:00:00 2001
From: Edward Samson
Date: Wed, 25 Apr 2012 23:29:58 +0800
Subject: [PATCH 03/72] Match `*.less` instead of just `*less` when checking
imports
This was preventing the implicit `.less` to be added when the import
name ended with *less*.
This fixes marceloverdijk/lesscss-java#4
---
src/main/java/org/lesscss/LessSource.java | 2 +-
src/test/java/integration/ImportIT.java | 5 +++++
src/test/resources/import/endsinless/css/import.css | 3 +++
src/test/resources/import/endsinless/less/iendinless.less | 3 +++
src/test/resources/import/endsinless/less/import.less | 1 +
5 files changed, 13 insertions(+), 1 deletion(-)
create mode 100644 src/test/resources/import/endsinless/css/import.css
create mode 100644 src/test/resources/import/endsinless/less/iendinless.less
create mode 100644 src/test/resources/import/endsinless/less/import.less
diff --git a/src/main/java/org/lesscss/LessSource.java b/src/main/java/org/lesscss/LessSource.java
index 6168a17..2ae8937 100644
--- a/src/main/java/org/lesscss/LessSource.java
+++ b/src/main/java/org/lesscss/LessSource.java
@@ -139,7 +139,7 @@ private void resolveImports() throws FileNotFoundException, IOException {
Matcher importMatcher = IMPORT_PATTERN.matcher(normalizedContent);
while (importMatcher.find()) {
String importedFile = importMatcher.group(2);
- importedFile = importedFile.matches(".*(le?|c)ss$") ? importedFile : importedFile + ".less";
+ importedFile = importedFile.matches(".*\\.(le?|c)ss$") ? importedFile : importedFile + ".less";
boolean css = importedFile.matches(".*css$");
if (!css) {
LessSource importedLessSource = new LessSource(new File(file.getParentFile(), importedFile));
diff --git a/src/test/java/integration/ImportIT.java b/src/test/java/integration/ImportIT.java
index 462d18d..6647caf 100644
--- a/src/test/java/integration/ImportIT.java
+++ b/src/test/java/integration/ImportIT.java
@@ -22,4 +22,9 @@ public class ImportIT extends AbstractCompileIT {
public void testImport() throws Exception {
testCompile(toFile("import/less/import.less"), toFile("import/css/import.css"));
}
+
+ @Test
+ public void testImportEndsInLess() throws Exception {
+ testCompile(toFile("import/endsinless/less/import.less"), toFile("import/endsinless/css/import.css"));
+ }
}
diff --git a/src/test/resources/import/endsinless/css/import.css b/src/test/resources/import/endsinless/css/import.css
new file mode 100644
index 0000000..6d8e92e
--- /dev/null
+++ b/src/test/resources/import/endsinless/css/import.css
@@ -0,0 +1,3 @@
+iendinless {
+ color: blue;
+}
diff --git a/src/test/resources/import/endsinless/less/iendinless.less b/src/test/resources/import/endsinless/less/iendinless.less
new file mode 100644
index 0000000..0e9d6b8
--- /dev/null
+++ b/src/test/resources/import/endsinless/less/iendinless.less
@@ -0,0 +1,3 @@
+iendinless {
+ color: blue;
+}
diff --git a/src/test/resources/import/endsinless/less/import.less b/src/test/resources/import/endsinless/less/import.less
new file mode 100644
index 0000000..b286272
--- /dev/null
+++ b/src/test/resources/import/endsinless/less/import.less
@@ -0,0 +1 @@
+@import "iendinless";
From d91a59d8bbfb3a3599e1b2b028015fc8904f1921 Mon Sep 17 00:00:00 2001
From: "David M. Carr"
Date: Fri, 10 Aug 2012 13:40:10 -0400
Subject: [PATCH 04/72] send envjs output to commons logging rather than
system.out
---
src/main/resources/META-INF/env.rhino.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/main/resources/META-INF/env.rhino.js b/src/main/resources/META-INF/env.rhino.js
index 2351d01..47ea2ee 100644
--- a/src/main/resources/META-INF/env.rhino.js
+++ b/src/main/resources/META-INF/env.rhino.js
@@ -1,3 +1,8 @@
+// Override the print function so that the messages go to commons logging
+print = function(message) {
+ Packages.org.apache.commons.logging.LogFactory.getLog('rhino').debug(message);
+};
+
/*
* Envjs core-env.1.2.13
* Pure JavaScript Browser Environment
From 0ca359f87372509dec52b60793950ea044a8d7ac Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 27 Sep 2012 16:33:05 -0400
Subject: [PATCH 05/72] Add animal-sniffer to ensure runtime compatibility with
Java 1.5
---
pom.xml | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/pom.xml b/pom.xml
index 2697ee3..fb9ceeb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -124,6 +124,26 @@
+
+ org.codehaus.mojo
+ animal-sniffer-maven-plugin
+ 1.8
+
+
+ test
+
+ check
+
+
+
+
+
+ org.codehaus.mojo.signature
+ java15
+ 1.0
+
+
+
From ff044a4a83c528f9a5abdae99c350aa03bcdcf83 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 27 Sep 2012 23:13:28 -0400
Subject: [PATCH 06/72] Make LessCompiler thread safe (one instance can be used
by multiple threads)
Added integration test to make sure LessCompiler really is thread safe
Updated the existing unit and integration tests
Enforce the documented restriction that envJs, lessJs, customJs, encoding, and compress cannot be changed after init() is called
---
pom.xml | 6 +
src/main/java/org/lesscss/LessCompiler.java | 109 ++++++---
.../java/integration/AbstractCompileIT.java | 8 +-
.../java/integration/MultithreadedIT.java | 70 ++++++
src/test/java/integration/ReuseIT.java | 25 ++
.../java/org/lesscss/LessCompilerTest.java | 227 ++++++++----------
6 files changed, 280 insertions(+), 165 deletions(-)
create mode 100644 src/test/java/integration/MultithreadedIT.java
create mode 100644 src/test/java/integration/ReuseIT.java
diff --git a/pom.xml b/pom.xml
index fb9ceeb..b3b9b8b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,6 +60,12 @@
1.4.11test
+
+ org.jodah
+ concurrentunit
+ 0.3.0
+ test
+ org.mozillarhino
diff --git a/src/main/java/org/lesscss/LessCompiler.java b/src/main/java/org/lesscss/LessCompiler.java
index e76c287..cfeb3fc 100644
--- a/src/main/java/org/lesscss/LessCompiler.java
+++ b/src/main/java/org/lesscss/LessCompiler.java
@@ -25,6 +25,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Function;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
@@ -57,7 +58,7 @@
*/
public class LessCompiler {
- private static final String COMPILE_STRING = "var result; var parser = new(less.Parser); parser.parse(input, function (e, tree) { if (e instanceof Object) { throw e } result = tree.toCSS({compress: %b}) });";
+ private static final String COMPILE_STRING = "function doIt(input, compress) { var result; var parser = new less.Parser(); parser.parse(input, function(e, tree) { if (e instanceof Object) { throw e; } ; result = tree.toCSS({compress: compress}); }); return result; }";
private Log log = LogFactory.getLog(LessCompiler.class);
@@ -67,7 +68,8 @@ public class LessCompiler {
private boolean compress = false;
private String encoding = null;
- private Context cx;
+ private Function doIt;
+
private Scriptable scope;
/**
@@ -92,12 +94,17 @@ public URL getEnvJs() {
* @param envJs The Envjs JavaScript file used by the compiler.
*/
public void setEnvJs(URL envJs) {
+ synchronized(this){
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
+ }
this.envJs = envJs;
}
/**
* Returns the LESS JavaScript file used by the compiler.
- *
+ * COMPILE_STRING
* @return The LESS JavaScript file used by the compiler.
*/
public URL getLessJs() {
@@ -111,6 +118,11 @@ public URL getLessJs() {
* @param The LESS JavaScript file used by the compiler.
*/
public void setLessJs(URL lessJs) {
+ synchronized(this){
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
+ }
this.lessJs = lessJs;
}
@@ -120,7 +132,7 @@ public void setLessJs(URL lessJs) {
* @return The custom JavaScript files used by the compiler.
*/
public List getCustomJs() {
- return customJs;
+ return Collections.unmodifiableList(customJs);
}
/**
@@ -130,8 +142,12 @@ public List getCustomJs() {
* @param customJs A single custom JavaScript file used by the compiler.
*/
public void setCustomJs(URL customJs) {
- this.customJs = new ArrayList();
- this.customJs.add(customJs);
+ synchronized(this){
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
+ }
+ this.customJs = Collections.singletonList(customJs);
}
/**
@@ -141,7 +157,13 @@ public void setCustomJs(URL customJs) {
* @param customJs The custom JavaScript files used by the compiler.
*/
public void setCustomJs(List customJs) {
- this.customJs = customJs;
+ synchronized(this){
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
+ }
+ // copy the list so there's no way for anyone else who holds a reference to the list to modify it
+ this.customJs = new ArrayList(customJs);
}
/**
@@ -155,10 +177,16 @@ public boolean isCompress() {
/**
* Sets the compiler to compress the CSS.
+ * Must be set before {@link #init()} is called.
*
* @param compress If true, sets the compiler to compress the CSS.
*/
public void setCompress(boolean compress) {
+ synchronized(this){
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
+ }
this.compress = compress;
}
@@ -174,10 +202,16 @@ public String getEncoding() {
/**
* Sets the character encoding used by the compiler when writing the output File.
* If not set the platform default will be used.
+ * Must be set before {@link #init()} is called.
*
* @param The character encoding used by the compiler when writing the output File.
*/
public void setEncoding(String encoding) {
+ synchronized(this){
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
+ }
this.encoding = encoding;
}
@@ -187,30 +221,40 @@ public void setEncoding(String encoding) {
* It is not needed to call this method manually, as it is called implicitly by the compile methods if needed.
*
*/
- public void init() {
+ public synchronized void init() {
long start = System.currentTimeMillis();
-
- cx = Context.enter();
- cx.setOptimizationLevel(-1);
- cx.setLanguageVersion(Context.VERSION_1_7);
-
- Global global = new Global();
- global.init(cx);
-
- scope = cx.initStandardObjects(global);
-
+
try {
- cx.evaluateReader(scope, new InputStreamReader(envJs.openConnection().getInputStream()), "env.rhino.js", 1, null);
- cx.evaluateReader(scope, new InputStreamReader(lessJs.openConnection().getInputStream()), "less.js", 1, null);
-
- for (URL url : customJs) {
- cx.evaluateReader(scope, new InputStreamReader(url.openConnection().getInputStream()), url.toString(), 1, null);
- }
+ Context cx = Context.enter();
+ cx.setOptimizationLevel(-1);
+ cx.setLanguageVersion(Context.VERSION_1_7);
+
+ Global global = new Global();
+ global.init(cx);
+
+ scope = cx.initStandardObjects(global);
+
+ List jsUrls = new ArrayList(2 + customJs.size());
+ jsUrls.add(envJs);
+ jsUrls.add(lessJs);
+ jsUrls.addAll(customJs);
+
+ for(URL url : jsUrls){
+ InputStreamReader inputStreamReader = new InputStreamReader(url.openConnection().getInputStream());
+ try{
+ cx.evaluateReader(scope, inputStreamReader, url.toString(), 1, null);
+ }finally{
+ inputStreamReader.close();
+ }
+ }
+ doIt = cx.compileFunction(scope, COMPILE_STRING, "doIt.js", 1, null);
}
catch (Exception e) {
String message = "Failed to initialize LESS compiler.";
log.error(message, e);
throw new IllegalStateException(message, e);
+ }finally{
+ Context.exit();
}
if (log.isDebugEnabled()) {
@@ -225,18 +269,17 @@ public void init() {
* @return The CSS.
*/
public String compile(String input) throws LessException {
- if (cx == null) {
- init();
- }
+ synchronized(this){
+ if (scope == null) {
+ init();
+ }
+ }
long start = System.currentTimeMillis();
try {
- scope.put("input", scope, input);
- scope.put("result", scope, "");
-
- cx.evaluateString(scope, String.format(COMPILE_STRING, compress), "compile.js", 1, null);
- Object result = scope.get("result", scope);
+ Context cx = Context.enter();
+ Object result = doIt.call(cx, scope, null, new Object[]{input, compress});
if (log.isDebugEnabled()) {
log.debug("Finished compilation of LESS source in " + (System.currentTimeMillis() - start) + " ms.");
@@ -253,6 +296,8 @@ public String compile(String input) throws LessException {
}
}
throw new LessException(e);
+ }finally{
+ Context.exit();
}
}
diff --git a/src/test/java/integration/AbstractCompileIT.java b/src/test/java/integration/AbstractCompileIT.java
index d2694dc..10d0736 100644
--- a/src/test/java/integration/AbstractCompileIT.java
+++ b/src/test/java/integration/AbstractCompileIT.java
@@ -35,14 +35,14 @@ public void setUp() throws Exception {
}
protected void testCompile(File lessFile, File cssFile) throws Exception {
- testCompile(lessFile, cssFile, false);
+ String expected = FileUtils.readFileToString(cssFile);
+ String actual = lessCompiler.compile(lessFile);
+ assertEquals(expected.replace("\r\n", "\n"), actual);
}
protected void testCompile(File lessFile, File cssFile, boolean compress) throws Exception {
lessCompiler.setCompress(compress);
- String expected = FileUtils.readFileToString(cssFile);
- String actual = lessCompiler.compile(lessFile);
- assertEquals(expected.replace("\r\n", "\n"), actual);
+ testCompile(lessFile, cssFile);
}
protected File toFile(String filename) {
diff --git a/src/test/java/integration/MultithreadedIT.java b/src/test/java/integration/MultithreadedIT.java
new file mode 100644
index 0000000..5b962de
--- /dev/null
+++ b/src/test/java/integration/MultithreadedIT.java
@@ -0,0 +1,70 @@
+package integration;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.apache.commons.io.FileUtils;
+import org.jodah.concurrentunit.Waiter;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MultithreadedIT extends AbstractCompileIT {
+ final Waiter waiter = new Waiter();
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ lessCompiler.setCustomJs(Arrays.asList(
+ toURL("compatibility/custom.math.js"),
+ toURL("compatibility/custom.color.js"),
+ toURL("compatibility/custom.process.title.js")));
+ }
+
+ @Test
+ public void testMultithreaded() throws Throwable {
+ final String[] filenames = new String[]{
+ "colors",
+ "comments",
+ "css-3",
+ "css-escapes",
+ "css",
+ "functions",
+ "ie-filters",
+ "import_custom",
+ "import_custom",
+ "javascript",
+ "lazy-eval",
+ "media",
+ "mixins-args",
+ "mixins-closure",
+ "mixins-guards"
+ };
+ final int ITERATIONS = 5;
+ for(int i=0;i
Date: Thu, 27 Sep 2012 23:15:58 -0400
Subject: [PATCH 07/72] Make log static and final.
It's the same for all instances, so why not? This is a (small) optimization.
---
src/main/java/org/lesscss/LessCompiler.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/lesscss/LessCompiler.java b/src/main/java/org/lesscss/LessCompiler.java
index cfeb3fc..d7fb917 100644
--- a/src/main/java/org/lesscss/LessCompiler.java
+++ b/src/main/java/org/lesscss/LessCompiler.java
@@ -60,7 +60,7 @@ public class LessCompiler {
private static final String COMPILE_STRING = "function doIt(input, compress) { var result; var parser = new less.Parser(); parser.parse(input, function(e, tree) { if (e instanceof Object) { throw e; } ; result = tree.toCSS({compress: compress}); }); return result; }";
- private Log log = LogFactory.getLog(LessCompiler.class);
+ private static final Log log = LogFactory.getLog(LessCompiler.class);
private URL envJs = LessCompiler.class.getClassLoader().getResource("META-INF/env.rhino.js");
private URL lessJs = LessCompiler.class.getClassLoader().getResource("META-INF/less.js");
From 289a8501c8dc53aefdbec5cd8e0bd2fe222a5575 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 27 Sep 2012 23:20:17 -0400
Subject: [PATCH 08/72] Instead of casting to String, use toString().
---
src/main/java/org/lesscss/LessCompiler.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/lesscss/LessCompiler.java b/src/main/java/org/lesscss/LessCompiler.java
index d7fb917..9589959 100644
--- a/src/main/java/org/lesscss/LessCompiler.java
+++ b/src/main/java/org/lesscss/LessCompiler.java
@@ -291,7 +291,7 @@ public String compile(String input) throws LessException {
if (e instanceof JavaScriptException) {
Scriptable value = (Scriptable)((JavaScriptException)e).getValue();
if (value != null && ScriptableObject.hasProperty(value, "message")) {
- String message = (String)ScriptableObject.getProperty(value, "message");
+ String message = ScriptableObject.getProperty(value, "message").toString();
throw new LessException(message, e);
}
}
From 2f9cba28721ffcf0d6e36e46c43c80d7486004ad Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 27 Sep 2012 23:21:05 -0400
Subject: [PATCH 09/72] Bump to Rhino 1.7R4
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index b3b9b8b..0321e6d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,7 +69,7 @@
org.mozillarhino
- 1.7R3
+ 1.7R4
From c4eb0cfea3f14ade10624cc34dfcedd4009a9698 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 27 Sep 2012 23:34:30 -0400
Subject: [PATCH 10/72] Add Craig Andrews (me) to the README.md
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 54577cc..36c8c39 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,10 @@ Authors
+ http://twitter.com/marceloverdijk
+ http://github.com/marceloverdijk
+**Craig Andrews**
+
++ candrews@integralblue.com
++ http://candrews.integralblue.com
Copyright and License
---------------------
From cf50c5721a366934690b94094911349fbc8295a6 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 27 Sep 2012 23:41:56 -0400
Subject: [PATCH 11/72] Note that LessCompiler is now thread safe
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 36c8c39..69f62b3 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,8 @@ Look at the simple example below to compile LESS to CSS:
// Or compile LESS input file to CSS output file
lessCompiler.compile(new File("main.less"), new File("main.css"));
+LessCompiler is thread safe. In other words, an application only needs one LessCompiler that it can reuse whenever necessary.
+
To learn more about LESS, please see http://lesscss.org/.
From 1159238229d6d43ac92ae1613b3917a48ec8810e Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 27 Sep 2012 23:42:22 -0400
Subject: [PATCH 12/72] Note that Rhino 1.7R4 is now used
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 69f62b3..66517f4 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@ Non-Maven users should download the latest version and add it to the project's c
+ Apache Commons IO 2.1
+ Apache Commons Lang 3.1
+ Apache Commons Logging 1.1.1
-+ Rhino: JavaScript for Java 1.7R3
++ Rhino: JavaScript for Java 1.7R4
Compatibility
From c6f45b7f30aaa433311a3bd76ab7377f96768ae6 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 27 Sep 2012 23:55:07 -0400
Subject: [PATCH 13/72] Bump to commons-io 2.4.
---
README.md | 2 +-
pom.xml | 4 ++--
src/test/java/org/lesscss/LessCompilerTest.java | 16 ++++++++--------
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 66517f4..053501a 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ Maven users should add the library using the following dependency:
Non-Maven users should download the latest version and add it to the project's classpath. Also the following dependencies are required:
-+ Apache Commons IO 2.1
++ Apache Commons IO 2.4
+ Apache Commons Lang 3.1
+ Apache Commons Logging 1.1.1
+ Rhino: JavaScript for Java 1.7R4
diff --git a/pom.xml b/pom.xml
index 0321e6d..0bf6805 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
commons-iocommons-io
- 2.1
+ 2.4commons-logging
@@ -184,4 +184,4 @@
http://github.com/marceloverdijk/lesscss-java
-
\ No newline at end of file
+
diff --git a/src/test/java/org/lesscss/LessCompilerTest.java b/src/test/java/org/lesscss/LessCompilerTest.java
index 3825cd1..d5fd8cb 100644
--- a/src/test/java/org/lesscss/LessCompilerTest.java
+++ b/src/test/java/org/lesscss/LessCompilerTest.java
@@ -309,7 +309,7 @@ public void testCompileFileToFile() throws Exception {
verify(doIt).call(cx, scope, null, new Object[]{less, false});
verifyStatic();
- FileUtils.writeStringToFile(outputFile, css, null);
+ FileUtils.writeStringToFile(outputFile, css, (String) null);
}
@Test
@@ -334,7 +334,7 @@ public void testCompileFileToFileWithForceTrue() throws Exception {
verify(doIt).call(cx, scope, null, new Object[]{less, false});
verifyStatic();
- FileUtils.writeStringToFile(outputFile, css, null);
+ FileUtils.writeStringToFile(outputFile, css, (String) null);
}
@Test
@@ -364,7 +364,7 @@ public void testCompileFileToFileWithForceFalseAndOutputNotExists() throws Excep
verify(doIt).call(cx, scope, null, new Object[]{less, false});
verifyStatic();
- FileUtils.writeStringToFile(outputFile, css, null);
+ FileUtils.writeStringToFile(outputFile, css, (String) null);
}
@Test
@@ -399,7 +399,7 @@ public void testCompileFileToFileWithForceFalseAndOutputExistsAndLessSourceModif
verify(doIt).call(cx, scope, null, new Object[]{less, false});
verifyStatic();
- FileUtils.writeStringToFile(outputFile, css, null);
+ FileUtils.writeStringToFile(outputFile, css, (String) null);
}
@Test
@@ -464,7 +464,7 @@ public void testCompileLessSourceToFile() throws Exception {
verify(doIt).call(cx, scope, null, new Object[]{less, false});
verifyStatic();
- FileUtils.writeStringToFile(outputFile, css, null);
+ FileUtils.writeStringToFile(outputFile, css, (String) null);
}
@Test
@@ -487,7 +487,7 @@ public void testCompileLessSourceToFileWithForceTrue() throws Exception {
verify(doIt).call(cx, scope, null, new Object[]{less, false});
verifyStatic();
- FileUtils.writeStringToFile(outputFile, css, null);
+ FileUtils.writeStringToFile(outputFile, css, (String) null);
}
@Test
@@ -514,7 +514,7 @@ public void testCompileLessSourceToFileWithForceFalseAndOutputNotExists() throws
verify(doIt).call(cx, scope, null, new Object[]{less, false});
verifyStatic();
- FileUtils.writeStringToFile(outputFile, css, null);
+ FileUtils.writeStringToFile(outputFile, css, (String) null);
}
@Test
@@ -545,7 +545,7 @@ public void testCompileLessSourceToFileWithForceFalseAndOutputExistsAndLessSourc
verify(doIt).call(cx, scope, null, new Object[]{less, false});
verifyStatic();
- FileUtils.writeStringToFile(outputFile, css, null);
+ FileUtils.writeStringToFile(outputFile, css, (String) null);
}
@Test
From 3f6095b5676b0faa698414b41254db0ff2ae1605 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Fri, 28 Sep 2012 10:33:52 -0400
Subject: [PATCH 14/72] Add Craig Andrews (me) to the pom.xml developers
section
---
pom.xml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/pom.xml b/pom.xml
index 0bf6805..cfb87cd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -171,6 +171,16 @@
+2
+
+ candrews
+ Craig Andrews
+ candrews@integralblue.com
+ http://candrews.integralblue.com
+
+ Developer
+
+ -5
+
From 61d5c4bf669c91f8c3a236805d82a069144a5150 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Fri, 28 Sep 2012 10:48:23 -0400
Subject: [PATCH 15/72] Synchronize all methods that use scope
The fine grained mechanism had a potential race condition, which this change resolves.
---
src/main/java/org/lesscss/LessCompiler.java | 60 +++++++++------------
1 file changed, 24 insertions(+), 36 deletions(-)
diff --git a/src/main/java/org/lesscss/LessCompiler.java b/src/main/java/org/lesscss/LessCompiler.java
index 9589959..6b71866 100644
--- a/src/main/java/org/lesscss/LessCompiler.java
+++ b/src/main/java/org/lesscss/LessCompiler.java
@@ -93,12 +93,10 @@ public URL getEnvJs() {
*
* @param envJs The Envjs JavaScript file used by the compiler.
*/
- public void setEnvJs(URL envJs) {
- synchronized(this){
- if (scope != null) {
- throw new IllegalStateException("This method can only be called before init()");
- }
- }
+ public synchronized void setEnvJs(URL envJs) {
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
this.envJs = envJs;
}
@@ -117,12 +115,10 @@ public URL getLessJs() {
*
* @param The LESS JavaScript file used by the compiler.
*/
- public void setLessJs(URL lessJs) {
- synchronized(this){
- if (scope != null) {
- throw new IllegalStateException("This method can only be called before init()");
- }
- }
+ public synchronized void setLessJs(URL lessJs) {
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
this.lessJs = lessJs;
}
@@ -141,12 +137,10 @@ public List getCustomJs() {
*
* @param customJs A single custom JavaScript file used by the compiler.
*/
- public void setCustomJs(URL customJs) {
- synchronized(this){
- if (scope != null) {
- throw new IllegalStateException("This method can only be called before init()");
- }
- }
+ public synchronized void setCustomJs(URL customJs) {
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
this.customJs = Collections.singletonList(customJs);
}
@@ -156,12 +150,10 @@ public void setCustomJs(URL customJs) {
*
* @param customJs The custom JavaScript files used by the compiler.
*/
- public void setCustomJs(List customJs) {
- synchronized(this){
- if (scope != null) {
- throw new IllegalStateException("This method can only be called before init()");
- }
- }
+ public synchronized void setCustomJs(List customJs) {
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
// copy the list so there's no way for anyone else who holds a reference to the list to modify it
this.customJs = new ArrayList(customJs);
}
@@ -181,12 +173,10 @@ public boolean isCompress() {
*
* @param compress If true, sets the compiler to compress the CSS.
*/
- public void setCompress(boolean compress) {
- synchronized(this){
- if (scope != null) {
- throw new IllegalStateException("This method can only be called before init()");
- }
- }
+ public synchronized void setCompress(boolean compress) {
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
this.compress = compress;
}
@@ -206,12 +196,10 @@ public String getEncoding() {
*
* @param The character encoding used by the compiler when writing the output File.
*/
- public void setEncoding(String encoding) {
- synchronized(this){
- if (scope != null) {
- throw new IllegalStateException("This method can only be called before init()");
- }
- }
+ public synchronized void setEncoding(String encoding) {
+ if (scope != null) {
+ throw new IllegalStateException("This method can only be called before init()");
+ }
this.encoding = encoding;
}
From e67b3b81fe59ccea6c766383cd9047a8619ed49b Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Fri, 28 Sep 2012 10:49:57 -0400
Subject: [PATCH 16/72] [maven-release-plugin] prepare release lesscss-1.3.1
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index cfb87cd..be89c6b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0org.lesscsslesscss
- 1.3.1-SNAPSHOT
+ 1.3.1jarOfficial LESS CSS Compiler for JavaOfficial LESS CSS Compiler for Java
From 2658d1dbe69394c275223a39480d15e02c7d3a32 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Fri, 28 Sep 2012 10:50:03 -0400
Subject: [PATCH 17/72] [maven-release-plugin] prepare for next development
iteration
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index be89c6b..571530a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0org.lesscsslesscss
- 1.3.1
+ 1.3.2-SNAPSHOTjarOfficial LESS CSS Compiler for JavaOfficial LESS CSS Compiler for Java
From 5fc32538cb428ae39aa80ab47e0c8f54b332ba35 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Mon, 1 Oct 2012 13:31:34 -0400
Subject: [PATCH 18/72] Set the version to 1.3.1-SNAPSHOT
I did not mean to commit the version bump. 1.3.1 will be the next release.
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 571530a..cfb87cd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0org.lesscsslesscss
- 1.3.2-SNAPSHOT
+ 1.3.1-SNAPSHOTjarOfficial LESS CSS Compiler for JavaOfficial LESS CSS Compiler for Java
From dc0947c4fb76c210a51c33e45e644c0685c7ee3e Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Mon, 1 Oct 2012 13:34:44 -0400
Subject: [PATCH 19/72] [maven-release-plugin] prepare release lesscss-1.3.1
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index cfb87cd..be89c6b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0org.lesscsslesscss
- 1.3.1-SNAPSHOT
+ 1.3.1jarOfficial LESS CSS Compiler for JavaOfficial LESS CSS Compiler for Java
From 6a9c5b9872359308d30f1844f116a1d5bce24811 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Mon, 1 Oct 2012 13:36:07 -0400
Subject: [PATCH 20/72] [maven-release-plugin] prepare for next development
iteration
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index be89c6b..571530a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0org.lesscsslesscss
- 1.3.1
+ 1.3.2-SNAPSHOTjarOfficial LESS CSS Compiler for JavaOfficial LESS CSS Compiler for Java
From 4818c769ef670daea90c328656b01b9a951d7810 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Tue, 13 Nov 2012 22:37:54 -0500
Subject: [PATCH 21/72] Bump the bundled less.js to 1.3.1
---
src/main/resources/META-INF/less.js | 3475 +--------------------------
1 file changed, 3 insertions(+), 3472 deletions(-)
diff --git a/src/main/resources/META-INF/less.js b/src/main/resources/META-INF/less.js
index fce5fb5..4043d44 100644
--- a/src/main/resources/META-INF/less.js
+++ b/src/main/resources/META-INF/less.js
@@ -1,3478 +1,9 @@
//
-// LESS - Leaner CSS v1.3.0
+// LESS - Leaner CSS v1.3.1
// http://lesscss.org
//
// Copyright (c) 2009-2011, Alexis Sellier
// Licensed under the Apache 2.0 License.
//
-(function (window, undefined) {
-//
-// Stub out `require` in the browser
-//
-function require(arg) {
- return window.less[arg.split('/')[1]];
-};
-
-// amd.js
-//
-// Define Less as an AMD module.
-if (typeof define === "function" && define.amd) {
- define("less", [], function () { return less; } );
-}
-
-// ecma-5.js
-//
-// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
-// -- tlrobinson Tom Robinson
-// dantman Daniel Friesen
-
-//
-// Array
-//
-if (!Array.isArray) {
- Array.isArray = function(obj) {
- return Object.prototype.toString.call(obj) === "[object Array]" ||
- (obj instanceof Array);
- };
-}
-if (!Array.prototype.forEach) {
- Array.prototype.forEach = function(block, thisObject) {
- var len = this.length >>> 0;
- for (var i = 0; i < len; i++) {
- if (i in this) {
- block.call(thisObject, this[i], i, this);
- }
- }
- };
-}
-if (!Array.prototype.map) {
- Array.prototype.map = function(fun /*, thisp*/) {
- var len = this.length >>> 0;
- var res = new Array(len);
- var thisp = arguments[1];
-
- for (var i = 0; i < len; i++) {
- if (i in this) {
- res[i] = fun.call(thisp, this[i], i, this);
- }
- }
- return res;
- };
-}
-if (!Array.prototype.filter) {
- Array.prototype.filter = function (block /*, thisp */) {
- var values = [];
- var thisp = arguments[1];
- for (var i = 0; i < this.length; i++) {
- if (block.call(thisp, this[i])) {
- values.push(this[i]);
- }
- }
- return values;
- };
-}
-if (!Array.prototype.reduce) {
- Array.prototype.reduce = function(fun /*, initial*/) {
- var len = this.length >>> 0;
- var i = 0;
-
- // no value to return if no initial value and an empty array
- if (len === 0 && arguments.length === 1) throw new TypeError();
-
- if (arguments.length >= 2) {
- var rv = arguments[1];
- } else {
- do {
- if (i in this) {
- rv = this[i++];
- break;
- }
- // if array contains no values, no initial value to return
- if (++i >= len) throw new TypeError();
- } while (true);
- }
- for (; i < len; i++) {
- if (i in this) {
- rv = fun.call(null, rv, this[i], i, this);
- }
- }
- return rv;
- };
-}
-if (!Array.prototype.indexOf) {
- Array.prototype.indexOf = function (value /*, fromIndex */ ) {
- var length = this.length;
- var i = arguments[1] || 0;
-
- if (!length) return -1;
- if (i >= length) return -1;
- if (i < 0) i += length;
-
- for (; i < length; i++) {
- if (!Object.prototype.hasOwnProperty.call(this, i)) { continue }
- if (value === this[i]) return i;
- }
- return -1;
- };
-}
-
-//
-// Object
-//
-if (!Object.keys) {
- Object.keys = function (object) {
- var keys = [];
- for (var name in object) {
- if (Object.prototype.hasOwnProperty.call(object, name)) {
- keys.push(name);
- }
- }
- return keys;
- };
-}
-
-//
-// String
-//
-if (!String.prototype.trim) {
- String.prototype.trim = function () {
- return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
- };
-}
-var less, tree;
-
-if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
- // Rhino
- // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
- if (typeof(window) === 'undefined') { less = {} }
- else { less = window.less = {} }
- tree = less.tree = {};
- less.mode = 'rhino';
-} else if (typeof(window) === 'undefined') {
- // Node.js
- less = exports,
- tree = require('./tree');
- less.mode = 'node';
-} else {
- // Browser
- if (typeof(window.less) === 'undefined') { window.less = {} }
- less = window.less,
- tree = window.less.tree = {};
- less.mode = 'browser';
-}
-//
-// less.js - parser
-//
-// A relatively straight-forward predictive parser.
-// There is no tokenization/lexing stage, the input is parsed
-// in one sweep.
-//
-// To make the parser fast enough to run in the browser, several
-// optimization had to be made:
-//
-// - Matching and slicing on a huge input is often cause of slowdowns.
-// The solution is to chunkify the input into smaller strings.
-// The chunks are stored in the `chunks` var,
-// `j` holds the current chunk index, and `current` holds
-// the index of the current chunk in relation to `input`.
-// This gives us an almost 4x speed-up.
-//
-// - In many cases, we don't need to match individual tokens;
-// for example, if a value doesn't hold any variables, operations
-// or dynamic references, the parser can effectively 'skip' it,
-// treating it as a literal.
-// An example would be '1px solid #000' - which evaluates to itself,
-// we don't need to know what the individual components are.
-// The drawback, of course is that you don't get the benefits of
-// syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
-// and a smaller speed-up in the code-gen.
-//
-//
-// Token matching is done with the `$` function, which either takes
-// a terminal string or regexp, or a non-terminal function to call.
-// It also takes care of moving all the indices forwards.
-//
-//
-less.Parser = function Parser(env) {
- var input, // LeSS input string
- i, // current index in `input`
- j, // current chunk
- temp, // temporarily holds a chunk's state, for backtracking
- memo, // temporarily holds `i`, when backtracking
- furthest, // furthest index the parser has gone to
- chunks, // chunkified input
- current, // index of current chunk, in `input`
- parser;
-
- var that = this;
-
- // This function is called after all files
- // have been imported through `@import`.
- var finish = function () {};
-
- var imports = this.imports = {
- paths: env && env.paths || [], // Search paths, when importing
- queue: [], // Files which haven't been imported yet
- files: {}, // Holds the imported parse trees
- contents: {}, // Holds the imported file contents
- mime: env && env.mime, // MIME type of .less files
- error: null, // Error in parsing/evaluating an import
- push: function (path, callback) {
- var that = this;
- this.queue.push(path);
-
- //
- // Import a file asynchronously
- //
- less.Parser.importer(path, this.paths, function (e, root, contents) {
- that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
- that.files[path] = root; // Store the root
- that.contents[path] = contents;
-
- if (e && !that.error) { that.error = e }
- callback(e, root);
-
- if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing
- }, env);
- }
- };
-
- function save() { temp = chunks[j], memo = i, current = i }
- function restore() { chunks[j] = temp, i = memo, current = i }
-
- function sync() {
- if (i > current) {
- chunks[j] = chunks[j].slice(i - current);
- current = i;
- }
- }
- //
- // Parse from a token, regexp or string, and move forward if match
- //
- function $(tok) {
- var match, args, length, c, index, endIndex, k, mem;
-
- //
- // Non-terminal
- //
- if (tok instanceof Function) {
- return tok.call(parser.parsers);
- //
- // Terminal
- //
- // Either match a single character in the input,
- // or match a regexp in the current chunk (chunk[j]).
- //
- } else if (typeof(tok) === 'string') {
- match = input.charAt(i) === tok ? tok : null;
- length = 1;
- sync ();
- } else {
- sync ();
-
- if (match = tok.exec(chunks[j])) {
- length = match[0].length;
- } else {
- return null;
- }
- }
-
- // The match is confirmed, add the match length to `i`,
- // and consume any extra white-space characters (' ' || '\n')
- // which come after that. The reason for this is that LeSS's
- // grammar is mostly white-space insensitive.
- //
- if (match) {
- mem = i += length;
- endIndex = i + chunks[j].length - length;
-
- while (i < endIndex) {
- c = input.charCodeAt(i);
- if (! (c === 32 || c === 10 || c === 9)) { break }
- i++;
- }
- chunks[j] = chunks[j].slice(length + (i - mem));
- current = i;
-
- if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
-
- if(typeof(match) === 'string') {
- return match;
- } else {
- return match.length === 1 ? match[0] : match;
- }
- }
- }
-
- function expect(arg, msg) {
- var result = $(arg);
- if (! result) {
- error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
- : "unexpected token"));
- } else {
- return result;
- }
- }
-
- function error(msg, type) {
- throw { index: i, type: type || 'Syntax', message: msg };
- }
-
- // Same as $(), but don't change the state of the parser,
- // just return the match.
- function peek(tok) {
- if (typeof(tok) === 'string') {
- return input.charAt(i) === tok;
- } else {
- if (tok.test(chunks[j])) {
- return true;
- } else {
- return false;
- }
- }
- }
-
- function basename(pathname) {
- if (less.mode === 'node') {
- return require('path').basename(pathname);
- } else {
- return pathname.match(/[^\/]+$/)[0];
- }
- }
-
- function getInput(e, env) {
- if (e.filename && env.filename && (e.filename !== env.filename)) {
- return parser.imports.contents[basename(e.filename)];
- } else {
- return input;
- }
- }
-
- function getLocation(index, input) {
- for (var n = index, column = -1;
- n >= 0 && input.charAt(n) !== '\n';
- n--) { column++ }
-
- return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null,
- column: column };
- }
-
- function LessError(e, env) {
- var input = getInput(e, env),
- loc = getLocation(e.index, input),
- line = loc.line,
- col = loc.column,
- lines = input.split('\n');
-
- this.type = e.type || 'Syntax';
- this.message = e.message;
- this.filename = e.filename || env.filename;
- this.index = e.index;
- this.line = typeof(line) === 'number' ? line + 1 : null;
- this.callLine = e.call && (getLocation(e.call, input).line + 1);
- this.callExtract = lines[getLocation(e.call, input).line];
- this.stack = e.stack;
- this.column = col;
- this.extract = [
- lines[line - 1],
- lines[line],
- lines[line + 1]
- ];
- }
-
- this.env = env = env || {};
-
- // The optimization level dictates the thoroughness of the parser,
- // the lower the number, the less nodes it will create in the tree.
- // This could matter for debugging, or if you want to access
- // the individual nodes in the tree.
- this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
-
- this.env.filename = this.env.filename || null;
-
- //
- // The Parser
- //
- return parser = {
-
- imports: imports,
- //
- // Parse an input string into an abstract syntax tree,
- // call `callback` when done.
- //
- parse: function (str, callback) {
- var root, start, end, zone, line, lines, buff = [], c, error = null;
-
- i = j = current = furthest = 0;
- input = str.replace(/\r\n/g, '\n');
-
- // Split the input into chunks.
- chunks = (function (chunks) {
- var j = 0,
- skip = /[^"'`\{\}\/\(\)\\]+/g,
- comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
- string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g,
- level = 0,
- match,
- chunk = chunks[0],
- inParam;
-
- for (var i = 0, c, cc; i < input.length; i++) {
- skip.lastIndex = i;
- if (match = skip.exec(input)) {
- if (match.index === i) {
- i += match[0].length;
- chunk.push(match[0]);
- }
- }
- c = input.charAt(i);
- comment.lastIndex = string.lastIndex = i;
-
- if (match = string.exec(input)) {
- if (match.index === i) {
- i += match[0].length;
- chunk.push(match[0]);
- c = input.charAt(i);
- }
- }
-
- if (!inParam && c === '/') {
- cc = input.charAt(i + 1);
- if (cc === '/' || cc === '*') {
- if (match = comment.exec(input)) {
- if (match.index === i) {
- i += match[0].length;
- chunk.push(match[0]);
- c = input.charAt(i);
- }
- }
- }
- }
-
- switch (c) {
- case '{': if (! inParam) { level ++; chunk.push(c); break }
- case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break }
- case '(': if (! inParam) { inParam = true; chunk.push(c); break }
- case ')': if ( inParam) { inParam = false; chunk.push(c); break }
- default: chunk.push(c);
- }
- }
- if (level > 0) {
- error = new(LessError)({
- index: i,
- type: 'Parse',
- message: "missing closing `}`",
- filename: env.filename
- }, env);
- }
-
- return chunks.map(function (c) { return c.join('') });;
- })([[]]);
-
- if (error) {
- return callback(error);
- }
-
- // Start with the primary rule.
- // The whole syntax tree is held under a Ruleset node,
- // with the `root` property set to true, so no `{}` are
- // output. The callback is called when the input is parsed.
- try {
- root = new(tree.Ruleset)([], $(this.parsers.primary));
- root.root = true;
- } catch (e) {
- return callback(new(LessError)(e, env));
- }
-
- root.toCSS = (function (evaluate) {
- var line, lines, column;
-
- return function (options, variables) {
- var frames = [], importError;
-
- options = options || {};
- //
- // Allows setting variables with a hash, so:
- //
- // `{ color: new(tree.Color)('#f01') }` will become:
- //
- // new(tree.Rule)('@color',
- // new(tree.Value)([
- // new(tree.Expression)([
- // new(tree.Color)('#f01')
- // ])
- // ])
- // )
- //
- if (typeof(variables) === 'object' && !Array.isArray(variables)) {
- variables = Object.keys(variables).map(function (k) {
- var value = variables[k];
-
- if (! (value instanceof tree.Value)) {
- if (! (value instanceof tree.Expression)) {
- value = new(tree.Expression)([value]);
- }
- value = new(tree.Value)([value]);
- }
- return new(tree.Rule)('@' + k, value, false, 0);
- });
- frames = [new(tree.Ruleset)(null, variables)];
- }
-
- try {
- var css = evaluate.call(this, { frames: frames })
- .toCSS([], { compress: options.compress || false });
- } catch (e) {
- throw new(LessError)(e, env);
- }
-
- if ((importError = parser.imports.error)) { // Check if there was an error during importing
- if (importError instanceof LessError) throw importError;
- else throw new(LessError)(importError, env);
- }
-
- if (options.yuicompress && less.mode === 'node') {
- return require('./cssmin').compressor.cssmin(css);
- } else if (options.compress) {
- return css.replace(/(\s)+/g, "$1");
- } else {
- return css;
- }
- };
- })(root.eval);
-
- // If `i` is smaller than the `input.length - 1`,
- // it means the parser wasn't able to parse the whole
- // string, so we've got a parsing error.
- //
- // We try to extract a \n delimited string,
- // showing the line where the parse error occured.
- // We split it up into two parts (the part which parsed,
- // and the part which didn't), so we can color them differently.
- if (i < input.length - 1) {
- i = furthest;
- lines = input.split('\n');
- line = (input.slice(0, i).match(/\n/g) || "").length + 1;
-
- for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
-
- error = {
- type: "Parse",
- message: "Syntax Error on line " + line,
- index: i,
- filename: env.filename,
- line: line,
- column: column,
- extract: [
- lines[line - 2],
- lines[line - 1],
- lines[line]
- ]
- };
- }
-
- if (this.imports.queue.length > 0) {
- finish = function () { callback(error, root) };
- } else {
- callback(error, root);
- }
- },
-
- //
- // Here in, the parsing rules/functions
- //
- // The basic structure of the syntax tree generated is as follows:
- //
- // Ruleset -> Rule -> Value -> Expression -> Entity
- //
- // Here's some LESS code:
- //
- // .class {
- // color: #fff;
- // border: 1px solid #000;
- // width: @w + 4px;
- // > .child {...}
- // }
- //
- // And here's what the parse tree might look like:
- //
- // Ruleset (Selector '.class', [
- // Rule ("color", Value ([Expression [Color #fff]]))
- // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
- // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
- // Ruleset (Selector [Element '>', '.child'], [...])
- // ])
- //
- // In general, most rules will try to parse a token with the `$()` function, and if the return
- // value is truly, will return a new node, of the relevant type. Sometimes, we need to check
- // first, before parsing, that's when we use `peek()`.
- //
- parsers: {
- //
- // The `primary` rule is the *entry* and *exit* point of the parser.
- // The rules here can appear at any level of the parse tree.
- //
- // The recursive nature of the grammar is an interplay between the `block`
- // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
- // as represented by this simplified grammar:
- //
- // primary → (ruleset | rule)+
- // ruleset → selector+ block
- // block → '{' primary '}'
- //
- // Only at one point is the primary rule not called from the
- // block rule: at the root level.
- //
- primary: function () {
- var node, root = [];
-
- while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
- $(this.mixin.call) || $(this.comment) || $(this.directive))
- || $(/^[\s\n]+/)) {
- node && root.push(node);
- }
- return root;
- },
-
- // We create a Comment node for CSS comments `/* */`,
- // but keep the LeSS comments `//` silent, by just skipping
- // over them.
- comment: function () {
- var comment;
-
- if (input.charAt(i) !== '/') return;
-
- if (input.charAt(i + 1) === '/') {
- return new(tree.Comment)($(/^\/\/.*/), true);
- } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
- return new(tree.Comment)(comment);
- }
- },
-
- //
- // Entities are tokens which can be found inside an Expression
- //
- entities: {
- //
- // A string, which supports escaping " and '
- //
- // "milky way" 'he\'s the one!'
- //
- quoted: function () {
- var str, j = i, e;
-
- if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
- if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
-
- e && $('~');
-
- if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
- return new(tree.Quoted)(str[0], str[1] || str[2], e);
- }
- },
-
- //
- // A catch-all word, such as:
- //
- // black border-collapse
- //
- keyword: function () {
- var k;
-
- if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
- if (tree.colors.hasOwnProperty(k)) {
- // detect named color
- return new(tree.Color)(tree.colors[k].slice(1));
- } else {
- return new(tree.Keyword)(k);
- }
- }
- },
-
- //
- // A function call
- //
- // rgb(255, 0, 255)
- //
- // We also try to catch IE's `alpha()`, but let the `alpha` parser
- // deal with the details.
- //
- // The arguments are parsed with the `entities.arguments` parser.
- //
- call: function () {
- var name, args, index = i;
-
- if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return;
-
- name = name[1].toLowerCase();
-
- if (name === 'url') { return null }
- else { i += name.length }
-
- if (name === 'alpha') { return $(this.alpha) }
-
- $('('); // Parse the '(' and consume whitespace.
-
- args = $(this.entities.arguments);
-
- if (! $(')')) return;
-
- if (name) { return new(tree.Call)(name, args, index, env.filename) }
- },
- arguments: function () {
- var args = [], arg;
-
- while (arg = $(this.entities.assignment) || $(this.expression)) {
- args.push(arg);
- if (! $(',')) { break }
- }
- return args;
- },
- literal: function () {
- return $(this.entities.dimension) ||
- $(this.entities.color) ||
- $(this.entities.quoted);
- },
-
- // Assignments are argument entities for calls.
- // They are present in ie filter properties as shown below.
- //
- // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
- //
-
- assignment: function () {
- var key, value;
- if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) {
- return new(tree.Assignment)(key, value);
- }
- },
-
- //
- // Parse url() tokens
- //
- // We use a specific rule for urls, because they don't really behave like
- // standard function calls. The difference is that the argument doesn't have
- // to be enclosed within a string, so it can't be parsed as an Expression.
- //
- url: function () {
- var value;
-
- if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
- value = $(this.entities.quoted) || $(this.entities.variable) ||
- $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || "";
-
- expect(')');
-
- return new(tree.URL)((value.value || value.data || value instanceof tree.Variable)
- ? value : new(tree.Anonymous)(value), imports.paths);
- },
-
- dataURI: function () {
- var obj;
-
- if ($(/^data:/)) {
- obj = {};
- obj.mime = $(/^[^\/]+\/[^,;)]+/) || '';
- obj.charset = $(/^;\s*charset=[^,;)]+/) || '';
- obj.base64 = $(/^;\s*base64/) || '';
- obj.data = $(/^,\s*[^)]+/);
-
- if (obj.data) { return obj }
- }
- },
-
- //
- // A Variable entity, such as `@fink`, in
- //
- // width: @fink + 2px
- //
- // We use a different parser for variable definitions,
- // see `parsers.variable`.
- //
- variable: function () {
- var name, index = i;
-
- if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
- return new(tree.Variable)(name, index, env.filename);
- }
- },
-
- //
- // A Hexadecimal color
- //
- // #4F3C2F
- //
- // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
- //
- color: function () {
- var rgb;
-
- if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) {
- return new(tree.Color)(rgb[1]);
- }
- },
-
- //
- // A Dimension, that is, a number and a unit
- //
- // 0.5em 95%
- //
- dimension: function () {
- var value, c = input.charCodeAt(i);
- if ((c > 57 || c < 45) || c === 47) return;
-
- if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
- return new(tree.Dimension)(value[1], value[2]);
- }
- },
-
- //
- // JavaScript code to be evaluated
- //
- // `window.location.href`
- //
- javascript: function () {
- var str, j = i, e;
-
- if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
- if (input.charAt(j) !== '`') { return }
-
- e && $('~');
-
- if (str = $(/^`([^`]*)`/)) {
- return new(tree.JavaScript)(str[1], i, e);
- }
- }
- },
-
- //
- // The variable part of a variable definition. Used in the `rule` parser
- //
- // @fink:
- //
- variable: function () {
- var name;
-
- if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
- },
-
- //
- // A font size/line-height shorthand
- //
- // small/12px
- //
- // We need to peek first, or we'll match on keywords and dimensions
- //
- shorthand: function () {
- var a, b;
-
- if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return;
-
- if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) {
- return new(tree.Shorthand)(a, b);
- }
- },
-
- //
- // Mixins
- //
- mixin: {
- //
- // A Mixin call, with an optional argument list
- //
- // #mixins > .square(#fff);
- // .rounded(4px, black);
- // .button;
- //
- // The `while` loop is there because mixins can be
- // namespaced, but we only support the child and descendant
- // selector for now.
- //
- call: function () {
- var elements = [], e, c, args, index = i, s = input.charAt(i), important = false;
-
- if (s !== '.' && s !== '#') { return }
-
- while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
- elements.push(new(tree.Element)(c, e, i));
- c = $('>');
- }
- $('(') && (args = $(this.entities.arguments)) && $(')');
-
- if ($(this.important)) {
- important = true;
- }
-
- if (elements.length > 0 && ($(';') || peek('}'))) {
- return new(tree.mixin.Call)(elements, args || [], index, env.filename, important);
- }
- },
-
- //
- // A Mixin definition, with a list of parameters
- //
- // .rounded (@radius: 2px, @color) {
- // ...
- // }
- //
- // Until we have a finer grained state-machine, we have to
- // do a look-ahead, to make sure we don't have a mixin call.
- // See the `rule` function for more information.
- //
- // We start by matching `.rounded (`, and then proceed on to
- // the argument list, which has optional default values.
- // We store the parameters in `params`, with a `value` key,
- // if there is a value, such as in the case of `@radius`.
- //
- // Once we've got our params list, and a closing `)`, we parse
- // the `{...}` block.
- //
- definition: function () {
- var name, params = [], match, ruleset, param, value, cond, variadic = false;
- if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
- peek(/^[^{]*(;|})/)) return;
-
- save();
-
- if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) {
- name = match[1];
-
- do {
- if (input.charAt(i) === '.' && $(/^\.{3}/)) {
- variadic = true;
- break;
- } else if (param = $(this.entities.variable) || $(this.entities.literal)
- || $(this.entities.keyword)) {
- // Variable
- if (param instanceof tree.Variable) {
- if ($(':')) {
- value = expect(this.expression, 'expected expression');
- params.push({ name: param.name, value: value });
- } else if ($(/^\.{3}/)) {
- params.push({ name: param.name, variadic: true });
- variadic = true;
- break;
- } else {
- params.push({ name: param.name });
- }
- } else {
- params.push({ value: param });
- }
- } else {
- break;
- }
- } while ($(','))
-
- expect(')');
-
- if ($(/^when/)) { // Guard
- cond = expect(this.conditions, 'expected condition');
- }
-
- ruleset = $(this.block);
-
- if (ruleset) {
- return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
- } else {
- restore();
- }
- }
- }
- },
-
- //
- // Entities are the smallest recognized token,
- // and can be found inside a rule's value.
- //
- entity: function () {
- return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
- $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) ||
- $(this.comment);
- },
-
- //
- // A Rule terminator. Note that we use `peek()` to check for '}',
- // because the `block` rule will be expecting it, but we still need to make sure
- // it's there, if ';' was ommitted.
- //
- end: function () {
- return $(';') || peek('}');
- },
-
- //
- // IE's alpha function
- //
- // alpha(opacity=88)
- //
- alpha: function () {
- var value;
-
- if (! $(/^\(opacity=/i)) return;
- if (value = $(/^\d+/) || $(this.entities.variable)) {
- expect(')');
- return new(tree.Alpha)(value);
- }
- },
-
- //
- // A Selector Element
- //
- // div
- // + h1
- // #socks
- // input[type="text"]
- //
- // Elements are the building blocks for Selectors,
- // they are made out of a `Combinator` (see combinator rule),
- // and an element name, such as a tag a class, or `*`.
- //
- element: function () {
- var e, t, c, v;
-
- c = $(this.combinator);
- e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) ||
- $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
-
- if (! e) {
- $('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v));
- }
-
- if (e) { return new(tree.Element)(c, e, i) }
-
- if (c.value && c.value.charAt(0) === '&') {
- return new(tree.Element)(c, null, i);
- }
- },
-
- //
- // Combinators combine elements together, in a Selector.
- //
- // Because our parser isn't white-space sensitive, special care
- // has to be taken, when parsing the descendant combinator, ` `,
- // as it's an empty space. We have to check the previous character
- // in the input, to see if it's a ` ` character. More info on how
- // we deal with this in *combinator.js*.
- //
- combinator: function () {
- var match, c = input.charAt(i);
-
- if (c === '>' || c === '+' || c === '~') {
- i++;
- while (input.charAt(i) === ' ') { i++ }
- return new(tree.Combinator)(c);
- } else if (c === '&') {
- match = '&';
- i++;
- if(input.charAt(i) === ' ') {
- match = '& ';
- }
- while (input.charAt(i) === ' ') { i++ }
- return new(tree.Combinator)(match);
- } else if (input.charAt(i - 1) === ' ') {
- return new(tree.Combinator)(" ");
- } else {
- return new(tree.Combinator)(null);
- }
- },
-
- //
- // A CSS Selector
- //
- // .class > div + h1
- // li a:hover
- //
- // Selectors are made out of one or more Elements, see above.
- //
- selector: function () {
- var sel, e, elements = [], c, match;
-
- if ($('(')) {
- sel = $(this.entity);
- expect(')');
- return new(tree.Selector)([new(tree.Element)('', sel, i)]);
- }
-
- while (e = $(this.element)) {
- c = input.charAt(i);
- elements.push(e)
- if (c === '{' || c === '}' || c === ';' || c === ',') { break }
- }
-
- if (elements.length > 0) { return new(tree.Selector)(elements) }
- },
- tag: function () {
- return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*');
- },
- attribute: function () {
- var attr = '', key, val, op;
-
- if (! $('[')) return;
-
- if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) {
- if ((op = $(/^[|~*$^]?=/)) &&
- (val = $(this.entities.quoted) || $(/^[\w-]+/))) {
- attr = [key, op, val.toCSS ? val.toCSS() : val].join('');
- } else { attr = key }
- }
-
- if (! $(']')) return;
-
- if (attr) { return "[" + attr + "]" }
- },
-
- //
- // The `block` rule is used by `ruleset` and `mixin.definition`.
- // It's a wrapper around the `primary` rule, with added `{}`.
- //
- block: function () {
- var content;
-
- if ($('{') && (content = $(this.primary)) && $('}')) {
- return content;
- }
- },
-
- //
- // div, .class, body > p {...}
- //
- ruleset: function () {
- var selectors = [], s, rules, match;
- save();
-
- while (s = $(this.selector)) {
- selectors.push(s);
- $(this.comment);
- if (! $(',')) { break }
- $(this.comment);
- }
-
- if (selectors.length > 0 && (rules = $(this.block))) {
- return new(tree.Ruleset)(selectors, rules, env.strictImports);
- } else {
- // Backtrack
- furthest = i;
- restore();
- }
- },
- rule: function () {
- var name, value, c = input.charAt(i), important, match;
- save();
-
- if (c === '.' || c === '#' || c === '&') { return }
-
- if (name = $(this.variable) || $(this.property)) {
- if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) {
- i += match[0].length - 1;
- value = new(tree.Anonymous)(match[1]);
- } else if (name === "font") {
- value = $(this.font);
- } else {
- value = $(this.value);
- }
- important = $(this.important);
-
- if (value && $(this.end)) {
- return new(tree.Rule)(name, value, important, memo);
- } else {
- furthest = i;
- restore();
- }
- }
- },
-
- //
- // An @import directive
- //
- // @import "lib";
- //
- // Depending on our environemnt, importing is done differently:
- // In the browser, it's an XHR request, in Node, it would be a
- // file-system operation. The function used for importing is
- // stored in `import`, which we pass to the Import constructor.
- //
- "import": function () {
- var path, features, index = i;
- if ($(/^@import\s+/) &&
- (path = $(this.entities.quoted) || $(this.entities.url))) {
- features = $(this.mediaFeatures);
- if ($(';')) {
- return new(tree.Import)(path, imports, features, index);
- }
- }
- },
-
- mediaFeature: function () {
- var e, p, nodes = [];
-
- do {
- if (e = $(this.entities.keyword)) {
- nodes.push(e);
- } else if ($('(')) {
- p = $(this.property);
- e = $(this.entity);
- if ($(')')) {
- if (p && e) {
- nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true)));
- } else if (e) {
- nodes.push(new(tree.Paren)(e));
- } else {
- return null;
- }
- } else { return null }
- }
- } while (e);
-
- if (nodes.length > 0) {
- return new(tree.Expression)(nodes);
- }
- },
-
- mediaFeatures: function () {
- var e, features = [];
-
- do {
- if (e = $(this.mediaFeature)) {
- features.push(e);
- if (! $(',')) { break }
- } else if (e = $(this.entities.variable)) {
- features.push(e);
- if (! $(',')) { break }
- }
- } while (e);
-
- return features.length > 0 ? features : null;
- },
-
- media: function () {
- var features, rules;
-
- if ($(/^@media/)) {
- features = $(this.mediaFeatures);
-
- if (rules = $(this.block)) {
- return new(tree.Media)(rules, features);
- }
- }
- },
-
- //
- // A CSS Directive
- //
- // @charset "utf-8";
- //
- directive: function () {
- var name, value, rules, types, e, nodes;
-
- if (input.charAt(i) !== '@') return;
-
- if (value = $(this['import']) || $(this.media)) {
- return value;
- } else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) {
- types = ($(/^[^{]+/) || '').trim();
- if (rules = $(this.block)) {
- return new(tree.Directive)(name + " " + types, rules);
- }
- } else if (name = $(/^@[-a-z]+/)) {
- if (name === '@font-face') {
- if (rules = $(this.block)) {
- return new(tree.Directive)(name, rules);
- }
- } else if ((value = $(this.entity)) && $(';')) {
- return new(tree.Directive)(name, value);
- }
- }
- },
- font: function () {
- var value = [], expression = [], weight, shorthand, font, e;
-
- while (e = $(this.shorthand) || $(this.entity)) {
- expression.push(e);
- }
- value.push(new(tree.Expression)(expression));
-
- if ($(',')) {
- while (e = $(this.expression)) {
- value.push(e);
- if (! $(',')) { break }
- }
- }
- return new(tree.Value)(value);
- },
-
- //
- // A Value is a comma-delimited list of Expressions
- //
- // font-family: Baskerville, Georgia, serif;
- //
- // In a Rule, a Value represents everything after the `:`,
- // and before the `;`.
- //
- value: function () {
- var e, expressions = [], important;
-
- while (e = $(this.expression)) {
- expressions.push(e);
- if (! $(',')) { break }
- }
-
- if (expressions.length > 0) {
- return new(tree.Value)(expressions);
- }
- },
- important: function () {
- if (input.charAt(i) === '!') {
- return $(/^! *important/);
- }
- },
- sub: function () {
- var e;
-
- if ($('(') && (e = $(this.expression)) && $(')')) {
- return e;
- }
- },
- multiplication: function () {
- var m, a, op, operation;
- if (m = $(this.operand)) {
- while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) {
- operation = new(tree.Operation)(op, [operation || m, a]);
- }
- return operation || m;
- }
- },
- addition: function () {
- var m, a, op, operation;
- if (m = $(this.multiplication)) {
- while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) &&
- (a = $(this.multiplication))) {
- operation = new(tree.Operation)(op, [operation || m, a]);
- }
- return operation || m;
- }
- },
- conditions: function () {
- var a, b, index = i, condition;
-
- if (a = $(this.condition)) {
- while ($(',') && (b = $(this.condition))) {
- condition = new(tree.Condition)('or', condition || a, b, index);
- }
- return condition || a;
- }
- },
- condition: function () {
- var a, b, c, op, index = i, negate = false;
-
- if ($(/^not/)) { negate = true }
- expect('(');
- if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
- if (op = $(/^(?:>=|=<|[<=>])/)) {
- if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
- c = new(tree.Condition)(op, a, b, index, negate);
- } else {
- error('expected expression');
- }
- } else {
- c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
- }
- expect(')');
- return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c;
- }
- },
-
- //
- // An operand is anything that can be part of an operation,
- // such as a Color, or a Variable
- //
- operand: function () {
- var negate, p = input.charAt(i + 1);
-
- if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') }
- var o = $(this.sub) || $(this.entities.dimension) ||
- $(this.entities.color) || $(this.entities.variable) ||
- $(this.entities.call);
- return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o])
- : o;
- },
-
- //
- // Expressions either represent mathematical operations,
- // or white-space delimited Entities.
- //
- // 1px solid black
- // @var * 2
- //
- expression: function () {
- var e, delim, entities = [], d;
-
- while (e = $(this.addition) || $(this.entity)) {
- entities.push(e);
- }
- if (entities.length > 0) {
- return new(tree.Expression)(entities);
- }
- },
- property: function () {
- var name;
-
- if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) {
- return name[1];
- }
- }
- }
- };
-};
-
-if (less.mode === 'browser' || less.mode === 'rhino') {
- //
- // Used by `@import` directives
- //
- less.Parser.importer = function (path, paths, callback, env) {
- if (!/^([a-z]+:)?\//.test(path) && paths.length > 0) {
- path = paths[0] + path;
- }
- // We pass `true` as 3rd argument, to force the reload of the import.
- // This is so we can get the syntax tree as opposed to just the CSS output,
- // as we need this to evaluate the current stylesheet.
- loadStyleSheet({ href: path, title: path, type: env.mime }, function (e) {
- if (e && typeof(env.errback) === "function") {
- env.errback.call(null, path, paths, callback, env);
- } else {
- callback.apply(null, arguments);
- }
- }, true);
- };
-}
-
-(function (tree) {
-
-tree.functions = {
- rgb: function (r, g, b) {
- return this.rgba(r, g, b, 1.0);
- },
- rgba: function (r, g, b, a) {
- var rgb = [r, g, b].map(function (c) { return number(c) }),
- a = number(a);
- return new(tree.Color)(rgb, a);
- },
- hsl: function (h, s, l) {
- return this.hsla(h, s, l, 1.0);
- },
- hsla: function (h, s, l, a) {
- h = (number(h) % 360) / 360;
- s = number(s); l = number(l); a = number(a);
-
- var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
- var m1 = l * 2 - m2;
-
- return this.rgba(hue(h + 1/3) * 255,
- hue(h) * 255,
- hue(h - 1/3) * 255,
- a);
-
- function hue(h) {
- h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
- if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
- else if (h * 2 < 1) return m2;
- else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
- else return m1;
- }
- },
- hue: function (color) {
- return new(tree.Dimension)(Math.round(color.toHSL().h));
- },
- saturation: function (color) {
- return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
- },
- lightness: function (color) {
- return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
- },
- alpha: function (color) {
- return new(tree.Dimension)(color.toHSL().a);
- },
- saturate: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.s += amount.value / 100;
- hsl.s = clamp(hsl.s);
- return hsla(hsl);
- },
- desaturate: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.s -= amount.value / 100;
- hsl.s = clamp(hsl.s);
- return hsla(hsl);
- },
- lighten: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.l += amount.value / 100;
- hsl.l = clamp(hsl.l);
- return hsla(hsl);
- },
- darken: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.l -= amount.value / 100;
- hsl.l = clamp(hsl.l);
- return hsla(hsl);
- },
- fadein: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.a += amount.value / 100;
- hsl.a = clamp(hsl.a);
- return hsla(hsl);
- },
- fadeout: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.a -= amount.value / 100;
- hsl.a = clamp(hsl.a);
- return hsla(hsl);
- },
- fade: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.a = amount.value / 100;
- hsl.a = clamp(hsl.a);
- return hsla(hsl);
- },
- spin: function (color, amount) {
- var hsl = color.toHSL();
- var hue = (hsl.h + amount.value) % 360;
-
- hsl.h = hue < 0 ? 360 + hue : hue;
-
- return hsla(hsl);
- },
- //
- // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
- // http://sass-lang.com
- //
- mix: function (color1, color2, weight) {
- var p = weight.value / 100.0;
- var w = p * 2 - 1;
- var a = color1.toHSL().a - color2.toHSL().a;
-
- var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
- var w2 = 1 - w1;
-
- var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
- color1.rgb[1] * w1 + color2.rgb[1] * w2,
- color1.rgb[2] * w1 + color2.rgb[2] * w2];
-
- var alpha = color1.alpha * p + color2.alpha * (1 - p);
-
- return new(tree.Color)(rgb, alpha);
- },
- greyscale: function (color) {
- return this.desaturate(color, new(tree.Dimension)(100));
- },
- e: function (str) {
- return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
- },
- escape: function (str) {
- return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
- },
- '%': function (quoted /* arg, arg, ...*/) {
- var args = Array.prototype.slice.call(arguments, 1),
- str = quoted.value;
-
- for (var i = 0; i < args.length; i++) {
- str = str.replace(/%[sda]/i, function(token) {
- var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
- return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
- });
- }
- str = str.replace(/%%/g, '%');
- return new(tree.Quoted)('"' + str + '"', str);
- },
- round: function (n) {
- return this._math('round', n);
- },
- ceil: function (n) {
- return this._math('ceil', n);
- },
- floor: function (n) {
- return this._math('floor', n);
- },
- _math: function (fn, n) {
- if (n instanceof tree.Dimension) {
- return new(tree.Dimension)(Math[fn](number(n)), n.unit);
- } else if (typeof(n) === 'number') {
- return Math[fn](n);
- } else {
- throw { type: "Argument", message: "argument must be a number" };
- }
- },
- argb: function (color) {
- return new(tree.Anonymous)(color.toARGB());
-
- },
- percentage: function (n) {
- return new(tree.Dimension)(n.value * 100, '%');
- },
- color: function (n) {
- if (n instanceof tree.Quoted) {
- return new(tree.Color)(n.value.slice(1));
- } else {
- throw { type: "Argument", message: "argument must be a string" };
- }
- },
- iscolor: function (n) {
- return this._isa(n, tree.Color);
- },
- isnumber: function (n) {
- return this._isa(n, tree.Dimension);
- },
- isstring: function (n) {
- return this._isa(n, tree.Quoted);
- },
- iskeyword: function (n) {
- return this._isa(n, tree.Keyword);
- },
- isurl: function (n) {
- return this._isa(n, tree.URL);
- },
- ispixel: function (n) {
- return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False;
- },
- ispercentage: function (n) {
- return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False;
- },
- isem: function (n) {
- return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False;
- },
- _isa: function (n, Type) {
- return (n instanceof Type) ? tree.True : tree.False;
- }
-};
-
-function hsla(hsla) {
- return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a);
-}
-
-function number(n) {
- if (n instanceof tree.Dimension) {
- return parseFloat(n.unit == '%' ? n.value / 100 : n.value);
- } else if (typeof(n) === 'number') {
- return n;
- } else {
- throw {
- error: "RuntimeError",
- message: "color functions take numbers as parameters"
- };
- }
-}
-
-function clamp(val) {
- return Math.min(1, Math.max(0, val));
-}
-
-})(require('./tree'));
-(function (tree) {
- tree.colors = {
- 'aliceblue':'#f0f8ff',
- 'antiquewhite':'#faebd7',
- 'aqua':'#00ffff',
- 'aquamarine':'#7fffd4',
- 'azure':'#f0ffff',
- 'beige':'#f5f5dc',
- 'bisque':'#ffe4c4',
- 'black':'#000000',
- 'blanchedalmond':'#ffebcd',
- 'blue':'#0000ff',
- 'blueviolet':'#8a2be2',
- 'brown':'#a52a2a',
- 'burlywood':'#deb887',
- 'cadetblue':'#5f9ea0',
- 'chartreuse':'#7fff00',
- 'chocolate':'#d2691e',
- 'coral':'#ff7f50',
- 'cornflowerblue':'#6495ed',
- 'cornsilk':'#fff8dc',
- 'crimson':'#dc143c',
- 'cyan':'#00ffff',
- 'darkblue':'#00008b',
- 'darkcyan':'#008b8b',
- 'darkgoldenrod':'#b8860b',
- 'darkgray':'#a9a9a9',
- 'darkgrey':'#a9a9a9',
- 'darkgreen':'#006400',
- 'darkkhaki':'#bdb76b',
- 'darkmagenta':'#8b008b',
- 'darkolivegreen':'#556b2f',
- 'darkorange':'#ff8c00',
- 'darkorchid':'#9932cc',
- 'darkred':'#8b0000',
- 'darksalmon':'#e9967a',
- 'darkseagreen':'#8fbc8f',
- 'darkslateblue':'#483d8b',
- 'darkslategray':'#2f4f4f',
- 'darkslategrey':'#2f4f4f',
- 'darkturquoise':'#00ced1',
- 'darkviolet':'#9400d3',
- 'deeppink':'#ff1493',
- 'deepskyblue':'#00bfff',
- 'dimgray':'#696969',
- 'dimgrey':'#696969',
- 'dodgerblue':'#1e90ff',
- 'firebrick':'#b22222',
- 'floralwhite':'#fffaf0',
- 'forestgreen':'#228b22',
- 'fuchsia':'#ff00ff',
- 'gainsboro':'#dcdcdc',
- 'ghostwhite':'#f8f8ff',
- 'gold':'#ffd700',
- 'goldenrod':'#daa520',
- 'gray':'#808080',
- 'grey':'#808080',
- 'green':'#008000',
- 'greenyellow':'#adff2f',
- 'honeydew':'#f0fff0',
- 'hotpink':'#ff69b4',
- 'indianred':'#cd5c5c',
- 'indigo':'#4b0082',
- 'ivory':'#fffff0',
- 'khaki':'#f0e68c',
- 'lavender':'#e6e6fa',
- 'lavenderblush':'#fff0f5',
- 'lawngreen':'#7cfc00',
- 'lemonchiffon':'#fffacd',
- 'lightblue':'#add8e6',
- 'lightcoral':'#f08080',
- 'lightcyan':'#e0ffff',
- 'lightgoldenrodyellow':'#fafad2',
- 'lightgray':'#d3d3d3',
- 'lightgrey':'#d3d3d3',
- 'lightgreen':'#90ee90',
- 'lightpink':'#ffb6c1',
- 'lightsalmon':'#ffa07a',
- 'lightseagreen':'#20b2aa',
- 'lightskyblue':'#87cefa',
- 'lightslategray':'#778899',
- 'lightslategrey':'#778899',
- 'lightsteelblue':'#b0c4de',
- 'lightyellow':'#ffffe0',
- 'lime':'#00ff00',
- 'limegreen':'#32cd32',
- 'linen':'#faf0e6',
- 'magenta':'#ff00ff',
- 'maroon':'#800000',
- 'mediumaquamarine':'#66cdaa',
- 'mediumblue':'#0000cd',
- 'mediumorchid':'#ba55d3',
- 'mediumpurple':'#9370d8',
- 'mediumseagreen':'#3cb371',
- 'mediumslateblue':'#7b68ee',
- 'mediumspringgreen':'#00fa9a',
- 'mediumturquoise':'#48d1cc',
- 'mediumvioletred':'#c71585',
- 'midnightblue':'#191970',
- 'mintcream':'#f5fffa',
- 'mistyrose':'#ffe4e1',
- 'moccasin':'#ffe4b5',
- 'navajowhite':'#ffdead',
- 'navy':'#000080',
- 'oldlace':'#fdf5e6',
- 'olive':'#808000',
- 'olivedrab':'#6b8e23',
- 'orange':'#ffa500',
- 'orangered':'#ff4500',
- 'orchid':'#da70d6',
- 'palegoldenrod':'#eee8aa',
- 'palegreen':'#98fb98',
- 'paleturquoise':'#afeeee',
- 'palevioletred':'#d87093',
- 'papayawhip':'#ffefd5',
- 'peachpuff':'#ffdab9',
- 'peru':'#cd853f',
- 'pink':'#ffc0cb',
- 'plum':'#dda0dd',
- 'powderblue':'#b0e0e6',
- 'purple':'#800080',
- 'red':'#ff0000',
- 'rosybrown':'#bc8f8f',
- 'royalblue':'#4169e1',
- 'saddlebrown':'#8b4513',
- 'salmon':'#fa8072',
- 'sandybrown':'#f4a460',
- 'seagreen':'#2e8b57',
- 'seashell':'#fff5ee',
- 'sienna':'#a0522d',
- 'silver':'#c0c0c0',
- 'skyblue':'#87ceeb',
- 'slateblue':'#6a5acd',
- 'slategray':'#708090',
- 'slategrey':'#708090',
- 'snow':'#fffafa',
- 'springgreen':'#00ff7f',
- 'steelblue':'#4682b4',
- 'tan':'#d2b48c',
- 'teal':'#008080',
- 'thistle':'#d8bfd8',
- 'tomato':'#ff6347',
- 'turquoise':'#40e0d0',
- 'violet':'#ee82ee',
- 'wheat':'#f5deb3',
- 'white':'#ffffff',
- 'whitesmoke':'#f5f5f5',
- 'yellow':'#ffff00',
- 'yellowgreen':'#9acd32'
- };
-})(require('./tree'));
-(function (tree) {
-
-tree.Alpha = function (val) {
- this.value = val;
-};
-tree.Alpha.prototype = {
- toCSS: function () {
- return "alpha(opacity=" +
- (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
- },
- eval: function (env) {
- if (this.value.eval) { this.value = this.value.eval(env) }
- return this;
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Anonymous = function (string) {
- this.value = string.value || string;
-};
-tree.Anonymous.prototype = {
- toCSS: function () {
- return this.value;
- },
- eval: function () { return this }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Assignment = function (key, val) {
- this.key = key;
- this.value = val;
-};
-tree.Assignment.prototype = {
- toCSS: function () {
- return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value);
- },
- eval: function (env) {
- if (this.value.eval) { this.value = this.value.eval(env) }
- return this;
- }
-};
-
-})(require('../tree'));(function (tree) {
-
-//
-// A function call node.
-//
-tree.Call = function (name, args, index, filename) {
- this.name = name;
- this.args = args;
- this.index = index;
- this.filename = filename;
-};
-tree.Call.prototype = {
- //
- // When evaluating a function call,
- // we either find the function in `tree.functions` [1],
- // in which case we call it, passing the evaluated arguments,
- // or we simply print it out as it appeared originally [2].
- //
- // The *functions.js* file contains the built-in functions.
- //
- // The reason why we evaluate the arguments, is in the case where
- // we try to pass a variable to a function, like: `saturate(@color)`.
- // The function should receive the value, not the variable.
- //
- eval: function (env) {
- var args = this.args.map(function (a) { return a.eval(env) });
-
- if (this.name in tree.functions) { // 1.
- try {
- return tree.functions[this.name].apply(tree.functions, args);
- } catch (e) {
- throw { type: e.type || "Runtime",
- message: "error evaluating function `" + this.name + "`" +
- (e.message ? ': ' + e.message : ''),
- index: this.index, filename: this.filename };
- }
- } else { // 2.
- return new(tree.Anonymous)(this.name +
- "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")");
- }
- },
-
- toCSS: function (env) {
- return this.eval(env).toCSS();
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-//
-// RGB Colors - #ff0014, #eee
-//
-tree.Color = function (rgb, a) {
- //
- // The end goal here, is to parse the arguments
- // into an integer triplet, such as `128, 255, 0`
- //
- // This facilitates operations and conversions.
- //
- if (Array.isArray(rgb)) {
- this.rgb = rgb;
- } else if (rgb.length == 6) {
- this.rgb = rgb.match(/.{2}/g).map(function (c) {
- return parseInt(c, 16);
- });
- } else {
- this.rgb = rgb.split('').map(function (c) {
- return parseInt(c + c, 16);
- });
- }
- this.alpha = typeof(a) === 'number' ? a : 1;
-};
-tree.Color.prototype = {
- eval: function () { return this },
-
- //
- // If we have some transparency, the only way to represent it
- // is via `rgba`. Otherwise, we use the hex representation,
- // which has better compatibility with older browsers.
- // Values are capped between `0` and `255`, rounded and zero-padded.
- //
- toCSS: function () {
- if (this.alpha < 1.0) {
- return "rgba(" + this.rgb.map(function (c) {
- return Math.round(c);
- }).concat(this.alpha).join(', ') + ")";
- } else {
- return '#' + this.rgb.map(function (i) {
- i = Math.round(i);
- i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
- return i.length === 1 ? '0' + i : i;
- }).join('');
- }
- },
-
- //
- // Operations have to be done per-channel, if not,
- // channels will spill onto each other. Once we have
- // our result, in the form of an integer triplet,
- // we create a new Color node to hold the result.
- //
- operate: function (op, other) {
- var result = [];
-
- if (! (other instanceof tree.Color)) {
- other = other.toColor();
- }
-
- for (var c = 0; c < 3; c++) {
- result[c] = tree.operate(op, this.rgb[c], other.rgb[c]);
- }
- return new(tree.Color)(result, this.alpha + other.alpha);
- },
-
- toHSL: function () {
- var r = this.rgb[0] / 255,
- g = this.rgb[1] / 255,
- b = this.rgb[2] / 255,
- a = this.alpha;
-
- var max = Math.max(r, g, b), min = Math.min(r, g, b);
- var h, s, l = (max + min) / 2, d = max - min;
-
- if (max === min) {
- h = s = 0;
- } else {
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
-
- switch (max) {
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
- case g: h = (b - r) / d + 2; break;
- case b: h = (r - g) / d + 4; break;
- }
- h /= 6;
- }
- return { h: h * 360, s: s, l: l, a: a };
- },
- toARGB: function () {
- var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
- return '#' + argb.map(function (i) {
- i = Math.round(i);
- i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
- return i.length === 1 ? '0' + i : i;
- }).join('');
- }
-};
-
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Comment = function (value, silent) {
- this.value = value;
- this.silent = !!silent;
-};
-tree.Comment.prototype = {
- toCSS: function (env) {
- return env.compress ? '' : this.value;
- },
- eval: function () { return this }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Condition = function (op, l, r, i, negate) {
- this.op = op.trim();
- this.lvalue = l;
- this.rvalue = r;
- this.index = i;
- this.negate = negate;
-};
-tree.Condition.prototype.eval = function (env) {
- var a = this.lvalue.eval(env),
- b = this.rvalue.eval(env);
-
- var i = this.index, result;
-
- var result = (function (op) {
- switch (op) {
- case 'and':
- return a && b;
- case 'or':
- return a || b;
- default:
- if (a.compare) {
- result = a.compare(b);
- } else if (b.compare) {
- result = b.compare(a);
- } else {
- throw { type: "Type",
- message: "Unable to perform comparison",
- index: i };
- }
- switch (result) {
- case -1: return op === '<' || op === '=<';
- case 0: return op === '=' || op === '>=' || op === '=<';
- case 1: return op === '>' || op === '>=';
- }
- }
- })(this.op);
- return this.negate ? !result : result;
-};
-
-})(require('../tree'));
-(function (tree) {
-
-//
-// A number with a unit
-//
-tree.Dimension = function (value, unit) {
- this.value = parseFloat(value);
- this.unit = unit || null;
-};
-
-tree.Dimension.prototype = {
- eval: function () { return this },
- toColor: function () {
- return new(tree.Color)([this.value, this.value, this.value]);
- },
- toCSS: function () {
- var css = this.value + this.unit;
- return css;
- },
-
- // In an operation between two Dimensions,
- // we default to the first Dimension's unit,
- // so `1px + 2em` will yield `3px`.
- // In the future, we could implement some unit
- // conversions such that `100cm + 10mm` would yield
- // `101cm`.
- operate: function (op, other) {
- return new(tree.Dimension)
- (tree.operate(op, this.value, other.value),
- this.unit || other.unit);
- },
-
- // TODO: Perform unit conversion before comparing
- compare: function (other) {
- if (other instanceof tree.Dimension) {
- if (other.value > this.value) {
- return -1;
- } else if (other.value < this.value) {
- return 1;
- } else {
- return 0;
- }
- } else {
- return -1;
- }
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Directive = function (name, value, features) {
- this.name = name;
-
- if (Array.isArray(value)) {
- this.ruleset = new(tree.Ruleset)([], value);
- this.ruleset.allowImports = true;
- } else {
- this.value = value;
- }
-};
-tree.Directive.prototype = {
- toCSS: function (ctx, env) {
- if (this.ruleset) {
- this.ruleset.root = true;
- return this.name + (env.compress ? '{' : ' {\n ') +
- this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
- (env.compress ? '}': '\n}\n');
- } else {
- return this.name + ' ' + this.value.toCSS() + ';\n';
- }
- },
- eval: function (env) {
- env.frames.unshift(this);
- this.ruleset = this.ruleset && this.ruleset.eval(env);
- env.frames.shift();
- return this;
- },
- variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
- find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
- rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Element = function (combinator, value, index) {
- this.combinator = combinator instanceof tree.Combinator ?
- combinator : new(tree.Combinator)(combinator);
-
- if (typeof(value) === 'string') {
- this.value = value.trim();
- } else if (value) {
- this.value = value;
- } else {
- this.value = "";
- }
- this.index = index;
-};
-tree.Element.prototype.eval = function (env) {
- return new(tree.Element)(this.combinator,
- this.value.eval ? this.value.eval(env) : this.value,
- this.index);
-};
-tree.Element.prototype.toCSS = function (env) {
- return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value);
-};
-
-tree.Combinator = function (value) {
- if (value === ' ') {
- this.value = ' ';
- } else if (value === '& ') {
- this.value = '& ';
- } else {
- this.value = value ? value.trim() : "";
- }
-};
-tree.Combinator.prototype.toCSS = function (env) {
- return {
- '' : '',
- ' ' : ' ',
- '&' : '',
- '& ' : ' ',
- ':' : ' :',
- '+' : env.compress ? '+' : ' + ',
- '~' : env.compress ? '~' : ' ~ ',
- '>' : env.compress ? '>' : ' > '
- }[this.value];
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Expression = function (value) { this.value = value };
-tree.Expression.prototype = {
- eval: function (env) {
- if (this.value.length > 1) {
- return new(tree.Expression)(this.value.map(function (e) {
- return e.eval(env);
- }));
- } else if (this.value.length === 1) {
- return this.value[0].eval(env);
- } else {
- return this;
- }
- },
- toCSS: function (env) {
- return this.value.map(function (e) {
- return e.toCSS ? e.toCSS(env) : '';
- }).join(' ');
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-//
-// CSS @import node
-//
-// The general strategy here is that we don't want to wait
-// for the parsing to be completed, before we start importing
-// the file. That's because in the context of a browser,
-// most of the time will be spent waiting for the server to respond.
-//
-// On creation, we push the import path to our import queue, though
-// `import,push`, we also pass it a callback, which it'll call once
-// the file has been fetched, and parsed.
-//
-tree.Import = function (path, imports, features, index) {
- var that = this;
-
- this.index = index;
- this._path = path;
- this.features = features && new(tree.Value)(features);
-
- // The '.less' extension is optional
- if (path instanceof tree.Quoted) {
- this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less';
- } else {
- this.path = path.value.value || path.value;
- }
-
- this.css = /css(\?.*)?$/.test(this.path);
-
- // Only pre-compile .less files
- if (! this.css) {
- imports.push(this.path, function (e, root) {
- if (e) { e.index = index }
- that.root = root || new(tree.Ruleset)([], []);
- });
- }
-};
-
-//
-// The actual import node doesn't return anything, when converted to CSS.
-// The reason is that it's used at the evaluation stage, so that the rules
-// it imports can be treated like any other rules.
-//
-// In `eval`, we make sure all Import nodes get evaluated, recursively, so
-// we end up with a flat structure, which can easily be imported in the parent
-// ruleset.
-//
-tree.Import.prototype = {
- toCSS: function (env) {
- var features = this.features ? ' ' + this.features.toCSS(env) : '';
-
- if (this.css) {
- return "@import " + this._path.toCSS() + features + ';\n';
- } else {
- return "";
- }
- },
- eval: function (env) {
- var ruleset, features = this.features && this.features.eval(env);
-
- if (this.css) {
- return this;
- } else {
- ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
-
- for (var i = 0; i < ruleset.rules.length; i++) {
- if (ruleset.rules[i] instanceof tree.Import) {
- Array.prototype
- .splice
- .apply(ruleset.rules,
- [i, 1].concat(ruleset.rules[i].eval(env)));
- }
- }
- return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
- }
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.JavaScript = function (string, index, escaped) {
- this.escaped = escaped;
- this.expression = string;
- this.index = index;
-};
-tree.JavaScript.prototype = {
- eval: function (env) {
- var result,
- that = this,
- context = {};
-
- var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
- return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
- });
-
- try {
- expression = new(Function)('return (' + expression + ')');
- } catch (e) {
- throw { message: "JavaScript evaluation error: `" + expression + "`" ,
- index: this.index };
- }
-
- for (var k in env.frames[0].variables()) {
- context[k.slice(1)] = {
- value: env.frames[0].variables()[k].value,
- toJS: function () {
- return this.value.eval(env).toCSS();
- }
- };
- }
-
- try {
- result = expression.call(context);
- } catch (e) {
- throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
- index: this.index };
- }
- if (typeof(result) === 'string') {
- return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
- } else if (Array.isArray(result)) {
- return new(tree.Anonymous)(result.join(', '));
- } else {
- return new(tree.Anonymous)(result);
- }
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Keyword = function (value) { this.value = value };
-tree.Keyword.prototype = {
- eval: function () { return this },
- toCSS: function () { return this.value },
- compare: function (other) {
- if (other instanceof tree.Keyword) {
- return other.value === this.value ? 0 : 1;
- } else {
- return -1;
- }
- }
-};
-
-tree.True = new(tree.Keyword)('true');
-tree.False = new(tree.Keyword)('false');
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Media = function (value, features) {
- var el = new(tree.Element)('&', null, 0),
- selectors = [new(tree.Selector)([el])];
-
- this.features = new(tree.Value)(features);
- this.ruleset = new(tree.Ruleset)(selectors, value);
- this.ruleset.allowImports = true;
-};
-tree.Media.prototype = {
- toCSS: function (ctx, env) {
- var features = this.features.toCSS(env);
-
- this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia);
- return '@media ' + features + (env.compress ? '{' : ' {\n ') +
- this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
- (env.compress ? '}': '\n}\n');
- },
- eval: function (env) {
- if (!env.mediaBlocks) {
- env.mediaBlocks = [];
- env.mediaPath = [];
- }
-
- var blockIndex = env.mediaBlocks.length;
- env.mediaPath.push(this);
- env.mediaBlocks.push(this);
-
- var media = new(tree.Media)([], []);
- media.features = this.features.eval(env);
-
- env.frames.unshift(this.ruleset);
- media.ruleset = this.ruleset.eval(env);
- env.frames.shift();
-
- env.mediaBlocks[blockIndex] = media;
- env.mediaPath.pop();
-
- return env.mediaPath.length === 0 ? media.evalTop(env) :
- media.evalNested(env)
- },
- variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
- find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
- rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) },
-
- evalTop: function (env) {
- var result = this;
-
- // Render all dependent Media blocks.
- if (env.mediaBlocks.length > 1) {
- var el = new(tree.Element)('&', null, 0);
- var selectors = [new(tree.Selector)([el])];
- result = new(tree.Ruleset)(selectors, env.mediaBlocks);
- result.multiMedia = true;
- }
-
- delete env.mediaBlocks;
- delete env.mediaPath;
-
- return result;
- },
- evalNested: function (env) {
- var i, value,
- path = env.mediaPath.concat([this]);
-
- // Extract the media-query conditions separated with `,` (OR).
- for (i = 0; i < path.length; i++) {
- value = path[i].features instanceof tree.Value ?
- path[i].features.value : path[i].features;
- path[i] = Array.isArray(value) ? value : [value];
- }
-
- // Trace all permutations to generate the resulting media-query.
- //
- // (a, b and c) with nested (d, e) ->
- // a and d
- // a and e
- // b and c and d
- // b and c and e
- this.features = new(tree.Value)(this.permute(path).map(function (path) {
- path = path.map(function (fragment) {
- return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
- });
-
- for(i = path.length - 1; i > 0; i--) {
- path.splice(i, 0, new(tree.Anonymous)("and"));
- }
-
- return new(tree.Expression)(path);
- }));
-
- // Fake a tree-node that doesn't output anything.
- return new(tree.Ruleset)([], []);
- },
- permute: function (arr) {
- if (arr.length === 0) {
- return [];
- } else if (arr.length === 1) {
- return arr[0];
- } else {
- var result = [];
- var rest = this.permute(arr.slice(1));
- for (var i = 0; i < rest.length; i++) {
- for (var j = 0; j < arr[0].length; j++) {
- result.push([arr[0][j]].concat(rest[i]));
- }
- }
- return result;
- }
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.mixin = {};
-tree.mixin.Call = function (elements, args, index, filename, important) {
- this.selector = new(tree.Selector)(elements);
- this.arguments = args;
- this.index = index;
- this.filename = filename;
- this.important = important;
-};
-tree.mixin.Call.prototype = {
- eval: function (env) {
- var mixins, args, rules = [], match = false;
-
- for (var i = 0; i < env.frames.length; i++) {
- if ((mixins = env.frames[i].find(this.selector)).length > 0) {
- args = this.arguments && this.arguments.map(function (a) { return a.eval(env) });
- for (var m = 0; m < mixins.length; m++) {
- if (mixins[m].match(args, env)) {
- try {
- Array.prototype.push.apply(
- rules, mixins[m].eval(env, this.arguments, this.important).rules);
- match = true;
- } catch (e) {
- throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack };
- }
- }
- }
- if (match) {
- return rules;
- } else {
- throw { type: 'Runtime',
- message: 'No matching definition was found for `' +
- this.selector.toCSS().trim() + '(' +
- this.arguments.map(function (a) {
- return a.toCSS();
- }).join(', ') + ")`",
- index: this.index, filename: this.filename };
- }
- }
- }
- throw { type: 'Name',
- message: this.selector.toCSS().trim() + " is undefined",
- index: this.index, filename: this.filename };
- }
-};
-
-tree.mixin.Definition = function (name, params, rules, condition, variadic) {
- this.name = name;
- this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
- this.params = params;
- this.condition = condition;
- this.variadic = variadic;
- this.arity = params.length;
- this.rules = rules;
- this._lookups = {};
- this.required = params.reduce(function (count, p) {
- if (!p.name || (p.name && !p.value)) { return count + 1 }
- else { return count }
- }, 0);
- this.parent = tree.Ruleset.prototype;
- this.frames = [];
-};
-tree.mixin.Definition.prototype = {
- toCSS: function () { return "" },
- variable: function (name) { return this.parent.variable.call(this, name) },
- variables: function () { return this.parent.variables.call(this) },
- find: function () { return this.parent.find.apply(this, arguments) },
- rulesets: function () { return this.parent.rulesets.apply(this) },
-
- evalParams: function (env, args) {
- var frame = new(tree.Ruleset)(null, []), varargs;
-
- for (var i = 0, val, name; i < this.params.length; i++) {
- if (name = this.params[i].name) {
- if (this.params[i].variadic && args) {
- varargs = [];
- for (var j = i; j < args.length; j++) {
- varargs.push(args[j].eval(env));
- }
- frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
- } else if (val = (args && args[i]) || this.params[i].value) {
- frame.rules.unshift(new(tree.Rule)(name, val.eval(env)));
- } else {
- throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
- ' (' + args.length + ' for ' + this.arity + ')' };
- }
- }
- }
- return frame;
- },
- eval: function (env, args, important) {
- var frame = this.evalParams(env, args), context, _arguments = [], rules, start;
-
- for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
- _arguments.push(args[i] || this.params[i].value);
- }
- frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
-
- rules = important ?
- this.rules.map(function (r) {
- return new(tree.Rule)(r.name, r.value, '!important', r.index);
- }) : this.rules.slice(0);
-
- return new(tree.Ruleset)(null, rules).eval({
- frames: [this, frame].concat(this.frames, env.frames)
- });
- },
- match: function (args, env) {
- var argsLength = (args && args.length) || 0, len, frame;
-
- if (! this.variadic) {
- if (argsLength < this.required) { return false }
- if (argsLength > this.params.length) { return false }
- if ((this.required > 0) && (argsLength > this.params.length)) { return false }
- }
-
- if (this.condition && !this.condition.eval({
- frames: [this.evalParams(env, args)].concat(env.frames)
- })) { return false }
-
- len = Math.min(argsLength, this.arity);
-
- for (var i = 0; i < len; i++) {
- if (!this.params[i].name) {
- if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
- return false;
- }
- }
- }
- return true;
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Operation = function (op, operands) {
- this.op = op.trim();
- this.operands = operands;
-};
-tree.Operation.prototype.eval = function (env) {
- var a = this.operands[0].eval(env),
- b = this.operands[1].eval(env),
- temp;
-
- if (a instanceof tree.Dimension && b instanceof tree.Color) {
- if (this.op === '*' || this.op === '+') {
- temp = b, b = a, a = temp;
- } else {
- throw { name: "OperationError",
- message: "Can't substract or divide a color from a number" };
- }
- }
- return a.operate(this.op, b);
-};
-
-tree.operate = function (op, a, b) {
- switch (op) {
- case '+': return a + b;
- case '-': return a - b;
- case '*': return a * b;
- case '/': return a / b;
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Paren = function (node) {
- this.value = node;
-};
-tree.Paren.prototype = {
- toCSS: function (env) {
- return '(' + this.value.toCSS(env) + ')';
- },
- eval: function (env) {
- return new(tree.Paren)(this.value.eval(env));
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Quoted = function (str, content, escaped, i) {
- this.escaped = escaped;
- this.value = content || '';
- this.quote = str.charAt(0);
- this.index = i;
-};
-tree.Quoted.prototype = {
- toCSS: function () {
- if (this.escaped) {
- return this.value;
- } else {
- return this.quote + this.value + this.quote;
- }
- },
- eval: function (env) {
- var that = this;
- var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
- return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
- }).replace(/@\{([\w-]+)\}/g, function (_, name) {
- var v = new(tree.Variable)('@' + name, that.index).eval(env);
- return ('value' in v) ? v.value : v.toCSS();
- });
- return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Rule = function (name, value, important, index, inline) {
- this.name = name;
- this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
- this.important = important ? ' ' + important.trim() : '';
- this.index = index;
- this.inline = inline || false;
-
- if (name.charAt(0) === '@') {
- this.variable = true;
- } else { this.variable = false }
-};
-tree.Rule.prototype.toCSS = function (env) {
- if (this.variable) { return "" }
- else {
- return this.name + (env.compress ? ':' : ': ') +
- this.value.toCSS(env) +
- this.important + (this.inline ? "" : ";");
- }
-};
-
-tree.Rule.prototype.eval = function (context) {
- return new(tree.Rule)(this.name,
- this.value.eval(context),
- this.important,
- this.index, this.inline);
-};
-
-tree.Shorthand = function (a, b) {
- this.a = a;
- this.b = b;
-};
-
-tree.Shorthand.prototype = {
- toCSS: function (env) {
- return this.a.toCSS(env) + "/" + this.b.toCSS(env);
- },
- eval: function () { return this }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Ruleset = function (selectors, rules, strictImports) {
- this.selectors = selectors;
- this.rules = rules;
- this._lookups = {};
- this.strictImports = strictImports;
-};
-tree.Ruleset.prototype = {
- eval: function (env) {
- var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
- var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
-
- ruleset.root = this.root;
- ruleset.allowImports = this.allowImports;
-
- // push the current ruleset to the frames stack
- env.frames.unshift(ruleset);
-
- // Evaluate imports
- if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
- for (var i = 0; i < ruleset.rules.length; i++) {
- if (ruleset.rules[i] instanceof tree.Import) {
- Array.prototype.splice
- .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
- }
- }
- }
-
- // Store the frames around mixin definitions,
- // so they can be evaluated like closures when the time comes.
- for (var i = 0; i < ruleset.rules.length; i++) {
- if (ruleset.rules[i] instanceof tree.mixin.Definition) {
- ruleset.rules[i].frames = env.frames.slice(0);
- }
- }
-
- // Evaluate mixin calls.
- for (var i = 0; i < ruleset.rules.length; i++) {
- if (ruleset.rules[i] instanceof tree.mixin.Call) {
- Array.prototype.splice
- .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
- }
- }
-
- // Evaluate everything else
- for (var i = 0, rule; i < ruleset.rules.length; i++) {
- rule = ruleset.rules[i];
-
- if (! (rule instanceof tree.mixin.Definition)) {
- ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
- }
- }
-
- // Pop the stack
- env.frames.shift();
-
- return ruleset;
- },
- match: function (args) {
- return !args || args.length === 0;
- },
- variables: function () {
- if (this._variables) { return this._variables }
- else {
- return this._variables = this.rules.reduce(function (hash, r) {
- if (r instanceof tree.Rule && r.variable === true) {
- hash[r.name] = r;
- }
- return hash;
- }, {});
- }
- },
- variable: function (name) {
- return this.variables()[name];
- },
- rulesets: function () {
- if (this._rulesets) { return this._rulesets }
- else {
- return this._rulesets = this.rules.filter(function (r) {
- return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
- });
- }
- },
- find: function (selector, self) {
- self = self || this;
- var rules = [], rule, match,
- key = selector.toCSS();
-
- if (key in this._lookups) { return this._lookups[key] }
-
- this.rulesets().forEach(function (rule) {
- if (rule !== self) {
- for (var j = 0; j < rule.selectors.length; j++) {
- if (match = selector.match(rule.selectors[j])) {
- if (selector.elements.length > rule.selectors[j].elements.length) {
- Array.prototype.push.apply(rules, rule.find(
- new(tree.Selector)(selector.elements.slice(1)), self));
- } else {
- rules.push(rule);
- }
- break;
- }
- }
- }
- });
- return this._lookups[key] = rules;
- },
- //
- // Entry point for code generation
- //
- // `context` holds an array of arrays.
- //
- toCSS: function (context, env) {
- var css = [], // The CSS output
- rules = [], // node.Rule instances
- rulesets = [], // node.Ruleset instances
- paths = [], // Current selectors
- selector, // The fully rendered selector
- rule;
-
- if (! this.root) {
- if (context.length === 0) {
- paths = this.selectors.map(function (s) { return [s] });
- } else {
- this.joinSelectors(paths, context, this.selectors);
- }
- }
-
- // Compile rules and rulesets
- for (var i = 0; i < this.rules.length; i++) {
- rule = this.rules[i];
-
- if (rule.rules || (rule instanceof tree.Directive) || (rule instanceof tree.Media)) {
- rulesets.push(rule.toCSS(paths, env));
- } else if (rule instanceof tree.Comment) {
- if (!rule.silent) {
- if (this.root) {
- rulesets.push(rule.toCSS(env));
- } else {
- rules.push(rule.toCSS(env));
- }
- }
- } else {
- if (rule.toCSS && !rule.variable) {
- rules.push(rule.toCSS(env));
- } else if (rule.value && !rule.variable) {
- rules.push(rule.value.toString());
- }
- }
- }
-
- rulesets = rulesets.join('');
-
- // If this is the root node, we don't render
- // a selector, or {}.
- // Otherwise, only output if this ruleset has rules.
- if (this.root) {
- css.push(rules.join(env.compress ? '' : '\n'));
- } else {
- if (rules.length > 0) {
- selector = paths.map(function (p) {
- return p.map(function (s) {
- return s.toCSS(env);
- }).join('').trim();
- }).join( env.compress ? ',' : ',\n');
-
- css.push(selector,
- (env.compress ? '{' : ' {\n ') +
- rules.join(env.compress ? '' : '\n ') +
- (env.compress ? '}' : '\n}\n'));
- }
- }
- css.push(rulesets);
-
- return css.join('') + (env.compress ? '\n' : '');
- },
-
- joinSelectors: function (paths, context, selectors) {
- for (var s = 0; s < selectors.length; s++) {
- this.joinSelector(paths, context, selectors[s]);
- }
- },
-
- joinSelector: function (paths, context, selector) {
- var before = [], after = [], beforeElements = [],
- afterElements = [], hasParentSelector = false, el;
-
- for (var i = 0; i < selector.elements.length; i++) {
- el = selector.elements[i];
- if (el.combinator.value.charAt(0) === '&') {
- hasParentSelector = true;
- }
- if (hasParentSelector) afterElements.push(el);
- else beforeElements.push(el);
- }
-
- if (! hasParentSelector) {
- afterElements = beforeElements;
- beforeElements = [];
- }
-
- if (beforeElements.length > 0) {
- before.push(new(tree.Selector)(beforeElements));
- }
-
- if (afterElements.length > 0) {
- after.push(new(tree.Selector)(afterElements));
- }
-
- for (var c = 0; c < context.length; c++) {
- paths.push(before.concat(context[c]).concat(after));
- }
- }
-};
-})(require('../tree'));
-(function (tree) {
-
-tree.Selector = function (elements) {
- this.elements = elements;
- if (this.elements[0].combinator.value === "") {
- this.elements[0].combinator.value = ' ';
- }
-};
-tree.Selector.prototype.match = function (other) {
- var len = this.elements.length,
- olen = other.elements.length,
- max = Math.min(len, olen);
-
- if (len < olen) {
- return false;
- } else {
- for (var i = 0; i < max; i++) {
- if (this.elements[i].value !== other.elements[i].value) {
- return false;
- }
- }
- }
- return true;
-};
-tree.Selector.prototype.eval = function (env) {
- return new(tree.Selector)(this.elements.map(function (e) {
- return e.eval(env);
- }));
-};
-tree.Selector.prototype.toCSS = function (env) {
- if (this._css) { return this._css }
-
- return this._css = this.elements.map(function (e) {
- if (typeof(e) === 'string') {
- return ' ' + e.trim();
- } else {
- return e.toCSS(env);
- }
- }).join('');
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.URL = function (val, paths) {
- if (val.data) {
- this.attrs = val;
- } else {
- // Add the base path if the URL is relative and we are in the browser
- if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) {
- val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
- }
- this.value = val;
- this.paths = paths;
- }
-};
-tree.URL.prototype = {
- toCSS: function () {
- return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data
- : this.value.toCSS()) + ")";
- },
- eval: function (ctx) {
- return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths);
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Value = function (value) {
- this.value = value;
- this.is = 'value';
-};
-tree.Value.prototype = {
- eval: function (env) {
- if (this.value.length === 1) {
- return this.value[0].eval(env);
- } else {
- return new(tree.Value)(this.value.map(function (v) {
- return v.eval(env);
- }));
- }
- },
- toCSS: function (env) {
- return this.value.map(function (e) {
- return e.toCSS(env);
- }).join(env.compress ? ',' : ', ');
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file };
-tree.Variable.prototype = {
- eval: function (env) {
- var variable, v, name = this.name;
-
- if (name.indexOf('@@') == 0) {
- name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
- }
-
- if (variable = tree.find(env.frames, function (frame) {
- if (v = frame.variable(name)) {
- return v.value.eval(env);
- }
- })) { return variable }
- else {
- throw { type: 'Name',
- message: "variable " + name + " is undefined",
- filename: this.file,
- index: this.index };
- }
- }
-};
-
-})(require('../tree'));
-(function (tree) {
-
-tree.find = function (obj, fun) {
- for (var i = 0, r; i < obj.length; i++) {
- if (r = fun.call(obj, obj[i])) { return r }
- }
- return null;
-};
-tree.jsify = function (obj) {
- if (Array.isArray(obj.value) && (obj.value.length > 1)) {
- return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
- } else {
- return obj.toCSS(false);
- }
-};
-
-})(require('./tree'));
-//
-// browser.js - client-side engine
-//
-
-var isFileProtocol = (location.protocol === 'file:' ||
- location.protocol === 'chrome:' ||
- location.protocol === 'chrome-extension:' ||
- location.protocol === 'resource:');
-
-less.env = less.env || (location.hostname == '127.0.0.1' ||
- location.hostname == '0.0.0.0' ||
- location.hostname == 'localhost' ||
- location.port.length > 0 ||
- isFileProtocol ? 'development'
- : 'production');
-
-// Load styles asynchronously (default: false)
-//
-// This is set to `false` by default, so that the body
-// doesn't start loading before the stylesheets are parsed.
-// Setting this to `true` can result in flickering.
-//
-less.async = false;
-
-// Interval between watch polls
-less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
-
-//
-// Watch mode
-//
-less.watch = function () { return this.watchMode = true };
-less.unwatch = function () { return this.watchMode = false };
-
-if (less.env === 'development') {
- less.optimization = 0;
-
- if (/!watch/.test(location.hash)) {
- less.watch();
- }
- less.watchTimer = setInterval(function () {
- if (less.watchMode) {
- loadStyleSheets(function (e, root, _, sheet, env) {
- if (root) {
- createCSS(root.toCSS(), sheet, env.lastModified);
- }
- });
- }
- }, less.poll);
-} else {
- less.optimization = 3;
-}
-
-var cache;
-
-try {
- cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
-} catch (_) {
- cache = null;
-}
-
-//
-// Get all tags with the 'rel' attribute set to "stylesheet/less"
-//
-var links = document.getElementsByTagName('link');
-var typePattern = /^text\/(x-)?less$/;
-
-less.sheets = [];
-
-for (var i = 0; i < links.length; i++) {
- if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
- (links[i].type.match(typePattern)))) {
- less.sheets.push(links[i]);
- }
-}
-
-
-less.refresh = function (reload) {
- var startTime, endTime;
- startTime = endTime = new(Date);
-
- loadStyleSheets(function (e, root, _, sheet, env) {
- if (env.local) {
- log("loading " + sheet.href + " from cache.");
- } else {
- log("parsed " + sheet.href + " successfully.");
- createCSS(root.toCSS(), sheet, env.lastModified);
- }
- log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
- (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
- endTime = new(Date);
- }, reload);
-
- loadStyles();
-};
-less.refreshStyles = loadStyles;
-
-less.refresh(less.env === 'development');
-
-function loadStyles() {
- var styles = document.getElementsByTagName('style');
- for (var i = 0; i < styles.length; i++) {
- if (styles[i].type.match(typePattern)) {
- new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) {
- var css = tree.toCSS();
- var style = styles[i];
- style.type = 'text/css';
- if (style.styleSheet) {
- style.styleSheet.cssText = css;
- } else {
- style.innerHTML = css;
- }
- });
- }
- }
-}
-
-function loadStyleSheets(callback, reload) {
- for (var i = 0; i < less.sheets.length; i++) {
- loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
- }
-}
-
-function loadStyleSheet(sheet, callback, reload, remaining) {
- var url = window.location.href.replace(/[#?].*$/, '');
- var href = sheet.href.replace(/\?.*$/, '');
- var css = cache && cache.getItem(href);
- var timestamp = cache && cache.getItem(href + ':timestamp');
- var styles = { css: css, timestamp: timestamp };
-
- // Stylesheets in IE don't always return the full path
- if (! /^(https?|file):/.test(href)) {
- if (href.charAt(0) == "/") {
- href = window.location.protocol + "//" + window.location.host + href;
- } else {
- href = url.slice(0, url.lastIndexOf('/') + 1) + href;
- }
- }
- var filename = href.match(/([^\/]+)$/)[1];
-
- xhr(sheet.href, sheet.type, function (data, lastModified) {
- if (!reload && styles && lastModified &&
- (new(Date)(lastModified).valueOf() ===
- new(Date)(styles.timestamp).valueOf())) {
- // Use local copy
- createCSS(styles.css, sheet);
- callback(null, null, data, sheet, { local: true, remaining: remaining });
- } else {
- // Use remote copy (re-parse)
- try {
- new(less.Parser)({
- optimization: less.optimization,
- paths: [href.replace(/[\w\.-]+$/, '')],
- mime: sheet.type,
- filename: filename
- }).parse(data, function (e, root) {
- if (e) { return error(e, href) }
- try {
- callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining });
- removeNode(document.getElementById('less-error-message:' + extractId(href)));
- } catch (e) {
- error(e, href);
- }
- });
- } catch (e) {
- error(e, href);
- }
- }
- }, function (status, url) {
- throw new(Error)("Couldn't load " + url + " (" + status + ")");
- });
-}
-
-function extractId(href) {
- return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain
- .replace(/^\//, '' ) // Remove root /
- .replace(/\?.*$/, '' ) // Remove query
- .replace(/\.[^\.\/]+$/, '' ) // Remove file extension
- .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
- .replace(/\./g, ':'); // Replace dots with colons(for valid id)
-}
-
-function createCSS(styles, sheet, lastModified) {
- var css;
-
- // Strip the query-string
- var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : '';
-
- // If there is no title set, use the filename, minus the extension
- var id = 'less:' + (sheet.title || extractId(href));
-
- // If the stylesheet doesn't exist, create a new node
- if ((css = document.getElementById(id)) === null) {
- css = document.createElement('style');
- css.type = 'text/css';
- css.media = sheet.media || 'screen';
- css.id = id;
- document.getElementsByTagName('head')[0].appendChild(css);
- }
-
- if (css.styleSheet) { // IE
- try {
- css.styleSheet.cssText = styles;
- } catch (e) {
- throw new(Error)("Couldn't reassign styleSheet.cssText.");
- }
- } else {
- (function (node) {
- if (css.childNodes.length > 0) {
- if (css.firstChild.nodeValue !== node.nodeValue) {
- css.replaceChild(node, css.firstChild);
- }
- } else {
- css.appendChild(node);
- }
- })(document.createTextNode(styles));
- }
-
- // Don't update the local store if the file wasn't modified
- if (lastModified && cache) {
- log('saving ' + href + ' to cache.');
- cache.setItem(href, styles);
- cache.setItem(href + ':timestamp', lastModified);
- }
-}
-
-function xhr(url, type, callback, errback) {
- var xhr = getXMLHttpRequest();
- var async = isFileProtocol ? false : less.async;
-
- if (typeof(xhr.overrideMimeType) === 'function') {
- xhr.overrideMimeType('text/css');
- }
- xhr.open('GET', url, async);
- xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
- xhr.send(null);
-
- if (isFileProtocol) {
- if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
- callback(xhr.responseText);
- } else {
- errback(xhr.status, url);
- }
- } else if (async) {
- xhr.onreadystatechange = function () {
- if (xhr.readyState == 4) {
- handleResponse(xhr, callback, errback);
- }
- };
- } else {
- handleResponse(xhr, callback, errback);
- }
-
- function handleResponse(xhr, callback, errback) {
- if (xhr.status >= 200 && xhr.status < 300) {
- callback(xhr.responseText,
- xhr.getResponseHeader("Last-Modified"));
- } else if (typeof(errback) === 'function') {
- errback(xhr.status, url);
- }
- }
-}
-
-function getXMLHttpRequest() {
- if (window.XMLHttpRequest) {
- return new(XMLHttpRequest);
- } else {
- try {
- return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
- } catch (e) {
- log("browser doesn't support AJAX.");
- return null;
- }
- }
-}
-
-function removeNode(node) {
- return node && node.parentNode.removeChild(node);
-}
-
-function log(str) {
- if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
-}
-
-function error(e, href) {
- var id = 'less-error-message:' + extractId(href);
- var template = '
"+(e.message||"There is an error in your .less file")+"
"+'
in '+l+" ";var c=function(e,t,n){e.extract[t]&&a.push(i.replace(/\{line\}/,parseInt(e.line)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};e.stack?u+=" "+e.stack.split("\n").slice(1).join(" "):e.extract&&(c(e,0,""),c(e,1,"line"),c(e,2,""),u+="on line "+e.line+", column "+(e.column+1)+":
"+"
"+a.join("")+"
"),s.innerHTML=u,m([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),s.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(o=setInterval(function(){document.body&&(document.getElementById(n)?document.body.replaceChild(s,document.getElementById(n)):document.body.insertBefore(s,document.body.firstChild),clearInterval(o))},10))}Array.isArray||(Array.isArray=function(e){return Object.prototype.toString.call(e)==="[object Array]"||e instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(e,t){var n=this.length>>>0;for(var r=0;r>>0,n=new Array(t),r=arguments[1];for(var i=0;i>>0,n=0;if(t===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var r=arguments[1];else do{if(n in this){r=this[n++];break}if(++n>=t)throw new TypeError}while(!0);for(;n=t)return-1;n<0&&(n+=t);for(;nh&&(c[u]=c[u].slice(o-h),h=o)}function w(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function E(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,b();else{b();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return S(r),typeof t=="string"?t:t.length===1?t[0]:t}function S(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function L(e){return r.mode==="browser"||r.mode==="rhino"?e.filename:n("path").resolve(e.filename)}function A(e,t,n){return{lineNumber:k(e,t).line+1,fileName:L(n)}}function O(e,t){var n=C(e,t),r=k(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&k(e.call,n).line+1,this.callExtract=o[k(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this,t=t||{};t.contents||(t.contents={});var v=function(){},m=this.imports={paths:t&&t.paths||[],queue:[],files:{},contents:t.contents,mime:t&&t.mime,error:null,push:function(e,n){var i=this;this.queue.push(e),r.Parser.importer(e,this.paths,function(t,r){i.queue.splice(i.queue.indexOf(e),1);var s=e in i.files;i.files[e]=r,t&&!i.error&&(i.error=t),n(t,r,s),i.queue.length===0&&v(t)},t)}};return this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,p={imports:m,parse:function(e,a){var f,d,m,g,y,b,w=[],S,x=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0&&(x=new O({index:c,type:"Parse",message:"missing closing `}`",filename:t.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(x)return a(x);try{f=new i.Ruleset([],E(this.parsers.primary)),f.root=!0}catch(T){return a(new O(T,t))}f.toCSS=function(e){var s,o,u;return function(s,o){var u=[],a;s=s||{},typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),u=[new i.Ruleset(null,o)]);try{var f=e.call(this,{frames:u}).toCSS([],{compress:s.compress||!1,dumpLineNumbers:t.dumpLineNumbers})}catch(l){throw new O(l,t)}if(a=p.imports.error)throw a instanceof O?a:new O(a,t);return s.yuicompress&&r.mode==="node"?n("./cssmin").compressor.cssmin(f):s.compress?f.replace(/(\s)+/g,"$1"):f}}(f.eval);if(o=0&&s.charAt(N)!=="\n";N--)C++;x={type:"Parse",message:"Syntax Error on line "+y,index:o,filename:t.filename,line:y,column:C,extract:[b[y-2],b[y-1],b[y]]}}this.imports.queue.length>0?v=function(e){e?a(e):a(null,f)}:a(x,f)},parsers:{primary:function(){var e,t=[];while((e=E(this.mixin.definition)||E(this.rule)||E(this.ruleset)||E(this.mixin.call)||E(this.comment)||E(this.directive))||E(/^[\s\n]+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(E(/^\/\/.*/),!0);if(e=E(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=='"'&&s.charAt(t)!=="'")return;n&&E("~");if(e=E(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],n)},keyword:function(){var e;if(e=E(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=E(this.alpha);if(typeof s!="undefined")return s}E("("),r=E(this.entities.arguments);if(!E(")"))return;if(e)return new i.Call(e,r,a,t.filename)},arguments:function(){var e=[],t;while(t=E(this.entities.assignment)||E(this.expression)){e.push(t);if(!E(","))break}return e},literal:function(){return E(this.entities.ratio)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.quoted)},assignment:function(){var e,t;if((e=E(/^\w+(?=\s?=)/i))&&E("=")&&(t=E(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!E(/^url\(/))return;return e=E(this.entities.quoted)||E(this.entities.variable)||E(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",x(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),m.paths)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=E(/^@@?[\w-]+/)))return new i.Variable(e,n,t.filename)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=E(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.filename)},color:function(){var e;if(s.charAt(o)==="#"&&(e=E(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<45||t===47)return;if(e=E(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/))return new i.Dimension(e[1],e[2])},ratio:function(){var e,t=s.charCodeAt(o);if(t>57||t<48)return;if(e=E(/^(\d+\/\d+)/))return new i.Ratio(e[1])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&E("~");if(e=E(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=E(/^(@[\w-]+)\s*:/)))return e[1]},shorthand:function(){var e,t;if(!N(/^[@\w.%-]+\/[@\w.-]+/))return;g();if((e=E(this.entity))&&E("/")&&(t=E(this.entity)))return new i.Shorthand(e,t);y()},mixin:{call:function(){var e=[],n,r,u=[],a,f=o,l=s.charAt(o),c,h,p=!1;if(l!=="."&&l!=="#")return;g();while(n=E(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=E(">");if(E("(")){while(a=E(this.expression)){h=a,c=null;if(a.value.length==1){var d=a.value[0];if(d instanceof i.Variable&&E(":")){if(!(h=E(this.expression)))throw new Error("Expected value");c=d.name}}u.push({name:c,value:h});if(!E(","))break}if(!E(")"))throw new Error("Expected )")}E(this.important)&&(p=!0);if(e.length>0&&(E(";")||N("}")))return new i.mixin.Call(e,u,f,t.filename,p);y()},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||N(/^[^{]*(;|})/))return;g();if(n=E(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];do{if(s.charAt(o)==="."&&E(/^\.{3}/)){c=!0;break}if(!(u=E(this.entities.variable)||E(this.entities.literal)||E(this.entities.keyword)))break;if(u instanceof i.Variable)if(E(":"))a=x(this.expression,"expected expression"),t.push({name:u.name,value:a});else{if(E(/^\.{3}/)){t.push({name:u.name,variadic:!0}),c=!0;break}t.push({name:u.name})}else t.push({value:u})}while(E(","));E(")")||(l=o,y()),E(/^when/)&&(f=x(this.conditions,"expected condition")),r=E(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);y()}}},entity:function(){return E(this.entities.literal)||E(this.entities.variable)||E(this.entities.url)||E(this.entities.call)||E(this.entities.keyword)||E(this.entities.javascript)||E(this.comment)},end:function(){return E(";")||N("}")},alpha:function(){var e;if(!E(/^\(opacity=/i))return;if(e=E(/^\d+/)||E(this.entities.variable))return x(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=E(this.combinator),e=E(/^(?:\d+\.\d+|\d+)%/)||E(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||E("*")||E("&")||E(this.attribute)||E(/^\([^)@]+\)/)||E(/^[\.#](?=@)/)||E(this.entities.variableCurly),e||E("(")&&(r=E(this.entities.variableCurly)||E(this.entities.variable))&&E(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e,t=s.charAt(o);if(t===">"||t==="+"||t==="~"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(t)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u;if(E("("))return e=E(this.entity),x(")"),new i.Selector([new i.Element("",e,o)]);while(t=E(this.element)){r=s.charAt(o),n.push(t);if(r==="{"||r==="}"||r===";"||r===",")break}if(n.length>0)return new i.Selector(n)},tag:function(){return E(/^[A-Za-z][A-Za-z-]*[0-9]?/)||E("*")},attribute:function(){var e="",t,n,r;if(!E("["))return;if(t=E(/^(?:[_A-Za-z0-9-]|\\.)+/)||E(this.entities.quoted))(r=E(/^[|~*$^]?=/))&&(n=E(this.entities.quoted)||E(/^[\w-]+/))?e=[t,r,n.toCSS?n.toCSS():n].join(""):e=t;if(!E("]"))return;if(e)return"["+e+"]"},block:function(){var e;if(E("{")&&(e=E(this.primary))&&E("}"))return e},ruleset:function(){var e=[],n,r,u,a;g(),t.dumpLineNumbers&&(a=A(o,s,t));while(n=E(this.selector)){e.push(n),E(this.comment);if(!E(","))break;E(this.comment)}if(e.length>0&&(r=E(this.block))){var f=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(f.debugInfo=a),f}l=o,y()},rule:function(){var e,t,n=s.charAt(o),r,a;g();if(n==="."||n==="#"||n==="&")return;if(e=E(this.variable)||E(this.property)){e.charAt(0)!="@"&&(a=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))?(o+=a[0].length-1,t=new i.Anonymous(a[1])):e==="font"?t=E(this.font):t=E(this.value),r=E(this.important);if(t&&E(this.end))return new i.Rule(e,t,r,f);l=o,y()}},"import":function(){var e,t,n=o;g();var r=E(/^@import(?:-(once))?\s+/);if(r&&(e=E(this.entities.quoted)||E(this.entities.url))){t=E(this.mediaFeatures);if(E(";"))return new i.Import(e,m,t,r[1]==="once",n)}y()},mediaFeature:function(){var e,t,n=[];do if(e=E(this.entities.keyword))n.push(e);else if(E("(")){t=E(this.property),e=E(this.entity);if(!E(")"))return null;if(t&&e)n.push(new i.Paren(new i.Rule(t,e,null,o,!0)));else{if(!e)return null;n.push(new i.Paren(e))}}while(e);if(n.length>0)return new i.Expression(n)},mediaFeatures:function(){var e,t=[];do if(e=E(this.mediaFeature)){t.push(e);if(!E(","))break}else if(e=E(this.entities.variable)){t.push(e);if(!E(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=A(o,s,t));if(E(/^@media/)){e=E(this.mediaFeatures);if(n=E(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,t,n,r,u,a,f,l,c;if(s.charAt(o)!=="@")return;if(t=E(this["import"])||E(this.media))return t;g(),e=E(/^@[a-z-]+/),f=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(f="@"+e.slice(e.indexOf("-",2)+1));switch(f){case"@font-face":l=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":l=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":l=!0,c=!0}c&&(e+=" "+(E(/^[^{]+/)||"").trim());if(l){if(n=E(this.block))return new i.Directive(e,n)}else if((t=E(this.entity))&&E(";"))return new i.Directive(e,t);y()},font:function(){var e=[],t=[],n,r,s,o;while(o=E(this.shorthand)||E(this.entity))t.push(o);e.push(new i.Expression(t));if(E(","))while(o=E(this.expression)){e.push(o);if(!E(","))break}return new i.Value(e)},value:function(){var e,t=[],n;while(e=E(this.expression)){t.push(e);if(!E(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return E(/^! *important/)},sub:function(){var e;if(E("(")&&(e=E(this.expression))&&E(")"))return e},multiplication:function(){var e,t,n,r;if(e=E(this.operand)){while(!N(/^\/\*/)&&(n=E("/")||E("*"))&&(t=E(this.operand)))r=new i.Operation(n,[r||e,t]);return r||e}},addition:function(){var e,t,n,r;if(e=E(this.multiplication)){while((n=E(/^[-+]\s+/)||!w(s.charAt(o-1))&&(E("+")||E("-")))&&(t=E(this.multiplication)))r=new i.Operation(n,[r||e,t]);return r||e}},conditions:function(){var e,t,n=o,r;if(e=E(this.condition)){while(E(",")&&(t=E(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;E(/^not/)&&(u=!0),x("(");if(e=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))return(r=E(/^(?:>=|=<|[<=>])/))?(t=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):T("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),x(")"),E(/^and/)?new i.Condition("and",n,E(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=E("-"));var n=E(this.sub)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.variable)||E(this.entities.call);return e?new i.Operation("*",[new i.Dimension(-1),n]):n},expression:function(){var e,t,n=[],r;while(e=E(this.addition)||E(this.entity))n.push(e);if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=E(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.length>0&&(e=t[0]+e),d({href:e,title:e,type:r.mime,contents:r.contents},function(i){i&&typeof r.errback=="function"?r.errback.call(null,e,t,n,r):n.apply(null,arguments)},!0)};(function(e){function t(t){return e.functions.hsla(t.h,t.s,t.l,t.a)}function n(t){if(t instanceof e.Dimension)return parseFloat(t.unit=="%"?t.value/100:t.value);if(typeof t=="number")return t;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function r(e){return Math.min(1,Math.max(0,e))}e.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(t,r,i,s){var o=[t,r,i].map(function(e){return n(e)}),s=n(s);return new e.Color(o,s)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,r,i){function u(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?o+(s-o)*e*6:e*2<1?s:e*3<2?o+(s-o)*(2/3-e)*6:o}e=n(e)%360/360,t=n(t),r=n(r),i=n(i);var s=r<=.5?r*(t+1):r+t-r*t,o=r*2-s;return this.rgba(u(e+1/3)*255,u(e)*255,u(e-1/3)*255,i)},hue:function(t){return new e.Dimension(Math.round(t.toHSL().h))},saturation:function(t){return new e.Dimension(Math.round(t.toHSL().s*100),"%")},lightness:function(t){return new e.Dimension(Math.round(t.toHSL().l*100),"%")},red:function(t){return new e.Dimension(t.rgb[0])},green:function(t){return new e.Dimension(t.rgb[1])},blue:function(t){return new e.Dimension(t.rgb[2])},alpha:function(t){return new e.Dimension(t.toHSL().a)},luma:function(t){return new e.Dimension(Math.round((.2126*(t.rgb[0]/255)+.7152*(t.rgb[1]/255)+.0722*(t.rgb[2]/255))*t.alpha*100),"%")},saturate:function(e,n){var i=e.toHSL();return i.s+=n.value/100,i.s=r(i.s),t(i)},desaturate:function(e,n){var i=e.toHSL();return i.s-=n.value/100,i.s=r(i.s),t(i)},lighten:function(e,n){var i=e.toHSL();return i.l+=n.value/100,i.l=r(i.l),t(i)},darken:function(e,n){var i=e.toHSL();return i.l-=n.value/100,i.l=r(i.l),t(i)},fadein:function(e,n){var i=e.toHSL();return i.a+=n.value/100,i.a=r(i.a),t(i)},fadeout:function(e,n){var i=e.toHSL();return i.a-=n.value/100,i.a=r(i.a),t(i)},fade:function(e,n){var i=e.toHSL();return i.a=n.value/100,i.a=r(i.a),t(i)},spin:function(e,n){var r=e.toHSL(),i=(r.h+n.value)%360;return r.h=i<0?360+i:i,t(r)},mix:function(t,n,r){r||(r=new e.Dimension(50));var i=r.value/100,s=i*2-1,o=t.toHSL().a-n.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[t.rgb[0]*u+n.rgb[0]*a,t.rgb[1]*u+n.rgb[1]*a,t.rgb[2]*u+n.rgb[2]*a],l=t.alpha*i+n.alpha*(1-i);return new e.Color(f,l)},greyscale:function(t){return this.desaturate(t,new e.Dimension(100))},contrast:function(e,t,n,r){return typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1)),typeof r=="undefined"?r=.43:r=r.value,(.2126*(e.rgb[0]/255)+.7152*(e.rgb[1]/255)+.0722*(e.rgb[2]/255))*e.alpha255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},operate:function(t,n){var r=[];n instanceof e.Color||(n=n.toColor());for(var i=0;i<3;i++)r[i]=e.operate(t,this.rgb[i],n.rgb[i]);return new e.Color(r,this.alpha+n.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,
+n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype.eval=function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}(n("../tree")),function(e){e.Dimension=function(e,t){this.value=parseFloat(e),this.unit=t||null},e.Dimension.prototype={eval:function(){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(){var e=this.value+this.unit;return e},operate:function(t,n){return new e.Dimension(e.operate(t,this.value,n.value),this.unit||n.unit)},compare:function(t){return t instanceof e.Dimension?t.value>this.value?-1:t.value":e.compress?">":" > "}[this.value]}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={eval:function(t){return this.value.length>1?new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?this.value[0].eval(t):this},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")}}}(n("../tree")),function(e){e.Import=function(t,n,r,i,s){var o=this;this.once=i,this.index=s,this._path=t,this.features=r&&new e.Value(r),t instanceof e.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(t.value)?t.value:t.value+".less":this.path=t.value.value||t.value,this.css=/css(\?.*)?$/.test(this.path),this.css||n.push(this.path,function(t,n,r){t&&(t.index=s),r&&o.once&&(o.skip=r),o.root=n||new e.Ruleset([],[])})},e.Import.prototype={toCSS:function(e){var t=this.features?" "+this.features.toCSS(e):"";return this.css?"@import "+this._path.toCSS()+t+";\n":""},eval:function(t){var n,r=this.features&&this.features.eval(t);if(this.skip)return[];if(this.css)return this;n=new e.Ruleset([],this.root.rules.slice(0));for(var i=0;i1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){n=this.arguments&&this.arguments.map(function(t){return{name:t.name,value:t.value.eval(e)}});for(var o=0;othis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}if(this.condition&&!this.condition.eval({frames:[this.evalParams(t,e)].concat(t.frames)}))return!1;r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t,n){var r=[],i=[],s=[],o=[],u=[],a,f,l;this.root||this.joinSelectors(u,t,this.selectors);for(var c=0;c0){f=e.debugInfo(n,this),a=u.map(function(e){return e.map(function(e){return e.toCSS(n)}).join("").trim()}).join(n.compress?",":",\n");for(var c=i.length-1;c>=0;c--)s.indexOf(i[c])===-1&&s.unshift(i[c]);i=s,r.push(f+a+(n.compress?"{":" {\n ")+i.join(n.compress?"":"\n ")+(n.compress?"}":"\n}\n"))}return r.push(o),r.join("")+(n.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0)),v=!1):d=new e.Selector([]),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t)):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e){this.elements=e},e.Selector.prototype.match=function(e){var t=this.elements.length,n=e.elements.length,r=Math.min(t,n);if(t0&&(r.value=this.paths[0]+(r.value.charAt(0)==="/"?r.value.slice(1):r.value)),new t.URL(r,this.paths)}}}(n("../tree")),function(e){e.Value=function(e){this.value=e,this.is="value"},e.Value.prototype={eval:function(t){return this.value.length===1?this.value[0].eval(t):new e.Value(this.value.map(function(e){return e.eval(t)}))},toCSS:function(e){return this.value.map(function(t){return t.toCSS(e)}).join(e.compress?",":", ")}}}(n("../tree")),function(e){e.Variable=function(e,t,n){this.name=e,this.index=t,this.file=n},e.Variable.prototype={eval:function(t){var n,r,i=this.name;i.indexOf("@@")==0&&(i="@"+(new e.Variable(i.slice(1))).eval(t).value);if(n=e.find(t.frames,function(e){if(r=e.variable(i))return r.value.eval(t)}))return n;throw{type:"Name",message:"variable "+i+" is undefined",filename:this.file,index:this.index}}}}(n("../tree")),function(e){e.debugInfo=function(t,n){var r="";if(t.dumpLineNumbers&&!t.compress)switch(t.dumpLineNumbers){case"comments":r=e.debugInfo.asComment(n);break;case"mediaquery":r=e.debugInfo.asMediaQuery(n);break;case"all":r=e.debugInfo.asComment(n)+e.debugInfo.asMediaQuery(n)}return r},e.debugInfo.asComment=function(e){return"/* line "+e.debugInfo.lineNumber+", "+e.debugInfo.fileName+" */\n"},e.debugInfo.asMediaQuery=function(e){return'@media -sass-debug-info{filename{font-family:"'+e.debugInfo.fileName+'";}line{font-family:"'+e.debugInfo.lineNumber+'";}}\n'},e.find=function(e,t){for(var n=0,r;n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree"));var s=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||s?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(s?1e3:1500),r.watch=function(){return this.watchMode=!0},r.unwatch=function(){return this.watchMode=!1};if(r.env==="development"){r.optimization=0,/!watch/.test(location.hash)&&r.watch();var o=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);o&&(r.dumpLineNumbers=o[1]),r.watchTimer=setInterval(function(){r.watchMode&&p(function(e,t,n,r,i){t&&m(t.toCSS(),r,i.lastModified)})},r.poll)}else r.optimization=3;var u;try{u=typeof e.localStorage=="undefined"?null:e.localStorage}catch(a){u=null}var f=document.getElementsByTagName("link"),l=/^text\/(x-)?less$/;r.sheets=[];for(var c=0;c
Date: Tue, 15 Jan 2013 00:25:30 -0800
Subject: [PATCH 22/72] Bump bundled less.js to 1.3.3
---
src/main/resources/META-INF/less.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/main/resources/META-INF/less.js b/src/main/resources/META-INF/less.js
index 4043d44..9b0fa6b 100644
--- a/src/main/resources/META-INF/less.js
+++ b/src/main/resources/META-INF/less.js
@@ -1,9 +1,9 @@
//
-// LESS - Leaner CSS v1.3.1
+// LESS - Leaner CSS v1.3.3
// http://lesscss.org
//
-// Copyright (c) 2009-2011, Alexis Sellier
+// Copyright (c) 2009-2013, Alexis Sellier
// Licensed under the Apache 2.0 License.
//
-(function(e,t){function n(t){return e.less[t.split("/")[1]]}function h(){var e=document.getElementsByTagName("style");for(var t=0;t0?r.firstChild.nodeValue!==e.nodeValue&&r.replaceChild(e,r.firstChild):r.appendChild(e)})(document.createTextNode(e));if(n&&u){w("saving "+i+" to cache.");try{u.setItem(i,e),u.setItem(i+":timestamp",n)}catch(a){w("failed to save")}}}function g(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var o=y(),u=s?r.fileAsync:r.async;typeof o.overrideMimeType=="function"&&o.overrideMimeType("text/css"),o.open("GET",e,u),o.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),o.send(null),s&&!r.fileAsync?o.status===0||o.status>=200&&o.status<300?n(o.responseText):i(o.status,e):u?o.onreadystatechange=function(){o.readyState==4&&a(o,n,i)}:a(o,n,i)}function y(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return w("browser doesn't support AJAX."),null}}function b(e){return e&&e.parentNode.removeChild(e)}function w(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function E(e,t){var n="less-error-message:"+v(t),i='
"+(e.message||"There is an error in your .less file")+"
"+'
in '+l+" ";var c=function(e,t,n){e.extract[t]&&a.push(i.replace(/\{line\}/,parseInt(e.line)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};e.stack?u+=" "+e.stack.split("\n").slice(1).join(" "):e.extract&&(c(e,0,""),c(e,1,"line"),c(e,2,""),u+="on line "+e.line+", column "+(e.column+1)+":
"+"
"+a.join("")+"
"),s.innerHTML=u,m([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),s.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(o=setInterval(function(){document.body&&(document.getElementById(n)?document.body.replaceChild(s,document.getElementById(n)):document.body.insertBefore(s,document.body.firstChild),clearInterval(o))},10))}Array.isArray||(Array.isArray=function(e){return Object.prototype.toString.call(e)==="[object Array]"||e instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(e,t){var n=this.length>>>0;for(var r=0;r>>0,n=new Array(t),r=arguments[1];for(var i=0;i>>0,n=0;if(t===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var r=arguments[1];else do{if(n in this){r=this[n++];break}if(++n>=t)throw new TypeError}while(!0);for(;n=t)return-1;n<0&&(n+=t);for(;nh&&(c[u]=c[u].slice(o-h),h=o)}function w(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function E(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,b();else{b();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return S(r),typeof t=="string"?t:t.length===1?t[0]:t}function S(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function L(e){return r.mode==="browser"||r.mode==="rhino"?e.filename:n("path").resolve(e.filename)}function A(e,t,n){return{lineNumber:k(e,t).line+1,fileName:L(n)}}function O(e,t){var n=C(e,t),r=k(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&k(e.call,n).line+1,this.callExtract=o[k(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this,t=t||{};t.contents||(t.contents={});var v=function(){},m=this.imports={paths:t&&t.paths||[],queue:[],files:{},contents:t.contents,mime:t&&t.mime,error:null,push:function(e,n){var i=this;this.queue.push(e),r.Parser.importer(e,this.paths,function(t,r){i.queue.splice(i.queue.indexOf(e),1);var s=e in i.files;i.files[e]=r,t&&!i.error&&(i.error=t),n(t,r,s),i.queue.length===0&&v(t)},t)}};return this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,p={imports:m,parse:function(e,a){var f,d,m,g,y,b,w=[],S,x=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0&&(x=new O({index:c,type:"Parse",message:"missing closing `}`",filename:t.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(x)return a(x);try{f=new i.Ruleset([],E(this.parsers.primary)),f.root=!0}catch(T){return a(new O(T,t))}f.toCSS=function(e){var s,o,u;return function(s,o){var u=[],a;s=s||{},typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),u=[new i.Ruleset(null,o)]);try{var f=e.call(this,{frames:u}).toCSS([],{compress:s.compress||!1,dumpLineNumbers:t.dumpLineNumbers})}catch(l){throw new O(l,t)}if(a=p.imports.error)throw a instanceof O?a:new O(a,t);return s.yuicompress&&r.mode==="node"?n("./cssmin").compressor.cssmin(f):s.compress?f.replace(/(\s)+/g,"$1"):f}}(f.eval);if(o=0&&s.charAt(N)!=="\n";N--)C++;x={type:"Parse",message:"Syntax Error on line "+y,index:o,filename:t.filename,line:y,column:C,extract:[b[y-2],b[y-1],b[y]]}}this.imports.queue.length>0?v=function(e){e?a(e):a(null,f)}:a(x,f)},parsers:{primary:function(){var e,t=[];while((e=E(this.mixin.definition)||E(this.rule)||E(this.ruleset)||E(this.mixin.call)||E(this.comment)||E(this.directive))||E(/^[\s\n]+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(E(/^\/\/.*/),!0);if(e=E(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=='"'&&s.charAt(t)!=="'")return;n&&E("~");if(e=E(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],n)},keyword:function(){var e;if(e=E(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=E(this.alpha);if(typeof s!="undefined")return s}E("("),r=E(this.entities.arguments);if(!E(")"))return;if(e)return new i.Call(e,r,a,t.filename)},arguments:function(){var e=[],t;while(t=E(this.entities.assignment)||E(this.expression)){e.push(t);if(!E(","))break}return e},literal:function(){return E(this.entities.ratio)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.quoted)},assignment:function(){var e,t;if((e=E(/^\w+(?=\s?=)/i))&&E("=")&&(t=E(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!E(/^url\(/))return;return e=E(this.entities.quoted)||E(this.entities.variable)||E(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",x(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),m.paths)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=E(/^@@?[\w-]+/)))return new i.Variable(e,n,t.filename)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=E(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.filename)},color:function(){var e;if(s.charAt(o)==="#"&&(e=E(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<45||t===47)return;if(e=E(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/))return new i.Dimension(e[1],e[2])},ratio:function(){var e,t=s.charCodeAt(o);if(t>57||t<48)return;if(e=E(/^(\d+\/\d+)/))return new i.Ratio(e[1])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&E("~");if(e=E(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=E(/^(@[\w-]+)\s*:/)))return e[1]},shorthand:function(){var e,t;if(!N(/^[@\w.%-]+\/[@\w.-]+/))return;g();if((e=E(this.entity))&&E("/")&&(t=E(this.entity)))return new i.Shorthand(e,t);y()},mixin:{call:function(){var e=[],n,r,u=[],a,f=o,l=s.charAt(o),c,h,p=!1;if(l!=="."&&l!=="#")return;g();while(n=E(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=E(">");if(E("(")){while(a=E(this.expression)){h=a,c=null;if(a.value.length==1){var d=a.value[0];if(d instanceof i.Variable&&E(":")){if(!(h=E(this.expression)))throw new Error("Expected value");c=d.name}}u.push({name:c,value:h});if(!E(","))break}if(!E(")"))throw new Error("Expected )")}E(this.important)&&(p=!0);if(e.length>0&&(E(";")||N("}")))return new i.mixin.Call(e,u,f,t.filename,p);y()},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||N(/^[^{]*(;|})/))return;g();if(n=E(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];do{if(s.charAt(o)==="."&&E(/^\.{3}/)){c=!0;break}if(!(u=E(this.entities.variable)||E(this.entities.literal)||E(this.entities.keyword)))break;if(u instanceof i.Variable)if(E(":"))a=x(this.expression,"expected expression"),t.push({name:u.name,value:a});else{if(E(/^\.{3}/)){t.push({name:u.name,variadic:!0}),c=!0;break}t.push({name:u.name})}else t.push({value:u})}while(E(","));E(")")||(l=o,y()),E(/^when/)&&(f=x(this.conditions,"expected condition")),r=E(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);y()}}},entity:function(){return E(this.entities.literal)||E(this.entities.variable)||E(this.entities.url)||E(this.entities.call)||E(this.entities.keyword)||E(this.entities.javascript)||E(this.comment)},end:function(){return E(";")||N("}")},alpha:function(){var e;if(!E(/^\(opacity=/i))return;if(e=E(/^\d+/)||E(this.entities.variable))return x(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=E(this.combinator),e=E(/^(?:\d+\.\d+|\d+)%/)||E(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||E("*")||E("&")||E(this.attribute)||E(/^\([^)@]+\)/)||E(/^[\.#](?=@)/)||E(this.entities.variableCurly),e||E("(")&&(r=E(this.entities.variableCurly)||E(this.entities.variable))&&E(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e,t=s.charAt(o);if(t===">"||t==="+"||t==="~"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(t)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u;if(E("("))return e=E(this.entity),x(")"),new i.Selector([new i.Element("",e,o)]);while(t=E(this.element)){r=s.charAt(o),n.push(t);if(r==="{"||r==="}"||r===";"||r===",")break}if(n.length>0)return new i.Selector(n)},tag:function(){return E(/^[A-Za-z][A-Za-z-]*[0-9]?/)||E("*")},attribute:function(){var e="",t,n,r;if(!E("["))return;if(t=E(/^(?:[_A-Za-z0-9-]|\\.)+/)||E(this.entities.quoted))(r=E(/^[|~*$^]?=/))&&(n=E(this.entities.quoted)||E(/^[\w-]+/))?e=[t,r,n.toCSS?n.toCSS():n].join(""):e=t;if(!E("]"))return;if(e)return"["+e+"]"},block:function(){var e;if(E("{")&&(e=E(this.primary))&&E("}"))return e},ruleset:function(){var e=[],n,r,u,a;g(),t.dumpLineNumbers&&(a=A(o,s,t));while(n=E(this.selector)){e.push(n),E(this.comment);if(!E(","))break;E(this.comment)}if(e.length>0&&(r=E(this.block))){var f=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(f.debugInfo=a),f}l=o,y()},rule:function(){var e,t,n=s.charAt(o),r,a;g();if(n==="."||n==="#"||n==="&")return;if(e=E(this.variable)||E(this.property)){e.charAt(0)!="@"&&(a=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))?(o+=a[0].length-1,t=new i.Anonymous(a[1])):e==="font"?t=E(this.font):t=E(this.value),r=E(this.important);if(t&&E(this.end))return new i.Rule(e,t,r,f);l=o,y()}},"import":function(){var e,t,n=o;g();var r=E(/^@import(?:-(once))?\s+/);if(r&&(e=E(this.entities.quoted)||E(this.entities.url))){t=E(this.mediaFeatures);if(E(";"))return new i.Import(e,m,t,r[1]==="once",n)}y()},mediaFeature:function(){var e,t,n=[];do if(e=E(this.entities.keyword))n.push(e);else if(E("(")){t=E(this.property),e=E(this.entity);if(!E(")"))return null;if(t&&e)n.push(new i.Paren(new i.Rule(t,e,null,o,!0)));else{if(!e)return null;n.push(new i.Paren(e))}}while(e);if(n.length>0)return new i.Expression(n)},mediaFeatures:function(){var e,t=[];do if(e=E(this.mediaFeature)){t.push(e);if(!E(","))break}else if(e=E(this.entities.variable)){t.push(e);if(!E(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=A(o,s,t));if(E(/^@media/)){e=E(this.mediaFeatures);if(n=E(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,t,n,r,u,a,f,l,c;if(s.charAt(o)!=="@")return;if(t=E(this["import"])||E(this.media))return t;g(),e=E(/^@[a-z-]+/),f=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(f="@"+e.slice(e.indexOf("-",2)+1));switch(f){case"@font-face":l=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":l=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":l=!0,c=!0}c&&(e+=" "+(E(/^[^{]+/)||"").trim());if(l){if(n=E(this.block))return new i.Directive(e,n)}else if((t=E(this.entity))&&E(";"))return new i.Directive(e,t);y()},font:function(){var e=[],t=[],n,r,s,o;while(o=E(this.shorthand)||E(this.entity))t.push(o);e.push(new i.Expression(t));if(E(","))while(o=E(this.expression)){e.push(o);if(!E(","))break}return new i.Value(e)},value:function(){var e,t=[],n;while(e=E(this.expression)){t.push(e);if(!E(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return E(/^! *important/)},sub:function(){var e;if(E("(")&&(e=E(this.expression))&&E(")"))return e},multiplication:function(){var e,t,n,r;if(e=E(this.operand)){while(!N(/^\/\*/)&&(n=E("/")||E("*"))&&(t=E(this.operand)))r=new i.Operation(n,[r||e,t]);return r||e}},addition:function(){var e,t,n,r;if(e=E(this.multiplication)){while((n=E(/^[-+]\s+/)||!w(s.charAt(o-1))&&(E("+")||E("-")))&&(t=E(this.multiplication)))r=new i.Operation(n,[r||e,t]);return r||e}},conditions:function(){var e,t,n=o,r;if(e=E(this.condition)){while(E(",")&&(t=E(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;E(/^not/)&&(u=!0),x("(");if(e=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))return(r=E(/^(?:>=|=<|[<=>])/))?(t=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):T("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),x(")"),E(/^and/)?new i.Condition("and",n,E(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=E("-"));var n=E(this.sub)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.variable)||E(this.entities.call);return e?new i.Operation("*",[new i.Dimension(-1),n]):n},expression:function(){var e,t,n=[],r;while(e=E(this.addition)||E(this.entity))n.push(e);if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=E(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.length>0&&(e=t[0]+e),d({href:e,title:e,type:r.mime,contents:r.contents},function(i){i&&typeof r.errback=="function"?r.errback.call(null,e,t,n,r):n.apply(null,arguments)},!0)};(function(e){function t(t){return e.functions.hsla(t.h,t.s,t.l,t.a)}function n(t){if(t instanceof e.Dimension)return parseFloat(t.unit=="%"?t.value/100:t.value);if(typeof t=="number")return t;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function r(e){return Math.min(1,Math.max(0,e))}e.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(t,r,i,s){var o=[t,r,i].map(function(e){return n(e)}),s=n(s);return new e.Color(o,s)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,r,i){function u(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?o+(s-o)*e*6:e*2<1?s:e*3<2?o+(s-o)*(2/3-e)*6:o}e=n(e)%360/360,t=n(t),r=n(r),i=n(i);var s=r<=.5?r*(t+1):r+t-r*t,o=r*2-s;return this.rgba(u(e+1/3)*255,u(e)*255,u(e-1/3)*255,i)},hue:function(t){return new e.Dimension(Math.round(t.toHSL().h))},saturation:function(t){return new e.Dimension(Math.round(t.toHSL().s*100),"%")},lightness:function(t){return new e.Dimension(Math.round(t.toHSL().l*100),"%")},red:function(t){return new e.Dimension(t.rgb[0])},green:function(t){return new e.Dimension(t.rgb[1])},blue:function(t){return new e.Dimension(t.rgb[2])},alpha:function(t){return new e.Dimension(t.toHSL().a)},luma:function(t){return new e.Dimension(Math.round((.2126*(t.rgb[0]/255)+.7152*(t.rgb[1]/255)+.0722*(t.rgb[2]/255))*t.alpha*100),"%")},saturate:function(e,n){var i=e.toHSL();return i.s+=n.value/100,i.s=r(i.s),t(i)},desaturate:function(e,n){var i=e.toHSL();return i.s-=n.value/100,i.s=r(i.s),t(i)},lighten:function(e,n){var i=e.toHSL();return i.l+=n.value/100,i.l=r(i.l),t(i)},darken:function(e,n){var i=e.toHSL();return i.l-=n.value/100,i.l=r(i.l),t(i)},fadein:function(e,n){var i=e.toHSL();return i.a+=n.value/100,i.a=r(i.a),t(i)},fadeout:function(e,n){var i=e.toHSL();return i.a-=n.value/100,i.a=r(i.a),t(i)},fade:function(e,n){var i=e.toHSL();return i.a=n.value/100,i.a=r(i.a),t(i)},spin:function(e,n){var r=e.toHSL(),i=(r.h+n.value)%360;return r.h=i<0?360+i:i,t(r)},mix:function(t,n,r){r||(r=new e.Dimension(50));var i=r.value/100,s=i*2-1,o=t.toHSL().a-n.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[t.rgb[0]*u+n.rgb[0]*a,t.rgb[1]*u+n.rgb[1]*a,t.rgb[2]*u+n.rgb[2]*a],l=t.alpha*i+n.alpha*(1-i);return new e.Color(f,l)},greyscale:function(t){return this.desaturate(t,new e.Dimension(100))},contrast:function(e,t,n,r){return typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1)),typeof r=="undefined"?r=.43:r=r.value,(.2126*(e.rgb[0]/255)+.7152*(e.rgb[1]/255)+.0722*(e.rgb[2]/255))*e.alpha255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},operate:function(t,n){var r=[];n instanceof e.Color||(n=n.toColor());for(var i=0;i<3;i++)r[i]=e.operate(t,this.rgb[i],n.rgb[i]);return new e.Color(r,this.alpha+n.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,
-n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype.eval=function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}(n("../tree")),function(e){e.Dimension=function(e,t){this.value=parseFloat(e),this.unit=t||null},e.Dimension.prototype={eval:function(){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(){var e=this.value+this.unit;return e},operate:function(t,n){return new e.Dimension(e.operate(t,this.value,n.value),this.unit||n.unit)},compare:function(t){return t instanceof e.Dimension?t.value>this.value?-1:t.value":e.compress?">":" > "}[this.value]}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={eval:function(t){return this.value.length>1?new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?this.value[0].eval(t):this},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")}}}(n("../tree")),function(e){e.Import=function(t,n,r,i,s){var o=this;this.once=i,this.index=s,this._path=t,this.features=r&&new e.Value(r),t instanceof e.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(t.value)?t.value:t.value+".less":this.path=t.value.value||t.value,this.css=/css(\?.*)?$/.test(this.path),this.css||n.push(this.path,function(t,n,r){t&&(t.index=s),r&&o.once&&(o.skip=r),o.root=n||new e.Ruleset([],[])})},e.Import.prototype={toCSS:function(e){var t=this.features?" "+this.features.toCSS(e):"";return this.css?"@import "+this._path.toCSS()+t+";\n":""},eval:function(t){var n,r=this.features&&this.features.eval(t);if(this.skip)return[];if(this.css)return this;n=new e.Ruleset([],this.root.rules.slice(0));for(var i=0;i1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){n=this.arguments&&this.arguments.map(function(t){return{name:t.name,value:t.value.eval(e)}});for(var o=0;othis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}if(this.condition&&!this.condition.eval({frames:[this.evalParams(t,e)].concat(t.frames)}))return!1;r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t,n){var r=[],i=[],s=[],o=[],u=[],a,f,l;this.root||this.joinSelectors(u,t,this.selectors);for(var c=0;c0){f=e.debugInfo(n,this),a=u.map(function(e){return e.map(function(e){return e.toCSS(n)}).join("").trim()}).join(n.compress?",":",\n");for(var c=i.length-1;c>=0;c--)s.indexOf(i[c])===-1&&s.unshift(i[c]);i=s,r.push(f+a+(n.compress?"{":" {\n ")+i.join(n.compress?"":"\n ")+(n.compress?"}":"\n}\n"))}return r.push(o),r.join("")+(n.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0)),v=!1):d=new e.Selector([]),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t)):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e){this.elements=e},e.Selector.prototype.match=function(e){var t=this.elements.length,n=e.elements.length,r=Math.min(t,n);if(t0&&(r.value=this.paths[0]+(r.value.charAt(0)==="/"?r.value.slice(1):r.value)),new t.URL(r,this.paths)}}}(n("../tree")),function(e){e.Value=function(e){this.value=e,this.is="value"},e.Value.prototype={eval:function(t){return this.value.length===1?this.value[0].eval(t):new e.Value(this.value.map(function(e){return e.eval(t)}))},toCSS:function(e){return this.value.map(function(t){return t.toCSS(e)}).join(e.compress?",":", ")}}}(n("../tree")),function(e){e.Variable=function(e,t,n){this.name=e,this.index=t,this.file=n},e.Variable.prototype={eval:function(t){var n,r,i=this.name;i.indexOf("@@")==0&&(i="@"+(new e.Variable(i.slice(1))).eval(t).value);if(n=e.find(t.frames,function(e){if(r=e.variable(i))return r.value.eval(t)}))return n;throw{type:"Name",message:"variable "+i+" is undefined",filename:this.file,index:this.index}}}}(n("../tree")),function(e){e.debugInfo=function(t,n){var r="";if(t.dumpLineNumbers&&!t.compress)switch(t.dumpLineNumbers){case"comments":r=e.debugInfo.asComment(n);break;case"mediaquery":r=e.debugInfo.asMediaQuery(n);break;case"all":r=e.debugInfo.asComment(n)+e.debugInfo.asMediaQuery(n)}return r},e.debugInfo.asComment=function(e){return"/* line "+e.debugInfo.lineNumber+", "+e.debugInfo.fileName+" */\n"},e.debugInfo.asMediaQuery=function(e){return'@media -sass-debug-info{filename{font-family:"'+e.debugInfo.fileName+'";}line{font-family:"'+e.debugInfo.lineNumber+'";}}\n'},e.find=function(e,t){for(var n=0,r;n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree"));var s=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||s?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(s?1e3:1500),r.watch=function(){return this.watchMode=!0},r.unwatch=function(){return this.watchMode=!1};if(r.env==="development"){r.optimization=0,/!watch/.test(location.hash)&&r.watch();var o=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);o&&(r.dumpLineNumbers=o[1]),r.watchTimer=setInterval(function(){r.watchMode&&p(function(e,t,n,r,i){t&&m(t.toCSS(),r,i.lastModified)})},r.poll)}else r.optimization=3;var u;try{u=typeof e.localStorage=="undefined"?null:e.localStorage}catch(a){u=null}var f=document.getElementsByTagName("link"),l=/^text\/(x-)?less$/;r.sheets=[];for(var c=0;c0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=t.contents||{},u=t.files||{},a=b(t.href,e.location.href),f=a.url,c=l&&l.getItem(f),h=l&&l.getItem(f+":timestamp"),p={css:c,timestamp:h},d;r.relativeUrls?r.rootpath?t.entryPath?d=b(r.rootpath+y(a.path,t.entryPath)).path:d=r.rootpath:d=a.path:r.rootpath?d=r.rootpath:t.entryPath?d=t.entryPath:d=a.path,x(f,t.type,function(e,l){v+=e.replace(/@import .+?;/ig,"");if(!i&&p&&l&&(new Date(l)).valueOf()===(new Date(p.timestamp)).valueOf())S(p.css,t),n(null,null,e,t,{local:!0,remaining:s},f);else try{o[f]=e,(new r.Parser({optimization:r.optimization,paths:[a.path],entryPath:t.entryPath||a.path,mime:t.type,filename:f,rootpath:d,relativeUrls:t.relativeUrls,contents:o,files:u,dumpLineNumbers:r.dumpLineNumbers})).parse(e,function(r,i){if(r)return k(r,f);try{n(r,i,e,t,{local:!1,lastModified:l,remaining:s},f),N(document.getElementById("less-error-message:"+E(f)))}catch(r){k(r,f)}})}catch(c){k(c,f)}},function(e,t){throw new Error("Couldn't load "+t+" ("+e+")")})}function E(e){return e.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r,i=t.href||"",s="less:"+(t.title||E(i));if((r=document.getElementById(s))===null){r=document.createElement("style"),r.type="text/css",t.media&&(r.media=t.media),r.id=s;var o=t&&t.nextSibling||null;(o||document.getElementsByTagName("head")[0]).parentNode.insertBefore(r,o)}if(r.styleSheet)try{r.styleSheet.cssText=e}catch(u){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(e){r.childNodes.length>0?r.firstChild.nodeValue!==e.nodeValue&&r.replaceChild(e,r.firstChild):r.appendChild(e)})(document.createTextNode(e));if(n&&l){C("saving "+i+" to cache.");try{l.setItem(i,e),l.setItem(i+":timestamp",n)}catch(u){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,t){var n="less-error-message:"+E(t),i='
"+(e.message||"There is an error in your .less file")+"
"+'
in '+l+" ";var c=function(e,t,n){e.extract[t]&&a.push(i.replace(/\{line\}/,parseInt(e.line)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};e.stack?u+=" "+e.stack.split("\n").slice(1).join(" "):e.extract&&(c(e,0,""),c(e,1,"line"),c(e,2,""),u+="on line "+e.line+", column "+(e.column+1)+":
* This will read the metadata and content of the LESS source, and will automatically resolve the imports.
*
+ *
+ * The file is read using the default Charset of the platform
+ *
*
* @param file The File reference to the LESS source to read.
* @throws FileNotFoundException If the LESS source (or one of its imports) could not be found.
* @throws IOException If the LESS source cannot be read.
*/
public LessSource(File file) throws FileNotFoundException, IOException {
+ this(file, Charset.defaultCharset());
+ }
+
+ /**
+ * Constructs a new LessSource.
+ *
+ * This will read the metadata and content of the LESS source, and will automatically resolve the imports.
+ *
+ *
+ * @param file The File reference to the LESS source to read.
+ * @param charset charset used to read the less file.
+ * @throws FileNotFoundException If the LESS source (or one of its imports) could not be found.
+ * @throws IOException If the LESS source cannot be read.
+ */
+ public LessSource(File file, Charset charset) throws IOException {
if (file == null) {
throw new IllegalArgumentException("File must not be null.");
}
- if (!file.exists()) {
+ if (!file.exists()) {
throw new FileNotFoundException("File " + file.getAbsolutePath() + " not found.");
}
this.file = file;
- this.content = this.normalizedContent = FileUtils.readFileToString(file);
+ this.content = this.normalizedContent = FileUtils.readFileToString(file, charset);
resolveImports();
}
-
+
/**
* Returns the absolute pathname of the LESS source.
*
diff --git a/src/test/java/org/lesscss/LessSourceTest.java b/src/test/java/org/lesscss/LessSourceTest.java
index bd1ae18..9deb957 100644
--- a/src/test/java/org/lesscss/LessSourceTest.java
+++ b/src/test/java/org/lesscss/LessSourceTest.java
@@ -14,26 +14,28 @@
*/
package org.lesscss;
-import static org.junit.Assert.assertEquals;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static org.powermock.api.mockito.PowerMockito.verifyStatic;
-import static org.powermock.api.mockito.PowerMockito.when;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
-import org.lesscss.LessSource;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.powermock.api.mockito.PowerMockito.*;
@PrepareForTest({FileUtils.class, LessSource.class})
@RunWith(PowerMockRunner.class)
@@ -115,6 +117,26 @@ public void testLastModifiedIncludingImportsWhenImportModifiedLater() throws Exc
assertEquals(2l, lessSource.getLastModifiedIncludingImports());
}
+ @Test
+ public void testUtf8EncodedLessFile() throws Exception {
+ String content = readLessSourceWithEncoding("UTF-8");
+ assertThat(content, containsString("↓"));
+ }
+
+ @Test
+ public void testWithBadEncodinfLessFile() throws Exception {
+ String content = readLessSourceWithEncoding("ISO-8859-1");
+ assertThat(content, not(containsString("↓")));
+ }
+
+ private String readLessSourceWithEncoding(String encoding) throws IOException, IllegalAccessException {
+ URL sourceUrl = getClass().getResource("/compatibility/utf8-content.less");
+ File sourceFile = new File(sourceUrl.getFile());
+ LessSource lessSource = new LessSource(sourceFile, Charset.forName(encoding));
+ return (String) FieldUtils.readField(lessSource, "content", true);
+ }
+
+
private File mockFile(boolean fileExists, String content, String absolutePath) throws IOException {
when(file.exists()).thenReturn(fileExists);
mockStatic(FileUtils.class);
diff --git a/src/test/resources/compatibility/utf8-content.less b/src/test/resources/compatibility/utf8-content.less
new file mode 100644
index 0000000..1cb5425
--- /dev/null
+++ b/src/test/resources/compatibility/utf8-content.less
@@ -0,0 +1 @@
+.sort-true::before{ content:'↓ '; }
From 5dbf33a6a9db3e950bbc02a518b441990b36e2cb Mon Sep 17 00:00:00 2001
From: 4ntoin3
Date: Thu, 13 Jun 2013 23:47:52 +0200
Subject: [PATCH 33/72] [Fix] import failed when closing brace is on same line
---
src/main/java/org/lesscss/LessSource.java | 6 +++---
src/test/resources/import/css/import.css | 5 +++++
src/test/resources/import/less/import.less | 4 +++-
src/test/resources/import/less/import_quotes.less | 4 +++-
4 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/src/main/java/org/lesscss/LessSource.java b/src/main/java/org/lesscss/LessSource.java
index ea3276b..8e352ea 100644
--- a/src/main/java/org/lesscss/LessSource.java
+++ b/src/main/java/org/lesscss/LessSource.java
@@ -37,7 +37,7 @@ public class LessSource {
/**
* The Pattern used to match imported files.
*/
- private static final Pattern IMPORT_PATTERN = Pattern.compile("^(?!\\s*//\\s*)@import\\s+(url\\()?\\s*(\"|')(.+)\\s*(\"|')(\\))?\\s*;.*$", MULTILINE);
+ private static final Pattern IMPORT_PATTERN = Pattern.compile("^(?!\\s*//\\s*).*(@import\\s+(url\\()?\\s*(\"|')(.+)\\s*(\"|')(\\))?\\s*;).*$", MULTILINE);
private File file;
private String content;
@@ -159,13 +159,13 @@ public Map getImports() {
private void resolveImports() throws FileNotFoundException, IOException {
Matcher importMatcher = IMPORT_PATTERN.matcher(normalizedContent);
while (importMatcher.find()) {
- String importedFile = importMatcher.group(3);
+ String importedFile = importMatcher.group(4);
importedFile = importedFile.matches(".*\\.(le?|c)ss$") ? importedFile : importedFile + ".less";
boolean css = importedFile.matches(".*css$");
if (!css) {
LessSource importedLessSource = new LessSource(new File(file.getParentFile(), importedFile));
imports.put(importedFile, importedLessSource);
- normalizedContent = normalizedContent.substring(0, importMatcher.start()) + importedLessSource.getNormalizedContent() + normalizedContent.substring(importMatcher.end());
+ normalizedContent = normalizedContent.substring(0, importMatcher.start(1)) + importedLessSource.getNormalizedContent() + normalizedContent.substring(importMatcher.end(1));
importMatcher = IMPORT_PATTERN.matcher(normalizedContent);
}
}
diff --git a/src/test/resources/import/css/import.css b/src/test/resources/import/css/import.css
index dd1986e..71efe95 100644
--- a/src/test/resources/import/css/import.css
+++ b/src/test/resources/import/css/import.css
@@ -7,3 +7,8 @@ import1b {
import4 {
color: blue;
}
+@media screen {
+ import4 {
+ color: blue;
+ }
+}
diff --git a/src/test/resources/import/less/import.less b/src/test/resources/import/less/import.less
index 11f88fe..386e3fb 100644
--- a/src/test/resources/import/less/import.less
+++ b/src/test/resources/import/less/import.less
@@ -1,4 +1,6 @@
@import "import1.less";
//@import "import2.less";
// @import "import3.less";
-@import "import4";
\ No newline at end of file
+@import "import4";
+
+@media screen { @import "import4"; }
\ No newline at end of file
diff --git a/src/test/resources/import/less/import_quotes.less b/src/test/resources/import/less/import_quotes.less
index bca12bf..5ac541b 100644
--- a/src/test/resources/import/less/import_quotes.less
+++ b/src/test/resources/import/less/import_quotes.less
@@ -1,4 +1,6 @@
@import 'import1.less';
//@import 'import2.less';
// @import 'import3.less';
-@import "import4";
\ No newline at end of file
+@import "import4";
+
+@media screen { @import 'import4'; }
\ No newline at end of file
From 235feb9669851d72f6b260323ad1a9df8663031e Mon Sep 17 00:00:00 2001
From: Anton Pechinsky
Date: Thu, 20 Jun 2013 20:10:12 +0300
Subject: [PATCH 34/72] Remove File dependency from LessSource. Introduce
abstract Resource.
---
pom.xml | 2 +-
src/main/java/org/lesscss/FileResource.java | 40 +++++++
src/main/java/org/lesscss/LessCompiler.java | 8 +-
src/main/java/org/lesscss/LessSource.java | 110 ++++++++++--------
src/main/java/org/lesscss/Resource.java | 44 +++++++
src/test/java/org/lesscss/LessSourceTest.java | 10 +-
6 files changed, 154 insertions(+), 60 deletions(-)
create mode 100644 src/main/java/org/lesscss/FileResource.java
create mode 100644 src/main/java/org/lesscss/Resource.java
diff --git a/pom.xml b/pom.xml
index f14ab4c..9d09a34 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0org.lesscsslesscss
- 1.3.3.1-SNAPSHOT
+ 1.3.3.1.resourcejarOfficial LESS CSS Compiler for JavaOfficial LESS CSS Compiler for Java
diff --git a/src/main/java/org/lesscss/FileResource.java b/src/main/java/org/lesscss/FileResource.java
new file mode 100644
index 0000000..0facfef
--- /dev/null
+++ b/src/main/java/org/lesscss/FileResource.java
@@ -0,0 +1,40 @@
+package org.lesscss;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * File based implementation of {@link Resource}.
+ *
+ * @author Anton Pechinsky
+ */
+public class FileResource implements Resource {
+
+ private File file;
+
+ public FileResource(File file) {
+ if (file == null) {
+ throw new IllegalArgumentException("File must not be null!");
+ }
+ this.file = file;
+ }
+
+ public boolean exists() {
+ return file.exists();
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return new FileInputStream(file);
+ }
+
+ public long lastModified() {
+ return file.lastModified();
+ }
+
+ public Resource createRelative(String relativePath) {
+ File relativeFile = new File(file.getParentFile(), relativePath);
+ return new FileResource(relativeFile);
+ }
+}
diff --git a/src/main/java/org/lesscss/LessCompiler.java b/src/main/java/org/lesscss/LessCompiler.java
index 1f3541e..a966327 100644
--- a/src/main/java/org/lesscss/LessCompiler.java
+++ b/src/main/java/org/lesscss/LessCompiler.java
@@ -113,7 +113,7 @@ public URL getLessJs() {
* Sets the LESS JavaScript file used by the compiler.
* Must be set before {@link #init()} is called.
*
- * @param The LESS JavaScript file used by the compiler.
+ * @param lessJs LESS JavaScript file used by the compiler.
*/
public synchronized void setLessJs(URL lessJs) {
if (scope != null) {
@@ -194,7 +194,7 @@ public String getEncoding() {
* If not set the platform default will be used.
* Must be set before {@link #init()} is called.
*
- * @param The character encoding used by the compiler when writing the output File.
+ * @param encoding character encoding used by the compiler when writing the output File.
*/
public synchronized void setEncoding(String encoding) {
if (scope != null) {
@@ -298,7 +298,7 @@ public String compile(String input) throws LessException {
* @throws IOException If the LESS file cannot be read.
*/
public String compile(File input) throws IOException, LessException {
- LessSource lessSource = new LessSource(input);
+ LessSource lessSource = new LessSource(new FileResource(input));
return compile(lessSource);
}
@@ -322,7 +322,7 @@ public void compile(File input, File output) throws IOException, LessException {
* @throws IOException If the LESS file cannot be read or the output file cannot be written.
*/
public void compile(File input, File output, boolean force) throws IOException, LessException {
- LessSource lessSource = new LessSource(input);
+ LessSource lessSource = new LessSource(new FileResource(input));
compile(lessSource, output, force);
}
diff --git a/src/main/java/org/lesscss/LessSource.java b/src/main/java/org/lesscss/LessSource.java
index ea3276b..8b38628 100644
--- a/src/main/java/org/lesscss/LessSource.java
+++ b/src/main/java/org/lesscss/LessSource.java
@@ -14,22 +14,21 @@
*/
package org.lesscss;
-import org.apache.commons.io.FileUtils;
-
-import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import static java.util.regex.Pattern.MULTILINE;
+import org.apache.commons.io.IOUtils;
+
/**
* Represents the metadata and content of a LESS source.
- *
+ *
* @author Marcel Overdijk
*/
public class LessSource {
@@ -39,96 +38,107 @@ public class LessSource {
*/
private static final Pattern IMPORT_PATTERN = Pattern.compile("^(?!\\s*//\\s*)@import\\s+(url\\()?\\s*(\"|')(.+)\\s*(\"|')(\\))?\\s*;.*$", MULTILINE);
- private File file;
+ private Resource resource;
private String content;
private String normalizedContent;
private Map imports = new LinkedHashMap();
-
+
/**
* Constructs a new LessSource.
*
- * This will read the metadata and content of the LESS source, and will automatically resolve the imports.
+ * This will read the metadata and content of the LESS source, and will automatically resolve the imports.
*
*
- * The file is read using the default Charset of the platform
+ * The resource is read using the default Charset of the platform
*
- *
- * @param file The File reference to the LESS source to read.
+ *
+ * @param resource The File reference to the LESS source to read.
* @throws FileNotFoundException If the LESS source (or one of its imports) could not be found.
* @throws IOException If the LESS source cannot be read.
*/
- public LessSource(File file) throws FileNotFoundException, IOException {
- this(file, Charset.defaultCharset());
+ public LessSource(Resource resource) throws FileNotFoundException, IOException {
+ this(resource, Charset.defaultCharset());
}
/**
* Constructs a new LessSource.
*
- * This will read the metadata and content of the LESS source, and will automatically resolve the imports.
+ * This will read the metadata and content of the LESS resource, and will automatically resolve the imports.
*
*
- * @param file The File reference to the LESS source to read.
- * @param charset charset used to read the less file.
- * @throws FileNotFoundException If the LESS source (or one of its imports) could not be found.
- * @throws IOException If the LESS source cannot be read.
+ * @param resource The File reference to the LESS resource to read.
+ * @param charset charset used to read the less resource.
+ * @throws FileNotFoundException If the LESS resource (or one of its imports) could not be found.
+ * @throws IOException If the LESS resource cannot be read.
*/
- public LessSource(File file, Charset charset) throws IOException {
- if (file == null) {
- throw new IllegalArgumentException("File must not be null.");
+ public LessSource(Resource resource, Charset charset) throws IOException {
+ if (resource == null) {
+ throw new IllegalArgumentException("Resource must not be null.");
}
- if (!file.exists()) {
- throw new FileNotFoundException("File " + file.getAbsolutePath() + " not found.");
+ if (!resource.exists()) {
+ throw new IOException("Resource " + resource + " not found.");
}
- this.file = file;
- this.content = this.normalizedContent = FileUtils.readFileToString(file, charset);
+ this.resource = resource;
+ this.content = this.normalizedContent = loadResource(resource, charset);
resolveImports();
}
+ private String loadResource(Resource resource, Charset charset) throws IOException {
+ InputStream inputStream = null;
+ try {
+ inputStream = resource.getInputStream();
+ return IOUtils.toString(inputStream, charset.name());
+ }
+ finally {
+ inputStream.close();
+ }
+ }
+
/**
* Returns the absolute pathname of the LESS source.
- *
+ *
* @return The absolute pathname of the LESS source.
*/
public String getAbsolutePath() {
- return file.getAbsolutePath();
+ return resource.toString();
}
-
+
/**
* Returns the content of the LESS source.
- *
+ *
* @return The content of the LESS source.
*/
public String getContent() {
return content;
}
-
+
/**
* Returns the normalized content of the LESS source.
*
- * The normalized content represents the LESS source as a flattened source
- * where import statements have been resolved and replaced by the actual
- * content.
+ * The normalized content represents the LESS source as a flattened source
+ * where import statements have been resolved and replaced by the actual
+ * content.
*
- *
+ *
* @return The normalized content of the LESS source.
*/
public String getNormalizedContent() {
return normalizedContent;
}
-
+
/**
* Returns the time that the LESS source was last modified.
- *
- * @return A long value representing the time the file was last modified, measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970).
+ *
+ * @return A long value representing the time the resource was last modified, measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970).
*/
public long getLastModified() {
- return file.lastModified();
+ return resource.lastModified();
}
/**
* Returns the time that the LESS source, or one of its imports, was last modified.
- *
- * @return A long value representing the time the file was last modified, measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970).
+ *
+ * @return A long value representing the time the resource was last modified, measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970).
*/
public long getLastModifiedIncludingImports() {
long lastModified = getLastModified();
@@ -141,15 +151,15 @@ public long getLastModifiedIncludingImports() {
}
return lastModified;
}
-
+
/**
* Returns the LESS sources imported by this LESS source.
*
- * The returned imports are represented by a
+ * The returned imports are represented by a
* Map<String, LessSource> which contains the filename and the
* LessSource.
*
"+(e.message||"There is an error in your .less file")+"
"+'
in '+l+" ";var c=function(e,t,n){e.extract[t]&&a.push(i.replace(/\{line\}/,parseInt(e.line)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};e.stack?u+=" "+e.stack.split("\n").slice(1).join(" "):e.extract&&(c(e,0,""),c(e,1,"line"),c(e,2,""),u+="on line "+e.line+", column "+(e.column+1)+":
"+"
"+a.join("")+"
"),s.innerHTML=u,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),s.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(o=setInterval(function(){document.body&&(document.getElementById(n)?document.body.replaceChild(s,document.getElementById(n)):document.body.insertBefore(s,document.body.firstChild),clearInterval(o))},10))}Array.isArray||(Array.isArray=function(e){return Object.prototype.toString.call(e)==="[object Array]"||e instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(e,t){var n=this.length>>>0;for(var r=0;r>>0,n=new Array(t),r=arguments[1];for(var i=0;i>>0,n=0;if(t===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var r=arguments[1];else do{if(n in this){r=this[n++];break}if(++n>=t)throw new TypeError}while(!0);for(;n=t)return-1;n<0&&(n+=t);for(;nh&&(c[u]=c[u].slice(o-h),h=o)}function w(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function E(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,b();else{b();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return S(r),typeof t=="string"?t:t.length===1?t[0]:t}function S(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function L(e){return r.mode==="browser"||r.mode==="rhino"?e.filename:n("path").resolve(e.filename)}function A(e,t,n){return{lineNumber:k(e,t).line+1,fileName:L(n)}}function O(e,t){var n=C(e,t),r=k(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&k(e.call,n).line+1,this.callExtract=o[k(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this,t=t||{};t.contents||(t.contents={}),t.rootpath=t.rootpath||"",t.files||(t.files={});var v=function(){},m=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n){var i=this;this.queue.push(e),r.Parser.importer(e,this.paths,function(t,r,s){i.queue.splice(i.queue.indexOf(e),1);var o=s in i.files;i.files[s]=r,t&&!i.error&&(i.error=t),n(t,r,o),i.queue.length===0&&v(i.error)},t)}};return this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,p={imports:m,parse:function(e,a){var f,d,m,g,y,b,w=[],S,x=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(x)return a(x,t);try{f=new i.Ruleset([],E(this.parsers.primary)),f.root=!0}catch(T){return a(new O(T,t))}f.toCSS=function(e){var s,o,u;return function(s,o){var u=[],a;s=s||{},typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),u=[new i.Ruleset(null,o)]);try{var f=e.call(this,{frames:u}).toCSS([],{compress:s.compress||!1,dumpLineNumbers:t.dumpLineNumbers})}catch(l){throw new O(l,t)}if(a=p.imports.error)throw a instanceof O?a:new O(a,t);return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(f):s.compress?f.replace(/(\s)+/g,"$1"):f}}(f.eval);if(o=0&&s.charAt(N)!=="\n";N--)C++;x={type:"Parse",message:"Syntax Error on line "+y,index:o,filename:t.filename,line:y,column:C,extract:[b[y-2],b[y-1],b[y]]}}this.imports.queue.length>0?v=function(e){e=x||e,e?a(e):a(null,f)}:a(x,f)},parsers:{primary:function(){var e,t=[];while((e=E(this.mixin.definition)||E(this.rule)||E(this.ruleset)||E(this.mixin.call)||E(this.comment)||E(this.directive))||E(/^[\s\n]+/)||E(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(E(/^\/\/.*/),!0);if(e=E(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=='"'&&s.charAt(t)!=="'")return;n&&E("~");if(e=E(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],n)},keyword:function(){var e;if(e=E(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=E(this.alpha);if(typeof s!="undefined")return s}E("("),r=E(this.entities.arguments);if(!E(")"))return;if(e)return new i.Call(e,r,a,t.filename)},arguments:function(){var e=[],t;while(t=E(this.entities.assignment)||E(this.expression)){e.push(t);if(!E(","))break}return e},literal:function(){return E(this.entities.ratio)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.quoted)||E(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=E(/^\w+(?=\s?=)/i))&&E("=")&&(t=E(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!E(/^url\(/))return;return e=E(this.entities.quoted)||E(this.entities.variable)||E(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",x(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.rootpath)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=E(/^@@?[\w-]+/)))return new i.Variable(e,n,t.filename)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=E(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.filename)},color:function(){var e;if(s.charAt(o)==="#"&&(e=E(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=E(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/))return new i.Dimension(e[1],e[2])},ratio:function(){var e,t=s.charCodeAt(o);if(t>57||t<48)return;if(e=E(/^(\d+\/\d+)/))return new i.Ratio(e[1])},unicodeDescriptor:function(){var e;if(e=E(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&E("~");if(e=E(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=E(/^(@[\w-]+)\s*:/)))return e[1]},shorthand:function(){var e,t;if(!N(/^[@\w.%-]+\/[@\w.-]+/))return;g();if((e=E(this.entity))&&E("/")&&(t=E(this.entity)))return new i.Shorthand(e,t);y()},mixin:{call:function(){var e=[],n,r,u=[],a=[],f,l,c,h,p,d,v,m=o,b=s.charAt(o),w,S,C=!1;if(b!=="."&&b!=="#")return;g();while(n=E(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=E(">");if(E("(")){p=[];while(c=E(this.expression)){h=null,S=c;if(c.value.length==1){var k=c.value[0];k instanceof i.Variable&&E(":")&&(p.length>0&&(d&&T("Cannot mix ; and , as delimiter types"),v=!0),S=x(this.expression),h=w=k.name)}p.push(S),a.push({name:h,value:S});if(E(","))continue;if(E(";")||d)v&&T("Cannot mix ; and , as delimiter types"),d=!0,p.length>1&&(S=new i.Value(p)),u.push({name:w,value:S}),w=null,p=[],v=!1}x(")")}f=d?u:a,E(this.important)&&(C=!0);if(e.length>0&&(E(";")||N("}")))return new i.mixin.Call(e,f,m,t.filename,C);y()},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||N(/^[^{]*\}/))return;g();if(n=E(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];do{E(this.comment);if(s.charAt(o)==="."&&E(/^\.{3}/)){c=!0,t.push({variadic:!0});break}if(!(u=E(this.entities.variable)||E(this.entities.literal)||E(this.entities.keyword)))break;if(u instanceof i.Variable)if(E(":"))a=x(this.expression,"expected expression"),t.push({name:u.name,value:a});else{if(E(/^\.{3}/)){t.push({name:u.name,variadic:!0}),c=!0;break}t.push({name:u.name})}else t.push({value:u})}while(E(",")||E(";"));E(")")||(l=o,y()),E(this.comment),E(/^when/)&&(f=x(this.conditions,"expected condition")),r=E(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);y()}}},entity:function(){return E(this.entities.literal)||E(this.entities.variable)||E(this.entities.url)||E(this.entities.call)||E(this.entities.keyword)||E(this.entities.javascript)||E(this.comment)},end:function(){return E(";")||N("}")},alpha:function(){var e;if(!E(/^\(opacity=/i))return;if(e=E(/^\d+/)||E(this.entities.variable))return x(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=E(this.combinator),e=E(/^(?:\d+\.\d+|\d+)%/)||E(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||E("*")||E("&")||E(this.attribute)||E(/^\([^()@]+\)/)||E(/^[\.#](?=@)/)||E(this.entities.variableCurly),e||E("(")&&(r=E(this.entities.variableCurly)||E(this.entities.variable)||E(this.selector))&&E(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e,t=s.charAt(o);if(t===">"||t==="+"||t==="~"||t==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(t)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u;if(E("("))return e=E(this.entity),E(")")?new i.Selector([new i.Element("",e,o)]):null;while(t=E(this.element)){r=s.charAt(o),n.push(t);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n)},attribute:function(){var e="",t,n,r;if(!E("["))return;if(t=E(/^(?:[_A-Za-z0-9-]|\\.)+/)||E(this.entities.quoted))(r=E(/^[|~*$^]?=/))&&(n=E(this.entities.quoted)||E(/^[\w-]+/))?e=[t,r,n.toCSS?n.toCSS():n].join(""):e=t;if(!E("]"))return;if(e)return"["+e+"]"},block:function(){var e;if(E("{")&&(e=E(this.primary))&&E("}"))return e},ruleset:function(){var e=[],n,r,u,a;g(),t.dumpLineNumbers&&(a=A(o,s,t));while(n=E(this.selector)){e.push(n),E(this.comment);if(!E(","))break;E(this.comment)}if(e.length>0&&(r=E(this.block))){var f=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(f.debugInfo=a),f}l=o,y()},rule:function(){var e,t,n=s.charAt(o),r,a;g();if(n==="."||n==="#"||n==="&")return;if(e=E(this.variable)||E(this.property)){e.charAt(0)!="@"&&(a=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))?(o+=a[0].length-1,t=new i.Anonymous(a[1])):e==="font"?t=E(this.font):t=E(this.value),r=E(this.important);if(t&&E(this.end))return new i.Rule(e,t,r,f);l=o,y()}},"import":function(){var e,n,r=o;g();var s=E(/^@import(?:-(once))?\s+/);if(s&&(e=E(this.entities.quoted)||E(this.entities.url))){n=E(this.mediaFeatures);if(E(";"))return new i.Import(e,m,n,s[1]==="once",r,t.rootpath)}y()},mediaFeature:function(){var e,t,n=[];do if(e=E(this.entities.keyword))n.push(e);else if(E("(")){t=E(this.property),e=E(this.entity);if(!E(")"))return null;if(t&&e)n.push(new i.Paren(new i.Rule(t,e,null,o,!0)));else{if(!e)return null;n.push(new i.Paren(e))}}while(e);if(n.length>0)return new i.Expression(n)},mediaFeatures:function(){var e,t=[];do if(e=E(this.mediaFeature)){t.push(e);if(!E(","))break}else if(e=E(this.entities.variable)){t.push(e);if(!E(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=A(o,s,t));if(E(/^@media/)){e=E(this.mediaFeatures);if(n=E(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=E(this["import"])||E(this.media))return n;g(),e=E(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(E(/^[^{]+/)||"").trim());if(c){if(r=E(this.block))return new i.Directive(e,r)}else if((n=p?E(this.expression):E(this.entity))&&E(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=A(o,s,t)),d}y()},font:function(){var e=[],t=[],n,r,s,o;while(o=E(this.shorthand)||E(this.entity))t.push(o);e.push(new i.Expression(t));if(E(","))while(o=E(this.expression)){e.push(o);if(!E(","))break}return new i.Value(e)},value:function(){var e,t=[],n;while(e=E(this.expression)){t.push(e);if(!E(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return E(/^! *important/)},sub:function(){var e;if(E("(")&&(e=E(this.expression))&&E(")"))return e},multiplication:function(){var e,t,n,r;if(e=E(this.operand)){while(!N(/^\/[*\/]/)&&(n=E("/")||E("*"))&&(t=E(this.operand)))r=new i.Operation(n,[r||e,t]);return r||e}},addition:function(){var e,t,n,r;if(e=E(this.multiplication)){while((n=E(/^[-+]\s+/)||!w(s.charAt(o-1))&&(E("+")||E("-")))&&(t=E(this.multiplication)))r=new i.Operation(n,[r||e,t]);return r||e}},conditions:function(){var e,t,n=o,r;if(e=E(this.condition)){while(E(",")&&(t=E(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;E(/^not/)&&(u=!0),x("(");if(e=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))return(r=E(/^(?:>=|=<|[<=>])/))?(t=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):T("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),x(")"),E(/^and/)?new i.Condition("and",n,E(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=E("-"));var n=E(this.sub)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.variable)||E(this.entities.call);return e?new i.Operation("*",[new i.Dimension(-1),n]):n},expression:function(){var e,t,n=[],r;while(e=E(this.addition)||E(this.entity))n.push(e);if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=E(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.length>0&&(e=t[0]+e),w({href:e,title:e,type:r.mime,contents:r.contents,files:r.files,rootpath:r.rootpath,entryPath:r.entryPath,relativeUrls:r.relativeUrls},function(e,i,s,o,u,a){e&&typeof r.errback=="function"?r.errback.call(null,a,t,n,r):n.call(null,e,i,a)},!0)};(function(e){function t(t){return e.functions.hsla(t.h,t.s,t.l,t.a)}function n(t,n){return t instanceof e.Dimension&&t.unit=="%"?parseFloat(t.value*n/100):r(t)}function r(t){if(t instanceof e.Dimension)return parseFloat(t.unit=="%"?t.value/100:t.value);if(typeof t=="number")return t;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function i(e){return Math.min(1,Math.max(0,e))}e.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(t,i,s,o){var u=[t,i,s].map(function(e){return n(e,256)});return o=r(o),new e.Color(u,o)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,i){function u(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?o+(s-o)*e*6:e*2<1?s:e*3<2?o+(s-o)*(2/3-e)*6:o}e=r(e)%360/360,t=r(t),n=r(n),i=r(i);var s=n<=.5?n*(t+1):n+t-n*t,o=n*2-s;return this.rgba(u(e+1/3)*255,u(e)*255,u(e-1/3)*255,i)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,i){e=r(e)%360/360*360,t=r(t),n=r(n),i=r(i);var s,o;s=Math.floor(e/60%6),o=e/60-s;var u=[n,n*(1-t),n*(1-o*t),n*(1-(1-o)*t)],a=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(u[a[s][0]]*255,u[a[s][1]]*255,u[a[s][2]]*255,i)},hue:function(t){return new e.Dimension(Math.round(t.toHSL().h))},saturation:function(t){return new e.Dimension(Math.round(t.toHSL().s*100),"%")},lightness:function(t){return new e.Dimension(Math.round(t.toHSL().l*100),"%")},red:function(t){return new e.Dimension(t.rgb[0])},green:function(t){return new e.Dimension(t.rgb[1])},blue:function(t){return new e.Dimension(t.rgb[2])},alpha:function(t){return new e.Dimension(t.toHSL().a)},luma:function(t){return new e.Dimension(Math.round((.2126*(t.rgb[0]/255)+.7152*(t.rgb[1]/255)+.0722*(t.rgb[2]/255))*t.alpha*100),"%")},saturate:function(e,n){var r=e.toHSL();return r.s+=n.value/100,r.s=i(r.s),t(r)},desaturate:function(e,n){var r=e.toHSL();return r.s-=n.value/100,r.s=i(r.s),t(r)},lighten:function(e,n){var r=e.toHSL();return r.l+=n.value/100,r.l=i(r.l),t(r)},darken:function(e,n){var r=e.toHSL();return r.l-=n.value/100,r.l=i(r.l),t(r)},fadein:function(e,n){var r=e.toHSL();return r.a+=n.value/100,r.a=i(r.a),t(r)},fadeout:function(e,n){var r=e.toHSL();return r.a-=n.value/100,r.a=i(r.a),t(r)},fade:function(e,n){var r=e.toHSL();return r.a=n.value/100,r.a=i(r.a),t(r)},spin:function(e,n){var r=e.toHSL(),i=(r.h+n.value)%360;return r.h=i<0?360+i:i,t(r)},mix:function(t,n,r){r||(r=new e.Dimension(50));var i=r.value/100,s=i*2-1,o=t.toHSL().a-n.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[t.rgb[0]*u+n.rgb[0]*a,t.rgb[1]*u+n.rgb[1]*a,t.rgb[2]*u+n.rgb[2]*a],l=t.alpha*i+n.alpha*(1-i);return new e.Color(f,l)},greyscale:function(t){return this.desaturate(t,new e.Dimension(100))},contrast:function(e,t,n,r){return e.rgb?(typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1)),typeof r=="undefined"?r=.43:r=r.value,(.2126*(e.rgb[0]/255)+.7152*(e.rgb[1]/255)+.0722*(e.rgb[2]/255))*e.alpha255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},operate:function(t,n){var r=[];n instanceof e.Color||(n=n.toColor());for(var i=0;i<3;i++)r[i]=e.operate(t,this.rgb[i],n.rgb[i]);return new e.Color(r,this.alpha+n.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype.eval=function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}(n("../tree")),function(e){e.Dimension=function(e,t){this.value=parseFloat(e),this.unit=t||null},e.Dimension.prototype={eval:function(){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(){var e=this.value+this.unit;return e},operate:function(t,n){return new e.Dimension(e.operate(t,this.value,n.value),this.unit||n.unit)},compare:function(t){return t instanceof e.Dimension?t.value>this.value?-1:t.value":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={eval:function(t){return this.value.length>1?new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?this.value[0].eval(t):this},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")}}}(n("../tree")),function(e){e.Import=function(t,n,r,i,s,o){var u=this;this.once=i,this.index=s,this._path=t,this.features=r&&new e.Value(r),this.rootpath=o,t instanceof e.Quoted?this.path=/(\.[a-z]*$)|([\?;].*)$/.test(t.value)?t.value:t.value+".less":this.path=t.value.value||t.value,this.css=/css([\?;].*)?$/.test(this.path),this.css||n.push(this.path,function(t,n,r){t&&(t.index=s),r&&u.once&&(u.skip=r),u.root=n||new e.Ruleset([],[])})},e.Import.prototype={toCSS:function(e){var t=this.features?" "+this.features.toCSS(e):"";return this.css?(typeof this._path.value=="string"&&!/^(?:[a-z-]+:|\/)/.test(this._path.value)&&(this._path.value=this.rootpath+this._path.value),"@import "+this._path.toCSS()+t+";\n"):""},eval:function(t){var n,r=this.features&&this.features.eval(t);return this.skip?[]:this.css?this:(n=new e.Ruleset([],this.root.rules.slice(0)),n.evalImports(t),this.features?new e.Media(n.rules,this.features.value):n.rules)}}}(n("../tree")),function(e){e.JavaScript=function(e,t,n){this.escaped=n,this.expression=e,this.index=t},e.JavaScript.prototype={eval:function(t){var n,r=this,i={},s=this.expression.replace(/@\{([\w-]+)\}/g,function(n,i){return e.jsify((new e.Variable("@"+i,r.index)).eval(t))});try{s=new Function("return ("+s+")")}catch(o){throw{message:"JavaScript evaluation error: `"+s+"`",index:this.index}}for(var u in t.frames[0].variables())i[u.slice(1)]={value:t.frames[0].variables()[u].value,toJS:function(){return this.value.eval(t).toCSS()}};try{n=s.call(i)}catch(o){throw{message:"JavaScript evaluation error: '"+o.name+": "+o.message+"'",index:this.index}}return typeof n=="string"?new e.Quoted('"'+n+'"',n,this.escaped,this.index):Array.isArray(n)?new e.Anonymous(n.join(", ")):new e.Anonymous(n)}}}(n("../tree")),function(e){e.Keyword=function(e){this.value=e},e.Keyword.prototype={eval:function(){return this},toCSS:function(){return this.value},compare:function(t){return t instanceof e.Keyword?t.value===this.value?0:1:-1}},e.True=new e.Keyword("true"),e.False=new e.Keyword("false")}(n("../tree")),function(e){e.Media=function(t,n){var r=this.emptySelectors();this.features=new e.Value(n),this.ruleset=new e.Ruleset(r,t),this.ruleset.allowImports=!0},e.Media.prototype={toCSS:function(e,t){var n=this.features.toCSS(t);return this.ruleset.root=e.length===0||e[0].multiMedia,"@media "+n+(t.compress?"{":" {\n ")+this.ruleset.toCSS(e,t).trim().replace(/\n/g,"\n ")+(t.compress?"}":"\n}\n")},eval:function(t){t.mediaBlocks||(t.mediaBlocks=[],t.mediaPath=[]);var n=new e.Media([],[]);return this.debugInfo&&(this.ruleset.debugInfo=this.debugInfo,n.debugInfo=this.debugInfo),n.features=this.features.eval(t),t.mediaPath.push(n),t.mediaBlocks.push(n),t.frames.unshift(this.ruleset),n.ruleset=this.ruleset.eval(t),t.frames.shift(),t.mediaPath.pop(),t.mediaPath.length===0?n.evalTop(t):n.evalNested(t)},variable:function(t){return e.Ruleset.prototype.variable.call(this.ruleset,t)},find:function(){return e.Ruleset.prototype.find.apply(this.ruleset,arguments)},rulesets:function(){return e.Ruleset.prototype.rulesets.apply(this.ruleset)},emptySelectors:function(){var t=new e.Element("","&",0);return[new e.Selector([t])]},evalTop:function(t){var n=this;if(t.mediaBlocks.length>1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t,n){var r=[],i=[],s=[],o=[],u=[],a,f,l;this.root||this.joinSelectors(u,t,this.selectors);for(var c=0;c0){f=e.debugInfo(n,this),a=u.map(function(e){return e.map(function(e){return e.toCSS(n)}).join("").trim()}).join(n.compress?",":",\n");for(var c=i.length-1;c>=0;c--)s.indexOf(i[c])===-1&&s.unshift(i[c]);i=s,r.push(f+a+(n.compress?"{":" {\n ")+i.join(n.compress?"":"\n ")+(n.compress?"}":"\n}\n"))}return r.push(o),r.join("")+(n.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0)),v=!1):d=new e.Selector([]),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t)):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e){this.elements=e},e.Selector.prototype.match=function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=b(t.href,e.location.href),u=o.url,a=l&&l.getItem(u),f=l&&l.getItem(u+":timestamp"),c={css:a,timestamp:f},h,p={relativeUrls:r.relativeUrls,currentDirectory:o.path,filename:u};t instanceof r.tree.parseEnv?(h=new r.tree.parseEnv(t),p.entryPath=h.currentFileInfo.entryPath,p.rootpath=h.currentFileInfo.rootpath,p.rootFilename=h.currentFileInfo.rootFilename):(h=new r.tree.parseEnv(r),h.mime=t.type,p.entryPath=o.path,p.rootpath=r.rootpath||o.path,p.rootFilename=u),h.relativeUrls&&(r.rootpath?p.rootpath=b(r.rootpath+y(o.path,p.entryPath)).path:p.rootpath=o.path),x(u,t.type,function(e,a){v+=e.replace(/@import .+?;/ig,"");if(!i&&c&&a&&(new Date(a)).valueOf()===(new Date(c.timestamp)).valueOf())S(c.css,t),n(null,null,e,t,{local:!0,remaining:s},u);else try{h.contents[u]=e,h.paths=[o.path],h.currentFileInfo=p,(new r.Parser(h)).parse(e,function(r,i){if(r)return n(r,null,null,t);try{n(r,i,e,t,{local:!1,lastModified:a,remaining:s},u),h.currentFileInfo.rootFilename===u&&N(document.getElementById("less-error-message:"+E(u)))}catch(r){n(r,null,null,t)}})}catch(f){n(f,null,null,t)}},function(e,r){n({type:"File",message:"'"+r+"' wasn't found ("+e+")"},null,null,t)})}function E(e){return e.replace(/^[a-z-]+:\/+?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r=t.href||"",i="less:"+(t.title||E(r)),s=document.getElementById(i),o=!1,u=document.createElement("style");u.setAttribute("type","text/css"),t.media&&u.setAttribute("media",t.media),u.id=i;if(u.styleSheet)try{u.styleSheet.cssText=e}catch(a){throw new Error("Couldn't reassign styleSheet.cssText.")}else u.appendChild(document.createTextNode(e)),o=s!==null&&s.childNodes.length>0&&u.childNodes.length>0&&s.firstChild.nodeValue===u.firstChild.nodeValue;var f=document.getElementsByTagName("head")[0];if(s==null||o===!1){var c=t&&t.nextSibling||null;(c||document.getElementsByTagName("head")[0]).parentNode.insertBefore(u,c)}s&&o===!1&&f.removeChild(s);if(n&&l){C("saving "+r+" to cache.");try{l.setItem(r,e),l.setItem(r+":timestamp",n)}catch(a){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,n){var i="less-error-message:"+E(n||""),s='
"+(e.type||"Syntax")+"Error: "+(e.message||"There is an error in your .less file")+"
"+'
in '+c+" ";var h=function(e,n,r){e.extract[n]!=t&&f.push(s.replace(/\{line\}/,(parseInt(e.line)||0)+(n-1)).replace(/\{class\}/,r).replace(/\{content\}/,e.extract[n]))};e.extract?(h(e,0,""),h(e,1,"line"),h(e,2,""),a+="on line "+e.line+", column "+(e.column+1)+":
"+"
"+f.join("")+"
"):e.stack&&(a+=" "+e.stack.split("\n").slice(1).join(" ")),o.innerHTML=a,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),o.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(u=setInterval(function(){document.body&&(document.getElementById(i)?document.body.replaceChild(o,document.getElementById(i)):document.body.insertBefore(o,document.body.firstChild),clearInterval(u))},10))}var r,i,s;typeof environment=="object"&&{}.toString.call(environment)==="[object Environment]"?(typeof e=="undefined"?r={}:r=e.less={},i=r.tree={},r.mode="rhino"):typeof e=="undefined"?(r=exports,i=n("./tree"),r.mode="node"):(typeof e.less=="undefined"&&(e.less={}),r=e.less,i=e.less.tree={},r.mode="browser"),r.Parser=function(t){function m(){a=c[u],f=o,h=o}function g(){c[u]=a,o=f,h=o}function y(){o>h&&(c[u]=c[u].slice(o-h),h=o)}function b(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function w(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,y();else{y();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return E(r),typeof t=="string"?t:t.length===1?t[0]:t}function E(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function k(e,t,i){var s=i.currentFileInfo.filename;return r.mode!=="browser"&&r.mode!=="rhino"&&(s=n("path").resolve(s)),{lineNumber:C(e,t).line+1,fileName:s}}function L(e,t){var n=N(e,t),r=C(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.currentFileInfo.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&C(e.call,n).line+1,this.callExtract=o[C(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this;t instanceof i.parseEnv||(t=new i.parseEnv(t));var v=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n,i){var s=this;this.queue.push(e),r.Parser.importer(e,n,function(t,n,r){s.queue.splice(s.queue.indexOf(e),1);var o=r in s.files;s.files[r]=n,t&&!s.error&&(s.error=t),i(t,n,o)},t)}};return L.prototype=new Error,L.prototype.constructor=L,this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,p={imports:v,parse:function(e,a){var f,d,v,m,g,y,b=[],E,S=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.currentFileInfo.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(S)return a(new L(S,t));try{f=new i.Ruleset([],w(this.parsers.primary)),f.root=!0,f.firstRoot=!0}catch(x){return a(new L(x,t))}f.toCSS=function(e){var s,o,u;return function(s,o){s=s||{};var u,a=new i.evalEnv(s);typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),a.frames=[new i.Ruleset(null,o)]);try{var f=e.call(this,a);(new i.joinSelectorVisitor).run(f),(new i.processExtendsVisitor).run(f);var l=f.toCSS({compress:Boolean(s.compress),dumpLineNumbers:t.dumpLineNumbers,strictUnits:Boolean(s.strictUnits)})}catch(c){throw new L(c,t)}return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(l,s.maxLineLen):s.compress?l.replace(/(\s)+/g,"$1"):l}}(f.eval);if(o=0&&s.charAt(T)!=="\n";T--)N++;S={type:"Parse",message:"Unrecognised input",index:o,filename:t.currentFileInfo.filename,line:g,column:N,extract:[y[g-2],y[g-1],y[g]]}}var C=function(e){e=S||e||p.imports.error,e?(e instanceof L||(e=new L(e,t)),a(e)):a(null,f)};t.processImports!==!1?(new i.importVisitor(this.imports,C)).run(f):C()},parsers:{primary:function(){var e,t=[];while((e=w(this.extendRule)||w(this.mixin.definition)||w(this.rule)||w(this.ruleset)||w(this.mixin.call)||w(this.comment)||w(this.directive))||w(/^[\s\n]+/)||w(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(w(/^\/\/.*/),!0);if(e=w(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,n=o,r,u=o;s.charAt(n)==="~"&&(n++,r=!0);if(s.charAt(n)!=='"'&&s.charAt(n)!=="'")return;r&&w("~");if(e=w(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],r,u,t.currentFileInfo)},keyword:function(){var e;if(e=w(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=w(this.alpha);if(typeof s!="undefined")return s}w("("),r=w(this.entities.arguments);if(!w(")"))return;if(e)return new i.Call(e,r,a,t.currentFileInfo)},arguments:function(){var e=[],t;while(t=w(this.entities.assignment)||w(this.expression)){e.push(t);if(!w(","))break}return e},literal:function(){return w(this.entities.dimension)||w(this.entities.color)||w(this.entities.quoted)||w(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=w(/^\w+(?=\s?=)/i))&&w("=")&&(t=w(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!w(/^url\(/))return;return e=w(this.entities.quoted)||w(this.entities.variable)||w(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",S(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.currentFileInfo)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=w(/^@@?[\w-]+/)))return new i.Variable(e,n,t.currentFileInfo)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=w(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.currentFileInfo)},color:function(){var e;if(s.charAt(o)==="#"&&(e=w(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=w(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/))return new i.Dimension(e[1],e[2])},unicodeDescriptor:function(){var e;if(e=w(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&w("~");if(e=w(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=w(/^(@[\w-]+)\s*:/)))return e[1]},extend:function(e){var t,n,r=o,s,u=[];if(!w(e?/^&:extend\(/:/^:extend\(/))return;do{s=null,t=[];for(;;){s=w(/^(all)(?=\s*(\)|,))/);if(s)break;n=w(this.element);if(!n)break;t.push(n)}s=s&&s[1],u.push(new i.Extend(new i.Selector(t),s,r))}while(w(","));return S(/^\)/),e&&S(/^;/),u},extendRule:function(){return this.extend(!0)},mixin:{call:function(){var e=[],n,r,u,a,f,l=o,c=s.charAt(o),h=!1;if(c!=="."&&c!=="#")return;m();while(n=w(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=w(">");w("(")&&(u=this.mixin.args.call(this,!0).args,S(")")),u=u||[],w(this.important)&&(h=!0);if(e.length>0&&(w(";")||T("}")))return new i.mixin.Call(e,u,l,t.currentFileInfo,h);g()},args:function(e){var t=[],n=[],r,u=[],a,f,l,c,h,p={args:null,variadic:!1};for(;;){if(e)h=w(this.expression);else{w(this.comment);if(s.charAt(o)==="."&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({variadic:!0});break}h=w(this.entities.variable)||w(this.entities.literal)||w(this.entities.keyword)}if(!h)break;l=null,h.throwAwayComments&&h.throwAwayComments(),c=h;var d=null;if(e){if(h.value.length==1)var d=h.value[0]}else d=h;if(d&&d instanceof i.Variable)if(w(":"))t.length>0&&(r&&x("Cannot mix ; and , as delimiter types"),a=!0),c=S(this.expression),l=f=d.name;else{if(!e&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({name:h.name,variadic:!0});break}e||(f=l=d.name,c=null)}c&&t.push(c),u.push({name:l,value:c});if(w(","))continue;if(w(";")||r)a&&x("Cannot mix ; and , as delimiter types"),r=!0,t.length>1&&(c=new i.Value(t)),n.push({name:f,value:c}),f=null,t=[],a=!1}return p.args=r?n:u,p},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||T(/^[^{]*\}/))return;m();if(n=w(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];var h=this.mixin.args.call(this,!1);t=h.args,c=h.variadic,w(")")||(l=o,g()),w(this.comment),w(/^when/)&&(f=S(this.conditions,"expected condition")),r=w(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);g()}}},entity:function(){return w(this.entities.literal)||w(this.entities.variable)||w(this.entities.url)||w(this.entities.call)||w(this.entities.keyword)||w(this.entities.javascript)||w(this.comment)},end:function(){return w(";")||T("}")},alpha:function(){var e;if(!w(/^\(opacity=/i))return;if(e=w(/^\d+/)||w(this.entities.variable))return S(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=w(this.combinator),e=w(/^(?:\d+\.\d+|\d+)%/)||w(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||w("*")||w("&")||w(this.attribute)||w(/^\([^()@]+\)/)||w(/^[\.#](?=@)/)||w(this.entities.variableCurly),e||w("(")&&(r=w(this.selector))&&w(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e=s.charAt(o);if(e===">"||e==="+"||e==="~"||e==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(e)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u,a=[];while((u=w(this.extend))||(t=w(this.element))){u?a.push.apply(a,u):(a.length&&x("Extend can only be used at the end of selector"),r=s.charAt(o),n.push(t),t=null);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n,a);a.length&&x("Extend must be used to extend a selector, it cannot be used on its own")},attribute:function(){var e="",t,n,r;if(!w("["))return;(t=w(this.entities.variableCurly))||(t=S(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/));if(r=w(/^[|~*$^]?=/))n=w(this.entities.quoted)||w(/^[\w-]+/)||w(this.entities.variableCurly);return S("]"),new i.Attribute(t,r,n)},block:function(){var e;if(w("{")&&(e=w(this.primary))&&w("}"))return e},ruleset:function(){var e=[],n,r,u;m(),t.dumpLineNumbers&&(u=k(o,s,t));while(n=w(this.selector)){e.push(n),w(this.comment);if(!w(","))break;w(this.comment)}if(e.length>0&&(r=w(this.block))){var a=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(a.debugInfo=u),a}l=o,g()},rule:function(e){var n,r,u=s.charAt(o),a;m();if(u==="."||u==="#"||u==="&")return;if(n=w(this.variable)||w(this.property)){r=!e&&(t.compress||n.charAt(0)==="@")?w(this.value)||w(this.anonymousValue):w(this.anonymousValue)||w(this.value),a=w(this.important);if(r&&w(this.end))return new i.Rule(n,r,a,f,t.currentFileInfo);l=o,g();if(r&&!e)return this.rule(!0)}},anonymousValue:function(){var e;if(e=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))return o+=e[0].length-1,new i.Anonymous(e[1])},"import":function(){var e,n,r=o;m();var s=w(/^@import?\s+/),u=(s?w(this.importOptions):null)||{};if(s&&(e=w(this.entities.quoted)||w(this.entities.url))){n=w(this.mediaFeatures);if(w(";"))return n=n&&new i.Value(n),new i.Import(e,n,u,r,t.currentFileInfo)}g()},importOptions:function(){var e,t={},n,r;if(!w("("))return null;do if(e=w(this.importOption)){n=e,r=!0;switch(n){case"css":n="less",r=!1;break;case"once":n="multiple",r=!1}t[n]=r;if(!w(","))break}while(e);return S(")"),t},importOption:function(){var e=w(/^(less|css|multiple|once)/);if(e)return e[1]},mediaFeature:function(){var e,n,r=[];do if(e=w(this.entities.keyword))r.push(e);else if(w("(")){n=w(this.property),e=w(this.value);if(!w(")"))return null;if(n&&e)r.push(new i.Paren(new i.Rule(n,e,null,o,t.currentFileInfo,!0)));else{if(!e)return null;r.push(new i.Paren(e))}}while(e);if(r.length>0)return new i.Expression(r)},mediaFeatures:function(){var e,t=[];do if(e=w(this.mediaFeature)){t.push(e);if(!w(","))break}else if(e=w(this.entities.variable)){t.push(e);if(!w(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=k(o,s,t));if(w(/^@media/)){e=w(this.mediaFeatures);if(n=w(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=w(this["import"])||w(this.media))return n;m(),e=w(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(w(/^[^{]+/)||"").trim());if(c){if(r=w(this.block))return new i.Directive(e,r)}else if((n=p?w(this.expression):w(this.entity))&&w(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=k(o,s,t)),d}g()},value:function(){var e,t=[],n;while(e=w(this.expression)){t.push(e);if(!w(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return w(/^! *important/)},sub:function(){var e,t;if(w("("))if(e=w(this.addition))return t=new i.Expression([e]),S(")"),t.parens=!0,t},multiplication:function(){var e,t,n,r,u,a=[];if(e=w(this.operand)){u=b(s.charAt(o-1));while(!T(/^\/[*\/]/)&&(n=w("/")||w("*"))){if(!(t=w(this.operand)))break;e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1))}return r||e}},addition:function(){var e,t,n,r,u;if(e=w(this.multiplication)){u=b(s.charAt(o-1));while((n=w(/^[-+]\s+/)||!u&&(w("+")||w("-")))&&(t=w(this.multiplication)))e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1));return r||e}},conditions:function(){var e,t,n=o,r;if(e=w(this.condition)){while(w(",")&&(t=w(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;w(/^not/)&&(u=!0),S("(");if(e=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))return(r=w(/^(?:>=|=<|[<=>])/))?(t=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):x("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),S(")"),w(/^and/)?new i.Condition("and",n,w(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=w("-"));var n=w(this.sub)||w(this.entities.dimension)||w(this.entities.color)||w(this.entities.variable)||w(this.entities.call);return e&&(n.parensInOp=!0,n=new i.Negative(n)),n},expression:function(){var e,t,n=[],r;while(e=w(this.addition)||w(this.entity))n.push(e),!T(/^\/[\/*]/)&&(t=w("/"))&&n.push(new i.Anonymous(t));if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=w(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.currentDirectory&&(e=t.currentDirectory+e);var i=r.toSheet(e);i.processImports=!1,i.currentFileInfo=t,w(i,function(e,t,r,i,s,o){n.call(null,e,t,o)},!0)};(function(r){function u(e){return r.functions.hsla(e.h,e.s,e.l,e.a)}function a(e,t){return e instanceof r.Dimension&&e.unit.is("%")?parseFloat(e.value*t/100):f(e)}function f(e){if(e instanceof r.Dimension)return parseFloat(e.unit.is("%")?e.value/100:e.value);if(typeof e=="number")return e;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function l(e){return Math.min(1,Math.max(0,e))}r.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(e,t,n,i){var s=[e,t,n].map(function(e){return a(e,256)});return i=f(i),new r.Color(s,i)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,r){function o(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?s+(i-s)*e*6:e*2<1?i:e*3<2?s+(i-s)*(2/3-e)*6:s}e=f(e)%360/360,t=l(f(t)),n=l(f(n)),r=l(f(r));var i=n<=.5?n*(t+1):n+t-n*t,s=n*2-i;return this.rgba(o(e+1/3)*255,o(e)*255,o(e-1/3)*255,r)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,r){e=f(e)%360/360*360,t=f(t),n=f(n),r=f(r);var i,s;i=Math.floor(e/60%6),s=e/60-i;var o=[n,n*(1-t),n*(1-s*t),n*(1-(1-s)*t)],u=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(o[u[i][0]]*255,o[u[i][1]]*255,o[u[i][2]]*255,r)},hue:function(e){return new r.Dimension(Math.round(e.toHSL().h))},saturation:function(e){return new r.Dimension(Math.round(e.toHSL().s*100),"%")},lightness:function(e){return new r.Dimension(Math.round(e.toHSL().l*100),"%")},hsvhue:function(e){return new r.Dimension(Math.round(e.toHSV().h))},hsvsaturation:function(e){return new r.Dimension(Math.round(e.toHSV().s*100),"%")},hsvvalue:function(e){return new r.Dimension(Math.round(e.toHSV().v*100),"%")},red:function(e){return new r.Dimension(e.rgb[0])},green:function(e){return new r.Dimension(e.rgb[1])},blue:function(e){return new r.Dimension(e.rgb[2])},alpha:function(e){return new r.Dimension(e.toHSL().a)},luma:function(e){return new r.Dimension(Math.round(e.luma()*e.alpha*100),"%")},saturate:function(e,t){var n=e.toHSL();return n.s+=t.value/100,n.s=l(n.s),u(n)},desaturate:function(e,t){var n=e.toHSL();return n.s-=t.value/100,n.s=l(n.s),u(n)},lighten:function(e,t){var n=e.toHSL();return n.l+=t.value/100,n.l=l(n.l),u(n)},darken:function(e,t){var n=e.toHSL();return n.l-=t.value/100,n.l=l(n.l),u(n)},fadein:function(e,t){var n=e.toHSL();return n.a+=t.value/100,n.a=l(n.a),u(n)},fadeout:function(e,t){var n=e.toHSL();return n.a-=t.value/100,n.a=l(n.a),u(n)},fade:function(e,t){var n=e.toHSL();return n.a=t.value/100,n.a=l(n.a),u(n)},spin:function(e,t){var n=e.toHSL(),r=(n.h+t.value)%360;return n.h=r<0?360+r:r,u(n)},mix:function(e,t,n){n||(n=new r.Dimension(50));var i=n.value/100,s=i*2-1,o=e.toHSL().a-t.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[e.rgb[0]*u+t.rgb[0]*a,e.rgb[1]*u+t.rgb[1]*a,e.rgb[2]*u+t.rgb[2]*a],l=e.alpha*i+t.alpha*(1-i);return new r.Color(f,l)},greyscale:function(e){return this.desaturate(e,new r.Dimension(100))},contrast:function(e,t,n,r){if(!e.rgb)return null;typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1));if(t.luma()>n.luma()){var i=n;n=t,t=i}return typeof r=="undefined"?r=.43:r=f(r),e.luma()*e.alpha=d){if(this.env.ieCompat!==!1)return this.env.silent||console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!",o,v,d),(new r.URL(i||t,this.currentFileInfo)).eval(this.env);this.env.silent||console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!",o,v,d)}p=f?p.toString("base64"):encodeURIComponent(p);var m="'data:"+s+","+p+"'";return new r.URL(new r.Anonymous(m))}},r._mime={_types:{".htm":"text/html",".html":"text/html",".gif":"image/gif",".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png"},lookup:function(e){var i=n("path").extname(e),s=r._mime._types[i];if(s===t)throw new Error('Optional dependency "mime" is required for '+i);return s},charsets:{lookup:function(e){return e&&/^text\//.test(e)?"UTF-8":""}}};var i=[{name:"ceil"},{name:"floor"},{name:"sqrt"},{name:"abs"},{name:"tan",unit:""},{name:"sin",unit:""},{name:"cos",unit:""},{name:"atan",unit:"rad"},{name:"asin",unit:"rad"},{name:"acos",unit:"rad"}],s=function(e,t){return function(n){return t!=null&&(n=n.unify()),this._math(Math[e],t,n)}};for(var o=0;o255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("");return n&&(r=r.split(""),r[0]==r[1]&&r[2]==r[3]&&r[4]==r[5]?r=r[0]+r[2]+r[4]:r=r.join("")),"#"+r},operate:function(t,n,r){var i=[];r instanceof e.Color||(r=r.toColor());for(var s=0;s<3;s++)i[s]=e.operate(t,n,this.rgb[s],r.rgb[s]);return new e.Color(i,this.alpha+r.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={type:"Comment",toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype={type:"Condition",accept:function(e){this.lvalue=e.visit(this.lvalue),this.rvalue=e.visit(this.rvalue)},eval:function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}}(n("../tree")),function(e){e.Dimension=function(n,r){this.value=parseFloat(n),this.unit=r&&r instanceof e.Unit?r:new e.Unit(r?[r]:t)},e.Dimension.prototype={type:"Dimension",accept:function(e){this.unit=e.visit(this.unit)},eval:function(e){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(e){if(e&&e.strictUnits&&!this.unit.isSingular())throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());var t=this.value,n=String(t);t!==0&&t<1e-6&&t>-0.000001&&(n=t.toFixed(20).replace(/0+$/,""));if(e&&e.compress){if(t===0&&!this.unit.isAngle())return n;t>0&&t<1&&(n=n.substr(1))}return n+this.unit.toCSS(e)},operate:function(t,n,r){var i=e.operate(t,n,this.value,r.value),s=this.unit.clone();if(n==="+"||n==="-"){if(s.numerator.length===0&&s.denominator.length===0)s.numerator=r.unit.numerator.slice(0),s.denominator=r.unit.denominator.slice(0);else if(r.unit.numerator.length!=0||s.denominator.length!=0){r=r.convertTo(this.unit.usedUnits());if(t.strictUnits&&r.unit.toString()!==s.toString())throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"+s.toString()+"' and '"+r.unit.toString()+"'.");i=e.operate(t,n,this.value,r.value)}}else n==="*"?(s.numerator=s.numerator.concat(r.unit.numerator).sort(),s.denominator=s.denominator.concat(r.unit.denominator).sort(),s.cancel()):n==="/"&&(s.numerator=s.numerator.concat(r.unit.denominator).sort(),s.denominator=s.denominator.concat(r.unit.numerator).sort(),s.cancel());return new e.Dimension(i,s)},compare:function(t){if(t instanceof e.Dimension){var n=this.unify(),r=t.unify(),i=n.value,s=r.value;return s>i?-1:s=1?this.numerator[0]:this.denominator.length>=1?this.denominator[0]:(!e||!e.strictUnits)&&this.backupUnit?this.backupUnit:""},toString:function(){var e,t=this.numerator.join("*");for(e=0;e0)for(n=0;n":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={type:"Expression",accept:function(e){this.value=e.visit(this.value)},eval:function(t){var n,r=this.parens&&!this.parensInOp,i=!1;return r&&t.inParenthesis(),this.value.length>1?n=new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?(this.value[0].parens&&!this.value[0].parensInOp&&(i=!0),n=this.value[0].eval(t)):n=this,r&&t.outOfParenthesis(),this.parens&&this.parensInOp&&!t.isMathOn()&&!i&&(n=new e.Paren(n)),n},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")},throwAwayComments:function(){this.value=this.value.filter(function(t){return!(t instanceof e.Comment)})}}}(n("../tree")),function(e){e.Extend=function(t,n,r){this.selector=t,this.option=n,this.index=r;switch(n){case"all":this.allowBefore=!0,this.allowAfter=!0;break;default:this.allowBefore=!1,this.allowAfter=!1}},e.Extend.prototype={type:"Extend",accept:function(e){this.selector=e.visit(this.selector)},eval:function(t){return new e.Extend(this.selector.eval(t),this.option,this.index)},clone:function(t){return new e.Extend(this.selector,this.option,this.index)},findSelfSelectors:function(e){var t=[],n;for(n=0;n1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t){var n=[],r=[],i=[],s=[],o,u,a;for(var f=0;f0){u=e.debugInfo(t,this),o=this.paths.map(function(e){return e.map(function(e){return e.toCSS(t)}).join("").trim()}).join(t.compress?",":",\n");for(var f=r.length-1;f>=0;f--)(r[f].slice(0,2)==="/*"||i.indexOf(r[f])===-1)&&i.unshift(r[f]);r=i,n.push(u+o+(t.compress?"{":" {\n ")+r.join(t.compress?"":"\n ")+(t.compress?"}":"\n}\n"))}return n.push(s),n.join("")+(t.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0),r.extendList),v=!1):d=new e.Selector([],r.extendList),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0&&t.push(a[i])},mergeElementsOnToSelectors:function(t,n){var r,i,s;if(n.length==0){n.push([new e.Selector(t)]);return}for(r=0;r0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t),i[i.length-1].extendList):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e,t){this.elements=e,this.extendList=t||[]},e.Selector.prototype={type:"Selector",accept:function(e){this.elements=e.visit(this.elements),this.extendList=e.visit(this.extendList)},match:function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree")),function(e){var t=["paths","optimization","files","contents","relativeUrls","strictImports","dumpLineNumbers","compress","processImports","syncImport","mime","currentFileInfo"];e.parseEnv=function(e){r(e,this,t),this.contents||(this.contents={}),this.files||(this.files={});if(!this.currentFileInfo){var n=e&&e.filename||"input",i=n.replace(/[^\/\\]*$/,"");e&&(e.filename=null),this.currentFileInfo={filename:n,relativeUrls:this.relativeUrls,rootpath:e&&e.rootpath||"",currentDirectory:i,entryPath:i,rootFilename:n}}},e.parseEnv.prototype.toSheet=function(t){var n=new e.parseEnv(this);return n.href=t,n.type=this.mime,n};var n=["silent","verbose","compress","yuicompress","ieCompat","strictMath","strictUnits"];e.evalEnv=function(e,t){r(e,this,n),this.frames=t||[]},e.evalEnv.prototype.inParenthesis=function(){this.parensStack||(this.parensStack=[]),this.parensStack.push(!0)},e.evalEnv.prototype.outOfParenthesis=function(){this.parensStack.pop()},e.evalEnv.prototype.isMathOn=function(){return this.strictMath?this.parensStack&&this.parensStack.length:!0},e.evalEnv.prototype.isPathRelative=function(e){return!/^(?:[a-z-]+:|\/)/.test(e)};var r=function(e,t,n){if(!e)return;for(var r=0;r100){var d="{unable to calculate}",v="{unable to calculate}";try{d=u[0].selfSelectors[0].toCSS(),v=u[0].selector.toCSS()}catch(m){}throw{message:"extend circular reference detected. One of the circular extends is currently:"+d+":extend("+v+")"}}return u.concat(f.doExtendChaining(u,n,r+1))}return u},inInheritanceChain:function(e,t){if(e===t)return!0;if(t.parents){if(this.inInheritanceChain(e,t.parents[0]))return!0;if(this.inInheritanceChain(e,t.parents[1]))return!0}return!1},visitRule:function(e,t){t.visitDeeper=!1},visitMixinDefinition:function(e,t){t.visitDeeper=!1},visitSelector:function(e,t){t.visitDeeper=!1},visitRuleset:function(e,t){if(e.root)return;var n,r,i,s=this.allExtendsStack[this.allExtendsStack.length-1],o=[],u=this,a;for(i=0;i0&&f[c.matched].combinator.value!==o?c=null:c.matched++,c&&(c.finished=c.matched===f.length,c.finished&&!e.allowAfter&&(i+1i&&s>0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,l.pathIndex)),o.push(new e.Selector(a.elements.slice(s,l.index).concat([f]).concat(r.elements.slice(1)))),i=l.endPathIndex,s=l.endPathElementIndex,s>=a.elements.length&&(s=0,i++);return i0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,n.length)),o},visitRulesetOut:function(e){},visitMedia:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitMediaOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1},visitDirective:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitDirectiveOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1}}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d
Date: Fri, 16 Aug 2013 18:00:51 +0100
Subject: [PATCH 38/72] support for lesscss 1.4.1
---
CHANGELOG.md | 9 +++++++++
pom.xml | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)
create mode 100644 CHANGELOG.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..e3e2579
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,9 @@
+
+# 1.4.1
+
+ - support for lesscss 1.4.1
+
+ # 1.3.3
+
+ - support for lesscss 1.3.3
+ - fixed #22 singe and double quotes import issue
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index f14ab4c..947be7f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0org.lesscsslesscss
- 1.3.3.1-SNAPSHOT
+ 1.4.1-SNAPSHOTjarOfficial LESS CSS Compiler for JavaOfficial LESS CSS Compiler for Java
From 34d604ce73c833c3d81ecdb4d2d05258de97eded Mon Sep 17 00:00:00 2001
From: Charlie Hubbard
Date: Sun, 15 Dec 2013 22:43:50 -0500
Subject: [PATCH 39/72] Added some helper methods for logging with args.
---
.../logging/JULILessLoggerProvider.java | 16 ++++++++++++++++
.../java/org/lesscss/logging/LessLogger.java | 7 +++++++
.../logging/SLF4JLessLoggerProvider.java | 19 +++++++++++++++++++
3 files changed, 42 insertions(+)
diff --git a/src/main/java/org/lesscss/logging/JULILessLoggerProvider.java b/src/main/java/org/lesscss/logging/JULILessLoggerProvider.java
index 77eb184..4b78793 100644
--- a/src/main/java/org/lesscss/logging/JULILessLoggerProvider.java
+++ b/src/main/java/org/lesscss/logging/JULILessLoggerProvider.java
@@ -27,12 +27,28 @@ public void debug(String msg) {
logger.fine(msg);
}
+ public void debug(String format, Object... args) {
+ if( isDebugEnabled() ) {
+ logger.fine( String.format(format, args) );
+ }
+ }
+
public void info(String msg) {
logger.info(msg);
}
+ public void info(String format, Object... args) {
+ if( isInfoEnabled() ) {
+ logger.info(String.format(format,args));
+ }
+ }
+
public void error(String msg, Throwable t) {
logger.log(Level.SEVERE, msg, t);
}
+
+ public void error(String format, Object... args) {
+ logger.severe(String.format(format,args));
+ }
}
}
diff --git a/src/main/java/org/lesscss/logging/LessLogger.java b/src/main/java/org/lesscss/logging/LessLogger.java
index f02bfc1..9abe7ce 100644
--- a/src/main/java/org/lesscss/logging/LessLogger.java
+++ b/src/main/java/org/lesscss/logging/LessLogger.java
@@ -7,7 +7,14 @@ public interface LessLogger {
void debug(String msg);
+ void debug(String format, Object... args);
+
void info(String msg);
+ void info(String format, Object... args);
+
void error(String msg, Throwable t);
+
+ void error(String format, Object... args);
+
}
diff --git a/src/main/java/org/lesscss/logging/SLF4JLessLoggerProvider.java b/src/main/java/org/lesscss/logging/SLF4JLessLoggerProvider.java
index 3c43177..4cc2a25 100644
--- a/src/main/java/org/lesscss/logging/SLF4JLessLoggerProvider.java
+++ b/src/main/java/org/lesscss/logging/SLF4JLessLoggerProvider.java
@@ -24,12 +24,31 @@ public void debug(String msg) {
logger.debug(msg);
}
+ public void debug(String format, Object... args) {
+ if( logger.isDebugEnabled() ) {
+ logger.debug(String.format(format, args));
+ }
+ }
+
public void info(String msg) {
logger.info(msg);
}
+ public void info(String format, Object... args) {
+ if( logger.isInfoEnabled() ) {
+ logger.info( String.format(format, args) );
+ }
+ }
+
public void error(String msg, Throwable t) {
logger.error(msg, t);
}
+
+ public void error(String format, Object... args) {
+ if( logger.isErrorEnabled() ) {
+ logger.error( String.format(format, args) );
+ }
+ }
+
}
}
From 0bce5d4be102e6488dddf784f518e6bbb4803e77 Mon Sep 17 00:00:00 2001
From: Charlie Hubbard
Date: Sun, 15 Dec 2013 22:53:55 -0500
Subject: [PATCH 40/72] Added support for Resource names for easier debugging.
---
src/main/java/org/lesscss/FileResource.java | 9 +++++++++
src/main/java/org/lesscss/Resource.java | 7 +++++++
2 files changed, 16 insertions(+)
diff --git a/src/main/java/org/lesscss/FileResource.java b/src/main/java/org/lesscss/FileResource.java
index 0facfef..5de1ce1 100644
--- a/src/main/java/org/lesscss/FileResource.java
+++ b/src/main/java/org/lesscss/FileResource.java
@@ -37,4 +37,13 @@ public Resource createRelative(String relativePath) {
File relativeFile = new File(file.getParentFile(), relativePath);
return new FileResource(relativeFile);
}
+
+ @Override
+ public String toString() {
+ return file.getAbsolutePath();
+ }
+
+ public String getName() {
+ return file.getAbsolutePath();
+ }
}
diff --git a/src/main/java/org/lesscss/Resource.java b/src/main/java/org/lesscss/Resource.java
index e04a173..7d6ca51 100644
--- a/src/main/java/org/lesscss/Resource.java
+++ b/src/main/java/org/lesscss/Resource.java
@@ -42,4 +42,11 @@ public interface Resource {
* @return Resource relative resource
*/
Resource createRelative(String relativeResourcePath);
+
+ /**
+ * Returns a unique name for this resource. (ie file name for files)
+ *
+ * @return the name of the resource
+ */
+ String getName();
}
From b7ffbd20ca1348949d8bd37a7b0fd4523a64ed8f Mon Sep 17 00:00:00 2001
From: Charlie Hubbard
Date: Sun, 15 Dec 2013 22:54:32 -0500
Subject: [PATCH 41/72] Added support for better error messages by pulling out
all information provided by less script, externalized doIt -> lessc.js for
easier editing and fixing error handling.
---
src/main/java/org/lesscss/LessCompiler.java | 79 +++++++++++++++------
1 file changed, 58 insertions(+), 21 deletions(-)
diff --git a/src/main/java/org/lesscss/LessCompiler.java b/src/main/java/org/lesscss/LessCompiler.java
index a966327..de8d59c 100644
--- a/src/main/java/org/lesscss/LessCompiler.java
+++ b/src/main/java/org/lesscss/LessCompiler.java
@@ -58,18 +58,15 @@
*/
public class LessCompiler {
- private static final String COMPILE_STRING = "function doIt(input, compress) { var result; var parser = new less.Parser(); parser.parse(input, function(e, tree) { if (e instanceof Object) { throw e; } ; result = tree.toCSS({compress: compress}); }); return result; }";
-
private static final LessLogger logger = LessLoggerFactory.getLogger(LessCompiler.class);
private URL envJs = LessCompiler.class.getClassLoader().getResource("META-INF/env.rhino.js");
- private URL lessJs = LessCompiler.class.getClassLoader().getResource("META-INF/less.js");
+ private URL lessJs = LessCompiler.class.getClassLoader().getResource("META-INF/less-1.5.1.js");
+ private URL lesscJs = LessCompiler.class.getClassLoader().getResource("META-INF/lessc.js");
private List customJs = Collections.emptyList();
private boolean compress = false;
private String encoding = null;
- private Function doIt;
-
private Scriptable scope;
/**
@@ -214,7 +211,7 @@ public synchronized void init() {
try {
Context cx = Context.enter();
- cx.setOptimizationLevel(-1);
+ cx.setOptimizationLevel(-1);
cx.setLanguageVersion(Context.VERSION_1_7);
Global global = new Global();
@@ -223,12 +220,13 @@ public synchronized void init() {
scope = cx.initStandardObjects(global);
scope.put("logger", scope, Context.toObject(logger, scope));
- List jsUrls = new ArrayList(2 + customJs.size());
- jsUrls.add(envJs);
- jsUrls.add(lessJs);
- jsUrls.addAll(customJs);
-
- for(URL url : jsUrls){
+ List jsUrls = new ArrayList();
+ jsUrls.add(envJs);
+ jsUrls.add(lessJs);
+ jsUrls.add(lesscJs);
+ jsUrls.addAll( customJs );
+
+ for(URL url : jsUrls) {
InputStreamReader inputStreamReader = new InputStreamReader(url.openConnection().getInputStream());
try{
cx.evaluateReader(scope, inputStreamReader, url.toString(), 1, null);
@@ -236,7 +234,6 @@ public synchronized void init() {
inputStreamReader.close();
}
}
- doIt = cx.compileFunction(scope, COMPILE_STRING, "doIt.js", 1, null);
}
catch (Exception e) {
String message = "Failed to initialize LESS compiler.";
@@ -247,7 +244,7 @@ public synchronized void init() {
}
if (logger.isDebugEnabled()) {
- logger.debug("Finished initialization of LESS compiler in " + (System.currentTimeMillis() - start) + " ms.");
+ logger.debug("Finished initialization of LESS compiler in %,d ms.%n", System.currentTimeMillis() - start);
}
}
@@ -258,6 +255,19 @@ public synchronized void init() {
* @return The CSS.
*/
public String compile(String input) throws LessException {
+ return compile( input, "");
+ }
+
+ /**
+ * Compiles the LESS input String to CSS, but specifies the source name String.
+ *
+ * @param input The LESS input String to compile
+ * @param name The source's name String to provide better error messages.
+ * @return the CSS.
+ *
+ * @throws LessException any error encountered by the compiler
+ */
+ public String compile(String input, String name) throws LessException {
synchronized(this){
if (scope == null) {
init();
@@ -268,10 +278,10 @@ public String compile(String input) throws LessException {
try {
Context cx = Context.enter();
- Object result = doIt.call(cx, scope, null, new Object[]{input, compress});
-
+ Function lessc = (Function)scope.get("lessc", scope);
+ Object result = lessc.call( cx, scope, null, new Object[] {name, input, compress});
if (logger.isDebugEnabled()) {
- logger.debug("Finished compilation of LESS source in " + (System.currentTimeMillis() - start) + " ms.");
+ logger.debug("Finished compilation of LESS source in %,d ms.", System.currentTimeMillis() - start );
}
return result.toString();
@@ -279,9 +289,36 @@ public String compile(String input) throws LessException {
catch (Exception e) {
if (e instanceof JavaScriptException) {
Scriptable value = (Scriptable)((JavaScriptException)e).getValue();
- if (value != null && ScriptableObject.hasProperty(value, "message")) {
- String message = ScriptableObject.getProperty(value, "message").toString();
- throw new LessException(message, e);
+ if (value != null ) {
+ StringBuilder message = new StringBuilder();
+ if( ScriptableObject.hasProperty(value, "filename") ) {
+ message.append( ScriptableObject.getProperty(value, "filename").toString() );
+ }
+
+ if( ScriptableObject.hasProperty(value, "line") ) {
+ message.append( "@(" );
+ message.append( ScriptableObject.getProperty(value, "line").toString() );
+ message.append( "," );
+ message.append( ScriptableObject.getProperty(value, "column").toString() );
+ message.append( ")" );
+ }
+
+ if( ScriptableObject.hasProperty(value, "message") ) {
+ if( message.length() > 0 ) message.append(": ");
+ message.append( ScriptableObject.getProperty(value, "message").toString() );
+ }
+
+ if( ScriptableObject.hasProperty(value, "extract") ) {
+ List lines = (List) ScriptableObject.getProperty(value, "extract");
+ for( String line : lines ) {
+ if( line != null ) {
+ message.append("\n");
+ message.append( line );
+ }
+ }
+ }
+
+ throw new LessException(message.toString(), e);
}
}
throw new LessException(e);
@@ -333,7 +370,7 @@ public void compile(File input, File output, boolean force) throws IOException,
* @return The CSS.
*/
public String compile(LessSource input) throws LessException {
- return compile(input.getNormalizedContent());
+ return compile(input.getNormalizedContent(), input.getName());
}
/**
From 50cb26cc10065139c407296bc2fe3c8d14d28288 Mon Sep 17 00:00:00 2001
From: Charlie Hubbard
Date: Sun, 15 Dec 2013 22:55:23 -0500
Subject: [PATCH 42/72] Added support for better error messages by pulling out
all information provided by less script, externalized doIt -> lessc.js for
easier editing and fixing error handling.
---
src/main/resources/META-INF/less-1.5.1.js | 6941 +++++++++++++++++++++
src/main/resources/META-INF/lessc.js | 12 +
2 files changed, 6953 insertions(+)
create mode 100644 src/main/resources/META-INF/less-1.5.1.js
create mode 100644 src/main/resources/META-INF/lessc.js
diff --git a/src/main/resources/META-INF/less-1.5.1.js b/src/main/resources/META-INF/less-1.5.1.js
new file mode 100644
index 0000000..dfff28a
--- /dev/null
+++ b/src/main/resources/META-INF/less-1.5.1.js
@@ -0,0 +1,6941 @@
+/*!
+ * LESS - Leaner CSS v1.5.1
+ * http://lesscss.org
+ *
+ * Copyright (c) 2009-2013, Alexis Sellier
+ * Licensed under the Apache v2 License.
+ *
+ * @licence
+ */
+
+
+
+(function (window, undefined) {//
+// Stub out `require` in the browser
+//
+function require(arg) {
+ return window.less[arg.split('/')[1]];
+};
+
+
+if (typeof(window.less) === 'undefined' || typeof(window.less.nodeType) !== 'undefined') { window.less = {}; }
+less = window.less;
+tree = window.less.tree = {};
+less.mode = 'browser';
+
+var less, tree;
+
+// Node.js does not have a header file added which defines less
+if (less === undefined) {
+ less = exports;
+ tree = require('./tree');
+ less.mode = 'node';
+}
+//
+// less.js - parser
+//
+// A relatively straight-forward predictive parser.
+// There is no tokenization/lexing stage, the input is parsed
+// in one sweep.
+//
+// To make the parser fast enough to run in the browser, several
+// optimization had to be made:
+//
+// - Matching and slicing on a huge input is often cause of slowdowns.
+// The solution is to chunkify the input into smaller strings.
+// The chunks are stored in the `chunks` var,
+// `j` holds the current chunk index, and `current` holds
+// the index of the current chunk in relation to `input`.
+// This gives us an almost 4x speed-up.
+//
+// - In many cases, we don't need to match individual tokens;
+// for example, if a value doesn't hold any variables, operations
+// or dynamic references, the parser can effectively 'skip' it,
+// treating it as a literal.
+// An example would be '1px solid #000' - which evaluates to itself,
+// we don't need to know what the individual components are.
+// The drawback, of course is that you don't get the benefits of
+// syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
+// and a smaller speed-up in the code-gen.
+//
+//
+// Token matching is done with the `$` function, which either takes
+// a terminal string or regexp, or a non-terminal function to call.
+// It also takes care of moving all the indices forwards.
+//
+//
+less.Parser = function Parser(env) {
+ var input, // LeSS input string
+ i, // current index in `input`
+ j, // current chunk
+ temp, // temporarily holds a chunk's state, for backtracking
+ memo, // temporarily holds `i`, when backtracking
+ furthest, // furthest index the parser has gone to
+ chunks, // chunkified input
+ current, // index of current chunk, in `input`
+ parser,
+ rootFilename = env && env.filename;
+
+ // Top parser on an import tree must be sure there is one "env"
+ // which will then be passed around by reference.
+ if (!(env instanceof tree.parseEnv)) {
+ env = new tree.parseEnv(env);
+ }
+
+ var imports = this.imports = {
+ paths: env.paths || [], // Search paths, when importing
+ queue: [], // Files which haven't been imported yet
+ files: env.files, // Holds the imported parse trees
+ contents: env.contents, // Holds the imported file contents
+ mime: env.mime, // MIME type of .less files
+ error: null, // Error in parsing/evaluating an import
+ push: function (path, currentFileInfo, importOptions, callback) {
+ var parserImports = this;
+ this.queue.push(path);
+
+ var fileParsedFunc = function (e, root, fullPath) {
+ parserImports.queue.splice(parserImports.queue.indexOf(path), 1); // Remove the path from the queue
+
+ var importedPreviously = fullPath in parserImports.files || fullPath === rootFilename;
+
+ parserImports.files[fullPath] = root; // Store the root
+
+ if (e && !parserImports.error) { parserImports.error = e; }
+
+ callback(e, root, importedPreviously, fullPath);
+ };
+
+ if (less.Parser.importer) {
+ less.Parser.importer(path, currentFileInfo, fileParsedFunc, env);
+ } else {
+ less.Parser.fileLoader(path, currentFileInfo, function(e, contents, fullPath, newFileInfo) {
+ if (e) {fileParsedFunc(e); return;}
+
+ var newEnv = new tree.parseEnv(env);
+
+ newEnv.currentFileInfo = newFileInfo;
+ newEnv.processImports = false;
+ newEnv.contents[fullPath] = contents;
+
+ if (currentFileInfo.reference || importOptions.reference) {
+ newFileInfo.reference = true;
+ }
+
+ if (importOptions.inline) {
+ fileParsedFunc(null, contents, fullPath);
+ } else {
+ new(less.Parser)(newEnv).parse(contents, function (e, root) {
+ fileParsedFunc(e, root, fullPath);
+ });
+ }
+ }, env);
+ }
+ }
+ };
+
+ function save() { temp = chunks[j], memo = i, current = i; }
+ function restore() { chunks[j] = temp, i = memo, current = i; }
+
+ function sync() {
+ if (i > current) {
+ chunks[j] = chunks[j].slice(i - current);
+ current = i;
+ }
+ }
+ function isWhitespace(c) {
+ // Could change to \s?
+ var code = c.charCodeAt(0);
+ return code === 32 || code === 10 || code === 9;
+ }
+ //
+ // Parse from a token, regexp or string, and move forward if match
+ //
+ function $(tok) {
+ var match, length;
+
+ //
+ // Non-terminal
+ //
+ if (tok instanceof Function) {
+ return tok.call(parser.parsers);
+ //
+ // Terminal
+ //
+ // Either match a single character in the input,
+ // or match a regexp in the current chunk (chunk[j]).
+ //
+ } else if (typeof(tok) === 'string') {
+ match = input.charAt(i) === tok ? tok : null;
+ length = 1;
+ sync ();
+ } else {
+ sync ();
+
+ if (match = tok.exec(chunks[j])) {
+ length = match[0].length;
+ } else {
+ return null;
+ }
+ }
+
+ // The match is confirmed, add the match length to `i`,
+ // and consume any extra white-space characters (' ' || '\n')
+ // which come after that. The reason for this is that LeSS's
+ // grammar is mostly white-space insensitive.
+ //
+ if (match) {
+ skipWhitespace(length);
+
+ if(typeof(match) === 'string') {
+ return match;
+ } else {
+ return match.length === 1 ? match[0] : match;
+ }
+ }
+ }
+
+ function skipWhitespace(length) {
+ var oldi = i, oldj = j,
+ endIndex = i + chunks[j].length,
+ mem = i += length;
+
+ while (i < endIndex) {
+ if (! isWhitespace(input.charAt(i))) { break; }
+ i++;
+ }
+ chunks[j] = chunks[j].slice(length + (i - mem));
+ current = i;
+
+ if (chunks[j].length === 0 && j < chunks.length - 1) { j++; }
+
+ return oldi !== i || oldj !== j;
+ }
+
+ function expect(arg, msg) {
+ var result = $(arg);
+ if (! result) {
+ error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
+ : "unexpected token"));
+ } else {
+ return result;
+ }
+ }
+
+ function error(msg, type) {
+ var e = new Error(msg);
+ e.index = i;
+ e.type = type || 'Syntax';
+ throw e;
+ }
+
+ // Same as $(), but don't change the state of the parser,
+ // just return the match.
+ function peek(tok) {
+ if (typeof(tok) === 'string') {
+ return input.charAt(i) === tok;
+ } else {
+ return tok.test(chunks[j]);
+ }
+ }
+
+ function getInput(e, env) {
+ if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) {
+ return parser.imports.contents[e.filename];
+ } else {
+ return input;
+ }
+ }
+
+ function getLocation(index, inputStream) {
+ var n = index + 1,
+ line = null,
+ column = -1;
+
+ while (--n >= 0 && inputStream.charAt(n) !== '\n') {
+ column++;
+ }
+
+ if (typeof index === 'number') {
+ line = (inputStream.slice(0, index).match(/\n/g) || "").length;
+ }
+
+ return {
+ line: line,
+ column: column
+ };
+ }
+
+ function getDebugInfo(index, inputStream, env) {
+ var filename = env.currentFileInfo.filename;
+ if(less.mode !== 'browser' && less.mode !== 'rhino') {
+ filename = require('path').resolve(filename);
+ }
+
+ return {
+ lineNumber: getLocation(index, inputStream).line + 1,
+ fileName: filename
+ };
+ }
+
+ function LessError(e, env) {
+ var input = getInput(e, env),
+ loc = getLocation(e.index, input),
+ line = loc.line,
+ col = loc.column,
+ callLine = e.call && getLocation(e.call, input).line,
+ lines = input.split('\n');
+
+ this.type = e.type || 'Syntax';
+ this.message = e.message;
+ this.filename = e.filename || env.currentFileInfo.filename;
+ this.index = e.index;
+ this.line = typeof(line) === 'number' ? line + 1 : null;
+ this.callLine = callLine + 1;
+ this.callExtract = lines[callLine];
+ this.stack = e.stack;
+ this.column = col;
+ this.extract = [
+ lines[line - 1],
+ lines[line],
+ lines[line + 1]
+ ];
+ }
+
+ LessError.prototype = new Error();
+ LessError.prototype.constructor = LessError;
+
+ this.env = env = env || {};
+
+ // The optimization level dictates the thoroughness of the parser,
+ // the lower the number, the less nodes it will create in the tree.
+ // This could matter for debugging, or if you want to access
+ // the individual nodes in the tree.
+ this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
+
+ //
+ // The Parser
+ //
+ return parser = {
+
+ imports: imports,
+ //
+ // Parse an input string into an abstract syntax tree,
+ // call `callback` when done.
+ //
+ parse: function (str, callback) {
+ var root, line, lines, error = null;
+
+ i = j = current = furthest = 0;
+ input = str.replace(/\r\n/g, '\n');
+
+ // Remove potential UTF Byte Order Mark
+ input = input.replace(/^\uFEFF/, '');
+
+ parser.imports.contents[env.currentFileInfo.filename] = input;
+
+ // Split the input into chunks.
+ chunks = (function (chunks) {
+ var j = 0,
+ skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,
+ comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
+ string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,
+ level = 0,
+ match,
+ chunk = chunks[0],
+ inParam;
+
+ for (var i = 0, c, cc; i < input.length;) {
+ skip.lastIndex = i;
+ if (match = skip.exec(input)) {
+ if (match.index === i) {
+ i += match[0].length;
+ chunk.push(match[0]);
+ }
+ }
+ c = input.charAt(i);
+ comment.lastIndex = string.lastIndex = i;
+
+ if (match = string.exec(input)) {
+ if (match.index === i) {
+ i += match[0].length;
+ chunk.push(match[0]);
+ continue;
+ }
+ }
+
+ if (!inParam && c === '/') {
+ cc = input.charAt(i + 1);
+ if (cc === '/' || cc === '*') {
+ if (match = comment.exec(input)) {
+ if (match.index === i) {
+ i += match[0].length;
+ chunk.push(match[0]);
+ continue;
+ }
+ }
+ }
+ }
+
+ switch (c) {
+ case '{':
+ if (!inParam) {
+ level++;
+ chunk.push(c);
+ break;
+ }
+ /* falls through */
+ case '}':
+ if (!inParam) {
+ level--;
+ chunk.push(c);
+ chunks[++j] = chunk = [];
+ break;
+ }
+ /* falls through */
+ case '(':
+ if (!inParam) {
+ inParam = true;
+ chunk.push(c);
+ break;
+ }
+ /* falls through */
+ case ')':
+ if (inParam) {
+ inParam = false;
+ chunk.push(c);
+ break;
+ }
+ /* falls through */
+ default:
+ chunk.push(c);
+ }
+
+ i++;
+ }
+ if (level !== 0) {
+ error = new(LessError)({
+ index: i-1,
+ type: 'Parse',
+ message: (level > 0) ? "missing closing `}`" : "missing opening `{`",
+ filename: env.currentFileInfo.filename
+ }, env);
+ }
+
+ return chunks.map(function (c) { return c.join(''); });
+ })([[]]);
+
+ if (error) {
+ return callback(new(LessError)(error, env));
+ }
+
+ // Start with the primary rule.
+ // The whole syntax tree is held under a Ruleset node,
+ // with the `root` property set to true, so no `{}` are
+ // output. The callback is called when the input is parsed.
+ try {
+ root = new(tree.Ruleset)([], $(this.parsers.primary));
+ root.root = true;
+ root.firstRoot = true;
+ } catch (e) {
+ return callback(new(LessError)(e, env));
+ }
+
+ root.toCSS = (function (evaluate) {
+ return function (options, variables) {
+ options = options || {};
+ var evaldRoot,
+ css,
+ evalEnv = new tree.evalEnv(options);
+
+ //
+ // Allows setting variables with a hash, so:
+ //
+ // `{ color: new(tree.Color)('#f01') }` will become:
+ //
+ // new(tree.Rule)('@color',
+ // new(tree.Value)([
+ // new(tree.Expression)([
+ // new(tree.Color)('#f01')
+ // ])
+ // ])
+ // )
+ //
+ if (typeof(variables) === 'object' && !Array.isArray(variables)) {
+ variables = Object.keys(variables).map(function (k) {
+ var value = variables[k];
+
+ if (! (value instanceof tree.Value)) {
+ if (! (value instanceof tree.Expression)) {
+ value = new(tree.Expression)([value]);
+ }
+ value = new(tree.Value)([value]);
+ }
+ return new(tree.Rule)('@' + k, value, false, null, 0);
+ });
+ evalEnv.frames = [new(tree.Ruleset)(null, variables)];
+ }
+
+ try {
+ evaldRoot = evaluate.call(this, evalEnv);
+
+ new(tree.joinSelectorVisitor)()
+ .run(evaldRoot);
+
+ new(tree.processExtendsVisitor)()
+ .run(evaldRoot);
+
+ new(tree.toCSSVisitor)({compress: Boolean(options.compress)})
+ .run(evaldRoot);
+
+ if (options.sourceMap) {
+ evaldRoot = new tree.sourceMapOutput(
+ {
+ writeSourceMap: options.writeSourceMap,
+ rootNode: evaldRoot,
+ contentsMap: parser.imports.contents,
+ sourceMapFilename: options.sourceMapFilename,
+ sourceMapURL: options.sourceMapURL,
+ outputFilename: options.sourceMapOutputFilename,
+ sourceMapBasepath: options.sourceMapBasepath,
+ sourceMapRootpath: options.sourceMapRootpath,
+ outputSourceFiles: options.outputSourceFiles,
+ sourceMapGenerator: options.sourceMapGenerator
+ });
+ }
+
+ css = evaldRoot.toCSS({
+ compress: Boolean(options.compress),
+ dumpLineNumbers: env.dumpLineNumbers,
+ strictUnits: Boolean(options.strictUnits)});
+ } catch (e) {
+ throw new(LessError)(e, env);
+ }
+
+ if (options.cleancss && less.mode === 'node') {
+ var CleanCSS = require('clean-css');
+ //TODO would be nice for no advanced to be an option
+ return new CleanCSS({keepSpecialComments: '*', processImport: false, noRebase: true, noAdvanced: true}).minify(css);
+ } else if (options.compress) {
+ return css.replace(/(^(\s)+)|((\s)+$)/g, "");
+ } else {
+ return css;
+ }
+ };
+ })(root.eval);
+
+ // If `i` is smaller than the `input.length - 1`,
+ // it means the parser wasn't able to parse the whole
+ // string, so we've got a parsing error.
+ //
+ // We try to extract a \n delimited string,
+ // showing the line where the parse error occured.
+ // We split it up into two parts (the part which parsed,
+ // and the part which didn't), so we can color them differently.
+ if (i < input.length - 1) {
+ i = furthest;
+ var loc = getLocation(i, input);
+ lines = input.split('\n');
+ line = loc.line + 1;
+
+ error = {
+ type: "Parse",
+ message: "Unrecognised input",
+ index: i,
+ filename: env.currentFileInfo.filename,
+ line: line,
+ column: loc.column,
+ extract: [
+ lines[line - 2],
+ lines[line - 1],
+ lines[line]
+ ]
+ };
+ }
+
+ var finish = function (e) {
+ e = error || e || parser.imports.error;
+
+ if (e) {
+ if (!(e instanceof LessError)) {
+ e = new(LessError)(e, env);
+ }
+
+ return callback(e);
+ }
+ else {
+ return callback(null, root);
+ }
+ };
+
+ if (env.processImports !== false) {
+ new tree.importVisitor(this.imports, finish)
+ .run(root);
+ } else {
+ return finish();
+ }
+ },
+
+ //
+ // Here in, the parsing rules/functions
+ //
+ // The basic structure of the syntax tree generated is as follows:
+ //
+ // Ruleset -> Rule -> Value -> Expression -> Entity
+ //
+ // Here's some LESS code:
+ //
+ // .class {
+ // color: #fff;
+ // border: 1px solid #000;
+ // width: @w + 4px;
+ // > .child {...}
+ // }
+ //
+ // And here's what the parse tree might look like:
+ //
+ // Ruleset (Selector '.class', [
+ // Rule ("color", Value ([Expression [Color #fff]]))
+ // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
+ // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
+ // Ruleset (Selector [Element '>', '.child'], [...])
+ // ])
+ //
+ // In general, most rules will try to parse a token with the `$()` function, and if the return
+ // value is truly, will return a new node, of the relevant type. Sometimes, we need to check
+ // first, before parsing, that's when we use `peek()`.
+ //
+ parsers: {
+ //
+ // The `primary` rule is the *entry* and *exit* point of the parser.
+ // The rules here can appear at any level of the parse tree.
+ //
+ // The recursive nature of the grammar is an interplay between the `block`
+ // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
+ // as represented by this simplified grammar:
+ //
+ // primary → (ruleset | rule)+
+ // ruleset → selector+ block
+ // block → '{' primary '}'
+ //
+ // Only at one point is the primary rule not called from the
+ // block rule: at the root level.
+ //
+ primary: function () {
+ var node, root = [];
+
+ while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
+ $(this.mixin.call) || $(this.comment) || $(this.directive))
+ || $(/^[\s\n]+/) || $(/^;+/)) {
+ node && root.push(node);
+ }
+ return root;
+ },
+
+ // We create a Comment node for CSS comments `/* */`,
+ // but keep the LeSS comments `//` silent, by just skipping
+ // over them.
+ comment: function () {
+ var comment;
+
+ if (input.charAt(i) !== '/') { return; }
+
+ if (input.charAt(i + 1) === '/') {
+ return new(tree.Comment)($(/^\/\/.*/), true, i, env.currentFileInfo);
+ } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
+ return new(tree.Comment)(comment, false, i, env.currentFileInfo);
+ }
+ },
+
+ comments: function () {
+ var comment, comments = [];
+
+ while(comment = $(this.comment)) {
+ comments.push(comment);
+ }
+
+ return comments;
+ },
+
+ //
+ // Entities are tokens which can be found inside an Expression
+ //
+ entities: {
+ //
+ // A string, which supports escaping " and '
+ //
+ // "milky way" 'he\'s the one!'
+ //
+ quoted: function () {
+ var str, j = i, e, index = i;
+
+ if (input.charAt(j) === '~') { j++, e = true; } // Escaped strings
+ if (input.charAt(j) !== '"' && input.charAt(j) !== "'") { return; }
+
+ e && $('~');
+
+ if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
+ return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo);
+ }
+ },
+
+ //
+ // A catch-all word, such as:
+ //
+ // black border-collapse
+ //
+ keyword: function () {
+ var k;
+
+ if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
+ var color = tree.Color.fromKeyword(k);
+ if (color) {
+ return color;
+ }
+ return new(tree.Keyword)(k);
+ }
+ },
+
+ //
+ // A function call
+ //
+ // rgb(255, 0, 255)
+ //
+ // We also try to catch IE's `alpha()`, but let the `alpha` parser
+ // deal with the details.
+ //
+ // The arguments are parsed with the `entities.arguments` parser.
+ //
+ call: function () {
+ var name, nameLC, args, alpha_ret, index = i;
+
+ if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) { return; }
+
+ name = name[1];
+ nameLC = name.toLowerCase();
+
+ if (nameLC === 'url') { return null; }
+ else { i += name.length; }
+
+ if (nameLC === 'alpha') {
+ alpha_ret = $(this.alpha);
+ if(typeof alpha_ret !== 'undefined') {
+ return alpha_ret;
+ }
+ }
+
+ $('('); // Parse the '(' and consume whitespace.
+
+ args = $(this.entities.arguments);
+
+ if (! $(')')) {
+ return;
+ }
+
+ if (name) { return new(tree.Call)(name, args, index, env.currentFileInfo); }
+ },
+ arguments: function () {
+ var args = [], arg;
+
+ while (arg = $(this.entities.assignment) || $(this.expression)) {
+ args.push(arg);
+ if (! $(',')) {
+ break;
+ }
+ }
+ return args;
+ },
+ literal: function () {
+ return $(this.entities.dimension) ||
+ $(this.entities.color) ||
+ $(this.entities.quoted) ||
+ $(this.entities.unicodeDescriptor);
+ },
+
+ // Assignments are argument entities for calls.
+ // They are present in ie filter properties as shown below.
+ //
+ // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
+ //
+
+ assignment: function () {
+ var key, value;
+ if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) {
+ return new(tree.Assignment)(key, value);
+ }
+ },
+
+ //
+ // Parse url() tokens
+ //
+ // We use a specific rule for urls, because they don't really behave like
+ // standard function calls. The difference is that the argument doesn't have
+ // to be enclosed within a string, so it can't be parsed as an Expression.
+ //
+ url: function () {
+ var value;
+
+ if (input.charAt(i) !== 'u' || !$(/^url\(/)) {
+ return;
+ }
+
+ value = $(this.entities.quoted) || $(this.entities.variable) ||
+ $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
+
+ expect(')');
+
+ /*jshint eqnull:true */
+ return new(tree.URL)((value.value != null || value instanceof tree.Variable)
+ ? value : new(tree.Anonymous)(value), env.currentFileInfo);
+ },
+
+ //
+ // A Variable entity, such as `@fink`, in
+ //
+ // width: @fink + 2px
+ //
+ // We use a different parser for variable definitions,
+ // see `parsers.variable`.
+ //
+ variable: function () {
+ var name, index = i;
+
+ if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
+ return new(tree.Variable)(name, index, env.currentFileInfo);
+ }
+ },
+
+ // A variable entity useing the protective {} e.g. @{var}
+ variableCurly: function () {
+ var curly, index = i;
+
+ if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) {
+ return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo);
+ }
+ },
+
+ //
+ // A Hexadecimal color
+ //
+ // #4F3C2F
+ //
+ // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
+ //
+ color: function () {
+ var rgb;
+
+ if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
+ return new(tree.Color)(rgb[1]);
+ }
+ },
+
+ //
+ // A Dimension, that is, a number and a unit
+ //
+ // 0.5em 95%
+ //
+ dimension: function () {
+ var value, c = input.charCodeAt(i);
+ //Is the first char of the dimension 0-9, '.', '+' or '-'
+ if ((c > 57 || c < 43) || c === 47 || c == 44) {
+ return;
+ }
+
+ if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) {
+ return new(tree.Dimension)(value[1], value[2]);
+ }
+ },
+
+ //
+ // A unicode descriptor, as is used in unicode-range
+ //
+ // U+0?? or U+00A1-00A9
+ //
+ unicodeDescriptor: function () {
+ var ud;
+
+ if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) {
+ return new(tree.UnicodeDescriptor)(ud[0]);
+ }
+ },
+
+ //
+ // JavaScript code to be evaluated
+ //
+ // `window.location.href`
+ //
+ javascript: function () {
+ var str, j = i, e;
+
+ if (input.charAt(j) === '~') { j++; e = true; } // Escaped strings
+ if (input.charAt(j) !== '`') { return; }
+ if (env.javascriptEnabled !== undefined && !env.javascriptEnabled) {
+ error("You are using JavaScript, which has been disabled.");
+ }
+
+ if (e) { $('~'); }
+
+ if (str = $(/^`([^`]*)`/)) {
+ return new(tree.JavaScript)(str[1], i, e);
+ }
+ }
+ },
+
+ //
+ // The variable part of a variable definition. Used in the `rule` parser
+ //
+ // @fink:
+ //
+ variable: function () {
+ var name;
+
+ if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1]; }
+ },
+
+ //
+ // extend syntax - used to extend selectors
+ //
+ extend: function(isRule) {
+ var elements, e, index = i, option, extendList = [];
+
+ if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; }
+
+ do {
+ option = null;
+ elements = [];
+ while (true) {
+ option = $(/^(all)(?=\s*(\)|,))/);
+ if (option) { break; }
+ e = $(this.element);
+ if (!e) { break; }
+ elements.push(e);
+ }
+
+ option = option && option[1];
+
+ extendList.push(new(tree.Extend)(new(tree.Selector)(elements), option, index));
+
+ } while($(","));
+
+ expect(/^\)/);
+
+ if (isRule) {
+ expect(/^;/);
+ }
+
+ return extendList;
+ },
+
+ //
+ // extendRule - used in a rule to extend all the parent selectors
+ //
+ extendRule: function() {
+ return this.extend(true);
+ },
+
+ //
+ // Mixins
+ //
+ mixin: {
+ //
+ // A Mixin call, with an optional argument list
+ //
+ // #mixins > .square(#fff);
+ // .rounded(4px, black);
+ // .button;
+ //
+ // The `while` loop is there because mixins can be
+ // namespaced, but we only support the child and descendant
+ // selector for now.
+ //
+ call: function () {
+ var elements = [], e, c, args, index = i, s = input.charAt(i), important = false;
+
+ if (s !== '.' && s !== '#') { return; }
+
+ save(); // stop us absorbing part of an invalid selector
+
+ while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
+ elements.push(new(tree.Element)(c, e, i, env.currentFileInfo));
+ c = $('>');
+ }
+ if ($('(')) {
+ args = this.mixin.args.call(this, true).args;
+ expect(')');
+ }
+
+ args = args || [];
+
+ if ($(this.important)) {
+ important = true;
+ }
+
+ if (elements.length > 0 && ($(';') || peek('}'))) {
+ return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important);
+ }
+
+ restore();
+ },
+ args: function (isCall) {
+ var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg,
+ returner = {args:null, variadic: false};
+ while (true) {
+ if (isCall) {
+ arg = $(this.expression);
+ } else {
+ $(this.comments);
+ if (input.charAt(i) === '.' && $(/^\.{3}/)) {
+ returner.variadic = true;
+ if ($(";") && !isSemiColonSeperated) {
+ isSemiColonSeperated = true;
+ }
+ (isSemiColonSeperated ? argsSemiColon : argsComma)
+ .push({ variadic: true });
+ break;
+ }
+ arg = $(this.entities.variable) || $(this.entities.literal)
+ || $(this.entities.keyword);
+ }
+
+ if (!arg) {
+ break;
+ }
+
+ nameLoop = null;
+ if (arg.throwAwayComments) {
+ arg.throwAwayComments();
+ }
+ value = arg;
+ var val = null;
+
+ if (isCall) {
+ // Variable
+ if (arg.value.length == 1) {
+ val = arg.value[0];
+ }
+ } else {
+ val = arg;
+ }
+
+ if (val && val instanceof tree.Variable) {
+ if ($(':')) {
+ if (expressions.length > 0) {
+ if (isSemiColonSeperated) {
+ error("Cannot mix ; and , as delimiter types");
+ }
+ expressionContainsNamed = true;
+ }
+ value = expect(this.expression);
+ nameLoop = (name = val.name);
+ } else if (!isCall && $(/^\.{3}/)) {
+ returner.variadic = true;
+ if ($(";") && !isSemiColonSeperated) {
+ isSemiColonSeperated = true;
+ }
+ (isSemiColonSeperated ? argsSemiColon : argsComma)
+ .push({ name: arg.name, variadic: true });
+ break;
+ } else if (!isCall) {
+ name = nameLoop = val.name;
+ value = null;
+ }
+ }
+
+ if (value) {
+ expressions.push(value);
+ }
+
+ argsComma.push({ name:nameLoop, value:value });
+
+ if ($(',')) {
+ continue;
+ }
+
+ if ($(';') || isSemiColonSeperated) {
+
+ if (expressionContainsNamed) {
+ error("Cannot mix ; and , as delimiter types");
+ }
+
+ isSemiColonSeperated = true;
+
+ if (expressions.length > 1) {
+ value = new(tree.Value)(expressions);
+ }
+ argsSemiColon.push({ name:name, value:value });
+
+ name = null;
+ expressions = [];
+ expressionContainsNamed = false;
+ }
+ }
+
+ returner.args = isSemiColonSeperated ? argsSemiColon : argsComma;
+ return returner;
+ },
+ //
+ // A Mixin definition, with a list of parameters
+ //
+ // .rounded (@radius: 2px, @color) {
+ // ...
+ // }
+ //
+ // Until we have a finer grained state-machine, we have to
+ // do a look-ahead, to make sure we don't have a mixin call.
+ // See the `rule` function for more information.
+ //
+ // We start by matching `.rounded (`, and then proceed on to
+ // the argument list, which has optional default values.
+ // We store the parameters in `params`, with a `value` key,
+ // if there is a value, such as in the case of `@radius`.
+ //
+ // Once we've got our params list, and a closing `)`, we parse
+ // the `{...}` block.
+ //
+ definition: function () {
+ var name, params = [], match, ruleset, cond, variadic = false;
+ if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
+ peek(/^[^{]*\}/)) {
+ return;
+ }
+
+ save();
+
+ if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) {
+ name = match[1];
+
+ var argInfo = this.mixin.args.call(this, false);
+ params = argInfo.args;
+ variadic = argInfo.variadic;
+
+ // .mixincall("@{a}");
+ // looks a bit like a mixin definition.. so we have to be nice and restore
+ if (!$(')')) {
+ furthest = i;
+ restore();
+ }
+
+ $(this.comments);
+
+ if ($(/^when/)) { // Guard
+ cond = expect(this.conditions, 'expected condition');
+ }
+
+ ruleset = $(this.block);
+
+ if (ruleset) {
+ return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
+ } else {
+ restore();
+ }
+ }
+ }
+ },
+
+ //
+ // Entities are the smallest recognized token,
+ // and can be found inside a rule's value.
+ //
+ entity: function () {
+ return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
+ $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) ||
+ $(this.comment);
+ },
+
+ //
+ // A Rule terminator. Note that we use `peek()` to check for '}',
+ // because the `block` rule will be expecting it, but we still need to make sure
+ // it's there, if ';' was ommitted.
+ //
+ end: function () {
+ return $(';') || peek('}');
+ },
+
+ //
+ // IE's alpha function
+ //
+ // alpha(opacity=88)
+ //
+ alpha: function () {
+ var value;
+
+ if (! $(/^\(opacity=/i)) { return; }
+ if (value = $(/^\d+/) || $(this.entities.variable)) {
+ expect(')');
+ return new(tree.Alpha)(value);
+ }
+ },
+
+ //
+ // A Selector Element
+ //
+ // div
+ // + h1
+ // #socks
+ // input[type="text"]
+ //
+ // Elements are the building blocks for Selectors,
+ // they are made out of a `Combinator` (see combinator rule),
+ // and an element name, such as a tag a class, or `*`.
+ //
+ element: function () {
+ var e, c, v;
+
+ c = $(this.combinator);
+
+ e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
+ $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly);
+
+ if (! e) {
+ if ($('(')) {
+ if ((v = ($(this.selector))) &&
+ $(')')) {
+ e = new(tree.Paren)(v);
+ }
+ }
+ }
+
+ if (e) { return new(tree.Element)(c, e, i, env.currentFileInfo); }
+ },
+
+ //
+ // Combinators combine elements together, in a Selector.
+ //
+ // Because our parser isn't white-space sensitive, special care
+ // has to be taken, when parsing the descendant combinator, ` `,
+ // as it's an empty space. We have to check the previous character
+ // in the input, to see if it's a ` ` character. More info on how
+ // we deal with this in *combinator.js*.
+ //
+ combinator: function () {
+ var c = input.charAt(i);
+
+ if (c === '>' || c === '+' || c === '~' || c === '|') {
+ i++;
+ while (input.charAt(i).match(/\s/)) { i++; }
+ return new(tree.Combinator)(c);
+ } else if (input.charAt(i - 1).match(/\s/)) {
+ return new(tree.Combinator)(" ");
+ } else {
+ return new(tree.Combinator)(null);
+ }
+ },
+ //
+ // A CSS selector (see selector below)
+ // with less extensions e.g. the ability to extend and guard
+ //
+ lessSelector: function () {
+ return this.selector(true);
+ },
+ //
+ // A CSS Selector
+ //
+ // .class > div + h1
+ // li a:hover
+ //
+ // Selectors are made out of one or more Elements, see above.
+ //
+ selector: function (isLess) {
+ var e, elements = [], c, extend, extendList = [], when, condition;
+
+ while ((isLess && (extend = $(this.extend))) || (isLess && (when = $(/^when/))) || (e = $(this.element))) {
+ if (when) {
+ condition = expect(this.conditions, 'expected condition');
+ } else if (condition) {
+ error("CSS guard can only be used at the end of selector");
+ } else if (extend) {
+ extendList.push.apply(extendList, extend);
+ } else {
+ if (extendList.length) {
+ error("Extend can only be used at the end of selector");
+ }
+ c = input.charAt(i);
+ elements.push(e);
+ e = null;
+ }
+ if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {
+ break;
+ }
+ }
+
+ if (elements.length > 0) { return new(tree.Selector)(elements, extendList, condition, i, env.currentFileInfo); }
+ if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
+ },
+ attribute: function () {
+ var key, val, op;
+
+ if (! $('[')) { return; }
+
+ if (!(key = $(this.entities.variableCurly))) {
+ key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
+ }
+
+ if ((op = $(/^[|~*$^]?=/))) {
+ val = $(this.entities.quoted) || $(/^[0-9]+%/) || $(/^[\w-]+/) || $(this.entities.variableCurly);
+ }
+
+ expect(']');
+
+ return new(tree.Attribute)(key, op, val);
+ },
+
+ //
+ // The `block` rule is used by `ruleset` and `mixin.definition`.
+ // It's a wrapper around the `primary` rule, with added `{}`.
+ //
+ block: function () {
+ var content;
+ if ($('{') && (content = $(this.primary)) && $('}')) {
+ return content;
+ }
+ },
+
+ //
+ // div, .class, body > p {...}
+ //
+ ruleset: function () {
+ var selectors = [], s, rules, debugInfo;
+
+ save();
+
+ if (env.dumpLineNumbers) {
+ debugInfo = getDebugInfo(i, input, env);
+ }
+
+ while (s = $(this.lessSelector)) {
+ selectors.push(s);
+ $(this.comments);
+ if (! $(',')) { break; }
+ if (s.condition) {
+ error("Guards are only currently allowed on a single selector.");
+ }
+ $(this.comments);
+ }
+
+ if (selectors.length > 0 && (rules = $(this.block))) {
+ var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports);
+ if (env.dumpLineNumbers) {
+ ruleset.debugInfo = debugInfo;
+ }
+ return ruleset;
+ } else {
+ // Backtrack
+ furthest = i;
+ restore();
+ }
+ },
+ rule: function (tryAnonymous) {
+ var name, value, c = input.charAt(i), important, merge = false;
+ save();
+
+ if (c === '.' || c === '#' || c === '&') { return; }
+
+ if (name = $(this.variable) || $(this.ruleProperty)) {
+ // prefer to try to parse first if its a variable or we are compressing
+ // but always fallback on the other one
+ value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ?
+ ($(this.value) || $(this.anonymousValue)) :
+ ($(this.anonymousValue) || $(this.value));
+
+
+ important = $(this.important);
+ if (name[name.length-1] === "+") {
+ merge = true;
+ name = name.substr(0, name.length - 1);
+ }
+
+ if (value && $(this.end)) {
+ return new (tree.Rule)(name, value, important, merge, memo, env.currentFileInfo);
+ } else {
+ furthest = i;
+ restore();
+ if (value && !tryAnonymous) {
+ return this.rule(true);
+ }
+ }
+ }
+ },
+ anonymousValue: function () {
+ var match;
+ if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) {
+ i += match[0].length - 1;
+ return new(tree.Anonymous)(match[1]);
+ }
+ },
+
+ //
+ // An @import directive
+ //
+ // @import "lib";
+ //
+ // Depending on our environemnt, importing is done differently:
+ // In the browser, it's an XHR request, in Node, it would be a
+ // file-system operation. The function used for importing is
+ // stored in `import`, which we pass to the Import constructor.
+ //
+ "import": function () {
+ var path, features, index = i;
+
+ save();
+
+ var dir = $(/^@import?\s+/);
+
+ var options = (dir ? $(this.importOptions) : null) || {};
+
+ if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) {
+ features = $(this.mediaFeatures);
+ if ($(';')) {
+ features = features && new(tree.Value)(features);
+ return new(tree.Import)(path, features, options, index, env.currentFileInfo);
+ }
+ }
+
+ restore();
+ },
+
+ importOptions: function() {
+ var o, options = {}, optionName, value;
+
+ // list of options, surrounded by parens
+ if (! $('(')) { return null; }
+ do {
+ if (o = $(this.importOption)) {
+ optionName = o;
+ value = true;
+ switch(optionName) {
+ case "css":
+ optionName = "less";
+ value = false;
+ break;
+ case "once":
+ optionName = "multiple";
+ value = false;
+ break;
+ }
+ options[optionName] = value;
+ if (! $(',')) { break; }
+ }
+ } while (o);
+ expect(')');
+ return options;
+ },
+
+ importOption: function() {
+ var opt = $(/^(less|css|multiple|once|inline|reference)/);
+ if (opt) {
+ return opt[1];
+ }
+ },
+
+ mediaFeature: function () {
+ var e, p, nodes = [];
+
+ do {
+ if (e = ($(this.entities.keyword) || $(this.entities.variable))) {
+ nodes.push(e);
+ } else if ($('(')) {
+ p = $(this.property);
+ e = $(this.value);
+ if ($(')')) {
+ if (p && e) {
+ nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, null, i, env.currentFileInfo, true)));
+ } else if (e) {
+ nodes.push(new(tree.Paren)(e));
+ } else {
+ return null;
+ }
+ } else { return null; }
+ }
+ } while (e);
+
+ if (nodes.length > 0) {
+ return new(tree.Expression)(nodes);
+ }
+ },
+
+ mediaFeatures: function () {
+ var e, features = [];
+
+ do {
+ if (e = $(this.mediaFeature)) {
+ features.push(e);
+ if (! $(',')) { break; }
+ } else if (e = $(this.entities.variable)) {
+ features.push(e);
+ if (! $(',')) { break; }
+ }
+ } while (e);
+
+ return features.length > 0 ? features : null;
+ },
+
+ media: function () {
+ var features, rules, media, debugInfo;
+
+ if (env.dumpLineNumbers) {
+ debugInfo = getDebugInfo(i, input, env);
+ }
+
+ if ($(/^@media/)) {
+ features = $(this.mediaFeatures);
+
+ if (rules = $(this.block)) {
+ media = new(tree.Media)(rules, features, i, env.currentFileInfo);
+ if (env.dumpLineNumbers) {
+ media.debugInfo = debugInfo;
+ }
+ return media;
+ }
+ }
+ },
+
+ //
+ // A CSS Directive
+ //
+ // @charset "utf-8";
+ //
+ directive: function () {
+ var name, value, rules, nonVendorSpecificName,
+ hasBlock, hasIdentifier, hasExpression, identifier;
+
+ if (input.charAt(i) !== '@') { return; }
+
+ if (value = $(this['import']) || $(this.media)) {
+ return value;
+ }
+
+ save();
+
+ name = $(/^@[a-z-]+/);
+
+ if (!name) { return; }
+
+ nonVendorSpecificName = name;
+ if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
+ nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1);
+ }
+
+ switch(nonVendorSpecificName) {
+ case "@font-face":
+ hasBlock = true;
+ break;
+ case "@viewport":
+ case "@top-left":
+ case "@top-left-corner":
+ case "@top-center":
+ case "@top-right":
+ case "@top-right-corner":
+ case "@bottom-left":
+ case "@bottom-left-corner":
+ case "@bottom-center":
+ case "@bottom-right":
+ case "@bottom-right-corner":
+ case "@left-top":
+ case "@left-middle":
+ case "@left-bottom":
+ case "@right-top":
+ case "@right-middle":
+ case "@right-bottom":
+ hasBlock = true;
+ break;
+ case "@host":
+ case "@page":
+ case "@document":
+ case "@supports":
+ case "@keyframes":
+ hasBlock = true;
+ hasIdentifier = true;
+ break;
+ case "@namespace":
+ hasExpression = true;
+ break;
+ }
+
+ if (hasIdentifier) {
+ identifier = ($(/^[^{]+/) || '').trim();
+ if (identifier) {
+ name += " " + identifier;
+ }
+ }
+
+ if (hasBlock)
+ {
+ if (rules = $(this.block)) {
+ return new(tree.Directive)(name, rules, i, env.currentFileInfo);
+ }
+ } else {
+ if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) {
+ var directive = new(tree.Directive)(name, value, i, env.currentFileInfo);
+ if (env.dumpLineNumbers) {
+ directive.debugInfo = getDebugInfo(i, input, env);
+ }
+ return directive;
+ }
+ }
+
+ restore();
+ },
+
+ //
+ // A Value is a comma-delimited list of Expressions
+ //
+ // font-family: Baskerville, Georgia, serif;
+ //
+ // In a Rule, a Value represents everything after the `:`,
+ // and before the `;`.
+ //
+ value: function () {
+ var e, expressions = [];
+
+ while (e = $(this.expression)) {
+ expressions.push(e);
+ if (! $(',')) { break; }
+ }
+
+ if (expressions.length > 0) {
+ return new(tree.Value)(expressions);
+ }
+ },
+ important: function () {
+ if (input.charAt(i) === '!') {
+ return $(/^! *important/);
+ }
+ },
+ sub: function () {
+ var a, e;
+
+ if ($('(')) {
+ if (a = $(this.addition)) {
+ e = new(tree.Expression)([a]);
+ expect(')');
+ e.parens = true;
+ return e;
+ }
+ }
+ },
+ multiplication: function () {
+ var m, a, op, operation, isSpaced;
+ if (m = $(this.operand)) {
+ isSpaced = isWhitespace(input.charAt(i - 1));
+ while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) {
+ if (a = $(this.operand)) {
+ m.parensInOp = true;
+ a.parensInOp = true;
+ operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
+ isSpaced = isWhitespace(input.charAt(i - 1));
+ } else {
+ break;
+ }
+ }
+ return operation || m;
+ }
+ },
+ addition: function () {
+ var m, a, op, operation, isSpaced;
+ if (m = $(this.multiplication)) {
+ isSpaced = isWhitespace(input.charAt(i - 1));
+ while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) &&
+ (a = $(this.multiplication))) {
+ m.parensInOp = true;
+ a.parensInOp = true;
+ operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
+ isSpaced = isWhitespace(input.charAt(i - 1));
+ }
+ return operation || m;
+ }
+ },
+ conditions: function () {
+ var a, b, index = i, condition;
+
+ if (a = $(this.condition)) {
+ while (peek(/^,\s*(not\s*)?\(/) && $(',') && (b = $(this.condition))) {
+ condition = new(tree.Condition)('or', condition || a, b, index);
+ }
+ return condition || a;
+ }
+ },
+ condition: function () {
+ var a, b, c, op, index = i, negate = false;
+
+ if ($(/^not/)) { negate = true; }
+ expect('(');
+ if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
+ if (op = $(/^(?:>=|<=|=<|[<=>])/)) {
+ if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
+ c = new(tree.Condition)(op, a, b, index, negate);
+ } else {
+ error('expected expression');
+ }
+ } else {
+ c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
+ }
+ expect(')');
+ return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c;
+ }
+ },
+
+ //
+ // An operand is anything that can be part of an operation,
+ // such as a Color, or a Variable
+ //
+ operand: function () {
+ var negate, p = input.charAt(i + 1);
+
+ if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-'); }
+ var o = $(this.sub) || $(this.entities.dimension) ||
+ $(this.entities.color) || $(this.entities.variable) ||
+ $(this.entities.call);
+
+ if (negate) {
+ o.parensInOp = true;
+ o = new(tree.Negative)(o);
+ }
+
+ return o;
+ },
+
+ //
+ // Expressions either represent mathematical operations,
+ // or white-space delimited Entities.
+ //
+ // 1px solid black
+ // @var * 2
+ //
+ expression: function () {
+ var e, delim, entities = [];
+
+ while (e = $(this.addition) || $(this.entity)) {
+ entities.push(e);
+ // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
+ if (!peek(/^\/[\/*]/) && (delim = $('/'))) {
+ entities.push(new(tree.Anonymous)(delim));
+ }
+ }
+ if (entities.length > 0) {
+ return new(tree.Expression)(entities);
+ }
+ },
+ property: function () {
+ var name;
+
+ if (name = $(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/)) {
+ return name[1];
+ }
+ },
+ ruleProperty: function () {
+ var name;
+
+ if (name = $(/^(\*?-?[_a-zA-Z0-9-]+)\s*(\+?)\s*:/)) {
+ return name[1] + (name[2] || "");
+ }
+ }
+ }
+ };
+};
+
+
+(function (tree) {
+
+tree.functions = {
+ rgb: function (r, g, b) {
+ return this.rgba(r, g, b, 1.0);
+ },
+ rgba: function (r, g, b, a) {
+ var rgb = [r, g, b].map(function (c) { return scaled(c, 256); });
+ a = number(a);
+ return new(tree.Color)(rgb, a);
+ },
+ hsl: function (h, s, l) {
+ return this.hsla(h, s, l, 1.0);
+ },
+ hsla: function (h, s, l, a) {
+ function hue(h) {
+ h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
+ if (h * 6 < 1) { return m1 + (m2 - m1) * h * 6; }
+ else if (h * 2 < 1) { return m2; }
+ else if (h * 3 < 2) { return m1 + (m2 - m1) * (2/3 - h) * 6; }
+ else { return m1; }
+ }
+
+ h = (number(h) % 360) / 360;
+ s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a));
+
+ var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
+ var m1 = l * 2 - m2;
+
+ return this.rgba(hue(h + 1/3) * 255,
+ hue(h) * 255,
+ hue(h - 1/3) * 255,
+ a);
+ },
+
+ hsv: function(h, s, v) {
+ return this.hsva(h, s, v, 1.0);
+ },
+
+ hsva: function(h, s, v, a) {
+ h = ((number(h) % 360) / 360) * 360;
+ s = number(s); v = number(v); a = number(a);
+
+ var i, f;
+ i = Math.floor((h / 60) % 6);
+ f = (h / 60) - i;
+
+ var vs = [v,
+ v * (1 - s),
+ v * (1 - f * s),
+ v * (1 - (1 - f) * s)];
+ var perm = [[0, 3, 1],
+ [2, 0, 1],
+ [1, 0, 3],
+ [1, 2, 0],
+ [3, 1, 0],
+ [0, 1, 2]];
+
+ return this.rgba(vs[perm[i][0]] * 255,
+ vs[perm[i][1]] * 255,
+ vs[perm[i][2]] * 255,
+ a);
+ },
+
+ hue: function (color) {
+ return new(tree.Dimension)(Math.round(color.toHSL().h));
+ },
+ saturation: function (color) {
+ return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
+ },
+ lightness: function (color) {
+ return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
+ },
+ hsvhue: function(color) {
+ return new(tree.Dimension)(Math.round(color.toHSV().h));
+ },
+ hsvsaturation: function (color) {
+ return new(tree.Dimension)(Math.round(color.toHSV().s * 100), '%');
+ },
+ hsvvalue: function (color) {
+ return new(tree.Dimension)(Math.round(color.toHSV().v * 100), '%');
+ },
+ red: function (color) {
+ return new(tree.Dimension)(color.rgb[0]);
+ },
+ green: function (color) {
+ return new(tree.Dimension)(color.rgb[1]);
+ },
+ blue: function (color) {
+ return new(tree.Dimension)(color.rgb[2]);
+ },
+ alpha: function (color) {
+ return new(tree.Dimension)(color.toHSL().a);
+ },
+ luma: function (color) {
+ return new(tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%');
+ },
+ saturate: function (color, amount) {
+ // filter: saturate(3.2);
+ // should be kept as is, so check for color
+ if (!color.rgb) {
+ return null;
+ }
+ var hsl = color.toHSL();
+
+ hsl.s += amount.value / 100;
+ hsl.s = clamp(hsl.s);
+ return hsla(hsl);
+ },
+ desaturate: function (color, amount) {
+ var hsl = color.toHSL();
+
+ hsl.s -= amount.value / 100;
+ hsl.s = clamp(hsl.s);
+ return hsla(hsl);
+ },
+ lighten: function (color, amount) {
+ var hsl = color.toHSL();
+
+ hsl.l += amount.value / 100;
+ hsl.l = clamp(hsl.l);
+ return hsla(hsl);
+ },
+ darken: function (color, amount) {
+ var hsl = color.toHSL();
+
+ hsl.l -= amount.value / 100;
+ hsl.l = clamp(hsl.l);
+ return hsla(hsl);
+ },
+ fadein: function (color, amount) {
+ var hsl = color.toHSL();
+
+ hsl.a += amount.value / 100;
+ hsl.a = clamp(hsl.a);
+ return hsla(hsl);
+ },
+ fadeout: function (color, amount) {
+ var hsl = color.toHSL();
+
+ hsl.a -= amount.value / 100;
+ hsl.a = clamp(hsl.a);
+ return hsla(hsl);
+ },
+ fade: function (color, amount) {
+ var hsl = color.toHSL();
+
+ hsl.a = amount.value / 100;
+ hsl.a = clamp(hsl.a);
+ return hsla(hsl);
+ },
+ spin: function (color, amount) {
+ var hsl = color.toHSL();
+ var hue = (hsl.h + amount.value) % 360;
+
+ hsl.h = hue < 0 ? 360 + hue : hue;
+
+ return hsla(hsl);
+ },
+ //
+ // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
+ // http://sass-lang.com
+ //
+ mix: function (color1, color2, weight) {
+ if (!weight) {
+ weight = new(tree.Dimension)(50);
+ }
+ var p = weight.value / 100.0;
+ var w = p * 2 - 1;
+ var a = color1.toHSL().a - color2.toHSL().a;
+
+ var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
+ var w2 = 1 - w1;
+
+ var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
+ color1.rgb[1] * w1 + color2.rgb[1] * w2,
+ color1.rgb[2] * w1 + color2.rgb[2] * w2];
+
+ var alpha = color1.alpha * p + color2.alpha * (1 - p);
+
+ return new(tree.Color)(rgb, alpha);
+ },
+ greyscale: function (color) {
+ return this.desaturate(color, new(tree.Dimension)(100));
+ },
+ contrast: function (color, dark, light, threshold) {
+ // filter: contrast(3.2);
+ // should be kept as is, so check for color
+ if (!color.rgb) {
+ return null;
+ }
+ if (typeof light === 'undefined') {
+ light = this.rgba(255, 255, 255, 1.0);
+ }
+ if (typeof dark === 'undefined') {
+ dark = this.rgba(0, 0, 0, 1.0);
+ }
+ //Figure out which is actually light and dark!
+ if (dark.luma() > light.luma()) {
+ var t = light;
+ light = dark;
+ dark = t;
+ }
+ if (typeof threshold === 'undefined') {
+ threshold = 0.43;
+ } else {
+ threshold = number(threshold);
+ }
+ if ((color.luma() * color.alpha) < threshold) {
+ return light;
+ } else {
+ return dark;
+ }
+ },
+ e: function (str) {
+ return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
+ },
+ escape: function (str) {
+ return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
+ },
+ '%': function (quoted /* arg, arg, ...*/) {
+ var args = Array.prototype.slice.call(arguments, 1),
+ str = quoted.value;
+
+ for (var i = 0; i < args.length; i++) {
+ /*jshint loopfunc:true */
+ str = str.replace(/%[sda]/i, function(token) {
+ var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
+ return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
+ });
+ }
+ str = str.replace(/%%/g, '%');
+ return new(tree.Quoted)('"' + str + '"', str);
+ },
+ unit: function (val, unit) {
+ if(!(val instanceof tree.Dimension)) {
+ throw { type: "Argument", message: "the first argument to unit must be a number" + (val instanceof tree.Operation ? ". Have you forgotten parenthesis?" : "") };
+ }
+ return new(tree.Dimension)(val.value, unit ? unit.toCSS() : "");
+ },
+ convert: function (val, unit) {
+ return val.convertTo(unit.value);
+ },
+ round: function (n, f) {
+ var fraction = typeof(f) === "undefined" ? 0 : f.value;
+ return this._math(function(num) { return num.toFixed(fraction); }, null, n);
+ },
+ pi: function () {
+ return new(tree.Dimension)(Math.PI);
+ },
+ mod: function(a, b) {
+ return new(tree.Dimension)(a.value % b.value, a.unit);
+ },
+ pow: function(x, y) {
+ if (typeof x === "number" && typeof y === "number") {
+ x = new(tree.Dimension)(x);
+ y = new(tree.Dimension)(y);
+ } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) {
+ throw { type: "Argument", message: "arguments must be numbers" };
+ }
+
+ return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit);
+ },
+ _math: function (fn, unit, n) {
+ if (n instanceof tree.Dimension) {
+ /*jshint eqnull:true */
+ return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit);
+ } else if (typeof(n) === 'number') {
+ return fn(n);
+ } else {
+ throw { type: "Argument", message: "argument must be a number" };
+ }
+ },
+ _minmax: function (isMin, args) {
+ args = Array.prototype.slice.call(args);
+ switch(args.length) {
+ case 0: throw { type: "Argument", message: "one or more arguments required" };
+ case 1: return args[0];
+ }
+ var i, j, current, currentUnified, referenceUnified, unit,
+ order = [], // elems only contains original argument values.
+ values = {}; // key is the unit.toString() for unified tree.Dimension values,
+ // value is the index into the order array.
+ for (i = 0; i < args.length; i++) {
+ current = args[i];
+ if (!(current instanceof tree.Dimension)) {
+ order.push(current);
+ continue;
+ }
+ currentUnified = current.unify();
+ unit = currentUnified.unit.toString();
+ j = values[unit];
+ if (j === undefined) {
+ values[unit] = order.length;
+ order.push(current);
+ continue;
+ }
+ referenceUnified = order[j].unify();
+ if ( isMin && currentUnified.value < referenceUnified.value ||
+ !isMin && currentUnified.value > referenceUnified.value) {
+ order[j] = current;
+ }
+ }
+ if (order.length == 1) {
+ return order[0];
+ }
+ args = order.map(function (a) { return a.toCSS(this.env); })
+ .join(this.env.compress ? "," : ", ");
+ return new(tree.Anonymous)((isMin ? "min" : "max") + "(" + args + ")");
+ },
+ min: function () {
+ return this._minmax(true, arguments);
+ },
+ max: function () {
+ return this._minmax(false, arguments);
+ },
+ argb: function (color) {
+ return new(tree.Anonymous)(color.toARGB());
+
+ },
+ percentage: function (n) {
+ return new(tree.Dimension)(n.value * 100, '%');
+ },
+ color: function (n) {
+ if (n instanceof tree.Quoted) {
+ var colorCandidate = n.value,
+ returnColor;
+ returnColor = tree.Color.fromKeyword(colorCandidate);
+ if (returnColor) {
+ return returnColor;
+ }
+ if (/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/.test(colorCandidate)) {
+ return new(tree.Color)(colorCandidate.slice(1));
+ }
+ throw { type: "Argument", message: "argument must be a color keyword or 3/6 digit hex e.g. #FFF" };
+ } else {
+ throw { type: "Argument", message: "argument must be a string" };
+ }
+ },
+ iscolor: function (n) {
+ return this._isa(n, tree.Color);
+ },
+ isnumber: function (n) {
+ return this._isa(n, tree.Dimension);
+ },
+ isstring: function (n) {
+ return this._isa(n, tree.Quoted);
+ },
+ iskeyword: function (n) {
+ return this._isa(n, tree.Keyword);
+ },
+ isurl: function (n) {
+ return this._isa(n, tree.URL);
+ },
+ ispixel: function (n) {
+ return this.isunit(n, 'px');
+ },
+ ispercentage: function (n) {
+ return this.isunit(n, '%');
+ },
+ isem: function (n) {
+ return this.isunit(n, 'em');
+ },
+ isunit: function (n, unit) {
+ return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? tree.True : tree.False;
+ },
+ _isa: function (n, Type) {
+ return (n instanceof Type) ? tree.True : tree.False;
+ },
+
+ /* Blending modes */
+
+ multiply: function(color1, color2) {
+ var r = color1.rgb[0] * color2.rgb[0] / 255;
+ var g = color1.rgb[1] * color2.rgb[1] / 255;
+ var b = color1.rgb[2] * color2.rgb[2] / 255;
+ return this.rgb(r, g, b);
+ },
+ screen: function(color1, color2) {
+ var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255;
+ var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255;
+ var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255;
+ return this.rgb(r, g, b);
+ },
+ overlay: function(color1, color2) {
+ var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255;
+ var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255;
+ var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255;
+ return this.rgb(r, g, b);
+ },
+ softlight: function(color1, color2) {
+ var t = color2.rgb[0] * color1.rgb[0] / 255;
+ var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255;
+ t = color2.rgb[1] * color1.rgb[1] / 255;
+ var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255;
+ t = color2.rgb[2] * color1.rgb[2] / 255;
+ var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255;
+ return this.rgb(r, g, b);
+ },
+ hardlight: function(color1, color2) {
+ var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255;
+ var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255;
+ var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255;
+ return this.rgb(r, g, b);
+ },
+ difference: function(color1, color2) {
+ var r = Math.abs(color1.rgb[0] - color2.rgb[0]);
+ var g = Math.abs(color1.rgb[1] - color2.rgb[1]);
+ var b = Math.abs(color1.rgb[2] - color2.rgb[2]);
+ return this.rgb(r, g, b);
+ },
+ exclusion: function(color1, color2) {
+ var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255;
+ var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255;
+ var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255;
+ return this.rgb(r, g, b);
+ },
+ average: function(color1, color2) {
+ var r = (color1.rgb[0] + color2.rgb[0]) / 2;
+ var g = (color1.rgb[1] + color2.rgb[1]) / 2;
+ var b = (color1.rgb[2] + color2.rgb[2]) / 2;
+ return this.rgb(r, g, b);
+ },
+ negation: function(color1, color2) {
+ var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]);
+ var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]);
+ var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]);
+ return this.rgb(r, g, b);
+ },
+ tint: function(color, amount) {
+ return this.mix(this.rgb(255,255,255), color, amount);
+ },
+ shade: function(color, amount) {
+ return this.mix(this.rgb(0, 0, 0), color, amount);
+ },
+ extract: function(values, index) {
+ index = index.value - 1; // (1-based index)
+ // handle non-array values as an array of length 1
+ // return 'undefined' if index is invalid
+ return Array.isArray(values.value)
+ ? values.value[index] : Array(values)[index];
+ },
+ length: function(values) {
+ var n = Array.isArray(values.value) ? values.value.length : 1;
+ return new tree.Dimension(n);
+ },
+
+ "data-uri": function(mimetypeNode, filePathNode) {
+
+ if (typeof window !== 'undefined') {
+ return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env);
+ }
+
+ var mimetype = mimetypeNode.value;
+ var filePath = (filePathNode && filePathNode.value);
+
+ var fs = require("fs"),
+ path = require("path"),
+ useBase64 = false;
+
+ if (arguments.length < 2) {
+ filePath = mimetype;
+ }
+
+ if (this.env.isPathRelative(filePath)) {
+ if (this.currentFileInfo.relativeUrls) {
+ filePath = path.join(this.currentFileInfo.currentDirectory, filePath);
+ } else {
+ filePath = path.join(this.currentFileInfo.entryPath, filePath);
+ }
+ }
+
+ // detect the mimetype if not given
+ if (arguments.length < 2) {
+ var mime;
+ try {
+ mime = require('mime');
+ } catch (ex) {
+ mime = tree._mime;
+ }
+
+ mimetype = mime.lookup(filePath);
+
+ // use base 64 unless it's an ASCII or UTF-8 format
+ var charset = mime.charsets.lookup(mimetype);
+ useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
+ if (useBase64) { mimetype += ';base64'; }
+ }
+ else {
+ useBase64 = /;base64$/.test(mimetype);
+ }
+
+ var buf = fs.readFileSync(filePath);
+
+ // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded
+ // and the --ieCompat flag is enabled, return a normal url() instead.
+ var DATA_URI_MAX_KB = 32,
+ fileSizeInKB = parseInt((buf.length / 1024), 10);
+ if (fileSizeInKB >= DATA_URI_MAX_KB) {
+
+ if (this.env.ieCompat !== false) {
+ if (!this.env.silent) {
+ console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB);
+ }
+
+ return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env);
+ }
+ }
+
+ buf = useBase64 ? buf.toString('base64')
+ : encodeURIComponent(buf);
+
+ var uri = "'data:" + mimetype + ',' + buf + "'";
+ return new(tree.URL)(new(tree.Anonymous)(uri));
+ },
+
+ "svg-gradient": function(direction) {
+
+ function throwArgumentDescriptor() {
+ throw { type: "Argument", message: "svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]" };
+ }
+
+ if (arguments.length < 3) {
+ throwArgumentDescriptor();
+ }
+ var stops = Array.prototype.slice.call(arguments, 1),
+ gradientDirectionSvg,
+ gradientType = "linear",
+ rectangleDimension = 'x="0" y="0" width="1" height="1"',
+ useBase64 = true,
+ renderEnv = {compress: false},
+ returner,
+ directionValue = direction.toCSS(renderEnv),
+ i, color, position, positionValue, alpha;
+
+ switch (directionValue) {
+ case "to bottom":
+ gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
+ break;
+ case "to right":
+ gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
+ break;
+ case "to bottom right":
+ gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
+ break;
+ case "to top right":
+ gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
+ break;
+ case "ellipse":
+ case "ellipse at center":
+ gradientType = "radial";
+ gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
+ rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
+ break;
+ default:
+ throw { type: "Argument", message: "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" };
+ }
+ returner = '' +
+ '';
+
+ if (useBase64) {
+ // only works in node, needs interface to what is supported in environment
+ try {
+ returner = new Buffer(returner).toString('base64');
+ } catch(e) {
+ useBase64 = false;
+ }
+ }
+
+ returner = "'data:image/svg+xml" + (useBase64 ? ";base64" : "") + "," + returner + "'";
+ return new(tree.URL)(new(tree.Anonymous)(returner));
+ }
+};
+
+// these static methods are used as a fallback when the optional 'mime' dependency is missing
+tree._mime = {
+ // this map is intentionally incomplete
+ // if you want more, install 'mime' dep
+ _types: {
+ '.htm' : 'text/html',
+ '.html': 'text/html',
+ '.gif' : 'image/gif',
+ '.jpg' : 'image/jpeg',
+ '.jpeg': 'image/jpeg',
+ '.png' : 'image/png'
+ },
+ lookup: function (filepath) {
+ var ext = require('path').extname(filepath),
+ type = tree._mime._types[ext];
+ if (type === undefined) {
+ throw new Error('Optional dependency "mime" is required for ' + ext);
+ }
+ return type;
+ },
+ charsets: {
+ lookup: function (type) {
+ // assumes all text types are UTF-8
+ return type && (/^text\//).test(type) ? 'UTF-8' : '';
+ }
+ }
+};
+
+var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"},
+ {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""},
+ {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}],
+ createMathFunction = function(name, unit) {
+ return function(n) {
+ /*jshint eqnull:true */
+ if (unit != null) {
+ n = n.unify();
+ }
+ return this._math(Math[name], unit, n);
+ };
+ };
+
+for(var i = 0; i < mathFunctions.length; i++) {
+ tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit);
+}
+
+function hsla(color) {
+ return tree.functions.hsla(color.h, color.s, color.l, color.a);
+}
+
+function scaled(n, size) {
+ if (n instanceof tree.Dimension && n.unit.is('%')) {
+ return parseFloat(n.value * size / 100);
+ } else {
+ return number(n);
+ }
+}
+
+function number(n) {
+ if (n instanceof tree.Dimension) {
+ return parseFloat(n.unit.is('%') ? n.value / 100 : n.value);
+ } else if (typeof(n) === 'number') {
+ return n;
+ } else {
+ throw {
+ error: "RuntimeError",
+ message: "color functions take numbers as parameters"
+ };
+ }
+}
+
+function clamp(val) {
+ return Math.min(1, Math.max(0, val));
+}
+
+tree.functionCall = function(env, currentFileInfo) {
+ this.env = env;
+ this.currentFileInfo = currentFileInfo;
+};
+
+tree.functionCall.prototype = tree.functions;
+
+})(require('./tree'));
+
+(function (tree) {
+ tree.colors = {
+ 'aliceblue':'#f0f8ff',
+ 'antiquewhite':'#faebd7',
+ 'aqua':'#00ffff',
+ 'aquamarine':'#7fffd4',
+ 'azure':'#f0ffff',
+ 'beige':'#f5f5dc',
+ 'bisque':'#ffe4c4',
+ 'black':'#000000',
+ 'blanchedalmond':'#ffebcd',
+ 'blue':'#0000ff',
+ 'blueviolet':'#8a2be2',
+ 'brown':'#a52a2a',
+ 'burlywood':'#deb887',
+ 'cadetblue':'#5f9ea0',
+ 'chartreuse':'#7fff00',
+ 'chocolate':'#d2691e',
+ 'coral':'#ff7f50',
+ 'cornflowerblue':'#6495ed',
+ 'cornsilk':'#fff8dc',
+ 'crimson':'#dc143c',
+ 'cyan':'#00ffff',
+ 'darkblue':'#00008b',
+ 'darkcyan':'#008b8b',
+ 'darkgoldenrod':'#b8860b',
+ 'darkgray':'#a9a9a9',
+ 'darkgrey':'#a9a9a9',
+ 'darkgreen':'#006400',
+ 'darkkhaki':'#bdb76b',
+ 'darkmagenta':'#8b008b',
+ 'darkolivegreen':'#556b2f',
+ 'darkorange':'#ff8c00',
+ 'darkorchid':'#9932cc',
+ 'darkred':'#8b0000',
+ 'darksalmon':'#e9967a',
+ 'darkseagreen':'#8fbc8f',
+ 'darkslateblue':'#483d8b',
+ 'darkslategray':'#2f4f4f',
+ 'darkslategrey':'#2f4f4f',
+ 'darkturquoise':'#00ced1',
+ 'darkviolet':'#9400d3',
+ 'deeppink':'#ff1493',
+ 'deepskyblue':'#00bfff',
+ 'dimgray':'#696969',
+ 'dimgrey':'#696969',
+ 'dodgerblue':'#1e90ff',
+ 'firebrick':'#b22222',
+ 'floralwhite':'#fffaf0',
+ 'forestgreen':'#228b22',
+ 'fuchsia':'#ff00ff',
+ 'gainsboro':'#dcdcdc',
+ 'ghostwhite':'#f8f8ff',
+ 'gold':'#ffd700',
+ 'goldenrod':'#daa520',
+ 'gray':'#808080',
+ 'grey':'#808080',
+ 'green':'#008000',
+ 'greenyellow':'#adff2f',
+ 'honeydew':'#f0fff0',
+ 'hotpink':'#ff69b4',
+ 'indianred':'#cd5c5c',
+ 'indigo':'#4b0082',
+ 'ivory':'#fffff0',
+ 'khaki':'#f0e68c',
+ 'lavender':'#e6e6fa',
+ 'lavenderblush':'#fff0f5',
+ 'lawngreen':'#7cfc00',
+ 'lemonchiffon':'#fffacd',
+ 'lightblue':'#add8e6',
+ 'lightcoral':'#f08080',
+ 'lightcyan':'#e0ffff',
+ 'lightgoldenrodyellow':'#fafad2',
+ 'lightgray':'#d3d3d3',
+ 'lightgrey':'#d3d3d3',
+ 'lightgreen':'#90ee90',
+ 'lightpink':'#ffb6c1',
+ 'lightsalmon':'#ffa07a',
+ 'lightseagreen':'#20b2aa',
+ 'lightskyblue':'#87cefa',
+ 'lightslategray':'#778899',
+ 'lightslategrey':'#778899',
+ 'lightsteelblue':'#b0c4de',
+ 'lightyellow':'#ffffe0',
+ 'lime':'#00ff00',
+ 'limegreen':'#32cd32',
+ 'linen':'#faf0e6',
+ 'magenta':'#ff00ff',
+ 'maroon':'#800000',
+ 'mediumaquamarine':'#66cdaa',
+ 'mediumblue':'#0000cd',
+ 'mediumorchid':'#ba55d3',
+ 'mediumpurple':'#9370d8',
+ 'mediumseagreen':'#3cb371',
+ 'mediumslateblue':'#7b68ee',
+ 'mediumspringgreen':'#00fa9a',
+ 'mediumturquoise':'#48d1cc',
+ 'mediumvioletred':'#c71585',
+ 'midnightblue':'#191970',
+ 'mintcream':'#f5fffa',
+ 'mistyrose':'#ffe4e1',
+ 'moccasin':'#ffe4b5',
+ 'navajowhite':'#ffdead',
+ 'navy':'#000080',
+ 'oldlace':'#fdf5e6',
+ 'olive':'#808000',
+ 'olivedrab':'#6b8e23',
+ 'orange':'#ffa500',
+ 'orangered':'#ff4500',
+ 'orchid':'#da70d6',
+ 'palegoldenrod':'#eee8aa',
+ 'palegreen':'#98fb98',
+ 'paleturquoise':'#afeeee',
+ 'palevioletred':'#d87093',
+ 'papayawhip':'#ffefd5',
+ 'peachpuff':'#ffdab9',
+ 'peru':'#cd853f',
+ 'pink':'#ffc0cb',
+ 'plum':'#dda0dd',
+ 'powderblue':'#b0e0e6',
+ 'purple':'#800080',
+ 'red':'#ff0000',
+ 'rosybrown':'#bc8f8f',
+ 'royalblue':'#4169e1',
+ 'saddlebrown':'#8b4513',
+ 'salmon':'#fa8072',
+ 'sandybrown':'#f4a460',
+ 'seagreen':'#2e8b57',
+ 'seashell':'#fff5ee',
+ 'sienna':'#a0522d',
+ 'silver':'#c0c0c0',
+ 'skyblue':'#87ceeb',
+ 'slateblue':'#6a5acd',
+ 'slategray':'#708090',
+ 'slategrey':'#708090',
+ 'snow':'#fffafa',
+ 'springgreen':'#00ff7f',
+ 'steelblue':'#4682b4',
+ 'tan':'#d2b48c',
+ 'teal':'#008080',
+ 'thistle':'#d8bfd8',
+ 'tomato':'#ff6347',
+ 'turquoise':'#40e0d0',
+ 'violet':'#ee82ee',
+ 'wheat':'#f5deb3',
+ 'white':'#ffffff',
+ 'whitesmoke':'#f5f5f5',
+ 'yellow':'#ffff00',
+ 'yellowgreen':'#9acd32'
+ };
+})(require('./tree'));
+
+(function (tree) {
+
+tree.debugInfo = function(env, ctx, lineSeperator) {
+ var result="";
+ if (env.dumpLineNumbers && !env.compress) {
+ switch(env.dumpLineNumbers) {
+ case 'comments':
+ result = tree.debugInfo.asComment(ctx);
+ break;
+ case 'mediaquery':
+ result = tree.debugInfo.asMediaQuery(ctx);
+ break;
+ case 'all':
+ result = tree.debugInfo.asComment(ctx) + (lineSeperator || "") + tree.debugInfo.asMediaQuery(ctx);
+ break;
+ }
+ }
+ return result;
+};
+
+tree.debugInfo.asComment = function(ctx) {
+ return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n';
+};
+
+tree.debugInfo.asMediaQuery = function(ctx) {
+ return '@media -sass-debug-info{filename{font-family:' +
+ ('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function (a) {
+ if (a == '\\') {
+ a = '\/';
+ }
+ return '\\' + a;
+ }) +
+ '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n';
+};
+
+tree.find = function (obj, fun) {
+ for (var i = 0, r; i < obj.length; i++) {
+ if (r = fun.call(obj, obj[i])) { return r; }
+ }
+ return null;
+};
+
+tree.jsify = function (obj) {
+ if (Array.isArray(obj.value) && (obj.value.length > 1)) {
+ return '[' + obj.value.map(function (v) { return v.toCSS(false); }).join(', ') + ']';
+ } else {
+ return obj.toCSS(false);
+ }
+};
+
+tree.toCSS = function (env) {
+ var strs = [];
+ this.genCSS(env, {
+ add: function(chunk, fileInfo, index) {
+ strs.push(chunk);
+ },
+ isEmpty: function () {
+ return strs.length === 0;
+ }
+ });
+ return strs.join('');
+};
+
+tree.outputRuleset = function (env, output, rules) {
+ output.add((env.compress ? '{' : ' {\n'));
+ env.tabLevel = (env.tabLevel || 0) + 1;
+ var tabRuleStr = env.compress ? '' : Array(env.tabLevel + 1).join(" "),
+ tabSetStr = env.compress ? '' : Array(env.tabLevel).join(" ");
+ for(var i = 0; i < rules.length; i++) {
+ output.add(tabRuleStr);
+ rules[i].genCSS(env, output);
+ output.add(env.compress ? '' : '\n');
+ }
+ env.tabLevel--;
+ output.add(tabSetStr + "}");
+};
+
+})(require('./tree'));
+
+(function (tree) {
+
+tree.Alpha = function (val) {
+ this.value = val;
+};
+tree.Alpha.prototype = {
+ type: "Alpha",
+ accept: function (visitor) {
+ this.value = visitor.visit(this.value);
+ },
+ eval: function (env) {
+ if (this.value.eval) { return new tree.Alpha(this.value.eval(env)); }
+ return this;
+ },
+ genCSS: function (env, output) {
+ output.add("alpha(opacity=");
+
+ if (this.value.genCSS) {
+ this.value.genCSS(env, output);
+ } else {
+ output.add(this.value);
+ }
+
+ output.add(")");
+ },
+ toCSS: tree.toCSS
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Anonymous = function (string, index, currentFileInfo, mapLines) {
+ this.value = string.value || string;
+ this.index = index;
+ this.mapLines = mapLines;
+ this.currentFileInfo = currentFileInfo;
+};
+tree.Anonymous.prototype = {
+ type: "Anonymous",
+ eval: function () { return this; },
+ compare: function (x) {
+ if (!x.toCSS) {
+ return -1;
+ }
+
+ var left = this.toCSS(),
+ right = x.toCSS();
+
+ if (left === right) {
+ return 0;
+ }
+
+ return left < right ? -1 : 1;
+ },
+ genCSS: function (env, output) {
+ output.add(this.value, this.currentFileInfo, this.index, this.mapLines);
+ },
+ toCSS: tree.toCSS
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Assignment = function (key, val) {
+ this.key = key;
+ this.value = val;
+};
+tree.Assignment.prototype = {
+ type: "Assignment",
+ accept: function (visitor) {
+ this.value = visitor.visit(this.value);
+ },
+ eval: function (env) {
+ if (this.value.eval) {
+ return new(tree.Assignment)(this.key, this.value.eval(env));
+ }
+ return this;
+ },
+ genCSS: function (env, output) {
+ output.add(this.key + '=');
+ if (this.value.genCSS) {
+ this.value.genCSS(env, output);
+ } else {
+ output.add(this.value);
+ }
+ },
+ toCSS: tree.toCSS
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+//
+// A function call node.
+//
+tree.Call = function (name, args, index, currentFileInfo) {
+ this.name = name;
+ this.args = args;
+ this.index = index;
+ this.currentFileInfo = currentFileInfo;
+};
+tree.Call.prototype = {
+ type: "Call",
+ accept: function (visitor) {
+ this.args = visitor.visit(this.args);
+ },
+ //
+ // When evaluating a function call,
+ // we either find the function in `tree.functions` [1],
+ // in which case we call it, passing the evaluated arguments,
+ // if this returns null or we cannot find the function, we
+ // simply print it out as it appeared originally [2].
+ //
+ // The *functions.js* file contains the built-in functions.
+ //
+ // The reason why we evaluate the arguments, is in the case where
+ // we try to pass a variable to a function, like: `saturate(@color)`.
+ // The function should receive the value, not the variable.
+ //
+ eval: function (env) {
+ var args = this.args.map(function (a) { return a.eval(env); }),
+ nameLC = this.name.toLowerCase(),
+ result, func;
+
+ if (nameLC in tree.functions) { // 1.
+ try {
+ func = new tree.functionCall(env, this.currentFileInfo);
+ result = func[nameLC].apply(func, args);
+ /*jshint eqnull:true */
+ if (result != null) {
+ return result;
+ }
+ } catch (e) {
+ throw { type: e.type || "Runtime",
+ message: "error evaluating function `" + this.name + "`" +
+ (e.message ? ': ' + e.message : ''),
+ index: this.index, filename: this.currentFileInfo.filename };
+ }
+ }
+
+ return new tree.Call(this.name, args, this.index, this.currentFileInfo);
+ },
+
+ genCSS: function (env, output) {
+ output.add(this.name + "(", this.currentFileInfo, this.index);
+
+ for(var i = 0; i < this.args.length; i++) {
+ this.args[i].genCSS(env, output);
+ if (i + 1 < this.args.length) {
+ output.add(", ");
+ }
+ }
+
+ output.add(")");
+ },
+
+ toCSS: tree.toCSS
+};
+
+})(require('../tree'));
+
+(function (tree) {
+//
+// RGB Colors - #ff0014, #eee
+//
+tree.Color = function (rgb, a) {
+ //
+ // The end goal here, is to parse the arguments
+ // into an integer triplet, such as `128, 255, 0`
+ //
+ // This facilitates operations and conversions.
+ //
+ if (Array.isArray(rgb)) {
+ this.rgb = rgb;
+ } else if (rgb.length == 6) {
+ this.rgb = rgb.match(/.{2}/g).map(function (c) {
+ return parseInt(c, 16);
+ });
+ } else {
+ this.rgb = rgb.split('').map(function (c) {
+ return parseInt(c + c, 16);
+ });
+ }
+ this.alpha = typeof(a) === 'number' ? a : 1;
+};
+
+var transparentKeyword = "transparent";
+
+tree.Color.prototype = {
+ type: "Color",
+ eval: function () { return this; },
+ luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); },
+
+ genCSS: function (env, output) {
+ output.add(this.toCSS(env));
+ },
+ toCSS: function (env, doNotCompress) {
+ var compress = env && env.compress && !doNotCompress;
+
+ // If we have some transparency, the only way to represent it
+ // is via `rgba`. Otherwise, we use the hex representation,
+ // which has better compatibility with older browsers.
+ // Values are capped between `0` and `255`, rounded and zero-padded.
+ if (this.alpha < 1.0) {
+ if (this.alpha === 0 && this.isTransparentKeyword) {
+ return transparentKeyword;
+ }
+ return "rgba(" + this.rgb.map(function (c) {
+ return Math.round(c);
+ }).concat(this.alpha).join(',' + (compress ? '' : ' ')) + ")";
+ } else {
+ var color = this.toRGB();
+
+ if (compress) {
+ var splitcolor = color.split('');
+
+ // Convert color to short format
+ if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) {
+ color = '#' + splitcolor[1] + splitcolor[3] + splitcolor[5];
+ }
+ }
+
+ return color;
+ }
+ },
+
+ //
+ // Operations have to be done per-channel, if not,
+ // channels will spill onto each other. Once we have
+ // our result, in the form of an integer triplet,
+ // we create a new Color node to hold the result.
+ //
+ operate: function (env, op, other) {
+ var result = [];
+
+ if (! (other instanceof tree.Color)) {
+ other = other.toColor();
+ }
+
+ for (var c = 0; c < 3; c++) {
+ result[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]);
+ }
+ return new(tree.Color)(result, this.alpha + other.alpha);
+ },
+
+ toRGB: function () {
+ return '#' + this.rgb.map(function (i) {
+ i = Math.round(i);
+ i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
+ return i.length === 1 ? '0' + i : i;
+ }).join('');
+ },
+
+ toHSL: function () {
+ var r = this.rgb[0] / 255,
+ g = this.rgb[1] / 255,
+ b = this.rgb[2] / 255,
+ a = this.alpha;
+
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h, s, l = (max + min) / 2, d = max - min;
+
+ if (max === min) {
+ h = s = 0;
+ } else {
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+
+ switch (max) {
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+ return { h: h * 360, s: s, l: l, a: a };
+ },
+ //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
+ toHSV: function () {
+ var r = this.rgb[0] / 255,
+ g = this.rgb[1] / 255,
+ b = this.rgb[2] / 255,
+ a = this.alpha;
+
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h, s, v = max;
+
+ var d = max - min;
+ if (max === 0) {
+ s = 0;
+ } else {
+ s = d / max;
+ }
+
+ if (max === min) {
+ h = 0;
+ } else {
+ switch(max){
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+ return { h: h * 360, s: s, v: v, a: a };
+ },
+ toARGB: function () {
+ var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
+ return '#' + argb.map(function (i) {
+ i = Math.round(i);
+ i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
+ return i.length === 1 ? '0' + i : i;
+ }).join('');
+ },
+ compare: function (x) {
+ if (!x.rgb) {
+ return -1;
+ }
+
+ return (x.rgb[0] === this.rgb[0] &&
+ x.rgb[1] === this.rgb[1] &&
+ x.rgb[2] === this.rgb[2] &&
+ x.alpha === this.alpha) ? 0 : -1;
+ }
+};
+
+tree.Color.fromKeyword = function(keyword) {
+ if (tree.colors.hasOwnProperty(keyword)) {
+ // detect named color
+ return new(tree.Color)(tree.colors[keyword].slice(1));
+ }
+ if (keyword === transparentKeyword) {
+ var transparent = new(tree.Color)([0, 0, 0], 0);
+ transparent.isTransparentKeyword = true;
+ return transparent;
+ }
+};
+
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Comment = function (value, silent, index, currentFileInfo) {
+ this.value = value;
+ this.silent = !!silent;
+ this.currentFileInfo = currentFileInfo;
+};
+tree.Comment.prototype = {
+ type: "Comment",
+ genCSS: function (env, output) {
+ if (this.debugInfo) {
+ output.add(tree.debugInfo(env, this), this.currentFileInfo, this.index);
+ }
+ output.add(this.value.trim()); //TODO shouldn't need to trim, we shouldn't grab the \n
+ },
+ toCSS: tree.toCSS,
+ isSilent: function(env) {
+ var isReference = (this.currentFileInfo && this.currentFileInfo.reference && !this.isReferenced),
+ isCompressed = env.compress && !this.value.match(/^\/\*!/);
+ return this.silent || isReference || isCompressed;
+ },
+ eval: function () { return this; },
+ markReferenced: function () {
+ this.isReferenced = true;
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Condition = function (op, l, r, i, negate) {
+ this.op = op.trim();
+ this.lvalue = l;
+ this.rvalue = r;
+ this.index = i;
+ this.negate = negate;
+};
+tree.Condition.prototype = {
+ type: "Condition",
+ accept: function (visitor) {
+ this.lvalue = visitor.visit(this.lvalue);
+ this.rvalue = visitor.visit(this.rvalue);
+ },
+ eval: function (env) {
+ var a = this.lvalue.eval(env),
+ b = this.rvalue.eval(env);
+
+ var i = this.index, result;
+
+ result = (function (op) {
+ switch (op) {
+ case 'and':
+ return a && b;
+ case 'or':
+ return a || b;
+ default:
+ if (a.compare) {
+ result = a.compare(b);
+ } else if (b.compare) {
+ result = b.compare(a);
+ } else {
+ throw { type: "Type",
+ message: "Unable to perform comparison",
+ index: i };
+ }
+ switch (result) {
+ case -1: return op === '<' || op === '=<' || op === '<=';
+ case 0: return op === '=' || op === '>=' || op === '=<' || op === '<=';
+ case 1: return op === '>' || op === '>=';
+ }
+ }
+ })(this.op);
+ return this.negate ? !result : result;
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+//
+// A number with a unit
+//
+tree.Dimension = function (value, unit) {
+ this.value = parseFloat(value);
+ this.unit = (unit && unit instanceof tree.Unit) ? unit :
+ new(tree.Unit)(unit ? [unit] : undefined);
+};
+
+tree.Dimension.prototype = {
+ type: "Dimension",
+ accept: function (visitor) {
+ this.unit = visitor.visit(this.unit);
+ },
+ eval: function (env) {
+ return this;
+ },
+ toColor: function () {
+ return new(tree.Color)([this.value, this.value, this.value]);
+ },
+ genCSS: function (env, output) {
+ if ((env && env.strictUnits) && !this.unit.isSingular()) {
+ throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());
+ }
+
+ var value = this.value,
+ strValue = String(value);
+
+ if (value !== 0 && value < 0.000001 && value > -0.000001) {
+ // would be output 1e-6 etc.
+ strValue = value.toFixed(20).replace(/0+$/, "");
+ }
+
+ if (env && env.compress) {
+ // Zero values doesn't need a unit
+ if (value === 0 && this.unit.isLength()) {
+ output.add(strValue);
+ return;
+ }
+
+ // Float values doesn't need a leading zero
+ if (value > 0 && value < 1) {
+ strValue = (strValue).substr(1);
+ }
+ }
+
+ output.add(strValue);
+ this.unit.genCSS(env, output);
+ },
+ toCSS: tree.toCSS,
+
+ // In an operation between two Dimensions,
+ // we default to the first Dimension's unit,
+ // so `1px + 2` will yield `3px`.
+ operate: function (env, op, other) {
+ /*jshint noempty:false */
+ var value = tree.operate(env, op, this.value, other.value),
+ unit = this.unit.clone();
+
+ if (op === '+' || op === '-') {
+ if (unit.numerator.length === 0 && unit.denominator.length === 0) {
+ unit.numerator = other.unit.numerator.slice(0);
+ unit.denominator = other.unit.denominator.slice(0);
+ } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) {
+ // do nothing
+ } else {
+ other = other.convertTo(this.unit.usedUnits());
+
+ if(env.strictUnits && other.unit.toString() !== unit.toString()) {
+ throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() +
+ "' and '" + other.unit.toString() + "'.");
+ }
+
+ value = tree.operate(env, op, this.value, other.value);
+ }
+ } else if (op === '*') {
+ unit.numerator = unit.numerator.concat(other.unit.numerator).sort();
+ unit.denominator = unit.denominator.concat(other.unit.denominator).sort();
+ unit.cancel();
+ } else if (op === '/') {
+ unit.numerator = unit.numerator.concat(other.unit.denominator).sort();
+ unit.denominator = unit.denominator.concat(other.unit.numerator).sort();
+ unit.cancel();
+ }
+ return new(tree.Dimension)(value, unit);
+ },
+
+ compare: function (other) {
+ if (other instanceof tree.Dimension) {
+ var a = this.unify(), b = other.unify(),
+ aValue = a.value, bValue = b.value;
+
+ if (bValue > aValue) {
+ return -1;
+ } else if (bValue < aValue) {
+ return 1;
+ } else {
+ if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) {
+ return -1;
+ }
+ return 0;
+ }
+ } else {
+ return -1;
+ }
+ },
+
+ unify: function () {
+ return this.convertTo({ length: 'm', duration: 's', angle: 'rad' });
+ },
+
+ convertTo: function (conversions) {
+ var value = this.value, unit = this.unit.clone(),
+ i, groupName, group, targetUnit, derivedConversions = {}, applyUnit;
+
+ if (typeof conversions === 'string') {
+ for(i in tree.UnitConversions) {
+ if (tree.UnitConversions[i].hasOwnProperty(conversions)) {
+ derivedConversions = {};
+ derivedConversions[i] = conversions;
+ }
+ }
+ conversions = derivedConversions;
+ }
+ applyUnit = function (atomicUnit, denominator) {
+ /*jshint loopfunc:true */
+ if (group.hasOwnProperty(atomicUnit)) {
+ if (denominator) {
+ value = value / (group[atomicUnit] / group[targetUnit]);
+ } else {
+ value = value * (group[atomicUnit] / group[targetUnit]);
+ }
+
+ return targetUnit;
+ }
+
+ return atomicUnit;
+ };
+
+ for (groupName in conversions) {
+ if (conversions.hasOwnProperty(groupName)) {
+ targetUnit = conversions[groupName];
+ group = tree.UnitConversions[groupName];
+
+ unit.map(applyUnit);
+ }
+ }
+
+ unit.cancel();
+
+ return new(tree.Dimension)(value, unit);
+ }
+};
+
+// http://www.w3.org/TR/css3-values/#absolute-lengths
+tree.UnitConversions = {
+ length: {
+ 'm': 1,
+ 'cm': 0.01,
+ 'mm': 0.001,
+ 'in': 0.0254,
+ 'pt': 0.0254 / 72,
+ 'pc': 0.0254 / 72 * 12
+ },
+ duration: {
+ 's': 1,
+ 'ms': 0.001
+ },
+ angle: {
+ 'rad': 1/(2*Math.PI),
+ 'deg': 1/360,
+ 'grad': 1/400,
+ 'turn': 1
+ }
+};
+
+tree.Unit = function (numerator, denominator, backupUnit) {
+ this.numerator = numerator ? numerator.slice(0).sort() : [];
+ this.denominator = denominator ? denominator.slice(0).sort() : [];
+ this.backupUnit = backupUnit;
+};
+
+tree.Unit.prototype = {
+ type: "Unit",
+ clone: function () {
+ return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit);
+ },
+ genCSS: function (env, output) {
+ if (this.numerator.length >= 1) {
+ output.add(this.numerator[0]);
+ } else
+ if (this.denominator.length >= 1) {
+ output.add(this.denominator[0]);
+ } else
+ if ((!env || !env.strictUnits) && this.backupUnit) {
+ output.add(this.backupUnit);
+ }
+ },
+ toCSS: tree.toCSS,
+
+ toString: function () {
+ var i, returnStr = this.numerator.join("*");
+ for (i = 0; i < this.denominator.length; i++) {
+ returnStr += "/" + this.denominator[i];
+ }
+ return returnStr;
+ },
+
+ compare: function (other) {
+ return this.is(other.toString()) ? 0 : -1;
+ },
+
+ is: function (unitString) {
+ return this.toString() === unitString;
+ },
+
+ isLength: function () {
+ return Boolean(this.toCSS().match(/px|em|%|in|cm|mm|pc|pt|ex/));
+ },
+
+ isEmpty: function () {
+ return this.numerator.length === 0 && this.denominator.length === 0;
+ },
+
+ isSingular: function() {
+ return this.numerator.length <= 1 && this.denominator.length === 0;
+ },
+
+ map: function(callback) {
+ var i;
+
+ for (i = 0; i < this.numerator.length; i++) {
+ this.numerator[i] = callback(this.numerator[i], false);
+ }
+
+ for (i = 0; i < this.denominator.length; i++) {
+ this.denominator[i] = callback(this.denominator[i], true);
+ }
+ },
+
+ usedUnits: function() {
+ var group, result = {}, mapUnit;
+
+ mapUnit = function (atomicUnit) {
+ /*jshint loopfunc:true */
+ if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
+ result[groupName] = atomicUnit;
+ }
+
+ return atomicUnit;
+ };
+
+ for (var groupName in tree.UnitConversions) {
+ if (tree.UnitConversions.hasOwnProperty(groupName)) {
+ group = tree.UnitConversions[groupName];
+
+ this.map(mapUnit);
+ }
+ }
+
+ return result;
+ },
+
+ cancel: function () {
+ var counter = {}, atomicUnit, i, backup;
+
+ for (i = 0; i < this.numerator.length; i++) {
+ atomicUnit = this.numerator[i];
+ if (!backup) {
+ backup = atomicUnit;
+ }
+ counter[atomicUnit] = (counter[atomicUnit] || 0) + 1;
+ }
+
+ for (i = 0; i < this.denominator.length; i++) {
+ atomicUnit = this.denominator[i];
+ if (!backup) {
+ backup = atomicUnit;
+ }
+ counter[atomicUnit] = (counter[atomicUnit] || 0) - 1;
+ }
+
+ this.numerator = [];
+ this.denominator = [];
+
+ for (atomicUnit in counter) {
+ if (counter.hasOwnProperty(atomicUnit)) {
+ var count = counter[atomicUnit];
+
+ if (count > 0) {
+ for (i = 0; i < count; i++) {
+ this.numerator.push(atomicUnit);
+ }
+ } else if (count < 0) {
+ for (i = 0; i < -count; i++) {
+ this.denominator.push(atomicUnit);
+ }
+ }
+ }
+ }
+
+ if (this.numerator.length === 0 && this.denominator.length === 0 && backup) {
+ this.backupUnit = backup;
+ }
+
+ this.numerator.sort();
+ this.denominator.sort();
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Directive = function (name, value, index, currentFileInfo) {
+ this.name = name;
+
+ if (Array.isArray(value)) {
+ this.rules = [new(tree.Ruleset)([], value)];
+ this.rules[0].allowImports = true;
+ } else {
+ this.value = value;
+ }
+ this.currentFileInfo = currentFileInfo;
+
+};
+tree.Directive.prototype = {
+ type: "Directive",
+ accept: function (visitor) {
+ this.rules = visitor.visit(this.rules);
+ this.value = visitor.visit(this.value);
+ },
+ genCSS: function (env, output) {
+ output.add(this.name, this.currentFileInfo, this.index);
+ if (this.rules) {
+ tree.outputRuleset(env, output, this.rules);
+ } else {
+ output.add(' ');
+ this.value.genCSS(env, output);
+ output.add(';');
+ }
+ },
+ toCSS: tree.toCSS,
+ eval: function (env) {
+ var evaldDirective = this;
+ if (this.rules) {
+ env.frames.unshift(this);
+ evaldDirective = new(tree.Directive)(this.name, null, this.index, this.currentFileInfo);
+ evaldDirective.rules = [this.rules[0].eval(env)];
+ evaldDirective.rules[0].root = true;
+ env.frames.shift();
+ }
+ return evaldDirective;
+ },
+ variable: function (name) { return tree.Ruleset.prototype.variable.call(this.rules[0], name); },
+ find: function () { return tree.Ruleset.prototype.find.apply(this.rules[0], arguments); },
+ rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.rules[0]); },
+ markReferenced: function () {
+ var i, rules;
+ this.isReferenced = true;
+ if (this.rules) {
+ rules = this.rules[0].rules;
+ for (i = 0; i < rules.length; i++) {
+ if (rules[i].markReferenced) {
+ rules[i].markReferenced();
+ }
+ }
+ }
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Element = function (combinator, value, index, currentFileInfo) {
+ this.combinator = combinator instanceof tree.Combinator ?
+ combinator : new(tree.Combinator)(combinator);
+
+ if (typeof(value) === 'string') {
+ this.value = value.trim();
+ } else if (value) {
+ this.value = value;
+ } else {
+ this.value = "";
+ }
+ this.index = index;
+ this.currentFileInfo = currentFileInfo;
+};
+tree.Element.prototype = {
+ type: "Element",
+ accept: function (visitor) {
+ this.combinator = visitor.visit(this.combinator);
+ this.value = visitor.visit(this.value);
+ },
+ eval: function (env) {
+ return new(tree.Element)(this.combinator,
+ this.value.eval ? this.value.eval(env) : this.value,
+ this.index,
+ this.currentFileInfo);
+ },
+ genCSS: function (env, output) {
+ output.add(this.toCSS(env), this.currentFileInfo, this.index);
+ },
+ toCSS: function (env) {
+ var value = (this.value.toCSS ? this.value.toCSS(env) : this.value);
+ if (value === '' && this.combinator.value.charAt(0) === '&') {
+ return '';
+ } else {
+ return this.combinator.toCSS(env || {}) + value;
+ }
+ }
+};
+
+tree.Attribute = function (key, op, value) {
+ this.key = key;
+ this.op = op;
+ this.value = value;
+};
+tree.Attribute.prototype = {
+ type: "Attribute",
+ accept: function (visitor) {
+ this.value = visitor.visit(this.value);
+ },
+ eval: function (env) {
+ return new(tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key,
+ this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value);
+ },
+ genCSS: function (env, output) {
+ output.add(this.toCSS(env));
+ },
+ toCSS: function (env) {
+ var value = this.key.toCSS ? this.key.toCSS(env) : this.key;
+
+ if (this.op) {
+ value += this.op;
+ value += (this.value.toCSS ? this.value.toCSS(env) : this.value);
+ }
+
+ return '[' + value + ']';
+ }
+};
+
+tree.Combinator = function (value) {
+ if (value === ' ') {
+ this.value = ' ';
+ } else {
+ this.value = value ? value.trim() : "";
+ }
+};
+tree.Combinator.prototype = {
+ type: "Combinator",
+ _outputMap: {
+ '' : '',
+ ' ' : ' ',
+ ':' : ' :',
+ '+' : ' + ',
+ '~' : ' ~ ',
+ '>' : ' > ',
+ '|' : '|'
+ },
+ _outputMapCompressed: {
+ '' : '',
+ ' ' : ' ',
+ ':' : ' :',
+ '+' : '+',
+ '~' : '~',
+ '>' : '>',
+ '|' : '|'
+ },
+ genCSS: function (env, output) {
+ output.add((env.compress ? this._outputMapCompressed : this._outputMap)[this.value]);
+ },
+ toCSS: tree.toCSS
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Expression = function (value) { this.value = value; };
+tree.Expression.prototype = {
+ type: "Expression",
+ accept: function (visitor) {
+ this.value = visitor.visit(this.value);
+ },
+ eval: function (env) {
+ var returnValue,
+ inParenthesis = this.parens && !this.parensInOp,
+ doubleParen = false;
+ if (inParenthesis) {
+ env.inParenthesis();
+ }
+ if (this.value.length > 1) {
+ returnValue = new(tree.Expression)(this.value.map(function (e) {
+ return e.eval(env);
+ }));
+ } else if (this.value.length === 1) {
+ if (this.value[0].parens && !this.value[0].parensInOp) {
+ doubleParen = true;
+ }
+ returnValue = this.value[0].eval(env);
+ } else {
+ returnValue = this;
+ }
+ if (inParenthesis) {
+ env.outOfParenthesis();
+ }
+ if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) {
+ returnValue = new(tree.Paren)(returnValue);
+ }
+ return returnValue;
+ },
+ genCSS: function (env, output) {
+ for(var i = 0; i < this.value.length; i++) {
+ this.value[i].genCSS(env, output);
+ if (i + 1 < this.value.length) {
+ output.add(" ");
+ }
+ }
+ },
+ toCSS: tree.toCSS,
+ throwAwayComments: function () {
+ this.value = this.value.filter(function(v) {
+ return !(v instanceof tree.Comment);
+ });
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Extend = function Extend(selector, option, index) {
+ this.selector = selector;
+ this.option = option;
+ this.index = index;
+
+ switch(option) {
+ case "all":
+ this.allowBefore = true;
+ this.allowAfter = true;
+ break;
+ default:
+ this.allowBefore = false;
+ this.allowAfter = false;
+ break;
+ }
+};
+
+tree.Extend.prototype = {
+ type: "Extend",
+ accept: function (visitor) {
+ this.selector = visitor.visit(this.selector);
+ },
+ eval: function (env) {
+ return new(tree.Extend)(this.selector.eval(env), this.option, this.index);
+ },
+ clone: function (env) {
+ return new(tree.Extend)(this.selector, this.option, this.index);
+ },
+ findSelfSelectors: function (selectors) {
+ var selfElements = [],
+ i,
+ selectorElements;
+
+ for(i = 0; i < selectors.length; i++) {
+ selectorElements = selectors[i].elements;
+ // duplicate the logic in genCSS function inside the selector node.
+ // future TODO - move both logics into the selector joiner visitor
+ if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === "") {
+ selectorElements[0].combinator.value = ' ';
+ }
+ selfElements = selfElements.concat(selectors[i].elements);
+ }
+
+ this.selfSelectors = [{ elements: selfElements }];
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+//
+// CSS @import node
+//
+// The general strategy here is that we don't want to wait
+// for the parsing to be completed, before we start importing
+// the file. That's because in the context of a browser,
+// most of the time will be spent waiting for the server to respond.
+//
+// On creation, we push the import path to our import queue, though
+// `import,push`, we also pass it a callback, which it'll call once
+// the file has been fetched, and parsed.
+//
+tree.Import = function (path, features, options, index, currentFileInfo) {
+ this.options = options;
+ this.index = index;
+ this.path = path;
+ this.features = features;
+ this.currentFileInfo = currentFileInfo;
+
+ if (this.options.less !== undefined || this.options.inline) {
+ this.css = !this.options.less || this.options.inline;
+ } else {
+ var pathValue = this.getPath();
+ if (pathValue && /css([\?;].*)?$/.test(pathValue)) {
+ this.css = true;
+ }
+ }
+};
+
+//
+// The actual import node doesn't return anything, when converted to CSS.
+// The reason is that it's used at the evaluation stage, so that the rules
+// it imports can be treated like any other rules.
+//
+// In `eval`, we make sure all Import nodes get evaluated, recursively, so
+// we end up with a flat structure, which can easily be imported in the parent
+// ruleset.
+//
+tree.Import.prototype = {
+ type: "Import",
+ accept: function (visitor) {
+ this.features = visitor.visit(this.features);
+ this.path = visitor.visit(this.path);
+ if (!this.options.inline) {
+ this.root = visitor.visit(this.root);
+ }
+ },
+ genCSS: function (env, output) {
+ if (this.css) {
+ output.add("@import ", this.currentFileInfo, this.index);
+ this.path.genCSS(env, output);
+ if (this.features) {
+ output.add(" ");
+ this.features.genCSS(env, output);
+ }
+ output.add(';');
+ }
+ },
+ toCSS: tree.toCSS,
+ getPath: function () {
+ if (this.path instanceof tree.Quoted) {
+ var path = this.path.value;
+ return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less';
+ } else if (this.path instanceof tree.URL) {
+ return this.path.value.value;
+ }
+ return null;
+ },
+ evalForImport: function (env) {
+ return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo);
+ },
+ evalPath: function (env) {
+ var path = this.path.eval(env);
+ var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
+
+ if (!(path instanceof tree.URL)) {
+ if (rootpath) {
+ var pathValue = path.value;
+ // Add the base path if the import is relative
+ if (pathValue && env.isPathRelative(pathValue)) {
+ path.value = rootpath + pathValue;
+ }
+ }
+ path.value = env.normalizePath(path.value);
+ }
+
+ return path;
+ },
+ eval: function (env) {
+ var ruleset, features = this.features && this.features.eval(env);
+
+ if (this.skip) { return []; }
+
+ if (this.options.inline) {
+ //todo needs to reference css file not import
+ var contents = new(tree.Anonymous)(this.root, 0, {filename: this.importedFilename}, true);
+ return this.features ? new(tree.Media)([contents], this.features.value) : [contents];
+ } else if (this.css) {
+ var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index);
+ if (!newImport.css && this.error) {
+ throw this.error;
+ }
+ return newImport;
+ } else {
+ ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
+
+ ruleset.evalImports(env);
+
+ return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
+ }
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.JavaScript = function (string, index, escaped) {
+ this.escaped = escaped;
+ this.expression = string;
+ this.index = index;
+};
+tree.JavaScript.prototype = {
+ type: "JavaScript",
+ eval: function (env) {
+ var result,
+ that = this,
+ context = {};
+
+ var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
+ return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
+ });
+
+ try {
+ expression = new(Function)('return (' + expression + ')');
+ } catch (e) {
+ throw { message: "JavaScript evaluation error: " + e.message + " from `" + expression + "`" ,
+ index: this.index };
+ }
+
+ for (var k in env.frames[0].variables()) {
+ /*jshint loopfunc:true */
+ context[k.slice(1)] = {
+ value: env.frames[0].variables()[k].value,
+ toJS: function () {
+ return this.value.eval(env).toCSS();
+ }
+ };
+ }
+
+ try {
+ result = expression.call(context);
+ } catch (e) {
+ throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
+ index: this.index };
+ }
+ if (typeof(result) === 'string') {
+ return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
+ } else if (Array.isArray(result)) {
+ return new(tree.Anonymous)(result.join(', '));
+ } else {
+ return new(tree.Anonymous)(result);
+ }
+ }
+};
+
+})(require('../tree'));
+
+
+(function (tree) {
+
+tree.Keyword = function (value) { this.value = value; };
+tree.Keyword.prototype = {
+ type: "Keyword",
+ eval: function () { return this; },
+ genCSS: function (env, output) {
+ output.add(this.value);
+ },
+ toCSS: tree.toCSS,
+ compare: function (other) {
+ if (other instanceof tree.Keyword) {
+ return other.value === this.value ? 0 : 1;
+ } else {
+ return -1;
+ }
+ }
+};
+
+tree.True = new(tree.Keyword)('true');
+tree.False = new(tree.Keyword)('false');
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Media = function (value, features, index, currentFileInfo) {
+ this.index = index;
+ this.currentFileInfo = currentFileInfo;
+
+ var selectors = this.emptySelectors();
+
+ this.features = new(tree.Value)(features);
+ this.rules = [new(tree.Ruleset)(selectors, value)];
+ this.rules[0].allowImports = true;
+};
+tree.Media.prototype = {
+ type: "Media",
+ accept: function (visitor) {
+ this.features = visitor.visit(this.features);
+ this.rules = visitor.visit(this.rules);
+ },
+ genCSS: function (env, output) {
+ output.add('@media ', this.currentFileInfo, this.index);
+ this.features.genCSS(env, output);
+ tree.outputRuleset(env, output, this.rules);
+ },
+ toCSS: tree.toCSS,
+ eval: function (env) {
+ if (!env.mediaBlocks) {
+ env.mediaBlocks = [];
+ env.mediaPath = [];
+ }
+
+ var media = new(tree.Media)([], [], this.index, this.currentFileInfo);
+ if(this.debugInfo) {
+ this.rules[0].debugInfo = this.debugInfo;
+ media.debugInfo = this.debugInfo;
+ }
+ var strictMathBypass = false;
+ if (!env.strictMath) {
+ strictMathBypass = true;
+ env.strictMath = true;
+ }
+ try {
+ media.features = this.features.eval(env);
+ }
+ finally {
+ if (strictMathBypass) {
+ env.strictMath = false;
+ }
+ }
+
+ env.mediaPath.push(media);
+ env.mediaBlocks.push(media);
+
+ env.frames.unshift(this.rules[0]);
+ media.rules = [this.rules[0].eval(env)];
+ env.frames.shift();
+
+ env.mediaPath.pop();
+
+ return env.mediaPath.length === 0 ? media.evalTop(env) :
+ media.evalNested(env);
+ },
+ variable: function (name) { return tree.Ruleset.prototype.variable.call(this.rules[0], name); },
+ find: function () { return tree.Ruleset.prototype.find.apply(this.rules[0], arguments); },
+ rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.rules[0]); },
+ emptySelectors: function() {
+ var el = new(tree.Element)('', '&', this.index, this.currentFileInfo);
+ return [new(tree.Selector)([el], null, null, this.index, this.currentFileInfo)];
+ },
+ markReferenced: function () {
+ var i, rules = this.rules[0].rules;
+ this.isReferenced = true;
+ for (i = 0; i < rules.length; i++) {
+ if (rules[i].markReferenced) {
+ rules[i].markReferenced();
+ }
+ }
+ },
+
+ evalTop: function (env) {
+ var result = this;
+
+ // Render all dependent Media blocks.
+ if (env.mediaBlocks.length > 1) {
+ var selectors = this.emptySelectors();
+ result = new(tree.Ruleset)(selectors, env.mediaBlocks);
+ result.multiMedia = true;
+ }
+
+ delete env.mediaBlocks;
+ delete env.mediaPath;
+
+ return result;
+ },
+ evalNested: function (env) {
+ var i, value,
+ path = env.mediaPath.concat([this]);
+
+ // Extract the media-query conditions separated with `,` (OR).
+ for (i = 0; i < path.length; i++) {
+ value = path[i].features instanceof tree.Value ?
+ path[i].features.value : path[i].features;
+ path[i] = Array.isArray(value) ? value : [value];
+ }
+
+ // Trace all permutations to generate the resulting media-query.
+ //
+ // (a, b and c) with nested (d, e) ->
+ // a and d
+ // a and e
+ // b and c and d
+ // b and c and e
+ this.features = new(tree.Value)(this.permute(path).map(function (path) {
+ path = path.map(function (fragment) {
+ return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
+ });
+
+ for(i = path.length - 1; i > 0; i--) {
+ path.splice(i, 0, new(tree.Anonymous)("and"));
+ }
+
+ return new(tree.Expression)(path);
+ }));
+
+ // Fake a tree-node that doesn't output anything.
+ return new(tree.Ruleset)([], []);
+ },
+ permute: function (arr) {
+ if (arr.length === 0) {
+ return [];
+ } else if (arr.length === 1) {
+ return arr[0];
+ } else {
+ var result = [];
+ var rest = this.permute(arr.slice(1));
+ for (var i = 0; i < rest.length; i++) {
+ for (var j = 0; j < arr[0].length; j++) {
+ result.push([arr[0][j]].concat(rest[i]));
+ }
+ }
+ return result;
+ }
+ },
+ bubbleSelectors: function (selectors) {
+ this.rules = [new(tree.Ruleset)(selectors.slice(0), [this.rules[0]])];
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.mixin = {};
+tree.mixin.Call = function (elements, args, index, currentFileInfo, important) {
+ this.selector = new(tree.Selector)(elements);
+ this.arguments = args;
+ this.index = index;
+ this.currentFileInfo = currentFileInfo;
+ this.important = important;
+};
+tree.mixin.Call.prototype = {
+ type: "MixinCall",
+ accept: function (visitor) {
+ this.selector = visitor.visit(this.selector);
+ this.arguments = visitor.visit(this.arguments);
+ },
+ eval: function (env) {
+ var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule;
+
+ args = this.arguments && this.arguments.map(function (a) {
+ return { name: a.name, value: a.value.eval(env) };
+ });
+
+ for (i = 0; i < env.frames.length; i++) {
+ if ((mixins = env.frames[i].find(this.selector)).length > 0) {
+ isOneFound = true;
+ for (m = 0; m < mixins.length; m++) {
+ mixin = mixins[m];
+ isRecursive = false;
+ for(f = 0; f < env.frames.length; f++) {
+ if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) {
+ isRecursive = true;
+ break;
+ }
+ }
+ if (isRecursive) {
+ continue;
+ }
+ if (mixin.matchArgs(args, env)) {
+ if (!mixin.matchCondition || mixin.matchCondition(args, env)) {
+ try {
+ if (!(mixin instanceof tree.mixin.Definition)) {
+ mixin = new tree.mixin.Definition("", [], mixin.rules, null, false);
+ mixin.originalRuleset = mixins[m].originalRuleset || mixins[m];
+ }
+ //if (this.important) {
+ // isImportant = env.isImportant;
+ // env.isImportant = true;
+ //}
+ Array.prototype.push.apply(
+ rules, mixin.eval(env, args, this.important).rules);
+ //if (this.important) {
+ // env.isImportant = isImportant;
+ //}
+ } catch (e) {
+ throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
+ }
+ }
+ match = true;
+ }
+ }
+ if (match) {
+ if (!this.currentFileInfo || !this.currentFileInfo.reference) {
+ for (i = 0; i < rules.length; i++) {
+ rule = rules[i];
+ if (rule.markReferenced) {
+ rule.markReferenced();
+ }
+ }
+ }
+ return rules;
+ }
+ }
+ }
+ if (isOneFound) {
+ throw { type: 'Runtime',
+ message: 'No matching definition was found for `' +
+ this.selector.toCSS().trim() + '(' +
+ (args ? args.map(function (a) {
+ var argValue = "";
+ if (a.name) {
+ argValue += a.name + ":";
+ }
+ if (a.value.toCSS) {
+ argValue += a.value.toCSS();
+ } else {
+ argValue += "???";
+ }
+ return argValue;
+ }).join(', ') : "") + ")`",
+ index: this.index, filename: this.currentFileInfo.filename };
+ } else {
+ throw { type: 'Name',
+ message: this.selector.toCSS().trim() + " is undefined",
+ index: this.index, filename: this.currentFileInfo.filename };
+ }
+ }
+};
+
+tree.mixin.Definition = function (name, params, rules, condition, variadic) {
+ this.name = name;
+ this.selectors = [new(tree.Selector)([new(tree.Element)(null, name, this.index, this.currentFileInfo)])];
+ this.params = params;
+ this.condition = condition;
+ this.variadic = variadic;
+ this.arity = params.length;
+ this.rules = rules;
+ this._lookups = {};
+ this.required = params.reduce(function (count, p) {
+ if (!p.name || (p.name && !p.value)) { return count + 1; }
+ else { return count; }
+ }, 0);
+ this.parent = tree.Ruleset.prototype;
+ this.frames = [];
+};
+tree.mixin.Definition.prototype = {
+ type: "MixinDefinition",
+ accept: function (visitor) {
+ this.params = visitor.visit(this.params);
+ this.rules = visitor.visit(this.rules);
+ this.condition = visitor.visit(this.condition);
+ },
+ variable: function (name) { return this.parent.variable.call(this, name); },
+ variables: function () { return this.parent.variables.call(this); },
+ find: function () { return this.parent.find.apply(this, arguments); },
+ rulesets: function () { return this.parent.rulesets.apply(this); },
+
+ evalParams: function (env, mixinEnv, args, evaldArguments) {
+ /*jshint boss:true */
+ var frame = new(tree.Ruleset)(null, []),
+ varargs, arg,
+ params = this.params.slice(0),
+ i, j, val, name, isNamedFound, argIndex;
+
+ mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
+
+ if (args) {
+ args = args.slice(0);
+
+ for(i = 0; i < args.length; i++) {
+ arg = args[i];
+ if (name = (arg && arg.name)) {
+ isNamedFound = false;
+ for(j = 0; j < params.length; j++) {
+ if (!evaldArguments[j] && name === params[j].name) {
+ evaldArguments[j] = arg.value.eval(env);
+ frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env)));
+ isNamedFound = true;
+ break;
+ }
+ }
+ if (isNamedFound) {
+ args.splice(i, 1);
+ i--;
+ continue;
+ } else {
+ throw { type: 'Runtime', message: "Named argument for " + this.name +
+ ' ' + args[i].name + ' not found' };
+ }
+ }
+ }
+ }
+ argIndex = 0;
+ for (i = 0; i < params.length; i++) {
+ if (evaldArguments[i]) { continue; }
+
+ arg = args && args[argIndex];
+
+ if (name = params[i].name) {
+ if (params[i].variadic && args) {
+ varargs = [];
+ for (j = argIndex; j < args.length; j++) {
+ varargs.push(args[j].value.eval(env));
+ }
+ frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
+ } else {
+ val = arg && arg.value;
+ if (val) {
+ val = val.eval(env);
+ } else if (params[i].value) {
+ val = params[i].value.eval(mixinEnv);
+ frame.resetCache();
+ } else {
+ throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
+ ' (' + args.length + ' for ' + this.arity + ')' };
+ }
+
+ frame.rules.unshift(new(tree.Rule)(name, val));
+ evaldArguments[i] = val;
+ }
+ }
+
+ if (params[i].variadic && args) {
+ for (j = argIndex; j < args.length; j++) {
+ evaldArguments[j] = args[j].value.eval(env);
+ }
+ }
+ argIndex++;
+ }
+
+ return frame;
+ },
+ eval: function (env, args, important) {
+ var _arguments = [],
+ mixinFrames = this.frames.concat(env.frames),
+ frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments),
+ rules, ruleset;
+
+ frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
+
+ rules = this.rules.slice(0);
+
+ ruleset = new(tree.Ruleset)(null, rules);
+ ruleset.originalRuleset = this;
+ ruleset = ruleset.eval(new(tree.evalEnv)(env, [this, frame].concat(mixinFrames)));
+ if (important) {
+ ruleset = this.parent.makeImportant.apply(ruleset);
+ }
+ return ruleset;
+ },
+ matchCondition: function (args, env) {
+ if (this.condition && !this.condition.eval(
+ new(tree.evalEnv)(env,
+ [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])] // the parameter variables
+ .concat(this.frames) // the parent namespace/mixin frames
+ .concat(env.frames)))) { // the current environment frames
+ return false;
+ }
+ return true;
+ },
+ matchArgs: function (args, env) {
+ var argsLength = (args && args.length) || 0, len;
+
+ if (! this.variadic) {
+ if (argsLength < this.required) { return false; }
+ if (argsLength > this.params.length) { return false; }
+ } else {
+ if (argsLength < (this.required - 1)) { return false; }
+ }
+
+ len = Math.min(argsLength, this.arity);
+
+ for (var i = 0; i < len; i++) {
+ if (!this.params[i].name && !this.params[i].variadic) {
+ if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Negative = function (node) {
+ this.value = node;
+};
+tree.Negative.prototype = {
+ type: "Negative",
+ accept: function (visitor) {
+ this.value = visitor.visit(this.value);
+ },
+ genCSS: function (env, output) {
+ output.add('-');
+ this.value.genCSS(env, output);
+ },
+ toCSS: tree.toCSS,
+ eval: function (env) {
+ if (env.isMathOn()) {
+ return (new(tree.Operation)('*', [new(tree.Dimension)(-1), this.value])).eval(env);
+ }
+ return new(tree.Negative)(this.value.eval(env));
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Operation = function (op, operands, isSpaced) {
+ this.op = op.trim();
+ this.operands = operands;
+ this.isSpaced = isSpaced;
+};
+tree.Operation.prototype = {
+ type: "Operation",
+ accept: function (visitor) {
+ this.operands = visitor.visit(this.operands);
+ },
+ eval: function (env) {
+ var a = this.operands[0].eval(env),
+ b = this.operands[1].eval(env),
+ temp;
+
+ if (env.isMathOn()) {
+ if (a instanceof tree.Dimension && b instanceof tree.Color) {
+ if (this.op === '*' || this.op === '+') {
+ temp = b, b = a, a = temp;
+ } else {
+ throw { type: "Operation",
+ message: "Can't substract or divide a color from a number" };
+ }
+ }
+ if (!a.operate) {
+ throw { type: "Operation",
+ message: "Operation on an invalid type" };
+ }
+
+ return a.operate(env, this.op, b);
+ } else {
+ return new(tree.Operation)(this.op, [a, b], this.isSpaced);
+ }
+ },
+ genCSS: function (env, output) {
+ this.operands[0].genCSS(env, output);
+ if (this.isSpaced) {
+ output.add(" ");
+ }
+ output.add(this.op);
+ if (this.isSpaced) {
+ output.add(" ");
+ }
+ this.operands[1].genCSS(env, output);
+ },
+ toCSS: tree.toCSS
+};
+
+tree.operate = function (env, op, a, b) {
+ switch (op) {
+ case '+': return a + b;
+ case '-': return a - b;
+ case '*': return a * b;
+ case '/': return a / b;
+ }
+};
+
+})(require('../tree'));
+
+
+(function (tree) {
+
+tree.Paren = function (node) {
+ this.value = node;
+};
+tree.Paren.prototype = {
+ type: "Paren",
+ accept: function (visitor) {
+ this.value = visitor.visit(this.value);
+ },
+ genCSS: function (env, output) {
+ output.add('(');
+ this.value.genCSS(env, output);
+ output.add(')');
+ },
+ toCSS: tree.toCSS,
+ eval: function (env) {
+ return new(tree.Paren)(this.value.eval(env));
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Quoted = function (str, content, escaped, index, currentFileInfo) {
+ this.escaped = escaped;
+ this.value = content || '';
+ this.quote = str.charAt(0);
+ this.index = index;
+ this.currentFileInfo = currentFileInfo;
+};
+tree.Quoted.prototype = {
+ type: "Quoted",
+ genCSS: function (env, output) {
+ if (!this.escaped) {
+ output.add(this.quote, this.currentFileInfo, this.index);
+ }
+ output.add(this.value);
+ if (!this.escaped) {
+ output.add(this.quote);
+ }
+ },
+ toCSS: tree.toCSS,
+ eval: function (env) {
+ var that = this;
+ var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
+ return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
+ }).replace(/@\{([\w-]+)\}/g, function (_, name) {
+ var v = new(tree.Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true);
+ return (v instanceof tree.Quoted) ? v.value : v.toCSS();
+ });
+ return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index, this.currentFileInfo);
+ },
+ compare: function (x) {
+ if (!x.toCSS) {
+ return -1;
+ }
+
+ var left = this.toCSS(),
+ right = x.toCSS();
+
+ if (left === right) {
+ return 0;
+ }
+
+ return left < right ? -1 : 1;
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Rule = function (name, value, important, merge, index, currentFileInfo, inline) {
+ this.name = name;
+ this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
+ this.important = important ? ' ' + important.trim() : '';
+ this.merge = merge;
+ this.index = index;
+ this.currentFileInfo = currentFileInfo;
+ this.inline = inline || false;
+ this.variable = (name.charAt(0) === '@');
+};
+
+tree.Rule.prototype = {
+ type: "Rule",
+ accept: function (visitor) {
+ this.value = visitor.visit(this.value);
+ },
+ genCSS: function (env, output) {
+ output.add(this.name + (env.compress ? ':' : ': '), this.currentFileInfo, this.index);
+ try {
+ this.value.genCSS(env, output);
+ }
+ catch(e) {
+ e.index = this.index;
+ e.filename = this.currentFileInfo.filename;
+ throw e;
+ }
+ output.add(this.important + ((this.inline || (env.lastRule && env.compress)) ? "" : ";"), this.currentFileInfo, this.index);
+ },
+ toCSS: tree.toCSS,
+ eval: function (env) {
+ var strictMathBypass = false;
+ if (this.name === "font" && !env.strictMath) {
+ strictMathBypass = true;
+ env.strictMath = true;
+ }
+ try {
+ return new(tree.Rule)(this.name,
+ this.value.eval(env),
+ this.important,
+ this.merge,
+ this.index, this.currentFileInfo, this.inline);
+ }
+ finally {
+ if (strictMathBypass) {
+ env.strictMath = false;
+ }
+ }
+ },
+ makeImportant: function () {
+ return new(tree.Rule)(this.name,
+ this.value,
+ "!important",
+ this.merge,
+ this.index, this.currentFileInfo, this.inline);
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Ruleset = function (selectors, rules, strictImports) {
+ this.selectors = selectors;
+ this.rules = rules;
+ this._lookups = {};
+ this.strictImports = strictImports;
+};
+tree.Ruleset.prototype = {
+ type: "Ruleset",
+ accept: function (visitor) {
+ if (this.paths) {
+ for(var i = 0; i < this.paths.length; i++) {
+ this.paths[i] = visitor.visit(this.paths[i]);
+ }
+ } else {
+ this.selectors = visitor.visit(this.selectors);
+ }
+ this.rules = visitor.visit(this.rules);
+ },
+ eval: function (env) {
+ var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env); });
+ var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
+ var rules;
+ var rule;
+ var i;
+
+ ruleset.originalRuleset = this;
+ ruleset.root = this.root;
+ ruleset.firstRoot = this.firstRoot;
+ ruleset.allowImports = this.allowImports;
+
+ if(this.debugInfo) {
+ ruleset.debugInfo = this.debugInfo;
+ }
+
+ // push the current ruleset to the frames stack
+ env.frames.unshift(ruleset);
+
+ // currrent selectors
+ if (!env.selectors) {
+ env.selectors = [];
+ }
+ env.selectors.unshift(this.selectors);
+
+ // Evaluate imports
+ if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
+ ruleset.evalImports(env);
+ }
+
+ // Store the frames around mixin definitions,
+ // so they can be evaluated like closures when the time comes.
+ for (i = 0; i < ruleset.rules.length; i++) {
+ if (ruleset.rules[i] instanceof tree.mixin.Definition) {
+ ruleset.rules[i].frames = env.frames.slice(0);
+ }
+ }
+
+ var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0;
+
+ // Evaluate mixin calls.
+ for (i = 0; i < ruleset.rules.length; i++) {
+ if (ruleset.rules[i] instanceof tree.mixin.Call) {
+ /*jshint loopfunc:true */
+ rules = ruleset.rules[i].eval(env).filter(function(r) {
+ if ((r instanceof tree.Rule) && r.variable) {
+ // do not pollute the scope if the variable is
+ // already there. consider returning false here
+ // but we need a way to "return" variable from mixins
+ return !(ruleset.variable(r.name));
+ }
+ return true;
+ });
+ ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules));
+ i += rules.length-1;
+ ruleset.resetCache();
+ }
+ }
+
+ // Evaluate everything else
+ for (i = 0; i < ruleset.rules.length; i++) {
+ rule = ruleset.rules[i];
+
+ if (! (rule instanceof tree.mixin.Definition)) {
+ ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
+ }
+ }
+
+ // Pop the stack
+ env.frames.shift();
+ env.selectors.shift();
+
+ if (env.mediaBlocks) {
+ for (i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
+ env.mediaBlocks[i].bubbleSelectors(selectors);
+ }
+ }
+
+ return ruleset;
+ },
+ evalImports: function(env) {
+ var i, rules;
+ for (i = 0; i < this.rules.length; i++) {
+ if (this.rules[i] instanceof tree.Import) {
+ rules = this.rules[i].eval(env);
+ if (typeof rules.length === "number") {
+ this.rules.splice.apply(this.rules, [i, 1].concat(rules));
+ i+= rules.length-1;
+ } else {
+ this.rules.splice(i, 1, rules);
+ }
+ this.resetCache();
+ }
+ }
+ },
+ makeImportant: function() {
+ return new tree.Ruleset(this.selectors, this.rules.map(function (r) {
+ if (r.makeImportant) {
+ return r.makeImportant();
+ } else {
+ return r;
+ }
+ }), this.strictImports);
+ },
+ matchArgs: function (args) {
+ return !args || args.length === 0;
+ },
+ matchCondition: function (args, env) {
+ var lastSelector = this.selectors[this.selectors.length-1];
+ if (lastSelector.condition &&
+ !lastSelector.condition.eval(
+ new(tree.evalEnv)(env,
+ env.frames))) {
+ return false;
+ }
+ return true;
+ },
+ resetCache: function () {
+ this._rulesets = null;
+ this._variables = null;
+ this._lookups = {};
+ },
+ variables: function () {
+ if (this._variables) { return this._variables; }
+ else {
+ return this._variables = this.rules.reduce(function (hash, r) {
+ if (r instanceof tree.Rule && r.variable === true) {
+ hash[r.name] = r;
+ }
+ return hash;
+ }, {});
+ }
+ },
+ variable: function (name) {
+ return this.variables()[name];
+ },
+ rulesets: function () {
+ return this.rules.filter(function (r) {
+ return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
+ });
+ },
+ find: function (selector, self) {
+ self = self || this;
+ var rules = [], match,
+ key = selector.toCSS();
+
+ if (key in this._lookups) { return this._lookups[key]; }
+
+ this.rulesets().forEach(function (rule) {
+ if (rule !== self) {
+ for (var j = 0; j < rule.selectors.length; j++) {
+ if (match = selector.match(rule.selectors[j])) {
+ if (selector.elements.length > match) {
+ Array.prototype.push.apply(rules, rule.find(
+ new(tree.Selector)(selector.elements.slice(match)), self));
+ } else {
+ rules.push(rule);
+ }
+ break;
+ }
+ }
+ }
+ });
+ return this._lookups[key] = rules;
+ },
+ genCSS: function (env, output) {
+ var i, j,
+ ruleNodes = [],
+ rulesetNodes = [],
+ debugInfo, // Line number debugging
+ rule,
+ firstRuleset = true,
+ path;
+
+ env.tabLevel = (env.tabLevel || 0);
+
+ if (!this.root) {
+ env.tabLevel++;
+ }
+
+ var tabRuleStr = env.compress ? '' : Array(env.tabLevel + 1).join(" "),
+ tabSetStr = env.compress ? '' : Array(env.tabLevel).join(" ");
+
+ for (i = 0; i < this.rules.length; i++) {
+ rule = this.rules[i];
+ if (rule.rules || (rule instanceof tree.Media) || rule instanceof tree.Directive || (this.root && rule instanceof tree.Comment)) {
+ rulesetNodes.push(rule);
+ } else {
+ ruleNodes.push(rule);
+ }
+ }
+
+ // If this is the root node, we don't render
+ // a selector, or {}.
+ if (!this.root) {
+ debugInfo = tree.debugInfo(env, this, tabSetStr);
+
+ if (debugInfo) {
+ output.add(debugInfo);
+ output.add(tabSetStr);
+ }
+
+ for(i = 0; i < this.paths.length; i++) {
+ path = this.paths[i];
+ env.firstSelector = true;
+ for(j = 0; j < path.length; j++) {
+ path[j].genCSS(env, output);
+ env.firstSelector = false;
+ }
+ if (i + 1 < this.paths.length) {
+ output.add(env.compress ? ',' : (',\n' + tabSetStr));
+ }
+ }
+
+ output.add((env.compress ? '{' : ' {\n') + tabRuleStr);
+ }
+
+ // Compile rules and rulesets
+ for (i = 0; i < ruleNodes.length; i++) {
+ rule = ruleNodes[i];
+
+ // @page{ directive ends up with root elements inside it, a mix of rules and rulesets
+ // In this instance we do not know whether it is the last property
+ if (i + 1 === ruleNodes.length && (!this.root || rulesetNodes.length === 0 || this.firstRoot)) {
+ env.lastRule = true;
+ }
+
+ if (rule.genCSS) {
+ rule.genCSS(env, output);
+ } else if (rule.value) {
+ output.add(rule.value.toString());
+ }
+
+ if (!env.lastRule) {
+ output.add(env.compress ? '' : ('\n' + tabRuleStr));
+ } else {
+ env.lastRule = false;
+ }
+ }
+
+ if (!this.root) {
+ output.add((env.compress ? '}' : '\n' + tabSetStr + '}'));
+ env.tabLevel--;
+ }
+
+ for (i = 0; i < rulesetNodes.length; i++) {
+ if (ruleNodes.length && firstRuleset) {
+ output.add((env.compress ? "" : "\n") + (this.root ? tabRuleStr : tabSetStr));
+ }
+ if (!firstRuleset) {
+ output.add((env.compress ? "" : "\n") + (this.root ? tabRuleStr : tabSetStr));
+ }
+ firstRuleset = false;
+ rulesetNodes[i].genCSS(env, output);
+ }
+
+ if (!output.isEmpty() && !env.compress && this.firstRoot) {
+ output.add('\n');
+ }
+ },
+
+ toCSS: tree.toCSS,
+
+ markReferenced: function () {
+ for (var s = 0; s < this.selectors.length; s++) {
+ this.selectors[s].markReferenced();
+ }
+ },
+
+ joinSelectors: function (paths, context, selectors) {
+ for (var s = 0; s < selectors.length; s++) {
+ this.joinSelector(paths, context, selectors[s]);
+ }
+ },
+
+ joinSelector: function (paths, context, selector) {
+
+ var i, j, k,
+ hasParentSelector, newSelectors, el, sel, parentSel,
+ newSelectorPath, afterParentJoin, newJoinedSelector,
+ newJoinedSelectorEmpty, lastSelector, currentElements,
+ selectorsMultiplied;
+
+ for (i = 0; i < selector.elements.length; i++) {
+ el = selector.elements[i];
+ if (el.value === '&') {
+ hasParentSelector = true;
+ }
+ }
+
+ if (!hasParentSelector) {
+ if (context.length > 0) {
+ for (i = 0; i < context.length; i++) {
+ paths.push(context[i].concat(selector));
+ }
+ }
+ else {
+ paths.push([selector]);
+ }
+ return;
+ }
+
+ // The paths are [[Selector]]
+ // The first list is a list of comma seperated selectors
+ // The inner list is a list of inheritance seperated selectors
+ // e.g.
+ // .a, .b {
+ // .c {
+ // }
+ // }
+ // == [[.a] [.c]] [[.b] [.c]]
+ //
+
+ // the elements from the current selector so far
+ currentElements = [];
+ // the current list of new selectors to add to the path.
+ // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
+ // by the parents
+ newSelectors = [[]];
+
+ for (i = 0; i < selector.elements.length; i++) {
+ el = selector.elements[i];
+ // non parent reference elements just get added
+ if (el.value !== "&") {
+ currentElements.push(el);
+ } else {
+ // the new list of selectors to add
+ selectorsMultiplied = [];
+
+ // merge the current list of non parent selector elements
+ // on to the current list of selectors to add
+ if (currentElements.length > 0) {
+ this.mergeElementsOnToSelectors(currentElements, newSelectors);
+ }
+
+ // loop through our current selectors
+ for (j = 0; j < newSelectors.length; j++) {
+ sel = newSelectors[j];
+ // if we don't have any parent paths, the & might be in a mixin so that it can be used
+ // whether there are parents or not
+ if (context.length === 0) {
+ // the combinator used on el should now be applied to the next element instead so that
+ // it is not lost
+ if (sel.length > 0) {
+ sel[0].elements = sel[0].elements.slice(0);
+ sel[0].elements.push(new(tree.Element)(el.combinator, '', 0, el.index, el.currentFileInfo));
+ }
+ selectorsMultiplied.push(sel);
+ }
+ else {
+ // and the parent selectors
+ for (k = 0; k < context.length; k++) {
+ parentSel = context[k];
+ // We need to put the current selectors
+ // then join the last selector's elements on to the parents selectors
+
+ // our new selector path
+ newSelectorPath = [];
+ // selectors from the parent after the join
+ afterParentJoin = [];
+ newJoinedSelectorEmpty = true;
+
+ //construct the joined selector - if & is the first thing this will be empty,
+ // if not newJoinedSelector will be the last set of elements in the selector
+ if (sel.length > 0) {
+ newSelectorPath = sel.slice(0);
+ lastSelector = newSelectorPath.pop();
+ newJoinedSelector = selector.createDerived(lastSelector.elements.slice(0));
+ newJoinedSelectorEmpty = false;
+ }
+ else {
+ newJoinedSelector = selector.createDerived([]);
+ }
+
+ //put together the parent selectors after the join
+ if (parentSel.length > 1) {
+ afterParentJoin = afterParentJoin.concat(parentSel.slice(1));
+ }
+
+ if (parentSel.length > 0) {
+ newJoinedSelectorEmpty = false;
+
+ // join the elements so far with the first part of the parent
+ newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, el.index, el.currentFileInfo));
+ newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));
+ }
+
+ if (!newJoinedSelectorEmpty) {
+ // now add the joined selector
+ newSelectorPath.push(newJoinedSelector);
+ }
+
+ // and the rest of the parent
+ newSelectorPath = newSelectorPath.concat(afterParentJoin);
+
+ // add that to our new set of selectors
+ selectorsMultiplied.push(newSelectorPath);
+ }
+ }
+ }
+
+ // our new selectors has been multiplied, so reset the state
+ newSelectors = selectorsMultiplied;
+ currentElements = [];
+ }
+ }
+
+ // if we have any elements left over (e.g. .a& .b == .b)
+ // add them on to all the current selectors
+ if (currentElements.length > 0) {
+ this.mergeElementsOnToSelectors(currentElements, newSelectors);
+ }
+
+ for (i = 0; i < newSelectors.length; i++) {
+ if (newSelectors[i].length > 0) {
+ paths.push(newSelectors[i]);
+ }
+ }
+ },
+
+ mergeElementsOnToSelectors: function(elements, selectors) {
+ var i, sel;
+
+ if (selectors.length === 0) {
+ selectors.push([ new(tree.Selector)(elements) ]);
+ return;
+ }
+
+ for (i = 0; i < selectors.length; i++) {
+ sel = selectors[i];
+
+ // if the previous thing in sel is a parent this needs to join on to it
+ if (sel.length > 0) {
+ sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
+ }
+ else {
+ sel.push(new(tree.Selector)(elements));
+ }
+ }
+ }
+};
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Selector = function (elements, extendList, condition, index, currentFileInfo, isReferenced) {
+ this.elements = elements;
+ this.extendList = extendList || [];
+ this.condition = condition;
+ this.currentFileInfo = currentFileInfo || {};
+ this.isReferenced = isReferenced;
+ if (!condition) {
+ this.evaldCondition = true;
+ }
+};
+tree.Selector.prototype = {
+ type: "Selector",
+ accept: function (visitor) {
+ this.elements = visitor.visit(this.elements);
+ this.extendList = visitor.visit(this.extendList);
+ this.condition = visitor.visit(this.condition);
+ },
+ createDerived: function(elements, extendList, evaldCondition) {
+ /*jshint eqnull:true */
+ evaldCondition = evaldCondition != null ? evaldCondition : this.evaldCondition;
+ var newSelector = new(tree.Selector)(elements, extendList || this.extendList, this.condition, this.index, this.currentFileInfo, this.isReferenced);
+ newSelector.evaldCondition = evaldCondition;
+ return newSelector;
+ },
+ match: function (other) {
+ var elements = this.elements,
+ len = elements.length,
+ oelements, olen, max, i;
+
+ oelements = other.elements.slice(
+ (other.elements.length && other.elements[0].value === "&") ? 1 : 0);
+ olen = oelements.length;
+ max = Math.min(len, olen);
+
+ if (olen === 0 || len < olen) {
+ return 0;
+ } else {
+ for (i = 0; i < max; i++) {
+ if (elements[i].value !== oelements[i].value) {
+ return 0;
+ }
+ }
+ }
+ return max; // return number of matched selectors
+ },
+ eval: function (env) {
+ var evaldCondition = this.condition && this.condition.eval(env);
+
+ return this.createDerived(this.elements.map(function (e) {
+ return e.eval(env);
+ }), this.extendList.map(function(extend) {
+ return extend.eval(env);
+ }), evaldCondition);
+ },
+ genCSS: function (env, output) {
+ var i, element;
+ if ((!env || !env.firstSelector) && this.elements[0].combinator.value === "") {
+ output.add(' ', this.currentFileInfo, this.index);
+ }
+ if (!this._css) {
+ //TODO caching? speed comparison?
+ for(i = 0; i < this.elements.length; i++) {
+ element = this.elements[i];
+ element.genCSS(env, output);
+ }
+ }
+ },
+ toCSS: tree.toCSS,
+ markReferenced: function () {
+ this.isReferenced = true;
+ },
+ getIsReferenced: function() {
+ return !this.currentFileInfo.reference || this.isReferenced;
+ },
+ getIsOutput: function() {
+ return this.evaldCondition;
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.UnicodeDescriptor = function (value) {
+ this.value = value;
+};
+tree.UnicodeDescriptor.prototype = {
+ type: "UnicodeDescriptor",
+ genCSS: function (env, output) {
+ output.add(this.value);
+ },
+ toCSS: tree.toCSS,
+ eval: function () { return this; }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.URL = function (val, currentFileInfo) {
+ this.value = val;
+ this.currentFileInfo = currentFileInfo;
+};
+tree.URL.prototype = {
+ type: "Url",
+ accept: function (visitor) {
+ this.value = visitor.visit(this.value);
+ },
+ genCSS: function (env, output) {
+ output.add("url(");
+ this.value.genCSS(env, output);
+ output.add(")");
+ },
+ toCSS: tree.toCSS,
+ eval: function (ctx) {
+ var val = this.value.eval(ctx), rootpath;
+
+ // Add the base path if the URL is relative
+ rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
+ if (rootpath && typeof val.value === "string" && ctx.isPathRelative(val.value)) {
+ if (!val.quote) {
+ rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; });
+ }
+ val.value = rootpath + val.value;
+ }
+
+ val.value = ctx.normalizePath(val.value);
+
+ return new(tree.URL)(val, null);
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Value = function (value) {
+ this.value = value;
+};
+tree.Value.prototype = {
+ type: "Value",
+ accept: function (visitor) {
+ this.value = visitor.visit(this.value);
+ },
+ eval: function (env) {
+ if (this.value.length === 1) {
+ return this.value[0].eval(env);
+ } else {
+ return new(tree.Value)(this.value.map(function (v) {
+ return v.eval(env);
+ }));
+ }
+ },
+ genCSS: function (env, output) {
+ var i;
+ for(i = 0; i < this.value.length; i++) {
+ this.value[i].genCSS(env, output);
+ if (i+1 < this.value.length) {
+ output.add((env && env.compress) ? ',' : ', ');
+ }
+ }
+ },
+ toCSS: tree.toCSS
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+tree.Variable = function (name, index, currentFileInfo) {
+ this.name = name;
+ this.index = index;
+ this.currentFileInfo = currentFileInfo;
+};
+tree.Variable.prototype = {
+ type: "Variable",
+ eval: function (env) {
+ var variable, v, name = this.name;
+
+ if (name.indexOf('@@') === 0) {
+ name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
+ }
+
+ if (this.evaluating) {
+ throw { type: 'Name',
+ message: "Recursive variable definition for " + name,
+ filename: this.currentFileInfo.file,
+ index: this.index };
+ }
+
+ this.evaluating = true;
+
+ if (variable = tree.find(env.frames, function (frame) {
+ if (v = frame.variable(name)) {
+ return v.value.eval(env);
+ }
+ })) {
+ this.evaluating = false;
+ return variable;
+ }
+ else {
+ throw { type: 'Name',
+ message: "variable " + name + " is undefined",
+ filename: this.currentFileInfo.filename,
+ index: this.index };
+ }
+ }
+};
+
+})(require('../tree'));
+
+(function (tree) {
+
+ var parseCopyProperties = [
+ 'paths', // option - unmodified - paths to search for imports on
+ 'optimization', // option - optimization level (for the chunker)
+ 'files', // list of files that have been imported, used for import-once
+ 'contents', // browser-only, contents of all the files
+ 'relativeUrls', // option - whether to adjust URL's to be relative
+ 'rootpath', // option - rootpath to append to URL's
+ 'strictImports', // option -
+ 'insecure', // option - whether to allow imports from insecure ssl hosts
+ 'dumpLineNumbers', // option - whether to dump line numbers
+ 'compress', // option - whether to compress
+ 'processImports', // option - whether to process imports. if false then imports will not be imported
+ 'syncImport', // option - whether to import synchronously
+ 'javascriptEnabled',// option - whether JavaScript is enabled. if undefined, defaults to true
+ 'mime', // browser only - mime type for sheet import
+ 'useFileCache', // browser only - whether to use the per file session cache
+ 'currentFileInfo' // information about the current file - for error reporting and importing and making urls relative etc.
+ ];
+
+ //currentFileInfo = {
+ // 'relativeUrls' - option - whether to adjust URL's to be relative
+ // 'filename' - full resolved filename of current file
+ // 'rootpath' - path to append to normal URLs for this node
+ // 'currentDirectory' - path to the current file, absolute
+ // 'rootFilename' - filename of the base file
+ // 'entryPath' - absolute path to the entry file
+ // 'reference' - whether the file should not be output and only output parts that are referenced
+
+ tree.parseEnv = function(options) {
+ copyFromOriginal(options, this, parseCopyProperties);
+
+ if (!this.contents) { this.contents = {}; }
+ if (!this.files) { this.files = {}; }
+
+ if (!this.currentFileInfo) {
+ var filename = (options && options.filename) || "input";
+ var entryPath = filename.replace(/[^\/\\]*$/, "");
+ if (options) {
+ options.filename = null;
+ }
+ this.currentFileInfo = {
+ filename: filename,
+ relativeUrls: this.relativeUrls,
+ rootpath: (options && options.rootpath) || "",
+ currentDirectory: entryPath,
+ entryPath: entryPath,
+ rootFilename: filename
+ };
+ }
+ };
+
+ var evalCopyProperties = [
+ 'silent', // whether to swallow errors and warnings
+ 'verbose', // whether to log more activity
+ 'compress', // whether to compress
+ 'yuicompress', // whether to compress with the outside tool yui compressor
+ 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
+ 'strictMath', // whether math has to be within parenthesis
+ 'strictUnits', // whether units need to evaluate correctly
+ 'cleancss', // whether to compress with clean-css
+ 'sourceMap', // whether to output a source map
+ 'importMultiple'// whether we are currently importing multiple copies
+ ];
+
+ tree.evalEnv = function(options, frames) {
+ copyFromOriginal(options, this, evalCopyProperties);
+
+ this.frames = frames || [];
+ };
+
+ tree.evalEnv.prototype.inParenthesis = function () {
+ if (!this.parensStack) {
+ this.parensStack = [];
+ }
+ this.parensStack.push(true);
+ };
+
+ tree.evalEnv.prototype.outOfParenthesis = function () {
+ this.parensStack.pop();
+ };
+
+ tree.evalEnv.prototype.isMathOn = function () {
+ return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
+ };
+
+ tree.evalEnv.prototype.isPathRelative = function (path) {
+ return !/^(?:[a-z-]+:|\/)/.test(path);
+ };
+
+ tree.evalEnv.prototype.normalizePath = function( path ) {
+ var
+ segments = path.split("/").reverse(),
+ segment;
+
+ path = [];
+ while (segments.length !== 0 ) {
+ segment = segments.pop();
+ switch( segment ) {
+ case ".":
+ break;
+ case "..":
+ if ((path.length === 0) || (path[path.length - 1] === "..")) {
+ path.push( segment );
+ } else {
+ path.pop();
+ }
+ break;
+ default:
+ path.push( segment );
+ break;
+ }
+ }
+
+ return path.join("/");
+ };
+
+ //todo - do the same for the toCSS env
+ //tree.toCSSEnv = function (options) {
+ //};
+
+ var copyFromOriginal = function(original, destination, propertiesToCopy) {
+ if (!original) { return; }
+
+ for(var i = 0; i < propertiesToCopy.length; i++) {
+ if (original.hasOwnProperty(propertiesToCopy[i])) {
+ destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
+ }
+ }
+ };
+
+})(require('./tree'));
+
+(function (tree) {
+
+ tree.visitor = function(implementation) {
+ this._implementation = implementation;
+ };
+
+ tree.visitor.prototype = {
+ visit: function(node) {
+
+ if (node instanceof Array) {
+ return this.visitArray(node);
+ }
+
+ if (!node || !node.type) {
+ return node;
+ }
+
+ var funcName = "visit" + node.type,
+ func = this._implementation[funcName],
+ visitArgs, newNode;
+ if (func) {
+ visitArgs = {visitDeeper: true};
+ newNode = func.call(this._implementation, node, visitArgs);
+ if (this._implementation.isReplacing) {
+ node = newNode;
+ }
+ }
+ if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) {
+ node.accept(this);
+ }
+ funcName = funcName + "Out";
+ if (this._implementation[funcName]) {
+ this._implementation[funcName](node);
+ }
+ return node;
+ },
+ visitArray: function(nodes) {
+ var i, newNodes = [];
+ for(i = 0; i < nodes.length; i++) {
+ var evald = this.visit(nodes[i]);
+ if (evald instanceof Array) {
+ evald = this.flatten(evald);
+ newNodes = newNodes.concat(evald);
+ } else {
+ newNodes.push(evald);
+ }
+ }
+ if (this._implementation.isReplacing) {
+ return newNodes;
+ }
+ return nodes;
+ },
+ doAccept: function (node) {
+ node.accept(this);
+ },
+ flatten: function(arr, master) {
+ return arr.reduce(this.flattenReduce.bind(this), master || []);
+ },
+ flattenReduce: function(sum, element) {
+ if (element instanceof Array) {
+ sum = this.flatten(element, sum);
+ } else {
+ sum.push(element);
+ }
+ return sum;
+ }
+ };
+
+})(require('./tree'));
+(function (tree) {
+ tree.importVisitor = function(importer, finish, evalEnv) {
+ this._visitor = new tree.visitor(this);
+ this._importer = importer;
+ this._finish = finish;
+ this.env = evalEnv || new tree.evalEnv();
+ this.importCount = 0;
+ };
+
+ tree.importVisitor.prototype = {
+ isReplacing: true,
+ run: function (root) {
+ var error;
+ try {
+ // process the contents
+ this._visitor.visit(root);
+ }
+ catch(e) {
+ error = e;
+ }
+
+ this.isFinished = true;
+
+ if (this.importCount === 0) {
+ this._finish(error);
+ }
+ },
+ visitImport: function (importNode, visitArgs) {
+ var importVisitor = this,
+ evaldImportNode,
+ inlineCSS = importNode.options.inline;
+
+ if (!importNode.css || inlineCSS) {
+
+ try {
+ evaldImportNode = importNode.evalForImport(this.env);
+ } catch(e){
+ if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
+ // attempt to eval properly and treat as css
+ importNode.css = true;
+ // if that fails, this error will be thrown
+ importNode.error = e;
+ }
+
+ if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {
+ importNode = evaldImportNode;
+ this.importCount++;
+ var env = new tree.evalEnv(this.env, this.env.frames.slice(0));
+
+ if (importNode.options.multiple) {
+ env.importMultiple = true;
+ }
+
+ this._importer.push(importNode.getPath(), importNode.currentFileInfo, importNode.options, function (e, root, imported, fullPath) {
+ if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
+
+ if (imported && !env.importMultiple) { importNode.skip = imported; }
+
+ var subFinish = function(e) {
+ importVisitor.importCount--;
+
+ if (importVisitor.importCount === 0 && importVisitor.isFinished) {
+ importVisitor._finish(e);
+ }
+ };
+
+ if (root) {
+ importNode.root = root;
+ importNode.importedFilename = fullPath;
+ if (!inlineCSS && !importNode.skip) {
+ new(tree.importVisitor)(importVisitor._importer, subFinish, env)
+ .run(root);
+ return;
+ }
+ }
+
+ subFinish();
+ });
+ }
+ }
+ visitArgs.visitDeeper = false;
+ return importNode;
+ },
+ visitRule: function (ruleNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ return ruleNode;
+ },
+ visitDirective: function (directiveNode, visitArgs) {
+ this.env.frames.unshift(directiveNode);
+ return directiveNode;
+ },
+ visitDirectiveOut: function (directiveNode) {
+ this.env.frames.shift();
+ },
+ visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
+ this.env.frames.unshift(mixinDefinitionNode);
+ return mixinDefinitionNode;
+ },
+ visitMixinDefinitionOut: function (mixinDefinitionNode) {
+ this.env.frames.shift();
+ },
+ visitRuleset: function (rulesetNode, visitArgs) {
+ this.env.frames.unshift(rulesetNode);
+ return rulesetNode;
+ },
+ visitRulesetOut: function (rulesetNode) {
+ this.env.frames.shift();
+ },
+ visitMedia: function (mediaNode, visitArgs) {
+ this.env.frames.unshift(mediaNode.ruleset);
+ return mediaNode;
+ },
+ visitMediaOut: function (mediaNode) {
+ this.env.frames.shift();
+ }
+ };
+
+})(require('./tree'));
+(function (tree) {
+ tree.joinSelectorVisitor = function() {
+ this.contexts = [[]];
+ this._visitor = new tree.visitor(this);
+ };
+
+ tree.joinSelectorVisitor.prototype = {
+ run: function (root) {
+ return this._visitor.visit(root);
+ },
+ visitRule: function (ruleNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+
+ visitRuleset: function (rulesetNode, visitArgs) {
+ var context = this.contexts[this.contexts.length - 1];
+ var paths = [];
+ this.contexts.push(paths);
+
+ if (! rulesetNode.root) {
+ rulesetNode.selectors = rulesetNode.selectors.filter(function(selector) { return selector.getIsOutput(); });
+ if (rulesetNode.selectors.length === 0) {
+ rulesetNode.rules.length = 0;
+ }
+ rulesetNode.joinSelectors(paths, context, rulesetNode.selectors);
+ rulesetNode.paths = paths;
+ }
+ },
+ visitRulesetOut: function (rulesetNode) {
+ this.contexts.length = this.contexts.length - 1;
+ },
+ visitMedia: function (mediaNode, visitArgs) {
+ var context = this.contexts[this.contexts.length - 1];
+ mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);
+ }
+ };
+
+})(require('./tree'));
+(function (tree) {
+ tree.toCSSVisitor = function(env) {
+ this._visitor = new tree.visitor(this);
+ this._env = env;
+ };
+
+ tree.toCSSVisitor.prototype = {
+ isReplacing: true,
+ run: function (root) {
+ return this._visitor.visit(root);
+ },
+
+ visitRule: function (ruleNode, visitArgs) {
+ if (ruleNode.variable) {
+ return [];
+ }
+ return ruleNode;
+ },
+
+ visitMixinDefinition: function (mixinNode, visitArgs) {
+ return [];
+ },
+
+ visitExtend: function (extendNode, visitArgs) {
+ return [];
+ },
+
+ visitComment: function (commentNode, visitArgs) {
+ if (commentNode.isSilent(this._env)) {
+ return [];
+ }
+ return commentNode;
+ },
+
+ visitMedia: function(mediaNode, visitArgs) {
+ mediaNode.accept(this._visitor);
+ visitArgs.visitDeeper = false;
+
+ if (!mediaNode.rules.length) {
+ return [];
+ }
+ return mediaNode;
+ },
+
+ visitDirective: function(directiveNode, visitArgs) {
+ if (directiveNode.currentFileInfo.reference && !directiveNode.isReferenced) {
+ return [];
+ }
+ if (directiveNode.name === "@charset") {
+ // Only output the debug info together with subsequent @charset definitions
+ // a comment (or @media statement) before the actual @charset directive would
+ // be considered illegal css as it has to be on the first line
+ if (this.charset) {
+ if (directiveNode.debugInfo) {
+ var comment = new tree.Comment("/* " + directiveNode.toCSS(this._env).replace(/\n/g, "")+" */\n");
+ comment.debugInfo = directiveNode.debugInfo;
+ return this._visitor.visit(comment);
+ }
+ return [];
+ }
+ this.charset = true;
+ }
+ return directiveNode;
+ },
+
+ checkPropertiesInRoot: function(rules) {
+ var ruleNode;
+ for(var i = 0; i < rules.length; i++) {
+ ruleNode = rules[i];
+ if (ruleNode instanceof tree.Rule && !ruleNode.variable) {
+ throw { message: "properties must be inside selector blocks, they cannot be in the root.",
+ index: ruleNode.index, filename: ruleNode.currentFileInfo ? ruleNode.currentFileInfo.filename : null};
+ }
+ }
+ },
+
+ visitRuleset: function (rulesetNode, visitArgs) {
+ var rule, rulesets = [];
+ if (rulesetNode.firstRoot) {
+ this.checkPropertiesInRoot(rulesetNode.rules);
+ }
+ if (! rulesetNode.root) {
+
+ rulesetNode.paths = rulesetNode.paths
+ .filter(function(p) {
+ var i;
+ if (p[0].elements[0].combinator.value === ' ') {
+ p[0].elements[0].combinator = new(tree.Combinator)('');
+ }
+ for(i = 0; i < p.length; i++) {
+ if (p[i].getIsReferenced() && p[i].getIsOutput()) {
+ return true;
+ }
+ return false;
+ }
+ });
+
+ // Compile rules and rulesets
+ for (var i = 0; i < rulesetNode.rules.length; i++) {
+ rule = rulesetNode.rules[i];
+
+ if (rule.rules) {
+ // visit because we are moving them out from being a child
+ rulesets.push(this._visitor.visit(rule));
+ rulesetNode.rules.splice(i, 1);
+ i--;
+ continue;
+ }
+ }
+ // accept the visitor to remove rules and refactor itself
+ // then we can decide now whether we want it or not
+ if (rulesetNode.rules.length > 0) {
+ rulesetNode.accept(this._visitor);
+ }
+ visitArgs.visitDeeper = false;
+
+ this._mergeRules(rulesetNode.rules);
+ this._removeDuplicateRules(rulesetNode.rules);
+
+ // now decide whether we keep the ruleset
+ if (rulesetNode.rules.length > 0 && rulesetNode.paths.length > 0) {
+ rulesets.splice(0, 0, rulesetNode);
+ }
+ } else {
+ rulesetNode.accept(this._visitor);
+ visitArgs.visitDeeper = false;
+ if (rulesetNode.firstRoot || rulesetNode.rules.length > 0) {
+ rulesets.splice(0, 0, rulesetNode);
+ }
+ }
+ if (rulesets.length === 1) {
+ return rulesets[0];
+ }
+ return rulesets;
+ },
+
+ _removeDuplicateRules: function(rules) {
+ // remove duplicates
+ var ruleCache = {},
+ ruleList, rule, i;
+ for(i = rules.length - 1; i >= 0 ; i--) {
+ rule = rules[i];
+ if (rule instanceof tree.Rule) {
+ if (!ruleCache[rule.name]) {
+ ruleCache[rule.name] = rule;
+ } else {
+ ruleList = ruleCache[rule.name];
+ if (ruleList instanceof tree.Rule) {
+ ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._env)];
+ }
+ var ruleCSS = rule.toCSS(this._env);
+ if (ruleList.indexOf(ruleCSS) !== -1) {
+ rules.splice(i, 1);
+ } else {
+ ruleList.push(ruleCSS);
+ }
+ }
+ }
+ }
+ },
+
+ _mergeRules: function (rules) {
+ var groups = {},
+ parts,
+ rule,
+ key;
+
+ for (var i = 0; i < rules.length; i++) {
+ rule = rules[i];
+
+ if ((rule instanceof tree.Rule) && rule.merge) {
+ key = [rule.name,
+ rule.important ? "!" : ""].join(",");
+
+ if (!groups[key]) {
+ parts = groups[key] = [];
+ } else {
+ rules.splice(i--, 1);
+ }
+
+ parts.push(rule);
+ }
+ }
+
+ Object.keys(groups).map(function (k) {
+ parts = groups[k];
+
+ if (parts.length > 1) {
+ rule = parts[0];
+
+ rule.value = new (tree.Value)(parts.map(function (p) {
+ return p.value;
+ }));
+ }
+ });
+ }
+ };
+
+})(require('./tree'));
+(function (tree) {
+ /*jshint loopfunc:true */
+
+ tree.extendFinderVisitor = function() {
+ this._visitor = new tree.visitor(this);
+ this.contexts = [];
+ this.allExtendsStack = [[]];
+ };
+
+ tree.extendFinderVisitor.prototype = {
+ run: function (root) {
+ root = this._visitor.visit(root);
+ root.allExtends = this.allExtendsStack[0];
+ return root;
+ },
+ visitRule: function (ruleNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitRuleset: function (rulesetNode, visitArgs) {
+
+ if (rulesetNode.root) {
+ return;
+ }
+
+ var i, j, extend, allSelectorsExtendList = [], extendList;
+
+ // get &:extend(.a); rules which apply to all selectors in this ruleset
+ for(i = 0; i < rulesetNode.rules.length; i++) {
+ if (rulesetNode.rules[i] instanceof tree.Extend) {
+ allSelectorsExtendList.push(rulesetNode.rules[i]);
+ rulesetNode.extendOnEveryPath = true;
+ }
+ }
+
+ // now find every selector and apply the extends that apply to all extends
+ // and the ones which apply to an individual extend
+ for(i = 0; i < rulesetNode.paths.length; i++) {
+ var selectorPath = rulesetNode.paths[i],
+ selector = selectorPath[selectorPath.length-1];
+ extendList = selector.extendList.slice(0).concat(allSelectorsExtendList).map(function(allSelectorsExtend) {
+ return allSelectorsExtend.clone();
+ });
+ for(j = 0; j < extendList.length; j++) {
+ this.foundExtends = true;
+ extend = extendList[j];
+ extend.findSelfSelectors(selectorPath);
+ extend.ruleset = rulesetNode;
+ if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
+ this.allExtendsStack[this.allExtendsStack.length-1].push(extend);
+ }
+ }
+
+ this.contexts.push(rulesetNode.selectors);
+ },
+ visitRulesetOut: function (rulesetNode) {
+ if (!rulesetNode.root) {
+ this.contexts.length = this.contexts.length - 1;
+ }
+ },
+ visitMedia: function (mediaNode, visitArgs) {
+ mediaNode.allExtends = [];
+ this.allExtendsStack.push(mediaNode.allExtends);
+ },
+ visitMediaOut: function (mediaNode) {
+ this.allExtendsStack.length = this.allExtendsStack.length - 1;
+ },
+ visitDirective: function (directiveNode, visitArgs) {
+ directiveNode.allExtends = [];
+ this.allExtendsStack.push(directiveNode.allExtends);
+ },
+ visitDirectiveOut: function (directiveNode) {
+ this.allExtendsStack.length = this.allExtendsStack.length - 1;
+ }
+ };
+
+ tree.processExtendsVisitor = function() {
+ this._visitor = new tree.visitor(this);
+ };
+
+ tree.processExtendsVisitor.prototype = {
+ run: function(root) {
+ var extendFinder = new tree.extendFinderVisitor();
+ extendFinder.run(root);
+ if (!extendFinder.foundExtends) { return root; }
+ root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
+ this.allExtendsStack = [root.allExtends];
+ return this._visitor.visit(root);
+ },
+ doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
+ //
+ // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
+ // the selector we would do normally, but we are also adding an extend with the same target selector
+ // this means this new extend can then go and alter other extends
+ //
+ // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
+ // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
+ // we look at each selector at a time, as is done in visitRuleset
+
+ var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend, newExtend;
+
+ iterationCount = iterationCount || 0;
+
+ //loop through comparing every extend with every target extend.
+ // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
+ // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
+ // and the second is the target.
+ // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
+ // case when processing media queries
+ for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){
+ for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){
+
+ extend = extendsList[extendIndex];
+ targetExtend = extendsListTarget[targetExtendIndex];
+
+ // look for circular references
+ if (this.inInheritanceChain(targetExtend, extend)) { continue; }
+
+ // find a match in the target extends self selector (the bit before :extend)
+ selectorPath = [targetExtend.selfSelectors[0]];
+ matches = extendVisitor.findMatch(extend, selectorPath);
+
+ if (matches.length) {
+
+ // we found a match, so for each self selector..
+ extend.selfSelectors.forEach(function(selfSelector) {
+
+ // process the extend as usual
+ newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector);
+
+ // but now we create a new extend from it
+ newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0);
+ newExtend.selfSelectors = newSelector;
+
+ // add the extend onto the list of extends for that selector
+ newSelector[newSelector.length-1].extendList = [newExtend];
+
+ // record that we need to add it.
+ extendsToAdd.push(newExtend);
+ newExtend.ruleset = targetExtend.ruleset;
+
+ //remember its parents for circular references
+ newExtend.parents = [targetExtend, extend];
+
+ // only process the selector once.. if we have :extend(.a,.b) then multiple
+ // extends will look at the same selector path, so when extending
+ // we know that any others will be duplicates in terms of what is added to the css
+ if (targetExtend.firstExtendOnThisSelectorPath) {
+ newExtend.firstExtendOnThisSelectorPath = true;
+ targetExtend.ruleset.paths.push(newSelector);
+ }
+ });
+ }
+ }
+ }
+
+ if (extendsToAdd.length) {
+ // try to detect circular references to stop a stack overflow.
+ // may no longer be needed.
+ this.extendChainCount++;
+ if (iterationCount > 100) {
+ var selectorOne = "{unable to calculate}";
+ var selectorTwo = "{unable to calculate}";
+ try
+ {
+ selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
+ selectorTwo = extendsToAdd[0].selector.toCSS();
+ }
+ catch(e) {}
+ throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"};
+ }
+
+ // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
+ return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1));
+ } else {
+ return extendsToAdd;
+ }
+ },
+ inInheritanceChain: function (possibleParent, possibleChild) {
+ if (possibleParent === possibleChild) {
+ return true;
+ }
+ if (possibleChild.parents) {
+ if (this.inInheritanceChain(possibleParent, possibleChild.parents[0])) {
+ return true;
+ }
+ if (this.inInheritanceChain(possibleParent, possibleChild.parents[1])) {
+ return true;
+ }
+ }
+ return false;
+ },
+ visitRule: function (ruleNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitSelector: function (selectorNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitRuleset: function (rulesetNode, visitArgs) {
+ if (rulesetNode.root) {
+ return;
+ }
+ var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this, selectorPath;
+
+ // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
+
+ for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
+ for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
+
+ selectorPath = rulesetNode.paths[pathIndex];
+
+ // extending extends happens initially, before the main pass
+ if (rulesetNode.extendOnEveryPath || selectorPath[selectorPath.length-1].extendList.length) { continue; }
+
+ matches = this.findMatch(allExtends[extendIndex], selectorPath);
+
+ if (matches.length) {
+
+ allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
+ selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector));
+ });
+ }
+ }
+ }
+ rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
+ },
+ findMatch: function (extend, haystackSelectorPath) {
+ //
+ // look through the haystack selector path to try and find the needle - extend.selector
+ // returns an array of selector matches that can then be replaced
+ //
+ var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement,
+ targetCombinator, i,
+ extendVisitor = this,
+ needleElements = extend.selector.elements,
+ potentialMatches = [], potentialMatch, matches = [];
+
+ // loop through the haystack elements
+ for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
+ hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
+
+ for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
+
+ haystackElement = hackstackSelector.elements[hackstackElementIndex];
+
+ // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
+ if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
+ potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator});
+ }
+
+ for(i = 0; i < potentialMatches.length; i++) {
+ potentialMatch = potentialMatches[i];
+
+ // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
+ // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
+ // what the resulting combinator will be
+ targetCombinator = haystackElement.combinator.value;
+ if (targetCombinator === '' && hackstackElementIndex === 0) {
+ targetCombinator = ' ';
+ }
+
+ // if we don't match, null our match to indicate failure
+ if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) ||
+ (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {
+ potentialMatch = null;
+ } else {
+ potentialMatch.matched++;
+ }
+
+ // if we are still valid and have finished, test whether we have elements after and whether these are allowed
+ if (potentialMatch) {
+ potentialMatch.finished = potentialMatch.matched === needleElements.length;
+ if (potentialMatch.finished &&
+ (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) {
+ potentialMatch = null;
+ }
+ }
+ // if null we remove, if not, we are still valid, so either push as a valid match or continue
+ if (potentialMatch) {
+ if (potentialMatch.finished) {
+ potentialMatch.length = needleElements.length;
+ potentialMatch.endPathIndex = haystackSelectorIndex;
+ potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match
+ potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again
+ matches.push(potentialMatch);
+ }
+ } else {
+ potentialMatches.splice(i, 1);
+ i--;
+ }
+ }
+ }
+ }
+ return matches;
+ },
+ isElementValuesEqual: function(elementValue1, elementValue2) {
+ if (typeof elementValue1 === "string" || typeof elementValue2 === "string") {
+ return elementValue1 === elementValue2;
+ }
+ if (elementValue1 instanceof tree.Attribute) {
+ if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {
+ return false;
+ }
+ if (!elementValue1.value || !elementValue2.value) {
+ if (elementValue1.value || elementValue2.value) {
+ return false;
+ }
+ return true;
+ }
+ elementValue1 = elementValue1.value.value || elementValue1.value;
+ elementValue2 = elementValue2.value.value || elementValue2.value;
+ return elementValue1 === elementValue2;
+ }
+ elementValue1 = elementValue1.value;
+ elementValue2 = elementValue2.value;
+ if (elementValue1 instanceof tree.Selector) {
+ if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
+ return false;
+ }
+ for(var i = 0; i currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
+ path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
+ currentSelectorPathElementIndex = 0;
+ currentSelectorPathIndex++;
+ }
+
+ newElements = selector.elements
+ .slice(currentSelectorPathElementIndex, match.index)
+ .concat([firstElement])
+ .concat(replacementSelector.elements.slice(1));
+
+ if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {
+ path[path.length - 1].elements =
+ path[path.length - 1].elements.concat(newElements);
+ } else {
+ path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
+
+ path.push(new tree.Selector(
+ newElements
+ ));
+ }
+ currentSelectorPathIndex = match.endPathIndex;
+ currentSelectorPathElementIndex = match.endPathElementIndex;
+ if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {
+ currentSelectorPathElementIndex = 0;
+ currentSelectorPathIndex++;
+ }
+ }
+
+ if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
+ path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
+ currentSelectorPathIndex++;
+ }
+
+ path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
+
+ return path;
+ },
+ visitRulesetOut: function (rulesetNode) {
+ },
+ visitMedia: function (mediaNode, visitArgs) {
+ var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
+ newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
+ this.allExtendsStack.push(newAllExtends);
+ },
+ visitMediaOut: function (mediaNode) {
+ this.allExtendsStack.length = this.allExtendsStack.length - 1;
+ },
+ visitDirective: function (directiveNode, visitArgs) {
+ var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
+ newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
+ this.allExtendsStack.push(newAllExtends);
+ },
+ visitDirectiveOut: function (directiveNode) {
+ this.allExtendsStack.length = this.allExtendsStack.length - 1;
+ }
+ };
+
+})(require('./tree'));
+
+(function (tree) {
+
+ tree.sourceMapOutput = function (options) {
+ this._css = [];
+ this._rootNode = options.rootNode;
+ this._writeSourceMap = options.writeSourceMap;
+ this._contentsMap = options.contentsMap;
+ this._sourceMapFilename = options.sourceMapFilename;
+ this._outputFilename = options.outputFilename;
+ this._sourceMapURL = options.sourceMapURL;
+ this._sourceMapBasepath = options.sourceMapBasepath;
+ this._sourceMapRootpath = options.sourceMapRootpath;
+ this._outputSourceFiles = options.outputSourceFiles;
+ this._sourceMapGeneratorConstructor = options.sourceMapGenerator || require("source-map").SourceMapGenerator;
+
+ if (this._sourceMapRootpath && this._sourceMapRootpath.charAt(this._sourceMapRootpath.length-1) !== '/') {
+ this._sourceMapRootpath += '/';
+ }
+
+ this._lineNumber = 0;
+ this._column = 0;
+ };
+
+ tree.sourceMapOutput.prototype.normalizeFilename = function(filename) {
+ if (this._sourceMapBasepath && filename.indexOf(this._sourceMapBasepath) === 0) {
+ filename = filename.substring(this._sourceMapBasepath.length);
+ if (filename.charAt(0) === '\\' || filename.charAt(0) === '/') {
+ filename = filename.substring(1);
+ }
+ }
+ return (this._sourceMapRootpath || "") + filename.replace(/\\/g, '/');
+ };
+
+ tree.sourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) {
+
+ //ignore adding empty strings
+ if (!chunk) {
+ return;
+ }
+
+ var lines,
+ sourceLines,
+ columns,
+ sourceColumns,
+ i;
+
+ if (fileInfo) {
+ var inputSource = this._contentsMap[fileInfo.filename].substring(0, index);
+ sourceLines = inputSource.split("\n");
+ sourceColumns = sourceLines[sourceLines.length-1];
+ }
+
+ lines = chunk.split("\n");
+ columns = lines[lines.length-1];
+
+ if (fileInfo) {
+ if (!mapLines) {
+ this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column},
+ original: { line: sourceLines.length, column: sourceColumns.length},
+ source: this.normalizeFilename(fileInfo.filename)});
+ } else {
+ for(i = 0; i < lines.length; i++) {
+ this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0},
+ original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0},
+ source: this.normalizeFilename(fileInfo.filename)});
+ }
+ }
+ }
+
+ if (lines.length === 1) {
+ this._column += columns.length;
+ } else {
+ this._lineNumber += lines.length - 1;
+ this._column = columns.length;
+ }
+
+ this._css.push(chunk);
+ };
+
+ tree.sourceMapOutput.prototype.isEmpty = function() {
+ return this._css.length === 0;
+ };
+
+ tree.sourceMapOutput.prototype.toCSS = function(env) {
+ this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null });
+
+ if (this._outputSourceFiles) {
+ for(var filename in this._contentsMap) {
+ this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), this._contentsMap[filename]);
+ }
+ }
+
+ this._rootNode.genCSS(env, this);
+
+ if (this._css.length > 0) {
+ var sourceMapURL,
+ sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON());
+
+ if (this._sourceMapURL) {
+ sourceMapURL = this._sourceMapURL;
+ } else if (this._sourceMapFilename) {
+ sourceMapURL = this.normalizeFilename(this._sourceMapFilename);
+ }
+
+ if (this._writeSourceMap) {
+ this._writeSourceMap(sourceMapContent);
+ } else {
+ sourceMapURL = "data:application/json," + encodeURIComponent(sourceMapContent);
+ }
+
+ if (sourceMapURL) {
+ this._css.push("/*# sourceMappingURL=" + sourceMapURL + " */");
+ }
+ }
+
+ return this._css.join('');
+ };
+
+})(require('./tree'));
+
+//
+// browser.js - client-side engine
+//
+/*global less, window, document, XMLHttpRequest, location */
+
+var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);
+
+less.env = less.env || (location.hostname == '127.0.0.1' ||
+ location.hostname == '0.0.0.0' ||
+ location.hostname == 'localhost' ||
+ (location.port &&
+ location.port.length > 0) ||
+ isFileProtocol ? 'development'
+ : 'production');
+
+var logLevel = {
+ info: 2,
+ errors: 1,
+ none: 0
+};
+
+// The amount of logging in the javascript console.
+// 2 - Information and errors
+// 1 - Errors
+// 0 - None
+// Defaults to 2
+less.logLevel = typeof(less.logLevel) != 'undefined' ? less.logLevel : logLevel.info;
+
+// Load styles asynchronously (default: false)
+//
+// This is set to `false` by default, so that the body
+// doesn't start loading before the stylesheets are parsed.
+// Setting this to `true` can result in flickering.
+//
+less.async = less.async || false;
+less.fileAsync = less.fileAsync || false;
+
+// Interval between watch polls
+less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
+
+//Setup user functions
+if (less.functions) {
+ for(var func in less.functions) {
+ less.tree.functions[func] = less.functions[func];
+ }
+}
+
+var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);
+if (dumpLineNumbers) {
+ less.dumpLineNumbers = dumpLineNumbers[1];
+}
+
+var typePattern = /^text\/(x-)?less$/;
+var cache = null;
+var fileCache = {};
+var varsPre = "";
+
+function log(str, level) {
+ if (less.env == 'development' && typeof(console) !== 'undefined' && less.logLevel >= level) {
+ console.log('less: ' + str);
+ }
+}
+
+function extractId(href) {
+ return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain
+ .replace(/^\//, '' ) // Remove root /
+ .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension
+ .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
+ .replace(/\./g, ':'); // Replace dots with colons(for valid id)
+}
+
+function errorConsole(e, rootHref) {
+ var template = '{line} {content}';
+ var filename = e.filename || rootHref;
+ var errors = [];
+ var content = (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
+ " in " + filename + " ";
+
+ var errorline = function (e, i, classname) {
+ if (e.extract[i] !== undefined) {
+ errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
+ .replace(/\{class\}/, classname)
+ .replace(/\{content\}/, e.extract[i]));
+ }
+ };
+
+ if (e.extract) {
+ errorline(e, 0, '');
+ errorline(e, 1, 'line');
+ errorline(e, 2, '');
+ content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n' +
+ errors.join('\n');
+ } else if (e.stack) {
+ content += e.stack;
+ }
+ log(content, logLevel.errors);
+}
+
+function createCSS(styles, sheet, lastModified) {
+ // Strip the query-string
+ var href = sheet.href || '';
+
+ // If there is no title set, use the filename, minus the extension
+ var id = 'less:' + (sheet.title || extractId(href));
+
+ // If this has already been inserted into the DOM, we may need to replace it
+ var oldCss = document.getElementById(id);
+ var keepOldCss = false;
+
+ // Create a new stylesheet node for insertion or (if necessary) replacement
+ var css = document.createElement('style');
+ css.setAttribute('type', 'text/css');
+ if (sheet.media) {
+ css.setAttribute('media', sheet.media);
+ }
+ css.id = id;
+
+ if (css.styleSheet) { // IE
+ try {
+ css.styleSheet.cssText = styles;
+ } catch (e) {
+ throw new(Error)("Couldn't reassign styleSheet.cssText.");
+ }
+ } else {
+ css.appendChild(document.createTextNode(styles));
+
+ // If new contents match contents of oldCss, don't replace oldCss
+ keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 &&
+ oldCss.firstChild.nodeValue === css.firstChild.nodeValue);
+ }
+
+ var head = document.getElementsByTagName('head')[0];
+
+ // If there is no oldCss, just append; otherwise, only append if we need
+ // to replace oldCss with an updated stylesheet
+ if (oldCss === null || keepOldCss === false) {
+ var nextEl = sheet && sheet.nextSibling || null;
+ if (nextEl) {
+ nextEl.parentNode.insertBefore(css, nextEl);
+ } else {
+ head.appendChild(css);
+ }
+ }
+ if (oldCss && keepOldCss === false) {
+ oldCss.parentNode.removeChild(oldCss);
+ }
+
+ // Don't update the local store if the file wasn't modified
+ if (lastModified && cache) {
+ log('saving ' + href + ' to cache.', logLevel.info);
+ try {
+ cache.setItem(href, styles);
+ cache.setItem(href + ':timestamp', lastModified);
+ } catch(e) {
+ //TODO - could do with adding more robust error handling
+ log('failed to save', logLevel.errors);
+ }
+ }
+}
+
+function errorHTML(e, rootHref) {
+ var id = 'less-error-message:' + extractId(rootHref || "");
+ var template = '