# Coverage

95%
486
464
22

## csv.js

97%
68
66
2

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 |  | /*
3 |  |
4 |  | Node CSV
5 |  | ========
6 |  |
7 |  | This project provides CSV parsing and has been tested and used
8 |  | on a large input file (over 2Gb).
9 |  |
10 |  | * Follow the NodeJs streaming API
11 |  | * Async and event based
12 |  | * Support delimiters, quotes and escape characters
13 |  | * Line breaks discovery: detected in source and reported to destination
14 |  | * Data transformation
15 |  | * Support for large datasets
16 |  | * Complete test coverage as sample and inspiration
17 |  | * no external dependencies
18 |  |
19 |  | Important, this documentation cover the current version of the node
20 |  | csv parser. The documentation for the current version 0.1.0 is
21 |  | available [here](https://github.com/wdavidw/node-csv-parser/tree/v0.1).
22 |  |
23 |  | Quick example
24 |  | -------------
25 |  |
26 |  | // node samples/string.js
27 |  | var csv = require('csv');
28 |  | csv()
29 |  | .from( '"1","2","3","4"\n"a","b","c","d"' )
30 |  | .to( console.log )
31 |  | // Output:
32 |  | // 1,2,3,4
33 |  | // a,b,c,d
34 |  |
35 |  | Advanced example
36 |  | ----------------
37 |  |
38 |  | The following example illustrates 4 usages of the library:
39 |  | 1. Plug a readable stream by defining a file path
40 |  | 2. Direct output to a file path
41 |  | 3. Transform the data (optional)
42 |  | 4. Listen to events (optional)
43 |  |
44 |  | // node samples/sample.js
45 |  | var csv = require('csv');
46 |  | csv()
47 |  | .from.stream(fs.createReadStream(__dirname+'/sample.in')
48 |  | .to.path(__dirname+'/sample.out')
49 |  | .transform( function(data){
50 |  | data.unshift(data.pop());
51 |  | return data;
52 |  | })
53 |  | .on('record', function(data,index){
54 |  | console.log('#'+index+' '+JSON.stringify(data));
55 |  | })
56 |  | .on('end', function(count){
57 |  | console.log('Number of lines: '+count);
58 |  | })
59 |  | .on('error', function(error){
60 |  | console.log(error.message);
61 |  | });
62 |  | // Output:
63 |  | // #0 ["2000-01-01","20322051544","1979.0","8.8017226E7","ABC","45"]
64 |  | // #1 ["2050-11-27","28392898392","1974.0","8.8392926E7","DEF","23"]
65 |  | // Number of lines: 2
66 |  |
67 |  | Pipe example
68 |  | ------------
69 |  |
70 |  | The module follow a Stream architecture. At it's core, the parser and
71 |  | the stringifier utilities provide a [Stream Writer][writable_stream]
72 |  | and a [Stream Reader][readable_stream] implementation available in the CSV API.
73 |  |
74 |  | |-----------| |---------|---------| |---------|
75 |  | | | | | | | |
76 |  | | | | CSV | | |
77 |  | | | | | | | |
78 |  | | Stream | | Writer | Reader | | Stream |
79 |  | | Reader |.pipe(| API | API |).pipe(| Writer |)
80 |  | | | | | | | |
81 |  | | | | | | | |
82 |  | |-----------| |---------|---------| |---------|
83 |  |
84 |  | Here's a quick example:
85 |  |
86 |  | in = fs.createReadStream('./in')
87 |  | out = fs.createWriteStream('./out')
88 |  | in.pipe(csv()).pipe(out)
89 |  |
90 |  | Installing
91 |  | ----------
92 |  |
93 |  | Via [npm](http://github.com/isaacs/npm):
94 |  | ```bash
95 |  | npm install csv
96 |  | ```
97 |  |
98 |  | Via git (or downloaded tarball):
99 |  | ```bash
100 |  | git clone http://github.com/wdavidw/node-csv-parser.git
101 |  | ```
102 |  |
103 |  | Events
104 |  | ------
105 |  |
106 |  | The library extends Node [EventEmitter][event] class and emit all
107 |  | the events of the Writable and Readable [Stream API][stream]. Additionally, the useful "records" event
108 |  | is emitted.
109 |  |
110 |  | * *record*
111 |  | Emitted by the stringifier when a new row is parsed and transformed. The data is
112 |  | the value returned by the user `transform` callback if any. Note however that the event won't
113 |  | be called if transform return `null` since the record is skipped.
114 |  | The callback provides two arguments. `data` is the CSV line being processed (an array or an object)
115 |  | and `index` is the index number of the line starting at zero
116 |  | * *data*
117 |  | Emitted by the stringifier on each line once the data has been transformed and stringified.
118 |  | * *drain*
119 |  | * *end*
120 |  | Emitted when the CSV content has been parsed.
121 |  | * *close*
122 |  | Emitted when the underlying resource has been closed. For example, when writting to a file with `csv().to.path()`, the event will be called once the writing process is complete and the file closed.
123 |  | * *error*
124 |  | Thrown whenever an error occured.
125 |  | */
126 |  |
127 | 1 | var CSV, from, options, parser, state, stream, stringifier, to, transformer;
128 |  |
129 | 1 | stream = require('stream');
130 |  |
131 | 1 | state = require('./state');
132 |  |
133 | 1 | options = require('./options');
134 |  |
135 | 1 | from = require('./from');
136 |  |
137 | 1 | to = require('./to');
138 |  |
139 | 1 | stringifier = require('./stringifier');
140 |  |
141 | 1 | parser = require('./parser');
142 |  |
143 | 1 | transformer = require('./transformer');
144 |  |
145 | 1 | CSV = function() {
146 | 78 | this.paused = false;
147 | 78 | this.readable = true;
148 | 78 | this.writable = true;
149 | 78 | this.state = state();
150 | 78 | this.options = options();
151 | 78 | this.from = from(this);
152 | 78 | this.to = to(this);
153 | 78 | this.parser = parser(this);
154 | 78 | this.parser.on('row', (function(row) {
155 | 27450 | return this.transformer.transform(row);
156 |  | }).bind(this));
157 | 78 | this.parser.on('end', (function() {
158 | 73 | return this.transformer.end();
159 |  | }).bind(this));
160 | 78 | this.parser.on('error', (function(e) {
161 | 3 | return this.error(e);
162 |  | }).bind(this));
163 | 78 | this.stringifier = stringifier(this);
164 | 78 | this.transformer = transformer(this);
165 | 78 | this.transformer.on('end', (function() {
166 | 73 | return this.emit('end', this.state.count);
167 |  | }).bind(this));
168 | 78 | return this;
169 |  | };
170 |  |
171 | 1 | CSV.prototype.__proto__ = stream.prototype;
172 |  |
173 |  | /*
174 |  |
175 |  | `pause()`
176 |  | ---------
177 |  |
178 |  | Implementation of the Readable Stream API, requesting that no further data
179 |  | be sent until resume() is called.
180 |  | */
181 |  |
182 |  |
183 | 1 | CSV.prototype.pause = function() {
184 | 19463 | return this.paused = true;
185 |  | };
186 |  |
187 |  | /*
188 |  |
189 |  | `resume()`
190 |  | ----------
191 |  |
192 |  | Implementation of the Readable Stream API, resuming the incoming 'data'
193 |  | events after a pause().
194 |  | */
195 |  |
196 |  |
197 | 1 | CSV.prototype.resume = function() {
198 | 15346 | this.paused = false;
199 | 15346 | return this.emit('drain');
200 |  | };
201 |  |
202 |  | /*
203 |  |
204 |  | `write(data, [preserve])`
205 |  | -------------------------
206 |  |
207 |  | Implementation of the Writable Stream API with a larger signature. Data
208 |  | may be a string, a buffer, an array or an object.
209 |  |
210 |  | If data is a string or a buffer, it could span multiple lines. If data
211 |  | is an object or an array, it must represent a single line.
212 |  | Preserve is for line which are not considered as CSV data.
213 |  | */
214 |  |
215 |  |
216 | 1 | CSV.prototype.write = function(data, preserve) {
217 | 29461 | var csv;
218 | 29461 | if (!this.writable) {
219 | 0 | return false;
220 |  | }
221 | 29461 | if (data instanceof Buffer) {
222 | 26286 | data = data.toString();
223 |  | }
224 | 29461 | if (typeof data === 'string' && !preserve) {
225 | 26420 | this.parser.parse(data);
226 | 3041 | } else if (Array.isArray(data) && !this.state.transforming) {
227 | 2020 | csv = this;
228 | 2020 | this.transformer.transform(data);
229 |  | } else {
230 | 1021 | if (preserve || this.state.transforming) {
231 | 9 | this.stringifier.write(data, preserve);
232 |  | } else {
233 | 1012 | this.transformer.transform(data);
234 |  | }
235 |  | }
236 | 29461 | return !this.paused;
237 |  | };
238 |  |
239 |  | /*
240 |  |
241 |  | `end()`
242 |  | -------
243 |  |
244 |  | Terminate the parsing. Call this method when no more csv data is
245 |  | to be parsed. It implement the StreamWriter API by setting the `writable`
246 |  | property to "false" and emitting the `end` event.
247 |  | */
248 |  |
249 |  |
250 | 1 | CSV.prototype.end = function() {
251 | 75 | if (!this.writable) {
252 | 1 | return;
253 |  | }
254 | 74 | this.readable = false;
255 | 74 | this.writable = false;
256 | 74 | return this.parser.end();
257 |  | };
258 |  |
259 |  | /*
260 |  |
261 |  | `transform(callback)`
262 |  | ---------------------
263 |  |
264 |  | Register the transformer callback. The callback is a user provided
265 |  | function call on each line to filter, enrich or modify the
266 |  | dataset. More information in the "transforming data" section.
267 |  | */
268 |  |
269 |  |
270 | 1 | CSV.prototype.transform = function(callback) {
271 | 31 | this.transformer.callback = callback;
272 | 31 | return this;
273 |  | };
274 |  |
275 |  | /*
276 |  |
277 |  | `error(error)`
278 |  | --------------
279 |  |
280 |  | Unified mechanism to handle error, emit the error and mark the
281 |  | stream as non readable and non writable.
282 |  | */
283 |  |
284 |  |
285 | 1 | CSV.prototype.error = function(e) {
286 | 5 | this.readable = false;
287 | 5 | this.writable = false;
288 | 5 | this.emit('error', e);
289 | 5 | if (this.readStream) {
290 | 0 | this.readStream.destroy();
291 |  | }
292 | 5 | return this;
293 |  | };
294 |  |
295 | 1 | module.exports = function() {
296 | 78 | return new CSV;
297 |  | };
298 |  |
299 |  | /*
300 |  | [event]: http://nodejs.org/api/events.html
301 |  | [stream]: http://nodejs.org/api/stream.html
302 |  | [writable_stream]: http://nodejs.org/api/stream.html#stream_writable_stream
303 |  | [readable_stream]: http://nodejs.org/api/stream.html#stream_readable_stream
304 |  | */
305 |  |

