mirror of
https://github.com/less/less.js.git
synced 2026-01-22 21:58:14 -05:00
221 lines
7.9 KiB
JavaScript
221 lines
7.9 KiB
JavaScript
var path = require('path'),
|
|
url = require('url'),
|
|
request,
|
|
fs = require('./fs'),
|
|
isUrlRe = /^(?:https?:)?\/\//i;
|
|
|
|
module.exports = {
|
|
warn: function(msg) {
|
|
console.warn(msg);
|
|
},
|
|
encodeBase64: function encodeBase64(str) {
|
|
return new Buffer(str).toString('base64');
|
|
},
|
|
supportsDataURI: function() {
|
|
return true;
|
|
},
|
|
mimeLookup: function (filename) {
|
|
return require('mime').lookup(filename);
|
|
},
|
|
charsetLookup: function (mime) {
|
|
return require('mime').charsets.lookup(mime);
|
|
},
|
|
readFileSync: function (filename) {
|
|
return require("fs").readFileSync(filename);
|
|
},
|
|
getPath: function (filename) {
|
|
var j = filename.lastIndexOf('/');
|
|
if (j < 0) {
|
|
j = filename.lastIndexOf('\\');
|
|
}
|
|
if (j < 0) {
|
|
return "";
|
|
}
|
|
return filename.slice(0, j + 1);
|
|
},
|
|
isPathAbsolute: function(filename) {
|
|
return (/^(?:[a-z-]+:|\/|\\)/i).test(filename);
|
|
},
|
|
getAbsolutePath: function getAbsolutePath(filename) {
|
|
return require('path').resolve(filename);
|
|
},
|
|
getSourceMapGenerator: function getSourceMapGenerator() {
|
|
return require("source-map").SourceMapGenerator;
|
|
},
|
|
alwaysMakePathsAbsolute: function alwaysMakePathsAbsolute() {
|
|
return false;
|
|
},
|
|
join: function join(basePath, laterPath) {
|
|
if (!basePath) {
|
|
return laterPath;
|
|
}
|
|
return basePath + laterPath;
|
|
},
|
|
pathDiff: function pathDiff(url, baseUrl) {
|
|
// diff between two paths to create a relative path
|
|
|
|
var urlParts = this.extractUrlParts(url),
|
|
baseUrlParts = this.extractUrlParts(baseUrl),
|
|
i, max, urlDirectories, baseUrlDirectories, diff = "";
|
|
if (urlParts.hostPart !== baseUrlParts.hostPart) {
|
|
return "";
|
|
}
|
|
max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
|
|
for(i = 0; i < max; i++) {
|
|
if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
|
|
}
|
|
baseUrlDirectories = baseUrlParts.directories.slice(i);
|
|
urlDirectories = urlParts.directories.slice(i);
|
|
for(i = 0; i < baseUrlDirectories.length-1; i++) {
|
|
diff += "../";
|
|
}
|
|
for(i = 0; i < urlDirectories.length-1; i++) {
|
|
diff += urlDirectories[i] + "/";
|
|
}
|
|
return diff;
|
|
},
|
|
// helper function, not part of API
|
|
extractUrlParts: function extractUrlParts(url, baseUrl) {
|
|
// urlParts[1] = protocol&hostname || /
|
|
// urlParts[2] = / if path relative to host base
|
|
// urlParts[3] = directories
|
|
// urlParts[4] = filename
|
|
// urlParts[5] = parameters
|
|
|
|
var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
|
|
urlParts = url.match(urlPartsRegex),
|
|
returner = {}, directories = [], i, baseUrlParts;
|
|
|
|
if (!urlParts) {
|
|
throw new Error("Could not parse sheet href - '"+url+"'");
|
|
}
|
|
|
|
// Stylesheets in IE don't always return the full path
|
|
if (baseUrl && (!urlParts[1] || urlParts[2])) {
|
|
baseUrlParts = baseUrl.match(urlPartsRegex);
|
|
if (!baseUrlParts) {
|
|
throw new Error("Could not parse page url - '"+baseUrl+"'");
|
|
}
|
|
urlParts[1] = urlParts[1] || baseUrlParts[1] || "";
|
|
if (!urlParts[2]) {
|
|
urlParts[3] = baseUrlParts[3] + urlParts[3];
|
|
}
|
|
}
|
|
|
|
if (urlParts[3]) {
|
|
directories = urlParts[3].replace(/\\/g, "/").split("/");
|
|
|
|
// extract out . before .. so .. doesn't absorb a non-directory
|
|
for(i = 0; i < directories.length; i++) {
|
|
if (directories[i] === ".") {
|
|
directories.splice(i, 1);
|
|
i -= 1;
|
|
}
|
|
}
|
|
|
|
for(i = 0; i < directories.length; i++) {
|
|
if (directories[i] === ".." && i > 0) {
|
|
directories.splice(i-1, 2);
|
|
i -= 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
returner.hostPart = urlParts[1];
|
|
returner.directories = directories;
|
|
returner.path = urlParts[1] + directories.join("/");
|
|
returner.fileUrl = returner.path + (urlParts[4] || "");
|
|
returner.url = returner.fileUrl + (urlParts[5] || "");
|
|
return returner;
|
|
},
|
|
loadFile: function(filename, currentDirectory, options, callback) {
|
|
var fullFilename,
|
|
data,
|
|
isUrl = isUrlRe.test( filename );
|
|
|
|
options = options || {};
|
|
|
|
if (isUrl || isUrlRe.test(currentDirectory)) {
|
|
if (request === undefined) {
|
|
try { request = require('request'); }
|
|
catch(e) { request = null; }
|
|
}
|
|
if (!request) {
|
|
callback({ type: 'File', message: "optional dependency 'request' required to import over http(s)\n" });
|
|
return;
|
|
}
|
|
|
|
var urlStr = isUrl ? filename : url.resolve(currentDirectory, filename),
|
|
urlObj = url.parse(urlStr);
|
|
|
|
if (!urlObj.protocol) {
|
|
urlObj.protocol = "http";
|
|
urlStr = urlObj.format();
|
|
}
|
|
|
|
request.get({uri: urlStr, strictSSL: !options.insecure }, function (error, res, body) {
|
|
if (error) {
|
|
callback({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n "+ error +"\n" });
|
|
}
|
|
if (res && res.statusCode === 404) {
|
|
callback({ type: 'File', message: "resource '" + urlStr + "' was not found\n" });
|
|
return;
|
|
}
|
|
if (!body) {
|
|
this.warn('Warning: Empty body (HTTP '+ res.statusCode + ') returned by "' + urlStr +'"');
|
|
}
|
|
fullFilename = urlStr;
|
|
callback(null, body, fullFilename);
|
|
});
|
|
} else {
|
|
|
|
var paths = [currentDirectory];
|
|
if (options.paths) paths.push.apply(paths, options.paths);
|
|
if (paths.indexOf('.') === -1) paths.push('.');
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
if (!fullFilename) {
|
|
callback({ type: 'File', message: "'" + filename + "' wasn't found" });
|
|
return;
|
|
}
|
|
|
|
data = fs.readFileSync(fullFilename, 'utf-8');
|
|
callback(null, data, fullFilename);
|
|
} 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) { callback(e); }
|
|
|
|
// do processing in the next tick to allow
|
|
// file handling to dispose
|
|
process.nextTick(function() {
|
|
callback(null, data, fullFilename);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
callback({ type: 'File', message: "'" + filename + "' wasn't found" });
|
|
}
|
|
}(0));
|
|
}
|
|
}
|
|
}
|
|
};
|