7

Problem:

js2coffe does work only with single file input/output redirection. to convert a whole project and it's directory structure can be a real pain.

Want to convert a ExpressJS default application project incl. it's directory structure?

Check out the script below

Inoperable
  • 1,429
  • 5
  • 17
  • 33
  • 1
    I hope you have a very complete test suite, js2coffee can do some odd things to your code. You're better off translating your code by hand or even better, leave it alone and translate it to CoffeeScript by hand piecemeal as you update the functionality. – mu is too short Dec 30 '12 at 18:45
  • 1
    that's more about using bash and stdin/out redirection to make life easier - besides there is cs2 lurking around: https://github.com/michaelficarra/CoffeeScriptRedux – Inoperable Dec 30 '12 at 21:11

2 Answers2

23

UPDATE: Please check the short version of this script below if you are in a hurry.

A simple Bash script does the Job for ya:

#!/bin/bash

for FILE in `find . -name "*.js" -type f -o -path './node_modules' -prune -o -path './components' -prune`
do 
    if [ -e $FILE ] ; then        
        COFFEE=${FILE//.js/.coffee}

        echo "converting ${FILE} to ${COFFEE}"
        js2coffee "$FILE" > "$COFFEE"
    else     
        echo "File: {$1} does not exist!"
    fi
done

make a file, for example all2coffee, put it in /usr/local/bin, add an chmod + x flag it in terminal

REQUIREMENTS

js2coffee installed globally, if not yet instaleld do: npm install -g js2coffee

SCRIPT EXPLAINED

for loop:

for FILE in `find arguments` .... means:

find output is assigned to FILE string every time find stumbles upon a .js file

find parameters:

-name "*.js" grab all files with .js ending

-type f must be of type file since we don't want .js dir's but file's only

-o -path './node_modules' -prune

excludes files in dir's ./node_modules adding -prune is crucial, otherwise find will descend into the dir and print *.js files found in the directory

do block:

if [ -e ${FILE} ] ; then

-e flag checks if the string from FILE is a existing file on the filesystem, otherwise else is executed.

string manipulation:

COFFEE=${FILE//.js/.coffee}

we assing thte COFFEE variable a string where we replace .js with .coffee through the bash string manipulation: ${STRING//match_this/replace_with}

conversion:

js2coffee "$FILE" > "$COFFEE" we feed js2coffee with FILE and COFFEE as strings

EXTRA:

You like to move all of your converted .coffee files to a new directory, but keep the structure?

Use find with rsync in Linux or ditto on Os X since cp won't create directories needed by this command. Here a little script to execute in the main dir that will do the job

all .coffee files will in the /coffee dir copying the .js files hierarchy

for FILE in `find . -name "*.coffee"`
do 
    ditto .${FILE/./} coffee${FILE/./}    
done

execute this after you converted your files to .coffee

UPDATE

you can swap ditto or rsync with mv after the first run to move the files since mv like cp does not create sub dirs.

UPDATE 2

added an one liner for those on time, see my second answer below!

UPDATE 3

added an option to exclude ./node_modules directory from conversion, for those who don't want to convert their dependencies

Inoperable
  • 1,429
  • 5
  • 17
  • 33
9

For those on short time - use this nifty one-liner! It's start's in the current dir ./ and goes through subdirs grinding every .js file to .coffee

find . -type f -name '*.js' | while read f; do echo "grinding $f to ${f/.js/.coffee} "; js2coffee "$f" > "${f/.js/.coffee}"; done

want to exclude ./node_modules directory from conversion? Use the one below instead:

find . -path ./node_modules -prune -o -type f -name '*.js' | while read f; do echo "grinding $f to ${f/.js/.coffee} "; js2coffee "$f" > "${f/.js/.coffee}"; done

small tip: You can use this loop for moving or copying files as well: substitute the js2coffee command with whatever you need to do. find output (the list of found files) can be simply modified and filtered.

In bash, substring extraction (or replacement) is simple - as in the example above:

IMPORTANT (long version) bash variables are accessible by adding $ in front of the variable's name - BUT initially they are defined without the $ so for your mental health keep that in mind and check your code for the $var/var= syntax in case you got some not-so-logic errors showing up. I make this mistake over and over again after not doing anything in Bash for a while so I thought it would be wise share this simple truth (might also be me, being a lousy dev)

IMPORTANT (short version) variable definition: var_name=value variable access: $var_name=value, bad idea: $var_name=value, later on accessed by $var_name.

In the example, variable f is accessed by $f, accessed wth ${f} we replace .js -> /.js (/ is a seperator) with .coffee -> /.coffee like this: ${f/.js/.coffee}.

apple="green"; 
echo $apple;

outputs:

green

Inoperable
  • 1,429
  • 5
  • 17
  • 33