UNPKG

12.2 kBJavaScriptView Raw
1(function (require, exports) {
2
3var Q = require("qq");
4var FS_BOOT = require("fs-boot");
5var ROOT = require("./root");
6var MOCK = require("./mock");
7
8// TODO patternToRegExp
9// TODO glob
10// TODO match
11// TODO copyTree
12
13var concat = function (arrays) {
14 return Array.prototype.concat.apply([], arrays);
15};
16
17exports.update = function (exports, workingDirectory) {
18
19 for (var name in FS_BOOT)
20 exports[name] = FS_BOOT[name];
21
22 /**
23 * @param {String} path
24 * @param {Object} options
25 * @returns {Promise * (String || Buffer)}
26 */
27 exports.read = function (path, flags, charset, options) {
28 if (typeof flags == "object") {
29 options = flags;
30 } else {
31 options = options || {};
32 options.flags = flags;
33 options.carset = charset;
34 }
35 options.flags = "r" + (options.flags || "").replace(/r/g, "");
36 return Q.when(exports.open(path, options), function (stream) {
37 return stream.read();
38 }, function (reason) {
39 var message = "Can't read " + path;
40 return Q.reject({
41 "toString": function () {
42 return JSON.stringify(this);
43 },
44 "message": message,
45 "path": path,
46 "flags": flags,
47 "charset": charset,
48 "cause": reason,
49 "stack": new Error(message).stack
50 });
51 });
52 };
53
54 /**
55 * @param {String} path
56 * @param {String || Buffer} content
57 * @param {Object} options
58 * @returns {Promise * Undefined} a promise that resolves
59 * when the writing is complete.
60 */
61 exports.write = function (path, content, flags, charset, options) {
62 if (typeof flags == "object") {
63 options = flags;
64 } else {
65 options = options || {};
66 options.flags = flags;
67 options.carset = charset;
68 }
69 options.flags = "w" + (options.flags || "").replace(/w/g, "");
70 return Q.when(exports.open(path, options), function (stream) {
71 return Q.when(stream.write(content), function () {
72 return stream.close();
73 });
74 });
75 };
76
77 // TODO append
78 exports.append = function (path, content, flags, charset, options) {
79 if (typeof flags == "object") {
80 options = flags;
81 } else {
82 options = options || {};
83 options.flags = flags;
84 options.carset = charset;
85 }
86 options.flags = "w+" + (options.flags || "").replace(/[w\+]/g, "");
87 return Q.when(exports.open(path, options), function (stream) {
88 return Q.when(stream.write(content), function () {
89 return stream.close();
90 });
91 });
92 };
93
94 // TODO copy
95
96 /**
97 */
98 exports.listTree = function (basePath, guard) {
99 basePath = String(basePath || '');
100 if (!basePath)
101 basePath = ".";
102 guard = guard || function () {
103 return true;
104 };
105 var stat = exports.stat(basePath);
106 return Q.Lazy(Array, Q.when(stat, function (stat) {
107 var paths = [];
108 var mode; // true:include, false:exclude, null:no-recur
109 try {
110 var include = guard(basePath, stat);
111 } catch (exception) {
112 return Q.reject(exception);
113 }
114 return Q.when(include, function (include) {
115 if (include) {
116 paths.push([basePath]);
117 }
118 if (include !== null && stat.isDirectory()) {
119 return Q.when(exports.list(basePath), function (children) {
120 paths.push.apply(paths, children.map(function (child) {
121 var path = exports.join(basePath, child);
122 return exports.listTree(path, guard);
123 }));
124 return paths;
125 });
126 } else {
127 return paths;
128 }
129 });
130 }, function noSuchFile(reason) {
131 return [];
132 }).then(Q.shallow).then(concat));
133 };
134
135 exports.listDirectoryTree = function (path) {
136 return exports.listTree(path, function (path, stat) {
137 return stat.isDirectory();
138 });
139 };
140
141 exports.makeTree = function (path, mode) {
142 var parts = exports.split(path);
143 var at = [];
144 if (exports.isAbsolute(path))
145 at.push(exports.ROOT);
146 return parts.reduce(function (parent, part) {
147 return Q.when(parent, function () {
148 at.push(part);
149 var parts = exports.join(at);
150 var made = exports.makeDirectory(parts, mode);
151 return Q.when(made, null, function rejected(reason) {
152 // throw away errors for already made directories
153 if (reason.code == "EEXIST") {
154 return;
155 } else {
156 return Q.reject(reason);
157 }
158 });
159 });
160 }, undefined);
161 };
162
163 exports.removeTree = function (path) {
164 return Q.when(exports.stat(path), function (stat) {
165 if (stat.isLink()) {
166 return exports.remove(path);
167 } else if (stat.isDirectory()) {
168 var list = exports.list(path);
169 return Q.when(list, function (list) {
170 // asynchronously remove every subtree
171 var done = list.reduce(function (prev, name) {
172 var child = exports.join(path, name);
173 var next = exports.removeTree(child);
174 // join next and prev
175 return Q.when(prev, function () {
176 return next;
177 });
178 });
179 return Q.when(done, function () {
180 exports.removeDirectory(path);
181 });
182 });
183 } else {
184 return exports.remove(path);
185 }
186 });
187 };
188
189 exports.exists = function (path) {
190 return Q.when(exports.stat(path), function () {
191 return true;
192 }, function () {
193 return false;
194 });
195 };
196
197 exports.isFile = function (path) {
198 return Q.when(exports.stat(path), function (stat) {
199 return stat.isFile();
200 }, function (reason) {
201 return false;
202 });
203 };
204
205 exports.isDirectory = function (path) {
206 return Q.when(exports.stat(path), function (stat) {
207 return stat.isDirectory();
208 }, function (reason) {
209 return false;
210 });
211 };
212
213 exports.absolute = function (path) {
214 if (exports.isAbsolute(path))
215 return path;
216 return exports.join(workingDirectory(), path);
217 };
218
219 exports.relative = function (source, target) {
220 return Q.when(exports.isDirectory(source), function (isDirectory) {
221 if (isDirectory) {
222 return exports.relativeFromDirectory(source, target);
223 } else {
224 return exports.relativeFromFile(source, target);
225 }
226 });
227 };
228
229 exports.relativeFromFile = function (source, target) {
230 source = exports.absolute(source);
231 target = exports.absolute(target);
232 source = source.split(exports.SEPARATORS_RE());
233 target = target.split(exports.SEPARATORS_RE());
234 source.pop();
235 while (
236 source.length &&
237 target.length &&
238 target[0] == source[0]
239 ) {
240 source.shift();
241 target.shift();
242 }
243 while (source.length) {
244 source.shift();
245 target.unshift("..");
246 }
247 return target.join(exports.SEPARATOR);
248 };
249
250 exports.relativeFromDirectory = function (source, target) {
251 if (!target) {
252 target = source;
253 source = workingDirectory();
254 }
255 source = exports.absolute(source);
256 target = exports.absolute(target);
257 source = source.split(exports.SEPARATORS_RE());
258 target = target.split(exports.SEPARATORS_RE());
259 if (source.length === 2 && source[1] === "")
260 source.pop();
261 while (
262 source.length &&
263 target.length &&
264 target[0] == source[0]
265 ) {
266 source.shift();
267 target.shift();
268 }
269 while (source.length) {
270 source.shift();
271 target.unshift("..");
272 }
273 return target.join(exports.SEPARATOR);
274 };
275
276 exports.contains = function (parent, child) {
277 var i, ii;
278 parent = exports.absolute(parent);
279 child = exports.absolute(child);
280 parent = parent.split(exports.SEPARATORS_RE());
281 child = child.split(exports.SEPARATORS_RE());
282 if (parent.length === 2 && parent[1] === "")
283 parent.pop();
284 if (parent.length > child.length)
285 return false;
286 for (i = 0, ii = parent.length; i < ii; i++) {
287 if (parent[i] !== child[i])
288 break;
289 }
290 return i == ii;
291 };
292
293 exports.reroot = reroot;
294 function reroot(path) {
295 path = path || exports.ROOT;
296 return Q.when(exports.list(path), function (list) {
297 if (list.length !== 1)
298 return ROOT.Fs(exports, path);
299 var nextPath = exports.join(path, list[0]);
300 return Q.when(exports.stat(nextPath), function (stat) {
301 if (stat.isDirectory()) {
302 return reroot(nextPath);
303 } else {
304 return ROOT.Fs(exports, path);
305 }
306 });
307 });
308 }
309
310 exports.toObject = function (path) {
311 var list = exports.listTree(path || "", function (path, stat) {
312 return stat.isFile();
313 });
314 return Q.when(list, function (list) {
315 var tree = {};
316 var done;
317 list.forEach(function (path) {
318 tree[path] = exports.read(path, "rb");
319 });
320 return Q.when(done, function () {
321 return Q.shallow(tree);
322 });
323 });
324 };
325
326 exports.merge = function (fss) {
327 var tree = {};
328 var done;
329 fss.forEach(function (fs) {
330 // fetch lists in parallel
331 var list = fs.listTree("", function (path, stat) {
332 return stat.isFile();
333 });
334 // merge each fs serially
335 done = Q.when(done, function () {
336 return Q.when(list, function (list) {
337 list.forEach(function (path) {
338 tree[path] = fs.read(path, "rb");
339 });
340 });
341 });
342 });
343 return Q.when(done, function () {
344 return Q.when(Q.shallow(tree), MOCK.Fs);
345 });
346 };
347
348 var stats = [
349 "isDirectory",
350 "isFile",
351 "isBlockDevice",
352 "isCharacterDevice",
353 "isSymbolicLink",
354 "isFIFO",
355 "isSocket"
356 ];
357
358 var Stats = exports.Stats = function (copy) {
359 var self = Object.create(copy);
360 stats.forEach(function (name) {
361 if (copy["_" + name] !== undefined) {
362 self["_" + name] = copy["_" + name];
363 } else {
364 self["_" + name] = copy[name]();
365 }
366 });
367 return self;
368 };
369
370 stats.forEach(function (name) {
371 Stats.prototype[name] = function () {
372 return this["_" + name];
373 };
374 });
375
376}
377
378}).apply(null, typeof exports !== "undefined" ?
379 [require, exports] :
380 [
381 function (id) {
382 id = id.toUpperCase()
383 .replace(".", "Q_FS")
384 .replace("/", "$")
385 .replace("-", "_");
386 return window[id] = window[id] || {};
387 },
388 Q_FS$COMMON = {}
389 ]
390)