refactoring - add a env type to better organise its properties

This commit is contained in:
Luke Page
2013-01-23 19:07:05 +00:00
parent 26d35c98fe
commit e45ec8a31e
6 changed files with 110 additions and 87 deletions

View File

@@ -38,6 +38,7 @@ less:
${SRC}/colors.js\
${SRC}/tree/*.js\
${SRC}/tree.js\
${SRC}/env.js\
${SRC}/browser.js\
build/amd.js >> ${DIST}
@@echo "})(window);" >> ${DIST}
@@ -58,6 +59,7 @@ rhino:
@@cat build/require-rhino.js\
build/ecma-5.js\
${SRC}/parser.js\
${SRC}/env.js\
${SRC}/functions.js\
${SRC}/colors.js\
${SRC}/tree/*.js\

View File

@@ -148,15 +148,11 @@ var parseLessFile = function (e, data) {
return;
}
new(less.Parser)({
paths: [path.dirname(input)].concat(options.paths),
optimization: options.optimization,
filename: input,
rootpath: options.rootpath,
relativeUrls: options.relativeUrls,
strictImports: options.strictImports,
dumpLineNumbers: options.dumpLineNumbers
}).parse(data, function (err, tree) {
options.paths = [path.dirname(input)].concat(options.paths);
options.filename = input;
new(less.Parser)(options)
.parse(data, function (err, tree) {
if (err) {
less.writeError(err, options);
currentErrorcode = 1;

View File

@@ -103,7 +103,7 @@ less.modifyVars = function(record) {
str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+
((record[name].slice(-1) === ';')? record[name] : record[name] +';');
}
new(less.Parser)().parse(str, function (e, root) {
new(less.Parser)(new less.tree.parseEnv(less)).parse(str, function (e, root) {
createCSS(root.toCSS(), less.sheets[less.sheets.length - 1]);
});
};
@@ -134,11 +134,11 @@ function loadStyles() {
var styles = document.getElementsByTagName('style');
for (var i = 0; i < styles.length; i++) {
if (styles[i].type.match(typePattern)) {
new(less.Parser)({
filename: document.location.href.replace(/#.*$/, ''),
dumpLineNumbers: less.dumpLineNumbers
}).parse(styles[i].innerHTML || '', function (e, tree) {
var css = tree.toCSS();
var env = new less.tree.parseEnv(less);
env.filename = document.location.href.replace(/#.*$/, '');
new(less.Parser)(env).parse(styles[i].innerHTML || '', function (e, cssAST) {
var css = cssAST.toCSS();
var style = styles[i];
style.type = 'text/css';
if (style.styleSheet) {
@@ -228,36 +228,35 @@ function extractUrlParts(url, baseUrl) {
}
function loadStyleSheet(sheet, callback, reload, remaining) {
// sheet may be set to the stylesheet for the initial load or a collection of properties including
// some env variables for imports
var contents = sheet.contents || {};
var files = sheet.files || {};
var hrefParts = extractUrlParts(sheet.href, window.location.href);
var href = hrefParts.url;
var css = cache && cache.getItem(href);
var timestamp = cache && cache.getItem(href + ':timestamp');
var styles = { css: css, timestamp: timestamp };
var rootpath;
var env;
if (less.relativeUrls) {
if (sheet instanceof less.tree.parseEnv) {
env = new less.tree.parseEnv(sheet);
} else {
env = new less.tree.parseEnv(less);
env.entryPath = hrefParts.path;
env.mime = sheet.type;
}
if (env.relativeUrls) {
//todo - this relies on option being set on less object rather than being passed in as an option
// - need an originalRootpath
if (less.rootpath) {
if (sheet.entryPath) {
rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, sheet.entryPath)).path;
} else {
rootpath = less.rootpath;
}
env.rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, env.entryPath)).path;
} else {
rootpath = hrefParts.path;
env.rootpath = hrefParts.path;
}
} else {
if (less.rootpath) {
rootpath = less.rootpath;
} else {
if (sheet.entryPath) {
rootpath = sheet.entryPath;
} else {
rootpath = hrefParts.path;
}
if (!less.rootpath) {
env.rootpath = env.entryPath;
}
}
@@ -274,20 +273,11 @@ function loadStyleSheet(sheet, callback, reload, remaining) {
} else {
// Use remote copy (re-parse)
try {
contents[href] = data; // Updating top importing parser content cache
new(less.Parser)({
optimization: less.optimization,
paths: [hrefParts.path],
entryPath: sheet.entryPath || hrefParts.path,
mime: sheet.type,
filename: href,
rootpath: rootpath,
relativeUrls: sheet.relativeUrls,
contents: contents, // Passing top importing parser content cache ref down.
files: files,
dumpLineNumbers: less.dumpLineNumbers
}).parse(data, function (e, root) {
if (e) { return error(e, href) }
env.contents[href] = data; // Updating content cache
env.paths = [hrefParts.path];
env.filename = href;
new(less.Parser)(env).parse(data, function (e, root) {
if (e) { return error(e, href); }
try {
callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href);
removeNode(document.getElementById('less-error-message:' + extractId(href)));

50
lib/less/env.js Normal file
View File

@@ -0,0 +1,50 @@
(function (tree) {
var parseCopyProperties = [
'paths', // paths to search for imports on
'optimization', // option - optimization level (for the chunker)
'filename', // current filename, used for error reporting
'files', // list of files that have been imported, used for import-once
'contents', // browser-only, contents of all the files
'rootpath', // current rootpath to append to all url's
'relativeUrls', // option - whether to adjust URL's to be relative
'strictImports', // option -
'dumpLineNumbers', // option - whether to dump line numbers
'compress', // option - whether to compress
'mime', // browser only - mime type for sheet import
'entryPath' // browser only, path of entry less file
];
tree.parseEnv = function(options) {
copyFromOriginal(options, this, parseCopyProperties);
if (!this.contents) { this.contents = {}; }
if (!this.rootpath) { this.rootpath = ''; }
if (!this.files) { this.files = {}; }
};
tree.parseEnv.prototype.toSheet = function (path) {
var env = new tree.parseEnv(this);
env.href = path;
//env.title = path;
env.type = this.mime;
return env;
};
//todo - do the same for the eval env and the toCSS env
//tree.evalEnv = function(options) {
//};
//tree.toCSSEnv = function (options) {
//};
var copyFromOriginal = function(original, destination, propertiesToCopy) {
if (!original) { return; }
for(var i = 0; i < propertiesToCopy.length; i++) {
if (original.hasOwnProperty(propertiesToCopy[i])) {
destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
}
}
}
})(require('./tree'));

View File

@@ -103,10 +103,11 @@ less.Parser.importer = function (file, paths, callback, env) {
var pathname, dirname, data;
function parseFile(e, data) {
if (e) return callback(e);
if (e) { return callback(e); }
env = new less.tree.parseEnv(env);
var rootpath = env.rootpath,
j = file.lastIndexOf('/');
var j = file.lastIndexOf('/');
// Pass on an updated rootpath if path of imported file is relative and file
// is in a (sub|sup) directory
@@ -117,20 +118,13 @@ less.Parser.importer = function (file, paths, callback, env) {
// - If path of imported file is '../mixins.less' and rootpath is 'less/',
// then rootpath should become 'less/../'
if(env.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
rootpath = rootpath + file.slice(0, j+1); // append (sub|sup) directory path of imported file
env.rootpath = env.rootpath + file.slice(0, j+1); // append (sub|sup) directory path of imported file
}
env.contents[pathname] = data; // Updating top importing parser content cache.
new(less.Parser)({
paths: [dirname].concat(paths),
filename: pathname,
contents: env.contents,
files: env.files,
syncImport: env.syncImport,
relativeUrls: env.relativeUrls,
rootpath: rootpath,
dumpLineNumbers: env.dumpLineNumbers
}).parse(data, function (e, root) {
env.paths = [dirname].concat(paths);
env.filename = pathname;
new(less.Parser)(env).parse(data, function (e, root) {
callback(e, root, pathname);
});
};
@@ -213,6 +207,7 @@ less.Parser.importer = function (file, paths, callback, env) {
}
}
require('./env');
require('./functions');
require('./colors');

View File

@@ -66,12 +66,10 @@ less.Parser = function Parser(env) {
var that = this;
// Top parser on an import tree must be sure there is one "env"
// which will then be passed arround by reference.
var env = env || { };
// env.contents and files must be passed arround with top env
if (!env.contents) { env.contents = {}; }
env.rootpath = env.rootpath || ''; // env.rootpath must be initialized to '' if not provided
if (!env.files) { env.files = {}; }
// which will then be passed around by reference.
if (!(env instanceof tree.parseEnv)) {
env = new tree.parseEnv(env);
}
// This function is called after all files
// have been imported through `@import`.
@@ -98,17 +96,17 @@ less.Parser = function Parser(env) {
that.files[fullPath] = root; // Store the root
if (e && !that.error) { that.error = e }
if (e && !that.error) { that.error = e; }
callback(e, root, imported);
if (that.queue.length === 0) { finish(that.error) } // Call `finish` if we're done importing
if (that.queue.length === 0) { finish(that.error); } // Call `finish` if we're done importing
}, env);
}
};
function save() { temp = chunks[j], memo = i, current = i }
function restore() { chunks[j] = temp, i = memo, current = i }
function save() { temp = chunks[j], memo = i, current = i; }
function restore() { chunks[j] = temp, i = memo, current = i; }
function sync() {
if (i > current) {
@@ -1527,22 +1525,14 @@ if (less.mode === 'browser' || less.mode === 'rhino') {
// We pass `true` as 3rd argument, to force the reload of the import.
// This is so we can get the syntax tree as opposed to just the CSS output,
// as we need this to evaluate the current stylesheet.
loadStyleSheet({
href: path,
title: path,
type: env.mime,
contents: env.contents,
files: env.files,
rootpath: env.rootpath,
entryPath: env.entryPath,
relativeUrls: env.relativeUrls },
function (e, root, data, sheet, _, path) {
if (e && typeof(env.errback) === "function") {
env.errback.call(null, path, paths, callback, env);
} else {
callback.call(null, e, root, path);
}
}, true);
loadStyleSheet(env.toSheet(path),
function (e, root, data, sheet, _, path) {
if (e && typeof(env.errback) === "function") {
env.errback.call(null, path, paths, callback, env);
} else {
callback.call(null, e, root, path);
}
}, true);
};
}