UNPKG

3.35 kBJavaScriptView Raw
1var fs = require('fs');
2
3/**
4 * read() : read(files, fn)
5 * Reads from files. If no files are given, read from stdin.
6 * The `err` argument will always be null, as errors will be part of `res`.
7 *
8 * var read = require('read');
9 * var fnames = process.argv.slice(2); //=> ['readme.txt']
10 *
11 * read(fnames, function (err, res) {
12 * res.data //=> '...'
13 * res.error //=> undefined | Error()
14 * res.stdin //=> true | false
15 * res.files //=> [...]
16 * });
17 *
18 * You can also iterate through `res.files`.
19 *
20 * read(fnames, function (err, res) {
21 * res.files.forEach(function (f) {
22 * f.data //=> ...
23 * f.error //=> undefined | Error(...)
24 * f.stdin //=> true | false
25 * f.name //=> 'readme.txt'
26 * }
27 * });
28 *
29 * If `files` is a blank array (or null), data will be read from stdin. The
30 * resulting data will have a similar schema.
31 *
32 * read([], function (err, res) {
33 * ...
34 * });
35 */
36
37function read (files, fn) {
38 // from stdin
39 if (!files || files.length === 0) {
40 read.stdin(function (err, data) {
41 if (err)
42 fn(null, new Result([{ stdin: true, error: err }]));
43 else
44 fn(null, new Result([{ stdin: true, data: data }]));
45 });
46 }
47 // from files
48 else {
49 var out = files.map(function (fname) {
50 try {
51 var data = fs.readFileSync(fname, 'utf-8');
52 return { name: fname, data: data };
53 } catch (err) {
54 return { name: fname, error: err };
55 }
56 });
57
58 out = new Result(out);
59 fn(null, out);
60 }
61}
62
63/**
64 * read.stdin() : read.stdin(fn)
65 * Read data from standard input. The `err` argument will always be null.
66 *
67 * read.stdin(function (err, data) {
68 * console.log(data); // string
69 * });
70 */
71
72read.stdin = function (fn) {
73 var data = '';
74
75 process.stdin.setEncoding('utf8');
76
77 process.stdin.on('readable', function() {
78 var chunk = process.stdin.read();
79 if (chunk !== null) data += chunk;
80 });
81
82 process.stdin.on('end', function() {
83 fn(null, data);
84 });
85};
86
87/**
88 * res:
89 * The results value is an object passed to the callback of `read()`.
90 *
91 * ~ data (String): a concatenation of all data in all the files.
92 * ~ error (Error): The first error in all files. `undefined` if successful.
93 * ~ stdin (Boolean): is `true` if the file is read from stdin
94 * ~ files (Array): A list of files.
95 *
96 * Each of the items in `files` has a similar list of values:
97 *
98 * ~ data (String): File data
99 * ~ error (Error): error, if applicable
100 * ~ stdin (Boolean): is `true` if the file is read from stdin
101 * ~ name (String): File name
102 *
103 * See [read()](read) for an example.
104 */
105
106function Result(files) {
107 this.files = files;
108}
109
110getter(Result.prototype, 'data', function () {
111 return this.files.map(function (f) { return f.data || ""; }).join("");
112});
113
114
115getter(Result.prototype, 'error', function () {
116 return this.files.reduce(function (acc, f) { return acc || f.error; });
117});
118
119getter(Result.prototype, 'stdin', function () {
120 return this.files && this.files[0] && this.files[0].stdin;
121});
122
123/**
124 * getter() : getter(prototype, prop, fn)
125 * (private) Defines a get property `prop` in the given `prototype` object.
126 */
127
128function getter (proto, prop, fn) {
129 Object.defineProperty(proto, prop, { get: fn });
130}
131
132module.exports = read;