From f662904a41ae287936c131e081b3ff8e26326d2a Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 14 Oct 2021 19:07:51 +0200 Subject: [PATCH] Update to node 12 (#50) --- .github/workflows/ci.yml | 25 +--------- README.md | 16 +----- bench.js | 10 ++-- index.js | 23 ++++++--- package.json | 4 -- test.js | 104 +++++++++++++++++++-------------------- 6 files changed, 76 insertions(+), 106 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4150a4e..7a5ded8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,35 +3,12 @@ name: ci on: [push, pull_request] jobs: - legacy: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [6.x, 8.x] - - steps: - - uses: actions/checkout@v2 - - - name: Use Node.js - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: Install - run: | - npm install - - - name: Run tests - run: | - npm run legacy - test: runs-on: ubuntu-latest strategy: matrix: - node-version: [10.x, 12.x, 13.x, 14.x] + node-version: [12.x, 14.x, 16.x] steps: - uses: actions/checkout@v2 diff --git a/README.md b/README.md index 00db262..451c6bb 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Break up a stream and reassemble it so that each line is a chunk. `split2` is inspired by [@dominictarr](https://github.com/dominictarr) [`split`](https://github.com/dominictarr/split) module, and it is totally API compatible with it. -However, it is based on Node.js core [`Transform`](https://nodejs.org/api/stream.html#stream_new_stream_transform_options) via [`readable-stream`](https://github.com/nodejs/readable-stream) +However, it is based on Node.js core [`Transform`](https://nodejs.org/api/stream.html#stream_new_stream_transform_options). `matcher` may be a `String`, or a `RegExp`. Example, read every line in a file ... @@ -68,21 +68,9 @@ fs.createReadStream(file) However, in [@dominictarr](https://github.com/dominictarr) [`split`](https://github.com/dominictarr/split) the mapper is wrapped in a try-catch, while here it is not: if your parsing logic can throw, wrap it yourself. Otherwise, you can also use the stream error handling when mapper function throw. -# Benchmark - -```bash -$ node bench.js -benchSplit*10000: 1484.983ms -benchBinarySplit*10000: 1484.080ms -benchSplit*10000: 1407.334ms -benchBinarySplit*10000: 1500.281ms -``` - -Benchmark taken on Node 8.11.3, on a Macbook i5 2018. - # License -Copyright (c) 2014-2018, Matteo Collina +Copyright (c) 2014-2021, Matteo Collina Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/bench.js b/bench.js index 7a3f9d5..15ec5df 100644 --- a/bench.js +++ b/bench.js @@ -1,9 +1,9 @@ 'use strict' -var split = require('./') -var bench = require('fastbench') -var binarySplit = require('binary-split') -var fs = require('fs') +const split = require('./') +const bench = require('fastbench') +const binarySplit = require('binary-split') +const fs = require('fs') function benchSplit (cb) { fs.createReadStream('package.json') @@ -19,7 +19,7 @@ function benchBinarySplit (cb) { .resume() } -var run = bench([ +const run = bench([ benchSplit, benchBinarySplit ], 10000) diff --git a/index.js b/index.js index fc2007b..e969e4b 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2014-2018, Matteo Collina +Copyright (c) 2014-2021, Matteo Collina Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -16,15 +16,15 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 'use strict' -const { Transform } = require('readable-stream') +const { Transform } = require('stream') const { StringDecoder } = require('string_decoder') const kLast = Symbol('last') const kDecoder = Symbol('decoder') function transform (chunk, enc, cb) { - var list + let list if (this.overflow) { // Line buffer is full. Skip to start of next line. - var buf = this[kDecoder].write(chunk) + const buf = this[kDecoder].write(chunk) list = buf.split(this.matcher) if (list.length === 1) return cb() // Line ending not found. Discard entire chunk. @@ -39,7 +39,7 @@ function transform (chunk, enc, cb) { this[kLast] = list.pop() - for (var i = 0; i < list.length; i++) { + for (let i = 0; i < list.length; i++) { try { push(this, this.mapper(list[i])) } catch (error) { @@ -48,7 +48,10 @@ function transform (chunk, enc, cb) { } this.overflow = this[kLast].length > this.maxLength - if (this.overflow && !this.skipOverflow) return cb(new Error('maximum buffer reached')) + if (this.overflow && !this.skipOverflow) { + cb(new Error('maximum buffer reached')) + return + } cb() } @@ -112,6 +115,7 @@ function split (matcher, mapper, options) { } options = Object.assign({}, options) + options.autoDestroy = true options.transform = transform options.flush = flush options.readableObjectMode = true @@ -123,8 +127,13 @@ function split (matcher, mapper, options) { stream.matcher = matcher stream.mapper = mapper stream.maxLength = options.maxLength - stream.skipOverflow = options.skipOverflow + stream.skipOverflow = options.skipOverflow || false stream.overflow = false + stream._destroy = function (err, cb) { + // Weird Node v12 bug that we need to work around + this._writableState.errorEmitted = false + cb(err) + } return stream } diff --git a/package.json b/package.json index 0775a21..5545a7d 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,7 @@ "fastbench": "^1.0.0", "nyc": "^15.0.1", "pre-commit": "^1.1.2", - "safe-buffer": "^5.1.1", "standard": "^16.0.1", "tape": "^5.0.0" - }, - "dependencies": { - "readable-stream": "^3.0.0" } } diff --git a/test.js b/test.js index e035787..964e121 100644 --- a/test.js +++ b/test.js @@ -1,16 +1,15 @@ 'use strict' -var test = require('tape') -var split = require('./') -var callback = require('callback-stream') -var Buffer = require('safe-buffer').Buffer -var strcb = callback.bind(null, { decodeStrings: false }) -var objcb = callback.bind(null, { objectMode: true }) +const test = require('tape') +const split = require('./') +const callback = require('callback-stream') +const strcb = callback.bind(null, { decodeStrings: false }) +const objcb = callback.bind(null, { objectMode: true }) test('split two lines on end', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) @@ -23,7 +22,7 @@ test('split two lines on end', function (t) { test('split two lines on two writes', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) @@ -38,7 +37,7 @@ test('split two lines on two writes', function (t) { test('split four lines on three writes', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) @@ -54,7 +53,7 @@ test('split four lines on three writes', function (t) { test('accumulate multiple writes', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) @@ -69,7 +68,7 @@ test('accumulate multiple writes', function (t) { test('split using a custom string matcher', function (t) { t.plan(2) - var input = split('~') + const input = split('~') input.pipe(strcb(function (err, list) { t.error(err) @@ -82,7 +81,7 @@ test('split using a custom string matcher', function (t) { test('split using a custom regexp matcher', function (t) { t.plan(2) - var input = split(/~/) + const input = split(/~/) input.pipe(strcb(function (err, list) { t.error(err) @@ -95,7 +94,7 @@ test('split using a custom regexp matcher', function (t) { test('support an option argument', function (t) { t.plan(2) - var input = split({ highWaterMark: 2 }) + const input = split({ highWaterMark: 2 }) input.pipe(strcb(function (err, list) { t.error(err) @@ -108,10 +107,10 @@ test('support an option argument', function (t) { test('support a mapper function', function (t) { t.plan(2) - var a = { a: '42' } - var b = { b: '24' } + const a = { a: '42' } + const b = { b: '24' } - var input = split(JSON.parse) + const input = split(JSON.parse) input.pipe(objcb(function (err, list) { t.error(err) @@ -126,7 +125,7 @@ test('support a mapper function', function (t) { test('split lines windows-style', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) @@ -139,7 +138,7 @@ test('split lines windows-style', function (t) { test('splits a buffer', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) @@ -152,7 +151,7 @@ test('splits a buffer', function (t) { test('do not end on undefined', function (t) { t.plan(2) - var input = split(function (line) { }) + const input = split(function (line) { }) input.pipe(strcb(function (err, list) { t.error(err) @@ -165,7 +164,7 @@ test('do not end on undefined', function (t) { test('has destroy method', function (t) { t.plan(1) - var input = split(function (line) { }) + const input = split(function (line) { }) input.on('close', function () { t.ok(true, 'close emitted') @@ -178,9 +177,9 @@ test('has destroy method', function (t) { test('support custom matcher and mapper', function (t) { t.plan(4) - var a = { a: '42' } - var b = { b: '24' } - var input = split('~', JSON.parse) + const a = { a: '42' } + const b = { b: '24' } + const input = split('~', JSON.parse) t.equal(input.matcher, '~') t.equal(typeof input.mapper, 'function') @@ -198,7 +197,7 @@ test('support custom matcher and mapper', function (t) { test('support custom matcher and options', function (t) { t.plan(6) - var input = split('~', { highWaterMark: 1024 }) + const input = split('~', { highWaterMark: 1024 }) t.equal(input.matcher, '~') t.equal(typeof input.mapper, 'function') @@ -216,9 +215,9 @@ test('support custom matcher and options', function (t) { test('support mapper and options', function (t) { t.plan(6) - var a = { a: '42' } - var b = { b: '24' } - var input = split(JSON.parse, { highWaterMark: 1024 }) + const a = { a: '42' } + const b = { b: '24' } + const input = split(JSON.parse, { highWaterMark: 1024 }) t.ok(input.matcher instanceof RegExp, 'matcher is RegExp') t.equal(typeof input.mapper, 'function') @@ -238,15 +237,15 @@ test('support mapper and options', function (t) { test('split utf8 chars', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) t.deepEqual(list, ['烫烫烫', '锟斤拷']) })) - var buf = Buffer.from('烫烫烫\r\n锟斤拷', 'utf8') - for (var i = 0; i < buf.length; ++i) { + const buf = Buffer.from('烫烫烫\r\n锟斤拷', 'utf8') + for (let i = 0; i < buf.length; ++i) { input.write(buf.slice(i, i + 1)) } input.end() @@ -255,16 +254,16 @@ test('split utf8 chars', function (t) { test('split utf8 chars 2by2', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) t.deepEqual(list, ['烫烫烫', '烫烫烫']) })) - var str = '烫烫烫\r\n烫烫烫' - var buf = Buffer.from(str, 'utf8') - for (var i = 0; i < buf.length; i += 2) { + const str = '烫烫烫\r\n烫烫烫' + const buf = Buffer.from(str, 'utf8') + for (let i = 0; i < buf.length; i += 2) { input.write(buf.slice(i, i + 2)) } input.end() @@ -273,7 +272,7 @@ test('split utf8 chars 2by2', function (t) { test('split lines when the \n comes at the end of a chunk', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) @@ -287,15 +286,15 @@ test('split lines when the \n comes at the end of a chunk', function (t) { test('truncated utf-8 char', function (t) { t.plan(2) - var input = split() + const input = split() input.pipe(strcb(function (err, list) { t.error(err) t.deepEqual(list, ['烫' + Buffer.from('e7', 'hex').toString()]) })) - var str = '烫烫' - var buf = Buffer.from(str, 'utf8') + const str = '烫烫' + const buf = Buffer.from(str, 'utf8') input.write(buf.slice(0, 3)) input.end(buf.slice(3, 4)) @@ -304,17 +303,18 @@ test('truncated utf-8 char', function (t) { test('maximum buffer limit', function (t) { t.plan(1) - var input = split({ maxLength: 2 }) - - input.pipe(strcb(function (err, list) { + const input = split({ maxLength: 2 }) + input.on('error', function (err) { t.ok(err) - })) + }) + + input.resume() input.write('hey') }) test('readable highWaterMark', function (t) { - var input = split() + const input = split() t.equal(input._readableState.highWaterMark, 16) t.end() }) @@ -322,7 +322,7 @@ test('readable highWaterMark', function (t) { test('maxLength < chunk size', function (t) { t.plan(2) - var input = split({ maxLength: 2 }) + const input = split({ maxLength: 2 }) input.pipe(strcb(function (err, list) { t.error(err) @@ -335,7 +335,7 @@ test('maxLength < chunk size', function (t) { test('maximum buffer limit w/skip', function (t) { t.plan(2) - var input = split({ maxLength: 2, skipOverflow: true }) + const input = split({ maxLength: 2, skipOverflow: true }) input.pipe(strcb(function (err, list) { t.error(err) @@ -351,8 +351,8 @@ test('maximum buffer limit w/skip', function (t) { test("don't modify the options object", function (t) { t.plan(2) - var options = {} - var input = split(options) + const options = {} + const input = split(options) input.pipe(strcb(function (err, list) { t.error(err) @@ -364,8 +364,8 @@ test("don't modify the options object", function (t) { test('mapper throws flush', function (t) { t.plan(1) - var error = new Error() - var input = split(function () { + const error = new Error() + const input = split(function () { throw error }) @@ -376,10 +376,10 @@ test('mapper throws flush', function (t) { }) test('mapper throws on transform', function (t) { - t.plan(2) + t.plan(1) - var error = new Error() - var input = split(function (l) { + const error = new Error() + const input = split(function (l) { throw error })