## state.js

100%
2
2
0

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 |  |
3 | 1 | module.exports = function() {
4 | 78 | return {
5 |  | count: 0,
6 |  | field: '',
7 |  | line: [],
8 |  | lastC: '',
9 |  | countWriten: 0,
10 |  | transforming: 0
11 |  | };
12 |  | };

## options.js

100%
2
2
0

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 |  | /*
3 |  | Input and output options
4 |  | ========================
5 |  |
6 |  | The `options` property provide access to the `from` and `to` object used to store options. This
7 |  | property is for internal usage and could be considered private. It is recommanded to use
8 |  | the `from.options()` and `to.options()` to access those objects.
9 |  | */
10 |  |
11 | 1 | module.exports = function() {
12 | 78 | return {
13 |  | from: {
14 |  | delimiter: ',',
15 |  | quote: '"',
16 |  | escape: '"',
17 |  | columns: null,
18 |  | flags: 'r',
19 |  | encoding: 'utf8',
20 |  | trim: false,
21 |  | ltrim: false,
22 |  | rtrim: false
23 |  | },
24 |  | to: {
25 |  | delimiter: null,
26 |  | quote: null,
27 |  | quoted: false,
28 |  | escape: null,
29 |  | columns: null,
30 |  | header: false,
31 |  | lineBreaks: null,
32 |  | flags: 'w',
33 |  | encoding: 'utf8',
34 |  | newColumns: false,
35 |  | end: true
36 |  | }
37 |  | };
38 |  | };

## from.js

