Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented URL rewriting in relative imports and urls relatively to the file that defines them. #976

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion bin/lessc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ var options = {
silent: false,
paths: [],
color: true,
strictImports: false
strictImports: false,
rootpath: ''
};
var continueProcessing = true,
currentErrorcode;
Expand Down Expand Up @@ -77,6 +78,10 @@ args = args.filter(function (arg) {
case 'line-numbers':
options.dumpLineNumbers = match[2];
break;
case 'rp':
case 'rootpath':
options.rootpath = path.normalize(match[2] + '/');
break;
}
});

Expand Down Expand Up @@ -114,6 +119,7 @@ var parseLessFile = function (e, data) {
paths: [path.dirname(input)].concat(options.paths),
optimization: options.optimization,
filename: input,
rootpath: options.rootpath,
strictImports: options.strictImports,
dumpLineNumbers: options.dumpLineNumbers
}).parse(data, function (err, tree) {
Expand Down
4 changes: 4 additions & 0 deletions lib/less/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ function loadStyleSheet(sheet, callback, reload, remaining) {
href = url.slice(0, url.lastIndexOf('/') + 1) + href;
}
}

var rootpath = sheet.rootpath || href.replace(/[\w\.-]+$/, '');

xhr(sheet.href, sheet.type, function (data, lastModified) {
if (!reload && styles && lastModified &&
(new(Date)(lastModified).valueOf() ===
Expand All @@ -157,6 +160,7 @@ function loadStyleSheet(sheet, callback, reload, remaining) {
paths: [href.replace(/[\w\.-]+$/, '')],
mime: sheet.type,
filename: href,
rootpath: rootpath,
'contents': contents, // Passing top importing parser content cache ref down.
dumpLineNumbers: less.dumpLineNumbers
}).parse(data, function (e, root) {
Expand Down
16 changes: 16 additions & 0 deletions lib/less/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,26 @@ less.Parser.importer = function (file, paths, callback, env) {
fs.readFile(pathname, 'utf-8', function(e, data) {
if (e) return callback(e);

var rootpath = env.rootpath,
j = file.lastIndexOf('/');

// 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/../'
if(!/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
rootpath = 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: [path.dirname(pathname)].concat(paths),
filename: pathname,
rootpath: rootpath,
contents: env.contents,
dumpLineNumbers: env.dumpLineNumbers
}).parse(data, function (e, root) {
Expand Down
1 change: 1 addition & 0 deletions lib/less/lessc_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var lessc_helper = {
sys.puts(" that will output the information within a fake");
sys.puts(" media query which is compatible with the SASS");
sys.puts(" format, and 'all' which will do both.");
sys.puts(" -rp, --rootpath Set rootpath for url rewriting in relative imports and urls.");
sys.puts("");
sys.puts("Report bugs to: http://github.com/cloudhead/less.js/issues");
sys.puts("Home page: <http://lesscss.org/>");
Expand Down
7 changes: 4 additions & 3 deletions lib/less/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ less.Parser = function Parser(env) {
// which will then be passed arround by reference.
var env = env || { };
if (!env.contents) { env.contents={}; } // env.contents must be passed arround with top env
env.rootpath = env.rootpath || ''; // env.rootpath must be initialized to '' if not provided

// This function is called after all files
// have been imported through `@import`.
Expand Down Expand Up @@ -661,7 +662,7 @@ less.Parser = function Parser(env) {
expect(')');

return new(tree.URL)((value.value != null || value instanceof tree.Variable)
? value : new(tree.Anonymous)(value), imports.paths);
? value : new(tree.Anonymous)(value), env.rootpath);
},

//
Expand Down Expand Up @@ -1140,7 +1141,7 @@ less.Parser = function Parser(env) {
if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) {
features = $(this.mediaFeatures);
if ($(';')) {
return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index);
return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index, env.rootpath);
}
}

Expand Down Expand Up @@ -1433,7 +1434,7 @@ if (less.mode === 'browser' || less.mode === 'rhino') {
// 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.
// __ Now using the hack of passing a ref to top parser's content cache in the 1st arg. __
loadStyleSheet({ href: path, title: path, type: env.mime, contents: env.contents }, function (e) {
loadStyleSheet({ href: path, title: path, type: env.mime, contents: env.contents, rootpath: env.rootpath }, function (e) {
if (e && typeof(env.errback) === "function") {
env.errback.call(null, path, paths, callback, env);
} else {
Expand Down
9 changes: 7 additions & 2 deletions lib/less/tree/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
// `import,push`, we also pass it a callback, which it'll call once
// the file has been fetched, and parsed.
//
tree.Import = function (path, imports, features, once, index) {
tree.Import = function (path, imports, features, once, index, rootpath) {
var that = this;

this.once = once;
this.index = index;
this._path = path;
this.features = features && new(tree.Value)(features);

this.rootpath = rootpath;

// The '.less' extension is optional
if (path instanceof tree.Quoted) {
this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less';
Expand Down Expand Up @@ -52,6 +53,10 @@ tree.Import.prototype = {
var features = this.features ? ' ' + this.features.toCSS(env) : '';

if (this.css) {
// Add the base path if the import is relative
if (typeof this._path.value === "string" && !/^(?:[a-z-]+:|\/)/.test(this._path.value)) {
this._path.value = this.rootpath + this._path.value;
}
return "@import " + this._path.toCSS() + features + ';\n';
} else {
return "";
Expand Down
12 changes: 6 additions & 6 deletions lib/less/tree/url.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
(function (tree) {

tree.URL = function (val, paths) {
tree.URL = function (val, rootpath) {
this.value = val;
this.paths = paths;
this.rootpath = rootpath;
};
tree.URL.prototype = {
toCSS: function () {
Expand All @@ -11,12 +11,12 @@ tree.URL.prototype = {
eval: function (ctx) {
var val = this.value.eval(ctx);

// Add the base path if the URL is relative and we are in the browser
if (typeof window !== 'undefined' && typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value) && this.paths.length > 0) {
val.value = this.paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
// Add the base path if the URL is relative
if (typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value)) {
val.value = this.rootpath + val.value;
}

return new(tree.URL)(val, this.paths);
return new(tree.URL)(val, this.rootpath);
}
};

Expand Down
4 changes: 2 additions & 2 deletions test/css/import-once.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import "import-test-d.css";
@import "import/import-test-d.css";

@import "../import-test-d.css";
@import "import/deeper/../import-test-d.css";
#import {
color: #ff0000;
}
16 changes: 15 additions & 1 deletion test/css/import.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
@import "import-test-d.css";
@import "import/import-test-d.css";

@import url(http://fonts.googleapis.com/css?family=Open+Sans);

@import url(something.css) screen and (color) and (max-width: 600px);

@import "import/../css/background.css";
#import {
color: #ff0000;
}
Expand All @@ -21,3 +23,15 @@
width: 100%;
}
}
#logo {
width: 100px;
height: 100px;
background: url('import/imports/../assets/logo.png');
}
@font-face {
font-family: xecret;
src: url('import/imports/../assets/xecret.ttf');
}
#secret {
font-family: xecret, sans-serif;
}
3 changes: 2 additions & 1 deletion test/less/import-once.less
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import "import/import-once-test-c";
@import-once "import/import-once-test-c";
@import-once "import/import-once-test-c";
@import-once "import/deeper/import-once-test-a";
@import-once "import/deeper/import-once-test-a";
2 changes: 2 additions & 0 deletions test/less/import.less
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
height: @a + 10%;
}
@import "import/import-test-e" screen and (max-width: 600px);

@import "import/import-and-relative-paths-test";
5 changes: 5 additions & 0 deletions test/less/import/import-and-relative-paths-test.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import "../css/background.css";

@import "imports/logo";
@import "imports/font";

8 changes: 8 additions & 0 deletions test/less/import/imports/font.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@font-face {
font-family: xecret;
src: url('../assets/xecret.ttf');
}

#secret {
font-family: xecret, sans-serif;
}
5 changes: 5 additions & 0 deletions test/less/import/imports/logo.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#logo {
width: 100px;
height: 100px;
background: url('../assets/logo.png');
}