Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81159 views
1
var assert = require("assert");
2
var path = require("path");
3
var fs = require("graceful-fs");
4
var Q = require("q");
5
var createHash = require("crypto").createHash;
6
var mkdirp = require("mkdirp");
7
var iconv = require("iconv-lite");
8
var Ap = Array.prototype;
9
var slice = Ap.slice;
10
var join = Ap.join;
11
12
// The graceful-fs module attempts to limit the total number of open files
13
// by queueing fs operations, but it doesn't know about all open files, so
14
// we set the limit somewhat lower than the default to provide a healthy
15
// buffer against EMFILE (too many open files) errors.
16
fs.MAX_OPEN = 512;
17
18
function makePromise(callback, context) {
19
var deferred = Q.defer();
20
21
function finish(err, result) {
22
if (err) {
23
deferred.reject(err);
24
} else {
25
deferred.resolve(result);
26
}
27
}
28
29
process.nextTick(function() {
30
try {
31
callback.call(context || null, finish);
32
} catch (err) {
33
finish(err);
34
}
35
});
36
37
return deferred.promise;
38
}
39
exports.makePromise = makePromise;
40
41
exports.cachedMethod = function(fn, keyFn) {
42
var p = require("private").makeAccessor();
43
44
function wrapper() {
45
var priv = p(this);
46
var cache = priv.cache || (priv.cache = {});
47
var args = arguments;
48
var key = keyFn
49
? keyFn.apply(this, args)
50
: join.call(args, "\0");
51
return cache.hasOwnProperty(key)
52
? cache[key]
53
: cache[key] = fn.apply(this, args);
54
}
55
56
wrapper.originalFn = fn;
57
58
return wrapper;
59
};
60
61
function readFileP(file, charset) {
62
return makePromise(charset ? function(callback) {
63
return fs.readFile(file, function(err, data) {
64
if (err) {
65
callback(err);
66
} else {
67
callback(null, iconv.decode(data, charset));
68
}
69
});
70
} : function(callback) {
71
return fs.readFile(file, "utf8", callback);
72
});
73
}
74
exports.readFileP = readFileP;
75
76
exports.readJsonFileP = function(file) {
77
return readFileP(file).then(function(json) {
78
return JSON.parse(json);
79
});
80
};
81
82
function mkdirP(dir) {
83
return makePromise(function(callback) {
84
mkdirp(dir, function(err) {
85
callback(err, dir);
86
});
87
});
88
}
89
exports.mkdirP = mkdirP;
90
91
function readFromStdinP(timeLimit, message, color) {
92
var deferred = Q.defer();
93
var ins = [];
94
95
timeLimit = timeLimit || 1000;
96
var timeout = setTimeout(function() {
97
log.err(
98
message || ("Warning: still waiting for STDIN after " +
99
timeLimit + "ms"),
100
color || "yellow"
101
);
102
}, timeLimit);
103
104
try {
105
// On Windows, just accessing process.stdin throws an exception
106
// when no standard input has been provided. For consistency with
107
// other platforms, log the error but continue waiting (until
108
// killed) for the nonexistent input.
109
var stdin = process.stdin;
110
} catch (err) {
111
log.err(err);
112
}
113
114
if (stdin) {
115
stdin.resume();
116
stdin.setEncoding("utf8");
117
118
stdin.on("data", function(data) {
119
ins.push(data);
120
}).on("end", function() {
121
clearTimeout(timeout);
122
deferred.resolve(ins.join(""));
123
});
124
}
125
126
return deferred.promise;
127
}
128
exports.readFromStdinP = readFromStdinP;
129
130
exports.readJsonFromStdinP = function(timeLimit) {
131
return readFromStdinP(timeLimit).then(function(input) {
132
return JSON.parse(input);
133
});
134
};
135
136
function deepHash(val) {
137
var hash = createHash("sha1");
138
var type = typeof val;
139
140
if (val === null) {
141
type = "null";
142
}
143
144
switch (type) {
145
case "object":
146
Object.keys(val).sort().forEach(function(key) {
147
if (typeof val[key] === "function") {
148
// Silently ignore nested methods, but nevertheless
149
// complain below if the root value is a function.
150
return;
151
}
152
153
hash.update(key + "\0")
154
.update(deepHash(val[key]));
155
});
156
break;
157
158
case "function":
159
assert.ok(false, "cannot hash function objects");
160
break;
161
162
default:
163
hash.update(val + "");
164
break;
165
}
166
167
return hash.digest("hex");
168
}
169
exports.deepHash = deepHash;
170
171
exports.existsP = function(fullPath) {
172
return makePromise(function(callback) {
173
fs.exists(fullPath, function(exists) {
174
callback(null, exists);
175
});
176
});
177
};
178
179
function writeFdP(fd, content) {
180
return makePromise(function(callback) {
181
content += "";
182
var buffer = new Buffer(content, "utf8");
183
var length = fs.writeSync(fd, buffer, 0, buffer.length, null);
184
assert.strictEqual(length, buffer.length);
185
callback(null, content);
186
}).finally(function() {
187
fs.closeSync(fd);
188
});
189
}
190
exports.writeFdP = writeFdP;
191
192
function openFileP(file, mode) {
193
return makePromise(function(callback) {
194
fs.open(file, mode || "w+", callback);
195
});
196
}
197
exports.openFileP = openFileP;
198
199
function openExclusiveP(file) {
200
// The 'x' in "wx+" means the file must be newly created.
201
return openFileP(file, "wx+");
202
}
203
exports.openExclusiveP = openExclusiveP;
204
205
exports.copyP = function(srcFile, dstFile) {
206
return makePromise(function(callback) {
207
var reader = fs.createReadStream(srcFile);
208
209
function onError(err) {
210
callback(err || new Error(
211
"error in util.copyP(" +
212
JSON.stringify(srcFile) + ", " +
213
JSON.stringify(dstFile) + ")"
214
));
215
}
216
217
reader.on("error", onError).pipe(
218
fs.createWriteStream(dstFile)
219
).on("finish", function() {
220
callback(null, dstFile);
221
}).on("error", onError);
222
});
223
};
224
225
// Even though they use synchronous operations to avoid race conditions,
226
// linkP and unlinkP have promise interfaces, for consistency. Note that
227
// this means the operation will not happen until at least the next tick
228
// of the event loop, but it will be atomic when it happens.
229
exports.linkP = function(srcFile, dstFile) {
230
return mkdirP(path.dirname(dstFile)).then(function() {
231
if (fs.existsSync(dstFile))
232
fs.unlinkSync(dstFile);
233
fs.linkSync(srcFile, dstFile);
234
return dstFile;
235
});
236
};
237
238
exports.unlinkP = function(file) {
239
return makePromise(function(callback) {
240
try {
241
if (fs.existsSync(file))
242
fs.unlinkSync(file);
243
callback(null, file);
244
} catch (err) {
245
callback(err);
246
}
247
});
248
};
249
250
var colors = {
251
bold: "\033[1m",
252
red: "\033[31m",
253
green: "\033[32m",
254
yellow: "\033[33m",
255
cyan: "\033[36m",
256
reset: "\033[0m"
257
};
258
259
Object.keys(colors).forEach(function(key) {
260
if (key !== "reset") {
261
exports[key] = function(text) {
262
return colors[key] + text + colors.reset;
263
};
264
}
265
});
266
267
var log = exports.log = {
268
out: function(text, color) {
269
text = (text + "").trim();
270
if (colors.hasOwnProperty(color))
271
text = colors[color] + text + colors.reset;
272
process.stdout.write(text + "\n");
273
},
274
275
err: function(text, color) {
276
text = (text + "").trim();
277
if (!colors.hasOwnProperty(color))
278
color = "red";
279
text = colors[color] + text + colors.reset;
280
process.stderr.write(text + "\n");
281
}
282
};
283
284
var slugExp = /[^a-z\-]/ig;
285
exports.idToSlug = function(id) {
286
return id.replace(slugExp, "_");
287
};
288
289
var moduleIdExp = /^[ a-z0-9\-_\/\.]+$/i;
290
exports.isValidModuleId = function(id) {
291
return id === "<stdin>" || moduleIdExp.test(id);
292
};
293
294
var objToStr = Object.prototype.toString;
295
var arrStr = objToStr.call([]);
296
297
function flatten(value, into) {
298
if (objToStr.call(value) === arrStr) {
299
into = into || [];
300
for (var i = 0, len = value.length; i < len; ++i)
301
if (i in value) // Skip holes.
302
flatten(value[i], into);
303
} else if (into) {
304
into.push(value);
305
} else {
306
return value;
307
}
308
309
return into;
310
};
311
exports.flatten = flatten;
312
313
exports.inherits = function(ctor, base) {
314
return ctor.prototype = Object.create(base.prototype, {
315
constructor: { value: ctor }
316
});
317
};
318
319
function absolutize(moduleId, requiredId) {
320
if (requiredId.charAt(0) === ".")
321
requiredId = path.join(moduleId, "..", requiredId);
322
return path.normalize(requiredId).replace(/\\/g, '/');
323
}
324
exports.absolutize = absolutize;
325
326
function relativize(moduleId, requiredId) {
327
requiredId = absolutize(moduleId, requiredId);
328
329
if (requiredId.charAt(0) === ".") {
330
// Keep the required ID relative.
331
} else {
332
// Relativize the required ID.
333
requiredId = path.relative(
334
path.join(moduleId, ".."),
335
requiredId
336
);
337
}
338
339
if (requiredId.charAt(0) !== ".")
340
requiredId = "./" + requiredId;
341
342
return requiredId.replace(/\\/g, '/');
343
}
344
exports.relativize = relativize;
345
346
function waitForValuesP(obj, makeCopy) {
347
if (typeof obj !== "object")
348
return Q(obj);
349
350
var result = makeCopy ? {} : obj;
351
var keys = Object.keys(obj);
352
if (keys.length === 0)
353
return Q(result);
354
355
return Q.all(keys.map(function(key) {
356
return obj[key];
357
})).then(function(values) {
358
for (var i = values.length - 1; i >= 0; --i)
359
result[keys[i]] = values[i];
360
return result;
361
});
362
}
363
exports.waitForValuesP = waitForValuesP;
364
365
function camelize(hyphenated) {
366
return hyphenated.replace(/-(.)/g, function(_, ch) {
367
return ch.toUpperCase();
368
});
369
}
370
exports.camelize = camelize;
371
372