91%
60
55
5

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 | 1 | var Stream, fs, path, utils, _ref;
3 |  |
4 | 1 | fs = require('fs');
5 |  |
6 | 1 | path = require('path');
7 |  |
8 | 1 | if ((_ref = fs.exists) == null) {
9 | 0 | fs.exists = path.exists;
10 |  | }
11 |  |
12 | 1 | utils = require('./utils');
13 |  |
14 | 1 | Stream = require('stream');
15 |  |
16 |  | /*
17 |  |
18 |  | Reading data from a source
19 |  | ==========================
20 |  |
21 |  | The `csv().from` property provides functions to read from an external
22 |  | source and write to a CSV instance. The source may be a string, a file,
23 |  | a buffer or a readable stream.
24 |  |
25 |  | You may call the `from` function or one of its sub function. For example,
26 |  | here are two identical ways to read from a file:
27 |  |
28 |  | csv.from('/tmp/data.csv').on('data', console.log);
29 |  | csv.from.path('/tmp/data.csv').on('data', console.log);
30 |  | */
31 |  |
32 |  |
33 | 1 | module.exports = function(csv) {
34 |  | /*
35 |  |
36 |  | `from(mixed)`
37 |  | -------------
38 |  |
39 |  | Read from any sort of source. It should be considered as a convenient function which
40 |  | will discover the nature of the data source to parse.
41 |  |
42 |  | If it is a string, then if check if it match an existing file path and read the file content,
43 |  | otherwise, it treat the string as csv data. If it is an instance of stream, it consider the
44 |  | object to be an input stream. If is an array, then for each line should correspond a record.
45 |  |
46 |  | Here's some examples on how to use this function:
47 |  |
48 |  | csv()
49 |  | .from('"1","2","3","4"\n"a","b","c","d"')
50 |  | .on('end', function(){ console.log('done') })
51 |  |
52 |  | csv()
53 |  | .from('./path/to/file.csv')
54 |  | .on('end', function(){ console.log('done') })
55 |  |
56 |  | csv()
57 |  | .from(fs.createReadStream('./path/to/file.csv'))
58 |  | .on('end', function(){ console.log('done') })
59 |  |
60 |  | csv()
61 |  | .from(['"1","2","3","4","5"',['1','2','3','4','5']])
62 |  | .on('end', function(){ console.log('done') })
63 |  | */
64 |  |
65 | 78 | var from;
66 | 78 | from = function(mixed, options) {
67 | 13 | var error;
68 | 13 | error = false;
69 | 13 | switch (typeof mixed) {
70 |  | case 'string':
71 | 9 | fs.exists(mixed, function(exists) {
72 | 9 | if (exists) {
73 | 1 | return from.path(mixed, options);
74 |  | } else {
75 | 8 | return from.string(mixed, options);
76 |  | }
77 |  | });
78 | 9 | break;
79 |  | case 'object':
80 | 4 | if (Array.isArray(mixed)) {
81 | 3 | from.array(mixed, options);
82 |  | } else {
83 | 1 | if (mixed instanceof Stream) {
84 | 1 | from.stream(mixed, options);
85 |  | } else {
86 | 0 | error = true;
87 |  | }
88 |  | }
89 | 4 | break;
90 |  | default:
91 | 0 | error = true;
92 |  | }
93 | 13 | if (error) {
94 | 0 | csv.error(new Error("Invalid mixed argument in from"));
95 |  | }
96 | 13 | return csv;
97 |  | };
98 |  | /*
99 |  |
100 |  | `from.options([options])`
101 |  | -------------------------
102 |  |
103 |  | Update and retrieve options relative to the input source. Return
104 |  | the options as an object if no argument is provided.
105 |  |
106 |  | * `delimiter` Set the field delimiter, one character only, defaults to comma.
107 |  | * `quote` Set the field delimiter, one character only, defaults to double quotes.
108 |  | * `escape` Set the field delimiter, one character only, defaults to double quotes.
109 |  | * `columns` List of fields or true if autodiscovered in the first CSV line, default to null. Impact the `transform` argument and the `data` event by providing an object instead of an array, order matters, see the transform and the columns sections for more details.
110 |  | * `flags` Used to read a file stream, default to the r charactere.
111 |  | * `encoding` Encoding of the read stream, defaults to 'utf8', applied when a readable stream is created.
112 |  | * `trim` If true, ignore whitespace immediately around the delimiter, defaults to false.
113 |  | * `ltrim` If true, ignore whitespace immediately following the delimiter (i.e. left-trim all fields), defaults to false.
114 |  | * `rtrim` If true, ignore whitespace immediately preceding the delimiter (i.e. right-trim all fields), defaults to false.
115 |  |
116 |  | Additionnaly, in case you are working with stream, you can pass all
117 |  | the options accepted by the `stream.pipe` function.
118 |  | */
119 |  |
120 | 78 | from.options = function(options) {
121 | 191 | if (options != null) {
122 | 24 | utils.merge(csv.options.from, options);
123 | 24 | return csv;
124 |  | } else {
125 | 167 | return csv.options.from;
126 |  | }
127 |  | };
128 |  | /*
129 |  |
130 |  | `from.array(data, [options])`
131 |  | ------------------------------
132 |  |
133 |  | Read from an array. Take an array as first argument and optionally
134 |  | some options as a second argument. Each element of the array
135 |  | represents a csv record. Those elements may be a string, a buffer, an
136 |  | array or an object.
137 |  | */
138 |  |
139 | 78 | from.array = function(data, options) {
140 | 8 | this.options(options);
141 | 8 | process.nextTick(function() {
142 | 8 | var record, _i, _len;
143 | 8 | for (_i = 0, _len = data.length; _i < _len; _i++) {
144 | 17 | record = data[_i];
145 | 17 | csv.write(record);
146 |  | }
147 | 8 | return csv.end();
148 |  | });
149 | 8 | return csv;
150 |  | };
151 |  | /*
152 |  |
153 |  | `from.string(data, [options])`
154 |  | -------------------------------
155 |  |
156 |  | Read from a string or a buffer. Take a string as first argument and
157 |  | optionally an object of options as a second argument. The string
158 |  | must be the complete csv data, look at the streaming alternative if your
159 |  | CSV is large.
160 |  |
161 |  | csv()
162 |  | .from( '"1","2","3","4"\n"a","b","c","d"' )
163 |  | .to( function(data){} )
164 |  | */
165 |  |
166 | 78 | from.string = function(data, options) {
167 | 17 | this.options(options);
168 | 17 | process.nextTick(function() {
169 | 17 | csv.write(data);
170 | 17 | return csv.end();
171 |  | });
172 | 17 | return csv;
173 |  | };
174 |  | /*
175 |  |
176 |  | `from.path(path, [options])`
177 |  | ----------------------------
178 |  |
179 |  | Read from a file path. Take a file path as first argument and optionally an object
180 |  | of options as a second argument.
181 |  | */
182 |  |
183 | 78 | from.path = function(path, options) {
184 | 40 | var stream;
185 | 40 | this.options(options);
186 | 40 | stream = fs.createReadStream(path, csv.from.options());
187 | 40 | return csv.from.stream(stream);
188 |  | };
189 |  | /*
190 |  |
191 |  | `from.stream(stream, [options])`
192 |  | --------------------------------
193 |  |
194 |  | Read from a stream. Take a readable stream as first argument and optionally
195 |  | an object of options as a second argument.
196 |  | */
197 |  |
198 | 78 | from.stream = function(stream, options) {
199 | 43 | if (options) {
200 | 0 | this.options(options);
201 |  | }
202 | 43 | stream.setEncoding(csv.from.options().encoding);
203 | 43 | stream.pipe(csv, csv.from.options());
204 | 43 | return csv;
205 |  | };
206 | 78 | return from;
207 |  | };

