jscodeshift icon indicating copy to clipboard operation
jscodeshift copied to clipboard

Can jscodeshift output to a different file?

Open pbomb opened this issue 8 years ago • 14 comments

I'm building a library that creates model classes backed by Immutable.js data structures based on Flow type definitions. I would prefer my jscodeshift transform to read the Flow definition in one file but output the transformed file in a different location, but I don't see that as being supported by jscodeshift. It seems to only be set up to overwrite files it processes (which is obviously the common use case). Could anybody let me know if this is possible or if you'd suggest an alternate approach? Here's an example of what I'm trying to build:

model_defs/user.js

export type UserType {
  id: number,
  name: string,
};

The jscodeshift transform would process this file and output something like:

models/user.js

export class User {
  _state: Immutable.Map();

  constructor(

  get id(): string {
    return this._state.get('id');
  }

  setId(id: number): User {
    return new User(this._state.set('id', id));
  }

  get name(): string {
    return this._state.get('name');
  }

  setId(name: string): User {
    return new User(this._state.set('name', name));
  }
}

I have this transform working, but it currently overwrites the definition file. I've thought about copying all the matching files into a temp directory, processing those and then moving them to their final destination, but that approach seems more difficult than I'd like. I've also thought about creating my own runner that runs each file through the jscodeshift API - maybe using a dry run - and writes the desired file based on the string results of the transform. This is less than ideal as I'd be copying many aspects of the jscodeshift runner and I'm not sure yet if I can easily access the string results, but I think I will be able to.

I'm trying to take this approach so that the resulting class files are not stored in source control, but generated based solely on the type definitions. As a last resort, I could probably drop that desire in favor of overwriting previously transformed files. But I feel this approach is more confusing and prone to producing unexpected results.

Thanks for reading this long post. I'd love to hear suggestions on how best to approach this.

pbomb avatar Oct 09 '16 23:10 pbomb

In my experience, not with the command line. But you can with the API.

rossipedia avatar Oct 10 '16 03:10 rossipedia

Hi, I am new to jscodeshift.

Please can somebody explain, how we can write output to a new file, without changing the original file

SohanChotia avatar Apr 11 '20 13:04 SohanChotia

you can follow this https://github.com/igetgames/jscodeshift-demo/blob/master/index.js

pseudocode below

import jscodeshift from 'jscodeshift';

const inputFile = ...read()

const outputSource = transform(inputFile.source, jscodeshit, options)

saveOutputFile()

sibelius avatar Jun 19 '20 15:06 sibelius

I've still haven't been able to find any evidence that jscodeshift has this capability. But luckily when running on the command line you can use the node native fs methods to handle the filesystem side effects.

Run with -d for a dry run (to prevent jscodeshift from modifying the original files). Then in the codemod you can do something like this:

import fs from 'fs'

export default (fileInfo, api) => {
  const j = api.jscodeshift
  const root = j(fileInfo.source)

  // modify code as needed
  // ...

  fs.writeFile('path/to/new/file', root.toSource(), err => {
    if (err) {
      console.log(err)
    } else {
      console.log('File written')
    }
  })
}

dbchristopher avatar Apr 20 '21 19:04 dbchristopher

What if you want to build a new program from pieces of this one? For example, move some variables to a new file. I don't see an easy way to create a program body. All it wants are statements, but some things like variable declarations are not statemets, so how you build such body?

danielo515 avatar May 27 '21 16:05 danielo515

@danielo515 Maybe you can create multiple instances of the root, such as:

  const rootA = j(fileInfo.source)
  const rootB = j('')

Then remove nodes from rootA, and add them to rootB Then writeFile rootB.toSource such as @dbchristopher suggested https://github.com/facebook/jscodeshift/issues/160#issuecomment-823541122

TSMMark avatar Jan 19 '22 04:01 TSMMark

a CLI switch to save results in another folder would be much appreciated

a7madgamal avatar Jun 20 '22 07:06 a7madgamal

I believe jscodeshift does have a —print option that prints transformed files to stdout instead. Would this cover what you’re trying to do?

ElonVolo avatar Jun 20 '22 08:06 ElonVolo

tbh there are multiple workarounds for my case but still, this flag sounds like a reasonable request, just like TS can have an output folder why not here. For the record this is my use case: I'm trying to write test cases by writing a few dummy files in a folder where each file is focusing on a code feature. I wanted to commit those source files along with their transformed output to work as testing snapshots. I'm basically lazy to setup jest testing for my transformer haha 😅

a7madgamal avatar Jun 20 '22 08:06 a7madgamal

what I ended up doing is just committing the source files and just manually check the git diff after conversion and discarding it. MVP solution for now but it works

a7madgamal avatar Jun 20 '22 08:06 a7madgamal

In my evcodeshift fork of jscodeshift, I added the ability to pass an option to defineTest that create a folder in the project directory that contains all the transforms that are made during the unit tests. I had trouble with figuring out what transforms were going bad during unit tests, and the diffed output wasn't very helped, so I added in the options to save output from unit tests. See the below link for documentation on it.

(I probably need to put it in the README at some point (thought I think the general documentation on what to pass in for test options was kind of sparse).

https://github.com/ElonVolo/evcodeshift/blob/main/sample/tests/reverse-identifiers-test.js

But at this point, my understanding from the Facebook people is that they're not going to be adding any additional features to jscodeshift (I already tried adding a --gitignore flag to use the projects .gitignore to avoid transforms), so work on jscodeshift is pretty much going to be limited to bugfixes. I'm guessing that a new flag isn't going to fly with them (pun intended).

ElonVolo avatar Jun 20 '22 09:06 ElonVolo

Like @ElonVolo suggested, I'm doing this with --print like so:

jscodeshift -p -d -s -t ./transformer.ts source.ts > destination.ts

-p echoes out the result -d prevents modifications of the source file -s making sure only code is being printed out > ... saves result to destination file

A bit unorthodox, but keeps both transformers and tests hacks-free.

Testing the above transformer like so:

import { defineInlineTest } from 'jscodeshift/src/testUtils'
import { readFileSync } from 'fs';
import transform from '../transformer'

const input = readFileSync('__testfixtures__/transformer/source.ts', 'utf8');
const output = readFileSync('__testfixtures__/transformer/destination.ts', 'utf8');

defineInlineTest(transform, {}, input, output);

mgorianskyi avatar May 02 '23 19:05 mgorianskyi

Facebook is unwilling to add any additional command line switches to jscodeshift.Additional switches are something I could add to evcodeshift without any issue.Sent from my iPhoneOn Jun 20, 2022, at 03:53, Ahmed Hassanein @.***> wrote: a CLI switch to save results in another folder would be much appreciated

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: @.***>

ElonVolo avatar May 02 '23 19:05 ElonVolo

I should add that evcodeshift adds ‘saveoutput’ parameter option for unit tests, which saves a file with transformed content to a directory with the unit test name.Sent from my iPhoneOn May 2, 2023, at 15:54, Elon Volow @.> wrote:Facebook is unwilling to add any additional command line switches to jscodeshift.Additional switches are something I could add to evcodeshift without any issue.Sent from my iPhoneOn Jun 20, 2022, at 03:53, Ahmed Hassanein @.> wrote: a CLI switch to save results in another folder would be much appreciated

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: @.***>

ElonVolo avatar May 02 '23 22:05 ElonVolo