Skip to content
This repository was archived by the owner on Aug 15, 2024. It is now read-only.

Commit 3620200

Browse files
committed
added readlink, normalize and join
with test cases
1 parent d784408 commit 3620200

File tree

4 files changed

+204
-10
lines changed

4 files changed

+204
-10
lines changed

lib/MemoryFileSystem.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Author Tobias Koppers @sokra
44
*/
55

6-
var normalize = require('path').normalize;
6+
var normalize = require("./normalize");
77

88
function MemoryFileSystem(data) {
99
this.data = data || {};
@@ -161,6 +161,10 @@ MemoryFileSystem.prototype.unlinkSync = function(_path) {
161161
return this._remove(_path, "File", isFile);
162162
};
163163

164+
MemoryFileSystem.prototype.readlinkSync = function(_path) {
165+
throw new Error("Path is not a link '" + _path + "'");
166+
};
167+
164168
MemoryFileSystem.prototype.writeFileSync = function(_path, content, encoding) {
165169
if(!content && !encoding) throw new Error("No content");
166170
var path = pathToArray(_path);
@@ -177,15 +181,13 @@ MemoryFileSystem.prototype.writeFileSync = function(_path, content, encoding) {
177181
return;
178182
};
179183

180-
MemoryFileSystem.prototype.join = function(a, b) {
181-
if(a[a.length-1] === "/") return a + b;
182-
if(a[a.length-1] === "\\") return a + b;
183-
return a + "/" + b;
184-
};
184+
MemoryFileSystem.prototype.join = require("./join");
185+
186+
MemoryFileSystem.prototype.normalize = normalize;
185187

186188
// async functions
187189

188-
["stat", "readdir", "mkdirp", "mkdir", "rmdir", "unlink"].forEach(function(fn) {
190+
["stat", "readdir", "mkdirp", "mkdir", "rmdir", "unlink", "readlink"].forEach(function(fn) {
189191
MemoryFileSystem.prototype[fn] = function(path, callback) {
190192
try {
191193
var result = this[fn + "Sync"](path);

lib/join.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
var normalize = require("./normalize");
2+
3+
var absoluteWinRegExp = /^[A-Z]:([\\\/]|$)/i;
4+
var absoluteNixRegExp = /^\//i;
5+
6+
module.exports = function join(path, request) {
7+
if(request == "") return normalize(path);
8+
if(absoluteWinRegExp.test(request)) return normalize(request.replace(/\//g, "\\"));
9+
if(absoluteNixRegExp.test(request)) return normalize(request);
10+
if(path == "/") return normalize(path + request);
11+
if(absoluteWinRegExp.test(path)) return normalize(path + "\\" + request.replace(/\//g, "\\"));
12+
if(absoluteNixRegExp.test(path)) return normalize(path + "/" + request);
13+
return normalize(path + "/" + request);
14+
};

lib/normalize.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
var doubleSlashWinRegExp = /\\+/g;
2+
var doubleSlashNixRegExp = /\/+/g;
3+
var currentDirectoryWinMiddleRegExp = /\\(\.\\)+/;
4+
var currentDirectoryWinEndRegExp = /\\\.$/;
5+
var parentDirectoryWinMiddleRegExp = /\\+[^\\]+\\+\.\.\\/;
6+
var parentDirectoryWinEndRegExp1 = /([A-Z]:\\)\\*[^\\]+\\+\.\.$/i;
7+
var parentDirectoryWinEndRegExp2 = /\\+[^\\]+\\+\.\.$/;
8+
var currentDirectoryNixMiddleRegExp = /\/+(\.\/)+/;
9+
var currentDirectoryNixEndRegExp1 = /^\/+\.$/;
10+
var currentDirectoryNixEndRegExp2 = /\/+\.$/;
11+
var parentDirectoryNixMiddleRegExp = /(^|\/[^\/]+)\/+\.\.\/+/;
12+
var parentDirectoryNixEndRegExp1 = /^\/[^\/]+\/+\.\.$/;
13+
var parentDirectoryNixEndRegExp2 = /\/+[^\/]+\/+\.\.$/;
14+
var parentDirectoryNixEndRegExp3 = /^\/+\.\.$/;
15+
16+
// RegExp magic :)
17+
18+
module.exports = function normalize(path) {
19+
while(currentDirectoryWinMiddleRegExp.test(path))
20+
path = path.replace(currentDirectoryWinMiddleRegExp, "\\");
21+
path = path.replace(currentDirectoryWinEndRegExp, "");
22+
while(parentDirectoryWinMiddleRegExp.test(path))
23+
path = path.replace(parentDirectoryWinMiddleRegExp, "\\");
24+
path = path.replace(parentDirectoryWinEndRegExp1, "$1");
25+
path = path.replace(parentDirectoryWinEndRegExp2, "");
26+
27+
while(currentDirectoryNixMiddleRegExp.test(path))
28+
path = path.replace(currentDirectoryNixMiddleRegExp, "/");
29+
path = path.replace(currentDirectoryNixEndRegExp1, "/");
30+
path = path.replace(currentDirectoryNixEndRegExp2, "");
31+
while(parentDirectoryNixMiddleRegExp.test(path))
32+
path = path.replace(parentDirectoryNixMiddleRegExp, "/");
33+
path = path.replace(parentDirectoryNixEndRegExp1, "/");
34+
path = path.replace(parentDirectoryNixEndRegExp2, "");
35+
path = path.replace(parentDirectoryNixEndRegExp3, "/");
36+
37+
return path.replace(doubleSlashWinRegExp, "\\").replace(doubleSlashNixRegExp, "/");
38+
};

test/MemoryFileSystem.js

Lines changed: 143 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,25 @@ describe("errors", function() {
171171
}).should.throw();
172172
fs.readdirSync("/test/").should.be.eql(["dir", "file"]);
173173
});
174+
it("should throw on readlink", function() {
175+
var fs = new MemoryFileSystem();
176+
fs.mkdirpSync("/test/dir");
177+
(function() {
178+
fs.readlinkSync("/");
179+
}).should.throw();
180+
(function() {
181+
fs.readlinkSync("/link");
182+
}).should.throw();
183+
(function() {
184+
fs.readlinkSync("/test");
185+
}).should.throw();
186+
(function() {
187+
fs.readlinkSync("/test/dir");
188+
}).should.throw();
189+
(function() {
190+
fs.readlinkSync("/test/dir/link");
191+
}).should.throw();
192+
});
174193
});
175194
describe("async", function() {
176195
it("should be able to use the async versions", function(done) {
@@ -205,18 +224,139 @@ describe("async", function() {
205224
});
206225
});
207226
});
227+
describe("normalize", function() {
228+
it("should normalize paths", function() {
229+
var fs = new MemoryFileSystem();
230+
fs.normalize("/a/b/c").should.be.eql("/a/b/c");
231+
fs.normalize("/a//b/c").should.be.eql("/a/b/c");
232+
fs.normalize("/a//b//c").should.be.eql("/a/b/c");
233+
fs.normalize("//a//b//c").should.be.eql("/a/b/c");
234+
fs.normalize("/a/////b/c").should.be.eql("/a/b/c");
235+
fs.normalize("/./a/d///..////b/c").should.be.eql("/a/b/c");
236+
fs.normalize("/..").should.be.eql("/");
237+
fs.normalize("/.").should.be.eql("/");
238+
fs.normalize("/.git").should.be.eql("/.git");
239+
fs.normalize("/a/b/c/.git").should.be.eql("/a/b/c/.git");
240+
fs.normalize("/a/b/c/..git").should.be.eql("/a/b/c/..git");
241+
fs.normalize("/a/b/c/..").should.be.eql("/a/b");
242+
fs.normalize("/a/b/c/../..").should.be.eql("/a");
243+
fs.normalize("/a/b/c/../../..").should.be.eql("/");
244+
fs.normalize("C:\\a\\..").should.be.eql("C:\\");
245+
fs.normalize("C:\\a\\b\\..").should.be.eql("C:\\a");
246+
fs.normalize("C:\\a\\b\\\c\\..\\..").should.be.eql("C:\\a");
247+
fs.normalize("C:\\a\\b\\d\\..\\c\\..\\..").should.be.eql("C:\\a");
248+
fs.normalize("C:\\a\\b\\d\\\\.\\\\.\\c\\.\\..").should.be.eql("C:\\a\\b\\d");
249+
});
250+
});
208251
describe("join", function() {
209252
it("should join paths", function() {
210253
var fs = new MemoryFileSystem();
211254
fs.join("/", "a/b/c").should.be.eql("/a/b/c");
212255
fs.join("/a", "b/c").should.be.eql("/a/b/c");
213256
fs.join("/a/b", "c").should.be.eql("/a/b/c");
214257
fs.join("/a/", "b/c").should.be.eql("/a/b/c");
215-
fs.join("/a//", "b/c").should.be.eql("/a//b/c");
258+
fs.join("/a//", "b/c").should.be.eql("/a/b/c");
216259
fs.join("a", "b/c").should.be.eql("a/b/c");
217260
fs.join("a/b", "c").should.be.eql("a/b/c");
218-
fs.join("C:", "a/b").should.be.eql("C:/a/b");
219-
fs.join("C:\\", "a/b").should.be.eql("C:\\a/b");
261+
fs.join("C:", "a/b").should.be.eql("C:\\a\\b");
262+
fs.join("C:\\", "a/b").should.be.eql("C:\\a\\b");
220263
fs.join("C:\\", "a\\b").should.be.eql("C:\\a\\b");
221264
});
265+
it("should join paths (weird cases)", function() {
266+
var fs = new MemoryFileSystem();
267+
fs.join("/", "").should.be.eql("/");
268+
fs.join("/a/b/", "").should.be.eql("/a/b/");
269+
fs.join("/a/b/c", "").should.be.eql("/a/b/c");
270+
fs.join("C:", "").should.be.eql("C:");
271+
fs.join("C:\\a\\b", "").should.be.eql("C:\\a\\b");
272+
});
273+
it("should join paths (absolute request)", function() {
274+
var fs = new MemoryFileSystem();
275+
fs.join("/a/b/c", "/d/e/f").should.be.eql("/d/e/f");
276+
fs.join("C:\\a\\b\\c", "/d/e/f").should.be.eql("/d/e/f");
277+
fs.join("/a/b/c", "C:\\d\\e\\f").should.be.eql("C:\\d\\e\\f");
278+
fs.join("C:\\a\\b\\c", "C:\\d\\e\\f").should.be.eql("C:\\d\\e\\f");
279+
});
280+
});
281+
describe("os", function() {
282+
var fileSystem;
283+
284+
beforeEach(function() {
285+
fileSystem = new MemoryFileSystem({
286+
"": true,
287+
a: {
288+
"": true,
289+
index: new Buffer("1"), // /a/index
290+
dir: {
291+
"": true,
292+
index: new Buffer("2") // /a/dir/index
293+
}
294+
},
295+
"C:": {
296+
"": true,
297+
a: {
298+
"": true,
299+
index: new Buffer("3"), // C:\files\index
300+
dir: {
301+
"": true,
302+
index: new Buffer("4") // C:\files\a\index
303+
}
304+
}
305+
}
306+
});
307+
});
308+
309+
describe("unix", function() {
310+
it("should stat stuff", function() {
311+
fileSystem.statSync("/a").isDirectory().should.be.eql(true);
312+
fileSystem.statSync("/a").isFile().should.be.eql(false);
313+
fileSystem.statSync("/a/index").isDirectory().should.be.eql(false);
314+
fileSystem.statSync("/a/index").isFile().should.be.eql(true);
315+
fileSystem.statSync("/a/dir").isDirectory().should.be.eql(true);
316+
fileSystem.statSync("/a/dir").isFile().should.be.eql(false);
317+
fileSystem.statSync("/a/dir/index").isDirectory().should.be.eql(false);
318+
fileSystem.statSync("/a/dir/index").isFile().should.be.eql(true);
319+
});
320+
it("should readdir directories", function() {
321+
fileSystem.readdirSync("/a").should.be.eql(["index", "dir"]);
322+
fileSystem.readdirSync("/a/dir").should.be.eql(["index"]);
323+
});
324+
it("should readdir directories", function() {
325+
fileSystem.readFileSync("/a/index", "utf-8").should.be.eql("1");
326+
fileSystem.readFileSync("/a/dir/index", "utf-8").should.be.eql("2");
327+
});
328+
it("should also accept multi slashs", function() {
329+
fileSystem.statSync("/a///dir//index").isFile().should.be.eql(true);
330+
});
331+
});
332+
333+
describe("windows", function() {
334+
it("should stat stuff", function() {
335+
fileSystem.statSync("C:\\a").isDirectory().should.be.eql(true);
336+
fileSystem.statSync("C:\\a").isFile().should.be.eql(false);
337+
fileSystem.statSync("C:\\a\\index").isDirectory().should.be.eql(false);
338+
fileSystem.statSync("C:\\a\\index").isFile().should.be.eql(true);
339+
fileSystem.statSync("C:\\a\\dir").isDirectory().should.be.eql(true);
340+
fileSystem.statSync("C:\\a\\dir").isFile().should.be.eql(false);
341+
fileSystem.statSync("C:\\a\\dir\\index").isDirectory().should.be.eql(false);
342+
fileSystem.statSync("C:\\a\\dir\\index").isFile().should.be.eql(true);
343+
});
344+
it("should readdir directories", function() {
345+
fileSystem.readdirSync("C:\\a").should.be.eql(["index", "dir"]);
346+
fileSystem.readdirSync("C:\\a\\dir").should.be.eql(["index"]);
347+
});
348+
it("should readdir directories", function() {
349+
fileSystem.readFileSync("C:\\a\\index", "utf-8").should.be.eql("3");
350+
fileSystem.readFileSync("C:\\a\\dir\\index", "utf-8").should.be.eql("4");
351+
});
352+
it("should also accept multi slashs", function() {
353+
fileSystem.statSync("C:\\\\a\\\\\\dir\\\\index").isFile().should.be.eql(true);
354+
});
355+
it("should also accept a normal slash", function() {
356+
fileSystem.statSync("C:\\a\\dir/index").isFile().should.be.eql(true);
357+
fileSystem.statSync("C:\\a\\dir\\index").isFile().should.be.eql(true);
358+
fileSystem.statSync("C:\\a/dir/index").isFile().should.be.eql(true);
359+
fileSystem.statSync("C:\\a/dir\\index").isFile().should.be.eql(true);
360+
});
361+
});
222362
});

0 commit comments

Comments
 (0)