## utils.js

100%
6
6
0

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 |  |
3 | 1 | module.exports = {
4 |  | merge: function(obj1, obj2) {
5 | 94 | var key, r;
6 | 94 | r = obj1 || {};
7 | 94 | for (key in obj2) {
8 | 618 | r[key] = obj2[key];
9 |  | }
10 | 94 | return r;
11 |  | }
12 |  | };

## to.js

86%
67
58
9

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 | 1 | var Stream, fs, utils;
3 |  |
4 | 1 | fs = require('fs');
5 |  |
6 | 1 | Stream = require('stream');
7 |  |
8 | 1 | utils = require('./utils');
9 |  |
10 |  | /*
11 |  |
12 |  | Writing data to a destination
13 |  | =============================
14 |  |
15 |  | The `csv().to` property provides functions to read from a CSV instance and
16 |  | to write to an external destination. The destination may be a stream, a file
17 |  | or a callback.
18 |  |
19 |  | You may call the `to` function or one of its sub function. For example,
20 |  | here are two identical ways to write to a file:
21 |  |
22 |  | csv.from(data).to('/tmp/data.csv');
23 |  | csv.from(data).to.path('/tmp/data.csv');
24 |  | */
25 |  |
26 |  |
27 | 1 | module.exports = function(csv) {
28 |  | /*
29 |  |
30 |  | `to(mixed)`
31 |  | -----------
32 |  |
33 |  | Write from any sort of destination. It should be considered as a convenient function
34 |  | which will discover the nature of the destination where to write the CSV data.
35 |  |
36 |  | If is an function, then the csv will be provided as the first argument
37 |  | of the callback. If it is a string, then it is expected to be a
38 |  | file path. If it is an instance of stream, it consider the object to be an
39 |  | output stream.
40 |  |
41 |  | Here's some examples on how to use this function:
42 |  |
43 |  | csv()
44 |  | .from('"1","2","3","4","5"')
45 |  | .to(function(data){ console.log(data) })
46 |  |
47 |  | csv()
48 |  | .from('"1","2","3","4","5"')
49 |  | .to('./path/to/file.csv')
50 |  |
51 |  | csv()
52 |  | .from('"1","2","3","4","5"')
53 |  | .to(fs.createWriteStream('./path/to/file.csv'))
54 |  | */
55 |  |
56 | 78 | var to;
57 | 78 | to = function(mixed, options) {
58 | 13 | var error;
59 | 13 | error = false;
60 | 13 | switch (typeof mixed) {
61 |  | case 'string':
62 | 1 | to.path(mixed, options);
63 | 1 | break;
64 |  | case 'object':
65 | 0 | if (mixed instanceof Stream) {
66 | 0 | to.stream(mixed, options);
67 |  | } else {
68 | 0 | error = true;
69 |  | }
70 | 0 | break;
71 |  | case 'function':
72 | 12 | to.string(mixed, options);
73 | 12 | break;
74 |  | default:
75 | 0 | error = true;
76 |  | }
77 | 13 | if (error) {
78 | 0 | csv.error(new Error("Invalid mixed argument in from"));
79 |  | }
80 | 13 | return csv;
81 |  | };
82 |  | /*
83 |  |
84 |  | `to.options([options])`
85 |  | -----------------------
86 |  |
87 |  | Update and retrieve options relative to the output. Return the options
88 |  | as an object if no argument is provided.
89 |  |
90 |  | * `delimiter` Set the field delimiter, one character only, defaults to `options.from.delimiter` which is a comma.
91 |  | * `quote` Defaults to the quote read option.
92 |  | * `quoted` Boolean, default to false, quote all the fields even if not required.
93 |  | * `escape` Defaults to the escape read option.
94 |  | * `columns` List of fields, applied when `transform` returns an object, order matters, see the transform and the columns sections below.
95 |  | * `header` Display the column names on the first line if the columns option is provided.
96 |  | * `lineBreaks` String used to delimit record rows or a special value; special values are 'auto', 'unix', 'mac', 'windows', 'unicode'; defaults to 'auto' (discovered in source or 'unix' if no source is specified).
97 |  | * `flags` Defaults to 'w', 'w' to create or overwrite an file, 'a' to append to a file. Applied when using the `toPath` method.
98 |  | * `newColumns` If the `columns` option is not specified (which means columns will be taken from the reader options, will automatically append new columns if they are added during `transform()`.
99 |  | * `end` Prevent calling `end` on the destination, so that destination is no longer writable, similar to passing `{end: false}` option in `stream.pipe()`.
100 |  | */
101 |  |
102 | 78 | to.options = function(options) {
103 | 116 | if (options != null) {
104 | 19 | utils.merge(csv.options.to, options);
105 | 19 | return csv;
106 |  | } else {
107 | 97 | return csv.options.to;
108 |  | }
109 |  | };
110 |  | /*
111 |  |
112 |  | `to.string(callback, [options])`
113 |  | ------------------------------
114 |  |
115 |  | Provide the output string to a callback.
116 |  |
117 |  | csv()
118 |  | .from( '"1","2","3","4"\n"a","b","c","d"' )
119 |  | .to( function(data, count){} )
120 |  |
121 |  | Callback is called with 2 arguments:
122 |  | * data Stringify CSV string
123 |  | * count Number of stringified records
124 |  | */
125 |  |
126 | 78 | to.string = function(callback, options) {
127 | 13 | var data, stream;
128 | 13 | this.options(options);
129 | 13 | data = '';
130 | 13 | stream = new Stream;
131 | 13 | stream.writable = true;
132 | 13 | stream.write = function(d) {
133 | 26 | data += d;
134 | 26 | return true;
135 |  | };
136 | 13 | stream.end = function() {
137 | 13 | return callback(data, csv.state.countWriten);
138 |  | };
139 | 13 | csv.pipe(stream);
140 | 13 | return csv;
141 |  | };
142 |  | /*
143 |  |
144 |  | `to.stream(stream, [options])`
145 |  | ------------------------------
146 |  |
147 |  | Write to a stream. Take a writable stream as first argument and
148 |  | optionally an object of options as a second argument.
149 |  | */
150 |  |
151 | 78 | to.stream = function(stream, options) {
152 | 52 | this.options(options);
153 | 52 | switch (csv.options.to.lineBreaks) {
154 |  | case 'auto':
155 | 0 | csv.options.to.lineBreaks = null;
156 | 0 | break;
157 |  | case 'unix':
158 | 2 | csv.options.to.lineBreaks = "\n";
159 | 2 | break;
160 |  | case 'mac':
161 | 1 | csv.options.to.lineBreaks = "\r";
162 | 1 | break;
163 |  | case 'windows':
164 | 1 | csv.options.to.lineBreaks = "\r\n";
165 | 1 | break;
166 |  | case 'unicode':
167 | 1 | csv.options.to.lineBreaks = "\u2028";
168 |  | }
169 | 52 | csv.pipe(stream);
170 | 52 | stream.on('error', function(e) {
171 | 0 | return csv.error(e);
172 |  | });
173 | 52 | stream.on('close', function() {
174 | 47 | return csv.emit('close', csv.state.count);
175 |  | });
176 | 52 | return csv;
177 |  | };
178 |  | /*
179 |  |
180 |  | `to.path(path, [options])`
181 |  | --------------------------
182 |  |
183 |  | Write to a path. Take a file path as first argument and optionally an object of
184 |  | options as a second argument. The `close` event is sent after the file is written.
185 |  | Relying on the `end` event is incorrect because it is sent when parsing is done
186 |  | but before the file is written.
187 |  | */
188 |  |
189 | 78 | to.path = function(path, options) {
190 | 51 | var stream;
191 | 51 | this.options(options);
192 | 51 | options = utils.merge({}, csv.options.to);
193 | 51 | delete options.end;
194 | 51 | stream = fs.createWriteStream(path, options);
195 | 51 | csv.to.stream(stream, null);
196 | 51 | return csv;
197 |  | };
198 | 78 | return to;
199 |  | };

