[Pkg-javascript-commits] [less.js] 67/285: Also remove dep-injection from visitors, none of which use environment. make functions used as classes TitleCase
Jonas Smedegaard
dr at jones.dk
Mon Oct 26 23:23:39 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 e325aec74d396f8bc0a412f80a5107a1f6f4af05
Author: Luke Page <luke.a.page at gmail.com>
Date: Sun Aug 24 18:47:25 2014 +0100
Also remove dep-injection from visitors, none of which use environment. make functions used as classes TitleCase
---
lib/less/non-node-index.js | 2 +-
lib/less/parser.js | 8 +-
lib/less/visitor/extend-visitor.js | 733 +++++++++++++++---------------
lib/less/visitor/import-visitor.js | 246 +++++-----
lib/less/visitor/index.js | 20 +-
lib/less/visitor/join-selector-visitor.js | 78 ++--
lib/less/visitor/to-css-visitor.js | 409 ++++++++---------
lib/less/visitor/visitor.js | 239 +++++-----
8 files changed, 866 insertions(+), 869 deletions(-)
diff --git a/lib/less/non-node-index.js b/lib/less/non-node-index.js
index a14c1c3..8c1abfc 100644
--- a/lib/less/non-node-index.js
+++ b/lib/less/non-node-index.js
@@ -4,7 +4,7 @@ var less = {
};
less.tree = require('./tree/index.js');
-less.visitor = require('./visitor/index.js')(less, less.tree);
+less.visitor = require('./visitor/index.js');
less.Parser = (require('./parser'))(less, less.tree, less.visitor);
less.functions = require('./functions/index.js')(less);
less.contexts = require("./contexts.js");
diff --git a/lib/less/parser.js b/lib/less/parser.js
index 7a8744e..e909957 100644
--- a/lib/less/parser.js
+++ b/lib/less/parser.js
@@ -485,9 +485,9 @@ var Parser = function Parser(env) {
try {
var preEvalVisitors = [],
visitors = [
- new(visitor.joinSelectorVisitor)(),
- new(visitor.extendVisitor)(),
- new(visitor.toCSSVisitor)({compress: Boolean(options.compress)})
+ new(visitor.JoinSelectorVisitor)(),
+ new(visitor.ExtendVisitor)(),
+ new(visitor.ToCSSVisitor)({compress: Boolean(options.compress)})
], i, root = this;
if (options.plugins) {
@@ -623,7 +623,7 @@ var Parser = function Parser(env) {
};
if (env.processImports !== false) {
- new visitor.importVisitor(this.imports, finish)
+ new visitor.ImportVisitor(this.imports, finish)
.run(root);
} else {
return finish();
diff --git a/lib/less/visitor/extend-visitor.js b/lib/less/visitor/extend-visitor.js
index bd63614..9616cd6 100644
--- a/lib/less/visitor/extend-visitor.js
+++ b/lib/less/visitor/extend-visitor.js
@@ -1,417 +1,418 @@
-module.exports = function (visitor, tree) {
- /*jshint loopfunc:true */
-
- var extendFinderVisitor = function() {
- this._visitor = new visitor(this);
- this.contexts = [];
- this.allExtendsStack = [[]];
- };
-
- extendFinderVisitor.prototype = {
- run: function (root) {
- root = this._visitor.visit(root);
- root.allExtends = this.allExtendsStack[0];
- return root;
- },
- visitRule: function (ruleNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitRuleset: function (rulesetNode, visitArgs) {
- if (rulesetNode.root) {
- return;
- }
+var tree = require("../tree/index.js"),
+ Visitor = require("./visitor.js");
- var i, j, extend, allSelectorsExtendList = [], extendList;
+/*jshint loopfunc:true */
- // get &:extend(.a); rules which apply to all selectors in this ruleset
- var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0;
- for(i = 0; i < ruleCnt; i++) {
- if (rulesetNode.rules[i] instanceof tree.Extend) {
- allSelectorsExtendList.push(rules[i]);
- rulesetNode.extendOnEveryPath = true;
- }
- }
+var ExtendFinderVisitor = function() {
+ this._visitor = new Visitor(this);
+ this.contexts = [];
+ this.allExtendsStack = [[]];
+};
- // now find every selector and apply the extends that apply to all extends
- // and the ones which apply to an individual extend
- var paths = rulesetNode.paths;
- for(i = 0; i < paths.length; i++) {
- var selectorPath = paths[i],
- selector = selectorPath[selectorPath.length - 1],
- selExtendList = selector.extendList;
+ExtendFinderVisitor.prototype = {
+ run: function (root) {
+ root = this._visitor.visit(root);
+ root.allExtends = this.allExtendsStack[0];
+ return root;
+ },
+ visitRule: function (ruleNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitRuleset: function (rulesetNode, visitArgs) {
+ if (rulesetNode.root) {
+ return;
+ }
- extendList = selExtendList ? selExtendList.slice(0).concat(allSelectorsExtendList)
- : allSelectorsExtendList;
+ var i, j, extend, allSelectorsExtendList = [], extendList;
- if (extendList) {
- extendList = extendList.map(function(allSelectorsExtend) {
- return allSelectorsExtend.clone();
- });
- }
+ // get &:extend(.a); rules which apply to all selectors in this ruleset
+ var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0;
+ for(i = 0; i < ruleCnt; i++) {
+ if (rulesetNode.rules[i] instanceof tree.Extend) {
+ allSelectorsExtendList.push(rules[i]);
+ rulesetNode.extendOnEveryPath = true;
+ }
+ }
- for(j = 0; j < extendList.length; j++) {
- this.foundExtends = true;
- extend = extendList[j];
- extend.findSelfSelectors(selectorPath);
- extend.ruleset = rulesetNode;
- if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
- this.allExtendsStack[this.allExtendsStack.length-1].push(extend);
- }
+ // now find every selector and apply the extends that apply to all extends
+ // and the ones which apply to an individual extend
+ var paths = rulesetNode.paths;
+ for(i = 0; i < paths.length; i++) {
+ var selectorPath = paths[i],
+ selector = selectorPath[selectorPath.length - 1],
+ selExtendList = selector.extendList;
+
+ extendList = selExtendList ? selExtendList.slice(0).concat(allSelectorsExtendList)
+ : allSelectorsExtendList;
+
+ if (extendList) {
+ extendList = extendList.map(function(allSelectorsExtend) {
+ return allSelectorsExtend.clone();
+ });
}
- this.contexts.push(rulesetNode.selectors);
- },
- visitRulesetOut: function (rulesetNode) {
- if (!rulesetNode.root) {
- this.contexts.length = this.contexts.length - 1;
+ for(j = 0; j < extendList.length; j++) {
+ this.foundExtends = true;
+ extend = extendList[j];
+ extend.findSelfSelectors(selectorPath);
+ extend.ruleset = rulesetNode;
+ if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
+ this.allExtendsStack[this.allExtendsStack.length-1].push(extend);
}
- },
- visitMedia: function (mediaNode, visitArgs) {
- mediaNode.allExtends = [];
- this.allExtendsStack.push(mediaNode.allExtends);
- },
- visitMediaOut: function (mediaNode) {
- this.allExtendsStack.length = this.allExtendsStack.length - 1;
- },
- visitDirective: function (directiveNode, visitArgs) {
- directiveNode.allExtends = [];
- this.allExtendsStack.push(directiveNode.allExtends);
- },
- visitDirectiveOut: function (directiveNode) {
- this.allExtendsStack.length = this.allExtendsStack.length - 1;
}
- };
-
- var processExtendsVisitor = function() {
- this._visitor = new visitor(this);
- };
-
- processExtendsVisitor.prototype = {
- run: function(root) {
- var extendFinder = new extendFinderVisitor();
- extendFinder.run(root);
- if (!extendFinder.foundExtends) { return root; }
- root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
- this.allExtendsStack = [root.allExtends];
- return this._visitor.visit(root);
- },
- doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
- //
- // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
- // the selector we would do normally, but we are also adding an extend with the same target selector
- // this means this new extend can then go and alter other extends
- //
- // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
- // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
- // we look at each selector at a time, as is done in visitRuleset
-
- var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend, newExtend;
-
- iterationCount = iterationCount || 0;
-
- //loop through comparing every extend with every target extend.
- // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
- // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
- // and the second is the target.
- // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
- // case when processing media queries
- for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){
- for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){
-
- extend = extendsList[extendIndex];
- targetExtend = extendsListTarget[targetExtendIndex];
-
- // look for circular references
- if( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ){ continue; }
-
- // find a match in the target extends self selector (the bit before :extend)
- selectorPath = [targetExtend.selfSelectors[0]];
- matches = extendVisitor.findMatch(extend, selectorPath);
-
- if (matches.length) {
-
- // we found a match, so for each self selector..
- extend.selfSelectors.forEach(function(selfSelector) {
-
- // process the extend as usual
- newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector);
-
- // but now we create a new extend from it
- newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0);
- newExtend.selfSelectors = newSelector;
-
- // add the extend onto the list of extends for that selector
- newSelector[newSelector.length-1].extendList = [newExtend];
-
- // record that we need to add it.
- extendsToAdd.push(newExtend);
- newExtend.ruleset = targetExtend.ruleset;
-
- //remember its parents for circular references
- newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids);
-
- // only process the selector once.. if we have :extend(.a,.b) then multiple
- // extends will look at the same selector path, so when extending
- // we know that any others will be duplicates in terms of what is added to the css
- if (targetExtend.firstExtendOnThisSelectorPath) {
- newExtend.firstExtendOnThisSelectorPath = true;
- targetExtend.ruleset.paths.push(newSelector);
- }
- });
- }
+
+ this.contexts.push(rulesetNode.selectors);
+ },
+ visitRulesetOut: function (rulesetNode) {
+ if (!rulesetNode.root) {
+ this.contexts.length = this.contexts.length - 1;
+ }
+ },
+ visitMedia: function (mediaNode, visitArgs) {
+ mediaNode.allExtends = [];
+ this.allExtendsStack.push(mediaNode.allExtends);
+ },
+ visitMediaOut: function (mediaNode) {
+ this.allExtendsStack.length = this.allExtendsStack.length - 1;
+ },
+ visitDirective: function (directiveNode, visitArgs) {
+ directiveNode.allExtends = [];
+ this.allExtendsStack.push(directiveNode.allExtends);
+ },
+ visitDirectiveOut: function (directiveNode) {
+ this.allExtendsStack.length = this.allExtendsStack.length - 1;
+ }
+};
+
+var ProcessExtendsVisitor = function() {
+ this._visitor = new Visitor(this);
+};
+
+ProcessExtendsVisitor.prototype = {
+ run: function(root) {
+ var extendFinder = new ExtendFinderVisitor();
+ extendFinder.run(root);
+ if (!extendFinder.foundExtends) { return root; }
+ root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
+ this.allExtendsStack = [root.allExtends];
+ return this._visitor.visit(root);
+ },
+ doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
+ //
+ // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
+ // the selector we would do normally, but we are also adding an extend with the same target selector
+ // this means this new extend can then go and alter other extends
+ //
+ // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
+ // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
+ // we look at each selector at a time, as is done in visitRuleset
+
+ var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend, newExtend;
+
+ iterationCount = iterationCount || 0;
+
+ //loop through comparing every extend with every target extend.
+ // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
+ // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
+ // and the second is the target.
+ // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
+ // case when processing media queries
+ for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){
+ for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){
+
+ extend = extendsList[extendIndex];
+ targetExtend = extendsListTarget[targetExtendIndex];
+
+ // look for circular references
+ if( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ){ continue; }
+
+ // find a match in the target extends self selector (the bit before :extend)
+ selectorPath = [targetExtend.selfSelectors[0]];
+ matches = extendVisitor.findMatch(extend, selectorPath);
+
+ if (matches.length) {
+
+ // we found a match, so for each self selector..
+ extend.selfSelectors.forEach(function(selfSelector) {
+
+ // process the extend as usual
+ newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector);
+
+ // but now we create a new extend from it
+ newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0);
+ newExtend.selfSelectors = newSelector;
+
+ // add the extend onto the list of extends for that selector
+ newSelector[newSelector.length-1].extendList = [newExtend];
+
+ // record that we need to add it.
+ extendsToAdd.push(newExtend);
+ newExtend.ruleset = targetExtend.ruleset;
+
+ //remember its parents for circular references
+ newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids);
+
+ // only process the selector once.. if we have :extend(.a,.b) then multiple
+ // extends will look at the same selector path, so when extending
+ // we know that any others will be duplicates in terms of what is added to the css
+ if (targetExtend.firstExtendOnThisSelectorPath) {
+ newExtend.firstExtendOnThisSelectorPath = true;
+ targetExtend.ruleset.paths.push(newSelector);
+ }
+ });
}
}
+ }
- if (extendsToAdd.length) {
- // try to detect circular references to stop a stack overflow.
- // may no longer be needed.
- this.extendChainCount++;
- if (iterationCount > 100) {
- var selectorOne = "{unable to calculate}";
- var selectorTwo = "{unable to calculate}";
- try
- {
- selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
- selectorTwo = extendsToAdd[0].selector.toCSS();
- }
- catch(e) {}
- throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"};
+ if (extendsToAdd.length) {
+ // try to detect circular references to stop a stack overflow.
+ // may no longer be needed.
+ this.extendChainCount++;
+ if (iterationCount > 100) {
+ var selectorOne = "{unable to calculate}";
+ var selectorTwo = "{unable to calculate}";
+ try
+ {
+ selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
+ selectorTwo = extendsToAdd[0].selector.toCSS();
}
-
- // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
- return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1));
- } else {
- return extendsToAdd;
- }
- },
- visitRule: function (ruleNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitSelector: function (selectorNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitRuleset: function (rulesetNode, visitArgs) {
- if (rulesetNode.root) {
- return;
+ catch(e) {}
+ throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"};
}
- var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this, selectorPath;
- // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
+ // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
+ return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1));
+ } else {
+ return extendsToAdd;
+ }
+ },
+ visitRule: function (ruleNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitSelector: function (selectorNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitRuleset: function (rulesetNode, visitArgs) {
+ if (rulesetNode.root) {
+ return;
+ }
+ var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this, selectorPath;
- for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
- for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
- selectorPath = rulesetNode.paths[pathIndex];
+ // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
- // extending extends happens initially, before the main pass
- if (rulesetNode.extendOnEveryPath) { continue; }
- var extendList = selectorPath[selectorPath.length-1].extendList;
- if (extendList && extendList.length) { continue; }
+ for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
+ for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
+ selectorPath = rulesetNode.paths[pathIndex];
- matches = this.findMatch(allExtends[extendIndex], selectorPath);
+ // extending extends happens initially, before the main pass
+ if (rulesetNode.extendOnEveryPath) { continue; }
+ var extendList = selectorPath[selectorPath.length-1].extendList;
+ if (extendList && extendList.length) { continue; }
- if (matches.length) {
+ matches = this.findMatch(allExtends[extendIndex], selectorPath);
- allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
- selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector));
- });
- }
+ if (matches.length) {
+
+ allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
+ selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector));
+ });
}
}
- rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
- },
- findMatch: function (extend, haystackSelectorPath) {
- //
- // look through the haystack selector path to try and find the needle - extend.selector
- // returns an array of selector matches that can then be replaced
- //
- var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement,
- targetCombinator, i,
- extendVisitor = this,
- needleElements = extend.selector.elements,
- potentialMatches = [], potentialMatch, matches = [];
-
- // loop through the haystack elements
- for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
- hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
-
- for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
-
- haystackElement = hackstackSelector.elements[hackstackElementIndex];
-
- // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
- if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
- potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator});
- }
+ }
+ rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
+ },
+ findMatch: function (extend, haystackSelectorPath) {
+ //
+ // look through the haystack selector path to try and find the needle - extend.selector
+ // returns an array of selector matches that can then be replaced
+ //
+ var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement,
+ targetCombinator, i,
+ extendVisitor = this,
+ needleElements = extend.selector.elements,
+ potentialMatches = [], potentialMatch, matches = [];
+
+ // loop through the haystack elements
+ for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
+ hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
+
+ for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
+
+ haystackElement = hackstackSelector.elements[hackstackElementIndex];
+
+ // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
+ if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
+ potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator});
+ }
- for(i = 0; i < potentialMatches.length; i++) {
- potentialMatch = potentialMatches[i];
+ for(i = 0; i < potentialMatches.length; i++) {
+ potentialMatch = potentialMatches[i];
- // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
- // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
- // what the resulting combinator will be
- targetCombinator = haystackElement.combinator.value;
- if (targetCombinator === '' && hackstackElementIndex === 0) {
- targetCombinator = ' ';
- }
+ // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
+ // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
+ // what the resulting combinator will be
+ targetCombinator = haystackElement.combinator.value;
+ if (targetCombinator === '' && hackstackElementIndex === 0) {
+ targetCombinator = ' ';
+ }
- // if we don't match, null our match to indicate failure
- if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) ||
- (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {
- potentialMatch = null;
- } else {
- potentialMatch.matched++;
- }
+ // if we don't match, null our match to indicate failure
+ if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) ||
+ (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {
+ potentialMatch = null;
+ } else {
+ potentialMatch.matched++;
+ }
- // if we are still valid and have finished, test whether we have elements after and whether these are allowed
- if (potentialMatch) {
- potentialMatch.finished = potentialMatch.matched === needleElements.length;
- if (potentialMatch.finished &&
- (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) {
- potentialMatch = null;
- }
+ // if we are still valid and have finished, test whether we have elements after and whether these are allowed
+ if (potentialMatch) {
+ potentialMatch.finished = potentialMatch.matched === needleElements.length;
+ if (potentialMatch.finished &&
+ (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) {
+ potentialMatch = null;
}
- // if null we remove, if not, we are still valid, so either push as a valid match or continue
- if (potentialMatch) {
- if (potentialMatch.finished) {
- potentialMatch.length = needleElements.length;
- potentialMatch.endPathIndex = haystackSelectorIndex;
- potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match
- potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again
- matches.push(potentialMatch);
- }
- } else {
- potentialMatches.splice(i, 1);
- i--;
+ }
+ // if null we remove, if not, we are still valid, so either push as a valid match or continue
+ if (potentialMatch) {
+ if (potentialMatch.finished) {
+ potentialMatch.length = needleElements.length;
+ potentialMatch.endPathIndex = haystackSelectorIndex;
+ potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match
+ potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again
+ matches.push(potentialMatch);
}
+ } else {
+ potentialMatches.splice(i, 1);
+ i--;
}
}
}
- return matches;
- },
- isElementValuesEqual: function(elementValue1, elementValue2) {
- if (typeof elementValue1 === "string" || typeof elementValue2 === "string") {
- return elementValue1 === elementValue2;
+ }
+ return matches;
+ },
+ isElementValuesEqual: function(elementValue1, elementValue2) {
+ if (typeof elementValue1 === "string" || typeof elementValue2 === "string") {
+ return elementValue1 === elementValue2;
+ }
+ if (elementValue1 instanceof tree.Attribute) {
+ if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {
+ return false;
}
- if (elementValue1 instanceof tree.Attribute) {
- if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {
+ if (!elementValue1.value || !elementValue2.value) {
+ if (elementValue1.value || elementValue2.value) {
return false;
}
- if (!elementValue1.value || !elementValue2.value) {
- if (elementValue1.value || elementValue2.value) {
+ return true;
+ }
+ elementValue1 = elementValue1.value.value || elementValue1.value;
+ elementValue2 = elementValue2.value.value || elementValue2.value;
+ return elementValue1 === elementValue2;
+ }
+ elementValue1 = elementValue1.value;
+ elementValue2 = elementValue2.value;
+ if (elementValue1 instanceof tree.Selector) {
+ if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
+ return false;
+ }
+ for(var i = 0; i <elementValue1.elements.length; i++) {
+ if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {
+ if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {
return false;
}
- return true;
}
- elementValue1 = elementValue1.value.value || elementValue1.value;
- elementValue2 = elementValue2.value.value || elementValue2.value;
- return elementValue1 === elementValue2;
- }
- elementValue1 = elementValue1.value;
- elementValue2 = elementValue2.value;
- if (elementValue1 instanceof tree.Selector) {
- if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
+ if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) {
return false;
}
- for(var i = 0; i <elementValue1.elements.length; i++) {
- if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {
- if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {
- return false;
- }
- }
- if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) {
- return false;
- }
- }
- return true;
}
- return false;
- },
- extendSelector:function (matches, selectorPath, replacementSelector) {
-
- //for a set of matches, replace each match with the replacement selector
-
- var currentSelectorPathIndex = 0,
- currentSelectorPathElementIndex = 0,
- path = [],
- matchIndex,
- selector,
- firstElement,
- match,
- newElements;
-
- for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {
- match = matches[matchIndex];
- selector = selectorPath[match.pathIndex];
- firstElement = new tree.Element(
- match.initialCombinator,
- replacementSelector.elements[0].value,
- replacementSelector.elements[0].index,
- replacementSelector.elements[0].currentFileInfo
- );
-
- if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
- path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
- currentSelectorPathElementIndex = 0;
- currentSelectorPathIndex++;
- }
+ return true;
+ }
+ return false;
+ },
+ extendSelector:function (matches, selectorPath, replacementSelector) {
+
+ //for a set of matches, replace each match with the replacement selector
+
+ var currentSelectorPathIndex = 0,
+ currentSelectorPathElementIndex = 0,
+ path = [],
+ matchIndex,
+ selector,
+ firstElement,
+ match,
+ newElements;
+
+ for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {
+ match = matches[matchIndex];
+ selector = selectorPath[match.pathIndex];
+ firstElement = new tree.Element(
+ match.initialCombinator,
+ replacementSelector.elements[0].value,
+ replacementSelector.elements[0].index,
+ replacementSelector.elements[0].currentFileInfo
+ );
+
+ if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
+ path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
+ currentSelectorPathElementIndex = 0;
+ currentSelectorPathIndex++;
+ }
- newElements = selector.elements
- .slice(currentSelectorPathElementIndex, match.index)
- .concat([firstElement])
- .concat(replacementSelector.elements.slice(1));
+ newElements = selector.elements
+ .slice(currentSelectorPathElementIndex, match.index)
+ .concat([firstElement])
+ .concat(replacementSelector.elements.slice(1));
- if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {
- path[path.length - 1].elements =
- path[path.length - 1].elements.concat(newElements);
- } else {
- path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
+ if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {
+ path[path.length - 1].elements =
+ path[path.length - 1].elements.concat(newElements);
+ } else {
+ path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
- path.push(new tree.Selector(
- newElements
- ));
- }
- currentSelectorPathIndex = match.endPathIndex;
- currentSelectorPathElementIndex = match.endPathElementIndex;
- if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {
- currentSelectorPathElementIndex = 0;
- currentSelectorPathIndex++;
- }
+ path.push(new tree.Selector(
+ newElements
+ ));
}
-
- if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
- path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
+ currentSelectorPathIndex = match.endPathIndex;
+ currentSelectorPathElementIndex = match.endPathElementIndex;
+ if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {
+ currentSelectorPathElementIndex = 0;
currentSelectorPathIndex++;
}
+ }
- path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
-
- return path;
- },
- visitRulesetOut: function (rulesetNode) {
- },
- visitMedia: function (mediaNode, visitArgs) {
- var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
- newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
- this.allExtendsStack.push(newAllExtends);
- },
- visitMediaOut: function (mediaNode) {
- this.allExtendsStack.length = this.allExtendsStack.length - 1;
- },
- visitDirective: function (directiveNode, visitArgs) {
- var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
- newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
- this.allExtendsStack.push(newAllExtends);
- },
- visitDirectiveOut: function (directiveNode) {
- this.allExtendsStack.length = this.allExtendsStack.length - 1;
+ if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
+ path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
+ currentSelectorPathIndex++;
}
- };
- return processExtendsVisitor;
+ path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
+
+ return path;
+ },
+ visitRulesetOut: function (rulesetNode) {
+ },
+ visitMedia: function (mediaNode, visitArgs) {
+ var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
+ newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
+ this.allExtendsStack.push(newAllExtends);
+ },
+ visitMediaOut: function (mediaNode) {
+ this.allExtendsStack.length = this.allExtendsStack.length - 1;
+ },
+ visitDirective: function (directiveNode, visitArgs) {
+ var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
+ newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
+ this.allExtendsStack.push(newAllExtends);
+ },
+ visitDirectiveOut: function (directiveNode) {
+ this.allExtendsStack.length = this.allExtendsStack.length - 1;
+ }
};
+
+module.exports = ProcessExtendsVisitor;
diff --git a/lib/less/visitor/import-visitor.js b/lib/less/visitor/import-visitor.js
index efff072..f7068df 100644
--- a/lib/less/visitor/import-visitor.js
+++ b/lib/less/visitor/import-visitor.js
@@ -1,145 +1,145 @@
-var contexts = require("../contexts.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 contexts.evalEnv();
- this.importCount = 0;
- this.onceFileDetectionMap = onceFileDetectionMap || {};
- this.recursionDetector = {};
- if (recursionDetector) {
- for(var fullFilename in recursionDetector) {
- if (recursionDetector.hasOwnProperty(fullFilename)) {
- this.recursionDetector[fullFilename] = true;
- }
+var contexts = require("../contexts.js"),
+ Visitor = require("./visitor.js");
+
+var ImportVisitor = function(importer, finish, evalEnv, onceFileDetectionMap, recursionDetector) {
+ this._visitor = new Visitor(this);
+ this._importer = importer;
+ this._finish = finish;
+ this.env = evalEnv || new contexts.evalEnv();
+ this.importCount = 0;
+ this.onceFileDetectionMap = onceFileDetectionMap || {};
+ this.recursionDetector = {};
+ if (recursionDetector) {
+ for(var fullFilename in recursionDetector) {
+ if (recursionDetector.hasOwnProperty(fullFilename)) {
+ this.recursionDetector[fullFilename] = true;
}
}
- };
+ }
+};
- ImportVisitor.prototype = {
- isReplacing: true,
- run: function (root) {
- var error;
- try {
- // process the contents
- this._visitor.visit(root);
- }
- catch(e) {
- error = e;
- }
+ImportVisitor.prototype = {
+ isReplacing: true,
+ run: function (root) {
+ var error;
+ try {
+ // process the contents
+ this._visitor.visit(root);
+ }
+ catch(e) {
+ error = e;
+ }
- this.isFinished = true;
+ this.isFinished = true;
+
+ if (this.importCount === 0) {
+ this._finish(error);
+ }
+ },
+ visitImport: function (importNode, visitArgs) {
+ var importVisitor = this,
+ evaldImportNode,
+ inlineCSS = importNode.options.inline;
- if (this.importCount === 0) {
- this._finish(error);
+ if (!importNode.css || inlineCSS) {
+
+ try {
+ evaldImportNode = importNode.evalForImport(this.env);
+ } catch(e){
+ if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
+ // attempt to eval properly and treat as css
+ importNode.css = true;
+ // if that fails, this error will be thrown
+ importNode.error = e;
}
- },
- visitImport: function (importNode, visitArgs) {
- var importVisitor = this,
- evaldImportNode,
- inlineCSS = importNode.options.inline;
- if (!importNode.css || inlineCSS) {
+ if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {
+ importNode = evaldImportNode;
+ this.importCount++;
+ var env = new contexts.evalEnv(this.env, this.env.frames.slice(0));
- try {
- evaldImportNode = importNode.evalForImport(this.env);
- } catch(e){
- if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
- // attempt to eval properly and treat as css
- importNode.css = true;
- // if that fails, this error will be thrown
- importNode.error = e;
+ if (importNode.options.multiple) {
+ env.importMultiple = true;
}
- if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {
- importNode = evaldImportNode;
- this.importCount++;
- var env = new contexts.evalEnv(this.env, this.env.frames.slice(0));
-
- if (importNode.options.multiple) {
- env.importMultiple = true;
+ this._importer.push(importNode.getPath(), importNode.currentFileInfo, importNode.options, function (e, root, importedAtRoot, fullPath) {
+ if (e && !e.filename) {
+ e.index = importNode.index; e.filename = importNode.currentFileInfo.filename;
}
- this._importer.push(importNode.getPath(), importNode.currentFileInfo, importNode.options, function (e, root, importedAtRoot, fullPath) {
- if (e && !e.filename) {
- e.index = importNode.index; e.filename = importNode.currentFileInfo.filename;
- }
-
- var duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector;
- if (!env.importMultiple) {
- if (duplicateImport) {
- importNode.skip = true;
- } else {
- importNode.skip = function() {
- if (fullPath in importVisitor.onceFileDetectionMap) {
- return true;
- }
- importVisitor.onceFileDetectionMap[fullPath] = true;
- return false;
- };
- }
+ var duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector;
+ if (!env.importMultiple) {
+ if (duplicateImport) {
+ importNode.skip = true;
+ } else {
+ importNode.skip = function() {
+ if (fullPath in importVisitor.onceFileDetectionMap) {
+ return true;
+ }
+ importVisitor.onceFileDetectionMap[fullPath] = true;
+ return false;
+ };
}
+ }
- var subFinish = function(e) {
- importVisitor.importCount--;
+ var subFinish = function(e) {
+ importVisitor.importCount--;
- if (importVisitor.importCount === 0 && importVisitor.isFinished) {
- importVisitor._finish(e);
- }
- };
+ if (importVisitor.importCount === 0 && importVisitor.isFinished) {
+ importVisitor._finish(e);
+ }
+ };
- if (root) {
- importNode.root = root;
- importNode.importedFilename = fullPath;
+ if (root) {
+ importNode.root = root;
+ importNode.importedFilename = fullPath;
- if (!inlineCSS && (env.importMultiple || !duplicateImport)) {
- importVisitor.recursionDetector[fullPath] = true;
- new(ImportVisitor)(importVisitor._importer, subFinish, env, importVisitor.onceFileDetectionMap, importVisitor.recursionDetector)
- .run(root);
- return;
- }
+ if (!inlineCSS && (env.importMultiple || !duplicateImport)) {
+ importVisitor.recursionDetector[fullPath] = true;
+ new(ImportVisitor)(importVisitor._importer, subFinish, env, importVisitor.onceFileDetectionMap, importVisitor.recursionDetector)
+ .run(root);
+ return;
}
+ }
- subFinish();
- });
- }
+ subFinish();
+ });
}
- visitArgs.visitDeeper = false;
- return importNode;
- },
- visitRule: function (ruleNode, visitArgs) {
- visitArgs.visitDeeper = false;
- return ruleNode;
- },
- visitDirective: function (directiveNode, visitArgs) {
- this.env.frames.unshift(directiveNode);
- return directiveNode;
- },
- visitDirectiveOut: function (directiveNode) {
- this.env.frames.shift();
- },
- visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
- this.env.frames.unshift(mixinDefinitionNode);
- return mixinDefinitionNode;
- },
- visitMixinDefinitionOut: function (mixinDefinitionNode) {
- this.env.frames.shift();
- },
- visitRuleset: function (rulesetNode, visitArgs) {
- this.env.frames.unshift(rulesetNode);
- return rulesetNode;
- },
- visitRulesetOut: function (rulesetNode) {
- this.env.frames.shift();
- },
- visitMedia: function (mediaNode, visitArgs) {
- this.env.frames.unshift(mediaNode.rules[0]);
- return mediaNode;
- },
- visitMediaOut: function (mediaNode) {
- this.env.frames.shift();
}
- };
- return ImportVisitor;
+ visitArgs.visitDeeper = false;
+ return importNode;
+ },
+ visitRule: function (ruleNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ return ruleNode;
+ },
+ visitDirective: function (directiveNode, visitArgs) {
+ this.env.frames.unshift(directiveNode);
+ return directiveNode;
+ },
+ visitDirectiveOut: function (directiveNode) {
+ this.env.frames.shift();
+ },
+ visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
+ this.env.frames.unshift(mixinDefinitionNode);
+ return mixinDefinitionNode;
+ },
+ visitMixinDefinitionOut: function (mixinDefinitionNode) {
+ this.env.frames.shift();
+ },
+ visitRuleset: function (rulesetNode, visitArgs) {
+ this.env.frames.unshift(rulesetNode);
+ return rulesetNode;
+ },
+ visitRulesetOut: function (rulesetNode) {
+ this.env.frames.shift();
+ },
+ visitMedia: function (mediaNode, visitArgs) {
+ this.env.frames.unshift(mediaNode.rules[0]);
+ return mediaNode;
+ },
+ visitMediaOut: function (mediaNode) {
+ this.env.frames.shift();
+ }
};
+module.exports = ImportVisitor;
diff --git a/lib/less/visitor/index.js b/lib/less/visitor/index.js
index 243910e..8a09617 100644
--- a/lib/less/visitor/index.js
+++ b/lib/less/visitor/index.js
@@ -1,13 +1,9 @@
-module.exports = function(less, tree) {
- var visitor = require("./visitor")(tree),
- visitors = {
- visitor: visitor
- };
-
- visitors.importVisitor = require('./import-visitor.js')(visitor, tree);
- visitors.extendVisitor = require('./extend-visitor.js')(visitor, tree);
- visitors.joinSelectorVisitor = require('./join-selector-visitor.js')(visitor);
- visitors.toCSSVisitor = require('./to-css-visitor.js')(visitor, tree);
- return visitors;
+var visitors = {
+ Visitor: require("./visitor"),
+ ImportVisitor: require('./import-visitor.js'),
+ ExtendVisitor: require('./extend-visitor.js'),
+ JoinSelectorVisitor: require('./join-selector-visitor.js'),
+ ToCSSVisitor: require('./to-css-visitor.js')
+};
-};
\ No newline at end of file
+module.exports = visitors;
diff --git a/lib/less/visitor/join-selector-visitor.js b/lib/less/visitor/join-selector-visitor.js
index bc511d9..05f8732 100644
--- a/lib/less/visitor/join-selector-visitor.js
+++ b/lib/less/visitor/join-selector-visitor.js
@@ -1,45 +1,45 @@
-module.exports = function (visitor) {
- var joinSelectorVisitor = function() {
- this.contexts = [[]];
- this._visitor = new visitor(this);
- };
+var Visitor = require("./visitor.js");
- joinSelectorVisitor.prototype = {
- run: function (root) {
- return this._visitor.visit(root);
- },
- visitRule: function (ruleNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
+var JoinSelectorVisitor = function() {
+ this.contexts = [[]];
+ this._visitor = new Visitor(this);
+};
- visitRuleset: function (rulesetNode, visitArgs) {
- var context = this.contexts[this.contexts.length - 1],
- paths = [], selectors;
+JoinSelectorVisitor.prototype = {
+ run: function (root) {
+ return this._visitor.visit(root);
+ },
+ visitRule: function (ruleNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
+ visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
+ visitArgs.visitDeeper = false;
+ },
- this.contexts.push(paths);
+ visitRuleset: function (rulesetNode, visitArgs) {
+ var context = this.contexts[this.contexts.length - 1],
+ paths = [], selectors;
- if (! rulesetNode.root) {
- selectors = rulesetNode.selectors;
- if (selectors) {
- selectors = selectors.filter(function(selector) { return selector.getIsOutput(); });
- rulesetNode.selectors = selectors.length ? selectors : (selectors = null);
- if (selectors) { rulesetNode.joinSelectors(paths, context, selectors); }
- }
- if (!selectors) { rulesetNode.rules = null; }
- rulesetNode.paths = paths;
+ this.contexts.push(paths);
+
+ if (! rulesetNode.root) {
+ selectors = rulesetNode.selectors;
+ if (selectors) {
+ selectors = selectors.filter(function(selector) { return selector.getIsOutput(); });
+ rulesetNode.selectors = selectors.length ? selectors : (selectors = null);
+ if (selectors) { rulesetNode.joinSelectors(paths, context, selectors); }
}
- },
- visitRulesetOut: function (rulesetNode) {
- this.contexts.length = this.contexts.length - 1;
- },
- visitMedia: function (mediaNode, visitArgs) {
- var context = this.contexts[this.contexts.length - 1];
- mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);
+ if (!selectors) { rulesetNode.rules = null; }
+ rulesetNode.paths = paths;
}
- };
-
- return joinSelectorVisitor;
-};
\ No newline at end of file
+ },
+ visitRulesetOut: function (rulesetNode) {
+ this.contexts.length = this.contexts.length - 1;
+ },
+ visitMedia: function (mediaNode, visitArgs) {
+ var context = this.contexts[this.contexts.length - 1];
+ mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);
+ }
+};
+
+module.exports = JoinSelectorVisitor;
diff --git a/lib/less/visitor/to-css-visitor.js b/lib/less/visitor/to-css-visitor.js
index cc3a900..1a8f5e2 100644
--- a/lib/less/visitor/to-css-visitor.js
+++ b/lib/less/visitor/to-css-visitor.js
@@ -1,244 +1,245 @@
-module.exports = function (visitor, tree) {
- var toCSSVisitor = function(env) {
- this._visitor = new visitor(this);
- this._env = env;
- };
-
- toCSSVisitor.prototype = {
- isReplacing: true,
- run: function (root) {
- return this._visitor.visit(root);
- },
-
- visitRule: function (ruleNode, visitArgs) {
- if (ruleNode.variable) {
- return [];
- }
- return ruleNode;
- },
+var tree = require("../tree/index.js"),
+ Visitor = require("./visitor.js");
- visitMixinDefinition: function (mixinNode, visitArgs) {
- // mixin definitions do not get eval'd - this means they keep state
- // so we have to clear that state here so it isn't used if toCSS is called twice
- mixinNode.frames = [];
- return [];
- },
+var ToCSSVisitor = function(env) {
+ this._visitor = new Visitor(this);
+ this._env = env;
+};
+
+ToCSSVisitor.prototype = {
+ isReplacing: true,
+ run: function (root) {
+ return this._visitor.visit(root);
+ },
- visitExtend: function (extendNode, visitArgs) {
+ visitRule: function (ruleNode, visitArgs) {
+ if (ruleNode.variable) {
return [];
- },
+ }
+ return ruleNode;
+ },
+
+ visitMixinDefinition: function (mixinNode, visitArgs) {
+ // mixin definitions do not get eval'd - this means they keep state
+ // so we have to clear that state here so it isn't used if toCSS is called twice
+ mixinNode.frames = [];
+ return [];
+ },
+
+ visitExtend: function (extendNode, visitArgs) {
+ return [];
+ },
+
+ visitComment: function (commentNode, visitArgs) {
+ if (commentNode.isSilent(this._env)) {
+ return [];
+ }
+ return commentNode;
+ },
- visitComment: function (commentNode, visitArgs) {
- if (commentNode.isSilent(this._env)) {
- return [];
- }
- return commentNode;
- },
+ visitMedia: function(mediaNode, visitArgs) {
+ mediaNode.accept(this._visitor);
+ visitArgs.visitDeeper = false;
- visitMedia: function(mediaNode, visitArgs) {
- mediaNode.accept(this._visitor);
- visitArgs.visitDeeper = false;
+ if (!mediaNode.rules.length) {
+ return [];
+ }
+ return mediaNode;
+ },
- if (!mediaNode.rules.length) {
+ visitDirective: function(directiveNode, visitArgs) {
+ if (directiveNode.currentFileInfo.reference && !directiveNode.isReferenced) {
+ return [];
+ }
+ if (directiveNode.name === "@charset") {
+ // Only output the debug info together with subsequent @charset definitions
+ // a comment (or @media statement) before the actual @charset directive would
+ // be considered illegal css as it has to be on the first line
+ if (this.charset) {
+ if (directiveNode.debugInfo) {
+ var comment = new tree.Comment("/* " + directiveNode.toCSS(this._env).replace(/\n/g, "")+" */\n");
+ comment.debugInfo = directiveNode.debugInfo;
+ return this._visitor.visit(comment);
+ }
return [];
}
- return mediaNode;
- },
+ this.charset = true;
+ }
+ if (directiveNode.rules && directiveNode.rules.rules) {
+ this._mergeRules(directiveNode.rules.rules);
+ }
+ return directiveNode;
+ },
+
+ checkPropertiesInRoot: function(rules) {
+ var ruleNode;
+ for(var i = 0; i < rules.length; i++) {
+ ruleNode = rules[i];
+ if (ruleNode instanceof tree.Rule && !ruleNode.variable) {
+ throw { message: "properties must be inside selector blocks, they cannot be in the root.",
+ index: ruleNode.index, filename: ruleNode.currentFileInfo ? ruleNode.currentFileInfo.filename : null};
+ }
+ }
+ },
- visitDirective: function(directiveNode, visitArgs) {
- if (directiveNode.currentFileInfo.reference && !directiveNode.isReferenced) {
- return [];
+ visitRuleset: function (rulesetNode, visitArgs) {
+ var rule, rulesets = [];
+ if (rulesetNode.firstRoot) {
+ this.checkPropertiesInRoot(rulesetNode.rules);
+ }
+ if (! rulesetNode.root) {
+ if (rulesetNode.paths) {
+ rulesetNode.paths = rulesetNode.paths
+ .filter(function(p) {
+ var i;
+ if (p[0].elements[0].combinator.value === ' ') {
+ p[0].elements[0].combinator = new(tree.Combinator)('');
+ }
+ for(i = 0; i < p.length; i++) {
+ if (p[i].getIsReferenced() && p[i].getIsOutput()) {
+ return true;
+ }
+ }
+ return false;
+ });
}
- if (directiveNode.name === "@charset") {
- // Only output the debug info together with subsequent @charset definitions
- // a comment (or @media statement) before the actual @charset directive would
- // be considered illegal css as it has to be on the first line
- if (this.charset) {
- if (directiveNode.debugInfo) {
- var comment = new tree.Comment("/* " + directiveNode.toCSS(this._env).replace(/\n/g, "")+" */\n");
- comment.debugInfo = directiveNode.debugInfo;
- return this._visitor.visit(comment);
- }
- return [];
+
+ // Compile rules and rulesets
+ var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0;
+ for (var i = 0; i < nodeRuleCnt; ) {
+ rule = nodeRules[i];
+ if (rule && rule.rules) {
+ // visit because we are moving them out from being a child
+ rulesets.push(this._visitor.visit(rule));
+ nodeRules.splice(i, 1);
+ nodeRuleCnt--;
+ continue;
}
- this.charset = true;
- }
- if (directiveNode.rules && directiveNode.rules.rules) {
- this._mergeRules(directiveNode.rules.rules);
+ i++;
}
- return directiveNode;
- },
-
- checkPropertiesInRoot: function(rules) {
- var ruleNode;
- for(var i = 0; i < rules.length; i++) {
- ruleNode = rules[i];
- if (ruleNode instanceof tree.Rule && !ruleNode.variable) {
- throw { message: "properties must be inside selector blocks, they cannot be in the root.",
- index: ruleNode.index, filename: ruleNode.currentFileInfo ? ruleNode.currentFileInfo.filename : null};
- }
+ // accept the visitor to remove rules and refactor itself
+ // then we can decide now whether we want it or not
+ if (nodeRuleCnt > 0) {
+ rulesetNode.accept(this._visitor);
+ } else {
+ rulesetNode.rules = null;
}
- },
+ visitArgs.visitDeeper = false;
- visitRuleset: function (rulesetNode, visitArgs) {
- var rule, rulesets = [];
- if (rulesetNode.firstRoot) {
- this.checkPropertiesInRoot(rulesetNode.rules);
+ nodeRules = rulesetNode.rules;
+ if (nodeRules) {
+ this._mergeRules(nodeRules);
+ nodeRules = rulesetNode.rules;
}
- if (! rulesetNode.root) {
- if (rulesetNode.paths) {
- rulesetNode.paths = rulesetNode.paths
- .filter(function(p) {
- var i;
- if (p[0].elements[0].combinator.value === ' ') {
- p[0].elements[0].combinator = new(tree.Combinator)('');
- }
- for(i = 0; i < p.length; i++) {
- if (p[i].getIsReferenced() && p[i].getIsOutput()) {
- return true;
- }
- }
- return false;
- });
- }
-
- // Compile rules and rulesets
- var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0;
- for (var i = 0; i < nodeRuleCnt; ) {
- rule = nodeRules[i];
- if (rule && rule.rules) {
- // visit because we are moving them out from being a child
- rulesets.push(this._visitor.visit(rule));
- nodeRules.splice(i, 1);
- nodeRuleCnt--;
- continue;
- }
- i++;
- }
- // accept the visitor to remove rules and refactor itself
- // then we can decide now whether we want it or not
- if (nodeRuleCnt > 0) {
- rulesetNode.accept(this._visitor);
- } else {
- rulesetNode.rules = null;
- }
- visitArgs.visitDeeper = false;
-
+ if (nodeRules) {
+ this._removeDuplicateRules(nodeRules);
nodeRules = rulesetNode.rules;
- if (nodeRules) {
- this._mergeRules(nodeRules);
- nodeRules = rulesetNode.rules;
- }
- if (nodeRules) {
- this._removeDuplicateRules(nodeRules);
- nodeRules = rulesetNode.rules;
- }
+ }
- // now decide whether we keep the ruleset
- if (nodeRules && nodeRules.length > 0 && rulesetNode.paths.length > 0) {
- rulesets.splice(0, 0, rulesetNode);
- }
- } else {
- rulesetNode.accept(this._visitor);
- visitArgs.visitDeeper = false;
- if (rulesetNode.firstRoot || (rulesetNode.rules && rulesetNode.rules.length > 0)) {
- rulesets.splice(0, 0, rulesetNode);
- }
+ // now decide whether we keep the ruleset
+ if (nodeRules && nodeRules.length > 0 && rulesetNode.paths.length > 0) {
+ rulesets.splice(0, 0, rulesetNode);
}
- if (rulesets.length === 1) {
- return rulesets[0];
+ } else {
+ rulesetNode.accept(this._visitor);
+ visitArgs.visitDeeper = false;
+ if (rulesetNode.firstRoot || (rulesetNode.rules && rulesetNode.rules.length > 0)) {
+ rulesets.splice(0, 0, rulesetNode);
}
- return rulesets;
- },
+ }
+ if (rulesets.length === 1) {
+ return rulesets[0];
+ }
+ return rulesets;
+ },
- _removeDuplicateRules: function(rules) {
- if (!rules) { return; }
+ _removeDuplicateRules: function(rules) {
+ if (!rules) { return; }
- // remove duplicates
- var ruleCache = {},
- ruleList, rule, i;
+ // remove duplicates
+ var ruleCache = {},
+ ruleList, rule, i;
- for(i = rules.length - 1; i >= 0 ; i--) {
- rule = rules[i];
- if (rule instanceof tree.Rule) {
- if (!ruleCache[rule.name]) {
- ruleCache[rule.name] = rule;
+ for(i = rules.length - 1; i >= 0 ; i--) {
+ rule = rules[i];
+ if (rule instanceof tree.Rule) {
+ if (!ruleCache[rule.name]) {
+ ruleCache[rule.name] = rule;
+ } else {
+ ruleList = ruleCache[rule.name];
+ if (ruleList instanceof tree.Rule) {
+ ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._env)];
+ }
+ var ruleCSS = rule.toCSS(this._env);
+ if (ruleList.indexOf(ruleCSS) !== -1) {
+ rules.splice(i, 1);
} else {
- ruleList = ruleCache[rule.name];
- if (ruleList instanceof tree.Rule) {
- ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._env)];
- }
- var ruleCSS = rule.toCSS(this._env);
- if (ruleList.indexOf(ruleCSS) !== -1) {
- rules.splice(i, 1);
- } else {
- ruleList.push(ruleCSS);
- }
+ ruleList.push(ruleCSS);
}
}
}
- },
+ }
+ },
- _mergeRules: function (rules) {
- if (!rules) { return; }
+ _mergeRules: function (rules) {
+ if (!rules) { return; }
- var groups = {},
- parts,
- rule,
- key;
+ var groups = {},
+ parts,
+ rule,
+ key;
- for (var i = 0; i < rules.length; i++) {
- rule = rules[i];
+ for (var i = 0; i < rules.length; i++) {
+ rule = rules[i];
- if ((rule instanceof tree.Rule) && rule.merge) {
- key = [rule.name,
- rule.important ? "!" : ""].join(",");
+ if ((rule instanceof tree.Rule) && rule.merge) {
+ key = [rule.name,
+ rule.important ? "!" : ""].join(",");
- if (!groups[key]) {
- groups[key] = [];
- } else {
- rules.splice(i--, 1);
- }
-
- groups[key].push(rule);
+ if (!groups[key]) {
+ groups[key] = [];
+ } else {
+ rules.splice(i--, 1);
}
+
+ groups[key].push(rule);
}
+ }
- Object.keys(groups).map(function (k) {
+ Object.keys(groups).map(function (k) {
- function toExpression(values) {
- return new (tree.Expression)(values.map(function (p) {
- return p.value;
- }));
- }
+ function toExpression(values) {
+ return new (tree.Expression)(values.map(function (p) {
+ return p.value;
+ }));
+ }
- function toValue(values) {
- return new (tree.Value)(values.map(function (p) {
- return p;
- }));
- }
+ function toValue(values) {
+ return new (tree.Value)(values.map(function (p) {
+ return p;
+ }));
+ }
- parts = groups[k];
+ parts = groups[k];
- if (parts.length > 1) {
- rule = parts[0];
- var spacedGroups = [];
- var lastSpacedGroup = [];
- parts.map(function (p) {
- if (p.merge==="+") {
- if (lastSpacedGroup.length > 0) {
- spacedGroups.push(toExpression(lastSpacedGroup));
- }
- lastSpacedGroup = [];
+ if (parts.length > 1) {
+ rule = parts[0];
+ var spacedGroups = [];
+ var lastSpacedGroup = [];
+ parts.map(function (p) {
+ if (p.merge==="+") {
+ if (lastSpacedGroup.length > 0) {
+ spacedGroups.push(toExpression(lastSpacedGroup));
}
- lastSpacedGroup.push(p);
- });
- spacedGroups.push(toExpression(lastSpacedGroup));
- rule.value = toValue(spacedGroups);
- }
- });
- }
- };
-
- return toCSSVisitor;
+ lastSpacedGroup = [];
+ }
+ lastSpacedGroup.push(p);
+ });
+ spacedGroups.push(toExpression(lastSpacedGroup));
+ rule.value = toValue(spacedGroups);
+ }
+ });
+ }
};
+
+module.exports = ToCSSVisitor;
diff --git a/lib/less/visitor/visitor.js b/lib/less/visitor/visitor.js
index d6cade4..cd0b328 100644
--- a/lib/less/visitor/visitor.js
+++ b/lib/less/visitor/visitor.js
@@ -1,146 +1,145 @@
-module.exports = function (tree) {
+var tree = require("../tree/index.js");
+
+var _visitArgs = { visitDeeper: true },
+ _hasIndexed = false;
+
+function _noop(node) {
+ return node;
+}
+
+function indexNodeTypes(parent, ticker) {
+ // add .typeIndex to tree node types for lookup table
+ var key, child;
+ for (key in parent) {
+ if (parent.hasOwnProperty(key)) {
+ child = parent[key];
+ switch (typeof child) {
+ case "function":
+ // ignore bound functions directly on tree which do not have a prototype
+ // or aren't nodes
+ if (child.prototype && child.prototype.type) {
+ child.prototype.typeIndex = ticker++;
+ }
+ break;
+ case "object":
+ ticker = indexNodeTypes(child, ticker);
+ break;
+ }
+ }
+ }
+ return ticker;
+}
- var _visitArgs = { visitDeeper: true },
- _hasIndexed = false;
+var Visitor = function(implementation) {
+ this._implementation = implementation;
+ this._visitFnCache = [];
- function _noop(node) {
- return node;
+ if (!_hasIndexed) {
+ indexNodeTypes(tree, 1);
+ _hasIndexed = true;
}
+};
- function indexNodeTypes(parent, ticker) {
- // add .typeIndex to tree node types for lookup table
- var key, child;
- for (key in parent) {
- if (parent.hasOwnProperty(key)) {
- child = parent[key];
- switch (typeof child) {
- case "function":
- // ignore bound functions directly on tree which do not have a prototype
- // or aren't nodes
- if (child.prototype && child.prototype.type) {
- child.prototype.typeIndex = ticker++;
- }
- break;
- case "object":
- ticker = indexNodeTypes(child, ticker);
- break;
- }
- }
+Visitor.prototype = {
+ visit: function(node) {
+ if (!node) {
+ return node;
}
- return ticker;
- }
- var visitor = function(implementation) {
- this._implementation = implementation;
- this._visitFnCache = [];
+ var nodeTypeIndex = node.typeIndex;
+ if (!nodeTypeIndex) {
+ return node;
+ }
- if (!_hasIndexed) {
- indexNodeTypes(tree, 1);
- _hasIndexed = true;
+ var visitFnCache = this._visitFnCache,
+ impl = this._implementation,
+ aryIndx = nodeTypeIndex << 1,
+ outAryIndex = aryIndx | 1,
+ func = visitFnCache[aryIndx],
+ funcOut = visitFnCache[outAryIndex],
+ visitArgs = _visitArgs,
+ fnName;
+
+ visitArgs.visitDeeper = true;
+
+ if (!func) {
+ fnName = "visit" + node.type;
+ func = impl[fnName] || _noop;
+ funcOut = impl[fnName + "Out"] || _noop;
+ visitFnCache[aryIndx] = func;
+ visitFnCache[outAryIndex] = funcOut;
}
- };
- visitor.prototype = {
- visit: function(node) {
- if (!node) {
- return node;
+ if (func !== _noop) {
+ var newNode = func.call(impl, node, visitArgs);
+ if (impl.isReplacing) {
+ node = newNode;
}
+ }
- var nodeTypeIndex = node.typeIndex;
- if (!nodeTypeIndex) {
- return node;
- }
+ if (visitArgs.visitDeeper && node && node.accept) {
+ node.accept(this);
+ }
- var visitFnCache = this._visitFnCache,
- impl = this._implementation,
- aryIndx = nodeTypeIndex << 1,
- outAryIndex = aryIndx | 1,
- func = visitFnCache[aryIndx],
- funcOut = visitFnCache[outAryIndex],
- visitArgs = _visitArgs,
- fnName;
-
- visitArgs.visitDeeper = true;
-
- if (!func) {
- fnName = "visit" + node.type;
- func = impl[fnName] || _noop;
- funcOut = impl[fnName + "Out"] || _noop;
- visitFnCache[aryIndx] = func;
- visitFnCache[outAryIndex] = funcOut;
- }
+ if (funcOut != _noop) {
+ funcOut.call(impl, node);
+ }
- if (func !== _noop) {
- var newNode = func.call(impl, node, visitArgs);
- if (impl.isReplacing) {
- node = newNode;
- }
- }
+ return node;
+ },
+ visitArray: function(nodes, nonReplacing) {
+ if (!nodes) {
+ return nodes;
+ }
- if (visitArgs.visitDeeper && node && node.accept) {
- node.accept(this);
- }
+ var cnt = nodes.length, i;
- if (funcOut != _noop) {
- funcOut.call(impl, node);
+ // Non-replacing
+ if (nonReplacing || !this._implementation.isReplacing) {
+ for (i = 0; i < cnt; i++) {
+ this.visit(nodes[i]);
}
+ return nodes;
+ }
- return node;
- },
- visitArray: function(nodes, nonReplacing) {
- if (!nodes) {
- return nodes;
+ // Replacing
+ var out = [];
+ for (i = 0; i < cnt; i++) {
+ var evald = this.visit(nodes[i]);
+ if (!evald.splice) {
+ out.push(evald);
+ } else if (evald.length) {
+ this.flatten(evald, out);
}
+ }
+ return out;
+ },
+ flatten: function(arr, out) {
+ if (!out) {
+ out = [];
+ }
- var cnt = nodes.length, i;
-
- // Non-replacing
- if (nonReplacing || !this._implementation.isReplacing) {
- for (i = 0; i < cnt; i++) {
- this.visit(nodes[i]);
- }
- return nodes;
- }
+ var cnt, i, item,
+ nestedCnt, j, nestedItem;
- // Replacing
- var out = [];
- for (i = 0; i < cnt; i++) {
- var evald = this.visit(nodes[i]);
- if (!evald.splice) {
- out.push(evald);
- } else if (evald.length) {
- this.flatten(evald, out);
- }
- }
- return out;
- },
- flatten: function(arr, out) {
- if (!out) {
- out = [];
+ for (i = 0, cnt = arr.length; i < cnt; i++) {
+ item = arr[i];
+ if (!item.splice) {
+ out.push(item);
+ continue;
}
- var cnt, i, item,
- nestedCnt, j, nestedItem;
-
- for (i = 0, cnt = arr.length; i < cnt; i++) {
- item = arr[i];
- if (!item.splice) {
- out.push(item);
- continue;
- }
-
- for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) {
- nestedItem = item[j];
- if (!nestedItem.splice) {
- out.push(nestedItem);
- } else if (nestedItem.length) {
- this.flatten(nestedItem, out);
- }
+ for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) {
+ nestedItem = item[j];
+ if (!nestedItem.splice) {
+ out.push(nestedItem);
+ } else if (nestedItem.length) {
+ this.flatten(nestedItem, out);
}
}
-
- return out;
}
- };
- return visitor;
+
+ return out;
+ }
};
+module.exports = Visitor;
--
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