asynchronous import functionality! All tests passing.

This commit is contained in:
cloudhead 2010-03-21 19:18:47 -04:00
parent ef97105ce3
commit 3253afad27
5 changed files with 76 additions and 21 deletions

View File

@ -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');

View File

@ -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;
}
};

View File

@ -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);

8
test/css/import.css vendored
View File

@ -1,5 +1,9 @@
#css { color: yellow; }
#import { color: red; }
#css {
color: yellow;
}
#import {
color: red;
}
.mixin {
height: 10px;
color: red;

View File

@ -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;