Moving old ReactJS codebase to Clojurescript? Tired of manually typing ReactJS examples as Clojurescript?
Search no more!
This is command utility and library to convert JSX snippets to Om/Reagent/Rum Clojurescript-style format. Note, this is by no means to be perfect JS->Cljs compiler, output will often still need touch of your loving hand, but, hey, most of dirty work will be done 😎
This library uses acorn-jsx to parse JSX into nice AST. So big kudos there. Since it's Node.js library, you can use this library only in Clojurescript targeted to Node.js
Installation
As command:
npm install -g jsx-to-clojurescript
As library:
[jsx-to-clojurescript "0.1.8"]
As Alfred workflow (Mac only):
I also made workflow, you can download it here Following things are needed:
- You installed via
npm install -g jsx-to-clojurescript
- Workflow assumes following paths
/usr/local/bin/node
/usr/local/bin/jsx-to-clojurescript
. If you have different, you can change it in Alfred preferences when you open this workflow's run script.
Use it with keyword jsxcljs
and paste JSX. To change command line arguments for all following queries use
jsxcljs set
and type arguments. Don't put arguments into jsxcljs
, only JSX string.
Build your own:
lein cljsbuild once
Usage
jsx-to-clojurescript -h Usage: jsx-to-clojurescript [options] <string> Converts JSX string into selected Clojurescript React library format Options: -h, --help output usage information -V, --version output the version number -t --target [target] Target library . Default om --ns [string] Namespace
Okay let's start with something simple :bowtie:
<div> <RaisedButton label="Secondary" secondary=true style=style /> <RaisedButton label="Disabled" disabled=true style=style /></div>
jsx-to-clojurescript --kebab-tags "$(pbpaste)"
Now something more nested... 😉
<AppBar title="Title" iconElementLeft=<IconButton><NavigationClose /></IconButton> iconElementRight= <IconMenu iconButtonElement= <IconButton><MoreVertIcon /></IconButton> targetOrigin=horizontal: 'right' vertical: 'top' anchorOrigin=horizontal: 'right' vertical: 'top' > <MenuItem primaryText="Refresh" /> <MenuItem primaryText="Help" /> <MenuItem primaryText="Sign out" /> </IconMenu> />
jsx-to-clojurescript --kebab-tags --kebab-attrs --ns "u" --target reagent --omit-empty-attrs "$(pbpaste)"
Conditions and anonymous functions are okay too! 😃
<div style=width: '100%' maxWidth: 700 margin: 'auto'> <Stepper activeStep=stepIndex> <Step> <StepLabel>Select campaign settings</StepLabel> </Step> <Step> <StepLabel>Create an ad group</StepLabel> </Step> <Step> <StepLabel>Create an ad</StepLabel> </Step> </Stepper> <div style=contentStyle> finished ? <p> <a href="#" onClick= { event; this; } > Click here </a> to reset the example </p> : <div> <p>this</p> <div style=marginTop: 12> <FlatButton label="Back" disabled=stepIndex === 0 onTouchTap=thishandlePrev style=marginRight: 12 /> <RaisedButton label=stepIndex === 2 ? 'Finish' : 'Next' primary=true onTouchTap=thishandleNext /> </div> </div> </div> </div>
jsx-to-clojurescript --kebab-tags --kebab-attrs --ns "u" --target reagent --omit-empty-attrs "$(pbpaste)"
Mapping? No problem! Notice how map
doesn't require any more editing ☺️
<ul> thispropsresults</ul>
jsx-to-clojurescript --ns "" --target om "$(pbpaste)"
Still not impressed? We can do spread attributes too! 😀
<AnimatedView ...thisstatepanResponderpanHandlers style=thisstatepan> thispropschildren </AnimatedView>
jsx-to-clojurescript --ns "" --target om "$(pbpaste)"
Array of styles as a nice merge 😌
<View style=stylescontainer> <View style=stylesbox width: thisstatew height: thisstateh /></View>
jsx-to-clojurescript --target reagent "$(pbpaste)"
Reagent can do neat trick with ids and classes 😗
<div id="my-id" className="some-class some-other"> <span className=stylesspan> <b className="home">Home</b> </span></div>
jsx-to-clojurescript --kebab-attrs --target reagent "$(pbpaste)"
LOL variable declarations and conditions?! 😂
< Navigator initialRoute = name: 'My First Scene' index: 0 renderScene = < MySceneComponent name = routename onForward = { var nextIndex = routeindex + 1 myOtherIndex = nextIndex + 10; navigator; var yetAnotherIndex = myOtherIndex - 1; } onBack = { if routeindex > 0 navigator; else if routeindex == 0 ; ; else var myGreatParam = 5; ; } /> />
jsx-to-clojurescript --kebab-attrs --kebab-tags "$(pbpaste)"
No problem with regular JS 😉
const myConst = some: 34; { var earth = "planet"; var foo = "bar"; return * size + myConst;} ;
jsx-to-clojurescript "$(pbpaste)"
Alright folks, that's enough of examples, I guess you get the picture 😉. If you saw error like
ERROR: Don't know how to handle node type <something>
it means I haven't implmented some JS syntax yet. Open issue or PR :)
Library API
I won't write API here for 2 reasons:
-
Not sure if this has many use cases as a library
-
Core codebase is just ~200 very straightforward lines of code. You will get it very quickly, when you see it. (gotta love Clojure 💜)
If interested, library is extendable, you can easily add other targets other than Om/Reagent (with a single function!)