From e45ec8a31efdaace482e3881417eb4b050141eee Mon Sep 17 00:00:00 2001 From: Luke Page Date: Wed, 23 Jan 2013 19:07:05 +0000 Subject: [PATCH] refactoring - add a env type to better organise its properties --- Makefile | 2 ++ bin/lessc | 14 ++++------ lib/less/browser.js | 66 +++++++++++++++++++-------------------------- lib/less/env.js | 50 ++++++++++++++++++++++++++++++++++ lib/less/index.js | 23 +++++++--------- lib/less/parser.js | 42 +++++++++++------------------ 6 files changed, 110 insertions(+), 87 deletions(-) create mode 100644 lib/less/env.js diff --git a/Makefile b/Makefile index 043b0aa4..1f88aa22 100644 --- a/Makefile +++ b/Makefile @@ -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\ diff --git a/bin/lessc b/bin/lessc index ae617e7b..fe0c22d3 100755 --- a/bin/lessc +++ b/bin/lessc @@ -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; diff --git a/lib/less/browser.js b/lib/less/browser.js index ae8c9d75..e0cef82b 100644 --- a/lib/less/browser.js +++ b/lib/less/browser.js @@ -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))); diff --git a/lib/less/env.js b/lib/less/env.js new file mode 100644 index 00000000..abba76e4 --- /dev/null +++ b/lib/less/env.js @@ -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')); \ No newline at end of file diff --git a/lib/less/index.js b/lib/less/index.js index 4005a74f..e431be64 100644 --- a/lib/less/index.js +++ b/lib/less/index.js @@ -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'); diff --git a/lib/less/parser.js b/lib/less/parser.js index e6c73073..2e9efef6 100644 --- a/lib/less/parser.js +++ b/lib/less/parser.js @@ -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); }; }