1 | var 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 |
|
37 | function 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 |
|
72 | read.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 |
|
106 | function Result(files) {
|
107 | this.files = files;
|
108 | }
|
109 |
|
110 | getter(Result.prototype, 'data', function () {
|
111 | return this.files.map(function (f) { return f.data || ""; }).join("");
|
112 | });
|
113 |
|
114 |
|
115 | getter(Result.prototype, 'error', function () {
|
116 | return this.files.reduce(function (acc, f) { return acc || f.error; });
|
117 | });
|
118 |
|
119 | getter(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 |
|
128 | function getter (proto, prop, fn) {
|
129 | Object.defineProperty(proto, prop, { get: fn });
|
130 | }
|
131 |
|
132 | module.exports = read;
|