From 49087390f1eadce848eab9537e5273666c07d590 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Sun, 27 Oct 2024 16:16:46 +0000 Subject: [PATCH] Use stream.pipeline() --- README.md | 64 ++++++++++++++------------ src/helpers/gulpfiles/stream.test.js | 69 ++++++++++++++++------------ src/helpers/methods.test.js | 15 ++++-- src/main.d.ts | 54 ++++++++++++---------- src/main.test-d.ts | 4 +- src/stream/main.js | 4 +- 6 files changed, 120 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 0728e06..cee947d 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,10 @@ technical lead for 2.5 years. I am available for full-time remote positions. `gulpfile.js`: ```js +import { pipeline } from 'node:stream/promises' + import gulp from 'gulp' -import { task, exec, stream } from 'gulp-execa' +import { exec, stream, task } from 'gulp-execa' export const audit = task('npm audit') @@ -61,10 +63,11 @@ export const outdated = async () => { } export const sort = () => - gulp - .src('*.txt') - .pipe(stream(({ path }) => `sort ${path}`)) - .pipe(gulp.dest('sorted')) + pipeline( + gulp.src('*.txt'), + stream(({ path }) => `sort ${path}`), + gulp.dest('sorted'), + ) ``` # Install @@ -128,14 +131,17 @@ Returns a stream that executes a `command` on each input file. - `undefined` ```js +import { pipeline } from 'node:stream/promises' + import gulp from 'gulp' import { stream } from 'gulp-execa' export const sort = () => - gulp - .src('*.txt') - .pipe(stream(({ path }) => `sort ${path}`)) - .pipe(gulp.dest('sorted')) + pipeline( + gulp.src('*.txt'), + stream(({ path }) => `sort ${path}`), + gulp.dest('sorted'), + ) ``` Each file in the stream will spawn a separate process. This can consume lots of @@ -251,21 +257,22 @@ With [`stream()`](#streamfunction-options), whether the command result should: ```js +import { pipeline } from 'node:stream/promises' + import gulp from 'gulp' import { stream } from 'gulp-execa' import through from 'through2' export const task = () => - gulp - .src('*.js') + pipeline( + gulp.src('*.js'), // Prints the number of lines of each file - .pipe(stream(({ path }) => `wc -l ${path}`, { result: 'save' })) - .pipe( - through.obj((file, encoding, func) => { - console.log(file.execa[0].stdout) - func(null, file) - }), - ) + stream(({ path }) => `wc -l ${path}`, { result: 'save' }), + through.obj((file, encoding, func) => { + console.log(file.execa[0].stdout) + func(null, file) + }), + ) ``` ## from @@ -279,23 +286,22 @@ Which output stream to use with [`result: 'replace'`](#result). ```js +import { pipeline } from 'node:stream/promises' + import gulp from 'gulp' import { stream } from 'gulp-execa' import through from 'through2' export const task = () => - gulp - .src('*.js') + pipeline( + gulp.src('*.js'), // Prints the number of lines of each file, including `stderr` - .pipe( - stream(({ path }) => `wc -l ${path}`, { result: 'replace', from: 'all' }), - ) - .pipe( - through.obj((file, encoding, func) => { - console.log(file.contents.toString()) - func(null, file) - }), - ) + stream(({ path }) => `wc -l ${path}`, { result: 'replace', from: 'all' }), + through.obj((file, encoding, func) => { + console.log(file.contents.toString()) + func(null, file) + }), + ) ``` ## maxConcurrency diff --git a/src/helpers/gulpfiles/stream.test.js b/src/helpers/gulpfiles/stream.test.js index cb812d2..03c8f89 100644 --- a/src/helpers/gulpfiles/stream.test.js +++ b/src/helpers/gulpfiles/stream.test.js @@ -1,4 +1,5 @@ import { Buffer } from 'node:buffer' +import { pipeline } from 'node:stream/promises' import { fileURLToPath } from 'node:url' import { callbackify } from 'node:util' @@ -20,56 +21,63 @@ const DUMMY_TWO = fileURLToPath( // Task used in most tests export const main = () => - gulp - .src(DUMMY, { buffer }) - .pipe(stream(() => command, opts)) - .pipe(through.obj(execVinyl)) + pipeline( + gulp.src(DUMMY, { buffer }), + stream(() => command, opts), + through.obj(execVinyl), + ) // `input` should be an async function export const inputAsync = () => - gulp - .src(DUMMY, { buffer }) - .pipe(stream(() => Promise.resolve(command), opts)) - .pipe(through.obj(execVinyl)) + pipeline( + gulp.src(DUMMY, { buffer }), + stream(() => Promise.resolve(command), opts), + through.obj(execVinyl), + ) // `input` should be fired with the Vinyl file export const inputFile = () => - gulp - .src(DUMMY, { buffer }) - .pipe(stream(({ basename }) => `${command} ${basename}`, opts)) - .pipe(through.obj(execVinyl)) + pipeline( + gulp.src(DUMMY, { buffer }), + stream(({ basename }) => `${command} ${basename}`, opts), + through.obj(execVinyl), + ) const noop = () => {} // File should be skipped when returning a non-string export const inputUndefined = () => - gulp - .src(DUMMY, { buffer }) - .pipe(stream(noop, opts)) - .pipe(through.obj(execVinyl)) + pipeline( + gulp.src(DUMMY, { buffer }), + stream(noop, opts), + through.obj(execVinyl), + ) // Should allow several files export const severalFiles = () => - gulp - .src([DUMMY, DUMMY_TWO], { buffer }) - .pipe(stream(() => command, opts)) - .pipe(through.obj(execVinyl)) + pipeline( + gulp.src([DUMMY, DUMMY_TWO], { buffer }), + stream(() => command, opts), + through.obj(execVinyl), + ) // Should allow doing several times export const severalTimes = () => - gulp - .src(DUMMY, { buffer }) - .pipe(stream(() => command, opts)) - .pipe(stream(() => command, opts)) - .pipe(through.obj(execVinyl)) + pipeline( + gulp.src(DUMMY, { buffer }), + stream(() => command, opts), + stream(() => command, opts), + through.obj(execVinyl), + ) // `input` should be a function export const inputNotFunc = () => - gulp.src(DUMMY, { buffer }).pipe(stream(command, opts)) + pipeline(gulp.src(DUMMY, { buffer }), stream(command, opts)) // `input` exceptions should be propagated export const inputThrows = () => - gulp.src(DUMMY, { buffer }).pipe( + pipeline( + gulp.src(DUMMY, { buffer }), stream(() => { throw new Error('error') }, opts), @@ -77,9 +85,10 @@ export const inputThrows = () => // `input` async exceptions should be propagated export const inputThrowsAsync = () => - gulp - .src(DUMMY, { buffer }) - .pipe(stream(() => Promise.reject(new Error('error')), opts)) + pipeline( + gulp.src(DUMMY, { buffer }), + stream(() => Promise.reject(new Error('error')), opts), + ) const cExecVinyl = async (file) => { // When `file.contents` is a stream and an `error` event should be emitted, diff --git a/src/helpers/methods.test.js b/src/helpers/methods.test.js index 61408ac..df91190 100644 --- a/src/helpers/methods.test.js +++ b/src/helpers/methods.test.js @@ -10,11 +10,20 @@ export const TASK_METHODS = [ ] export const STREAM_METHODS = [ - // `gulp.src(...).pipe(stream(..., { result: 'replace' }))` + // `pipeline( + // gulp.src(...), + // stream(..., { result: 'replace' }), + // )` { title: 'stream-buffer', method: 'stream' }, - // `gulp.src(..., { buffer: false }).pipe(stream(..., { result: 'replace' }))` + // `pipeline( + // gulp.src(..., { buffer: false }), + // stream(..., { result: 'replace' }), + // )` { title: 'stream-stream', method: 'stream', buffer: false }, - // `gulp.src(...).pipe(stream(..., { result: 'save' }))` + // `pipeline( + // gulp.src(...), + // stream(..., { result: 'save' }), + // )` { title: 'stream-save', method: 'stream', opts: { result: 'save' } }, ] diff --git a/src/main.d.ts b/src/main.d.ts index 100332f..c8c531d 100644 --- a/src/main.d.ts +++ b/src/main.d.ts @@ -40,20 +40,22 @@ type StreamOptions = Omit< * * @example * ```js + * import { pipeline } from 'node:stream/promises' + * * import gulp from 'gulp' + * import { stream } from 'gulp-execa' * import through from 'through2' * * export const task = () => - * gulp - * .src('*.js') + * pipeline( + * gulp.src('*.js'), * // Prints the number of lines of each file - * .pipe(stream(({ path }) => `wc -l ${path}`, { result: 'save' })) - * .pipe( - * through.obj((file, encoding, func) => { - * console.log(file.execa[0].stdout) - * func(null, file) - * }), - * ) + * stream(({ path }) => `wc -l ${path}`, { result: 'save' }), + * through.obj((file, encoding, func) => { + * console.log(file.execa[0].stdout) + * func(null, file) + * }), + * ) * ``` */ result: 'save' | 'replace' @@ -65,22 +67,22 @@ type StreamOptions = Omit< * * @example * ```js + * import { pipeline } from 'node:stream/promises' + * * import gulp from 'gulp' + * import { stream } from 'gulp-execa' * import through from 'through2' * * export const task = () => - * gulp - * .src('*.js') + * pipeline( + * gulp.src('*.js'), * // Prints the number of lines of each file, including `stderr` - * .pipe( - * stream(({ path }) => `wc -l ${path}`, { result: 'replace', from: 'all' }), - * ) - * .pipe( - * through.obj((file, encoding, func) => { - * console.log(file.contents.toString()) - * func(null, file) - * }), - * ) + * stream(({ path }) => `wc -l ${path}`, { result: 'replace', from: 'all' }), + * through.obj((file, encoding, func) => { + * console.log(file.contents.toString()) + * func(null, file) + * }), + * ) * ``` */ from: 'stdout' | 'stderr' | 'all' @@ -137,13 +139,17 @@ export function task( * * @example * ```js + * import { pipeline } from 'node:stream/promises' + * * import gulp from 'gulp' + * import { stream } from 'gulp-execa' * * export const sort = () => - * gulp - * .src('*.txt') - * .pipe(stream(({ path }) => `sort ${path}`)) - * .pipe(gulp.dest('sorted')) + * pipeline( + * gulp.src('*.txt'), + * stream(({ path }) => `sort ${path}`), + * gulp.dest('sorted'), + * ) * ``` */ export function stream( diff --git a/src/main.test-d.ts b/src/main.test-d.ts index 52f9baa..c0a72d5 100644 --- a/src/main.test-d.ts +++ b/src/main.test-d.ts @@ -1,7 +1,7 @@ import type { Readable, Transform } from 'node:stream' -import { exec, task, stream, type Options } from 'gulp-execa' -import { expectType, expectAssignable, expectNotAssignable } from 'tsd' +import { exec, stream, task, type Options } from 'gulp-execa' +import { expectAssignable, expectNotAssignable, expectType } from 'tsd' // eslint-disable-next-line n/no-extraneous-import, @typescript-eslint/no-shadow import type File from 'vinyl' diff --git a/src/stream/main.js b/src/stream/main.js index fa9f271..d160e36 100644 --- a/src/stream/main.js +++ b/src/stream/main.js @@ -6,11 +6,11 @@ import through from 'through2-concurrent' import { throwError } from '../error.js' import { parseOpts } from '../options/main.js' -import { getDefaultOpts, forcedOpts } from './options.js' +import { forcedOpts, getDefaultOpts } from './options.js' import { setResult } from './result.js' // Creates a stream that fires child processes on each file: -// gulp.src(...).pipe(stream(({ path }) => `command ${path}`)) +// pipeline(gulp.src(...), stream(({ path }) => `command ${path}`)) export const stream = (getInput, opts) => { validateGetInput(getInput)