UNPKG

5.74 kBJavaScriptView Raw
1var EventEmitter = require('events').EventEmitter;
2var rfs = require('fs');
3var path = require('path');
4
5module.exports = function walk (dir, opts, emitter, dstat) {
6 if (!opts) opts = {};
7 var fdir = opts._original || dir;
8 opts._original = undefined;
9 var fs = opts.fs || rfs;
10
11 if (!emitter) {
12 emitter = new EventEmitter;
13 emitter.stop = function () {
14 emitter._stopped = true;
15 emitter.emit('stop');
16 };
17 emitter._pending = 0;
18 emitter._seen = {};
19 }
20
21 if (dstat) {
22 var stopped = false;
23 emitter.emit('directory', fdir, dstat, function stop () {
24 stopped = true;
25 });
26 emitter.emit('path', fdir, dstat);
27 if (!stopped) {
28 emitter._pending ++;
29 fs.readdir(dir, function (err, files) {
30 emitter._pending --;
31 onreaddir(dir, err, files);
32 });
33 }
34 else check()
35 }
36 else {
37 emitter._pending ++;
38 fs.lstat(dir, function (err, stat) {
39 emitter._pending --;
40 onlstat(err, stat);
41 });
42 }
43 function onlstat (err, stat) {
44 if (emitter._stopped) return;
45
46 if (err) {
47 if (!err.path) err.path = dir;
48 emitter.emit('error', err);
49 return check();
50 }
51 emitter._seen[stat.ino || dir] = true;
52
53 if (stat.isSymbolicLink() && opts.followSymlinks) {
54 emitter.emit('link', fdir, stat);
55 emitter._pending ++;
56 fs.readlink(dir, function (err, rfile) {
57 if (emitter._stopped) return;
58 emitter._pending --;
59 if (err) {
60 if (!err.path) err.path = dir;
61 emitter.emit('error', err);
62 return check();
63 }
64 var file_ = path.resolve(dir, rfile);
65 emitter.emit('readlink', fdir, file_);
66 emitter._pending ++;
67 fs.lstat(file_, function (err, stat) {
68 emitter._pending --;
69 onstat(err, stat);
70 });
71 });
72 }
73 else if (stat.isSymbolicLink()) {
74 emitter.emit('link', fdir, stat);
75 emitter.emit('path', fdir, stat);
76 check();
77 }
78 else if (stat.isDirectory()) {
79 var stopped = false;
80 emitter.emit('directory', fdir, stat, function stop () {
81 stopped = true;
82 });
83 emitter.emit('path', fdir, stat);
84 if (!stopped) {
85 emitter._pending ++;
86 fs.readdir(dir, function (err, files) {
87 emitter._pending --;
88 onreaddir(dir, err, files);
89 });
90 }
91 else check()
92 }
93 else {
94 emitter.emit('file', fdir, stat);
95 emitter.emit('path', fdir, stat);
96 check();
97 }
98 }
99
100 return emitter;
101
102 function check () {
103 if (emitter._pending === 0) finish();
104 }
105
106 function finish () {
107 emitter.emit('end');
108 emitter._stopped = true;
109 }
110
111 function onreaddir (dir, err, files) {
112 if (emitter._stopped) return;
113
114 if (err) {
115 if (!err.path) err.path = dir;
116 emitter.emit('error', err);
117 return check();
118 }
119
120 files.forEach(function (rfile) {
121 var file = path.join(fdir, rfile);
122
123 emitter._pending ++;
124 fs.lstat(file, function (err, stat) {
125 emitter._pending --;
126
127 if (emitter._stopped) return;
128 if (err) {
129 if (!err.path) err.path = file;
130 emitter.emit('error', err);
131 check()
132 }
133 else onstat(file, stat)
134 });
135 });
136 check();
137 }
138
139 function onstat (file, stat, original) {
140 if (emitter._seen[stat.ino || file]) return check();
141 emitter._seen[stat.ino || file] = true;
142
143 if (stat.isDirectory()) {
144 if (original) opts._original = original;
145 walk(file, opts, emitter, stat);
146 check();
147 }
148 else if (stat.isSymbolicLink() && opts.followSymlinks) {
149 emitter.emit('link', file, stat);
150
151 fs.readlink(file, function (err, rfile) {
152 if (emitter._stopped) return;
153 if (err) {
154 if (!err.path) err.path = file;
155 emitter.emit('error', err);
156 return check();
157 }
158 var file_ = path.resolve(path.dirname(file), rfile);
159
160 emitter.emit('readlink', file, file_);
161 emitter._pending ++;
162 fs.lstat(file_, function (err, stat_) {
163 emitter._pending --;
164 if (emitter._stopped) return;
165 if (err) {
166 if (!err.path) err.path = file_;
167 emitter.emit('error', err);
168 return check();
169 }
170
171 onstat(file_, stat_, file);
172 check();
173 });
174 });
175 }
176 else if (stat.isSymbolicLink()) {
177 emitter.emit('link', file, stat);
178 emitter.emit('path', file, stat);
179 check();
180 }
181 else {
182 emitter.emit('file', file, stat);
183 emitter.emit('path', file, stat);
184 check();
185 }
186 }
187};