## stringifier.js

98%
67
66
1

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 |  | /*
3 |  |
4 |  | Stringifier
5 |  | ===========
6 |  |
7 |  | Convert an array or an object into a CSV line.
8 |  | */
9 |  |
10 | 1 | var Stringifier;
11 |  |
12 | 1 | Stringifier = function(csv) {
13 | 78 | this.csv = csv;
14 | 78 | return this;
15 |  | };
16 |  |
17 |  | /*
18 |  | Write a line to the written stream. Line may be an object, an array or a string
19 |  | The `preserve` argument is for line which are not considered as CSV data.
20 |  | */
21 |  |
22 |  |
23 | 1 | Stringifier.prototype.write = function(line, preserve) {
24 | 30491 | if (typeof line === 'undefined' || line === null) {
25 | 9 | return;
26 |  | }
27 | 30482 | if (!preserve) {
28 | 30475 | try {
29 | 30475 | this.csv.emit('record', line, this.csv.state.count - 1);
30 |  | } catch (e) {
31 | 1 | return this.csv.error(e);
32 |  | }
33 | 30474 | line = this.csv.stringifier.stringify(line);
34 |  | }
35 | 30481 | this.csv.emit('data', line);
36 | 30481 | if (!preserve) {
37 | 30474 | this.csv.state.countWriten++;
38 |  | }
39 | 30481 | return true;
40 |  | };
41 |  |
42 | 1 | Stringifier.prototype.stringify = function(line) {
43 | 30474 | var column, columns, containsLinebreak, containsQuote, containsdelimiter, delimiter, escape, field, i, newLine, quote, regexp, _i, _j, _line, _ref, _ref1;
44 | 30474 | columns = this.csv.options.to.columns || this.csv.options.from.columns;
45 | 30474 | if (typeof columns === 'object' && columns !== null && !Array.isArray(columns)) {
46 | 8 | columns = Object.keys(columns);
47 |  | }
48 | 30474 | delimiter = this.csv.options.to.delimiter || this.csv.options.from.delimiter;
49 | 30474 | quote = this.csv.options.to.quote || this.csv.options.from.quote;
50 | 30474 | escape = this.csv.options.to.escape || this.csv.options.from.escape;
51 | 30474 | if (typeof line === 'object') {
52 | 29469 | if (!Array.isArray(line)) {
53 | 1029 | _line = [];
54 | 1029 | if (columns) {
55 | 1023 | for (i = _i = 0, _ref = columns.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
56 | 3073 | column = columns[i];
57 | 3073 | _line[i] = typeof line[column] === 'undefined' || line[column] === null ? '' : line[column];
58 |  | }
59 |  | } else {
60 | 6 | for (column in line) {
61 | 14 | _line.push(line[column]);
62 |  | }
63 |  | }
64 | 1029 | line = _line;
65 | 1029 | _line = null;
66 | 28440 | } else if (columns) {
67 | 11 | line.splice(columns.length);
68 |  | }
69 | 29469 | if (Array.isArray(line)) {
70 | 29469 | newLine = this.csv.state.countWriten ? this.csv.options.to.lineBreaks || "\n" : '';
71 | 29469 | for (i = _j = 0, _ref1 = line.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
72 | 220181 | field = line[i];
73 | 220181 | if (typeof field === 'string') {
74 |  |
75 | 2027 | } else if (typeof field === 'number') {
76 | 2017 | field = '' + field;
77 | 10 | } else if (typeof field === 'boolean') {
78 | 4 | field = field ? '1' : '';
79 | 6 | } else if (field instanceof Date) {
80 | 0 | field = '' + field.getTime();
81 |  | }
82 | 220181 | if (field) {
83 | 220151 | containsdelimiter = field.indexOf(delimiter) >= 0;
84 | 220151 | containsQuote = field.indexOf(quote) >= 0;
85 | 220151 | containsLinebreak = field.indexOf("\r") >= 0 || field.indexOf("\n") >= 0;
86 | 220151 | if (containsQuote) {
87 | 3021 | regexp = new RegExp(quote, 'g');
88 | 3021 | field = field.replace(regexp, escape + quote);
89 |  | }
90 | 220151 | if (containsQuote || containsdelimiter || containsLinebreak || this.csv.options.to.quoted) {
91 | 3035 | field = quote + field + quote;
92 |  | }
93 | 220151 | newLine += field;
94 |  | }
95 | 220181 | if (i !== line.length - 1) {
96 | 190712 | newLine += delimiter;
97 |  | }
98 |  | }
99 | 29469 | line = newLine;
100 |  | }
101 | 1005 | } else if (typeof line === 'number') {
102 | 1003 | line = '' + line;
103 |  | }
104 | 30474 | return line;
105 |  | };
106 |  |
107 | 1 | module.exports = function(csv) {
108 | 78 | return new Stringifier(csv);
109 |  | };
110 |  |
111 | 1 | module.exports.Stringifier = Stringifier;

## parser.js

