Skip to content

Commit 9fd1ef5

Browse files
committed
Pushing WIP of changes to file manager to track changes
1 parent ff5760e commit 9fd1ef5

File tree

13 files changed

+231
-110
lines changed

13 files changed

+231
-110
lines changed

Gruntfile.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
module.exports = function (grunt) {
44

5+
6+
grunt.option('stack', true)
7+
58
// Report the elapsed execution time of tasks.
69
require('time-grunt')(grunt);
710

@@ -438,7 +441,7 @@ module.exports = function (grunt) {
438441
'uglify:dist'
439442
]);
440443

441-
// Release Rhino Version
444+
// Release Rhino Version (UNSUPPORTED)
442445
grunt.registerTask('rhino', [
443446
'browserify:rhino',
444447
'concat:rhino',

lib/less-browser/index.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,7 @@ module.exports = function(window, options) {
3030
var typePattern = /^text\/(x-)?less$/;
3131

3232
function clone(obj) {
33-
var cloned = {};
34-
for (var prop in obj) {
35-
if (obj.hasOwnProperty(prop)) {
36-
cloned[prop] = obj[prop];
37-
}
38-
}
39-
return cloned;
33+
return JSON.parse(JSON.stringify(obj || {}));
4034
}
4135

4236
// only really needed for phantom

lib/less-node/file-manager.js

Lines changed: 87 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
var path = require('path'),
22
fs = require('./fs'),
3-
PromiseConstructor,
3+
PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise,
44
AbstractFileManager = require("../less/environment/abstract-file-manager.js");
55

6-
try {
7-
PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
8-
} catch (e) {
9-
}
10-
116
var FileManager = function() {
7+
this.files = {};
128
};
139

1410
FileManager.prototype = new AbstractFileManager();
@@ -20,46 +16,85 @@ FileManager.prototype.supportsSync = function(filename, currentDirectory, option
2016
return true;
2117
};
2218

23-
FileManager.prototype.loadFile = function(filename, currentDirectory, options, environment, callback) {
19+
FileManager.prototype.loadFile = function(filename, currentDirectory, options, environment) {
20+
21+
// TODO refactor so isn't cut and paste between loadFileSync
2422
var fullFilename,
2523
data,
2624
isAbsoluteFilename = this.isPathAbsolute(filename),
27-
filenamesTried = [];
25+
filenamesTried = [],
26+
self = this,
27+
prefix = filename.slice(0, 1),
28+
explicit = prefix === "." || prefix === "/";
2829

2930
options = options || {};
3031

31-
if (options.syncImport || !PromiseConstructor) {
32-
data = this.loadFileSync(filename, currentDirectory, options, environment, 'utf-8');
33-
callback(data.error, data);
34-
return;
35-
}
32+
var paths = isAbsoluteFilename ? [''] : [currentDirectory];
3633

37-
var paths = isAbsoluteFilename ? [""] : [currentDirectory];
3834
if (options.paths) { paths.push.apply(paths, options.paths); }
35+
36+
// Search node_modules
37+
if (!explicit) { paths.push.apply(paths, this.modulePaths); }
38+
3939
if (!isAbsoluteFilename && paths.indexOf('.') === -1) { paths.push('.'); }
4040

41+
var prefixes = options.prefixes || [''];
42+
var fileParts = this.extractUrlParts(filename);
43+
4144
// promise is guaranteed to be asyncronous
4245
// which helps as it allows the file handle
4346
// to be closed before it continues with the next file
4447
return new PromiseConstructor(function(fulfill, reject) {
48+
if (options.syncImport) {
49+
data = this.loadFileSync(filename, currentDirectory, options, environment, 'utf-8');
50+
if (data.error) {
51+
reject(data.error);
52+
}
53+
else {
54+
fulfill(data);
55+
}
56+
return;
57+
}
4558
(function tryPathIndex(i) {
4659
if (i < paths.length) {
47-
fullFilename = filename;
48-
if (paths[i]) {
49-
fullFilename = path.join(paths[i], fullFilename);
50-
}
51-
fs.stat(fullFilename, function (err) {
52-
if (err) {
53-
filenamesTried.push(fullFilename);
54-
tryPathIndex(i + 1);
55-
} else {
56-
fs.readFile(fullFilename, 'utf-8', function(e, data) {
57-
if (e) { reject(e); return; }
60+
(function tryPrefix(j) {
61+
if (j < prefixes.length) {
62+
63+
fullFilename = fileParts.rawPath + prefixes[j] + fileParts.filename;
64+
65+
if (paths[i]) {
66+
fullFilename = path.join(paths[i], fullFilename);
67+
}
68+
if (paths[i].indexOf('node_modules') > -1) {
69+
try {
70+
fullFilename = require.resolve(fullFilename);
71+
}
72+
catch (e) {}
73+
}
74+
else {
75+
fullFilename = options.ext ? self.tryAppendExtension(fullFilename, options.ext) : fullFilename;
76+
}
77+
78+
if (self.files[fullFilename]) {
79+
fulfill({ contents: self.files[fullFilename], filename: fullFilename});
80+
}
81+
else {
82+
83+
fs.readFile(fullFilename, 'utf-8', function(e, data) {
84+
if (e) {
85+
filenamesTried.push(fullFilename);
86+
return tryPrefix(j + 1);
87+
}
88+
self.files[fullFilename] = data;
89+
fulfill({ contents: data, filename: fullFilename});
90+
});
91+
}
5892

59-
fulfill({ contents: data, filename: fullFilename});
60-
});
6193
}
62-
});
94+
else {
95+
tryPathIndex(i + 1);
96+
}
97+
})(0);
6398
} else {
6499
reject({ type: 'File', message: "'" + filename + "' wasn't found. Tried - " + filenamesTried.join(",") });
65100
}
@@ -79,26 +114,39 @@ FileManager.prototype.loadFileSync = function(filename, currentDirectory, option
79114
paths.push('.');
80115
}
81116

82-
var err, result;
117+
var prefixes = options.prefixes || [''];
118+
var fileParts = this.extractUrlParts(filename);
119+
120+
var err, result, breakAll = false;
83121
for (var i = 0; i < paths.length; i++) {
84-
try {
85-
fullFilename = filename;
86-
if (paths[i]) {
87-
fullFilename = path.join(paths[i], fullFilename);
122+
for (var j = 0; j < prefixes.length; j++) {
123+
try {
124+
fullFilename = fileParts.rawPath + prefixes[j] + fileParts.filename;
125+
if (paths[i]) {
126+
fullFilename = path.join(paths[i], fullFilename);
127+
}
128+
filenamesTried.push(fullFilename);
129+
fs.statSync(fullFilename);
130+
breakAll = true;
131+
break;
132+
} catch (e) {
133+
fullFilename = null;
88134
}
89-
filenamesTried.push(fullFilename);
90-
fs.statSync(fullFilename);
91-
break;
92-
} catch (e) {
93-
fullFilename = null;
94135
}
136+
if (breakAll) { break; }
95137
}
96138

97139
if (!fullFilename) {
98140
err = { type: 'File', message: "'" + filename + "' wasn't found. Tried - " + filenamesTried.join(",") };
99141
result = { error: err };
100142
} else {
101-
data = fs.readFileSync(fullFilename, encoding);
143+
if (this.files[fullFilename]) {
144+
data = this.files[fullFilename];
145+
}
146+
else {
147+
data = fs.readFileSync(fullFilename, encoding);
148+
this.files[fullFilename] = data;
149+
}
102150
result = { contents: data, filename: fullFilename};
103151
}
104152

lib/less-node/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ var environment = require("./environment"),
33
UrlFileManager = require("./url-file-manager"),
44
createFromEnvironment = require("../less"),
55
less = createFromEnvironment(environment, [new FileManager(), new UrlFileManager()]),
6-
lesscHelper = require('./lessc-helper');
6+
lesscHelper = require('./lessc-helper'),
7+
path = require('path');
78

89
// allow people to create less with their own environment
910
less.createFromEnvironment = createFromEnvironment;
@@ -13,6 +14,9 @@ less.fs = require("./fs");
1314
less.FileManager = FileManager;
1415
less.UrlFileManager = UrlFileManager;
1516
less.options = require('../less/default-options');
17+
less.options.paths = [
18+
path.join(process.cwd(), "node_modules")
19+
];
1620

1721
// provide image-size functionality
1822
require('./image-size')(less.environment);

lib/less-node/plugin-loader.js

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
var path = require("path"),
2+
PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise,
23
AbstractPluginLoader = require("../less/environment/abstract-plugin-loader.js");
34

45
/**
56
* Node Plugin Loader
67
*/
78
var PluginLoader = function(less) {
89
this.less = less;
9-
this.require = require;
10-
this.requireRelative = function(prefix) {
10+
this.require = function(prefix) {
1111
prefix = path.dirname(prefix);
1212
return function(id) {
1313
var str = id.substr(0, 2);
@@ -23,24 +23,31 @@ var PluginLoader = function(less) {
2323

2424
PluginLoader.prototype = new AbstractPluginLoader();
2525

26-
PluginLoader.prototype.tryLoadPlugin = function(name, basePath, callback) {
26+
PluginLoader.prototype.loadPlugin = function(filename, basePath, context, environment, fileManager) {
2727
var self = this;
28-
var prefix = name.slice(0, 1);
29-
var explicit = prefix === "." || prefix === "/" || name.slice(-3).toLowerCase() === ".js";
30-
if (explicit) {
31-
this.tryLoadFromEnvironment(name, basePath, explicit, callback);
32-
}
33-
else {
34-
this.tryLoadFromEnvironment('less-plugin-' + name, basePath, explicit, function(err, data) {
35-
if (!err) {
36-
callback(null, data);
37-
}
38-
else {
39-
self.tryLoadFromEnvironment(name, basePath, explicit, callback);
40-
}
41-
});
28+
var prefixes, prefix = filename.slice(0, 1);
29+
var explicit = prefix === "." || prefix === "/" || filename.slice(-3).toLowerCase() === ".js";
30+
if (!explicit) {
31+
context.prefixes = ['less-plugin-', ''];
4232
}
4333

34+
return fileManager.loadFile(filename, basePath, context, environment);
35+
// return new PromiseConstructor(function(fulfill, reject) {
36+
// fileManager.loadFile(filename, basePath, context, environment).then(
37+
// function(data) {
38+
// try {
39+
// self.require = self.requireRelative(filename);
40+
// fulfill(data);
41+
// }
42+
// catch (e) {
43+
// reject(e);
44+
// }
45+
// }
46+
// ).catch(function(err) {
47+
// reject(err);
48+
// });
49+
// });
50+
4451
};
4552

4653
PluginLoader.prototype.tryLoadFromEnvironment = function(name, basePath, explicit, callback) {

lib/less/environment/abstract-file-manager.js

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, ba
7676

7777
var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
7878
urlParts = url.match(urlPartsRegex),
79-
returner = {}, directories = [], i, baseUrlParts;
79+
returner = {}, rawDirectories = [], directories = [], i, d, baseUrlParts;
8080

8181
if (!urlParts) {
8282
throw new Error("Could not parse sheet href - '" + url + "'");
@@ -95,26 +95,25 @@ abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, ba
9595
}
9696

9797
if (urlParts[3]) {
98-
directories = urlParts[3].replace(/\\/g, "/").split("/");
98+
rawDirectories = urlParts[3].replace(/\\/g, "/").split("/");
9999

100-
// extract out . before .. so .. doesn't absorb a non-directory
101-
for (i = 0; i < directories.length; i++) {
102-
if (directories[i] === ".") {
103-
directories.splice(i, 1);
104-
i -= 1;
105-
}
106-
}
100+
// collapse '..' and skip '.'
101+
for (d = 0, i = 0; i < rawDirectories.length; i++) {
107102

108-
for (i = 0; i < directories.length; i++) {
109-
if (directories[i] === ".." && i > 0) {
110-
directories.splice(i - 1, 2);
111-
i -= 2;
103+
if (rawDirectories[i] === ".." && d > 0) {
104+
d -= 1;
105+
}
106+
else if (rawDirectories[i] !== ".") {
107+
directories[d] = rawDirectories[i];
108+
d++;
112109
}
110+
113111
}
114112
}
115113

116114
returner.hostPart = urlParts[1];
117115
returner.directories = directories;
116+
returner.rawPath = (urlParts[1] || "") + rawDirectories.join("/");
118117
returner.path = (urlParts[1] || "") + directories.join("/");
119118
returner.filename = urlParts[4];
120119
returner.fileUrl = returner.path + (urlParts[4] || "");

0 commit comments

Comments
 (0)