From c757befb4f113cd5543967b6e52496debdadcf3e Mon Sep 17 00:00:00 2001 From: Luke Page Date: Thu, 23 Oct 2014 21:33:28 +0100 Subject: [PATCH] flatten import visitor so that variable imports can be processed at the end of a global queue --- lib/less/tree/import.js | 11 +++++++ lib/less/tree/quoted.js | 3 ++ lib/less/visitors/import-visitor.js | 50 +++++++++++++++++++++-------- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/lib/less/tree/import.js b/lib/less/tree/import.js index d8ce4f3a..69e1aad9 100644 --- a/lib/less/tree/import.js +++ b/lib/less/tree/import.js @@ -73,6 +73,17 @@ Import.prototype.getPath = function () { } return null; }; +Import.prototype.isVariableImport = function () { + var path = this.path; + if (path instanceof URL) { + path = path.value; + } + if (path instanceof Quoted) { + return path.containsVariables(); + } + + return true; +}; Import.prototype.evalForImport = function (context) { var path = this.path; if (path instanceof URL) { diff --git a/lib/less/tree/quoted.js b/lib/less/tree/quoted.js index c7d83051..f1534553 100644 --- a/lib/less/tree/quoted.js +++ b/lib/less/tree/quoted.js @@ -20,6 +20,9 @@ Quoted.prototype.genCSS = function (context, output) { output.add(this.quote); } }; +Quoted.prototype.containsVariables = function() { + return this.value.match(/(`([^`]+)`)|@\{([\w-]+)\}/); +}; Quoted.prototype.eval = function (context) { var that = this, value = this.value; var javascriptReplacement = function (_, exp) { diff --git a/lib/less/visitors/import-visitor.js b/lib/less/visitors/import-visitor.js index 62175046..ebf67677 100644 --- a/lib/less/visitors/import-visitor.js +++ b/lib/less/visitors/import-visitor.js @@ -3,10 +3,13 @@ var contexts = require("../contexts"), ImportSequencer = require("./import-sequencer"); var ImportVisitor = function(importer, finish, evalEnv, onceFileDetectionMap, recursionDetector) { + // TODO arguments not all necessary now + this._visitor = new Visitor(this); this._importer = importer; this._finish = finish; - this.context = evalEnv || new contexts.Eval(); + // TODO probably doesnt need to be an array + this.contextStack = [evalEnv || new contexts.Eval()]; this.importCount = 0; this.onceFileDetectionMap = onceFileDetectionMap || {}; this.recursionDetector = {}; @@ -43,8 +46,14 @@ ImportVisitor.prototype = { if (!importNode.css || inlineCSS) { + // TODO - process this type of imports *last* + //if (importNode.isVariableImport()) { + // console.log("variable import detected"); + //} + var currentContext = this.contextStack[this.contextStack.length - 1]; + try { - evaldImportNode = importNode.evalForImport(this.context); + evaldImportNode = importNode.evalForImport(currentContext); } catch(e){ if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } // attempt to eval properly and treat as css @@ -56,7 +65,7 @@ ImportVisitor.prototype = { if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) { importNode = evaldImportNode; this.importCount++; - var context = new contexts.Eval(this.context, this.context.frames.slice(0)); + var context = new contexts.Eval(currentContext, currentContext.frames.slice(0)); if (importNode.options.multiple) { context.importMultiple = true; @@ -113,9 +122,14 @@ ImportVisitor.prototype = { if (!inlineCSS && (context.importMultiple || !duplicateImport)) { importVisitor.recursionDetector[fullPath] = true; - new ImportVisitor(importVisitor._importer, subFinish, context, importVisitor.onceFileDetectionMap, importVisitor.recursionDetector) - .run(root); - return; + + this.contextStack.push(context); + try { + this._visitor.visit(root); + } catch (e) { + this.error = e; + } + this.contextStack.pop(); } } @@ -126,32 +140,40 @@ ImportVisitor.prototype = { return ruleNode; }, visitDirective: function (directiveNode, visitArgs) { - this.context.frames.unshift(directiveNode); + var currentContext = this.contextStack[this.contextStack.length - 1]; + currentContext.frames.unshift(directiveNode); return directiveNode; }, visitDirectiveOut: function (directiveNode) { - this.context.frames.shift(); + var currentContext = this.contextStack[this.contextStack.length - 1]; + currentContext.frames.shift(); }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { - this.context.frames.unshift(mixinDefinitionNode); + var currentContext = this.contextStack[this.contextStack.length - 1]; + currentContext.frames.unshift(mixinDefinitionNode); return mixinDefinitionNode; }, visitMixinDefinitionOut: function (mixinDefinitionNode) { - this.context.frames.shift(); + var currentContext = this.contextStack[this.contextStack.length - 1]; + currentContext.frames.shift(); }, visitRuleset: function (rulesetNode, visitArgs) { - this.context.frames.unshift(rulesetNode); + var currentContext = this.contextStack[this.contextStack.length - 1]; + currentContext.frames.unshift(rulesetNode); return rulesetNode; }, visitRulesetOut: function (rulesetNode) { - this.context.frames.shift(); + var currentContext = this.contextStack[this.contextStack.length - 1]; + currentContext.frames.shift(); }, visitMedia: function (mediaNode, visitArgs) { - this.context.frames.unshift(mediaNode.rules[0]); + var currentContext = this.contextStack[this.contextStack.length - 1]; + currentContext.frames.unshift(mediaNode.rules[0]); return mediaNode; }, visitMediaOut: function (mediaNode) { - this.context.frames.shift(); + var currentContext = this.contextStack[this.contextStack.length - 1]; + currentContext.frames.shift(); } }; module.exports = ImportVisitor;