diff options
Diffstat (limited to 'node_modules/line-reader')
20 files changed, 1135 insertions, 0 deletions
diff --git a/node_modules/line-reader/.eslintrc b/node_modules/line-reader/.eslintrc new file mode 100644 index 00000000000..d097e3a5629 --- /dev/null +++ b/node_modules/line-reader/.eslintrc @@ -0,0 +1,14 @@ +{ + "env": { + "node": true, + "mocha": true + }, + "extends": "airbnb/base", + "rules": { + "no-var": 0, + "indent": [2, 2, {"VariableDeclarator": { "var": 2 }}], + "func-names": 0, + "strict": [2, "global"], + } +} + diff --git a/node_modules/line-reader/.npmignore b/node_modules/line-reader/.npmignore new file mode 100644 index 00000000000..68286e6b826 --- /dev/null +++ b/node_modules/line-reader/.npmignore @@ -0,0 +1,35 @@ + +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history diff --git a/node_modules/line-reader/LICENSE b/node_modules/line-reader/LICENSE new file mode 100644 index 00000000000..4202b5e08b9 --- /dev/null +++ b/node_modules/line-reader/LICENSE @@ -0,0 +1,20 @@ +Copyright (C) 2012 by Nick Ewing + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/node_modules/line-reader/README.md b/node_modules/line-reader/README.md new file mode 100644 index 00000000000..decdcad6426 --- /dev/null +++ b/node_modules/line-reader/README.md @@ -0,0 +1,166 @@ +Line Reader +=========== + +Asynchronous, buffered, line-by-line file/stream reader with support for +user-defined line separators. + +Install +------- + +`npm install line-reader` + +Usage +----- + +The `eachLine` function reads each line of the given file. Upon each new line, +the given callback function is called with two parameters: the line read and a +boolean value specifying whether the line read was the last line of the file. +If the callback returns `false`, reading will stop and the file will be closed. + + var lineReader = require('line-reader'); + + lineReader.eachLine('file.txt', function(line, last) { + console.log(line); + + if (/* done */) { + return false; // stop reading + } + }); + +`eachLine` can also be used in an asynchronous manner by providing a third +callback parameter like so: + + var lineReader = require('line-reader'); + + lineReader.eachLine('file.txt', function(line, last, cb) { + console.log(line); + + if (/* done */) { + cb(false); // stop reading + } else { + cb(); + } + }); + +You can provide an optional second node-style callback that will be called with +`(err)` on failure or `()` when finished (even if you manually terminate iteration +by returning `false` from the iteratee): + + var lineReader = require('line-reader'); + + // read all lines: + lineReader.eachLine('file.txt', function(line) { + console.log(line); + }).then(function (err) { + if (err) throw err; + console.log("I'm done!!"); + }); + +For more granular control, `open`, `hasNextLine`, and `nextLine` maybe be used +to iterate a file (but you must `close` it yourself): + + // or read line by line: + lineReader.open('file.txt', function(err, reader) { + if (err) throw err; + if (reader.hasNextLine()) { + reader.nextLine(function(err, line) { + try { + if (err) throw err; + console.log(line); + } finally { + reader.close(function(err) { + if (err) throw err; + }); + } + }); + } + else { + reader.close(function(err) { + if (err) throw err; + }); + } + }); + +You may provide additional options in a hash before the callbacks to `eachLine` or `open`: +* `separator` - a `string` or `RegExp` separator (defaults to `/\r\n?|\n/`) +* `encoding` - file encoding (defaults to `'utf8'`) +* `bufferSize` - amount of bytes to buffer (defaults to 1024) + +For example: + + lineReader.eachLine('file.txt', {separator: ';', encoding: 'utf8'}, function(line, last, cb) { + console.log(line); + }); + lineReader.open('file.txt', {bufferSize: 1024}, function(err, reader) { + ... + }); + +Streams +------- + +Both `eachLine` and `open` support passing either a file name or a read stream: + + // reading from stdin + lineReader.eachLine(process.stdin, function(line) {}); + + // reading with file position boundaries + var readStream = fs.createReadStream('test.log', { start: 0, end: 10000 }); + lineReader.eachLine(readStream, function(line) {}); + +Note however that if you're reading user input from stdin then the +[readline module](https://nodejs.org/api/readline.html) is probably a better choice. + +Promises +-------- + +`eachLine` and `open` are compatible with `promisify` from [bluebird](https://github.com/petkaantonov/bluebird/blob/master/API.md#promisepromisifyfunction-nodefunction--dynamic-receiver---function): + + var lineReader = require('line-reader'), + Promise = require('bluebird'); + + var eachLine = Promise.promisify(lineReader.eachLine); + eachLine('file.txt', function(line) { + console.log(line); + }).then(function() { + console.log('done'); + }).catch(function(err) { + console.error(err); + }); + +If you're using a promise library that doesn't have a promisify function, here's how you can do it: + + var lineReader = require('line-reader'), + Promise = require(...); + + var eachLine = function(filename, options, iteratee) { + return new Promise(function(resolve, reject) { + lineReader.eachLine(filename, options, iteratee, function(err) { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + } + eachLine('file.txt', function(line) { + console.log(line); + }).then(function() { + console.log('done'); + }).catch(function(err) { + console.error(err); + }); + +Contributors +------------ + +* Nick Ewing +* Andy Edwards (jedwards1211) +* Jameson Little (beatgammit) +* Masum (masumsoft) +* Matthew Caruana Galizia (mattcg) +* Ricardo Bin (ricardohbin) + +Paul Em has also written a reverse-version of this gem to read files from bottom to top: [reverse-line-reader](https://github.com/paul-em/reverse-line-reader). + +Copyright 2011 Nick Ewing. diff --git a/node_modules/line-reader/lib/line_reader.js b/node_modules/line-reader/lib/line_reader.js new file mode 100644 index 00000000000..f1fd87342a2 --- /dev/null +++ b/node_modules/line-reader/lib/line_reader.js @@ -0,0 +1,306 @@ +'use strict'; + +var fs = require('fs'), + StringDecoder = require('string_decoder').StringDecoder; + +function createLineReader(readStream, options, creationCb) { + if (options instanceof Function) { + creationCb = options; + options = undefined; + } + if (!options) options = {}; + + var encoding = options.encoding || 'utf8', + separator = options.separator || /\r\n?|\n/, + bufferSize = options.bufferSize || 1024, + bufferStr = '', + decoder = new StringDecoder(encoding), + closed = false, + eof = false, + separatorIndex = -1, + separatorLen, + readDefer, + moreToRead = false, + findSeparator; + + if (separator instanceof RegExp) { + findSeparator = function() { + var result = separator.exec(bufferStr); + if (result && (result.index + result[0].length < bufferStr.length || eof)) { + separatorIndex = result.index; + separatorLen = result[0].length; + } else { + separatorIndex = -1; + separatorLen = 0; + } + }; + } else { + separatorLen = separator.length; + findSeparator = function() { + separatorIndex = bufferStr.indexOf(separator); + }; + } + + function getReadStream() { + return readStream; + } + + function close(cb) { + if (!closed) { + closed = true; + if (typeof readStream.close == 'function') { + readStream.close(); + } + setImmediate(cb); + } + } + + function onFailure(err) { + close(function(err2) { + return creationCb(err || err2); + }); + } + + function isOpen() { + return !closed; + } + + function isClosed() { + return closed; + } + + function waitForMoreToRead(cb) { + if (moreToRead) { + cb(); + } else { + readDefer = cb; + } + } + + function resumeDeferredRead() { + if (readDefer) { + readDefer(); + readDefer = null; + } + } + + function read(cb) { + waitForMoreToRead(function() { + var chunk; + + try { + chunk = readStream.read(bufferSize); + } catch (err) { + cb(err); + } + + if (chunk) { + bufferStr += decoder.write(chunk.slice(0, chunk.length)); + } else { + moreToRead = false; + } + + cb(); + }); + } + + function onStreamReadable() { + moreToRead = true; + resumeDeferredRead(); + } + + function onStreamEnd() { + eof = true; + resumeDeferredRead(); + } + + readStream.on('readable', onStreamReadable); + readStream.on('end', onStreamEnd); + readStream.on('error', onFailure); + + function shouldReadMore() { + findSeparator(); + + return separatorIndex < 0 && !eof; + } + + function callWhile(conditionFn, bodyFn, doneCallback) { + if (conditionFn()) { + bodyFn(function (err) { + if (err) { + doneCallback(err); + } else { + setImmediate(callWhile, conditionFn, bodyFn, doneCallback); + } + }); + } else { + doneCallback(); + } + } + + function readToSeparator(cb) { + callWhile(shouldReadMore, read, cb); + } + + function hasNextLine() { + return bufferStr.length > 0 || !eof; + } + + function nextLine(cb) { + if (closed) { + return cb(new Error('LineReader has been closed')); + } + + function getLine(err) { + if (err) { + return cb(err); + } + + if (separatorIndex < 0 && eof) { + separatorIndex = bufferStr.length; + } + var ret = bufferStr.substring(0, separatorIndex); + + bufferStr = bufferStr.substring(separatorIndex + separatorLen); + separatorIndex = -1; + cb(undefined, ret); + } + + findSeparator(); + + if (separatorIndex < 0) { + if (eof) { + if (hasNextLine()) { + separatorIndex = bufferStr.length; + getLine(); + } else { + return cb(new Error('No more lines to read.')); + } + } else { + readToSeparator(getLine); + } + } else { + getLine(); + } + } + + readToSeparator(function(err) { + if (err) { + onFailure(err); + } else { + return creationCb(undefined, { + hasNextLine: hasNextLine, + nextLine: nextLine, + close: close, + isOpen: isOpen, + isClosed: isClosed, + getReadStream: getReadStream + }); + } + }); +} + +function open(filenameOrStream, options, cb) { + if (options instanceof Function) { + cb = options; + options = undefined; + } + + var readStream; + + if (typeof filenameOrStream.read == 'function') { + readStream = filenameOrStream; + } else if (typeof filenameOrStream === 'string' || filenameOrStream instanceof String) { + readStream = fs.createReadStream(filenameOrStream); + } else { + cb(new Error('Invalid file argument for LineReader.open. Must be filename or stream.')); + return; + } + + readStream.pause(); + createLineReader(readStream, options, cb); +} + +function eachLine(filename, options, iteratee, cb) { + if (options instanceof Function) { + cb = iteratee; + iteratee = options; + options = undefined; + } + var asyncIteratee = iteratee.length === 3; + + var theReader; + var getReaderCb; + + open(filename, options, function(err, reader) { + theReader = reader; + if (getReaderCb) { + getReaderCb(reader); + } + + if (err) { + if (cb) cb(err); + return; + } + + function finish(err) { + reader.close(function(err2) { + if (cb) cb(err || err2); + }); + } + + function newRead() { + if (reader.hasNextLine()) { + setImmediate(readNext); + } else { + finish(); + } + } + + function continueCb(continueReading) { + if (continueReading !== false) { + newRead(); + } else { + finish(); + } + } + + function readNext() { + reader.nextLine(function(err, line) { + if (err) { + finish(err); + } + + var last = !reader.hasNextLine(); + + if (asyncIteratee) { + iteratee(line, last, continueCb); + } else { + if (iteratee(line, last) !== false) { + newRead(); + } else { + finish(); + } + } + }); + } + + newRead(); + }); + + // this hook is only for the sake of testing; if you choose to use it, + // please don't file any issues (unless you can also reproduce them without + // using this). + return { + getReader: function(cb) { + if (theReader) { + cb(theReader); + } else { + getReaderCb = cb; + } + } + }; +} + +module.exports.open = open; +module.exports.eachLine = eachLine; diff --git a/node_modules/line-reader/package.json b/node_modules/line-reader/package.json new file mode 100644 index 00000000000..7915ce24dc2 --- /dev/null +++ b/node_modules/line-reader/package.json @@ -0,0 +1,61 @@ +{ + "name": "line-reader", + "version": "0.4.0", + "description": "Asynchronous, buffered, line-by-line file/stream reader", + "url": "https://github.com/nickewing/line-reader", + "keywords": [ + "file", + "line", + "reader", + "scanner" + ], + "author": { + "name": "Nick Ewing", + "email": "nick@nickewing.net" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/nickewing/line-reader/issues" + }, + "directories": { + "lib": "./lib" + }, + "main": "./lib/line_reader", + "scripts": { + "test": "mocha test/line_reader.js" + }, + "repository": { + "type": "git", + "url": "git+https://nickewing@github.com/nickewing/line-reader.git" + }, + "devDependencies": { + "mocha": "^2.4.5" + }, + "gitHead": "bd38cc8c5483e4b6799c01bc9b88819fda1461c7", + "homepage": "https://github.com/nickewing/line-reader#readme", + "_id": "line-reader@0.4.0", + "_shasum": "17e44818da0ac335675ba300954f94ef670e66fd", + "_from": "line-reader@*", + "_npmVersion": "3.6.0", + "_nodeVersion": "5.6.0", + "_npmUser": { + "name": "nickewing", + "email": "nick@nickewing.net" + }, + "maintainers": [ + { + "name": "nickewing", + "email": "nick@nickewing.net" + } + ], + "dist": { + "shasum": "17e44818da0ac335675ba300954f94ef670e66fd", + "tarball": "https://registry.npmjs.org/line-reader/-/line-reader-0.4.0.tgz" + }, + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/line-reader-0.4.0.tgz_1458196332410_0.8783941068686545" + }, + "_resolved": "https://registry.npmjs.org/line-reader/-/line-reader-0.4.0.tgz", + "readme": "ERROR: No README data found!" +} diff --git a/node_modules/line-reader/test.js b/node_modules/line-reader/test.js new file mode 100644 index 00000000000..b8bfa55d330 --- /dev/null +++ b/node_modules/line-reader/test.js @@ -0,0 +1,89 @@ +// var file = './test/data/multibyte_file.txt'; +var file = './test/data/three_line_file.txt'; +// var file = './test/data/mac_os_9_file.txt'; +// var file = './test/data/separator_file.txt'; + +var util = require('util'); + +// var lineReader = require('readline').createInterface({ + // input: require('fs').createReadStream(file) +// }); + +// lineReader.on('line', function (line) { + // console.log('Line from file:', util.inspect(line)); +// }); + + + +var fs = require('fs'); + +// var readStream = fs.createReadStream(file); +// // var hash = crypto.createHash('sha1'); + +// readStream + // .on('readable', function () { + // var chunk; + // while (null !== (chunk = readStream.read())) { + // console.log(chunk.length); + // } + // }) + // .on('end', function () { + // console.log('done!'); + // }); + + + +// var readable = process.stdin; +// + +// var readable = fs.createReadStream(file); +// readable.pause(); + +// console.log(readable.isPaused()); + +// readable.on('readable', () => { + // var chunk; + // console.log('called'); + // while (null !== (chunk = readable.read(4))) { + // console.log('got %d bytes of data: %s', chunk.length, util.inspect(chunk.toString())); + // } +// }); + +// readable.on('end', () => { + // console.log('done!'); +// }); +// +// + +var lineReader = require('./lib/line_reader'); +var readStream = fs.createReadStream('development.log', { start: 0, end: 10000 }); +lineReader.eachLine(readStream, (line) => console.log(line)); + + + +// var lineReader = require('./lib/line_reader'), + // Promise = require('bluebird'); + +// var eachLine = Promise.promisify(lineReader.eachLine); +// eachLine(process.stdin, function(line) { + // console.log(line); +// }).then(function() { + // console.log('DONE'); +// }).catch(function(err) { + // console.error(err); +// }); + + +// const readline = require('readline'); + +// const rl = readline.createInterface({ + // input: process.stdin, + // output: process.stdout +// }); + +// rl.question('What do you think of Node.js? ', (answer) => { + // TODO: Log the answer in a database + // console.log('Thank you for your valuable feedback:', answer); + + // rl.close(); +// }); diff --git a/node_modules/line-reader/test/data/empty_file.txt b/node_modules/line-reader/test/data/empty_file.txt new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/node_modules/line-reader/test/data/empty_file.txt diff --git a/node_modules/line-reader/test/data/mac_os_9_file.txt b/node_modules/line-reader/test/data/mac_os_9_file.txt new file mode 100644 index 00000000000..b6fb9c0ceab --- /dev/null +++ b/node_modules/line-reader/test/data/mac_os_9_file.txt @@ -0,0 +1 @@ +Jabberwocky
’Twas brillig, and the slithy toves
Did gyre and gimble in the wabe;
\ No newline at end of file diff --git a/node_modules/line-reader/test/data/multi_separator_file.txt b/node_modules/line-reader/test/data/multi_separator_file.txt new file mode 100644 index 00000000000..dd6e9d9b510 --- /dev/null +++ b/node_modules/line-reader/test/data/multi_separator_file.txt @@ -0,0 +1,2 @@ +foo||bar +||baz diff --git a/node_modules/line-reader/test/data/multibyte_file.txt b/node_modules/line-reader/test/data/multibyte_file.txt new file mode 100644 index 00000000000..34d7f1682ad --- /dev/null +++ b/node_modules/line-reader/test/data/multibyte_file.txt @@ -0,0 +1,2 @@ +ふうりうの初やおくの田植うた + diff --git a/node_modules/line-reader/test/data/normal_file.txt b/node_modules/line-reader/test/data/normal_file.txt new file mode 100644 index 00000000000..27efca4a4ca --- /dev/null +++ b/node_modules/line-reader/test/data/normal_file.txt @@ -0,0 +1,6 @@ +Jabberwocky + +’Twas brillig, and the slithy toves +Did gyre and gimble in the wabe; + + diff --git a/node_modules/line-reader/test/data/one_line_file.txt b/node_modules/line-reader/test/data/one_line_file.txt new file mode 100644 index 00000000000..dfcec8b8886 --- /dev/null +++ b/node_modules/line-reader/test/data/one_line_file.txt @@ -0,0 +1 @@ +one line file diff --git a/node_modules/line-reader/test/data/one_line_file_no_endline.txt b/node_modules/line-reader/test/data/one_line_file_no_endline.txt new file mode 100644 index 00000000000..c727740fd8b --- /dev/null +++ b/node_modules/line-reader/test/data/one_line_file_no_endline.txt @@ -0,0 +1 @@ +one line file no endline
\ No newline at end of file diff --git a/node_modules/line-reader/test/data/separator_file.txt b/node_modules/line-reader/test/data/separator_file.txt new file mode 100644 index 00000000000..0c948c02bbc --- /dev/null +++ b/node_modules/line-reader/test/data/separator_file.txt @@ -0,0 +1,2 @@ +foo;bar +;baz diff --git a/node_modules/line-reader/test/data/three_line_file.txt b/node_modules/line-reader/test/data/three_line_file.txt new file mode 100644 index 00000000000..90a453c31e3 --- /dev/null +++ b/node_modules/line-reader/test/data/three_line_file.txt @@ -0,0 +1,3 @@ +This is line one. +This is line two. +This is line three. diff --git a/node_modules/line-reader/test/data/unix_file.txt b/node_modules/line-reader/test/data/unix_file.txt new file mode 100644 index 00000000000..27efca4a4ca --- /dev/null +++ b/node_modules/line-reader/test/data/unix_file.txt @@ -0,0 +1,6 @@ +Jabberwocky + +’Twas brillig, and the slithy toves +Did gyre and gimble in the wabe; + + diff --git a/node_modules/line-reader/test/data/windows_buffer_overlap_file.txt b/node_modules/line-reader/test/data/windows_buffer_overlap_file.txt new file mode 100644 index 00000000000..6c8808b19f8 --- /dev/null +++ b/node_modules/line-reader/test/data/windows_buffer_overlap_file.txt @@ -0,0 +1,2 @@ +test
+file
\ No newline at end of file diff --git a/node_modules/line-reader/test/data/windows_file.txt b/node_modules/line-reader/test/data/windows_file.txt new file mode 100644 index 00000000000..baacab1fa9e --- /dev/null +++ b/node_modules/line-reader/test/data/windows_file.txt @@ -0,0 +1,6 @@ +Jabberwocky
+
+’Twas brillig, and the slithy toves
+Did gyre and gimble in the wabe;
+
+
diff --git a/node_modules/line-reader/test/line_reader.js b/node_modules/line-reader/test/line_reader.js new file mode 100644 index 00000000000..43e127dd439 --- /dev/null +++ b/node_modules/line-reader/test/line_reader.js @@ -0,0 +1,412 @@ +var lineReader = require('../lib/line_reader'), + assert = require('assert'), + fs = require('fs'), + testFilePath = __dirname + '/data/normal_file.txt', + windowsFilePath = __dirname + '/data/windows_file.txt', + windowsBufferOverlapFilePath = __dirname + '/data/windows_buffer_overlap_file.txt', + unixFilePath = __dirname + '/data/unix_file.txt', + macOs9FilePath = __dirname + '/data/mac_os_9_file.txt', + separatorFilePath = __dirname + '/data/separator_file.txt', + multiSeparatorFilePath = __dirname + '/data/multi_separator_file.txt', + multibyteFilePath = __dirname + '/data/multibyte_file.txt', + emptyFilePath = __dirname + '/data/empty_file.txt', + oneLineFilePath = __dirname + '/data/one_line_file.txt', + oneLineFileNoEndlinePath = __dirname + '/data/one_line_file_no_endline.txt', + threeLineFilePath = __dirname + '/data/three_line_file.txt', + testSeparatorFile = ['foo', 'bar\n', 'baz\n'], + testFile = [ + 'Jabberwocky', + '', + '’Twas brillig, and the slithy toves', + 'Did gyre and gimble in the wabe;', + '', + '' + ], + testBufferOverlapFile = [ + 'test', + 'file' + ]; + +describe("lineReader", function() { + describe("eachLine", function() { + it("should read lines using the default separator", function(done) { + var i = 0; + + lineReader.eachLine(testFilePath, function(line, last) { + assert.equal(testFile[i], line, 'Each line should be what we expect'); + i += 1; + + if (i === 6) { + assert.ok(last); + } else { + assert.ok(!last); + } + }, function(err) { + assert.ok(!err); + assert.equal(6, i); + done(); + }); + }); + + it("should read windows files by default", function(done) { + var i = 0; + + lineReader.eachLine(windowsFilePath, function(line, last) { + assert.equal(testFile[i], line, 'Each line should be what we expect'); + i += 1; + + if (i === 6) { + assert.ok(last); + } else { + assert.ok(!last); + } + }, function(err) { + assert.ok(!err); + assert.equal(6, i); + done(); + }); + }); + + it("should handle \\r\\n overlapping buffer window correctly", function(done) { + var i = 0; + var bufferSize = 5; + + lineReader.eachLine(windowsBufferOverlapFilePath, {bufferSize: bufferSize}, function(line, last) { + assert.equal(testBufferOverlapFile[i], line, 'Each line should be what we expect'); + i += 1; + + if (i === 2) { + assert.ok(last); + } else { + assert.ok(!last); + } + }, function(err) { + assert.ok(!err); + assert.equal(2, i); + done(); + }); + }); + + it("should read unix files by default", function(done) { + var i = 0; + + lineReader.eachLine(unixFilePath, function(line, last) { + assert.equal(testFile[i], line, 'Each line should be what we expect'); + i += 1; + + if (i === 6) { + assert.ok(last); + } else { + assert.ok(!last); + } + }, function(err) { + assert.ok(!err); + assert.equal(6, i); + done(); + }); + }); + + it("should read mac os 9 files by default", function(done) { + var i = 0; + + lineReader.eachLine(macOs9FilePath, function(line, last) { + assert.equal(testFile[i], line, 'Each line should be what we expect'); + i += 1; + + if (i === 6) { + assert.ok(last); + } else { + assert.ok(!last); + } + }, function(err) { + assert.ok(!err); + assert.equal(6, i); + done(); + }); + }); + + it("should allow continuation of line reading via a callback", function(done) { + var i = 0; + + lineReader.eachLine(testFilePath, function(line, last, cb) { + assert.equal(testFile[i], line, 'Each line should be what we expect'); + i += 1; + + if (i === 6) { + assert.ok(last); + } else { + assert.ok(!last); + } + + process.nextTick(cb); + }, function(err) { + assert.ok(!err); + assert.equal(6, i); + done(); + }); + }); + + it("should separate files using given separator", function(done) { + var i = 0; + lineReader.eachLine(separatorFilePath, {separator: ';'}, function(line, last) { + assert.equal(testSeparatorFile[i], line); + i += 1; + + if (i === 3) { + assert.ok(last); + } else { + assert.ok(!last); + } + }, function(err) { + assert.ok(!err); + assert.equal(3, i); + done(); + }); + }); + + it("should separate files using given separator with more than one character", function(done) { + var i = 0; + lineReader.eachLine(multiSeparatorFilePath, {separator: '||'}, function(line, last) { + assert.equal(testSeparatorFile[i], line); + i += 1; + + if (i === 3) { + assert.ok(last); + } else { + assert.ok(!last); + } + }, function(err) { + assert.ok(!err); + assert.equal(3, i); + done(); + }); + }); + + it("should allow early termination of line reading", function(done) { + var i = 0; + lineReader.eachLine(testFilePath, function(line, last) { + assert.equal(testFile[i], line, 'Each line should be what we expect'); + i += 1; + + if (i === 2) { + return false; + } + }, function(err) { + assert.ok(!err); + assert.equal(2, i); + done(); + }); + }); + + it("should allow early termination of line reading via a callback", function(done) { + var i = 0; + lineReader.eachLine(testFilePath, function(line, last, cb) { + assert.equal(testFile[i], line, 'Each line should be what we expect'); + i += 1; + + if (i === 2) { + cb(false); + } else { + cb(); + } + + }, function(err) { + assert.ok(!err); + assert.equal(2, i); + done(); + }); + }); + + it("should not call callback on empty file", function(done) { + lineReader.eachLine(emptyFilePath, function(line) { + assert.ok(false, "Empty file should not cause any callbacks"); + }, function(err) { + assert.ok(!err); + done() + }); + }); + + it("should error when the user tries calls nextLine on a closed LineReader", function(done) { + lineReader.open(oneLineFilePath, function(err, reader) { + assert.ok(!err); + reader.close(function(err) { + assert.ok(!err); + reader.nextLine(function(err, line) { + assert.ok(err, "nextLine should have errored because the reader is closed"); + done(); + }); + }); + }); + }); + + it("should work with a file containing only one line", function(done) { + lineReader.eachLine(oneLineFilePath, function(line, last) { + return true; + }, function(err) { + assert.ok(!err); + done(); + }); + }); + + it("should work with a file containing only one line and no endline character.", function(done) { + var count = 0; var isDone = false; + lineReader.eachLine(oneLineFileNoEndlinePath, function(line, last) { + assert.equal(last, true, 'last should be true'); + return true; + }, function(err) { + assert.ok(!err); + done(); + }); + }); + + it("should close the file when eachLine finishes", function(done) { + var reader; + lineReader.eachLine(oneLineFilePath, function(line, last) { + return false; + }, function(err) { + assert.ok(!err); + assert.ok(reader.isClosed()); + done(); + }).getReader(function(_reader) { + reader = _reader; + }); + }); + + it("should close the file if there is an error during eachLine", function(done) { + lineReader.eachLine(testFilePath, {bufferSize: 10}, function(line, last) { + }, function(err) { + assert.equal('a test error', err.message); + assert.ok(reader.isClosed()); + done(); + }).getReader(function(_reader) { + reader = _reader; + + reader.getReadStream().read = function() { + throw new Error('a test error'); + }; + }); + }); + }); + + describe("open", function() { + it("should return a reader object and allow calls to nextLine", function(done) { + lineReader.open(testFilePath, function(err, reader) { + assert.ok(!err); + assert.ok(reader.hasNextLine()); + + assert.ok(reader.hasNextLine(), 'Calling hasNextLine multiple times should be ok'); + + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal('Jabberwocky', line); + assert.ok(reader.hasNextLine()); + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal('', line); + assert.ok(reader.hasNextLine()); + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal('’Twas brillig, and the slithy toves', line); + assert.ok(reader.hasNextLine()); + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal('Did gyre and gimble in the wabe;', line); + assert.ok(reader.hasNextLine()); + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal('', line); + assert.ok(reader.hasNextLine()); + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal('', line); + assert.ok(!reader.hasNextLine()); + reader.nextLine(function(err, line) { + assert.ok(err); + done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + + it("should work with a file containing only one line", function(done) { + lineReader.open(oneLineFilePath, function(err, reader) { + assert.ok(!err); + reader.close(function(err) { + assert.ok(!err); + done(); + }); + }); + }); + + it("should read multibyte characters on the buffer boundary", function(done) { + lineReader.open(multibyteFilePath, {separator: '\n', encoding: 'utf8', bufferSize: 2}, function(err, reader) { + assert.ok(!err); + assert.ok(reader.hasNextLine()); + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal('ふうりうの初やおくの田植うた', line, + "Should read multibyte characters on buffer boundary"); + reader.close(function(err) { + assert.ok(!err); + done(); + }); + }); + }); + }); + + it("should support opened streams", function() { + var readStream = fs.createReadStream(testFilePath); + + lineReader.open(readStream, function(err, reader) { + assert.ok(!err); + assert.ok(reader.hasNextLine()); + + assert.ok(reader.hasNextLine(), 'Calling hasNextLine multiple times should be ok'); + + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal('Jabberwocky', line); + }); + }); + }); + + it("should handle error while opening read stream", function() { + lineReader.open('a file that does not exist', function(err, reader) { + assert.ok(err); + assert.ok(reader.isClosed()); + }); + }); + + describe("hasNextLine", function() { + it("should return true when buffer is empty but not at EOF", function(done) { + lineReader.open(threeLineFilePath, {separator: '\n', encoding: 'utf8', bufferSize: 36}, function(err, reader) { + assert.ok(!err); + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal("This is line one.", line); + assert.ok(reader.hasNextLine()); + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal("This is line two.", line); + assert.ok(reader.hasNextLine()); + reader.nextLine(function(err, line) { + assert.ok(!err); + assert.equal("This is line three.", line); + assert.ok(!reader.hasNextLine()); + reader.close(function(err) { + assert.ok(!err); + done(); + }) + }); + }); + }); + }); + }); + }); + }); +}); |