2010-02-11 01:57:33 -05:00
( function ( ) {
2010-06-12 19:05:13 -04:00
var BANNER , CoffeeScript , SWITCHES , _a , compileOptions , compileScript , compileScripts , compileStdio , exec , fs , lint , optionParser , options , optparse , parseOptions , path , printTokens , sources , spawn , usage , version , watch , writeJs ;
2010-03-06 23:48:06 -05:00
// The `coffee` utility. Handles command-line compilation of CoffeeScript
// into various forms: saved into `.js` files or printed to stdout, piped to
2010-03-07 00:28:58 -05:00
// [JSLint](http://javascriptlint.com/) or recompiled every time the source is
// saved, printed as a token stream or as the syntax tree, or launch an
// interactive REPL.
2010-03-06 23:48:06 -05:00
// External dependencies.
2010-02-15 19:08:14 -05:00
fs = require ( 'fs' ) ;
2010-02-12 22:59:21 -05:00
path = require ( 'path' ) ;
2010-03-15 20:39:46 -07:00
optparse = require ( './optparse' ) ;
CoffeeScript = require ( './coffee-script' ) ;
2010-04-10 18:05:35 -04:00
_a = require ( 'child_process' ) ;
spawn = _a . spawn ;
exec = _a . exec ;
2010-03-07 00:28:58 -05:00
// The help banner that is printed when `coffee` is called without arguments.
2010-03-17 20:47:27 -04:00
BANNER = 'coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee' ;
2010-03-07 00:28:58 -05:00
// The list of all the valid option flags that `coffee` knows how to handle.
2010-05-04 23:22:28 -04:00
SWITCHES = [ [ '-c' , '--compile' , 'compile to JavaScript and save as .js files' ] , [ '-i' , '--interactive' , 'run an interactive CoffeeScript REPL' ] , [ '-o' , '--output [DIR]' , 'set the directory for compiled JavaScript' ] , [ '-w' , '--watch' , 'watch scripts for changes, and recompile' ] , [ '-p' , '--print' , 'print the compiled JavaScript to stdout' ] , [ '-l' , '--lint' , 'pipe the compiled JavaScript through JSLint' ] , [ '-s' , '--stdio' , 'listen for and compile scripts over stdio' ] , [ '-e' , '--eval' , 'compile a string from the command line' ] , [ '--no-wrap' , 'compile without the top-level function wrapper' ] , [ '-t' , '--tokens' , 'print the tokens that the lexer produces' ] , [ '-n' , '--nodes' , 'print the parse tree that Jison produces' ] , [ '-v' , '--version' , 'display CoffeeScript version' ] , [ '-h' , '--help' , 'display this help message' ] ] ;
2010-03-07 00:28:58 -05:00
// Top-level objects shared by all the functions.
2010-02-13 10:16:28 -05:00
options = { } ;
sources = [ ] ;
2010-06-12 19:05:13 -04:00
optionParser = null ;
2010-03-07 00:28:58 -05:00
// Run `coffee` by parsing passed options and determining what action to take.
// Many flags cause us to divert before compiling anything. Flags passed after
2010-03-07 13:41:15 -05:00
// `--` will be passed verbatim to your script as arguments in `process.argv`
2010-05-14 23:40:04 -04:00
exports . run = function ( ) {
2010-02-16 01:04:48 -05:00
var flags , separator ;
2010-06-12 19:05:13 -04:00
parseOptions ( ) ;
2010-02-24 17:57:58 -05:00
if ( options . help ) {
return usage ( ) ;
}
if ( options . version ) {
return version ( ) ;
}
2010-02-13 10:16:28 -05:00
if ( options . interactive ) {
2010-03-15 20:39:46 -07:00
return require ( './repl' ) ;
2010-02-13 10:07:59 -05:00
}
2010-02-24 18:18:29 -05:00
if ( options . stdio ) {
2010-06-12 19:05:13 -04:00
return compileStdio ( ) ;
2010-02-24 18:18:29 -05:00
}
2010-02-13 23:27:13 -05:00
if ( options . eval ) {
2010-06-12 19:05:13 -04:00
return compileScript ( 'console' , sources [ 0 ] ) ;
2010-02-13 23:27:13 -05:00
}
2010-02-13 10:16:28 -05:00
if ( ! ( sources . length ) ) {
2010-06-12 11:09:30 -04:00
return require ( './repl' ) ;
2010-02-13 10:16:28 -05:00
}
2010-02-16 01:04:48 -05:00
separator = sources . indexOf ( '--' ) ;
flags = [ ] ;
if ( separator >= 0 ) {
2010-03-30 20:06:44 -04:00
flags = sources . slice ( ( separator + 1 ) , sources . length ) ;
sources = sources . slice ( 0 , separator ) ;
2010-02-16 01:04:48 -05:00
}
2010-03-06 20:09:08 -05:00
process . ARGV = ( process . argv = flags ) ;
2010-06-12 19:05:13 -04:00
return compileScripts ( ) ;
2010-02-11 01:57:33 -05:00
} ;
2010-03-07 00:28:58 -05:00
// Asynchronously read in each CoffeeScript in a list of source files and
2010-05-31 15:36:41 -04:00
// compile them. If a directory is passed, recursively compile all
// '.coffee' extension source files in it and all subdirectories.
2010-06-12 19:05:13 -04:00
compileScripts = function ( ) {
2010-06-13 21:21:30 -04:00
var _b , _c , _d , _e ;
2010-05-04 23:22:28 -04:00
_b = [ ] ; _d = sources ;
for ( _c = 0 , _e = _d . length ; _c < _e ; _c ++ ) {
2010-06-13 21:21:30 -04:00
( function ( ) {
var base , compile ;
var source = _d [ _c ] ;
return _b . push ( ( function ( ) {
base = source ;
compile = function ( source , topLevel ) {
return path . exists ( source , function ( exists ) {
if ( ! ( exists ) ) {
throw new Error ( ( "File not found: " + source ) ) ;
}
return fs . stat ( source , function ( err , stats ) {
if ( stats . isDirectory ( ) ) {
return fs . readdir ( source , function ( err , files ) {
var _f , _g , _h , _i , file ;
_f = [ ] ; _h = files ;
for ( _g = 0 , _i = _h . length ; _g < _i ; _g ++ ) {
file = _h [ _g ] ;
_f . push ( compile ( path . join ( source , file ) ) ) ;
}
return _f ;
} ) ;
} else if ( topLevel || path . extname ( source ) === '.coffee' ) {
fs . readFile ( source , function ( err , code ) {
return compileScript ( source , code . toString ( ) , base ) ;
} ) ;
if ( options . watch ) {
return watch ( source , base ) ;
2010-05-04 23:22:28 -04:00
}
}
2010-06-13 21:21:30 -04:00
} ) ;
2010-05-03 17:38:59 -04:00
} ) ;
2010-06-13 21:21:30 -04:00
} ;
return compile ( source , true ) ;
} ) ( ) ) ;
} ) ( ) ;
2010-02-11 01:57:33 -05:00
}
2010-05-04 23:22:28 -04:00
return _b ;
2010-02-16 23:59:32 -05:00
} ;
// Compile a single source script, containing the given code, according to the
2010-05-04 23:22:28 -04:00
// requested options. If evaluating the script directly sets `__filename`,
// `__dirname` and `module.filename` to be correct relative to the script's path.
2010-06-12 19:05:13 -04:00
compileScript = function ( source , code , base ) {
var codeOpts , js , o ;
2010-02-24 18:56:32 -05:00
o = options ;
2010-06-12 19:05:13 -04:00
codeOpts = compileOptions ( source ) ;
2010-02-16 23:59:32 -05:00
try {
2010-02-24 18:56:32 -05:00
if ( o . tokens ) {
2010-06-12 19:05:13 -04:00
return printTokens ( CoffeeScript . tokens ( code ) ) ;
2010-02-25 18:42:35 -05:00
} else if ( o . nodes ) {
return puts ( CoffeeScript . nodes ( code ) . toString ( ) ) ;
2010-03-07 21:49:08 -05:00
} else if ( o . run ) {
2010-06-12 19:05:13 -04:00
return CoffeeScript . run ( code , codeOpts ) ;
2010-02-12 23:09:57 -05:00
} else {
2010-06-12 19:05:13 -04:00
js = CoffeeScript . compile ( code , codeOpts ) ;
2010-03-08 04:46:24 -05:00
if ( o . print ) {
2010-04-10 18:05:35 -04:00
return print ( js ) ;
2010-03-08 04:46:24 -05:00
} else if ( o . compile ) {
2010-06-12 19:05:13 -04:00
return writeJs ( source , js , base ) ;
2010-02-24 18:56:32 -05:00
} else if ( o . lint ) {
2010-02-16 23:59:32 -05:00
return lint ( js ) ;
2010-02-13 09:39:25 -05:00
}
2010-02-12 23:09:57 -05:00
}
2010-02-16 23:59:32 -05:00
} catch ( err ) {
2010-06-01 20:21:12 -04:00
if ( ! ( o . watch ) ) {
error ( err . stack ) && process . exit ( 1 ) ;
2010-02-16 23:59:32 -05:00
}
2010-06-01 20:21:12 -04:00
return puts ( err . message ) ;
2010-02-16 23:59:32 -05:00
}
} ;
2010-03-07 00:28:58 -05:00
// Attach the appropriate listeners to compile scripts incoming over **stdin**,
// and write them back to **stdout**.
2010-06-12 19:05:13 -04:00
compileStdio = function ( ) {
2010-04-10 18:05:35 -04:00
var code , stdin ;
2010-02-24 18:18:29 -05:00
code = '' ;
2010-04-10 18:05:35 -04:00
stdin = process . openStdin ( ) ;
stdin . addListener ( 'data' , function ( buffer ) {
if ( buffer ) {
return code += buffer . toString ( ) ;
2010-02-24 18:18:29 -05:00
}
} ) ;
2010-04-10 18:05:35 -04:00
return stdin . addListener ( 'end' , function ( ) {
2010-06-12 19:05:13 -04:00
return compileScript ( 'stdio' , code ) ;
2010-02-24 18:18:29 -05:00
} ) ;
} ;
2010-05-03 17:38:59 -04:00
// Watch a source CoffeeScript file using `fs.watchFile`, recompiling it every
// time the file is updated. May be used in combination with other options,
// such as `--lint` or `--print`.
2010-05-14 23:40:04 -04:00
watch = function ( source , base ) {
2010-05-03 17:38:59 -04:00
return fs . watchFile ( source , {
persistent : true ,
interval : 500
} , function ( curr , prev ) {
if ( curr . mtime . getTime ( ) === prev . mtime . getTime ( ) ) {
return null ;
}
return fs . readFile ( source , function ( err , code ) {
2010-06-12 19:05:13 -04:00
return compileScript ( source , code . toString ( ) , base ) ;
2010-02-21 18:59:27 -06:00
} ) ;
2010-05-03 17:38:59 -04:00
} ) ;
2010-02-11 01:57:33 -05:00
} ;
2010-03-07 00:28:58 -05:00
// Write out a JavaScript source file with the compiled code. By default, files
// are written out in `cwd` as `.js` files with the same name, but the output
// directory can be customized with `--output`.
2010-06-12 19:05:13 -04:00
writeJs = function ( source , js , base ) {
var baseDir , compile , dir , filename , jsPath , srcDir ;
2010-02-12 22:59:21 -05:00
filename = path . basename ( source , path . extname ( source ) ) + '.js' ;
2010-06-12 19:05:13 -04:00
srcDir = path . dirname ( source ) ;
baseDir = srcDir . substring ( base . length ) ;
dir = options . output ? path . join ( options . output , baseDir ) : srcDir ;
jsPath = path . join ( dir , filename ) ;
2010-05-14 23:40:04 -04:00
compile = function ( ) {
2010-06-13 14:21:02 -04:00
return fs . writeFile ( jsPath , js , function ( err ) {
if ( options . compile && options . watch ) {
return puts ( ( "Compiled " + source ) ) ;
}
} ) ;
2010-05-04 23:22:28 -04:00
} ;
return path . exists ( dir , function ( exists ) {
if ( exists ) {
return compile ( ) ;
} else {
return exec ( ( "mkdir -p " + dir ) , compile ) ;
}
2010-05-03 17:38:59 -04:00
} ) ;
2010-02-12 22:59:21 -05:00
} ;
2010-03-07 00:28:58 -05:00
// Pipe compiled JS through JSLint (requires a working `jsl` command), printing
// any errors or warnings that arise.
2010-05-14 23:40:04 -04:00
lint = function ( js ) {
2010-06-12 19:05:13 -04:00
var jsl , printIt ;
printIt = function ( buffer ) {
2010-04-25 22:29:43 -04:00
return print ( buffer . toString ( ) ) ;
2010-04-10 18:05:35 -04:00
} ;
jsl = spawn ( 'jsl' , [ '-nologo' , '-stdin' ] ) ;
2010-06-12 19:05:13 -04:00
jsl . stdout . addListener ( 'data' , printIt ) ;
jsl . stderr . addListener ( 'data' , printIt ) ;
2010-04-10 18:05:35 -04:00
jsl . stdin . write ( js ) ;
return jsl . stdin . end ( ) ;
2010-02-12 23:09:57 -05:00
} ;
2010-03-07 00:28:58 -05:00
// Pretty-print a stream of tokens.
2010-06-12 19:05:13 -04:00
printTokens = function ( tokens ) {
2010-04-10 18:05:35 -04:00
var _b , _c , _d , _e , _f , strings , tag , token , value ;
2010-02-24 18:56:32 -05:00
strings = ( function ( ) {
2010-04-10 18:05:35 -04:00
_b = [ ] ; _d = tokens ;
for ( _c = 0 , _e = _d . length ; _c < _e ; _c ++ ) {
token = _d [ _c ] ;
_b . push ( ( function ( ) {
_f = [ token [ 0 ] , token [ 1 ] . toString ( ) . replace ( /\n/ , '\\n' ) ] ;
tag = _f [ 0 ] ;
value = _f [ 1 ] ;
2010-03-06 13:59:11 -05:00
return "[" + tag + " " + value + "]" ;
2010-04-10 14:40:05 -04:00
} ) ( ) ) ;
2010-02-24 18:56:32 -05:00
}
2010-04-10 18:05:35 -04:00
return _b ;
2010-04-10 14:40:05 -04:00
} ) ( ) ;
2010-02-24 18:56:32 -05:00
return puts ( strings . join ( ' ' ) ) ;
} ;
2010-03-07 00:28:58 -05:00
// Use the [OptionParser module](optparse.html) to extract all options from
2010-03-07 13:41:15 -05:00
// `process.argv` that are specified in `SWITCHES`.
2010-06-12 19:05:13 -04:00
parseOptions = function ( ) {
2010-03-07 21:49:08 -05:00
var o ;
2010-06-12 19:05:13 -04:00
optionParser = new optparse . OptionParser ( SWITCHES , BANNER ) ;
o = ( options = optionParser . parse ( process . argv ) ) ;
2010-03-08 04:46:24 -05:00
options . run = ! ( o . compile || o . print || o . lint ) ;
options . print = ! ! ( o . print || ( o . eval || o . stdio && o . compile ) ) ;
2010-03-30 20:06:44 -04:00
sources = options . arguments . slice ( 2 , options . arguments . length ) ;
2010-03-30 15:43:30 -04:00
return sources ;
2010-02-11 01:57:33 -05:00
} ;
2010-03-07 00:28:58 -05:00
// The compile-time options to pass to the CoffeeScript compiler.
2010-06-12 19:05:13 -04:00
compileOptions = function ( source ) {
2010-03-07 22:08:24 -05:00
var o ;
o = {
source : source
} ;
2010-03-08 04:28:26 -05:00
o [ 'no_wrap' ] = options [ 'no-wrap' ] ;
2010-03-07 22:08:24 -05:00
return o ;
2010-02-24 18:18:29 -05:00
} ;
2010-03-07 00:28:58 -05:00
// Print the `--help` usage message and exit.
2010-05-14 23:40:04 -04:00
usage = function ( ) {
2010-06-12 19:05:13 -04:00
puts ( optionParser . help ( ) ) ;
2010-03-07 00:28:58 -05:00
return process . exit ( 0 ) ;
} ;
2010-03-07 11:41:56 -05:00
// Print the `--version` message and exit.
2010-05-14 23:40:04 -04:00
version = function ( ) {
2010-04-11 16:57:53 -04:00
puts ( ( "CoffeeScript version " + CoffeeScript . VERSION ) ) ;
2010-03-07 00:28:58 -05:00
return process . exit ( 0 ) ;
} ;
2010-02-24 18:56:32 -05:00
} ) ( ) ;