2017-04-13 13:42:32 -04:00
// Generated by CoffeeScript 2.0.0-beta1
2010-07-24 11:31:43 -04:00
( function ( ) {
2017-04-06 13:06:45 -04:00
var BANNER , CoffeeScript , EventEmitter , SWITCHES , compileJoin , compileOptions , compilePath , compileScript , compileStdio , exec , findDirectoryIndex , forkNode , fs , helpers , hidden , joinTimeout , makePrelude , mkdirp , notSources , optionParser , optparse , opts , outputPath , parseOptions , path , printLine , printTokens , printWarn , removeSource , removeSourceDir , silentUnlink , sourceCode , sources , spawn , timeLog , usage , useWinPathSep , version , wait , watch , watchDir , watchedDirs , writeJs ,
2015-01-30 14:33:03 -05:00
indexOf = [ ] . indexOf || function ( item ) { for ( var i = 0 , l = this . length ; i < l ; i ++ ) { if ( i in this && this [ i ] === item ) return i ; } return - 1 ; } ;
2011-09-18 18:16:39 -04:00
2010-02-15 19:08:14 -05:00
fs = require ( 'fs' ) ;
2011-09-18 18:16:39 -04:00
2010-02-12 22:59:21 -05:00
path = require ( 'path' ) ;
2011-09-18 18:16:39 -04:00
2010-11-04 23:05:04 -04:00
helpers = require ( './helpers' ) ;
2011-09-18 18:16:39 -04:00
2010-03-15 23:39:46 -04:00
optparse = require ( './optparse' ) ;
2011-09-18 18:16:39 -04:00
2017-02-12 20:00:05 -05:00
CoffeeScript = require ( './coffeescript' ) ;
2011-09-18 18:16:39 -04:00
2017-04-06 13:06:45 -04:00
( { spawn , exec } = require ( 'child_process' ) ) ;
2011-09-18 18:16:39 -04:00
2017-04-06 13:06:45 -04:00
( { EventEmitter } = require ( 'events' ) ) ;
2011-09-18 18:16:39 -04:00
2013-03-20 12:11:42 -04:00
useWinPathSep = path . sep === '\\' ;
2010-09-25 04:39:19 -04:00
helpers . extend ( CoffeeScript , new EventEmitter ) ;
2011-09-18 18:16:39 -04:00
2011-10-24 16:19:15 -04:00
printLine = function ( line ) {
return process . stdout . write ( line + '\n' ) ;
} ;
printWarn = function ( line ) {
2011-10-27 11:23:03 -04:00
return process . stderr . write ( line + '\n' ) ;
2011-10-24 16:19:15 -04:00
} ;
2012-02-22 12:17:07 -05:00
hidden = function ( file ) {
2012-02-26 11:48:33 -05:00
return /^\.|~$/ . test ( file ) ;
2012-02-22 12:17:07 -05:00
} ;
2012-02-26 11:48:33 -05:00
BANNER = 'Usage: coffee [options] path/to/script.coffee -- [args]\n\nIf called without options, `coffee` will run your script.' ;
2011-09-18 18:16:39 -04:00
2017-02-12 20:00:05 -05:00
SWITCHES = [ [ '-b' , '--bare' , 'compile without a top-level function wrapper' ] , [ '-c' , '--compile' , 'compile to JavaScript and save as .js files' ] , [ '-e' , '--eval' , 'pass a string from the command line as input' ] , [ '-h' , '--help' , 'display this help message' ] , [ '-i' , '--interactive' , 'run an interactive CoffeeScript REPL' ] , [ '-j' , '--join [FILE]' , 'concatenate the source CoffeeScript before compiling' ] , [ '-m' , '--map' , 'generate source map and save as .js.map files' ] , [ '-M' , '--inline-map' , 'generate source map and include it directly in output' ] , [ '-n' , '--nodes' , 'print out the parse tree that the parser produces' ] , [ '--nodejs [ARGS]' , 'pass options directly to the "node" binary' ] , [ '--no-header' , 'suppress the "Generated by" header' ] , [ '-o' , '--output [DIR]' , 'set the output directory for compiled JavaScript' ] , [ '-p' , '--print' , 'print out the compiled JavaScript' ] , [ '-r' , '--require [MODULE*]' , 'require the given module before eval or REPL' ] , [ '-s' , '--stdio' , 'listen for and compile scripts over stdio' ] , [ '-l' , '--literate' , 'treat stdio as literate style coffeescript' ] , [ '-t' , '--tokens' , 'print out the tokens that the lexer/rewriter produce' ] , [ '-v' , '--version' , 'display the version number' ] , [ '-w' , '--watch' , 'watch scripts for changes and rerun commands' ] ] ;
2011-09-18 18:16:39 -04:00
2010-08-15 08:32:09 -04:00
opts = { } ;
2011-09-18 18:16:39 -04:00
2010-02-13 10:16:28 -05:00
sources = [ ] ;
2011-09-18 18:16:39 -04:00
2011-12-18 10:27:22 -05:00
sourceCode = [ ] ;
2011-09-18 18:16:39 -04:00
2011-12-18 11:27:02 -05:00
notSources = { } ;
2013-11-23 00:41:08 -05:00
watchedDirs = { } ;
2010-06-12 19:05:13 -04:00
optionParser = null ;
2011-09-18 18:16:39 -04:00
2011-04-30 23:01:36 -04:00
exports . run = function ( ) {
2017-04-06 13:06:45 -04:00
var i , len , literals , ref , replCliOpts , results , source ;
2010-06-12 19:05:13 -04:00
parseOptions ( ) ;
2013-09-03 17:27:13 -04:00
replCliOpts = {
useGlobal : true
} ;
2015-02-19 10:54:08 -05:00
if ( opts . require ) {
opts . prelude = makePrelude ( opts . require ) ;
}
replCliOpts . prelude = opts . prelude ;
2012-04-10 14:57:45 -04:00
if ( opts . nodejs ) {
return forkNode ( ) ;
}
if ( opts . help ) {
return usage ( ) ;
}
if ( opts . version ) {
return version ( ) ;
}
if ( opts . interactive ) {
2013-09-03 17:27:13 -04:00
return require ( './repl' ) . start ( replCliOpts ) ;
2012-04-10 14:57:45 -04:00
}
if ( opts . stdio ) {
return compileStdio ( ) ;
}
if ( opts [ "eval" ] ) {
2013-11-23 01:11:34 -05:00
return compileScript ( null , opts [ "arguments" ] [ 0 ] ) ;
2012-04-10 14:57:45 -04:00
}
2013-11-23 01:11:34 -05:00
if ( ! opts [ "arguments" ] . length ) {
2013-09-03 17:27:13 -04:00
return require ( './repl' ) . start ( replCliOpts ) ;
2012-04-10 14:57:45 -04:00
}
2013-11-23 01:11:34 -05:00
literals = opts . run ? opts [ "arguments" ] . splice ( 1 ) : [ ] ;
2012-01-25 19:47:03 -05:00
process . argv = process . argv . slice ( 0 , 2 ) . concat ( literals ) ;
2011-04-30 10:59:55 -04:00
process . argv [ 0 ] = 'coffee' ;
2013-11-23 00:41:08 -05:00
if ( opts . output ) {
opts . output = path . resolve ( opts . output ) ;
}
if ( opts . join ) {
opts . join = path . resolve ( opts . join ) ;
2014-05-12 01:41:39 -04:00
console . error ( '\nThe --join option is deprecated and will be removed in a future version.\n\nIf for some reason it\'s necessary to share local variables between files,\nreplace...\n\n $ coffee --compile --join bundle.js -- a.coffee b.coffee c.coffee\n\nwith...\n\n $ cat a.coffee b.coffee c.coffee | coffee --compile --stdio > bundle.js\n' ) ;
2013-11-23 00:41:08 -05:00
}
2017-04-06 13:06:45 -04:00
ref = opts [ "arguments" ] ;
2015-01-30 14:33:03 -05:00
results = [ ] ;
2017-04-06 13:06:45 -04:00
for ( i = 0 , len = ref . length ; i < len ; i ++ ) {
source = ref [ i ] ;
2013-11-23 00:41:08 -05:00
source = path . resolve ( source ) ;
2015-01-30 14:33:03 -05:00
results . push ( compilePath ( source , true , source ) ) ;
2011-12-18 11:27:02 -05:00
}
2015-01-30 14:33:03 -05:00
return results ;
2010-02-11 01:57:33 -05:00
} ;
2011-09-18 18:16:39 -04:00
2015-02-19 10:54:08 -05:00
makePrelude = function ( requires ) {
return requires . map ( function ( module ) {
var _ , match , name ;
if ( match = module . match ( /^(.*)=(.*)$/ ) ) {
2017-04-06 13:06:45 -04:00
[ _ , name , module ] = match ;
2015-02-19 10:54:08 -05:00
}
name || ( name = helpers . baseFileName ( module , true , useWinPathSep ) ) ;
2016-11-28 09:05:51 -05:00
return ` ${ name } = require(' ${ module } ') ` ;
2015-02-19 10:54:08 -05:00
} ) . join ( ';' ) ;
} ;
2011-12-18 11:27:02 -05:00
compilePath = function ( source , topLevel , base ) {
2015-09-13 06:27:07 -04:00
var code , err , file , files , i , len , results , stats ;
2015-01-30 14:33:03 -05:00
if ( indexOf . call ( sources , source ) >= 0 || watchedDirs [ source ] || ! topLevel && ( notSources [ source ] || hidden ( source ) ) ) {
2013-11-23 01:11:34 -05:00
return ;
}
2013-11-10 02:36:29 -05:00
try {
stats = fs . statSync ( source ) ;
2015-08-16 16:34:22 -04:00
} catch ( error ) {
err = error ;
2013-11-10 02:36:29 -05:00
if ( err . code === 'ENOENT' ) {
2016-11-28 09:05:51 -05:00
console . error ( ` File not found: ${ source } ` ) ;
2013-02-28 05:54:19 -05:00
process . exit ( 1 ) ;
2011-12-18 11:27:02 -05:00
}
2013-11-10 02:36:29 -05:00
throw err ;
}
2013-11-23 01:11:34 -05:00
if ( stats . isDirectory ( ) ) {
if ( path . basename ( source ) === 'node_modules' ) {
notSources [ source ] = true ;
return ;
}
2013-12-23 19:53:27 -05:00
if ( opts . run ) {
compilePath ( findDirectoryIndex ( source ) , topLevel , base ) ;
return ;
}
2013-11-10 02:36:29 -05:00
if ( opts . watch ) {
watchDir ( source , base ) ;
}
try {
files = fs . readdirSync ( source ) ;
2015-09-13 06:27:07 -04:00
} catch ( error ) {
err = error ;
2013-11-10 02:36:29 -05:00
if ( err . code === 'ENOENT' ) {
return ;
} else {
throw err ;
2012-04-10 14:57:45 -04:00
}
2013-11-10 02:36:29 -05:00
}
2015-01-30 14:33:03 -05:00
results = [ ] ;
for ( i = 0 , len = files . length ; i < len ; i ++ ) {
file = files [ i ] ;
results . push ( compilePath ( path . join ( source , file ) , false , base ) ) ;
2013-11-23 01:11:34 -05:00
}
2015-01-30 14:33:03 -05:00
return results ;
2013-11-10 02:36:29 -05:00
} else if ( topLevel || helpers . isCoffee ( source ) ) {
2013-11-23 01:11:34 -05:00
sources . push ( source ) ;
sourceCode . push ( null ) ;
delete notSources [ source ] ;
2013-11-10 02:36:29 -05:00
if ( opts . watch ) {
watch ( source , base ) ;
}
try {
code = fs . readFileSync ( source ) ;
2015-09-13 06:27:07 -04:00
} catch ( error ) {
err = error ;
2013-11-10 02:36:29 -05:00
if ( err . code === 'ENOENT' ) {
return ;
} else {
throw err ;
2012-04-10 14:57:45 -04:00
}
2011-12-18 13:50:04 -05:00
}
2013-11-10 02:36:29 -05:00
return compileScript ( source , code . toString ( ) , base ) ;
} else {
2013-11-23 01:11:34 -05:00
return notSources [ source ] = true ;
2013-11-10 02:36:29 -05:00
}
2010-02-16 23:59:32 -05:00
} ;
2011-09-18 18:16:39 -04:00
2013-12-23 19:53:27 -05:00
findDirectoryIndex = function ( source ) {
2017-04-06 13:06:45 -04:00
var err , ext , i , index , len , ref ;
ref = CoffeeScript . FILE _EXTENSIONS ;
for ( i = 0 , len = ref . length ; i < len ; i ++ ) {
ext = ref [ i ] ;
2016-11-28 09:05:51 -05:00
index = path . join ( source , ` index ${ ext } ` ) ;
2013-12-23 19:53:27 -05:00
try {
if ( ( fs . statSync ( index ) ) . isFile ( ) ) {
return index ;
}
2015-08-16 16:34:22 -04:00
} catch ( error ) {
err = error ;
2013-12-23 19:53:27 -05:00
if ( err . code !== 'ENOENT' ) {
throw err ;
}
}
}
2016-11-28 09:05:51 -05:00
console . error ( ` Missing index.coffee or index.litcoffee in ${ source } ` ) ;
2013-12-23 19:53:27 -05:00
return process . exit ( 1 ) ;
} ;
[CS2] Output ES2015 arrow functions, default parameters, rest parameters (#4311)
* Eliminate wrapper around “bound” (arrow) functions; output `=>` for such functions
* Remove irrelevant (and breaking) tests
* Minor cleanup
* When a function parameter is a splat (i.e., it uses the ES2015 rest parameter syntax) output that parameter as ES2015
* Rearrange function parameters when one of the parameters is a splat and isn’t the last parameter (very WIP)
* Handle params like `@param`, adding assignment expressions for them when they appear; ensure splat parameter is last
* Add parameter names (not a text like `'\nValue IdentifierLiteral: a'`) to the scope, so that parameters can’t be deleted; move body-related lines together; more explanation of what’s going on
* For parameters with a default value, correctly add the parameter name to the function scope
* Handle expansions in function parameters: when an expansion is found, set the parameters to only be the original parameters left of the expansion, then an `...args` parameter; and in the function body define variables for the parameters to the right of the expansion, including setting default values
* Handle splat parameters the same way we handle expansions: if a splat parameter is found, it becomes the last parameter in the function definition, and all following parameters get declared in the function body. Fix the splat/rest parameter values after the post-splat parameters have been extracted from it. Clean up `Code.compileNode` so that we loop through the parameters only once, and we create all expressions using calls like `new IdentifierLiteral` rather than `@makeCode`.
* Fix parameter name when a parameter is a splat attached to `this` (e.g. `@param...`)
* Rather than assigning post-splat parameters based on index, use slice; passes test “Functions with splats being called with too few arguments”
* Dial back our w00t indentation
* Better parsing of parameter names (WIP)
* Refactor processing of splat/expansion parameters
* Fix assignment of default parameters for parameters that come after a splat
* Better check for whether a param is attached to `this`
* More understandable variable names
* For parameters after a splat or expansion, assign them similar to the 1.x destructuring method of using `arguments`, except only concern ourselves with the post-splat parameters instead of all parameters; and use the splat/expansion parameter name, since `arguments` in ES fat arrow functions refers to the parent function’s `arguments` rather than the fat arrow function’s arguments/parameters
* Don’t add unnamed parameters (like `[]` as a parameter) to the function scope
* Disallow multiple splat/expansion parameters in function definitions; disallow lone expansion parameters
* Fix `this` params not getting assigned if the parameter is after a splat parameter
* Allow names of function parameters attached to `this` to be reserved words
* Always add a statement to the function body defining a variable with its default value, if it has one, if the variable `== null`; this covers the case when ES doesn’t apply the default value when `null` is passed in as a value, but CoffeeScript expects `null` and `undefined` to act interchangeably
* Aftermath of having both `undefined` and `null` trigger the use of default values for parameters with default values
* More careful parsing of destructured parameters
* Fall back to processing destructured parameters in the function body, to account for `this` or default values within destructured objects
* Clean up comments
* Restore new bare function test, minus the arrow function part of it
* Test that bound/arrow functions aren’t overwriting the `arguments` object, which should refer to the parent scope’s `arguments` (like `this`)
* Follow ES2015 spec for parameter default values: `null` gets assigned as as `null`, not the default value
* Mimic ES default parameters behavior for parameters after a splat or expansion parameter
* Bound functions cannot be generators: remove no-longer-relevant test, add check to throw error if `yield` appears inside a bound (arrow) function
* Error for bound generator functions should underline the `yield`
2016-10-26 01:26:13 -04:00
compileScript = function ( file , input , base = null ) {
2015-09-13 06:27:07 -04:00
var compiled , err , message , o , options , t , task ;
2010-08-15 08:32:09 -04:00
o = opts ;
2013-03-06 11:05:57 -05:00
options = compileOptions ( file , base ) ;
2010-02-16 23:59:32 -05:00
try {
2017-04-06 13:06:45 -04:00
t = task = { file , input , options } ;
2010-08-15 08:32:09 -04:00
CoffeeScript . emit ( 'compile' , task ) ;
2010-02-24 18:56:32 -05:00
if ( o . tokens ) {
2012-09-25 20:15:40 -04:00
return printTokens ( CoffeeScript . tokens ( t . input , t . options ) ) ;
2010-02-25 18:42:35 -05:00
} else if ( o . nodes ) {
2012-09-25 20:15:40 -04:00
return printLine ( CoffeeScript . nodes ( t . input , t . options ) . toString ( ) . trim ( ) ) ;
2010-03-07 21:49:08 -05:00
} else if ( o . run ) {
2013-12-08 15:21:18 -05:00
CoffeeScript . register ( ) ;
2015-02-19 10:54:08 -05:00
if ( opts . prelude ) {
CoffeeScript [ "eval" ] ( opts . prelude , t . options ) ;
}
2010-08-15 08:32:09 -04:00
return CoffeeScript . run ( t . input , t . options ) ;
2011-12-18 11:27:02 -05:00
} else if ( o . join && t . file !== o . join ) {
2013-03-04 21:45:57 -05:00
if ( helpers . isLiterate ( file ) ) {
t . input = helpers . invertLiterate ( t . input ) ;
}
2011-12-18 11:27:02 -05:00
sourceCode [ sources . indexOf ( t . file ) ] = t . input ;
return compileJoin ( ) ;
2010-02-12 23:09:57 -05:00
} else {
2013-03-04 09:45:25 -05:00
compiled = CoffeeScript . compile ( t . input , t . options ) ;
2013-03-04 16:19:21 -05:00
t . output = compiled ;
2013-03-04 16:40:39 -05:00
if ( o . map ) {
2013-03-04 16:19:21 -05:00
t . output = compiled . js ;
t . sourceMap = compiled . v3SourceMap ;
}
2010-08-12 18:28:38 -04:00
CoffeeScript . emit ( 'success' , task ) ;
2010-11-08 23:07:51 -05:00
if ( o . print ) {
2011-10-24 16:19:15 -04:00
return printLine ( t . output . trim ( ) ) ;
2013-03-04 15:23:50 -05:00
} else if ( o . compile || o . map ) {
2013-03-06 11:05:57 -05:00
return writeJs ( base , t . file , t . output , options . jsPath , t . sourceMap ) ;
2010-11-08 23:07:51 -05:00
}
2010-02-12 23:09:57 -05:00
}
2015-08-16 16:34:22 -04:00
} catch ( error ) {
err = error ;
2010-08-12 18:28:38 -04:00
CoffeeScript . emit ( 'failure' , err , task ) ;
2012-04-10 14:57:45 -04:00
if ( CoffeeScript . listeners ( 'failure' ) . length ) {
return ;
}
2016-11-28 09:05:51 -05:00
message = ( err != null ? err . stack : void 0 ) || ` ${ err } ` ;
2012-04-10 14:57:45 -04:00
if ( o . watch ) {
2013-03-04 23:13:46 -05:00
return printLine ( message + '\x07' ) ;
2013-02-25 12:41:34 -05:00
} else {
printWarn ( message ) ;
return process . exit ( 1 ) ;
2012-04-10 14:57:45 -04:00
}
2010-02-16 23:59:32 -05:00
}
} ;
2011-09-18 18:16:39 -04:00
2010-06-12 19:05:13 -04:00
compileStdio = function ( ) {
2016-01-12 11:49:45 -05:00
var buffers , stdin ;
buffers = [ ] ;
2010-04-10 18:05:35 -04:00
stdin = process . openStdin ( ) ;
2010-07-18 07:54:44 -04:00
stdin . on ( 'data' , function ( buffer ) {
2012-04-10 14:57:45 -04:00
if ( buffer ) {
2016-01-12 11:49:45 -05:00
return buffers . push ( buffer ) ;
2012-04-10 14:57:45 -04:00
}
2010-02-24 18:18:29 -05:00
} ) ;
2010-07-18 07:54:44 -04:00
return stdin . on ( 'end' , function ( ) {
2016-01-12 11:49:45 -05:00
return compileScript ( null , Buffer . concat ( buffers ) . toString ( ) ) ;
2010-02-24 18:18:29 -05:00
} ) ;
} ;
2011-09-18 18:16:39 -04:00
2011-12-18 15:19:08 -05:00
joinTimeout = null ;
2011-12-18 11:27:02 -05:00
compileJoin = function ( ) {
2012-04-10 14:57:45 -04:00
if ( ! opts . join ) {
return ;
}
2011-12-18 10:27:22 -05:00
if ( ! sourceCode . some ( function ( code ) {
return code === null ;
} ) ) {
2011-12-18 15:19:08 -05:00
clearTimeout ( joinTimeout ) ;
2011-12-18 15:27:08 -05:00
return joinTimeout = wait ( 100 , function ( ) {
2011-12-18 15:19:08 -05:00
return compileScript ( opts . join , sourceCode . join ( '\n' ) , opts . join ) ;
2011-12-18 15:27:08 -05:00
} ) ;
2011-12-18 10:27:22 -05:00
}
2010-12-23 00:26:15 -05:00
} ;
2011-09-18 18:16:39 -04:00
2010-05-14 23:40:04 -04:00
watch = function ( source , base ) {
2015-09-13 06:27:07 -04:00
var compile , compileTimeout , err , prevStats , rewatch , startWatcher , watchErr , watcher ;
2013-12-02 15:05:47 -05:00
watcher = null ;
2011-12-18 09:05:42 -05:00
prevStats = null ;
2011-12-18 14:05:18 -05:00
compileTimeout = null ;
2013-12-02 15:05:47 -05:00
watchErr = function ( err ) {
if ( err . code !== 'ENOENT' ) {
throw err ;
}
2015-01-30 14:33:03 -05:00
if ( indexOf . call ( sources , source ) < 0 ) {
2013-12-02 15:05:47 -05:00
return ;
}
try {
rewatch ( ) ;
return compile ( ) ;
2015-08-16 16:34:22 -04:00
} catch ( error ) {
2013-12-02 15:05:47 -05:00
removeSource ( source , base ) ;
return compileJoin ( ) ;
2011-12-18 14:15:33 -05:00
}
} ;
2011-12-18 09:05:42 -05:00
compile = function ( ) {
2011-12-18 14:05:18 -05:00
clearTimeout ( compileTimeout ) ;
2011-12-18 14:26:23 -05:00
return compileTimeout = wait ( 25 , function ( ) {
2011-12-18 14:05:18 -05:00
return fs . stat ( source , function ( err , stats ) {
2012-04-10 14:57:45 -04:00
if ( err ) {
return watchErr ( err ) ;
}
2011-12-24 15:44:51 -05:00
if ( prevStats && stats . size === prevStats . size && stats . mtime . getTime ( ) === prevStats . mtime . getTime ( ) ) {
2011-12-22 14:30:12 -05:00
return rewatch ( ) ;
2011-12-18 14:05:18 -05:00
}
prevStats = stats ;
return fs . readFile ( source , function ( err , code ) {
2012-04-10 14:57:45 -04:00
if ( err ) {
return watchErr ( err ) ;
}
2011-12-22 14:30:12 -05:00
compileScript ( source , code . toString ( ) , base ) ;
return rewatch ( ) ;
2011-12-18 14:05:18 -05:00
} ) ;
2011-12-18 09:05:42 -05:00
} ) ;
2011-12-18 14:26:23 -05:00
} ) ;
} ;
2013-12-04 11:11:39 -05:00
startWatcher = function ( ) {
return watcher = fs . watch ( source ) . on ( 'change' , compile ) . on ( 'error' , function ( err ) {
if ( err . code !== 'EPERM' ) {
throw err ;
}
return removeSource ( source , base ) ;
} ) ;
} ;
2013-12-02 15:05:47 -05:00
rewatch = function ( ) {
2013-11-15 14:26:16 -05:00
if ( watcher != null ) {
watcher . close ( ) ;
2012-04-10 14:57:45 -04:00
}
2013-12-04 11:11:39 -05:00
return startWatcher ( ) ;
2011-12-24 14:00:09 -05:00
} ;
2013-12-02 15:05:47 -05:00
try {
2013-12-04 11:11:39 -05:00
return startWatcher ( ) ;
2015-08-16 16:34:22 -04:00
} catch ( error ) {
err = error ;
2013-12-02 15:05:47 -05:00
return watchErr ( err ) ;
}
2010-02-11 01:57:33 -05:00
} ;
2011-09-18 18:16:39 -04:00
2011-12-18 11:27:02 -05:00
watchDir = function ( source , base ) {
2015-09-13 06:27:07 -04:00
var err , readdirTimeout , startWatcher , stopWatcher , watcher ;
2013-12-04 11:11:39 -05:00
watcher = null ;
2011-12-18 15:19:08 -05:00
readdirTimeout = null ;
2013-12-04 11:11:39 -05:00
startWatcher = function ( ) {
return watcher = fs . watch ( source ) . on ( 'error' , function ( err ) {
if ( err . code !== 'EPERM' ) {
throw err ;
}
return stopWatcher ( ) ;
} ) . on ( 'change' , function ( ) {
2011-12-18 15:19:08 -05:00
clearTimeout ( readdirTimeout ) ;
2011-12-18 15:27:08 -05:00
return readdirTimeout = wait ( 25 , function ( ) {
2015-09-13 06:27:07 -04:00
var err , file , files , i , len , results ;
2013-11-22 01:31:46 -05:00
try {
files = fs . readdirSync ( source ) ;
2015-08-16 16:34:22 -04:00
} catch ( error ) {
err = error ;
2013-11-22 01:31:46 -05:00
if ( err . code !== 'ENOENT' ) {
throw err ;
2011-12-18 14:01:13 -05:00
}
2013-12-04 11:11:39 -05:00
return stopWatcher ( ) ;
2013-11-22 01:31:46 -05:00
}
2015-01-30 14:33:03 -05:00
results = [ ] ;
for ( i = 0 , len = files . length ; i < len ; i ++ ) {
file = files [ i ] ;
results . push ( compilePath ( path . join ( source , file ) , false , base ) ) ;
2013-11-22 01:31:46 -05:00
}
2015-01-30 14:33:03 -05:00
return results ;
2011-12-18 15:27:08 -05:00
} ) ;
2013-11-15 14:26:16 -05:00
} ) ;
2013-12-04 11:11:39 -05:00
} ;
stopWatcher = function ( ) {
watcher . close ( ) ;
return removeSourceDir ( source , base ) ;
} ;
watchedDirs [ source ] = true ;
try {
return startWatcher ( ) ;
2015-08-16 16:34:22 -04:00
} catch ( error ) {
err = error ;
2013-12-04 11:11:39 -05:00
if ( err . code !== 'ENOENT' ) {
throw err ;
2012-04-10 14:57:45 -04:00
}
2011-12-18 14:01:13 -05:00
}
2011-12-18 11:27:02 -05:00
} ;
2013-11-23 00:55:57 -05:00
removeSourceDir = function ( source , base ) {
2015-01-30 14:33:03 -05:00
var file , i , len , sourcesChanged ;
2013-11-23 00:41:08 -05:00
delete watchedDirs [ source ] ;
2013-11-23 00:55:57 -05:00
sourcesChanged = false ;
2015-01-30 14:33:03 -05:00
for ( i = 0 , len = sources . length ; i < len ; i ++ ) {
file = sources [ i ] ;
2013-11-23 00:55:57 -05:00
if ( ! ( source === path . dirname ( file ) ) ) {
continue ;
2011-12-18 15:19:08 -05:00
}
2013-12-01 05:30:24 -05:00
removeSource ( file , base ) ;
2013-11-23 00:55:57 -05:00
sourcesChanged = true ;
2011-12-18 15:19:08 -05:00
}
2013-11-23 00:55:57 -05:00
if ( sourcesChanged ) {
return compileJoin ( ) ;
2011-12-18 15:19:08 -05:00
}
} ;
2013-12-01 05:30:24 -05:00
removeSource = function ( source , base ) {
2013-12-01 06:03:22 -05:00
var index ;
2011-12-18 11:27:02 -05:00
index = sources . indexOf ( source ) ;
sources . splice ( index , 1 ) ;
2011-12-18 12:26:04 -05:00
sourceCode . splice ( index , 1 ) ;
2013-12-01 05:30:24 -05:00
if ( ! opts . join ) {
2013-12-01 06:03:22 -05:00
silentUnlink ( outputPath ( source , base ) ) ;
2014-07-29 09:46:19 -04:00
silentUnlink ( outputPath ( source , base , '.js.map' ) ) ;
2016-11-28 09:05:51 -05:00
return timeLog ( ` removed ${ source } ` ) ;
2011-12-18 12:26:04 -05:00
}
2011-12-18 11:27:02 -05:00
} ;
2013-12-01 06:03:22 -05:00
silentUnlink = function ( path ) {
2017-04-06 13:06:45 -04:00
var err , ref ;
2013-12-01 06:03:22 -05:00
try {
return fs . unlinkSync ( path ) ;
2015-08-16 16:34:22 -04:00
} catch ( error ) {
err = error ;
2017-04-06 13:06:45 -04:00
if ( ( ref = err . code ) !== 'ENOENT' && ref !== 'EPERM' ) {
2013-12-01 06:03:22 -05:00
throw err ;
}
}
} ;
[CS2] Output ES2015 arrow functions, default parameters, rest parameters (#4311)
* Eliminate wrapper around “bound” (arrow) functions; output `=>` for such functions
* Remove irrelevant (and breaking) tests
* Minor cleanup
* When a function parameter is a splat (i.e., it uses the ES2015 rest parameter syntax) output that parameter as ES2015
* Rearrange function parameters when one of the parameters is a splat and isn’t the last parameter (very WIP)
* Handle params like `@param`, adding assignment expressions for them when they appear; ensure splat parameter is last
* Add parameter names (not a text like `'\nValue IdentifierLiteral: a'`) to the scope, so that parameters can’t be deleted; move body-related lines together; more explanation of what’s going on
* For parameters with a default value, correctly add the parameter name to the function scope
* Handle expansions in function parameters: when an expansion is found, set the parameters to only be the original parameters left of the expansion, then an `...args` parameter; and in the function body define variables for the parameters to the right of the expansion, including setting default values
* Handle splat parameters the same way we handle expansions: if a splat parameter is found, it becomes the last parameter in the function definition, and all following parameters get declared in the function body. Fix the splat/rest parameter values after the post-splat parameters have been extracted from it. Clean up `Code.compileNode` so that we loop through the parameters only once, and we create all expressions using calls like `new IdentifierLiteral` rather than `@makeCode`.
* Fix parameter name when a parameter is a splat attached to `this` (e.g. `@param...`)
* Rather than assigning post-splat parameters based on index, use slice; passes test “Functions with splats being called with too few arguments”
* Dial back our w00t indentation
* Better parsing of parameter names (WIP)
* Refactor processing of splat/expansion parameters
* Fix assignment of default parameters for parameters that come after a splat
* Better check for whether a param is attached to `this`
* More understandable variable names
* For parameters after a splat or expansion, assign them similar to the 1.x destructuring method of using `arguments`, except only concern ourselves with the post-splat parameters instead of all parameters; and use the splat/expansion parameter name, since `arguments` in ES fat arrow functions refers to the parent function’s `arguments` rather than the fat arrow function’s arguments/parameters
* Don’t add unnamed parameters (like `[]` as a parameter) to the function scope
* Disallow multiple splat/expansion parameters in function definitions; disallow lone expansion parameters
* Fix `this` params not getting assigned if the parameter is after a splat parameter
* Allow names of function parameters attached to `this` to be reserved words
* Always add a statement to the function body defining a variable with its default value, if it has one, if the variable `== null`; this covers the case when ES doesn’t apply the default value when `null` is passed in as a value, but CoffeeScript expects `null` and `undefined` to act interchangeably
* Aftermath of having both `undefined` and `null` trigger the use of default values for parameters with default values
* More careful parsing of destructured parameters
* Fall back to processing destructured parameters in the function body, to account for `this` or default values within destructured objects
* Clean up comments
* Restore new bare function test, minus the arrow function part of it
* Test that bound/arrow functions aren’t overwriting the `arguments` object, which should refer to the parent scope’s `arguments` (like `this`)
* Follow ES2015 spec for parameter default values: `null` gets assigned as as `null`, not the default value
* Mimic ES default parameters behavior for parameters after a splat or expansion parameter
* Bound functions cannot be generators: remove no-longer-relevant test, add check to throw error if `yield` appears inside a bound (arrow) function
* Error for bound generator functions should underline the `yield`
2016-10-26 01:26:13 -04:00
outputPath = function ( source , base , extension = ".js" ) {
2013-11-23 00:41:08 -05:00
var basename , dir , srcDir ;
2013-03-20 12:11:42 -04:00
basename = helpers . baseFileName ( source , true , useWinPathSep ) ;
2010-06-12 19:05:13 -04:00
srcDir = path . dirname ( source ) ;
2013-11-23 00:41:08 -05:00
if ( ! opts . output ) {
dir = srcDir ;
} else if ( source === base ) {
dir = opts . output ;
} else {
dir = path . join ( opts . output , path . relative ( base , srcDir ) ) ;
}
2013-03-04 09:25:55 -05:00
return path . join ( dir , basename + extension ) ;
2011-12-18 11:27:02 -05:00
} ;
2015-01-21 15:20:34 -05:00
mkdirp = function ( dir , fn ) {
var mkdirs , mode ;
2016-10-22 14:51:41 -04:00
mode = 0o777 & ~ process . umask ( ) ;
2015-01-21 15:20:34 -05:00
return ( mkdirs = function ( p , fn ) {
return fs . exists ( p , function ( exists ) {
if ( exists ) {
return fn ( ) ;
} else {
return mkdirs ( path . dirname ( p ) , function ( ) {
return fs . mkdir ( p , mode , function ( err ) {
if ( err ) {
return fn ( err ) ;
}
return fn ( ) ;
} ) ;
} ) ;
}
} ) ;
} ) ( dir , fn ) ;
} ;
[CS2] Output ES2015 arrow functions, default parameters, rest parameters (#4311)
* Eliminate wrapper around “bound” (arrow) functions; output `=>` for such functions
* Remove irrelevant (and breaking) tests
* Minor cleanup
* When a function parameter is a splat (i.e., it uses the ES2015 rest parameter syntax) output that parameter as ES2015
* Rearrange function parameters when one of the parameters is a splat and isn’t the last parameter (very WIP)
* Handle params like `@param`, adding assignment expressions for them when they appear; ensure splat parameter is last
* Add parameter names (not a text like `'\nValue IdentifierLiteral: a'`) to the scope, so that parameters can’t be deleted; move body-related lines together; more explanation of what’s going on
* For parameters with a default value, correctly add the parameter name to the function scope
* Handle expansions in function parameters: when an expansion is found, set the parameters to only be the original parameters left of the expansion, then an `...args` parameter; and in the function body define variables for the parameters to the right of the expansion, including setting default values
* Handle splat parameters the same way we handle expansions: if a splat parameter is found, it becomes the last parameter in the function definition, and all following parameters get declared in the function body. Fix the splat/rest parameter values after the post-splat parameters have been extracted from it. Clean up `Code.compileNode` so that we loop through the parameters only once, and we create all expressions using calls like `new IdentifierLiteral` rather than `@makeCode`.
* Fix parameter name when a parameter is a splat attached to `this` (e.g. `@param...`)
* Rather than assigning post-splat parameters based on index, use slice; passes test “Functions with splats being called with too few arguments”
* Dial back our w00t indentation
* Better parsing of parameter names (WIP)
* Refactor processing of splat/expansion parameters
* Fix assignment of default parameters for parameters that come after a splat
* Better check for whether a param is attached to `this`
* More understandable variable names
* For parameters after a splat or expansion, assign them similar to the 1.x destructuring method of using `arguments`, except only concern ourselves with the post-splat parameters instead of all parameters; and use the splat/expansion parameter name, since `arguments` in ES fat arrow functions refers to the parent function’s `arguments` rather than the fat arrow function’s arguments/parameters
* Don’t add unnamed parameters (like `[]` as a parameter) to the function scope
* Disallow multiple splat/expansion parameters in function definitions; disallow lone expansion parameters
* Fix `this` params not getting assigned if the parameter is after a splat parameter
* Allow names of function parameters attached to `this` to be reserved words
* Always add a statement to the function body defining a variable with its default value, if it has one, if the variable `== null`; this covers the case when ES doesn’t apply the default value when `null` is passed in as a value, but CoffeeScript expects `null` and `undefined` to act interchangeably
* Aftermath of having both `undefined` and `null` trigger the use of default values for parameters with default values
* More careful parsing of destructured parameters
* Fall back to processing destructured parameters in the function body, to account for `this` or default values within destructured objects
* Clean up comments
* Restore new bare function test, minus the arrow function part of it
* Test that bound/arrow functions aren’t overwriting the `arguments` object, which should refer to the parent scope’s `arguments` (like `this`)
* Follow ES2015 spec for parameter default values: `null` gets assigned as as `null`, not the default value
* Mimic ES default parameters behavior for parameters after a splat or expansion parameter
* Bound functions cannot be generators: remove no-longer-relevant test, add check to throw error if `yield` appears inside a bound (arrow) function
* Error for bound generator functions should underline the `yield`
2016-10-26 01:26:13 -04:00
writeJs = function ( base , sourcePath , js , jsPath , generatedSourceMap = null ) {
2013-03-06 11:05:57 -05:00
var compile , jsDir , sourceMapPath ;
2014-07-29 09:46:19 -04:00
sourceMapPath = outputPath ( sourcePath , base , ".js.map" ) ;
2011-12-18 11:27:02 -05:00
jsDir = path . dirname ( jsPath ) ;
2010-05-14 23:40:04 -04:00
compile = function ( ) {
2013-02-28 15:51:29 -05:00
if ( opts . compile ) {
if ( js . length <= 0 ) {
js = ' ' ;
2010-11-08 23:07:51 -05:00
}
2013-03-01 10:12:10 -05:00
if ( generatedSourceMap ) {
2016-11-28 09:05:51 -05:00
js = ` ${ js } \n //# sourceMappingURL= ${ helpers . baseFileName ( sourceMapPath , false , useWinPathSep ) } \n ` ;
2013-02-28 15:51:29 -05:00
}
fs . writeFile ( jsPath , js , function ( err ) {
if ( err ) {
2014-08-26 12:24:29 -04:00
printLine ( err . message ) ;
return process . exit ( 1 ) ;
2013-02-28 15:51:29 -05:00
} else if ( opts . compile && opts . watch ) {
2016-11-28 09:05:51 -05:00
return timeLog ( ` compiled ${ sourcePath } ` ) ;
2013-02-28 15:51:29 -05:00
}
} ) ;
}
2013-03-01 10:12:10 -05:00
if ( generatedSourceMap ) {
2013-03-01 05:58:26 -05:00
return fs . writeFile ( sourceMapPath , generatedSourceMap , function ( err ) {
2013-02-28 15:51:29 -05:00
if ( err ) {
2016-11-28 09:05:51 -05:00
printLine ( ` Could not write source map: ${ err . message } ` ) ;
2014-08-26 12:24:29 -04:00
return process . exit ( 1 ) ;
2013-02-28 15:51:29 -05:00
}
} ) ;
}
2010-05-04 23:22:28 -04:00
} ;
2013-11-22 01:24:36 -05:00
return fs . exists ( jsDir , function ( itExists ) {
2013-08-01 11:03:32 -04:00
if ( itExists ) {
2010-11-08 23:07:51 -05:00
return compile ( ) ;
} else {
2013-08-01 17:14:12 -04:00
return mkdirp ( jsDir , compile ) ;
2010-11-08 23:07:51 -05:00
}
2010-05-03 17:38:59 -04:00
} ) ;
2010-02-12 22:59:21 -05:00
} ;
2011-09-18 18:16:39 -04:00
2011-12-18 14:26:23 -05:00
wait = function ( milliseconds , func ) {
return setTimeout ( func , milliseconds ) ;
} ;
2011-12-18 11:27:02 -05:00
timeLog = function ( message ) {
2016-11-28 09:05:51 -05:00
return console . log ( ` ${ ( new Date ) . toLocaleTimeString ( ) } - ${ message } ` ) ;
2011-12-18 11:27:02 -05:00
} ;
2010-06-12 19:05:13 -04:00
printTokens = function ( tokens ) {
2013-03-04 02:54:45 -05:00
var strings , tag , token , value ;
2010-12-23 13:50:52 -05:00
strings = ( function ( ) {
2015-01-30 14:33:03 -05:00
var i , len , results ;
results = [ ] ;
for ( i = 0 , len = tokens . length ; i < len ; i ++ ) {
token = tokens [ i ] ;
2013-01-14 15:20:35 -05:00
tag = token [ 0 ] ;
value = token [ 1 ] . toString ( ) . replace ( /\n/ , '\\n' ) ;
2016-11-28 09:05:51 -05:00
results . push ( ` [ ${ tag } ${ value } ] ` ) ;
2010-02-24 18:56:32 -05:00
}
2015-01-30 14:33:03 -05:00
return results ;
2010-12-23 13:50:52 -05:00
} ) ( ) ;
2011-10-24 16:19:15 -04:00
return printLine ( strings . join ( ' ' ) ) ;
2010-02-24 18:56:32 -05:00
} ;
2011-09-18 18:16:39 -04:00
2010-06-12 19:05:13 -04:00
parseOptions = function ( ) {
2013-11-23 01:11:34 -05:00
var o ;
2010-12-18 09:29:04 -05:00
optionParser = new optparse . OptionParser ( SWITCHES , BANNER ) ;
2010-10-20 13:29:06 -04:00
o = opts = optionParser . parse ( process . argv . slice ( 2 ) ) ;
2010-10-01 18:17:35 -04:00
o . compile || ( o . compile = ! ! o . output ) ;
2013-04-27 13:35:32 -04:00
o . run = ! ( o . compile || o . print || o . map ) ;
2013-11-23 01:11:34 -05:00
return o . print = ! ! ( o . print || ( o [ "eval" ] || o . stdio && o . compile ) ) ;
2010-02-11 01:57:33 -05:00
} ;
2011-09-18 18:16:39 -04:00
2013-03-06 11:05:57 -05:00
compileOptions = function ( filename , base ) {
2013-03-07 21:26:09 -05:00
var answer , cwd , jsDir , jsPath ;
answer = {
2017-04-06 13:06:45 -04:00
filename ,
2013-04-27 13:35:32 -04:00
literate : opts . literate || helpers . isLiterate ( filename ) ,
2012-01-10 12:55:41 -05:00
bare : opts . bare ,
2013-10-20 11:03:37 -04:00
header : opts . compile && ! opts [ 'no-header' ] ,
2016-01-31 13:48:40 -05:00
sourceMap : opts . map ,
inlineMap : opts [ 'inline-map' ]
2010-03-07 22:08:24 -05:00
} ;
2013-03-07 21:26:09 -05:00
if ( filename ) {
if ( base ) {
cwd = process . cwd ( ) ;
jsPath = outputPath ( filename , base ) ;
jsDir = path . dirname ( jsPath ) ;
answer = helpers . merge ( answer , {
2017-04-06 13:06:45 -04:00
jsPath ,
2013-03-07 21:26:09 -05:00
sourceRoot : path . relative ( jsDir , cwd ) ,
sourceFiles : [ path . relative ( cwd , filename ) ] ,
2013-03-20 12:11:42 -04:00
generatedFile : helpers . baseFileName ( jsPath , false , useWinPathSep )
2013-03-07 21:26:09 -05:00
} ) ;
} else {
answer = helpers . merge ( answer , {
sourceRoot : "" ,
2013-03-20 12:11:42 -04:00
sourceFiles : [ helpers . baseFileName ( filename , false , useWinPathSep ) ] ,
generatedFile : helpers . baseFileName ( filename , true , useWinPathSep ) + ".js"
2013-03-07 21:26:09 -05:00
} ) ;
}
}
return answer ;
2010-02-24 18:18:29 -05:00
} ;
2011-09-18 18:16:39 -04:00
2010-12-18 09:29:04 -05:00
forkNode = function ( ) {
2013-09-02 16:54:17 -04:00
var args , nodeArgs , p ;
2010-12-18 09:29:04 -05:00
nodeArgs = opts . nodejs . split ( /\s+/ ) ;
args = process . argv . slice ( 1 ) ;
args . splice ( args . indexOf ( '--nodejs' ) , 2 ) ;
2013-09-02 16:54:17 -04:00
p = spawn ( process . execPath , nodeArgs . concat ( args ) , {
2010-12-17 02:39:39 -05:00
cwd : process . cwd ( ) ,
env : process . env ,
2014-10-03 23:54:07 -04:00
stdio : [ 0 , 1 , 2 ]
2010-12-17 02:39:39 -05:00
} ) ;
2013-09-02 16:54:17 -04:00
return p . on ( 'exit' , function ( code ) {
return process . exit ( code ) ;
} ) ;
2010-12-17 02:39:39 -05:00
} ;
2011-09-18 18:16:39 -04:00
2010-05-14 23:40:04 -04:00
usage = function ( ) {
2011-10-24 16:19:15 -04:00
return printLine ( ( new optparse . OptionParser ( SWITCHES , BANNER ) ) . help ( ) ) ;
2010-03-07 00:28:58 -05:00
} ;
2011-09-18 18:16:39 -04:00
2010-05-14 23:40:04 -04:00
version = function ( ) {
2016-11-28 09:05:51 -05:00
return printLine ( ` CoffeeScript version ${ CoffeeScript . VERSION } ` ) ;
2010-03-07 00:28:58 -05:00
} ;
2011-12-14 10:39:20 -05:00
2010-09-21 03:53:58 -04:00
} ) . call ( this ) ;