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 |
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 | }; |
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 | }; |
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 | }; |
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 | }; |
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 | }; |
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; |
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 |
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; |
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; |