jscodeshift
jscodeshift copied to clipboard
Can jscodeshift output to a different file?
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.
In my experience, not with the command line. But you can with the API.
Hi, I am new to jscodeshift.
Please can somebody explain, how we can write output to a new file, without changing the original file
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()
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')
}
})
}
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 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
a CLI switch to save results in another folder would be much appreciated
I believe jscodeshift does have a —print option that prints transformed files to stdout instead. Would this cover what you’re trying to do?
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 😅
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
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).
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);
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: @.***>
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: @.***>