From b6eaa0abd4de2e17ec7f33ce2966be6880990d6c Mon Sep 17 00:00:00 2001 From: Felix Kling Date: Fri, 30 Nov 2018 16:25:51 -0800 Subject: [PATCH] Enable reading file/directory list from stdin This adds the `--stdin` flag, which makes jscodeshift read the list of files and directories to process from standard input instead of command line arguments. Given that jscodeshift is getting input from multiple sources (file list, transformer code, source code), there are obviously multiple options for what should be accepted on the standard input. My more longer term idea is to be able to accept any of these on stdin. The first step is the file/directory list. I decided to add the `--stdin` flag instead of reading from stdin by default, to require the user to be explicit about their intention. In the future I could imagine the other inputs being provided on stdin by using `-` as argument value. This is in-line with other commands, like `cat`. E.g. reading the transform from stdin could be done via `--transform -`. Similarly getting the source code from stdin could be done by passing `-` as a single positional argument. --- bin/__tests__/jscodeshift-test.js | 29 ++++++++++++++++++++++++++--- bin/jscodeshift.js | 27 +++++++++++++++++++++------ src/argsParser.js | 2 ++ 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/bin/__tests__/jscodeshift-test.js b/bin/__tests__/jscodeshift-test.js index 156cb229..56fc78fb 100644 --- a/bin/__tests__/jscodeshift-test.js +++ b/bin/__tests__/jscodeshift-test.js @@ -26,6 +26,10 @@ var testUtils = require('../../utils/testUtils'); var createTransformWith = testUtils.createTransformWith; var createTempFileWith = testUtils.createTempFileWith; +function readFile(path) { + return fs.readFileSync(path).toString(); +} + function run(args, stdin, cwd) { return new Promise(resolve => { var jscodeshift = child_process.spawn( @@ -64,19 +68,37 @@ describe('jscodeshift CLI', () => { run(['-t', transformA, sourceA, sourceB]).then( out => { expect(out[1]).toBe(''); - expect(fs.readFileSync(sourceA).toString()).toBe('transforma'); - expect(fs.readFileSync(sourceB).toString()).toBe('transformb\n'); + expect(readFile(sourceA)).toBe('transforma'); + expect(readFile(sourceB)).toBe('transformb\n'); } ), run(['-t', transformB, sourceC]).then( out => { expect(out[1]).toBe(''); - expect(fs.readFileSync(sourceC).toString()).toBe(sourceC); + expect(readFile(sourceC)).toBe(sourceC); } ) ]); }); + it('takes file list from stdin if --stdin is set', () => { + var sourceA = createTempFileWith('a'); + var sourceB = createTempFileWith('b\n'); + var sourceC = createTempFileWith('c'); + var transformA = createTransformWith( + 'return "transform" + fileInfo.source;' + ); + + return run(['--stdin', '-t', transformA], [sourceA, sourceB, sourceC].join('\n')).then( + out => { + expect(out[1]).toBe(''); + expect(readFile(sourceA)).toBe('transforma'); + expect(readFile(sourceB)).toBe('transformb\n'); + expect(readFile(sourceC)).toBe('transformc'); + } + ); + }); + it('does not transform files in a dry run', () => { var source = createTempFileWith('a'); var transform = createTransformWith( @@ -300,4 +322,5 @@ describe('jscodeshift CLI', () => { ); }); }) + }); diff --git a/bin/jscodeshift.js b/bin/jscodeshift.js index c34460e6..6c129e6e 100755 --- a/bin/jscodeshift.js +++ b/bin/jscodeshift.js @@ -101,12 +101,17 @@ const parser = require('../src/argsParser') ].join('\n'); }, }, + stdin: { + help: 'read file/directory list from stdin', + flag: true, + default: false, + }, }); let options, positionalArguments; try { ({options, positionalArguments} = parser.parse()); - if (positionalArguments.length === 0) { + if (positionalArguments.length === 0 && !options.stdin) { process.stderr.write( 'Error: You have to provide at least one file/directory to transform.' + '\n\n---\n\n' + @@ -120,8 +125,18 @@ try { process.exit(exitCode); } -Runner.run( - /^https?/.test(options.transform) ? options.transform : path.resolve(options.transform), - positionalArguments, - options -); +function run(paths, options) { + Runner.run( + /^https?/.test(options.transform) ? options.transform : path.resolve(options.transform), + paths, + options + ); +} + +if (options.stdin) { + let buffer = ''; + process.stdin.on('data', data => buffer += data); + process.stdin.on('end', () => run(buffer.split('\n'), options)); +} else { + run(positionalArguments, options); +} diff --git a/src/argsParser.js b/src/argsParser.js index 72b4cd42..b650b59d 100644 --- a/src/argsParser.js +++ b/src/argsParser.js @@ -56,8 +56,10 @@ function getHelpText(options) { Usage: jscodeshift [OPTION]... PATH... or: jscodeshift [OPTION]... -t TRANSFORM_PATH PATH... or: jscodeshift [OPTION]... -t URL PATH... + or: jscodeshift [OPTION]... --stdin < file_list.txt Apply transform logic in TRANSFORM_PATH (recursively) to every PATH. +If --stdin is set, each line of the standard input is used as a path. Options: "..." behind an option means that it can be supplied multiple times.