[Pkg-javascript-commits] [less.js] 22/26: Fix isSync option, turn browser back to running sychronously and fix many issues that came up
Jonas Smedegaard
dr at jones.dk
Mon Oct 26 23:25:19 UTC 2015
This is an automated email from the git hooks/post-receive script.
js pushed a commit to annotated tag v2.1.0
in repository less.js.
commit 89c95af0702d267a18f89e44e7733133bfd09cf1
Author: Luke Page <luke.a.page at gmail.com>
Date: Sat Nov 22 18:30:36 2014 +0000
Fix isSync option, turn browser back to running sychronously and fix many issues that came up
---
lib/less-browser/file-manager.js | 55 +++++++++++-----------
lib/less-browser/index.js | 57 ++++++++++++-----------
lib/less-node/file-manager.js | 93 +++++++++++++++++++------------------
lib/less/import-manager.js | 82 +++++++++++++++++---------------
lib/less/parser/parser.js | 23 +++++----
lib/less/render.js | 38 +++++++--------
lib/less/visitors/import-visitor.js | 22 +++------
test/index.js | 2 +
test/less-test.js | 44 +++++++++++-------
9 files changed, 218 insertions(+), 198 deletions(-)
diff --git a/lib/less-browser/file-manager.js b/lib/less-browser/file-manager.js
index 4fef205..3992821 100644
--- a/lib/less-browser/file-manager.js
+++ b/lib/less-browser/file-manager.js
@@ -2,8 +2,7 @@
module.exports = function(options, logger) {
-var PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise,
- AbstractFileManager = require("../less/environment/abstract-file-manager.js");
+var AbstractFileManager = require("../less/environment/abstract-file-manager.js");
var fileCache = {};
@@ -83,39 +82,37 @@ FileManager.prototype.clearFileCache = function() {
fileCache = {};
};
-FileManager.prototype.loadFile = function loadFile(filename, currentDirectory, options, environment) {
- return new PromiseConstructor(function(fulfill, reject) {
- if (currentDirectory && !this.isPathAbsolute(filename)) {
- filename = currentDirectory + filename;
- }
+FileManager.prototype.loadFile = function loadFile(filename, currentDirectory, options, environment, callback) {
+ if (currentDirectory && !this.isPathAbsolute(filename)) {
+ filename = currentDirectory + filename;
+ }
- options = options || {};
+ options = options || {};
- // sheet may be set to the stylesheet for the initial load or a collection of properties including
- // some context variables for imports
- var hrefParts = this.extractUrlParts(filename, window.location.href);
- var href = hrefParts.url;
+ // sheet may be set to the stylesheet for the initial load or a collection of properties including
+ // some context variables for imports
+ var hrefParts = this.extractUrlParts(filename, window.location.href);
+ var href = hrefParts.url;
- if (options.useFileCache && fileCache[href]) {
- try {
- var lessText = fileCache[href];
- fulfill({ contents: lessText, filename: href, webInfo: { lastModified: new Date() }});
- } catch (e) {
- reject({filename: href, message: "Error loading file " + href + " error was " + e.message});
- }
- return;
+ if (options.useFileCache && fileCache[href]) {
+ try {
+ var lessText = fileCache[href];
+ callback(null, { contents: lessText, filename: href, webInfo: { lastModified: new Date() }});
+ } catch (e) {
+ callback({filename: href, message: "Error loading file " + href + " error was " + e.message});
}
+ return;
+ }
- this.doXHR(href, options.mime, function doXHRCallback(data, lastModified) {
- // per file cache
- fileCache[href] = data;
+ this.doXHR(href, options.mime, function doXHRCallback(data, lastModified) {
+ // per file cache
+ fileCache[href] = data;
- // Use remote copy (re-parse)
- fulfill({ contents: data, filename: href, webInfo: { lastModified: lastModified }});
- }, function doXHRError(status, url) {
- reject({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")", href: href });
- });
- }.bind(this));
+ // Use remote copy (re-parse)
+ callback(null, { contents: data, filename: href, webInfo: { lastModified: lastModified }});
+ }, function doXHRError(status, url) {
+ callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")", href: href });
+ });
};
return FileManager;
diff --git a/lib/less-browser/index.js b/lib/less-browser/index.js
index 9741f41..69c7576 100644
--- a/lib/less-browser/index.js
+++ b/lib/less-browser/index.js
@@ -67,18 +67,19 @@ function loadStyles(modifyVars) {
/*jshint loopfunc:true */
// use closure to store current style
- less.render(lessText, instanceOptions)
- .then(bind(function(style, result) {
- style.type = 'text/css';
- if (style.styleSheet) {
- style.styleSheet.cssText = result.css;
- } else {
- style.innerHTML = result.css;
- }
- }, null, style),
- function(e) {
- errors.add(e, "inline");
- });
+ less.render(lessText, instanceOptions,
+ bind(function(style, e, result) {
+ if (e) {
+ errors.add(e, "inline");
+ } else {
+ style.type = 'text/css';
+ if (style.styleSheet) {
+ style.styleSheet.cssText = result.css;
+ } else {
+ style.innerHTML = result.css;
+ }
+ }
+ }, null, style));
}
}
}
@@ -93,12 +94,11 @@ function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
instanceOptions.modifyVars = modifyVars;
}
- fileManager.loadFile(sheet.href, null, instanceOptions, environment)
- .then(function loadInitialFileCallback(loadedFile) {
+ function loadInitialFileCallback(loadedFile) {
- var data = loadedFile.contents,
- path = loadedFile.filename,
- webInfo = loadedFile.webInfo;
+ var data = loadedFile.contents,
+ path = loadedFile.filename,
+ webInfo = loadedFile.webInfo;
var newFileInfo = {
currentDirectory: fileManager.getPath(path),
@@ -125,17 +125,22 @@ function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
errors.remove(path);
instanceOptions.rootFileInfo = newFileInfo;
- less.render(data, instanceOptions)
- .then(function(result) {
- callback(null, result.css, data, sheet, webInfo, path);
- },
- function(e) {
+ less.render(data, instanceOptions, function(e, result) {
+ if (e) {
e.href = path;
callback(e);
- });
- },
- function(e) {
- callback(e);
+ } else {
+ callback(null, result.css, data, sheet, webInfo, path);
+ }
+ });
+ }
+
+ fileManager.loadFile(sheet.href, null, instanceOptions, environment, function(e, loadedFile) {
+ if (e) {
+ callback(e);
+ return;
+ }
+ loadInitialFileCallback(loadedFile);
});
}
diff --git a/lib/less-node/file-manager.js b/lib/less-node/file-manager.js
index 40ddc30..62829b0 100644
--- a/lib/less-node/file-manager.js
+++ b/lib/less-node/file-manager.js
@@ -15,59 +15,60 @@ FileManager.prototype.supportsSync = function(filename, currentDirectory, option
return true;
};
-FileManager.prototype.loadFile = function(filename, currentDirectory, options, environment) {
- return new PromiseConstructor(function(fulfill, reject) {
- var fullFilename,
- data;
-
- options = options || {};
+FileManager.prototype.loadFile = function(filename, currentDirectory, options, environment, callback) {
+ var fullFilename,
+ data;
- var paths = [currentDirectory];
- if (options.paths) paths.push.apply(paths, options.paths);
- if (paths.indexOf('.') === -1) paths.push('.');
+ options = options || {};
- if (options.syncImport) {
- for (var i = 0; i < paths.length; i++) {
- try {
- fullFilename = path.join(paths[i], filename);
- fs.statSync(fullFilename);
- break;
- } catch (e) {
- fullFilename = null;
- }
- }
+ var paths = [currentDirectory];
+ if (options.paths) paths.push.apply(paths, options.paths);
+ if (paths.indexOf('.') === -1) paths.push('.');
- if (!fullFilename) {
- reject({ type: 'File', message: "'" + filename + "' wasn't found" });
- return;
+ if (options.syncImport) {
+ var err, result;
+ for (var i = 0; i < paths.length; i++) {
+ try {
+ fullFilename = path.join(paths[i], filename);
+ fs.statSync(fullFilename);
+ break;
+ } catch (e) {
+ fullFilename = null;
}
+ }
- data = fs.readFileSync(fullFilename, 'utf-8');
- fulfill({ contents: data, filename: fullFilename});
+ if (!fullFilename) {
+ err = { type: 'File', message: "'" + filename + "' wasn't found" };
} else {
- (function tryPathIndex(i) {
- if (i < paths.length) {
- fullFilename = path.join(paths[i], filename);
- fs.stat(fullFilename, function (err) {
- if (err) {
- tryPathIndex(i + 1);
- } else {
- fs.readFile(fullFilename, 'utf-8', function(e, data) {
- if (e) { reject(e); return; }
-
- // do processing in the next tick to allow
- // file handling to dispose
- process.nextTick(function() {
- fulfill({ contents: data, filename: fullFilename});
- });
- });
- }
- });
- } else {
- reject({ type: 'File', message: "'" + filename + "' wasn't found" });
- }
- }(0));
+ data = fs.readFileSync(fullFilename, 'utf-8');
+ result = { contents: data, filename: fullFilename};
}
+ callback(err, result);
+ return;
+ }
+
+ // promise is guarenteed to be asyncronous
+ // which helps as it allows the file handle
+ // to be closed before it continues with the next file
+ return new PromiseConstructor(function(fulfill, reject) {
+ (function tryPathIndex(i) {
+ if (i < paths.length) {
+ fullFilename = path.join(paths[i], filename);
+ fs.stat(fullFilename, function (err) {
+ if (err) {
+ tryPathIndex(i + 1);
+ } else {
+ fs.readFile(fullFilename, 'utf-8', function(e, data) {
+ if (e) { reject(e); return; }
+
+ fulfill({ contents: data, filename: fullFilename});
+ });
+ }
+ });
+ } else {
+ reject({ type: 'File', message: "'" + filename + "' wasn't found" });
+ }
+ }(0));
});
};
diff --git a/lib/less/import-manager.js b/lib/less/import-manager.js
index a370e59..57bc447 100644
--- a/lib/less/import-manager.js
+++ b/lib/less/import-manager.js
@@ -66,48 +66,56 @@ module.exports = function(environment) {
path = fileManager.tryAppendLessExtension(path);
}
- fileManager.loadFile(path, currentFileInfo.currentDirectory, this.context, environment)
- .then(function loadFileCallback(loadedFile) {
- var resolvedFilename = loadedFile.filename,
- contents = loadedFile.contents;
-
- // Pass on an updated rootpath if path of imported file is relative and file
- // is in a (sub|sup) directory
- //
- // Examples:
- // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/',
- // then rootpath should become 'less/module/nav/'
- // - If path of imported file is '../mixins.less' and rootpath is 'less/',
- // then rootpath should become 'less/../'
- newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename);
- if(newFileInfo.relativeUrls) {
- newFileInfo.rootpath = fileManager.join((importManager.context.rootpath || ""), fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath));
- if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) {
- newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath);
- }
+ var loadFileCallback = function(loadedFile) {
+ var resolvedFilename = loadedFile.filename,
+ contents = loadedFile.contents;
+
+ // Pass on an updated rootpath if path of imported file is relative and file
+ // is in a (sub|sup) directory
+ //
+ // Examples:
+ // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/',
+ // then rootpath should become 'less/module/nav/'
+ // - If path of imported file is '../mixins.less' and rootpath is 'less/',
+ // then rootpath should become 'less/../'
+ newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename);
+ if(newFileInfo.relativeUrls) {
+ newFileInfo.rootpath = fileManager.join((importManager.context.rootpath || ""), fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath));
+ if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) {
+ newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath);
}
- newFileInfo.filename = resolvedFilename;
+ }
+ newFileInfo.filename = resolvedFilename;
- var newEnv = new contexts.Parse(importManager.context);
+ var newEnv = new contexts.Parse(importManager.context);
- newEnv.processImports = false;
- importManager.contents[resolvedFilename] = contents;
+ newEnv.processImports = false;
+ importManager.contents[resolvedFilename] = contents;
- if (currentFileInfo.reference || importOptions.reference) {
- newFileInfo.reference = true;
- }
+ if (currentFileInfo.reference || importOptions.reference) {
+ newFileInfo.reference = true;
+ }
- if (importOptions.inline) {
- fileParsedFunc(null, contents, resolvedFilename);
- } else {
- new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) {
- fileParsedFunc(e, root, resolvedFilename);
- });
- }
- },
- function(error) {
- fileParsedFunc(error);
- });
+ if (importOptions.inline) {
+ fileParsedFunc(null, contents, resolvedFilename);
+ } else {
+ new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) {
+ fileParsedFunc(e, root, resolvedFilename);
+ });
+ }
+ };
+
+ var promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, this.context, environment,
+ function(err, loadedFile) {
+ if (err) {
+ fileParsedFunc(err);
+ } else {
+ loadFileCallback(loadedFile);
+ }
+ });
+ if (promise) {
+ promise.then(loadFileCallback, fileParsedFunc);
+ }
};
return ImportManager;
};
diff --git a/lib/less/parser/parser.js b/lib/less/parser/parser.js
index 5893cc9..fe08b9d 100644
--- a/lib/less/parser/parser.js
+++ b/lib/less/parser/parser.js
@@ -241,7 +241,14 @@ var Parser = function Parser(context, imports, fileInfo) {
if (parserInput.peek('}')) {
break;
}
- node = this.extendRule() || mixin.definition() || this.rule() || this.ruleset() ||
+
+ node = this.extendRule();
+ if (node) {
+ root = root.concat(node);
+ continue;
+ }
+
+ node = mixin.definition() || this.rule() || this.ruleset() ||
mixin.call() || this.rulesetCall() || this.directive();
if (node) {
root.push(node);
@@ -923,17 +930,17 @@ var Parser = function Parser(context, imports, fileInfo) {
// Selectors are made out of one or more Elements, see above.
//
selector: function (isLess) {
- var index = parserInput.i, elements, extendList, c, e, extend, when, condition;
+ var index = parserInput.i, elements, extendList, c, e, allExtends, when, condition;
- while ((isLess && (extend = this.extend())) || (isLess && (when = parserInput.$re(/^when/))) || (e = this.element())) {
+ while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$re(/^when/))) || (e = this.element())) {
if (when) {
condition = expect(this.conditions, 'expected condition');
} else if (condition) {
error("CSS guard can only be used at the end of selector");
- } else if (extend) {
- if (extendList) { extendList.push(extend); } else { extendList = [ extend ]; }
+ } else if (extendList) {
+ if (allExtends) { allExtends = allExtends.concat(extendList); } else { allExtends = extendList; }
} else {
- if (extendList) { error("Extend can only be used at the end of selector"); }
+ if (allExtends) { error("Extend can only be used at the end of selector"); }
c = parserInput.currentChar();
if (elements) { elements.push(e); } else { elements = [ e ]; }
e = null;
@@ -943,8 +950,8 @@ var Parser = function Parser(context, imports, fileInfo) {
}
}
- if (elements) { return new(tree.Selector)(elements, extendList, condition, index, fileInfo); }
- if (extendList) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
+ if (elements) { return new(tree.Selector)(elements, allExtends, condition, index, fileInfo); }
+ if (allExtends) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
},
attribute: function () {
if (! parserInput.$char('[')) { return; }
diff --git a/lib/less/render.js b/lib/less/render.js
index 2a164f9..4a56609 100644
--- a/lib/less/render.js
+++ b/lib/less/render.js
@@ -12,14 +12,16 @@ module.exports = function(environment, ParseTree, ImportManager) {
options = {};
}
- if (callback) {
- render.call(this, input, options)
- .then(function(css) {
- callback(null, css);
- },
- function(error) {
- callback(error);
+ if (!callback) {
+ return new PromiseConstructor(function (resolve, reject) {
+ render(input, options, function(err, output) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(output);
+ }
});
+ });
} else {
var context,
rootFileInfo,
@@ -46,19 +48,17 @@ module.exports = function(environment, ParseTree, ImportManager) {
}
var imports = new ImportManager(context, rootFileInfo);
- var parser = new Parser(context, imports, rootFileInfo);
- return new PromiseConstructor(function (resolve, reject) {
- parser.parse(input, function (e, root) {
- if (e) { return reject(e); }
- try {
- var parseTree = new ParseTree(root, imports);
- var result = parseTree.toCSS(options);
- resolve(result);
- }
- catch (err) { reject( err); }
- }, options);
- });
+ new Parser(context, imports, rootFileInfo)
+ .parse(input, function (e, root) {
+ if (e) { return callback(e); }
+ try {
+ var parseTree = new ParseTree(root, imports);
+ var result = parseTree.toCSS(options);
+ callback(null, result);
+ }
+ catch (err) { callback( err); }
+ }, options);
}
};
return render;
diff --git a/lib/less/visitors/import-visitor.js b/lib/less/visitors/import-visitor.js
index 14b5b97..a1a0516 100644
--- a/lib/less/visitors/import-visitor.js
+++ b/lib/less/visitors/import-visitor.js
@@ -15,7 +15,7 @@ var ImportVisitor = function(importer, finish) {
};
ImportVisitor.prototype = {
- isReplacing: true,
+ isReplacing: false,
run: function (root) {
var error;
try {
@@ -44,11 +44,10 @@ ImportVisitor.prototype = {
if (importNode.isVariableImport()) {
this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent));
} else {
- importNode = this.processImportNode(importNode, context, importParent);
+ this.processImportNode(importNode, context, importParent);
}
}
visitArgs.visitDeeper = false;
- return importNode;
},
processImportNode: function(importNode, context, importParent) {
var evaldImportNode,
@@ -73,22 +72,20 @@ ImportVisitor.prototype = {
// try appending if we haven't determined if it is css or not
var tryAppendLessExtension = evaldImportNode.css === undefined;
- var onImported = this.onImported.bind(this, evaldImportNode, context),
- sequencedOnImported = this._sequencer.addImport(onImported);
-
- this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.currentFileInfo, evaldImportNode.options, sequencedOnImported);
-
for(var i = 0; i < importParent.rules.length; i++) {
if (importParent.rules[i] === importNode) {
importParent.rules[i] = evaldImportNode;
break;
}
}
- importNode = evaldImportNode;
+
+ var onImported = this.onImported.bind(this, evaldImportNode, context),
+ sequencedOnImported = this._sequencer.addImport(onImported);
+
+ this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.currentFileInfo, evaldImportNode.options, sequencedOnImported);
} else {
this.importCount--;
}
- return importNode;
},
onImported: function (importNode, context, e, root, importedAtRoot, fullPath) {
if (e) {
@@ -145,32 +142,27 @@ ImportVisitor.prototype = {
},
visitRule: function (ruleNode, visitArgs) {
visitArgs.visitDeeper = false;
- return ruleNode;
},
visitDirective: function (directiveNode, visitArgs) {
this.context.frames.unshift(directiveNode);
- return directiveNode;
},
visitDirectiveOut: function (directiveNode) {
this.context.frames.shift();
},
visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
this.context.frames.unshift(mixinDefinitionNode);
- return mixinDefinitionNode;
},
visitMixinDefinitionOut: function (mixinDefinitionNode) {
this.context.frames.shift();
},
visitRuleset: function (rulesetNode, visitArgs) {
this.context.frames.unshift(rulesetNode);
- return rulesetNode;
},
visitRulesetOut: function (rulesetNode) {
this.context.frames.shift();
},
visitMedia: function (mediaNode, visitArgs) {
this.context.frames.unshift(mediaNode.rules[0]);
- return mediaNode;
},
visitMediaOut: function (mediaNode) {
this.context.frames.shift();
diff --git a/test/index.js b/test/index.js
index ce602e8..d0778d6 100644
--- a/test/index.js
+++ b/test/index.js
@@ -43,4 +43,6 @@ lessTester.runTestSet({globalVars: true, banner: "/**\n * Test\n */\n"}, "glob
lessTester.runTestSet({modifyVars: true}, "modifyVars/",
null, null, null, function(name) { return path.join('test/less/', name) + '.json'; });
lessTester.runTestSet({urlArgs: '424242'}, "url-args/");
+lessTester.testSyncronous({syncImport: true}, "import");
+lessTester.testSyncronous({syncImport: true}, "css");
lessTester.testNoOptions();
diff --git a/test/less-test.js b/test/less-test.js
index 0b0de4a..a57e9f3 100644
--- a/test/less-test.js
+++ b/test/less-test.js
@@ -87,6 +87,21 @@ module.exports = function() {
});
}
+ function testSyncronous(options, filenameNoExtension) {
+ var isSync = true;
+ totalTests++;
+ toCSS(options, path.join('test/less/', filenameNoExtension + ".less"), function (err, result) {
+ process.stdout.write("- Test Sync " + filenameNoExtension + ": ");
+
+ if (isSync) {
+ ok("OK");
+ } else {
+ fail("Not Sync");
+ }
+ });
+ isSync = false;
+ }
+
function runTestSet(options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
foldername = foldername || "";
@@ -204,27 +219,19 @@ module.exports = function() {
function toCSS(options, path, callback) {
options = options || {};
- fs.readFile(path, 'utf8', function (e, str) {
- if (e) { return callback(e); }
+ var str = fs.readFileSync(path, 'utf8');
- options.paths = [require('path').dirname(path)];
- options.filename = require('path').resolve(process.cwd(), path);
- options.optimization = options.optimization || 0;
+ options.paths = [require('path').dirname(path)];
+ options.filename = require('path').resolve(process.cwd(), path);
+ options.optimization = options.optimization || 0;
- if (options.globalVars) {
- options.globalVars = options.getVars(path);
- } else if (options.modifyVars) {
- options.modifyVars = options.getVars(path);
- }
+ if (options.globalVars) {
+ options.globalVars = options.getVars(path);
+ } else if (options.modifyVars) {
+ options.modifyVars = options.getVars(path);
+ }
- less.render(str, options)
- .then(function(result) {
- // TODO integration test that calling toCSS twice results in the same css?
- callback(null, result);
- }, function(e) {
- callback(e);
- });
- });
+ less.render(str, options, callback);
}
function testNoOptions() {
@@ -241,6 +248,7 @@ module.exports = function() {
return {
runTestSet: runTestSet,
+ testSyncronous: testSyncronous,
testErrors: testErrors,
testSourcemap: testSourcemap,
testNoOptions: testNoOptions
--
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