96%
96
93
3

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 | 1 | var EventEmitter, Parser;
3 |  |
4 | 1 | EventEmitter = require('events').EventEmitter;
5 |  |
6 |  | /*
7 |  |
8 |  | Parsing
9 |  | =======
10 |  |
11 |  | The library extend the [EventEmitter][event] and emit the following events:
12 |  |
13 |  | * *row*
14 |  | Emitted by the parser on each line with the line content as an array of fields.
15 |  | * *end*
16 |  | Emitted when no more data will be parsed.
17 |  | * *error*
18 |  | Emitted when an error occured.
19 |  | */
20 |  |
21 |  |
22 | 1 | Parser = function(csv) {
23 | 78 | this.csv = csv;
24 | 78 | this.options = csv.options.from;
25 | 78 | this.state = csv.state;
26 | 78 | this.quoted = false;
27 | 78 | this.commented = false;
28 | 78 | this.lines = 0;
29 | 78 | return this;
30 |  | };
31 |  |
32 | 1 | Parser.prototype.__proto__ = EventEmitter.prototype;
33 |  |
34 |  | /*
35 |  |
36 |  | `parse(chars)`
37 |  | --------------
38 |  |
39 |  | Parse a string which may hold multiple lines.
40 |  | Private state object is enriched on each character until
41 |  | transform is called on a new line.
42 |  | */
43 |  |
44 |  |
45 | 1 | Parser.prototype.parse = function(chars) {
46 | 26420 | var c, csv, escapeIsQuote, i, isEscape, isQuote, isReallyEscaped, l, nextChar;
47 | 26420 | csv = this.csv;
48 | 26420 | chars = '' + chars;
49 | 26420 | l = chars.length;
50 | 26420 | i = 0;
51 | 26420 | if (this.lines === 0 && csv.options.from.encoding === 'utf8' && 0xFEFF === chars.charCodeAt(0)) {
52 | 1 | i++;
53 |  | }
54 | 26420 | while (i < l) {
55 | 2020024 | c = chars.charAt(i);
56 | 2020024 | switch (c) {
57 |  | case this.options.escape:
58 |  | case this.options.quote:
59 | 3198 | if (this.commented) {
60 | 0 | break;
61 |  | }
62 | 3198 | isReallyEscaped = false;
63 | 3198 | if (c === this.options.escape) {
64 | 3194 | nextChar = chars.charAt(i + 1);
65 | 3194 | escapeIsQuote = this.options.escape === this.options.quote;
66 | 3194 | isEscape = nextChar === this.options.escape;
67 | 3194 | isQuote = nextChar === this.options.quote;
68 | 3194 | if (!(escapeIsQuote && !this.state.field && !this.quoted) && (isEscape || isQuote)) {
69 | 1012 | i++;
70 | 1012 | isReallyEscaped = true;
71 | 1012 | c = chars.charAt(i);
72 | 1012 | this.state.field += c;
73 |  | }
74 |  | }
75 | 3198 | if (!isReallyEscaped && c === this.options.quote) {
76 | 2186 | if (this.state.field && !this.quoted) {
77 | 3 | this.state.field += c;
78 | 3 | break;
79 |  | }
80 | 2183 | if (this.quoted) {
81 | 1091 | nextChar = chars.charAt(i + 1);
82 | 1091 | if (nextChar && nextChar !== '\r' && nextChar !== '\n' && nextChar !== this.options.delimiter) {
83 | 2 | return this.error(new Error("Invalid closing quote at line " + (this.lines + 1) + "; found " + (JSON.stringify(nextChar)) + " instead of delimiter " + (JSON.stringify(this.options.delimiter))));
84 |  | }
85 | 1089 | this.quoted = false;
86 | 1092 | } else if (this.state.field === '') {
87 | 1092 | this.quoted = true;
88 |  | }
89 |  | }
90 | 3193 | break;
91 |  | case this.options.delimiter:
92 | 186756 | if (this.commented) {
93 | 0 | break;
94 |  | }
95 | 186756 | if (this.quoted) {
96 | 9 | this.state.field += c;
97 |  | } else {
98 | 186747 | if (this.options.trim || this.options.rtrim) {
99 | 30 | this.state.field = this.state.field.trimRight();
100 |  | }
101 | 186747 | this.state.line.push(this.state.field);
102 | 186747 | this.state.field = '';
103 |  | }
104 | 186756 | break;
105 |  | case '\n':
106 |  | case '\r':
107 | 27445 | if (this.quoted) {
108 | 5 | this.state.field += c;
109 | 5 | break;
110 |  | }
111 | 27440 | if (!this.options.quoted && this.state.lastC === '\r') {
112 | 14 | break;
113 |  | }
114 | 27426 | this.lines++;
115 | 27426 | if (csv.options.to.lineBreaks === null) {
116 | 46 | csv.options.to.lineBreaks = c + (c === '\r' && chars.charAt(i + 1) === '\n' ? '\n' : '');
117 |  | }
118 | 27426 | if (this.options.trim || this.options.rtrim) {
119 | 5 | this.state.field = this.state.field.trimRight();
120 |  | }
121 | 27426 | this.state.line.push(this.state.field);
122 | 27426 | this.state.field = '';
123 | 27426 | this.emit('row', this.state.line);
124 | 27426 | this.state.line = [];
125 | 27426 | break;
126 |  | case ' ':
127 |  | case '\t':
128 | 1123 | if (this.quoted || (!this.options.trim && !this.options.ltrim) || this.state.field) {
129 | 1082 | this.state.field += c;
130 | 1082 | break;
131 |  | }
132 | 41 | break;
133 |  | default:
134 | 1801502 | if (this.commented) {
135 | 0 | break;
136 |  | }
137 | 1801502 | this.state.field += c;
138 |  | }
139 | 2020022 | this.state.lastC = c;
140 | 2020022 | i++;
141 |  | }
142 |  | };
143 |  |
144 | 1 | Parser.prototype.end = function() {
145 | 74 | if (this.quoted) {
146 | 1 | return this.error(new Error("Quoted field not terminated at line " + (this.lines + 1)));
147 |  | }
148 | 73 | if (this.state.field || this.state.lastC === this.options.delimiter || this.state.lastC === this.options.quote) {
149 | 24 | if (this.options.trim || this.options.rtrim) {
150 | 1 | this.state.field = this.state.field.trimRight();
151 |  | }
152 | 24 | this.state.line.push(this.state.field);
153 | 24 | this.state.field = '';
154 |  | }
155 | 73 | if (this.state.line.length > 0) {
156 | 24 | this.emit('row', this.state.line);
157 |  | }
158 | 73 | return this.emit('end', null);
159 |  | };
160 |  |
161 | 1 | Parser.prototype.error = function(e) {
162 | 3 | return this.emit('error', e);
163 |  | };
164 |  |
165 | 1 | module.exports = function(csv) {
166 | 78 | return new Parser(csv);
167 |  | };
168 |  |
169 | 1 | module.exports.Parser = Parser;
170 |  |
171 |  | /*
172 |  | [event]: http://nodejs.org/api/events.html
173 |  | */
174 |  |

