From 3253afad27d972acd02ccecd2d90894339aff856 Mon Sep 17 00:00:00 2001 From: cloudhead Date: Sun, 21 Mar 2010 19:18:47 -0400 Subject: [PATCH] asynchronous import functionality! All tests passing. --- lib/less.js | 47 ++++++++++++++++++++++++++++++++++++++-- lib/less/tree/import.js | 30 ++++++++++++------------- lib/less/tree/ruleset.js | 10 ++++++++- test/css/import.css | 8 +++++-- test/less/import.less | 2 +- 5 files changed, 76 insertions(+), 21 deletions(-) diff --git a/lib/less.js b/lib/less.js index 111cc2f..f71fe12 100644 --- a/lib/less.js +++ b/lib/less.js @@ -1,10 +1,13 @@ -var path = require('path'); +var path = require('path'), + fs = require('fs'); require.paths.unshift(__dirname); var less = { version: [2, 0, 0], - parser: require('less/parser').parser, + Parser: require('less/parser').Parser, + import: require('less/parser').import, + importer: require('less/parser').importer, tree: require('less/tree') }; @@ -17,6 +20,46 @@ var less = { require(path.join('less', 'tree', n)); }); +less.Parser.importer = function (file, paths, callback) { + var pathname; + + paths.unshift('.'); + + for (var i = 0; i < paths.length; i++) { + try { + pathname = path.join(paths[i], file); + fs.statSync(pathname); + break; + } catch (e) { + pathname = null; + } + } + + if (pathname) { + fs.stat(pathname, function (e, stats) { + if (e) process.stdio.writeError(e); + + fs.open(pathname, process.O_RDONLY, stats.mode, function (e, fd) { + if (e) process.stdio.writeError(e); + + fs.read(fd, stats.size, 0, "utf8", function (e, data) { + if (e) process.stdio.writeError(e); + + new(less.Parser)({ + paths: [path.dirname(pathname)] + }).parse(data, function (e, root) { + if (e) process.stdio.writeError(e); + callback(root); + }); + }); + }); + }); + } else { + process.stdio.writeError("file '" + file + "' wasn't found.\n"); + process.exit(1); + } +} + require('less/functions'); require('ext/array'); diff --git a/lib/less/tree/import.js b/lib/less/tree/import.js index 55de063..83c9b17 100644 --- a/lib/less/tree/import.js +++ b/lib/less/tree/import.js @@ -18,36 +18,36 @@ if (typeof(require) !== 'undefined') { var tree = require('less/tree') } // and when `this.eval` is called (during code-gen), we pass the // imported rules to the callback [1b]. // -// 2. The current file finishes parsing, and is evaluated before the import. +// 2. The current file finishes parsing before the import. // In this case, the rules aren't available yet, so we save // the callback in `this.callback` [2b], which will be called when // the importer is done [2a]. // -tree.Import = function Import(path, importer) { +tree.Import = function Import(path, import) { var that = this; // The '.less' extension is optional if (path instanceof tree.Quoted) { - this.path = /\.le?ss$/.test(path.content) ? path.content : path.content + '.less'; + this.path = /\.(le?|c)ss$/.test(path.content) ? path.content : path.content + '.less'; } else { - this.path = path.value; + this.path = path.value.content || path.value; } - importer(this.path, function (rules) { - if (this.callback) { - this.callback(rules); // 2a. - } else { - that.rules = rules; // 1a. - } + import.push(this.path, function (root) { + that.root = root; // 1a. }); }; tree.Import.prototype = { toCSS: function () { return "" }, - eval: function (callback) { - if (this.rules) { - callback(this.rules); // 1b. - } else { - this.callback = callback; // 2b. + eval: function () { + for (var i = 0; i < this.root.rules.length; i++) { + if (this.root.rules[i] instanceof tree.Import) { + Array.prototype + .splice + .apply(this.root.rules, + [i, 1].concat(this.root.rules[i].eval())); + } } + return this.root.rules; } }; diff --git a/lib/less/tree/ruleset.js b/lib/less/tree/ruleset.js index 45e792d..c71cc60 100644 --- a/lib/less/tree/ruleset.js +++ b/lib/less/tree/ruleset.js @@ -70,7 +70,15 @@ tree.Ruleset.prototype = { } } } - } else { context = [], env = { frames: [] } } + } else { + context = [], env = { frames: [] } + for (var i = 0; i < this.rules.length; i++) { + if (this.rules[i] instanceof tree.Import) { + Array.prototype.splice + .apply(this.rules, [i, 1].concat(this.rules[i].eval(env))); + } + } + } // push the current ruleset to the frames stack env.frames.unshift(this); diff --git a/test/css/import.css b/test/css/import.css index 3d53c0d..d57675a 100644 --- a/test/css/import.css +++ b/test/css/import.css @@ -1,5 +1,9 @@ -#css { color: yellow; } -#import { color: red; } +#css { + color: yellow; +} +#import { + color: red; +} .mixin { height: 10px; color: red; diff --git a/test/less/import.less b/test/less/import.less index a21ab76..08ad52c 100644 --- a/test/less/import.less +++ b/test/less/import.less @@ -1,5 +1,5 @@ @import url("import/import-test-a.less"); -@import url("import/import-test-a.less"); +//@import url("import/import-test-a.less"); #import-test { .mixin;