diff --git a/README.md b/README.md index f7d9a8c..03d67ca 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Install with * `options` - Object * `readChunk` - Integer number of bytes to read at once. Default: 1024 * `newLineCharacter` - String new line character, only works with one byte characters for now. Default: `\n` which is `0x0a` hex encoded + * `lineTrimCR` bool - If set to true, carriege return character - `0x0d` will be trimmed if found at the end of a line. Default: false `node-readlines` can handle files without newLineCharacter after the last line diff --git a/package-lock.json b/package-lock.json index 9a0d05f..4b8ac87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "n-readlines", - "version": "1.0.0", + "version": "1.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -16,7 +16,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -38,8 +38,8 @@ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "foreach": "2.0.5", - "object-keys": "1.0.11" + "foreach": "^2.0.5", + "object-keys": "^1.0.8" } }, "defined": { @@ -54,11 +54,11 @@ "integrity": "sha512-ZnQrE/lXTTQ39ulXZ+J1DTFazV9qBy61x2bY071B+qGco8Z8q1QddsLdt/EF8Ai9hcWH72dWS0kFqXLxOxqslA==", "dev": true, "requires": { - "es-to-primitive": "1.1.1", - "function-bind": "1.1.1", - "has": "1.0.1", - "is-callable": "1.1.3", - "is-regex": "1.0.4" + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" } }, "es-to-primitive": { @@ -67,9 +67,9 @@ "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", "dev": true, "requires": { - "is-callable": "1.1.3", - "is-date-object": "1.0.1", - "is-symbol": "1.0.1" + "is-callable": "^1.1.1", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.1" } }, "for-each": { @@ -78,7 +78,7 @@ "integrity": "sha1-LEBFC5NI6X8oEyJZO6lnBLmr1NQ=", "dev": true, "requires": { - "is-function": "1.0.1" + "is-function": "~1.0.0" } }, "foreach": { @@ -105,7 +105,7 @@ "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.0.2" } }, "inflight": { @@ -114,8 +114,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -148,7 +148,7 @@ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "has": "1.0.1" + "has": "^1.0.1" } }, "is-symbol": { @@ -175,7 +175,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "path-is-absolute": { @@ -196,7 +196,7 @@ "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "resumer": { @@ -205,7 +205,7 @@ "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", "dev": true, "requires": { - "through": "2.3.8" + "through": "~2.3.4" } }, "string.prototype.trim": { @@ -214,9 +214,9 @@ "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", "dev": true, "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.11.0", - "function-bind": "1.1.1" + "define-properties": "^1.1.2", + "es-abstract": "^1.5.0", + "function-bind": "^1.0.2" } }, "tape": { @@ -225,19 +225,19 @@ "integrity": "sha512-j0jO9BiScfqtPBb9QmPLL0qvxXMz98xjkMb7x8lKipFlJZwNJkqkWPou+NU4V6T9RnVh1kuSthLE8gLrN8bBfw==", "dev": true, "requires": { - "deep-equal": "1.0.1", - "defined": "1.0.0", - "for-each": "0.3.2", - "function-bind": "1.1.1", - "glob": "7.1.2", - "has": "1.0.1", - "inherits": "2.0.3", - "minimist": "1.2.0", - "object-inspect": "1.5.0", - "resolve": "1.5.0", - "resumer": "0.0.0", - "string.prototype.trim": "1.1.2", - "through": "2.3.8" + "deep-equal": "~1.0.1", + "defined": "~1.0.0", + "for-each": "~0.3.2", + "function-bind": "~1.1.1", + "glob": "~7.1.2", + "has": "~1.0.1", + "inherits": "~2.0.3", + "minimist": "~1.2.0", + "object-inspect": "~1.5.0", + "resolve": "~1.5.0", + "resumer": "~0.0.0", + "string.prototype.trim": "~1.1.2", + "through": "~2.3.8" }, "dependencies": { "glob": { @@ -246,12 +246,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "minimatch": { @@ -260,7 +260,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { diff --git a/readlines.js b/readlines.js index 6b8bdc1..e1f0113 100644 --- a/readlines.js +++ b/readlines.js @@ -11,6 +11,9 @@ class LineByLine { if (!options.readChunk) options.readChunk = 1024; + // Trim carriege return CR 0x0D if found at the end of a line. + if (!options.lineTrimCR) options.lineTrimCR = false; + if (!options.newLineCharacter) { options.newLineCharacter = 0x0a; //linux line ending } else { @@ -26,6 +29,7 @@ class LineByLine { this.options = options; this.newLineCharacter = options.newLineCharacter; + this.crCharacter = 0x0d; this.reset(); } @@ -152,6 +156,10 @@ class LineByLine { line = line.slice(0, line.length-1); } + if (this.options.lineTrimCR === true && line && line[line.length-1] === this.crCharacter) { + line = line.slice(0, line.length-1); + } + return line; } } diff --git a/test/fixtures/linesWithCR.txt b/test/fixtures/linesWithCR.txt new file mode 100644 index 0000000..a9eb9e9 --- /dev/null +++ b/test/fixtures/linesWithCR.txt @@ -0,0 +1,3 @@ +line1here +line2here +line3here diff --git a/test/readlines.test.js b/test/readlines.test.js index 970836f..03a8e7c 100644 --- a/test/readlines.test.js +++ b/test/readlines.test.js @@ -88,7 +88,6 @@ test('should reset and start from the beggining', (t) => { test('should read big lines', (t) => { const liner = new lineByLine(path.resolve(__dirname, 'fixtures/bigLines.json')); - t.ok(JSON.parse(liner.next()), 'line 0: valid JSON'); t.ok(JSON.parse(liner.next()), 'line 1: valid JSON'); @@ -130,3 +129,27 @@ test('should correctly processes NULL character in lines', (t) => { t.equals(liner.fd, null, 'fd is null'); t.end(); }) + +test('should NOT trim CR characters at the end of the line', (t) => { + const liner = new lineByLine(path.resolve(__dirname, 'fixtures/linesWithCR.txt')); + + t.equals(liner.next().toString(), 'line1here\r'); + t.equals(liner.next().toString(), 'line2here\r'); + t.equals(liner.next().toString(), 'line3here\r'); + + t.equals(liner.fd, null, 'fd is null'); + t.end(); +}) + +test('should trim CR characters at the end of the line', (t) => { + const liner = new lineByLine(path.resolve(__dirname, 'fixtures/linesWithCR.txt'), { + 'lineTrimCR': true + }); + + t.equals(liner.next().toString(), 'line1here'); + t.equals(liner.next().toString(), 'line2here'); + t.equals(liner.next().toString(), 'line3here'); + + t.equals(liner.fd, null, 'fd is null'); + t.end(); +})