From 9f2badb3e901fe3827d3ed42750d7025732441b1 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Tue, 16 Feb 2010 23:59:32 -0500 Subject: [PATCH] got a really nice --watch flag for bin/node_coffee going, thanks to Node.js' process.watchFile. Can be used with --print, --lint, --tokens, --run, or whatever your needs may be --- lib/coffee_script/command_line.js | 67 +++++++++++++++++++++++-------- src/command_line.coffee | 27 ++++++++++--- 2 files changed, 72 insertions(+), 22 deletions(-) diff --git a/lib/coffee_script/command_line.js b/lib/coffee_script/command_line.js index d17aa19a..a9d41184 100644 --- a/lib/coffee_script/command_line.js +++ b/lib/coffee_script/command_line.js @@ -1,15 +1,11 @@ (function(){ - var BANNER, SWITCHES, WATCH_INTERVAL, coffee, compile, compile_scripts, fs, lint, option_parser, options, optparse, parse_options, path, sources, usage, version, write_js; + var BANNER, SWITCHES, coffee, compile, compile_script, compile_scripts, fs, lint, option_parser, options, optparse, parse_options, path, sources, usage, version, watch_scripts, write_js; fs = require('fs'); path = require('path'); coffee = require('coffee-script'); optparse = require('optparse'); BANNER = "coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee"; - SWITCHES = [['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-r', '--run', 'compile and run a CoffeeScript'], ['-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'], ['-e', '--eval', 'compile a string from the command line'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-tr', '--tree', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message'] - ]; - WATCH_INTERVAL = 0.5; + SWITCHES = [['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-r', '--run', 'compile and run a CoffeeScript'], ['-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'], ['-e', '--eval', 'compile a string from the command line'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-tr', '--tree', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']]; options = {}; sources = []; option_parser = null; @@ -33,6 +29,9 @@ sources = sources.slice(0, separator); } process.ARGV = flags; + if (options.watch) { + watch_scripts(); + } compile_scripts(); return this; }; @@ -69,31 +68,65 @@ // Compiles the source CoffeeScript, returning the desired JavaScript, tokens, // or JSLint results. compile_scripts = function compile_scripts() { - var opts, source; + var source; if (!((source = sources.shift()))) { return null; } - opts = options; return fs.cat(source).addCallback(function(code) { - var js; + compile_script(source, code); + return compile_scripts(); + }); + }; + // Compile a single source script, containing the given code, according to the + // requested options. Both compile_scripts and watch_scripts share this method. + compile_script = function compile_script(source, code) { + var js, opts; + opts = options; + try { if (opts.tokens) { - coffee.print_tokens(coffee.tokenize(code)); + return coffee.print_tokens(coffee.tokenize(code)); } else if (opts.tree) { - puts(coffee.tree(code).toString()); + return puts(coffee.tree(code).toString()); } else { js = coffee.compile(code); if (opts.run) { - eval(js); + return eval(js); } else if (opts.print) { - puts(js); + return puts(js); } else if (opts.lint) { - lint(js); + return lint(js); } else { - write_js(source, coffee.compile(code)); + return write_js(source, coffee.compile(code)); } } - return compile_scripts(); - }); + } catch (err) { + if (opts.watch) { + return puts(err.message); + } else { + throw err; + } + } + }; + // Watch a list of source CoffeeScript files, recompiling them every time the + // files are updated. + watch_scripts = function watch_scripts() { + var _a, _b, _c, source; + _a = []; _b = sources; + for (_c = 0; _c < _b.length; _c++) { + source = _b[_c]; + _a.push(process.watchFile(source, { + persistent: true, + interval: 500 + }, function(curr, prev) { + if (curr.mtime.getTime() === prev.mtime.getTime()) { + return null; + } + return fs.cat(source).addCallback(function(code) { + return compile_script(source, code); + }); + })); + } + return _a; }; // Write out a JavaScript source file with the compiled code. write_js = function write_js(source, js) { diff --git a/src/command_line.coffee b/src/command_line.coffee index 2c7ac7ff..f7a78a94 100644 --- a/src/command_line.coffee +++ b/src/command_line.coffee @@ -14,7 +14,7 @@ SWITCHES: [ ['-i', '--interactive', 'run an interactive CoffeeScript REPL'] ['-r', '--run', 'compile and run a CoffeeScript'] ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'] - # ['-w', '--watch', 'watch scripts for changes, and recompile'] + ['-w', '--watch', 'watch scripts for changes, and recompile'] ['-p', '--print', 'print the compiled JavaScript to stdout'] ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'] ['-e', '--eval', 'compile a string from the command line'] @@ -24,8 +24,6 @@ SWITCHES: [ ['-h', '--help', 'display this help message'] ] -WATCH_INTERVAL: 0.5 - options: {} sources: [] option_parser: null @@ -42,6 +40,7 @@ exports.run: -> flags: sources[(separator + 1)...sources.length] sources: sources[0...separator] process.ARGV = flags + watch_scripts() if options.watch compile_scripts() this @@ -72,8 +71,15 @@ compile: (script, source) -> # or JSLint results. compile_scripts: -> return unless source: sources.shift() - opts: options fs.cat(source).addCallback (code) -> + compile_script(source, code) + compile_scripts() + +# Compile a single source script, containing the given code, according to the +# requested options. Both compile_scripts and watch_scripts share this method. +compile_script: (source, code) -> + opts: options + try if opts.tokens then coffee.print_tokens coffee.tokenize code else if opts.tree then puts coffee.tree(code).toString() else @@ -82,7 +88,17 @@ compile_scripts: -> else if opts.print then puts js else if opts.lint then lint js else write_js source, coffee.compile code - compile_scripts() + catch err + if opts.watch then puts err.message else throw err + +# Watch a list of source CoffeeScript files, recompiling them every time the +# files are updated. +watch_scripts: -> + for source in sources + process.watchFile source, {persistent: true, interval: 500}, (curr, prev) -> + return if curr.mtime.getTime() is prev.mtime.getTime() + fs.cat(source).addCallback (code) -> compile_script(source, code) + # Write out a JavaScript source file with the compiled code. write_js: (source, js) -> @@ -122,3 +138,4 @@ parse_options: -> paths: oparser.parse(process.ARGV) sources: paths[2...paths.length] +