1 | (function (require, exports) {
|
2 |
|
3 | var Q = require("qq");
|
4 | var BOOT = require("fs-boot");
|
5 | var FS = require("./q-fs");
|
6 | var COMMON = require("./common");
|
7 |
|
8 | var Fs = exports.Fs = function (files) {
|
9 | var fs = Object.create(BOOT);
|
10 | var root = {};
|
11 | var now = new Date();
|
12 |
|
13 | function init() {
|
14 |
|
15 | Object.keys(files).forEach(function (path) {
|
16 | var content = files[path];
|
17 | find(root, path).set(content);
|
18 | });
|
19 | }
|
20 |
|
21 | function find(at, path) {
|
22 | path = fs.absolute(path);
|
23 | if (path === "" || path === FS.ROOT) {
|
24 | return Node(function get() {
|
25 | return root;
|
26 | }, function set(content) {
|
27 | root = content;
|
28 | });
|
29 | }
|
30 | var parts = FS.split(path);
|
31 | var empty = parts.shift();
|
32 | if (empty !== "")
|
33 | throw new Error("assertion: first component of root should be empty");
|
34 | var i, ii;
|
35 | var manifest = function () {};
|
36 | for (i = 0, ii = parts.length - 1; i < ii; i++) {
|
37 | var part = parts[i];
|
38 | if (part === ".") {
|
39 | continue;
|
40 | } if (typeof at[part] !== "object") {
|
41 | manifest = (function (on, part, manifest) {
|
42 | var created = {};
|
43 | at = created;
|
44 | return function () {
|
45 | on[part] = created;
|
46 | manifest();
|
47 | };
|
48 | })(at, part, manifest);
|
49 | } else {
|
50 | at = at[part];
|
51 | }
|
52 | }
|
53 | var leaf = parts[i];
|
54 | return Node(function get() {
|
55 | return at[leaf];
|
56 | }, function set(content) {
|
57 | manifest();
|
58 | at[leaf] = content;
|
59 | });
|
60 | }
|
61 |
|
62 | fs.list = function (path) {
|
63 | path = String(path);
|
64 | return Q.when(fs.stat(path), function (stat) {
|
65 | if (!stat.isDirectory())
|
66 | throw new Error("Can't list non-directory " + path);
|
67 | var node = find(root, path).get();
|
68 | return Object.keys(node);
|
69 | });
|
70 | };
|
71 |
|
72 | fs.open = function (path, flags, charset, options) {
|
73 | if (typeof flags == "object") {
|
74 | options = flags;
|
75 | flags = options.flags;
|
76 | charset = options.charset;
|
77 | } else {
|
78 | options = options || {};
|
79 | }
|
80 | var node = find(root, path);
|
81 |
|
82 |
|
83 | flags = flags || "r";
|
84 | var binary = flags.indexOf("b") >= 0;
|
85 | charset = charset || "utf-8";
|
86 | var stat = fs.stat(path);
|
87 | var isFile = Q.post(stat, 'isFile');
|
88 | return Q.when(isFile, function (isFile) {
|
89 | if (!isFile) {
|
90 | throw new Error("Can't open non-file " + path);
|
91 | }
|
92 | return {
|
93 | "read": function () {
|
94 | var content = node.get();
|
95 | if (!binary)
|
96 | content = content.toString(charset);
|
97 | return content;
|
98 | }
|
99 | };
|
100 | });
|
101 | };
|
102 |
|
103 | fs.stat = function (path) {
|
104 | var stat = find(root, path);
|
105 | if (stat.get() === undefined)
|
106 | return Q.reject("No such file: " + path);
|
107 | return stat;
|
108 | };
|
109 |
|
110 | fs.getNode = function (path) {
|
111 | path = path || "";
|
112 | return find(root, path).get();
|
113 | };
|
114 |
|
115 | fs.canonical = function (path) {
|
116 | return fs.normal(path);
|
117 | };
|
118 |
|
119 | var Node = function (get, set) {
|
120 | var self = Object.create(Node.prototype);
|
121 | self.get = get;
|
122 | self.set = set;
|
123 | return self;
|
124 | };
|
125 |
|
126 | Node.prototype = Object.create(GenericNode.prototype);
|
127 |
|
128 | Node.prototype.constructor = Node;
|
129 |
|
130 | Node.prototype.lastModified = function () {
|
131 | return now;
|
132 | };
|
133 |
|
134 | COMMON.update(fs, function () {
|
135 | return fs.ROOT;
|
136 | });
|
137 |
|
138 | init();
|
139 |
|
140 | return fs;
|
141 | };
|
142 |
|
143 | var GenericNode = function () {};
|
144 |
|
145 | GenericNode.prototype.exists = function () {
|
146 | var node = this.get();
|
147 | return typeof node !== "undefined";
|
148 | };
|
149 |
|
150 | GenericNode.prototype.isFile = function () {
|
151 | var node = this.get();
|
152 | return typeof node !== "undefined" && (
|
153 | typeof node !== "object" ||
|
154 | node.constructor !== Object
|
155 | );
|
156 | };
|
157 |
|
158 | GenericNode.prototype.isDirectory = function () {
|
159 | var node = this.get();
|
160 | return (
|
161 | typeof node === "object" &&
|
162 | node.constructor === Object
|
163 | )
|
164 | };
|
165 |
|
166 | exports.mock = function (fs, root) {
|
167 | return Q.when(fs.listTree(root), function (list) {
|
168 | var tree = {};
|
169 | var done;
|
170 | list.forEach(function (path) {
|
171 | var actual = fs.join(root, path);
|
172 | var relative = fs.relativeFromDirectory(root, actual);
|
173 | var partial = Q.when(fs.stat(actual), function (stat) {
|
174 | if (stat.isFile()) {
|
175 | tree[relative] = fs.read(path, "rb");
|
176 | }
|
177 | });
|
178 | done = Q.when(done, function () {
|
179 | return partial;
|
180 | });
|
181 | });
|
182 | return Q.when(done, function () {
|
183 | return Q.when(Q.shallow(tree), Fs);
|
184 | });
|
185 | });
|
186 | };
|
187 |
|
188 | }).apply(null, typeof exports !== "undefined" ?
|
189 | [require, exports] :
|
190 | [
|
191 | function (id) {
|
192 | id = id.toUpperCase()
|
193 | .replace(".", "Q_FS")
|
194 | .replace("/", "$")
|
195 | .replace("-", "_");
|
196 | return window[id];
|
197 | },
|
198 | Q_FS$MOCK
|
199 | ]
|
200 | )
|