[Pkg-javascript-commits] [less.js] 63/285: untangle the mess of dependencies and remove all circular dependencies. Remove un-necessary dependency injection.
Jonas Smedegaard
dr at jones.dk
Mon Oct 26 23:23:38 UTC 2015
This is an automated email from the git hooks/post-receive script.
js pushed a commit to annotated tag v2.0.0
in repository less.js.
commit 16746e9b1eca8e5cbf0b2fb9f8e412a5ad26e95a
Author: Luke Page <luke.a.page at gmail.com>
Date: Sun Aug 24 17:55:46 2014 +0100
untangle the mess of dependencies and remove all circular dependencies. Remove un-necessary dependency injection.
---
lib/less/browser.js | 4 +-
lib/less/{tree => data}/unit-conversions.js | 0
lib/less/env.js | 257 ++++----
lib/less/functions/default.js | 44 +-
lib/less/functions/index.js | 6 +-
lib/less/functions/types.js | 5 +-
lib/less/non-node-index.js | 4 +-
lib/less/parser.js | 9 +-
lib/less/tree.js | 178 ++---
lib/less/tree/alpha.js | 43 +-
lib/less/tree/anonymous.js | 47 +-
lib/less/tree/assignment.js | 43 +-
lib/less/tree/attribute.js | 38 +-
lib/less/tree/call.js | 99 ++-
lib/less/tree/color.js | 283 ++++----
lib/less/tree/combinator.js | 25 +-
lib/less/tree/comment.js | 38 +-
lib/less/tree/condition.js | 74 ++-
lib/less/tree/debug-info.js | 34 +
lib/less/tree/detached-ruleset.js | 28 +-
lib/less/tree/dimension.js | 267 ++++----
lib/less/tree/directive.js | 143 ++--
lib/less/tree/element.js | 57 +-
lib/less/tree/expression.js | 93 ++-
lib/less/tree/extend.js | 54 +-
lib/less/tree/import.js | 147 ++---
lib/less/tree/javascript.js | 66 +-
lib/less/tree/js-eval-node.js | 53 ++
lib/less/tree/keyword.js | 36 +-
lib/less/tree/media.js | 270 ++++----
lib/less/tree/mixin-call.js | 235 +++----
lib/less/tree/mixin-definition.js | 254 ++++----
lib/less/tree/negative.js | 32 +-
lib/less/tree/node.js | 35 +
lib/less/tree/operation.js | 80 +--
lib/less/tree/paren.js | 26 +-
lib/less/tree/quoted.js | 84 ++-
lib/less/tree/rule.js | 137 ++--
lib/less/tree/ruleset-call.js | 19 +-
lib/less/tree/ruleset.js | 971 ++++++++++++++--------------
lib/less/tree/selector.js | 189 +++---
lib/less/tree/unicode-descriptor.js | 16 +-
lib/less/tree/unit.js | 209 +++---
lib/less/tree/url.js | 73 +--
lib/less/tree/value.js | 53 +-
lib/less/tree/variable.js | 65 +-
lib/less/visitor/import-visitor.js | 5 +-
47 files changed, 2434 insertions(+), 2494 deletions(-)
diff --git a/lib/less/browser.js b/lib/less/browser.js
index aed3d99..61d7691 100644
--- a/lib/less/browser.js
+++ b/lib/less/browser.js
@@ -309,7 +309,7 @@ function loadStyles(modifyVars) {
for (var i = 0; i < styles.length; i++) {
style = styles[i];
if (style.type.match(typePattern)) {
- var env = new less.tree.parseEnv(options),
+ var env = new less.contexts.parseEnv(options),
lessText = style.innerHTML || '';
env.filename = document.location.href.replace(/#.*$/, '');
@@ -340,7 +340,7 @@ function loadStyles(modifyVars) {
function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
- var env = new less.tree.parseEnv(options);
+ var env = new less.contexts.parseEnv(options);
env.mime = sheet.type;
if (modifyVars || options.globalVars) {
diff --git a/lib/less/tree/unit-conversions.js b/lib/less/data/unit-conversions.js
similarity index 100%
rename from lib/less/tree/unit-conversions.js
rename to lib/less/data/unit-conversions.js
diff --git a/lib/less/env.js b/lib/less/env.js
index aff2888..5df2cf8 100644
--- a/lib/less/env.js
+++ b/lib/less/env.js
@@ -1,138 +1,139 @@
-module.exports = function (tree) {
-
- var parseCopyProperties = [
- 'paths', // option - unmodified - paths to search for imports on
- 'files', // list of files that have been imported, used for import-once
- 'contents', // map - filename to contents of all the files
- 'contentsIgnoredChars', // map - filename to lines at the begining of each file to ignore
- '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
- 'chunkInput', // option - whether to chunk input. more performant but causes parse issues.
- '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.
- ];
+var contexts = {};
+module.exports = contexts;
- //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.contentsIgnoredChars) { this.contentsIgnoredChars = {}; }
- if (!this.files) { this.files = {}; }
-
- if (typeof this.paths === "string") { this.paths = [this.paths]; }
-
- 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
- 'urlArgs' // whether to add args into url tokens
- ];
-
- tree.evalEnv = function(options, frames) {
- copyFromOriginal(options, this, evalCopyProperties);
-
- this.frames = frames || [];
- };
-
- tree.evalEnv.prototype.inParenthesis = function () {
- if (!this.parensStack) {
- this.parensStack = [];
+var copyFromOriginal = function copyFromOriginal(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]];
}
- 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;
- }
+ }
+};
+
+var parseCopyProperties = [
+ 'paths', // option - unmodified - paths to search for imports on
+ 'files', // list of files that have been imported, used for import-once
+ 'contents', // map - filename to contents of all the files
+ 'contentsIgnoredChars', // map - filename to lines at the begining of each file to ignore
+ '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
+ 'chunkInput', // option - whether to chunk input. more performant but causes parse issues.
+ '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
+
+contexts.parseEnv = function(options) {
+ copyFromOriginal(options, this, parseCopyProperties);
+
+ if (!this.contents) { this.contents = {}; }
+ if (!this.contentsIgnoredChars) { this.contentsIgnoredChars = {}; }
+ if (!this.files) { this.files = {}; }
+
+ if (typeof this.paths === "string") { this.paths = [this.paths]; }
+
+ 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
+ };
+ }
+};
- return path.join("/");
- };
+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
+ 'urlArgs' // whether to add args into url tokens
+ ];
- //todo - do the same for the toCSS env
- //tree.toCSSEnv = function (options) {
- //};
+contexts.evalEnv = function(options, frames) {
+ copyFromOriginal(options, this, evalCopyProperties);
- var copyFromOriginal = function(original, destination, propertiesToCopy) {
- if (!original) { return; }
+ this.frames = frames || [];
+};
+
+contexts.evalEnv.prototype.inParenthesis = function () {
+ if (!this.parensStack) {
+ this.parensStack = [];
+ }
+ this.parensStack.push(true);
+};
- for(var i = 0; i < propertiesToCopy.length; i++) {
- if (original.hasOwnProperty(propertiesToCopy[i])) {
- destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
- }
+contexts.evalEnv.prototype.outOfParenthesis = function () {
+ this.parensStack.pop();
+};
+
+contexts.evalEnv.prototype.isMathOn = function () {
+ return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
+};
+
+contexts.evalEnv.prototype.isPathRelative = function (path) {
+ return !/^(?:[a-z-]+:|\/)/.test(path);
+};
+
+contexts.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) {
+//};
+
+
diff --git a/lib/less/functions/default.js b/lib/less/functions/default.js
index 6aa78aa..ee256c7 100644
--- a/lib/less/functions/default.js
+++ b/lib/less/functions/default.js
@@ -1,25 +1,23 @@
-module.exports = function(functions, tree) {
- var defaultFunc = {
- eval: function () {
- var v = this.value_, e = this.error_;
- if (e) {
- throw e;
- }
- if (v != null) {
- return v ? tree.True : tree.False;
- }
- },
- value: function (v) {
- this.value_ = v;
- },
- error: function (e) {
- this.error_ = e;
- },
- reset: function () {
- this.value_ = this.error_ = null;
- }
- };
+var Keyword = require("../tree/keyword.js");
- functions.functionRegistry.add("default", defaultFunc.eval.bind(defaultFunc));
- tree.defaultFunc = defaultFunc;
+var defaultFunc = {
+ eval: function () {
+ var v = this.value_, e = this.error_;
+ if (e) {
+ throw e;
+ }
+ if (v != null) {
+ return v ? Keyword.True : Keyword.False;
+ }
+ },
+ value: function (v) {
+ this.value_ = v;
+ },
+ error: function (e) {
+ this.error_ = e;
+ },
+ reset: function () {
+ this.value_ = this.error_ = null;
+ }
};
+module.exports = defaultFunc;
diff --git a/lib/less/functions/index.js b/lib/less/functions/index.js
index 36d7167..4600500 100644
--- a/lib/less/functions/index.js
+++ b/lib/less/functions/index.js
@@ -7,7 +7,11 @@ module.exports = function(less, tree) {
require("./color.js")(functions, tree);
require("./color-blending.js")(functions, tree);
require("./data-uri.js")(functions, tree, less);
- require("./default.js")(functions, tree);
+
+ var defaultFunc = require("./default.js");
+ functions.functionRegistry.add("default", defaultFunc.eval.bind(defaultFunc));
+ tree.defaultFunc = defaultFunc;
+
require("./math.js")(functions, tree);
require("./number.js")(functions, tree);
require("./string.js")(functions, tree);
diff --git a/lib/less/functions/types.js b/lib/less/functions/types.js
index 802d809..0473438 100644
--- a/lib/less/functions/types.js
+++ b/lib/less/functions/types.js
@@ -1,9 +1,10 @@
+var Keyword = require("../tree/keyword.js");
module.exports = function(functions, tree) {
var isa = function (n, Type) {
- return (n instanceof Type) ? tree.True : tree.False;
+ return (n instanceof Type) ? Keyword.True : Keyword.False;
},
isunit = function (n, unit) {
- return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? tree.True : tree.False;
+ return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? Keyword.True : Keyword.False;
};
functions.functionRegistry.addMultiple({
iscolor: function (n) {
diff --git a/lib/less/non-node-index.js b/lib/less/non-node-index.js
index c93846d..7a7e0f5 100644
--- a/lib/less/non-node-index.js
+++ b/lib/less/non-node-index.js
@@ -5,11 +5,11 @@ var less = {
}
};
-less.tree = (require('./tree'))(less, less.data);
+less.tree = require('./tree');
less.visitor = require('./visitor/index.js')(less, less.tree);
less.Parser = (require('./parser'))(less, less.tree, less.visitor);
less.functions = (require('./functions/index.js'))(less, less.tree);
-require('./env')(less.tree);
+less.contexts = require("./env.js");
less.tree.sourceMapOutput = require('./source-map-output.js')(less);
diff --git a/lib/less/parser.js b/lib/less/parser.js
index 05e0d6c..61fcd93 100644
--- a/lib/less/parser.js
+++ b/lib/less/parser.js
@@ -1,5 +1,6 @@
var chunker = require('./chunker.js');
var LessError = require('./less-error.js');
+var contexts = require("./env.js");
module.exports = function(less, tree, visitor) {
//
@@ -51,8 +52,8 @@ var Parser = function Parser(env) {
// 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);
+ if (!(env instanceof contexts.parseEnv)) {
+ env = new contexts.parseEnv(env);
}
var imports = this.imports = {
@@ -109,7 +110,7 @@ var Parser = function Parser(env) {
}
newFileInfo.filename = resolvedFilename;
- var newEnv = new tree.parseEnv(env);
+ var newEnv = new contexts.parseEnv(env);
newEnv.currentFileInfo = newFileInfo;
newEnv.processImports = false;
@@ -451,7 +452,7 @@ var Parser = function Parser(env) {
options = options || {};
var evaldRoot,
css,
- evalEnv = new tree.evalEnv(options);
+ evalEnv = new contexts.evalEnv(options);
//
// Allows setting variables with a hash, so:
diff --git a/lib/less/tree.js b/lib/less/tree.js
index b3d7b1c..ed72dc4 100644
--- a/lib/less/tree.js
+++ b/lib/less/tree.js
@@ -1,144 +1,40 @@
-module.exports = function (less, data) {
-
var 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++) {
- r = fun.call(obj, obj[i]);
- if (r) { 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(); }).join(', ') + ']';
- } else {
- return obj.toCSS();
- }
-};
-
-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) {
- var ruleCnt = rules.length, i;
- env.tabLevel = (env.tabLevel | 0) + 1;
-
- // Compressed
- if (env.compress) {
- output.add('{');
- for (i = 0; i < ruleCnt; i++) {
- rules[i].genCSS(env, output);
- }
- output.add('}');
- env.tabLevel--;
- return;
- }
-
- // Non-compressed
- var tabSetStr = '\n' + Array(env.tabLevel).join(" "), tabRuleStr = tabSetStr + " ";
- if (!ruleCnt) {
- output.add(" {" + tabSetStr + '}');
- } else {
- output.add(" {" + tabRuleStr);
- rules[0].genCSS(env, output);
- for (i = 1; i < ruleCnt; i++) {
- output.add(tabRuleStr);
- rules[i].genCSS(env, output);
- }
- output.add(tabSetStr + '}');
- }
-
- env.tabLevel--;
-};
-
-tree.Alpha = require('./tree/alpha')(tree);
-tree.Color = require('./tree/color')(data, tree);
-tree.Directive = require('./tree/directive')(tree);
-tree.DetachedRuleset = require('./tree/detached-ruleset')(tree);
-tree.Operation = require('./tree/operation')(tree);
-tree.Dimension = require('./tree/dimension')(tree, require('./tree/unit-conversions')); //todo move conversions
-tree.Unit = require('./tree/unit')(tree, require('./tree/unit-conversions'));
-tree.Keyword = require('./tree/keyword')(tree);
-tree.Variable = require('./tree/variable')(tree);
-tree.Ruleset = require('./tree/ruleset')(tree);
-tree.Element = require('./tree/element')(tree);
-tree.Attribute = require('./tree/attribute')(tree);
-tree.Combinator = require('./tree/combinator')(tree);
-tree.Selector = require('./tree/selector')(tree);
-tree.Quoted = require('./tree/quoted')(tree);
-tree.Expression = require('./tree/expression')(tree);
-tree.Rule = require('./tree/rule')(tree);
-tree.Call = require('./tree/call')(tree, less);
-tree.URL = require('./tree/url')(tree);
-tree.Import = require('./tree/import')(tree);
+tree.Alpha = require('./tree/alpha');
+tree.Color = require('./tree/color');
+tree.Directive = require('./tree/directive');
+tree.DetachedRuleset = require('./tree/detached-ruleset');
+tree.Operation = require('./tree/operation');
+tree.Dimension = require('./tree/dimension');
+tree.Unit = require('./tree/unit');
+tree.Keyword = require('./tree/keyword');
+tree.Variable = require('./tree/variable');
+tree.Ruleset = require('./tree/ruleset');
+tree.Element = require('./tree/element');
+tree.Attribute = require('./tree/attribute');
+tree.Combinator = require('./tree/combinator');
+tree.Selector = require('./tree/selector');
+tree.Quoted = require('./tree/quoted');
+tree.Expression = require('./tree/expression');
+tree.Rule = require('./tree/rule');
+tree.Call = require('./tree/call');
+tree.URL = require('./tree/url');
+tree.Import = require('./tree/import');
tree.mixin = {
- Call: require('./tree/mixin-call')(tree),
- Definition: require('./tree/mixin-definition')(tree)
-};
-tree.Comment = require('./tree/comment')(tree);
-tree.Anonymous = require('./tree/anonymous')(tree);
-tree.Value = require('./tree/value')(tree);
-tree.JavaScript = require('./tree/javascript')(tree);
-tree.Assignment = require('./tree/assignment')(tree);
-tree.Condition = require('./tree/condition')(tree);
-tree.Paren = require('./tree/paren')(tree);
-tree.Media = require('./tree/media')(tree);
-tree.UnicodeDescriptor = require('./tree/unicode-descriptor')(tree);
-tree.Negative = require('./tree/negative')(tree);
-tree.Extend = require('./tree/extend')(tree);
-tree.RulesetCall = require('./tree/ruleset-call')(tree);
-
-tree.fround = function(env, value) {
- var precision = env && env.numPrecision;
- //add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999....) are properly rounded...
- return (precision == null) ? value : Number((value + 2e-16).toFixed(precision));
-};
-
-return tree;
-
-};
+ Call: require('./tree/mixin-call'),
+ Definition: require('./tree/mixin-definition')
+};
+tree.Comment = require('./tree/comment');
+tree.Anonymous = require('./tree/anonymous');
+tree.Value = require('./tree/value');
+tree.JavaScript = require('./tree/javascript');
+tree.Assignment = require('./tree/assignment');
+tree.Condition = require('./tree/condition');
+tree.Paren = require('./tree/paren');
+tree.Media = require('./tree/media');
+tree.UnicodeDescriptor = require('./tree/unicode-descriptor');
+tree.Negative = require('./tree/negative');
+tree.Extend = require('./tree/extend');
+tree.RulesetCall = require('./tree/ruleset-call');
+
+module.exports = tree;
diff --git a/lib/less/tree/alpha.js b/lib/less/tree/alpha.js
index eb247ad..c4a7dd1 100644
--- a/lib/less/tree/alpha.js
+++ b/lib/less/tree/alpha.js
@@ -1,29 +1,28 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Alpha = function (val) {
this.value = val;
};
-Alpha.prototype = {
- type: "Alpha",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- eval: function (env) {
- if (this.value.eval) { return new Alpha(this.value.eval(env)); }
- return this;
- },
- genCSS: function (env, output) {
- output.add("alpha(opacity=");
+Alpha.prototype = new Node();
+Alpha.prototype.type = "Alpha";
- if (this.value.genCSS) {
- this.value.genCSS(env, output);
- } else {
- output.add(this.value);
- }
-
- output.add(")");
- },
- toCSS: tree.toCSS
+Alpha.prototype.accept = function (visitor) {
+ this.value = visitor.visit(this.value);
};
-return Alpha;
+Alpha.prototype.eval = function (env) {
+ if (this.value.eval) { return new Alpha(this.value.eval(env)); }
+ return this;
};
+Alpha.prototype.genCSS = function (env, output) {
+ output.add("alpha(opacity=");
+
+ if (this.value.genCSS) {
+ this.value.genCSS(env, output);
+ } else {
+ output.add(this.value);
+ }
+
+ output.add(")");
+};
+
+module.exports = Alpha;
diff --git a/lib/less/tree/anonymous.js b/lib/less/tree/anonymous.js
index 711579f..4c1695e 100644
--- a/lib/less/tree/anonymous.js
+++ b/lib/less/tree/anonymous.js
@@ -1,4 +1,4 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike) {
this.value = value;
@@ -7,32 +7,29 @@ var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike)
this.currentFileInfo = currentFileInfo;
this.rulesetLike = (typeof rulesetLike === 'undefined')? false : rulesetLike;
};
-Anonymous.prototype = {
- type: "Anonymous",
- eval: function () {
- return new Anonymous(this.value, this.index, this.currentFileInfo, this.mapLines, this.rulesetLike);
- },
- compare: function (x) {
- if (!x.toCSS) {
- return -1;
- }
+Anonymous.prototype = new Node();
+Anonymous.prototype.type = "Anonymous";
+Anonymous.prototype.eval = function () {
+ return new Anonymous(this.value, this.index, this.currentFileInfo, this.mapLines, this.rulesetLike);
+};
+Anonymous.prototype.compare = function (x) {
+ if (!x.toCSS) {
+ return -1;
+ }
- var left = this.toCSS(),
- right = x.toCSS();
+ var left = this.toCSS(),
+ right = x.toCSS();
- if (left === right) {
- return 0;
- }
+ if (left === right) {
+ return 0;
+ }
- return left < right ? -1 : 1;
- },
- isRulesetLike: function() {
- return this.rulesetLike;
- },
- genCSS: function (env, output) {
- output.add(this.value, this.currentFileInfo, this.index, this.mapLines);
- },
- toCSS: tree.toCSS
+ return left < right ? -1 : 1;
+};
+Anonymous.prototype.isRulesetLike = function() {
+ return this.rulesetLike;
};
-return Anonymous;
+Anonymous.prototype.genCSS = function (env, output) {
+ output.add(this.value, this.currentFileInfo, this.index, this.mapLines);
};
+module.exports = Anonymous;
diff --git a/lib/less/tree/assignment.js b/lib/less/tree/assignment.js
index afe6293..efcc903 100644
--- a/lib/less/tree/assignment.js
+++ b/lib/less/tree/assignment.js
@@ -1,29 +1,28 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Assignment = function (key, val) {
this.key = key;
this.value = val;
};
-Assignment.prototype = {
- type: "Assignment",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- eval: function (env) {
- if (this.value.eval) {
- return new(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
+
+Assignment.prototype = new Node();
+Assignment.prototype.type = "Assignment";
+Assignment.prototype.accept = function (visitor) {
+ this.value = visitor.visit(this.value);
+};
+Assignment.prototype.eval = function (env) {
+ if (this.value.eval) {
+ return new(Assignment)(this.key, this.value.eval(env));
+ }
+ return this;
};
-return Assignment;
+Assignment.prototype.genCSS = function (env, output) {
+ output.add(this.key + '=');
+ if (this.value.genCSS) {
+ this.value.genCSS(env, output);
+ } else {
+ output.add(this.value);
+ }
};
+module.exports = Assignment;
+
diff --git a/lib/less/tree/attribute.js b/lib/less/tree/attribute.js
index 4103bfc..4d713f2 100644
--- a/lib/less/tree/attribute.js
+++ b/lib/less/tree/attribute.js
@@ -1,29 +1,27 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Attribute = function (key, op, value) {
this.key = key;
this.op = op;
this.value = value;
};
-Attribute.prototype = {
- type: "Attribute",
- eval: function (env) {
- return new(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);
- }
+Attribute.prototype = new Node();
+Attribute.prototype.type = "Attribute";
+Attribute.prototype.eval = function (env) {
+ return new(Attribute)(this.key.eval ? this.key.eval(env) : this.key,
+ this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value);
+};
+Attribute.prototype.genCSS = function (env, output) {
+ output.add(this.toCSS(env));
+};
+Attribute.prototype.toCSS = function (env) {
+ var value = this.key.toCSS ? this.key.toCSS(env) : this.key;
- return '[' + value + ']';
+ if (this.op) {
+ value += this.op;
+ value += (this.value.toCSS ? this.value.toCSS(env) : this.value);
}
+
+ return '[' + value + ']';
};
-return Attribute;
-};
+module.exports = Attribute;
diff --git a/lib/less/tree/call.js b/lib/less/tree/call.js
index 08dc989..f7cbfed 100644
--- a/lib/less/tree/call.js
+++ b/lib/less/tree/call.js
@@ -1,5 +1,4 @@
-module.exports = function (tree, less) {
-
+var Node = require("./node.js");
//
// A function call node.
//
@@ -9,61 +8,57 @@ var Call = function (name, args, index, currentFileInfo) {
this.index = index;
this.currentFileInfo = currentFileInfo;
};
-Call.prototype = {
- type: "Call",
- accept: function (visitor) {
- if (this.args) {
- this.args = visitor.visitArray(this.args);
- }
- },
- //
- // When evaluating a function call,
- // we either find the function in `less.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); }),
- result, funcCaller = new less.functions.functionCaller(this.name, env, this.currentFileInfo);
+Call.prototype = new Node();
+Call.prototype.type = "Call";
+Call.prototype.accept = function (visitor) {
+ if (this.args) {
+ this.args = visitor.visitArray(this.args);
+ }
+};
+//
+// When evaluating a function call,
+// we either find the function in `less.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.
+//
+Call.prototype.eval = function (env) {
+ var args = this.args.map(function (a) { return a.eval(env); }),
+ FunctionCaller = require("../non-node-index.js").functions.functionCaller, //TODO! Move out
+ result, funcCaller = new FunctionCaller(this.name, env, this.currentFileInfo);
- if (funcCaller.isValid()) { // 1.
- try {
- result = funcCaller.call(args);
- 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 };
+ if (funcCaller.isValid()) { // 1.
+ try {
+ result = funcCaller.call(args);
+ 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 Call(this.name, args, this.index, this.currentFileInfo);
- },
-
- genCSS: function (env, output) {
- output.add(this.name + "(", this.currentFileInfo, this.index);
+ return new Call(this.name, args, this.index, this.currentFileInfo);
+};
+Call.prototype.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(", ");
- }
+ 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
-};
-return Call;
+ output.add(")");
};
+module.exports = Call;
diff --git a/lib/less/tree/color.js b/lib/less/tree/color.js
index 533235f..5a51d1c 100644
--- a/lib/less/tree/color.js
+++ b/lib/less/tree/color.js
@@ -1,4 +1,6 @@
-module.exports = function (data, tree) {
+var Node = require("./node.js"),
+ colors = require("../data/colors.js");
+
//
// RGB Colors - #ff0014, #eee
//
@@ -23,150 +25,157 @@ var Color = function (rgb, a) {
this.alpha = typeof(a) === 'number' ? a : 1;
};
-Color.prototype = {
- type: "Color",
- eval: function () { return this; },
- luma: function () {
- var r = this.rgb[0] / 255,
- g = this.rgb[1] / 255,
- b = this.rgb[2] / 255;
-
- r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4);
- g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4);
- b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4);
-
- return 0.2126 * r + 0.7152 * g + 0.0722 * b;
- },
-
- genCSS: function (env, output) {
- output.add(this.toCSS(env));
- },
- toCSS: function (env, doNotCompress) {
- var compress = env && env.compress && !doNotCompress, color, alpha;
-
- // `keyword` is set if this color was originally
- // converted from a named color string so we need
- // to respect this and try to output named color too.
- if (this.keyword) {
- return this.keyword;
- }
+Color.prototype = new Node();
+Color.prototype.type = "Color";
- // 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.
- alpha = tree.fround(env, this.alpha);
- if (alpha < 1) {
- return "rgba(" + this.rgb.map(function (c) {
- return clamp(Math.round(c), 255);
- }).concat(clamp(alpha, 1))
- .join(',' + (compress ? '' : ' ')) + ")";
- }
+function clamp(v, max) {
+ return Math.min(Math.max(v, 0), max);
+}
- color = this.toRGB();
+function toHex(v) {
+ return '#' + v.map(function (c) {
+ c = clamp(Math.round(c), 255);
+ return (c < 16 ? '0' : '') + c.toString(16);
+ }).join('');
+}
- if (compress) {
- var splitcolor = color.split('');
+Color.prototype.luma = function () {
+ var r = this.rgb[0] / 255,
+ g = this.rgb[1] / 255,
+ b = this.rgb[2] / 255;
- // 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];
- }
- }
+ r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4);
+ g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4);
+ b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4);
+
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
+};
+Color.prototype.genCSS = function (env, output) {
+ output.add(this.toCSS(env));
+};
+Color.prototype.toCSS = function (env, doNotCompress) {
+ var compress = env && env.compress && !doNotCompress, color, alpha;
+
+ // `keyword` is set if this color was originally
+ // converted from a named color string so we need
+ // to respect this and try to output named color too.
+ if (this.keyword) {
+ return this.keyword;
+ }
- return color;
- },
+ // 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.
+ alpha = this.fround(env, this.alpha);
+ if (alpha < 1) {
+ return "rgba(" + this.rgb.map(function (c) {
+ return clamp(Math.round(c), 255);
+ }).concat(clamp(alpha, 1))
+ .join(',' + (compress ? '' : ' ')) + ")";
+ }
- //
- // 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 rgb = [];
- var alpha = this.alpha * (1 - other.alpha) + other.alpha;
- for (var c = 0; c < 3; c++) {
- rgb[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]);
- }
- return new(Color)(rgb, alpha);
- },
-
- toRGB: function () {
- return toHex(this.rgb);
- },
-
- 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;
- }
+ color = this.toRGB();
- 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;
+ 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 { h: h * 360, s: s, v: v, a: a };
- },
- toARGB: function () {
- return toHex([this.alpha * 255].concat(this.rgb));
- },
- compare: function (x) {
- if (!x.rgb) {
- return -1;
+ }
+
+ 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.
+//
+Color.prototype.operate = function (env, op, other) {
+ var rgb = [];
+ var alpha = this.alpha * (1 - other.alpha) + other.alpha;
+ for (var c = 0; c < 3; c++) {
+ rgb[c] = this._operate(env, op, this.rgb[c], other.rgb[c]);
+ }
+ return new(Color)(rgb, alpha);
+};
+Color.prototype.toRGB = function () {
+ return toHex(this.rgb);
+};
+Color.prototype.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
+Color.prototype.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;
+ }
- 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;
+ 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 };
+};
+Color.prototype.toARGB = function () {
+ return toHex([this.alpha * 255].concat(this.rgb));
+};
+Color.prototype.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;
};
Color.fromKeyword = function(keyword) {
var c, key = keyword.toLowerCase();
- if (data.colors.hasOwnProperty(key)) {
- c = new(Color)(data.colors[key].slice(1));
+ if (colors.hasOwnProperty(key)) {
+ c = new(Color)(colors[key].slice(1));
}
else if (key === "transparent") {
c = new(Color)([0, 0, 0], 0);
@@ -177,16 +186,4 @@ Color.fromKeyword = function(keyword) {
return c;
}
};
-
-function toHex(v) {
- return '#' + v.map(function (c) {
- c = clamp(Math.round(c), 255);
- return (c < 16 ? '0' : '') + c.toString(16);
- }).join('');
-}
-
-function clamp(v, max) {
- return Math.min(Math.max(v, 0), max);
-}
-return Color;
-};
+module.exports = Color;
diff --git a/lib/less/tree/combinator.js b/lib/less/tree/combinator.js
index 0e34baf..ba0abb0 100644
--- a/lib/less/tree/combinator.js
+++ b/lib/less/tree/combinator.js
@@ -1,4 +1,4 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Combinator = function (value) {
if (value === ' ') {
@@ -7,18 +7,15 @@ var Combinator = function (value) {
this.value = value ? value.trim() : "";
}
};
-Combinator.prototype = {
- type: "Combinator",
- _noSpaceCombinators: {
- '': true,
- ' ': true,
- '|': true
- },
- genCSS: function (env, output) {
- var spaceOrEmpty = (env.compress || this._noSpaceCombinators[this.value]) ? '' : ' ';
- output.add(spaceOrEmpty + this.value + spaceOrEmpty);
- },
- toCSS: tree.toCSS
+Combinator.prototype = new Node();
+Combinator.prototype.type = "Combinator";
+var _noSpaceCombinators = {
+ '': true,
+ ' ': true,
+ '|': true
};
-return Combinator;
+Combinator.prototype.genCSS = function (env, output) {
+ var spaceOrEmpty = (env.compress || _noSpaceCombinators[this.value]) ? '' : ' ';
+ output.add(spaceOrEmpty + this.value + spaceOrEmpty);
};
+module.exports = Combinator;
diff --git a/lib/less/tree/comment.js b/lib/less/tree/comment.js
index 10c1e79..4226231 100644
--- a/lib/less/tree/comment.js
+++ b/lib/less/tree/comment.js
@@ -1,28 +1,28 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ getDebugInfo = require("./debug-info.js");
var Comment = function (value, isLineComment, index, currentFileInfo) {
this.value = value;
this.isLineComment = isLineComment;
this.currentFileInfo = currentFileInfo;
};
-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);
- },
- toCSS: tree.toCSS,
- isSilent: function(env) {
- var isReference = (this.currentFileInfo && this.currentFileInfo.reference && !this.isReferenced),
- isCompressed = env.compress && this.value[2] !== "!";
- return this.isLineComment || isReference || isCompressed;
- },
- eval: function () { return this; },
- markReferenced: function () {
- this.isReferenced = true;
+Comment.prototype = new Node();
+Comment.prototype.type = "Comment";
+Comment.prototype.genCSS = function (env, output) {
+ if (this.debugInfo) {
+ output.add(getDebugInfo(env, this), this.currentFileInfo, this.index);
}
+ output.add(this.value);
};
-return Comment;
+Comment.prototype.isSilent = function(env) {
+ var isReference = (this.currentFileInfo && this.currentFileInfo.reference && !this.isReferenced),
+ isCompressed = env.compress && this.value[2] !== "!";
+ return this.isLineComment || isReference || isCompressed;
};
+Comment.prototype.markReferenced = function () {
+ this.isReferenced = true;
+};
+Comment.prototype.isRulesetLike = function(root) {
+ return Boolean(root);
+};
+module.exports = Comment;
diff --git a/lib/less/tree/condition.js b/lib/less/tree/condition.js
index fdc7981..464c96c 100644
--- a/lib/less/tree/condition.js
+++ b/lib/less/tree/condition.js
@@ -1,4 +1,4 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Condition = function (op, l, r, i, negate) {
this.op = op.trim();
@@ -7,43 +7,41 @@ var Condition = function (op, l, r, i, negate) {
this.index = i;
this.negate = negate;
};
-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);
+Condition.prototype = new Node();
+Condition.prototype.type = "Condition";
+Condition.prototype.accept = function (visitor) {
+ this.lvalue = visitor.visit(this.lvalue);
+ this.rvalue = visitor.visit(this.rvalue);
+};
+Condition.prototype.eval = function (env) {
+ var a = this.lvalue.eval(env),
+ b = this.rvalue.eval(env);
- var i = this.index, result;
+ 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;
- }
-};
-return Condition;
+ 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;
};
+module.exports = Condition;
diff --git a/lib/less/tree/debug-info.js b/lib/less/tree/debug-info.js
new file mode 100644
index 0000000..5af873f
--- /dev/null
+++ b/lib/less/tree/debug-info.js
@@ -0,0 +1,34 @@
+var debugInfo = function(env, ctx, lineSeperator) {
+ var result="";
+ if (env.dumpLineNumbers && !env.compress) {
+ switch(env.dumpLineNumbers) {
+ case 'comments':
+ result = debugInfo.asComment(ctx);
+ break;
+ case 'mediaquery':
+ result = debugInfo.asMediaQuery(ctx);
+ break;
+ case 'all':
+ result = debugInfo.asComment(ctx) + (lineSeperator || "") + debugInfo.asMediaQuery(ctx);
+ break;
+ }
+ }
+ return result;
+};
+
+debugInfo.asComment = function(ctx) {
+ return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n';
+};
+
+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';
+};
+
+module.exports = debugInfo;
diff --git a/lib/less/tree/detached-ruleset.js b/lib/less/tree/detached-ruleset.js
index a58029c..009d67c 100644
--- a/lib/less/tree/detached-ruleset.js
+++ b/lib/less/tree/detached-ruleset.js
@@ -1,21 +1,21 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ contexts = require("../env.js");
var DetachedRuleset = function (ruleset, frames) {
this.ruleset = ruleset;
this.frames = frames;
};
-DetachedRuleset.prototype = {
- type: "DetachedRuleset",
- accept: function (visitor) {
- this.ruleset = visitor.visit(this.ruleset);
- },
- eval: function (env) {
- var frames = this.frames || env.frames.slice(0);
- return new DetachedRuleset(this.ruleset, frames);
- },
- callEval: function (env) {
- return this.ruleset.eval(this.frames ? new(tree.evalEnv)(env, this.frames.concat(env.frames)) : env);
- }
+DetachedRuleset.prototype = new Node();
+DetachedRuleset.prototype.type = "DetachedRuleset";
+DetachedRuleset.prototype.evalFirst = true;
+DetachedRuleset.prototype.accept = function (visitor) {
+ this.ruleset = visitor.visit(this.ruleset);
};
-return DetachedRuleset;
+DetachedRuleset.prototype.eval = function (env) {
+ var frames = this.frames || env.frames.slice(0);
+ return new DetachedRuleset(this.ruleset, frames);
};
+DetachedRuleset.prototype.callEval = function (env) {
+ return this.ruleset.eval(this.frames ? new(contexts.evalEnv)(env, this.frames.concat(env.frames)) : env);
+};
+module.exports = DetachedRuleset;
diff --git a/lib/less/tree/dimension.js b/lib/less/tree/dimension.js
index 2b24a8c..84b92c0 100644
--- a/lib/less/tree/dimension.js
+++ b/lib/less/tree/dimension.js
@@ -1,167 +1,164 @@
-module.exports = function (tree, unitConversions) {
+var Node = require("./node.js"),
+ unitConversions = require("../data/unit-conversions.js"),
+ Unit = require("./unit.js"),
+ Color = require("./color.js");
//
// A number with a unit
//
var Dimension = function (value, unit) {
this.value = parseFloat(value);
- this.unit = (unit && unit instanceof tree.Unit) ? unit :
- new(tree.Unit)(unit ? [unit] : undefined);
+ this.unit = (unit && unit instanceof Unit) ? unit :
+ new(Unit)(unit ? [unit] : undefined);
};
-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());
- }
+Dimension.prototype = new Node();
+Dimension.prototype.type = "Dimension";
+Dimension.prototype.accept = function (visitor) {
+ this.unit = visitor.visit(this.unit);
+};
+Dimension.prototype.eval = function (env) {
+ return this;
+};
+Dimension.prototype.toColor = function () {
+ return new(Color)([this.value, this.value, this.value]);
+};
+Dimension.prototype.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 = tree.fround(env, this.value),
- strValue = String(value);
+ var value = this.fround(env, 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;
- }
+ if (value !== 0 && value < 0.000001 && value > -0.000001) {
+ // would be output 1e-6 etc.
+ strValue = value.toFixed(20).replace(/0+$/, "");
+ }
- // Float values doesn't need a leading zero
- if (value > 0 && value < 1) {
- strValue = (strValue).substr(1);
- }
+ if (env && env.compress) {
+ // Zero values doesn't need a unit
+ if (value === 0 && this.unit.isLength()) {
+ output.add(strValue);
+ return;
}
- 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();
+ // Float values doesn't need a leading zero
+ if (value > 0 && value < 1) {
+ strValue = (strValue).substr(1);
}
- return new(Dimension)(value, unit);
- },
+ }
+
+ output.add(strValue);
+ this.unit.genCSS(env, output);
+};
- compare: function (other) {
- if (other instanceof Dimension) {
- var a, b,
- aValue, bValue;
+// In an operation between two Dimensions,
+// we default to the first Dimension's unit,
+// so `1px + 2` will yield `3px`.
+Dimension.prototype.operate = function (env, op, other) {
+ /*jshint noempty:false */
+ var value = this._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 (this.unit.isEmpty() || other.unit.isEmpty()) {
- a = this;
- b = other;
- } else {
- a = this.unify();
- b = other.unify();
- if (a.unit.compare(b.unit) !== 0) {
- return -1;
- }
+ 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() + "'.");
}
- aValue = a.value;
- bValue = b.value;
- if (bValue > aValue) {
+ value = this._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(Dimension)(value, unit);
+};
+Dimension.prototype.compare = function (other) {
+ if (other instanceof Dimension) {
+ var a, b,
+ aValue, bValue;
+
+ if (this.unit.isEmpty() || other.unit.isEmpty()) {
+ a = this;
+ b = other;
+ } else {
+ a = this.unify();
+ b = other.unify();
+ if (a.unit.compare(b.unit) !== 0) {
return -1;
- } else if (bValue < aValue) {
- return 1;
- } else {
- return 0;
}
- } else {
+ }
+ aValue = a.value;
+ bValue = b.value;
+
+ if (bValue > aValue) {
return -1;
+ } else if (bValue < aValue) {
+ return 1;
+ } else {
+ return 0;
}
- },
-
- unify: function () {
- return this.convertTo({ length: 'px', 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 unitConversions) {
- if (unitConversions[i].hasOwnProperty(conversions)) {
- derivedConversions = {};
- derivedConversions[i] = conversions;
- }
+ } else {
+ return -1;
+ }
+};
+Dimension.prototype.unify = function () {
+ return this.convertTo({ length: 'px', duration: 's', angle: 'rad' });
+};
+Dimension.prototype.convertTo = function (conversions) {
+ var value = this.value, unit = this.unit.clone(),
+ i, groupName, group, targetUnit, derivedConversions = {}, applyUnit;
+
+ if (typeof conversions === 'string') {
+ for(i in unitConversions) {
+ if (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;
+ 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 atomicUnit;
- };
+ return targetUnit;
+ }
- for (groupName in conversions) {
- if (conversions.hasOwnProperty(groupName)) {
- targetUnit = conversions[groupName];
- group = unitConversions[groupName];
+ return atomicUnit;
+ };
- unit.map(applyUnit);
- }
+ for (groupName in conversions) {
+ if (conversions.hasOwnProperty(groupName)) {
+ targetUnit = conversions[groupName];
+ group = unitConversions[groupName];
+
+ unit.map(applyUnit);
}
+ }
- unit.cancel();
+ unit.cancel();
- return new(Dimension)(value, unit);
- }
-};
-return Dimension;
+ return new(Dimension)(value, unit);
};
+module.exports = Dimension;
diff --git a/lib/less/tree/directive.js b/lib/less/tree/directive.js
index 7789ba3..2f99d3f 100644
--- a/lib/less/tree/directive.js
+++ b/lib/less/tree/directive.js
@@ -1,4 +1,5 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Ruleset = require("./ruleset.js");
var Directive = function (name, value, rules, index, currentFileInfo, debugInfo) {
this.name = name;
@@ -12,64 +13,92 @@ var Directive = function (name, value, rules, index, currentFileInfo, debugInfo)
this.debugInfo = debugInfo;
};
-Directive.prototype = {
- type: "Directive",
- accept: function (visitor) {
- var value = this.value, rules = this.rules;
- if (rules) {
- rules = visitor.visit(rules);
- }
- if (value) {
- value = visitor.visit(value);
- }
- },
- isRulesetLike: function() {
- return !this.isCharset();
- },
- isCharset: function() {
- return "@charset" === this.name;
- },
- genCSS: function (env, output) {
- var value = this.value, rules = this.rules;
- output.add(this.name, this.currentFileInfo, this.index);
- if (value) {
- output.add(' ');
- value.genCSS(env, output);
- }
- if (rules) {
- tree.outputRuleset(env, output, [rules]);
- } else {
- output.add(';');
- }
- },
- toCSS: tree.toCSS,
- eval: function (env) {
- var value = this.value, rules = this.rules;
- if (value) {
- value = value.eval(env);
- }
- if (rules) {
- rules = rules.eval(env);
- rules.root = true;
- }
- return new(Directive)(this.name, value, rules,
- this.index, this.currentFileInfo, this.debugInfo);
- },
- variable: function (name) { if (this.rules) return tree.Ruleset.prototype.variable.call(this.rules, name); },
- find: function () { if (this.rules) return tree.Ruleset.prototype.find.apply(this.rules, arguments); },
- rulesets: function () { if (this.rules) return tree.Ruleset.prototype.rulesets.apply(this.rules); },
- markReferenced: function () {
- var i, rules;
- this.isReferenced = true;
- if (this.rules) {
- rules = this.rules.rules;
- for (i = 0; i < rules.length; i++) {
- if (rules[i].markReferenced) {
- rules[i].markReferenced();
- }
+Directive.prototype = new Node();
+Directive.prototype.type = "Directive";
+Directive.prototype.accept = function (visitor) {
+ var value = this.value, rules = this.rules;
+ if (rules) {
+ rules = visitor.visit(rules);
+ }
+ if (value) {
+ value = visitor.visit(value);
+ }
+};
+Directive.prototype.isRulesetLike = function() {
+ return this.rules || !this.isCharset();
+};
+Directive.prototype.isCharset = function() {
+ return "@charset" === this.name;
+};
+Directive.prototype.genCSS = function (env, output) {
+ var value = this.value, rules = this.rules;
+ output.add(this.name, this.currentFileInfo, this.index);
+ if (value) {
+ output.add(' ');
+ value.genCSS(env, output);
+ }
+ if (rules) {
+ this.outputRuleset(env, output, [rules]);
+ } else {
+ output.add(';');
+ }
+};
+Directive.prototype.eval = function (env) {
+ var value = this.value, rules = this.rules;
+ if (value) {
+ value = value.eval(env);
+ }
+ if (rules) {
+ rules = rules.eval(env);
+ rules.root = true;
+ }
+ return new(Directive)(this.name, value, rules,
+ this.index, this.currentFileInfo, this.debugInfo);
+};
+Directive.prototype.variable = function (name) { if (this.rules) return Ruleset.prototype.variable.call(this.rules, name); };
+Directive.prototype.find = function () { if (this.rules) return Ruleset.prototype.find.apply(this.rules, arguments); };
+Directive.prototype.rulesets = function () { if (this.rules) return Ruleset.prototype.rulesets.apply(this.rules); };
+Directive.prototype.markReferenced = function () {
+ var i, rules;
+ this.isReferenced = true;
+ if (this.rules) {
+ rules = this.rules.rules;
+ for (i = 0; i < rules.length; i++) {
+ if (rules[i].markReferenced) {
+ rules[i].markReferenced();
}
}
}
};
-return Directive;
+Directive.prototype.outputRuleset = function (env, output, rules) {
+ var ruleCnt = rules.length, i;
+ env.tabLevel = (env.tabLevel | 0) + 1;
+
+ // Compressed
+ if (env.compress) {
+ output.add('{');
+ for (i = 0; i < ruleCnt; i++) {
+ rules[i].genCSS(env, output);
+ }
+ output.add('}');
+ env.tabLevel--;
+ return;
+ }
+
+ // Non-compressed
+ var tabSetStr = '\n' + Array(env.tabLevel).join(" "), tabRuleStr = tabSetStr + " ";
+ if (!ruleCnt) {
+ output.add(" {" + tabSetStr + '}');
+ } else {
+ output.add(" {" + tabRuleStr);
+ rules[0].genCSS(env, output);
+ for (i = 1; i < ruleCnt; i++) {
+ output.add(tabRuleStr);
+ rules[i].genCSS(env, output);
+ }
+ output.add(tabSetStr + '}');
+ }
+
+ env.tabLevel--;
};
+module.exports = Directive;
diff --git a/lib/less/tree/element.js b/lib/less/tree/element.js
index 925b4b9..8142d11 100644
--- a/lib/less/tree/element.js
+++ b/lib/less/tree/element.js
@@ -1,8 +1,9 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Combinator = require("./combinator.js");
var Element = function (combinator, value, index, currentFileInfo) {
- this.combinator = combinator instanceof tree.Combinator ?
- combinator : new(tree.Combinator)(combinator);
+ this.combinator = combinator instanceof Combinator ?
+ combinator : new(Combinator)(combinator);
if (typeof(value) === 'string') {
this.value = value.trim();
@@ -14,32 +15,30 @@ var Element = function (combinator, value, index, currentFileInfo) {
this.index = index;
this.currentFileInfo = currentFileInfo;
};
-Element.prototype = {
- type: "Element",
- accept: function (visitor) {
- var value = this.value;
- this.combinator = visitor.visit(this.combinator);
- if (typeof value === "object") {
- this.value = visitor.visit(value);
- }
- },
- eval: function (env) {
- return new(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;
- }
+Element.prototype = new Node();
+Element.prototype.type = "Element";
+Element.prototype.accept = function (visitor) {
+ var value = this.value;
+ this.combinator = visitor.visit(this.combinator);
+ if (typeof value === "object") {
+ this.value = visitor.visit(value);
}
};
-return Element;
+Element.prototype.eval = function (env) {
+ return new(Element)(this.combinator,
+ this.value.eval ? this.value.eval(env) : this.value,
+ this.index,
+ this.currentFileInfo);
};
+Element.prototype.genCSS = function (env, output) {
+ output.add(this.toCSS(env), this.currentFileInfo, this.index);
+};
+Element.prototype.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;
+ }
+};
+module.exports = Element;
diff --git a/lib/less/tree/expression.js b/lib/less/tree/expression.js
index 4614e15..11d09cb 100644
--- a/lib/less/tree/expression.js
+++ b/lib/less/tree/expression.js
@@ -1,54 +1,53 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Paren = require("./paren.js"),
+ Comment = require("./comment.js");
var Expression = function (value) { this.value = value; };
-Expression.prototype = {
- type: "Expression",
- accept: function (visitor) {
- if (this.value) {
- this.value = visitor.visitArray(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(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);
+Expression.prototype = new Node();
+Expression.prototype.type = "Expression";
+Expression.prototype.accept = function (visitor) {
+ if (this.value) {
+ this.value = visitor.visitArray(this.value);
+ }
+};
+Expression.prototype.eval = function (env) {
+ var returnValue,
+ inParenthesis = this.parens && !this.parensInOp,
+ doubleParen = false;
+ if (inParenthesis) {
+ env.inParenthesis();
+ }
+ if (this.value.length > 1) {
+ returnValue = new(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;
}
- 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(" ");
- }
+ returnValue = this.value[0].eval(env);
+ } else {
+ returnValue = this;
+ }
+ if (inParenthesis) {
+ env.outOfParenthesis();
+ }
+ if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) {
+ returnValue = new(Paren)(returnValue);
+ }
+ return returnValue;
+};
+Expression.prototype.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);
- });
}
};
-return Expression;
+Expression.prototype.throwAwayComments = function () {
+ this.value = this.value.filter(function(v) {
+ return !(v instanceof Comment);
+ });
};
+module.exports = Expression;
diff --git a/lib/less/tree/extend.js b/lib/less/tree/extend.js
index 746bdeb..d4d0676 100644
--- a/lib/less/tree/extend.js
+++ b/lib/less/tree/extend.js
@@ -1,4 +1,4 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Extend = function Extend(selector, option, index) {
this.selector = selector;
@@ -20,34 +20,32 @@ var Extend = function Extend(selector, option, index) {
};
Extend.next_id = 0;
-Extend.prototype = {
- type: "Extend",
- accept: function (visitor) {
- this.selector = visitor.visit(this.selector);
- },
- eval: function (env) {
- return new(Extend)(this.selector.eval(env), this.option, this.index);
- },
- clone: function (env) {
- return new(Extend)(this.selector, this.option, this.index);
- },
- findSelfSelectors: function (selectors) {
- var selfElements = [],
- i,
- selectorElements;
+Extend.prototype = new Node();
+Extend.prototype.type = "Extend";
+Extend.prototype.accept = function (visitor) {
+ this.selector = visitor.visit(this.selector);
+};
+Extend.prototype.eval = function (env) {
+ return new(Extend)(this.selector.eval(env), this.option, this.index);
+};
+Extend.prototype.clone = function (env) {
+ return new(Extend)(this.selector, this.option, this.index);
+};
+Extend.prototype.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);
+ 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 = ' ';
}
-
- this.selfSelectors = [{ elements: selfElements }];
+ selfElements = selfElements.concat(selectors[i].elements);
}
+
+ this.selfSelectors = [{ elements: selfElements }];
};
-return Extend;
-};
+module.exports = Extend;
diff --git a/lib/less/tree/import.js b/lib/less/tree/import.js
index 2042e2e..c0d0459 100644
--- a/lib/less/tree/import.js
+++ b/lib/less/tree/import.js
@@ -1,4 +1,10 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Media = require("./media.js"),
+ URL = require("./url.js"),
+ Quoted = require("./quoted.js"),
+ Ruleset = require("./ruleset.js"),
+ Anonymous = require("./anonymous.js");
+
//
// CSS @import node
//
@@ -37,88 +43,85 @@ var Import = function (path, features, options, index, currentFileInfo) {
// we end up with a flat structure, which can easily be imported in the parent
// ruleset.
//
-Import.prototype = {
- type: "Import",
- accept: function (visitor) {
+Import.prototype = new Node();
+Import.prototype.type = "Import";
+Import.prototype.accept = function (visitor) {
+ if (this.features) {
+ this.features = visitor.visit(this.features);
+ }
+ this.path = visitor.visit(this.path);
+ if (!this.options.inline && this.root) {
+ this.root = visitor.visit(this.root);
+ }
+};
+Import.prototype.genCSS = function (env, output) {
+ if (this.css) {
+ output.add("@import ", this.currentFileInfo, this.index);
+ this.path.genCSS(env, output);
if (this.features) {
- this.features = visitor.visit(this.features);
- }
- this.path = visitor.visit(this.path);
- if (!this.options.inline && this.root) {
- 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;
+ output.add(" ");
+ this.features.genCSS(env, output);
}
- return null;
- },
- evalForImport: function (env) {
- return new(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;
+ output.add(';');
+ }
+};
+Import.prototype.getPath = function () {
+ if (this.path instanceof Quoted) {
+ var path = this.path.value;
+ return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less';
+ } else if (this.path instanceof URL) {
+ return this.path.value.value;
+ }
+ return null;
+};
+Import.prototype.evalForImport = function (env) {
+ return new(Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo);
+};
+Import.prototype.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;
- }
+ if (!(path instanceof 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);
}
+ path.value = env.normalizePath(path.value);
+ }
- return path;
- },
- eval: function (env) {
- var ruleset, features = this.features && this.features.eval(env);
+ return path;
+};
+Import.prototype.eval = function (env) {
+ var ruleset, features = this.features && this.features.eval(env);
+ if (this.skip) {
+ if (typeof this.skip === "function") {
+ this.skip = this.skip();
+ }
if (this.skip) {
- if (typeof this.skip === "function") {
- this.skip = this.skip();
- }
- if (this.skip) {
- return [];
- }
+ 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, true);
- return this.features ? new(tree.Media)([contents], this.features.value) : [contents];
- } else if (this.css) {
- var newImport = new(Import)(this.evalPath(env), features, this.options, this.index);
- if (!newImport.css && this.error) {
- throw this.error;
- }
- return newImport;
- } else {
- ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));
+ if (this.options.inline) {
+ //todo needs to reference css file not import
+ var contents = new(Anonymous)(this.root, 0, {filename: this.importedFilename}, true, true);
+ return this.features ? new(Media)([contents], this.features.value) : [contents];
+ } else if (this.css) {
+ var newImport = new(Import)(this.evalPath(env), features, this.options, this.index);
+ if (!newImport.css && this.error) {
+ throw this.error;
+ }
+ return newImport;
+ } else {
+ ruleset = new(Ruleset)(null, this.root.rules.slice(0));
- ruleset.evalImports(env);
+ ruleset.evalImports(env);
- return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
- }
+ return this.features ? new(Media)(ruleset.rules, this.features.value) : ruleset.rules;
}
};
-return Import;
-};
+module.exports = Import;
diff --git a/lib/less/tree/javascript.js b/lib/less/tree/javascript.js
index fdca7bf..a8f5533 100644
--- a/lib/less/tree/javascript.js
+++ b/lib/less/tree/javascript.js
@@ -1,57 +1,27 @@
-module.exports = function (tree) {
+var JsEvalNode = require("./js-eval-node.js"),
+ Dimension = require("./dimension.js"),
+ Quoted = require("./quoted.js"),
+ Anonymous = require("./anonymous.js");
var JavaScript = function (string, index, escaped) {
this.escaped = escaped;
this.expression = string;
this.index = index;
};
-JavaScript.prototype = {
- type: "JavaScript",
- eval: function (env) {
- var result,
- that = this,
- context = {};
+JavaScript.prototype = new JsEvalNode();
+JavaScript.prototype.type = "JavaScript";
+JavaScript.prototype.eval = function(env) {
+ var result = this.evaluateJavaScript(this.expression, env);
- 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 };
- }
-
- var variables = env.frames[0].variables();
- for (var k in variables) {
- if (variables.hasOwnProperty(k)) {
- /*jshint loopfunc:true */
- context[k.slice(1)] = {
- value: 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.replace(/["]/g, "'") + "'" ,
- index: this.index };
- }
- if (typeof(result) === 'number') {
- return new(tree.Dimension)(result);
- } else 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);
- }
+ if (typeof(result) === 'number') {
+ return new(Dimension)(result);
+ } else if (typeof(result) === 'string') {
+ return new(Quoted)('"' + result + '"', result, this.escaped, this.index);
+ } else if (Array.isArray(result)) {
+ return new(Anonymous)(result.join(', '));
+ } else {
+ return new(Anonymous)(result);
}
};
-return JavaScript;
-};
+
+module.exports = JavaScript;
diff --git a/lib/less/tree/js-eval-node.js b/lib/less/tree/js-eval-node.js
new file mode 100644
index 0000000..0693873
--- /dev/null
+++ b/lib/less/tree/js-eval-node.js
@@ -0,0 +1,53 @@
+var Node = require("./node.js"),
+ Variable = require("./variable.js");
+
+var jsEvalNode = function() {
+};
+jsEvalNode.prototype = new Node();
+
+jsEvalNode.prototype.evaluateJavaScript = function (expression, env) {
+ var result,
+ that = this,
+ context = {};
+
+ expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
+ return that.jsify(new(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 };
+ }
+
+ var variables = env.frames[0].variables();
+ for (var k in variables) {
+ if (variables.hasOwnProperty(k)) {
+ /*jshint loopfunc:true */
+ context[k.slice(1)] = {
+ value: 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.replace(/["]/g, "'") + "'" ,
+ index: this.index };
+ }
+ return result;
+};
+jsEvalNode.prototype.jsify = function (obj) {
+ if (Array.isArray(obj.value) && (obj.value.length > 1)) {
+ return '[' + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + ']';
+ } else {
+ return obj.toCSS();
+ }
+};
+
+module.exports = jsEvalNode;
diff --git a/lib/less/tree/keyword.js b/lib/less/tree/keyword.js
index 46f5648..7f99a71 100644
--- a/lib/less/tree/keyword.js
+++ b/lib/less/tree/keyword.js
@@ -1,27 +1,21 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Keyword = function (value) { this.value = value; };
-Keyword.prototype = {
- type: "Keyword",
- eval: function () { return this; },
- genCSS: function (env, output) {
- if (this.value === '%') { throw { type: "Syntax", message: "Invalid % without number" }; }
- output.add(this.value);
- },
- toCSS: tree.toCSS,
- compare: function (other) {
- if (other instanceof Keyword) {
- return other.value === this.value ? 0 : 1;
- } else {
- return -1;
- }
+Keyword.prototype = new Node();
+Keyword.prototype.type = "Keyword";
+Keyword.prototype.genCSS = function (env, output) {
+ if (this.value === '%') { throw { type: "Syntax", message: "Invalid % without number" }; }
+ output.add(this.value);
+};
+Keyword.prototype.compare = function (other) {
+ if (other instanceof Keyword) {
+ return other.value === this.value ? 0 : 1;
+ } else {
+ return -1;
}
};
-//TODO move?
-tree.True = new(Keyword)('true');
-tree.False = new(Keyword)('false');
-
-return Keyword;
+Keyword.True = new(Keyword)('true');
+Keyword.False = new(Keyword)('false');
-};
+module.exports = Keyword;
diff --git a/lib/less/tree/media.js b/lib/less/tree/media.js
index 494e229..5926b32 100644
--- a/lib/less/tree/media.js
+++ b/lib/less/tree/media.js
@@ -1,4 +1,10 @@
-module.exports = function (tree) {
+var Ruleset = require("./ruleset.js"),
+ Value = require("./value.js"),
+ Element = require("./element.js"),
+ Selector = require("./selector.js"),
+ Anonymous = require("./anonymous.js"),
+ Expression = require("./expression.js"),
+ Directive = require("./directive.js");
var Media = function (value, features, index, currentFileInfo) {
this.index = index;
@@ -6,152 +12,150 @@ var Media = function (value, features, index, currentFileInfo) {
var selectors = this.emptySelectors();
- this.features = new(tree.Value)(features);
- this.rules = [new(tree.Ruleset)(selectors, value)];
+ this.features = new(Value)(features);
+ this.rules = [new(Ruleset)(selectors, value)];
this.rules[0].allowImports = true;
};
-Media.prototype = {
- type: "Media",
- accept: function (visitor) {
- if (this.features) {
- this.features = visitor.visit(this.features);
- }
- if (this.rules) {
- this.rules = visitor.visitArray(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 = [];
- }
+Media.prototype = new Directive();
+Media.prototype.type = "Media";
+Media.prototype.isRulesetLike = true;
+Media.prototype.accept = function (visitor) {
+ if (this.features) {
+ this.features = visitor.visit(this.features);
+ }
+ if (this.rules) {
+ this.rules = visitor.visitArray(this.rules);
+ }
+};
+Media.prototype.genCSS = function (env, output) {
+ output.add('@media ', this.currentFileInfo, this.index);
+ this.features.genCSS(env, output);
+ this.outputRuleset(env, output, this.rules);
+};
+Media.prototype.eval = function (env) {
+ if (!env.mediaBlocks) {
+ env.mediaBlocks = [];
+ env.mediaPath = [];
+ }
- var media = new(Media)(null, [], 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;
- }
+ var media = new(Media)(null, [], 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),
- sels = [new(tree.Selector)([el], null, null, this.index, this.currentFileInfo)];
- sels[0].mediaEmpty = true;
- return sels;
- },
- markReferenced: function () {
- var i, rules = this.rules[0].rules;
- this.rules[0].markReferenced();
- this.isReferenced = true;
- for (i = 0; i < rules.length; i++) {
- if (rules[i].markReferenced) {
- rules[i].markReferenced();
- }
- }
- },
+ env.mediaPath.push(media);
+ env.mediaBlocks.push(media);
- evalTop: function (env) {
- var result = this;
+ env.frames.unshift(this.rules[0]);
+ media.rules = [this.rules[0].eval(env)];
+ env.frames.shift();
- // Render all dependent Media blocks.
- if (env.mediaBlocks.length > 1) {
- var selectors = this.emptySelectors();
- result = new(tree.Ruleset)(selectors, env.mediaBlocks);
- result.multiMedia = true;
+ env.mediaPath.pop();
+
+ return env.mediaPath.length === 0 ? media.evalTop(env) :
+ media.evalNested(env);
+};
+//TODO merge with directive
+Media.prototype.variable = function (name) { return Ruleset.prototype.variable.call(this.rules[0], name); };
+Media.prototype.find = function () { return Ruleset.prototype.find.apply(this.rules[0], arguments); };
+Media.prototype.rulesets = function () { return Ruleset.prototype.rulesets.apply(this.rules[0]); };
+Media.prototype.emptySelectors = function() {
+ var el = new(Element)('', '&', this.index, this.currentFileInfo),
+ sels = [new(Selector)([el], null, null, this.index, this.currentFileInfo)];
+ sels[0].mediaEmpty = true;
+ return sels;
+};
+Media.prototype.markReferenced = function () {
+ var i, rules = this.rules[0].rules;
+ this.rules[0].markReferenced();
+ this.isReferenced = true;
+ for (i = 0; i < rules.length; i++) {
+ if (rules[i].markReferenced) {
+ rules[i].markReferenced();
}
+ }
+};
+Media.prototype.evalTop = function (env) {
+ var result = this;
+
+ // Render all dependent Media blocks.
+ if (env.mediaBlocks.length > 1) {
+ var selectors = this.emptySelectors();
+ result = new(Ruleset)(selectors, env.mediaBlocks);
+ result.multiMedia = true;
+ }
- delete env.mediaBlocks;
- delete env.mediaPath;
+ delete env.mediaBlocks;
+ delete env.mediaPath;
- return result;
- },
- evalNested: function (env) {
- var i, value,
- path = env.mediaPath.concat([this]);
+ return result;
+};
+Media.prototype.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 Value ?
+ path[i].features.value : path[i].features;
+ path[i] = Array.isArray(value) ? value : [value];
+ }
- // 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(Value)(this.permute(path).map(function (path) {
+ path = path.map(function (fragment) {
+ return fragment.toCSS ? fragment : new(Anonymous)(fragment);
+ });
+
+ for(i = path.length - 1; i > 0; i--) {
+ path.splice(i, 0, new(Anonymous)("and"));
}
- // 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 new(Expression)(path);
+ }));
+
+ // Fake a tree-node that doesn't output anything.
+ return new(Ruleset)([], []);
+};
+Media.prototype.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) {
- if (!selectors)
- return;
- this.rules = [new(tree.Ruleset)(selectors.slice(0), [this.rules[0]])];
- }
+ return result;
+ }
};
-return Media;
+Media.prototype.bubbleSelectors = function (selectors) {
+ if (!selectors)
+ return;
+ this.rules = [new(Ruleset)(selectors.slice(0), [this.rules[0]])];
};
+module.exports = Media;
diff --git a/lib/less/tree/mixin-call.js b/lib/less/tree/mixin-call.js
index e8faebf..e577b87 100644
--- a/lib/less/tree/mixin-call.js
+++ b/lib/less/tree/mixin-call.js
@@ -1,153 +1,154 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Selector = require("./selector.js"),
+ MixinDefinition = require("./mixin-definition.js"),
+ defaultFunc = require("../functions/default.js");
-var Call = function (elements, args, index, currentFileInfo, important) {
- this.selector = new(tree.Selector)(elements);
+var MixinCall = function (elements, args, index, currentFileInfo, important) {
+ this.selector = new(Selector)(elements);
this.arguments = (args && args.length) ? args : null;
this.index = index;
this.currentFileInfo = currentFileInfo;
this.important = important;
};
-Call.prototype = {
- type: "MixinCall",
- accept: function (visitor) {
- if (this.selector) {
- this.selector = visitor.visit(this.selector);
- }
- if (this.arguments) {
- this.arguments = visitor.visitArray(this.arguments);
- }
- },
- eval: function (env) {
- var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule,
- candidates = [], candidate, conditionResult = [], defaultFunc = tree.defaultFunc,
- defaultResult, defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset;
+MixinCall.prototype = new Node();
+MixinCall.prototype.type = "MixinCall";
+MixinCall.prototype.accept = function (visitor) {
+ if (this.selector) {
+ this.selector = visitor.visit(this.selector);
+ }
+ if (this.arguments) {
+ this.arguments = visitor.visitArray(this.arguments);
+ }
+};
+MixinCall.prototype.eval = function (env) {
+ var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule,
+ candidates = [], candidate, conditionResult = [],
+ defaultResult, defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset;
- args = this.arguments && this.arguments.map(function (a) {
- return { name: a.name, value: a.value.eval(env) };
- });
+ 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 (i = 0; i < env.frames.length; i++) {
+ if ((mixins = env.frames[i].find(this.selector)).length > 0) {
+ isOneFound = true;
- // To make `default()` function independent of definition order we have two "subpasses" here.
- // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
- // and build candidate list with corresponding flags. Then, when we know all possible matches,
- // we make a final decision.
+ // To make `default()` function independent of definition order we have two "subpasses" here.
+ // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
+ // and build candidate list with corresponding flags. Then, when we know all possible matches,
+ // we make a final decision.
- 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;
+ for (m = 0; m < mixins.length; m++) {
+ mixin = mixins[m];
+ isRecursive = false;
+ for(f = 0; f < env.frames.length; f++) {
+ if ((!(mixin instanceof MixinDefinition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) {
+ isRecursive = true;
+ break;
}
+ }
+ if (isRecursive) {
+ continue;
+ }
- if (mixin.matchArgs(args, env)) {
- candidate = {mixin: mixin, group: defNone};
+ if (mixin.matchArgs(args, env)) {
+ candidate = {mixin: mixin, group: defNone};
- if (mixin.matchCondition) {
- for (f = 0; f < 2; f++) {
- defaultFunc.value(f);
- conditionResult[f] = mixin.matchCondition(args, env);
+ if (mixin.matchCondition) {
+ for (f = 0; f < 2; f++) {
+ defaultFunc.value(f);
+ conditionResult[f] = mixin.matchCondition(args, env);
+ }
+ if (conditionResult[0] || conditionResult[1]) {
+ if (conditionResult[0] != conditionResult[1]) {
+ candidate.group = conditionResult[1] ?
+ defTrue : defFalse;
}
- if (conditionResult[0] || conditionResult[1]) {
- if (conditionResult[0] != conditionResult[1]) {
- candidate.group = conditionResult[1] ?
- defTrue : defFalse;
- }
- candidates.push(candidate);
- }
- }
- else {
candidates.push(candidate);
}
-
- match = true;
}
+ else {
+ candidates.push(candidate);
+ }
+
+ match = true;
}
+ }
- defaultFunc.reset();
+ defaultFunc.reset();
- count = [0, 0, 0];
- for (m = 0; m < candidates.length; m++) {
- count[candidates[m].group]++;
- }
+ count = [0, 0, 0];
+ for (m = 0; m < candidates.length; m++) {
+ count[candidates[m].group]++;
+ }
- if (count[defNone] > 0) {
- defaultResult = defFalse;
- } else {
- defaultResult = defTrue;
- if ((count[defTrue] + count[defFalse]) > 1) {
- throw { type: 'Runtime',
- message: 'Ambiguous use of `default()` found when matching for `'
- + this.format(args) + '`',
- index: this.index, filename: this.currentFileInfo.filename };
- }
+ if (count[defNone] > 0) {
+ defaultResult = defFalse;
+ } else {
+ defaultResult = defTrue;
+ if ((count[defTrue] + count[defFalse]) > 1) {
+ throw { type: 'Runtime',
+ message: 'Ambiguous use of `default()` found when matching for `'
+ + this.format(args) + '`',
+ index: this.index, filename: this.currentFileInfo.filename };
}
+ }
- for (m = 0; m < candidates.length; m++) {
- candidate = candidates[m].group;
- if ((candidate === defNone) || (candidate === defaultResult)) {
- try {
- mixin = candidates[m].mixin;
- if (!(mixin instanceof tree.mixin.Definition)) {
- originalRuleset = mixin.originalRuleset || mixin;
- mixin = new tree.mixin.Definition("", [], mixin.rules, null, false);
- mixin.originalRuleset = originalRuleset;
- }
- Array.prototype.push.apply(
- rules, mixin.evalCall(env, args, this.important).rules);
- } catch (e) {
- throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
+ for (m = 0; m < candidates.length; m++) {
+ candidate = candidates[m].group;
+ if ((candidate === defNone) || (candidate === defaultResult)) {
+ try {
+ mixin = candidates[m].mixin;
+ if (!(mixin instanceof MixinDefinition)) {
+ originalRuleset = mixin.originalRuleset || mixin;
+ mixin = new MixinDefinition("", [], mixin.rules, null, false);
+ mixin.originalRuleset = originalRuleset;
}
+ Array.prototype.push.apply(
+ rules, mixin.evalCall(env, args, this.important).rules);
+ } catch (e) {
+ throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
}
}
+ }
- if (match) {
- if (!this.currentFileInfo || !this.currentFileInfo.reference) {
- for (i = 0; i < rules.length; i++) {
- rule = rules[i];
- if (rule.markReferenced) {
- rule.markReferenced();
- }
+ 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;
}
+ return rules;
}
}
- if (isOneFound) {
- throw { type: 'Runtime',
- message: 'No matching definition was found for `' + this.format(args) + '`',
- 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 };
- }
- },
- format: function (args) {
- return 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(', ') : "") + ")";
+ }
+ if (isOneFound) {
+ throw { type: 'Runtime',
+ message: 'No matching definition was found for `' + this.format(args) + '`',
+ 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 };
}
};
-return Call;
+MixinCall.prototype.format = function (args) {
+ return 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(', ') : "") + ")";
};
+module.exports = MixinCall;
diff --git a/lib/less/tree/mixin-definition.js b/lib/less/tree/mixin-definition.js
index 7a891d6..044250b 100644
--- a/lib/less/tree/mixin-definition.js
+++ b/lib/less/tree/mixin-definition.js
@@ -1,8 +1,13 @@
-module.exports = function (tree) {
+var Selector = require("./selector.js"),
+ Element = require("./element.js"),
+ Ruleset = require("./ruleset.js"),
+ Rule = require("./rule.js"),
+ Expression = require("./expression.js"),
+ contexts = require("../env.js");
var Definition = function (name, params, rules, condition, variadic, frames) {
this.name = name;
- this.selectors = [new(tree.Selector)([new(tree.Element)(null, name, this.index, this.currentFileInfo)])];
+ this.selectors = [new(Selector)([new(Element)(null, name, this.index, this.currentFileInfo)])];
this.params = params;
this.condition = condition;
this.variadic = variadic;
@@ -13,153 +18,146 @@ var Definition = function (name, params, rules, condition, variadic, frames) {
if (!p.name || (p.name && !p.value)) { return count + 1; }
else { return count; }
}, 0);
- this.parent = tree.Ruleset.prototype;
this.frames = frames;
};
-Definition.prototype = {
- type: "MixinDefinition",
- accept: function (visitor) {
- if (this.params && this.params.length) {
- this.params = visitor.visitArray(this.params);
- }
- this.rules = visitor.visitArray(this.rules);
- if (this.condition) {
- 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, null),
- varargs, arg,
- params = this.params.slice(0),
- i, j, val, name, isNamedFound, argIndex, argsLength = 0;
-
- mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
-
- if (args) {
- args = args.slice(0);
- argsLength = args.length;
-
- for(i = 0; i < argsLength; 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.prependRule(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' };
+Definition.prototype = new Ruleset();
+Definition.prototype.type = "MixinDefinition";
+Definition.prototype.evalFirst = true;
+Definition.prototype.accept = function (visitor) {
+ if (this.params && this.params.length) {
+ this.params = visitor.visitArray(this.params);
+ }
+ this.rules = visitor.visitArray(this.rules);
+ if (this.condition) {
+ this.condition = visitor.visit(this.condition);
+ }
+};
+Definition.prototype.evalParams = function (env, mixinEnv, args, evaldArguments) {
+ /*jshint boss:true */
+ var frame = new(Ruleset)(null, null),
+ varargs, arg,
+ params = this.params.slice(0),
+ i, j, val, name, isNamedFound, argIndex, argsLength = 0;
+
+ mixinEnv = new contexts.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
+
+ if (args) {
+ args = args.slice(0);
+ argsLength = args.length;
+
+ for(i = 0; i < argsLength; 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.prependRule(new(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; }
+ }
+ argIndex = 0;
+ for (i = 0; i < params.length; i++) {
+ if (evaldArguments[i]) { continue; }
- arg = args && args[argIndex];
+ arg = args && args[argIndex];
- if (name = params[i].name) {
- if (params[i].variadic) {
- varargs = [];
- for (j = argIndex; j < argsLength; j++) {
- varargs.push(args[j].value.eval(env));
- }
- frame.prependRule(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
+ if (name = params[i].name) {
+ if (params[i].variadic) {
+ varargs = [];
+ for (j = argIndex; j < argsLength; j++) {
+ varargs.push(args[j].value.eval(env));
+ }
+ frame.prependRule(new(Rule)(name, new(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 {
- 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 +
- ' (' + argsLength + ' for ' + this.arity + ')' };
- }
-
- frame.prependRule(new(tree.Rule)(name, val));
- evaldArguments[i] = val;
+ throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
+ ' (' + argsLength + ' for ' + this.arity + ')' };
}
- }
- if (params[i].variadic && args) {
- for (j = argIndex; j < argsLength; j++) {
- evaldArguments[j] = args[j].value.eval(env);
- }
+ frame.prependRule(new(Rule)(name, val));
+ evaldArguments[i] = val;
}
- argIndex++;
}
- return frame;
- },
- eval: function (env) {
- return new tree.mixin.Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || env.frames.slice(0));
- },
- evalCall: function (env, args, important) {
- var _arguments = [],
- mixinFrames = this.frames ? this.frames.concat(env.frames) : env.frames,
- frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments),
- rules, ruleset;
+ if (params[i].variadic && args) {
+ for (j = argIndex; j < argsLength; j++) {
+ evaldArguments[j] = args[j].value.eval(env);
+ }
+ }
+ argIndex++;
+ }
- frame.prependRule(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
+ return frame;
+};
+Definition.prototype.eval = function (env) {
+ return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || env.frames.slice(0));
+};
+Definition.prototype.evalCall = function (env, args, important) {
+ var _arguments = [],
+ mixinFrames = this.frames ? this.frames.concat(env.frames) : env.frames,
+ frame = this.evalParams(env, new(contexts.evalEnv)(env, mixinFrames), args, _arguments),
+ rules, ruleset;
- rules = this.rules.slice(0);
+ frame.prependRule(new(Rule)('@arguments', new(Expression)(_arguments).eval(env)));
- 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 ? this.frames.concat(env.frames) : 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;
+ rules = this.rules.slice(0);
- if (! this.variadic) {
- if (argsLength < this.required) { return false; }
- if (argsLength > this.params.length) { return false; }
- } else {
- if (argsLength < (this.required - 1)) { return false; }
- }
+ ruleset = new(Ruleset)(null, rules);
+ ruleset.originalRuleset = this;
+ ruleset = ruleset.eval(new(contexts.evalEnv)(env, [this, frame].concat(mixinFrames)));
+ if (important) {
+ ruleset = this.makeImportant.apply(ruleset);
+ }
+ return ruleset;
+};
+Definition.prototype.matchCondition = function (args, env) {
+ if (this.condition && !this.condition.eval(
+ new(contexts.evalEnv)(env,
+ [this.evalParams(env, new(contexts.evalEnv)(env, this.frames ? this.frames.concat(env.frames) : 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;
+};
+Definition.prototype.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);
+ 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;
- }
+ 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;
}
+ return true;
};
-return Definition;
-};
+module.exports = Definition;
diff --git a/lib/less/tree/negative.js b/lib/less/tree/negative.js
index 6f3e9af..d33a315 100644
--- a/lib/less/tree/negative.js
+++ b/lib/less/tree/negative.js
@@ -1,24 +1,20 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Operation = require("./operation.js"),
+ Dimension = require("./dimension.js");
var Negative = function (node) {
this.value = node;
};
-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(Negative)(this.value.eval(env));
- }
+Negative.prototype = new Node();
+Negative.prototype.type = "Negative";
+Negative.prototype.genCSS = function (env, output) {
+ output.add('-');
+ this.value.genCSS(env, output);
};
-return Negative;
+Negative.prototype.eval = function (env) {
+ if (env.isMathOn()) {
+ return (new(Operation)('*', [new(Dimension)(-1), this.value])).eval(env);
+ }
+ return new(Negative)(this.value.eval(env));
};
+module.exports = Negative;
diff --git a/lib/less/tree/node.js b/lib/less/tree/node.js
new file mode 100644
index 0000000..c6bdd57
--- /dev/null
+++ b/lib/less/tree/node.js
@@ -0,0 +1,35 @@
+var Node = function() {
+};
+Node.prototype.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('');
+};
+Node.prototype.genCSS = function (env, output) {
+ output.add(this.value);
+};
+Node.prototype.accept = function (visitor) {
+ this.value = visitor.visit(this.value);
+};
+Node.prototype.eval = function () { return this; };
+Node.prototype._operate = function (env, op, a, b) {
+ switch (op) {
+ case '+': return a + b;
+ case '-': return a - b;
+ case '*': return a * b;
+ case '/': return a / b;
+ }
+};
+Node.prototype.fround = function(env, value) {
+ var precision = env && env.numPrecision;
+ //add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999....) are properly rounded...
+ return (precision == null) ? value : Number((value + 2e-16).toFixed(precision));
+};
+module.exports = Node;
diff --git a/lib/less/tree/operation.js b/lib/less/tree/operation.js
index 53dc37b..6b558e2 100644
--- a/lib/less/tree/operation.js
+++ b/lib/less/tree/operation.js
@@ -1,60 +1,48 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Color = require("./color.js"),
+ Dimension = require("./dimension.js");
var Operation = function (op, operands, isSpaced) {
this.op = op.trim();
this.operands = operands;
this.isSpaced = isSpaced;
};
-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);
-
- if (env.isMathOn()) {
- if (a instanceof tree.Dimension && b instanceof tree.Color) {
- a = a.toColor();
- }
- if (b instanceof tree.Dimension && a instanceof tree.Color) {
- b = b.toColor();
- }
- if (!a.operate) {
- throw { type: "Operation",
- message: "Operation on an invalid type" };
- }
+Operation.prototype = new Node();
+Operation.prototype.type = "Operation";
+Operation.prototype.accept = function (visitor) {
+ this.operands = visitor.visit(this.operands);
+};
+Operation.prototype.eval = function (env) {
+ var a = this.operands[0].eval(env),
+ b = this.operands[1].eval(env);
- return a.operate(env, this.op, b);
- } else {
- return new(Operation)(this.op, [a, b], this.isSpaced);
+ if (env.isMathOn()) {
+ if (a instanceof Dimension && b instanceof Color) {
+ a = a.toColor();
}
- },
- genCSS: function (env, output) {
- this.operands[0].genCSS(env, output);
- if (this.isSpaced) {
- output.add(" ");
+ if (b instanceof Dimension && a instanceof Color) {
+ b = b.toColor();
}
- output.add(this.op);
- if (this.isSpaced) {
- output.add(" ");
+ if (!a.operate) {
+ throw { type: "Operation",
+ message: "Operation on an invalid type" };
}
- this.operands[1].genCSS(env, output);
- },
- toCSS: tree.toCSS
-};
-// todo move!
-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;
+ return a.operate(env, this.op, b);
+ } else {
+ return new(Operation)(this.op, [a, b], this.isSpaced);
}
};
-
-return Operation;
-
+Operation.prototype.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);
};
+
+module.exports = Operation;
diff --git a/lib/less/tree/paren.js b/lib/less/tree/paren.js
index 5c7dca8..ab9b22a 100644
--- a/lib/less/tree/paren.js
+++ b/lib/less/tree/paren.js
@@ -1,22 +1,16 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Paren = function (node) {
this.value = node;
};
-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(Paren)(this.value.eval(env));
- }
+Paren.prototype = new Node();
+Paren.prototype.type = "Paren";
+Paren.prototype.genCSS = function (env, output) {
+ output.add('(');
+ this.value.genCSS(env, output);
+ output.add(')');
};
-return Paren;
+Paren.prototype.eval = function (env) {
+ return new(Paren)(this.value.eval(env));
};
+module.exports = Paren;
diff --git a/lib/less/tree/quoted.js b/lib/less/tree/quoted.js
index b0d3805..c46f8d5 100644
--- a/lib/less/tree/quoted.js
+++ b/lib/less/tree/quoted.js
@@ -1,4 +1,5 @@
-module.exports = function (tree) {
+var JsEvalNode = require("./js-eval-node.js"),
+ Variable = require("./variable.js");
var Quoted = function (str, content, escaped, index, currentFileInfo) {
this.escaped = escaped;
@@ -7,50 +8,47 @@ var Quoted = function (str, content, escaped, index, currentFileInfo) {
this.index = index;
this.currentFileInfo = currentFileInfo;
};
-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, right;
+Quoted.prototype = new JsEvalNode();
+Quoted.prototype.type = "Quoted";
+Quoted.prototype.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);
+ }
+};
+Quoted.prototype.eval = function (env) {
+ var that = this;
+ var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
+ return String(that.evaluateJavaScript(exp, env));
+ }).replace(/@\{([\w-]+)\}/g, function (_, name) {
+ var v = new(Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true);
+ return (v instanceof Quoted) ? v.value : v.toCSS();
+ });
+ return new(Quoted)(this.quote + value + this.quote, value, this.escaped, this.index, this.currentFileInfo);
+};
+Quoted.prototype.compare = function (x) {
+ if (!x.toCSS) {
+ return -1;
+ }
- // when comparing quoted strings allow the quote to differ
- if (x.type === "Quoted" && !this.escaped && !x.escaped) {
- left = x.value;
- right = this.value;
- } else {
- left = this.toCSS();
- right = x.toCSS();
- }
+ var left, right;
- if (left === right) {
- return 0;
- }
+ // when comparing quoted strings allow the quote to differ
+ if (x.type === "Quoted" && !this.escaped && !x.escaped) {
+ left = x.value;
+ right = this.value;
+ } else {
+ left = this.toCSS();
+ right = x.toCSS();
+ }
- return left < right ? -1 : 1;
+ if (left === right) {
+ return 0;
}
+
+ return left < right ? -1 : 1;
};
-return Quoted;
-};
+module.exports = Quoted;
diff --git a/lib/less/tree/rule.js b/lib/less/tree/rule.js
index 8dad863..ec09dcf 100644
--- a/lib/less/tree/rule.js
+++ b/lib/less/tree/rule.js
@@ -1,8 +1,10 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Value = require("./value.js"),
+ Keyword = require("./keyword.js");
var Rule = function (name, value, important, merge, index, currentFileInfo, inline) {
this.name = name;
- this.value = (value instanceof tree.Value || value instanceof tree.Ruleset) ? value : new(tree.Value)([value]);
+ this.value = (value instanceof Node) ? value : new(Value)([value]); //value instanceof tree.Value || value instanceof tree.Ruleset ??
this.important = important ? ' ' + important.trim() : '';
this.merge = merge;
this.index = index;
@@ -11,73 +13,6 @@ var Rule = function (name, value, important, merge, index, currentFileInfo, inli
this.variable = name.charAt && (name.charAt(0) === '@');
};
-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, name = this.name, evaldValue;
- if (typeof name !== "string") {
- // expand 'primitive' name directly to get
- // things faster (~10% for benchmark.less):
- name = (name.length === 1)
- && (name[0] instanceof tree.Keyword)
- ? name[0].value : evalName(env, name);
- }
- if (name === "font" && !env.strictMath) {
- strictMathBypass = true;
- env.strictMath = true;
- }
- try {
- evaldValue = this.value.eval(env);
-
- if (!this.variable && evaldValue.type === "DetachedRuleset") {
- throw { message: "Rulesets cannot be evaluated on a property.",
- index: this.index, filename: this.currentFileInfo.filename };
- }
-
- return new(Rule)(name,
- evaldValue,
- this.important,
- this.merge,
- this.index, this.currentFileInfo, this.inline);
- }
- catch(e) {
- if (typeof e.index !== 'number') {
- e.index = this.index;
- e.filename = this.currentFileInfo.filename;
- }
- throw e;
- }
- finally {
- if (strictMathBypass) {
- env.strictMath = false;
- }
- }
- },
- makeImportant: function () {
- return new(Rule)(this.name,
- this.value,
- "!important",
- this.merge,
- this.index, this.currentFileInfo, this.inline);
- }
-};
-
function evalName(env, name) {
var value = "", i, n = name.length,
output = {add: function (s) {value += s;}};
@@ -86,7 +21,67 @@ function evalName(env, name) {
}
return value;
}
-
-return Rule;
+Rule.prototype = new Node();
+Rule.prototype.type = "Rule";
+Rule.prototype.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);
};
+Rule.prototype.eval = function (env) {
+ var strictMathBypass = false, name = this.name, evaldValue;
+ if (typeof name !== "string") {
+ // expand 'primitive' name directly to get
+ // things faster (~10% for benchmark.less):
+ name = (name.length === 1)
+ && (name[0] instanceof Keyword)
+ ? name[0].value : evalName(env, name);
+ }
+ if (name === "font" && !env.strictMath) {
+ strictMathBypass = true;
+ env.strictMath = true;
+ }
+ try {
+ evaldValue = this.value.eval(env);
+
+ if (!this.variable && evaldValue.type === "DetachedRuleset") {
+ throw { message: "Rulesets cannot be evaluated on a property.",
+ index: this.index, filename: this.currentFileInfo.filename };
+ }
+
+ return new(Rule)(name,
+ evaldValue,
+ this.important,
+ this.merge,
+ this.index, this.currentFileInfo, this.inline);
+ }
+ catch(e) {
+ if (typeof e.index !== 'number') {
+ e.index = this.index;
+ e.filename = this.currentFileInfo.filename;
+ }
+ throw e;
+ }
+ finally {
+ if (strictMathBypass) {
+ env.strictMath = false;
+ }
+ }
+};
+Rule.prototype.makeImportant = function () {
+ return new(Rule)(this.name,
+ this.value,
+ "!important",
+ this.merge,
+ this.index, this.currentFileInfo, this.inline);
+};
+
+module.exports = Rule;
diff --git a/lib/less/tree/ruleset-call.js b/lib/less/tree/ruleset-call.js
index e7d998c..537a978 100644
--- a/lib/less/tree/ruleset-call.js
+++ b/lib/less/tree/ruleset-call.js
@@ -1,16 +1,13 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Variable = require("./variable.js");
var RulesetCall = function (variable) {
this.variable = variable;
};
-RulesetCall.prototype = {
- type: "RulesetCall",
- accept: function (visitor) {
- },
- eval: function (env) {
- var detachedRuleset = new(tree.Variable)(this.variable).eval(env);
- return detachedRuleset.callEval(env);
- }
-};
-return RulesetCall;
+RulesetCall.prototype = new Node();
+RulesetCall.prototype.type = "RulesetCall";
+RulesetCall.prototype.eval = function (env) {
+ var detachedRuleset = new(Variable)(this.variable).eval(env);
+ return detachedRuleset.callEval(env);
};
+module.exports = RulesetCall;
diff --git a/lib/less/tree/ruleset.js b/lib/less/tree/ruleset.js
index 92337cf..4c2ecf9 100644
--- a/lib/less/tree/ruleset.js
+++ b/lib/less/tree/ruleset.js
@@ -1,4 +1,10 @@
-module.exports = function (tree) {
+var Node = require("./node.js"),
+ Rule = require("./rule.js"),
+ Selector = require("./selector.js"),
+ Element = require("./element.js"),
+ contexts = require("../env.js"),
+ defaultFunc = require("../functions/default.js"),
+ getDebugInfo = require("./debug-info.js");
var Ruleset = function (selectors, rules, strictImports) {
this.selectors = selectors;
@@ -6,575 +12,566 @@ var Ruleset = function (selectors, rules, strictImports) {
this._lookups = {};
this.strictImports = strictImports;
};
-Ruleset.prototype = {
- type: "Ruleset",
- accept: function (visitor) {
- if (this.paths) {
- visitor.visitArray(this.paths, true);
- } else if (this.selectors) {
- this.selectors = visitor.visitArray(this.selectors);
- }
- if (this.rules && this.rules.length) {
- this.rules = visitor.visitArray(this.rules);
- }
- },
- eval: function (env) {
- var thisSelectors = this.selectors, selectors,
- selCnt, selector, i, defaultFunc = tree.defaultFunc, hasOnePassingSelector = false;
-
- if (thisSelectors && (selCnt = thisSelectors.length)) {
- selectors = [];
- defaultFunc.error({
- type: "Syntax",
- message: "it is currently only allowed in parametric mixin guards,"
- });
- for (i = 0; i < selCnt; i++) {
- selector = thisSelectors[i].eval(env);
- selectors.push(selector);
- if (selector.evaldCondition) {
- hasOnePassingSelector = true;
- }
+Ruleset.prototype = new Node();
+Ruleset.prototype.type = "Ruleset";
+Ruleset.prototype.isRuleset = true;
+Ruleset.prototype.isRulesetLike = true;
+Ruleset.prototype.accept = function (visitor) {
+ if (this.paths) {
+ visitor.visitArray(this.paths, true);
+ } else if (this.selectors) {
+ this.selectors = visitor.visitArray(this.selectors);
+ }
+ if (this.rules && this.rules.length) {
+ this.rules = visitor.visitArray(this.rules);
+ }
+};
+Ruleset.prototype.eval = function (env) {
+ var thisSelectors = this.selectors, selectors,
+ selCnt, selector, i, hasOnePassingSelector = false;
+
+ if (thisSelectors && (selCnt = thisSelectors.length)) {
+ selectors = [];
+ defaultFunc.error({
+ type: "Syntax",
+ message: "it is currently only allowed in parametric mixin guards,"
+ });
+ for (i = 0; i < selCnt; i++) {
+ selector = thisSelectors[i].eval(env);
+ selectors.push(selector);
+ if (selector.evaldCondition) {
+ hasOnePassingSelector = true;
}
- defaultFunc.reset();
- } else {
- hasOnePassingSelector = true;
}
+ defaultFunc.reset();
+ } else {
+ hasOnePassingSelector = true;
+ }
- var rules = this.rules ? this.rules.slice(0) : null,
- ruleset = new(Ruleset)(selectors, rules, this.strictImports),
- rule, subRule;
+ var rules = this.rules ? this.rules.slice(0) : null,
+ ruleset = new(Ruleset)(selectors, rules, this.strictImports),
+ rule, subRule;
- ruleset.originalRuleset = this;
- ruleset.root = this.root;
- ruleset.firstRoot = this.firstRoot;
- ruleset.allowImports = this.allowImports;
+ ruleset.originalRuleset = this;
+ ruleset.root = this.root;
+ ruleset.firstRoot = this.firstRoot;
+ ruleset.allowImports = this.allowImports;
- if(this.debugInfo) {
- ruleset.debugInfo = this.debugInfo;
- }
+ if(this.debugInfo) {
+ ruleset.debugInfo = this.debugInfo;
+ }
- if (!hasOnePassingSelector) {
- rules.length = 0;
- }
+ if (!hasOnePassingSelector) {
+ rules.length = 0;
+ }
- // push the current ruleset to the frames stack
- var envFrames = env.frames;
- envFrames.unshift(ruleset);
+ // push the current ruleset to the frames stack
+ var envFrames = env.frames;
+ envFrames.unshift(ruleset);
- // currrent selectors
- var envSelectors = env.selectors;
- if (!envSelectors) {
- env.selectors = envSelectors = [];
- }
- envSelectors.unshift(this.selectors);
+ // currrent selectors
+ var envSelectors = env.selectors;
+ if (!envSelectors) {
+ env.selectors = envSelectors = [];
+ }
+ envSelectors.unshift(this.selectors);
- // Evaluate imports
- if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
- ruleset.evalImports(env);
- }
+ // 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.
- var rsRules = ruleset.rules, rsRuleCnt = rsRules ? rsRules.length : 0;
- for (i = 0; i < rsRuleCnt; i++) {
- if (rsRules[i] instanceof tree.mixin.Definition || rsRules[i] instanceof tree.DetachedRuleset) {
- rsRules[i] = rsRules[i].eval(env);
- }
+ // Store the frames around mixin definitions,
+ // so they can be evaluated like closures when the time comes.
+ var rsRules = ruleset.rules, rsRuleCnt = rsRules ? rsRules.length : 0;
+ for (i = 0; i < rsRuleCnt; i++) {
+ if (rsRules[i].evalFirst) {
+ rsRules[i] = rsRules[i].eval(env);
}
+ }
- var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0;
-
- // Evaluate mixin calls.
- for (i = 0; i < rsRuleCnt; i++) {
- if (rsRules[i] instanceof tree.mixin.Call) {
- /*jshint loopfunc:true */
- rules = rsRules[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;
- });
- rsRules.splice.apply(rsRules, [i, 1].concat(rules));
- rsRuleCnt += rules.length - 1;
- i += rules.length-1;
- ruleset.resetCache();
- } else if (rsRules[i] instanceof tree.RulesetCall) {
- /*jshint loopfunc:true */
- rules = rsRules[i].eval(env).rules.filter(function(r) {
- if ((r instanceof tree.Rule) && r.variable) {
- // do not pollute the scope at all
- return false;
- }
- return true;
- });
- rsRules.splice.apply(rsRules, [i, 1].concat(rules));
- rsRuleCnt += rules.length - 1;
- i += rules.length-1;
- ruleset.resetCache();
- }
+ var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0;
+
+ // Evaluate mixin calls.
+ for (i = 0; i < rsRuleCnt; i++) {
+ if (rsRules[i].type === "MixinCall") {
+ /*jshint loopfunc:true */
+ rules = rsRules[i].eval(env).filter(function(r) {
+ if ((r instanceof 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;
+ });
+ rsRules.splice.apply(rsRules, [i, 1].concat(rules));
+ rsRuleCnt += rules.length - 1;
+ i += rules.length-1;
+ ruleset.resetCache();
+ } else if (rsRules[i].type === "RulesetCall") {
+ /*jshint loopfunc:true */
+ rules = rsRules[i].eval(env).rules.filter(function(r) {
+ if ((r instanceof Rule) && r.variable) {
+ // do not pollute the scope at all
+ return false;
+ }
+ return true;
+ });
+ rsRules.splice.apply(rsRules, [i, 1].concat(rules));
+ rsRuleCnt += rules.length - 1;
+ i += rules.length-1;
+ ruleset.resetCache();
}
+ }
- // Evaluate everything else
- for (i = 0; i < rsRules.length; i++) {
- rule = rsRules[i];
- if (! (rule instanceof tree.mixin.Definition || rule instanceof tree.DetachedRuleset)) {
- rsRules[i] = rule = rule.eval ? rule.eval(env) : rule;
- }
+ // Evaluate everything else
+ for (i = 0; i < rsRules.length; i++) {
+ rule = rsRules[i];
+ if (!rule.evalFirst) {
+ rsRules[i] = rule = rule.eval ? rule.eval(env) : rule;
}
+ }
- // Evaluate everything else
- for (i = 0; i < rsRules.length; i++) {
- rule = rsRules[i];
- // for rulesets, check if it is a css guard and can be removed
- if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) {
- // check if it can be folded in (e.g. & where)
- if (rule.selectors[0].isJustParentSelector()) {
- rsRules.splice(i--, 1);
-
- for(var j = 0; j < rule.rules.length; j++) {
- subRule = rule.rules[j];
- if (!(subRule instanceof tree.Rule) || !subRule.variable) {
- rsRules.splice(++i, 0, subRule);
- }
+ // Evaluate everything else
+ for (i = 0; i < rsRules.length; i++) {
+ rule = rsRules[i];
+ // for rulesets, check if it is a css guard and can be removed
+ if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) {
+ // check if it can be folded in (e.g. & where)
+ if (rule.selectors[0].isJustParentSelector()) {
+ rsRules.splice(i--, 1);
+
+ for(var j = 0; j < rule.rules.length; j++) {
+ subRule = rule.rules[j];
+ if (!(subRule instanceof Rule) || !subRule.variable) {
+ rsRules.splice(++i, 0, subRule);
}
}
}
}
+ }
- // Pop the stack
- envFrames.shift();
- envSelectors.shift();
+ // Pop the stack
+ envFrames.shift();
+ envSelectors.shift();
- if (env.mediaBlocks) {
- for (i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
- env.mediaBlocks[i].bubbleSelectors(selectors);
- }
+ if (env.mediaBlocks) {
+ for (i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
+ env.mediaBlocks[i].bubbleSelectors(selectors);
}
+ }
- return ruleset;
- },
- evalImports: function(env) {
- var rules = this.rules, i, importRules;
- if (!rules) { return; }
-
- for (i = 0; i < rules.length; i++) {
- if (rules[i] instanceof tree.Import) {
- importRules = rules[i].eval(env);
- if (importRules && importRules.length) {
- rules.splice.apply(rules, [i, 1].concat(importRules));
- i+= importRules.length-1;
- } else {
- rules.splice(i, 1, importRules);
- }
- this.resetCache();
+ return ruleset;
+};
+Ruleset.prototype.evalImports = function(env) {
+ var rules = this.rules, i, importRules;
+ if (!rules) { return; }
+
+ for (i = 0; i < rules.length; i++) {
+ if (rules[i].type === "Import") {
+ importRules = rules[i].eval(env);
+ if (importRules && importRules.length) {
+ rules.splice.apply(rules, [i, 1].concat(importRules));
+ i+= importRules.length-1;
+ } else {
+ rules.splice(i, 1, importRules);
}
+ this.resetCache();
}
- },
- makeImportant: function() {
- return new 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;
- },
- // lets you call a css selector with a guard
- matchCondition: function (args, env) {
- var lastSelector = this.selectors[this.selectors.length-1];
- if (!lastSelector.evaldCondition) {
- return false;
- }
- 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) {
- this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) {
- if (r instanceof tree.Rule && r.variable === true) {
- hash[r.name] = r;
+ }
+};
+Ruleset.prototype.makeImportant = function() {
+ return new Ruleset(this.selectors, this.rules.map(function (r) {
+ if (r.makeImportant) {
+ return r.makeImportant();
+ } else {
+ return r;
}
- return hash;
- }, {});
- }
- return this._variables;
- },
- variable: function (name) {
- return this.variables()[name];
- },
- rulesets: function () {
- if (!this.rules) { return null; }
-
- var _MixinDefinition = tree.mixin.Definition,
- filtRules = [], rules = this.rules, cnt = rules.length,
- i, rule;
-
- for (i = 0; i < cnt; i++) {
- rule = rules[i];
- if ((rule instanceof Ruleset) || (rule instanceof _MixinDefinition)) {
- filtRules.push(rule);
+ }), this.strictImports);
+};
+Ruleset.prototype.matchArgs = function (args) {
+ return !args || args.length === 0;
+};
+// lets you call a css selector with a guard
+Ruleset.prototype.matchCondition = function (args, env) {
+ var lastSelector = this.selectors[this.selectors.length-1];
+ if (!lastSelector.evaldCondition) {
+ return false;
+ }
+ if (lastSelector.condition &&
+ !lastSelector.condition.eval(
+ new(contexts.evalEnv)(env,
+ env.frames))) {
+ return false;
+ }
+ return true;
+};
+Ruleset.prototype.resetCache = function () {
+ this._rulesets = null;
+ this._variables = null;
+ this._lookups = {};
+};
+Ruleset.prototype.variables = function () {
+ if (!this._variables) {
+ this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) {
+ if (r instanceof Rule && r.variable === true) {
+ hash[r.name] = r;
}
+ return hash;
+ }, {});
+ }
+ return this._variables;
+};
+Ruleset.prototype.variable = function (name) {
+ return this.variables()[name];
+};
+Ruleset.prototype.rulesets = function () {
+ if (!this.rules) { return null; }
+
+ var filtRules = [], rules = this.rules, cnt = rules.length,
+ i, rule;
+
+ for (i = 0; i < cnt; i++) {
+ rule = rules[i];
+ if (rule.isRuleset) {
+ filtRules.push(rule);
}
+ }
- return filtRules;
- },
- prependRule: function (rule) {
- var rules = this.rules;
- if (rules) { rules.unshift(rule); } else { this.rules = [ rule ]; }
- },
- 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++) {
- match = selector.match(rule.selectors[j]);
- if (match) {
- 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 filtRules;
+};
+Ruleset.prototype.prependRule = function (rule) {
+ var rules = this.rules;
+ if (rules) { rules.unshift(rule); } else { this.rules = [ rule ]; }
+};
+Ruleset.prototype.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++) {
+ match = selector.match(rule.selectors[j]);
+ if (match) {
+ if (selector.elements.length > match) {
+ Array.prototype.push.apply(rules, rule.find(
+ new(Selector)(selector.elements.slice(match)), self));
+ } else {
+ rules.push(rule);
}
+ break;
}
}
- });
- this._lookups[key] = rules;
- return rules;
- },
- genCSS: function (env, output) {
- var i, j,
- charsetRuleNodes = [],
- ruleNodes = [],
- rulesetNodes = [],
- rulesetNodeCnt,
- debugInfo, // Line number debugging
- rule,
- path;
-
- env.tabLevel = (env.tabLevel || 0);
-
- if (!this.root) {
- env.tabLevel++;
}
+ });
+ this._lookups[key] = rules;
+ return rules;
+};
+Ruleset.prototype.genCSS = function (env, output) {
+ var i, j,
+ charsetRuleNodes = [],
+ ruleNodes = [],
+ rulesetNodes = [],
+ rulesetNodeCnt,
+ debugInfo, // Line number debugging
+ rule,
+ 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(" "),
- sep;
-
- function isRulesetLikeNode(rule, root) {
- // if it has nested rules, then it should be treated like a ruleset
- if (rule.rules)
- return true;
-
- // medias and comments do not have nested rules, but should be treated like rulesets anyway
- if ( (rule instanceof tree.Media) || (root && rule instanceof tree.Comment))
- return true;
-
- // some directives and anonumoust nodes are ruleset like, others are not
- if ((rule instanceof tree.Directive) || (rule instanceof tree.Anonymous)) {
- return rule.isRulesetLike();
- }
-
- //anything else is assumed to be a rule
- return false;
- }
+ var tabRuleStr = env.compress ? '' : Array(env.tabLevel + 1).join(" "),
+ tabSetStr = env.compress ? '' : Array(env.tabLevel).join(" "),
+ sep;
+
+ function isRulesetLikeNode(rule, root) {
+ // if it has nested rules, then it should be treated like a ruleset
+ // medias and comments do not have nested rules, but should be treated like rulesets anyway
+ // some directives and anonymous nodes are ruleset like, others are not
+ if (typeof rule.isRulesetLike === "boolean")
+ {
+ return rule.isRulesetLike;
+ } else if (typeof rule.isRulesetLike === "function")
+ {
+ return rule.isRulesetLike(root);
+ }
+
+ //anything else is assumed to be a rule
+ return false;
+ }
- for (i = 0; i < this.rules.length; i++) {
- rule = this.rules[i];
- if (isRulesetLikeNode(rule, this.root)) {
- rulesetNodes.push(rule);
+ for (i = 0; i < this.rules.length; i++) {
+ rule = this.rules[i];
+ if (isRulesetLikeNode(rule, this.root)) {
+ rulesetNodes.push(rule);
+ } else {
+ //charsets should float on top of everything
+ if (rule.isCharset && rule.isCharset()) {
+ charsetRuleNodes.push(rule);
} else {
- //charsets should float on top of everything
- if (rule.isCharset && rule.isCharset()) {
- charsetRuleNodes.push(rule);
- } else {
- ruleNodes.push(rule);
- }
+ ruleNodes.push(rule);
}
}
- ruleNodes = charsetRuleNodes.concat(ruleNodes);
+ }
+ ruleNodes = charsetRuleNodes.concat(ruleNodes);
- // If this is the root node, we don't render
- // a selector, or {}.
- if (!this.root) {
- debugInfo = tree.debugInfo(env, this, tabSetStr);
+ // If this is the root node, we don't render
+ // a selector, or {}.
+ if (!this.root) {
+ debugInfo = getDebugInfo(env, this, tabSetStr);
- if (debugInfo) {
- output.add(debugInfo);
- output.add(tabSetStr);
- }
+ if (debugInfo) {
+ output.add(debugInfo);
+ output.add(tabSetStr);
+ }
- var paths = this.paths, pathCnt = paths.length,
- pathSubCnt;
+ var paths = this.paths, pathCnt = paths.length,
+ pathSubCnt;
- sep = env.compress ? ',' : (',\n' + tabSetStr);
+ sep = env.compress ? ',' : (',\n' + tabSetStr);
- for (i = 0; i < pathCnt; i++) {
- path = paths[i];
- if (!(pathSubCnt = path.length)) { continue; }
- if (i > 0) { output.add(sep); }
+ for (i = 0; i < pathCnt; i++) {
+ path = paths[i];
+ if (!(pathSubCnt = path.length)) { continue; }
+ if (i > 0) { output.add(sep); }
- env.firstSelector = true;
- path[0].genCSS(env, output);
+ env.firstSelector = true;
+ path[0].genCSS(env, output);
- env.firstSelector = false;
- for (j = 1; j < pathSubCnt; j++) {
- path[j].genCSS(env, output);
- }
+ env.firstSelector = false;
+ for (j = 1; j < pathSubCnt; j++) {
+ path[j].genCSS(env, output);
}
-
- output.add((env.compress ? '{' : ' {\n') + tabRuleStr);
}
- // Compile rules and rulesets
- for (i = 0; i < ruleNodes.length; i++) {
- rule = ruleNodes[i];
+ output.add((env.compress ? '{' : ' {\n') + tabRuleStr);
+ }
- // @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;
- }
+ // Compile rules and rulesets
+ for (i = 0; i < ruleNodes.length; i++) {
+ rule = ruleNodes[i];
- 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;
- }
+ // @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 (!this.root) {
- output.add((env.compress ? '}' : '\n' + tabSetStr + '}'));
- env.tabLevel--;
+ if (rule.genCSS) {
+ rule.genCSS(env, output);
+ } else if (rule.value) {
+ output.add(rule.value.toString());
}
- sep = (env.compress ? "" : "\n") + (this.root ? tabRuleStr : tabSetStr);
- rulesetNodeCnt = rulesetNodes.length;
- if (rulesetNodeCnt) {
- if (ruleNodes.length && sep) { output.add(sep); }
- rulesetNodes[0].genCSS(env, output);
- for (i = 1; i < rulesetNodeCnt; i++) {
- if (sep) { output.add(sep); }
- rulesetNodes[i].genCSS(env, output);
- }
+ if (!env.lastRule) {
+ output.add(env.compress ? '' : ('\n' + tabRuleStr));
+ } else {
+ env.lastRule = false;
}
+ }
- if (!output.isEmpty() && !env.compress && this.firstRoot) {
- output.add('\n');
+ if (!this.root) {
+ output.add((env.compress ? '}' : '\n' + tabSetStr + '}'));
+ env.tabLevel--;
+ }
+
+ sep = (env.compress ? "" : "\n") + (this.root ? tabRuleStr : tabSetStr);
+ rulesetNodeCnt = rulesetNodes.length;
+ if (rulesetNodeCnt) {
+ if (ruleNodes.length && sep) { output.add(sep); }
+ rulesetNodes[0].genCSS(env, output);
+ for (i = 1; i < rulesetNodeCnt; i++) {
+ if (sep) { output.add(sep); }
+ rulesetNodes[i].genCSS(env, output);
}
- },
+ }
- toCSS: tree.toCSS,
+ if (!output.isEmpty() && !env.compress && this.firstRoot) {
+ output.add('\n');
+ }
+};
+Ruleset.prototype.markReferenced = function () {
+ if (!this.selectors) {
+ return;
+ }
+ for (var s = 0; s < this.selectors.length; s++) {
+ this.selectors[s].markReferenced();
+ }
+};
+Ruleset.prototype.joinSelectors = function (paths, context, selectors) {
+ for (var s = 0; s < selectors.length; s++) {
+ this.joinSelector(paths, context, selectors[s]);
+ }
+};
+Ruleset.prototype.joinSelector = function (paths, context, selector) {
- markReferenced: function () {
- if (!this.selectors) {
- return;
- }
- for (var s = 0; s < this.selectors.length; s++) {
- this.selectors[s].markReferenced();
- }
- },
+ var i, j, k,
+ hasParentSelector, newSelectors, el, sel, parentSel,
+ newSelectorPath, afterParentJoin, newJoinedSelector,
+ newJoinedSelectorEmpty, lastSelector, currentElements,
+ selectorsMultiplied;
- joinSelectors: function (paths, context, selectors) {
- for (var s = 0; s < selectors.length; s++) {
- this.joinSelector(paths, context, selectors[s]);
+ for (i = 0; i < selector.elements.length; i++) {
+ el = selector.elements[i];
+ if (el.value === '&') {
+ hasParentSelector = true;
}
- },
+ }
- joinSelector: function (paths, context, selector) {
+ if (!hasParentSelector) {
+ if (context.length > 0) {
+ for (i = 0; i < context.length; i++) {
+ paths.push(context[i].concat(selector));
+ }
+ }
+ else {
+ paths.push([selector]);
+ }
+ return;
+ }
- var i, j, k,
- hasParentSelector, newSelectors, el, sel, parentSel,
- newSelectorPath, afterParentJoin, newJoinedSelector,
- newJoinedSelectorEmpty, lastSelector, currentElements,
- selectorsMultiplied;
+ // 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 = [];
- for (i = 0; i < selector.elements.length; i++) {
- el = selector.elements[i];
- if (el.value === '&') {
- hasParentSelector = true;
+ // 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);
}
- }
- if (!hasParentSelector) {
- if (context.length > 0) {
- for (i = 0; i < context.length; i++) {
- paths.push(context[i].concat(selector));
+ // 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(Element)(el.combinator, '', el.index, el.currentFileInfo));
+ }
+ selectorsMultiplied.push(sel);
}
- }
- else {
- paths.push([selector]);
- }
- return;
- }
+ 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([]);
+ }
- // 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 = [];
+ //put together the parent selectors after the join
+ if (parentSel.length > 1) {
+ afterParentJoin = afterParentJoin.concat(parentSel.slice(1));
+ }
- // 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);
- }
+ if (parentSel.length > 0) {
+ newJoinedSelectorEmpty = false;
- // 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, '', el.index, el.currentFileInfo));
+ // join the elements so far with the first part of the parent
+ newJoinedSelector.elements.push(new(Element)(el.combinator, parentSel[0].elements[0].value, el.index, el.currentFileInfo));
+ newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));
}
- 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);
+
+ 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);
+ // our new selectors has been multiplied, so reset the state
+ newSelectors = selectorsMultiplied;
+ currentElements = [];
}
+ }
- for (i = 0; i < newSelectors.length; i++) {
- if (newSelectors[i].length > 0) {
- paths.push(newSelectors[i]);
- }
- }
- },
-
- mergeElementsOnToSelectors: function(elements, selectors) {
- var i, sel;
+ // 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);
+ }
- if (selectors.length === 0) {
- selectors.push([ new(tree.Selector)(elements) ]);
- return;
+ for (i = 0; i < newSelectors.length; i++) {
+ if (newSelectors[i].length > 0) {
+ paths.push(newSelectors[i]);
}
+ }
+};
+Ruleset.prototype.mergeElementsOnToSelectors = function(elements, selectors) {
+ var i, sel;
- for (i = 0; i < selectors.length; i++) {
- sel = selectors[i];
+ if (selectors.length === 0) {
+ selectors.push([ new(Selector)(elements) ]);
+ return;
+ }
- // 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));
- }
+ 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(Selector)(elements));
}
}
};
-return Ruleset;
-};
+module.exports = Ruleset;
diff --git a/lib/less/tree/selector.js b/lib/less/tree/selector.js
index 75d10e3..ef39ece 100644
--- a/lib/less/tree/selector.js
+++ b/lib/less/tree/selector.js
@@ -1,4 +1,4 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Selector = function (elements, extendList, condition, index, currentFileInfo, isReferenced) {
this.elements = elements;
@@ -10,120 +10,117 @@ var Selector = function (elements, extendList, condition, index, currentFileInfo
this.evaldCondition = true;
}
};
-Selector.prototype = {
- type: "Selector",
- accept: function (visitor) {
- if (this.elements) {
- this.elements = visitor.visitArray(this.elements);
- }
- if (this.extendList) {
- this.extendList = visitor.visitArray(this.extendList);
- }
- if (this.condition) {
- this.condition = visitor.visit(this.condition);
- }
- },
- createDerived: function(elements, extendList, evaldCondition) {
- evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition;
- var newSelector = new(Selector)(elements, extendList || this.extendList, null, this.index, this.currentFileInfo, this.isReferenced);
- newSelector.evaldCondition = evaldCondition;
- newSelector.mediaEmpty = this.mediaEmpty;
- return newSelector;
- },
- match: function (other) {
- var elements = this.elements,
- len = elements.length,
- olen, i;
+Selector.prototype = new Node();
+Selector.prototype.type = "Selector";
+Selector.prototype.accept = function (visitor) {
+ if (this.elements) {
+ this.elements = visitor.visitArray(this.elements);
+ }
+ if (this.extendList) {
+ this.extendList = visitor.visitArray(this.extendList);
+ }
+ if (this.condition) {
+ this.condition = visitor.visit(this.condition);
+ }
+};
+Selector.prototype.createDerived = function(elements, extendList, evaldCondition) {
+ evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition;
+ var newSelector = new(Selector)(elements, extendList || this.extendList, null, this.index, this.currentFileInfo, this.isReferenced);
+ newSelector.evaldCondition = evaldCondition;
+ newSelector.mediaEmpty = this.mediaEmpty;
+ return newSelector;
+};
+Selector.prototype.match = function (other) {
+ var elements = this.elements,
+ len = elements.length,
+ olen, i;
- other.CacheElements();
+ other.CacheElements();
- olen = other._elements.length;
- if (olen === 0 || len < olen) {
- return 0;
- } else {
- for (i = 0; i < olen; i++) {
- if (elements[i].value !== other._elements[i]) {
- return 0;
- }
+ olen = other._elements.length;
+ if (olen === 0 || len < olen) {
+ return 0;
+ } else {
+ for (i = 0; i < olen; i++) {
+ if (elements[i].value !== other._elements[i]) {
+ return 0;
}
}
+ }
- return olen; // return number of matched elements
- },
- CacheElements: function(){
- var css = '', len, v, i;
-
- if( !this._elements ){
+ return olen; // return number of matched elements
+};
+Selector.prototype.CacheElements = function(){
+ var css = '', len, v, i;
- len = this.elements.length;
- for(i = 0; i < len; i++){
+ if( !this._elements ){
- v = this.elements[i];
- css += v.combinator.value;
+ len = this.elements.length;
+ for(i = 0; i < len; i++){
- if( !v.value.value ){
- css += v.value;
- continue;
- }
+ v = this.elements[i];
+ css += v.combinator.value;
- if( typeof v.value.value !== "string" ){
- css = '';
- break;
- }
- css += v.value.value;
+ if( !v.value.value ){
+ css += v.value;
+ continue;
}
- this._elements = css.match(/[,&#\*\.\w-]([\w-]|(\\.))*/g);
+ if( typeof v.value.value !== "string" ){
+ css = '';
+ break;
+ }
+ css += v.value.value;
+ }
- if (this._elements) {
- if (this._elements[0] === "&") {
- this._elements.shift();
- }
+ this._elements = css.match(/[,&#\*\.\w-]([\w-]|(\\.))*/g);
- } else {
- this._elements = [];
+ if (this._elements) {
+ if (this._elements[0] === "&") {
+ this._elements.shift();
}
+ } else {
+ this._elements = [];
}
- },
- isJustParentSelector: function() {
- return !this.mediaEmpty &&
- this.elements.length === 1 &&
- this.elements[0].value === '&' &&
- (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === '');
- },
- eval: function (env) {
- var evaldCondition = this.condition && this.condition.eval(env),
- elements = this.elements, extendList = this.extendList;
- elements = elements && elements.map(function (e) { return e.eval(env); });
- extendList = extendList && extendList.map(function(extend) { return extend.eval(env); });
+ }
+};
+Selector.prototype.isJustParentSelector = function() {
+ return !this.mediaEmpty &&
+ this.elements.length === 1 &&
+ this.elements[0].value === '&' &&
+ (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === '');
+};
+Selector.prototype.eval = function (env) {
+ var evaldCondition = this.condition && this.condition.eval(env),
+ elements = this.elements, extendList = this.extendList;
- return this.createDerived(elements, extendList, 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);
- }
+ elements = elements && elements.map(function (e) { return e.eval(env); });
+ extendList = extendList && extendList.map(function(extend) { return extend.eval(env); });
+
+ return this.createDerived(elements, extendList, evaldCondition);
+};
+Selector.prototype.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;
}
};
-return Selector;
+Selector.prototype.markReferenced = function () {
+ this.isReferenced = true;
+};
+Selector.prototype.getIsReferenced = function() {
+ return !this.currentFileInfo.reference || this.isReferenced;
+};
+Selector.prototype.getIsOutput = function() {
+ return this.evaldCondition;
};
+module.exports = Selector;
diff --git a/lib/less/tree/unicode-descriptor.js b/lib/less/tree/unicode-descriptor.js
index 674ac98..72f33ea 100644
--- a/lib/less/tree/unicode-descriptor.js
+++ b/lib/less/tree/unicode-descriptor.js
@@ -1,15 +1,9 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var UnicodeDescriptor = function (value) {
this.value = value;
};
-UnicodeDescriptor.prototype = {
- type: "UnicodeDescriptor",
- genCSS: function (env, output) {
- output.add(this.value);
- },
- toCSS: tree.toCSS,
- eval: function () { return this; }
-};
-return UnicodeDescriptor;
-};
+UnicodeDescriptor.prototype = new Node();
+UnicodeDescriptor.prototype.type = "UnicodeDescriptor";
+
+module.exports = UnicodeDescriptor;
diff --git a/lib/less/tree/unit.js b/lib/less/tree/unit.js
index c25a717..9589498 100644
--- a/lib/less/tree/unit.js
+++ b/lib/less/tree/unit.js
@@ -1,4 +1,5 @@
-module.exports = function(tree, unitConversions) {
+var Node = require("./node.js"),
+ unitConversions = require("../data/unit-conversions.js");
var Unit = function (numerator, denominator, backupUnit) {
this.numerator = numerator ? numerator.slice(0).sort() : [];
@@ -6,132 +7,120 @@ var Unit = function (numerator, denominator, backupUnit) {
this.backupUnit = backupUnit;
};
-Unit.prototype = {
- type: "Unit",
- clone: function () {
- return new 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;
- },
+Unit.prototype = new Node();
+Unit.prototype.type = "Unit";
+Unit.prototype.clone = function () {
+ return new Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit);
+};
+Unit.prototype.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);
+ }
+};
+Unit.prototype.toString = function () {
+ var i, returnStr = this.numerator.join("*");
+ for (i = 0; i < this.denominator.length; i++) {
+ returnStr += "/" + this.denominator[i];
+ }
+ return returnStr;
+};
+Unit.prototype.compare = function (other) {
+ return this.is(other.toString()) ? 0 : -1;
+};
+Unit.prototype.is = function (unitString) {
+ return this.toString() === unitString;
+};
+Unit.prototype.isLength = function () {
+ return Boolean(this.toCSS().match(/px|em|%|in|cm|mm|pc|pt|ex/));
+};
+Unit.prototype.isEmpty = function () {
+ return this.numerator.length === 0 && this.denominator.length === 0;
+};
+Unit.prototype.isSingular = function() {
+ return this.numerator.length <= 1 && this.denominator.length === 0;
+};
+Unit.prototype.map = function(callback) {
+ var i;
- 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.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);
+ }
+};
+Unit.prototype.usedUnits = function() {
+ var group, result = {}, mapUnit;
- for (i = 0; i < this.denominator.length; i++) {
- this.denominator[i] = callback(this.denominator[i], true);
+ mapUnit = function (atomicUnit) {
+ /*jshint loopfunc:true */
+ if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
+ result[groupName] = atomicUnit;
}
- },
-
- usedUnits: function() {
- var group, result = {}, mapUnit;
-
- mapUnit = function (atomicUnit) {
- /*jshint loopfunc:true */
- if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
- result[groupName] = atomicUnit;
- }
- return atomicUnit;
- };
+ return atomicUnit;
+ };
- for (var groupName in unitConversions) {
- if (unitConversions.hasOwnProperty(groupName)) {
- group = unitConversions[groupName];
+ for (var groupName in unitConversions) {
+ if (unitConversions.hasOwnProperty(groupName)) {
+ group = unitConversions[groupName];
- this.map(mapUnit);
- }
+ this.map(mapUnit);
}
+ }
- return result;
- },
-
- cancel: function () {
- var counter = {}, atomicUnit, i, backup;
+ return result;
+};
+Unit.prototype.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.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;
+ 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];
- 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 (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();
+ if (this.numerator.length === 0 && this.denominator.length === 0 && backup) {
+ this.backupUnit = backup;
}
+
+ this.numerator.sort();
+ this.denominator.sort();
};
-return Unit;
-};
\ No newline at end of file
+module.exports = Unit;
diff --git a/lib/less/tree/url.js b/lib/less/tree/url.js
index 811c407..603e4b7 100644
--- a/lib/less/tree/url.js
+++ b/lib/less/tree/url.js
@@ -1,53 +1,50 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var URL = function (val, currentFileInfo, isEvald) {
this.value = val;
this.currentFileInfo = currentFileInfo;
this.isEvald = isEvald;
};
-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;
+URL.prototype = new Node();
+URL.prototype.type = "Url";
+URL.prototype.accept = function (visitor) {
+ this.value = visitor.visit(this.value);
+};
+URL.prototype.genCSS = function (env, output) {
+ output.add("url(");
+ this.value.genCSS(env, output);
+ output.add(")");
+};
+URL.prototype.eval = function (ctx) {
+ var val = this.value.eval(ctx),
+ rootpath;
- if (!this.isEvald) {
- // 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;
+ if (!this.isEvald) {
+ // 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);
+ val.value = ctx.normalizePath(val.value);
- // Add url args if enabled
- if (ctx.urlArgs) {
- if (!val.value.match(/^\s*data:/)) {
- var delimiter = val.value.indexOf('?') === -1 ? '?' : '&';
- var urlArgs = delimiter + ctx.urlArgs;
- if (val.value.indexOf('#') !== -1) {
- val.value = val.value.replace('#', urlArgs + '#');
- } else {
- val.value += urlArgs;
- }
+ // Add url args if enabled
+ if (ctx.urlArgs) {
+ if (!val.value.match(/^\s*data:/)) {
+ var delimiter = val.value.indexOf('?') === -1 ? '?' : '&';
+ var urlArgs = delimiter + ctx.urlArgs;
+ if (val.value.indexOf('#') !== -1) {
+ val.value = val.value.replace('#', urlArgs + '#');
+ } else {
+ val.value += urlArgs;
}
}
}
-
- return new(URL)(val, this.currentFileInfo, true);
}
+
+ return new(URL)(val, this.currentFileInfo, true);
};
-return URL;
-};
+module.exports = URL;
diff --git a/lib/less/tree/value.js b/lib/less/tree/value.js
index ea07367..fb1c7f8 100644
--- a/lib/less/tree/value.js
+++ b/lib/less/tree/value.js
@@ -1,34 +1,31 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Value = function (value) {
this.value = value;
};
-Value.prototype = {
- type: "Value",
- accept: function (visitor) {
- if (this.value) {
- this.value = visitor.visitArray(this.value);
- }
- },
- eval: function (env) {
- if (this.value.length === 1) {
- return this.value[0].eval(env);
- } else {
- return new(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
+Value.prototype = new Node();
+Value.prototype.type = "Value";
+Value.prototype.accept = function (visitor) {
+ if (this.value) {
+ this.value = visitor.visitArray(this.value);
+ }
};
-return Value;
+Value.prototype.eval = function (env) {
+ if (this.value.length === 1) {
+ return this.value[0].eval(env);
+ } else {
+ return new(Value)(this.value.map(function (v) {
+ return v.eval(env);
+ }));
+ }
+};
+Value.prototype.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) ? ',' : ', ');
+ }
+ }
};
+module.exports = Value;
diff --git a/lib/less/tree/variable.js b/lib/less/tree/variable.js
index 71c373f..85641a7 100644
--- a/lib/less/tree/variable.js
+++ b/lib/less/tree/variable.js
@@ -1,44 +1,49 @@
-module.exports = function (tree) {
+var Node = require("./node.js");
var Variable = function (name, index, currentFileInfo) {
this.name = name;
this.index = index;
this.currentFileInfo = currentFileInfo || {};
};
-Variable.prototype = {
- type: "Variable",
- eval: function (env) {
- var variable, name = this.name;
+Variable.prototype = new Node();
+Variable.prototype.type = "Variable";
+Variable.prototype.eval = function (env) {
+ var variable, name = this.name;
- if (name.indexOf('@@') === 0) {
- name = '@' + new(Variable)(name.slice(1)).eval(env).value;
- }
+ if (name.indexOf('@@') === 0) {
+ name = '@' + new(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 };
- }
+ if (this.evaluating) {
+ throw { type: 'Name',
+ message: "Recursive variable definition for " + name,
+ filename: this.currentFileInfo.file,
+ index: this.index };
+ }
- this.evaluating = true;
+ this.evaluating = true;
- variable = tree.find(env.frames, function (frame) {
- var v = frame.variable(name);
- if (v) {
- return v.value.eval(env);
- }
- });
- if (variable) {
- this.evaluating = false;
- return variable;
- } else {
- throw { type: 'Name',
- message: "variable " + name + " is undefined",
- filename: this.currentFileInfo.filename,
- index: this.index };
+ variable = this.find(env.frames, function (frame) {
+ var v = frame.variable(name);
+ if (v) {
+ return v.value.eval(env);
}
+ });
+ if (variable) {
+ this.evaluating = false;
+ return variable;
+ } else {
+ throw { type: 'Name',
+ message: "variable " + name + " is undefined",
+ filename: this.currentFileInfo.filename,
+ index: this.index };
}
};
-return Variable;
+Variable.prototype.find = function (obj, fun) {
+ for (var i = 0, r; i < obj.length; i++) {
+ r = fun.call(obj, obj[i]);
+ if (r) { return r; }
+ }
+ return null;
};
+module.exports = Variable;
diff --git a/lib/less/visitor/import-visitor.js b/lib/less/visitor/import-visitor.js
index 1dc19f2..2f1c24b 100644
--- a/lib/less/visitor/import-visitor.js
+++ b/lib/less/visitor/import-visitor.js
@@ -1,9 +1,10 @@
+var contexts = require("../env.js");
module.exports = function (visitor, tree) {
var ImportVisitor = function(importer, finish, evalEnv, onceFileDetectionMap, recursionDetector) {
this._visitor = new visitor(this);
this._importer = importer;
this._finish = finish;
- this.env = evalEnv || new tree.evalEnv();
+ this.env = evalEnv || new contexts.evalEnv();
this.importCount = 0;
this.onceFileDetectionMap = onceFileDetectionMap || {};
this.recursionDetector = {};
@@ -54,7 +55,7 @@ module.exports = function (visitor, tree) {
if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {
importNode = evaldImportNode;
this.importCount++;
- var env = new tree.evalEnv(this.env, this.env.frames.slice(0));
+ var env = new contexts.evalEnv(this.env, this.env.frames.slice(0));
if (importNode.options.multiple) {
env.importMultiple = true;
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/less.js.git
More information about the Pkg-javascript-commits
mailing list