## transformer.js

98%
75
74
1

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 | 1 | var Transformer, stream;
3 |  |
4 | 1 | stream = require('stream');
5 |  |
6 |  | /*
7 |  | Transforming data
8 |  | =================
9 |  |
10 |  | Transformation may occur synchronously or asynchronously dependending
11 |  | on the provided transform callback and its declared arguments length.
12 |  |
13 |  | Callback are called for each line and its arguments are :
14 |  |
15 |  | * *data*
16 |  | CSV record
17 |  | * *index*
18 |  | Incremented counter
19 |  | * *callback*
20 |  | Callback function to be called in asynchronous mode
21 |  |
22 |  | Unless you specify the `columns` read option, `data` are provided
23 |  | as arrays, otherwise they are objects with keys matching columns
24 |  | names.
25 |  |
26 |  | In synchronous mode, the contract is quite simple, you receive an array
27 |  | of fields for each record and return the transformed record.
28 |  |
29 |  | In asynchronous mode, it is your responsibility to call the callback
30 |  | provided as the third argument. It must be called with two arguments,
31 |  | the first one is an error if any, the second is the transformed record.
32 |  |
33 |  | Transformed records may be an array, an associative array, a
34 |  | string or null. If null, the record will simply be skipped. When the
35 |  | returned value is an array, the fields are merged in order.
36 |  | When the returned value is an object, it will search for
37 |  | the `columns` property in the write or in the read options and
38 |  | smartly order the values. If no `columns` options are found,
39 |  | it will merge the values in their order of appearance. When the
40 |  | returned value is a string, it is directly sent to the destination
41 |  | source and it is your responsibility to delimit, quote, escape
42 |  | or define line breaks.
43 |  |
44 |  | Transform callback run synchronously:
45 |  |
46 |  | csv()
47 |  | .from('82,Preisner,Zbigniew\n94,Gainsbourg,Serge')
48 |  | .to(console.log)
49 |  | .transform(function(data, index){
50 |  | return data.reverse()
51 |  | });
52 |  | // Executing `node samples/transform.js`, print:
53 |  | // 94,Gainsbourg,Serge\n82,Preisner,Zbigniew
54 |  |
55 |  | Transform callback run asynchronously:
56 |  |
57 |  | csv()
58 |  | .from('82,Preisner,Zbigniew\n94,Gainsbourg,Serge')
59 |  | .to(console.log)
60 |  | .transform(function(data, index, callback){
61 |  | process.nextTick(function(){
62 |  | callback(null, data.reverse());
63 |  | });
64 |  | });
65 |  | // Executing `node samples/transform.js`, print:
66 |  | // 94,Gainsbourg,Serge\n82,Preisner,Zbigniew
67 |  |
68 |  | Transform callback returning a string:
69 |  |
70 |  | csv()
71 |  | .from('82,Preisner,Zbigniew\n94,Gainsbourg,Serge')
72 |  | .to(console.log)
73 |  | .transform(function(data, index){
74 |  | return (index>0 ? ',' : '') + data[0] + ":" + data[2] + ' ' + data[1];
75 |  | });
76 |  | // Executing `node samples/transform.js`, print:
77 |  | // 82:Zbigniew Preisner,94:Serge Gainsbourg
78 |  | */
79 |  |
80 |  |
81 | 1 | Transformer = function(csv) {
82 | 78 | this.csv = csv;
83 | 78 | return this;
84 |  | };
85 |  |
86 | 1 | Transformer.prototype.__proto__ = stream.prototype;
87 |  |
88 |  | /* no doc
89 |  |
90 |  | `transformer(csv).transform(line)`
91 |  | ----------------------------------
92 |  |
93 |  | Call a callback to transform a line. Called from the `parse` function on each
94 |  | line. It is responsible for transforming the data and finally calling `write`.
95 |  | */
96 |  |
97 |  |
98 | 1 | Transformer.prototype.transform = function(line) {
99 | 30482 | var column, columns, csv, done, finish, i, lineAsObject, sync, _i, _j, _len, _len1;
100 | 30482 | csv = this.csv;
101 | 30482 | columns = csv.options.from.columns;
102 | 30482 | if (columns) {
103 | 23 | if (typeof columns === 'object' && columns !== null && !Array.isArray(columns)) {
104 | 2 | columns = Object.keys(columns);
105 |  | }
106 | 23 | if (csv.state.count === 0 && columns === true) {
107 | 6 | csv.options.from.columns = line;
108 | 6 | return;
109 |  | }
110 | 17 | if (Array.isArray(line)) {
111 | 11 | lineAsObject = {};
112 | 11 | for (i = _i = 0, _len = columns.length; _i < _len; i = ++_i) {
113 | 58 | column = columns[i];
114 | 58 | lineAsObject[column] = line[i] || null;
115 |  | }
116 | 11 | line = lineAsObject;
117 |  | } else {
118 | 6 | lineAsObject = {};
119 | 6 | for (i = _j = 0, _len1 = columns.length; _j < _len1; i = ++_j) {
120 | 12 | column = columns[i];
121 | 12 | lineAsObject[column] = line[column] || null;
122 |  | }
123 | 6 | line = lineAsObject;
124 |  | }
125 |  | }
126 | 30476 | finish = (function(line) {
127 | 30475 | var k, v;
128 | 30475 | if (csv.state.count === 1 && csv.options.to.header === true) {
129 | 7 | columns = csv.options.to.columns || csv.options.from.columns;
130 | 7 | if (typeof columns === 'object') {
131 | 7 | columns = (function() {
132 | 7 | var _results;
133 | 7 | _results = [];
134 | 7 | for (k in columns) {
135 | 19 | v = columns[k];
136 | 19 | _results.push(v);
137 |  | }
138 | 7 | return _results;
139 |  | })();
140 |  | }
141 | 7 | csv.stringifier.write(columns);
142 |  | }
143 | 30475 | csv.stringifier.write(line);
144 | 30475 | if (csv.state.transforming === 0 && this.closed === true) {
145 | 3 | return this.emit('end', csv.state.count);
146 |  | }
147 |  | }).bind(this);
148 | 30476 | csv.state.count++;
149 | 30476 | if (this.callback) {
150 | 1124 | sync = this.callback.length !== 3;
151 | 1124 | csv.state.transforming++;
152 | 1124 | done = function(err, line) {
153 | 1124 | var isObject;
154 | 1124 | if (err) {
155 | 1 | return csv.error(err);
156 |  | }
157 | 1123 | isObject = typeof line === 'object' && !Array.isArray(line);
158 | 1123 | if (csv.options.to.newColumns && !csv.options.to.columns && isObject) {
159 | 2 | Object.keys(line).filter(function(column) {
160 | 14 | return columns.indexOf(column) === -1;
161 |  | }).forEach(function(column) {
162 | 1 | return columns.push(column);
163 |  | });
164 |  | }
165 | 1123 | csv.state.transforming--;
166 | 1123 | return finish(line);
167 |  | };
168 | 1124 | if (sync) {
169 | 1116 | try {
170 | 1116 | return done(null, this.callback(line, csv.state.count - 1));
171 |  | } catch (err) {
172 | 1 | return done(err);
173 |  | }
174 |  | } else {
175 | 8 | try {
176 | 8 | return this.callback(line, csv.state.count - 1, function(err, line) {
177 | 8 | return done(err, line);
178 |  | });
179 |  | } catch (_error) {}
180 |  | }
181 |  | } else {
182 | 29352 | return finish(line);
183 |  | }
184 |  | };
185 |  |
186 |  | /* no doc
187 |  | `transformer(csv).end()`
188 |  | ------------------------
189 |  |
190 |  | A transformer instance extends the EventEmitter and
191 |  | emit the 'end' event when the last callback is called.
192 |  | */
193 |  |
194 |  |
195 | 1 | Transformer.prototype.end = function() {
196 | 73 | if (this.closed) {
197 | 0 | return this.csv.error(new Error('Transformer already closed'));
198 |  | }
199 | 73 | this.closed = true;
200 | 73 | if (this.csv.state.transforming === 0) {
201 | 70 | return this.emit('end');
202 |  | }
203 |  | };
204 |  |
205 | 1 | module.exports = function(csv) {
206 | 78 | return new Transformer(csv);
207 |  | };
208 |  |
209 | 1 | module.exports.Transformer = Transformer;

## generator.js

97%
43
42
1

Line | Hits | Source
--- | --- | ---
1 |  | // Generated by CoffeeScript 1.3.3
2 | 1 | var Generator, Stream, util;
3 |  |
4 | 1 | Stream = require('stream');
5 |  |
6 | 1 | util = require('util');
7 |  |
8 |  | /*
9 |  |
10 |  | `generator([options])`: Generate random CSV data
11 |  | ================================================
12 |  |
13 |  | This function is provided for conveniency in case you need to generate random CSV data.
14 |  |
15 |  | Note, it is quite simple at the moment, more functionnalities could come later. The code
16 |  | originates from "./samples/perf.coffee" and was later extracted in case other persons need
17 |  | its functionnalities.
18 |  |
19 |  | Options may include
20 |  |
21 |  | * duration Period to run in milliseconds, default to 4 minutes.
22 |  | * nb_columns Number of fields per record
23 |  | * max_word_length Maximum number of characters per word
24 |  | * start Start the generation on next tick, otherwise you must call resume
25 |  |
26 |  | Starting a generation
27 |  |
28 |  | csv = require 'csv'
29 |  | generator = csv.generator
30 |  | generator(start: true).pipe csv().to.path "#{__dirname}/perf.out"
31 |  | */
32 |  |
33 |  |
34 | 1 | Generator = function(options) {
35 | 2 | var _base, _base1, _ref, _ref1;
36 | 2 | this.options = options != null ? options : {};
37 | 2 | if ((_ref = (_base = this.options).duration) == null) {
38 | 0 | _base.duration = 4 * 60 * 1000;
39 |  | }
40 | 2 | this.options.nb_columns = 8;
41 | 2 | if ((_ref1 = (_base1 = this.options).max_word_length) == null) {
42 | 2 | _base1.max_word_length = 16;
43 |  | }
44 | 2 | this.start = Date.now();
45 | 2 | this.end = this.start + this.options.duration;
46 | 2 | this.readable = true;
47 | 2 | if (this.options.start) {
48 | 2 | process.nextTick(this.resume.bind(this));
49 |  | }
50 | 2 | return this;
51 |  | };
52 |  |
53 | 1 | Generator.prototype.__proto__ = Stream.prototype;
54 |  |
55 | 1 | Generator.prototype.resume = function() {
56 | 15312 | var char, column, line, nb_chars, nb_words, _i, _j, _ref, _ref1;
57 | 15312 | this.paused = false;
58 | 15312 | while (!this.paused && this.readable) {
59 | 26288 | if (Date.now() > this.end) {
60 | 2 | return this.destroy();
61 |  | }
62 | 26286 | line = [];
63 | 26286 | for (nb_words = _i = 0, _ref = this.options.nb_columns; 0 <= _ref ? _i < _ref : _i > _ref; nb_words = 0 <= _ref ? ++_i : --_i) {
64 | 210288 | column = [];
65 | 210288 | for (nb_chars = _j = 0, _ref1 = Math.ceil(Math.random() * this.options.max_word_length); 0 <= _ref1 ? _j < _ref1 : _j > _ref1; nb_chars = 0 <= _ref1 ? ++_j : --_j) {
66 | 1785881 | char = Math.floor(Math.random() * 32);
67 | 1785881 | column.push(String.fromCharCode(char + (char < 16 ? 65 : 97 - 16)));
68 |  | }
69 | 210288 | line.push(column.join(''));
70 |  | }
71 | 26286 | this.emit('data', new Buffer("" + (line.join(',')) + "\n", this.options.encoding));
72 |  | }
73 |  | };
74 |  |
75 | 1 | Generator.prototype.pause = function() {
76 | 15310 | return this.paused = true;
77 |  | };
78 |  |
79 | 1 | Generator.prototype.destroy = function() {
80 | 2 | this.readable = false;
81 | 2 | this.emit('end');
82 | 2 | return this.emit('close');
83 |  | };
84 |  |
85 |  | /*
86 |  | `setEncoding([encoding])`
87 |  |
88 |  | Makes the 'data' event emit a string instead of a Buffer.
89 |  | encoding can be 'utf8', 'utf16le' ('ucs2'), 'ascii', or
90 |  | 'hex'. Defaults to 'utf8'.
91 |  | */
92 |  |
93 |  |
94 | 1 | Generator.prototype.setEncoding = function(encoding) {
95 | 1 | return this.options.encoding = encoding;
96 |  | };
97 |  |
98 | 1 | module.exports = function(options) {
99 | 2 | return new Generator(options);
100 |  | };
101 |  |
102 | 1 | module.exports.Generator = Generator;