diff --git a/lib/command.js b/lib/command.js index 3dfd788c..7a3b86c1 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1,5 +1,5 @@ (function() { - var ALL_SWITCHES, BANNER, CoffeeScript, DEPRECATED_SWITCHES, EventEmitter, SWITCHES, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printTokens, sources, spawn, usage, version, watch, writeJs, _ref; + var ALL_SWITCHES, BANNER, CoffeeScript, DEPRECATED_SWITCHES, EventEmitter, SWITCHES, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, version, watch, writeJs, _ref; fs = require('fs'); path = require('path'); helpers = require('./helpers'); @@ -8,6 +8,12 @@ _ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec; EventEmitter = require('events').EventEmitter; helpers.extend(CoffeeScript, new EventEmitter); + printLine = function(line) { + return process.stdout.write(line + '\n'); + }; + printWarn = function(line) { + return process.binding('stdio').writeError(line + '\n'); + }; BANNER = 'Usage: coffee [options] path/to/script.coffee'; 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'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-b', '--bare', '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']]; DEPRECATED_SWITCHES = [['--no-wrap', 'compile without the top-level function wrapper']]; @@ -109,14 +115,14 @@ if (o.tokens) { return printTokens(CoffeeScript.tokens(t.input)); } else if (o.nodes) { - return console.log(CoffeeScript.nodes(t.input).toString().trim()); + return printLine(CoffeeScript.nodes(t.input).toString().trim()); } else if (o.run) { return CoffeeScript.run(t.input, t.options); } else { t.output = CoffeeScript.compile(t.input, t.options); CoffeeScript.emit('success', task); if (o.print) { - return console.log(t.output.trim()); + return printLine(t.output.trim()); } else if (o.compile) { return writeJs(t.file, t.output, base); } else if (o.lint) { @@ -129,9 +135,9 @@ return; } if (o.watch) { - return console.log(err.message); + return printLine(err.message); } - console.error(err.stack); + printWarn(err.stack); return process.exit(1); } }; @@ -177,9 +183,9 @@ } return fs.writeFile(jsPath, js, function(err) { if (err) { - return console.log(err.message); + return printLine(err.message); } else if (opts.compile && opts.watch) { - return console.log("Compiled " + source); + return printLine("Compiled " + source); } }); }; @@ -194,7 +200,7 @@ lint = function(file, js) { var conf, jsl, printIt; printIt = function(buffer) { - return console.log(file + ':\t' + buffer.toString().trim()); + return printLine(file + ':\t' + buffer.toString().trim()); }; conf = __dirname + '/../extras/jsl.conf'; jsl = spawn('jsl', ['-nologo', '-stdin', '-conf', conf]); @@ -214,7 +220,7 @@ } return _results; }(); - return console.log(strings.join(' ')); + return printLine(strings.join(' ')); }; parseOptions = function() { var o; @@ -225,7 +231,7 @@ o.print = !!(o.print || (o.eval || o.stdio && o.compile)); sources = o.arguments; if (opts['no-wrap']) { - return console.warn('--no-wrap is deprecated; please use --bare instead.'); + return printWarn('--no-wrap is deprecated; please use --bare instead.'); } }; compileOptions = function(fileName) { @@ -235,11 +241,11 @@ }; }; usage = function() { - console.log((new optparse.OptionParser(SWITCHES, BANNER)).help()); + printLine((new optparse.OptionParser(SWITCHES, BANNER)).help()); return process.exit(0); }; version = function() { - console.log("CoffeeScript version " + CoffeeScript.VERSION); + printLine("CoffeeScript version " + CoffeeScript.VERSION); return process.exit(0); }; }).call(this); diff --git a/src/command.coffee b/src/command.coffee index 00c039e6..9a7711d7 100644 --- a/src/command.coffee +++ b/src/command.coffee @@ -16,6 +16,9 @@ CoffeeScript = require './coffee-script' # Allow CoffeeScript to emit Node.js events. helpers.extend CoffeeScript, new EventEmitter +printLine = (line) -> process.stdout.write line + '\n' +printWarn = (line) -> process.binding('stdio').writeError line + '\n' + # The help banner that is printed when `coffee` is called without arguments. BANNER = ''' Usage: coffee [options] path/to/script.coffee @@ -103,19 +106,19 @@ compileScript = (file, input, base) -> t = task = {file, input, options} CoffeeScript.emit 'compile', task if o.tokens then printTokens CoffeeScript.tokens t.input - else if o.nodes then console.log CoffeeScript.nodes(t.input).toString().trim() + else if o.nodes then printLine CoffeeScript.nodes(t.input).toString().trim() else if o.run then CoffeeScript.run t.input, t.options else t.output = CoffeeScript.compile t.input, t.options CoffeeScript.emit 'success', task - if o.print then console.log t.output.trim() + if o.print then printLine t.output.trim() else if o.compile then writeJs t.file, t.output, base else if o.lint then lint t.file, t.output catch err CoffeeScript.emit 'failure', err, task return if CoffeeScript.listeners('failure').length - return console.log err.message if o.watch - console.error err.stack + return printLine err.message if o.watch + printWarn err.stack process.exit 1 # Attach the appropriate listeners to compile scripts incoming over **stdin**, @@ -150,15 +153,15 @@ writeJs = (source, js, base) -> compile = -> js = ' ' if js.length <= 0 fs.writeFile jsPath, js, (err) -> - if err then console.log err.message - else if opts.compile and opts.watch then console.log "Compiled #{source}" + if err then printLine err.message + else if opts.compile and opts.watch then printLine "Compiled #{source}" path.exists dir, (exists) -> if exists then compile() else exec "mkdir -p #{dir}", compile # Pipe compiled JS through JSLint (requires a working `jsl` command), printing # any errors or warnings that arise. lint = (file, js) -> - printIt = (buffer) -> console.log file + ':\t' + buffer.toString().trim() + printIt = (buffer) -> printLine file + ':\t' + buffer.toString().trim() conf = __dirname + '/../extras/jsl.conf' jsl = spawn 'jsl', ['-nologo', '-stdin', '-conf', conf] jsl.stdout.on 'data', printIt @@ -171,7 +174,7 @@ printTokens = (tokens) -> strings = for token in tokens [tag, value] = [token[0], token[1].toString().replace(/\n/, '\\n')] "[#{tag} #{value}]" - console.log strings.join(' ') + printLine strings.join(' ') # Use the [OptionParser module](optparse.html) to extract all options from # `process.argv` that are specified in `SWITCHES`. @@ -183,7 +186,7 @@ parseOptions = -> o.print = !! (o.print or (o.eval or o.stdio and o.compile)) sources = o.arguments if opts['no-wrap'] - console.warn '--no-wrap is deprecated; please use --bare instead.' + printWarn '--no-wrap is deprecated; please use --bare instead.' # The compile-time options to pass to the CoffeeScript compiler. compileOptions = (fileName) -> {fileName, bare: opts.bare or opts['no-wrap']} @@ -191,10 +194,10 @@ compileOptions = (fileName) -> {fileName, bare: opts.bare or opts['no-wrap']} # Print the `--help` usage message and exit. Deprecated switches are not # shown. usage = -> - console.log (new optparse.OptionParser SWITCHES, BANNER).help() + printLine (new optparse.OptionParser SWITCHES, BANNER).help() process.exit 0 # Print the `--version` message and exit. version = -> - console.log "CoffeeScript version #{CoffeeScript.VERSION}" + printLine "CoffeeScript version #{CoffeeScript.VERSION}" process.exit 0 diff --git a/test/test_compilation.coffee b/test/test_compilation.coffee index 078ab648..b8669f1f 100644 --- a/test/test_compilation.coffee +++ b/test/test_compilation.coffee @@ -1,3 +1,5 @@ +{ exec } = require 'child_process' + # Ensure that carriage returns don't break compilation on Windows. eq CoffeeScript.compile('one\r\ntwo', bare: on), 'one;\ntwo;' @@ -12,3 +14,9 @@ catch e then eq e.message, 'unclosed CALL_START on line 1' eq CoffeeScript.compile('for all k of o then', bare: on, globals: on), 'for (k in o) {}' + +#875: %d and %s in strings causes node.js to apply formatting +cmd = process.argv[1].replace /cake$/, 'coffee' +exec "#{cmd} -bpe \"'%d isnt %s'\"", (error, stdout, stderr) -> + throw error if error + eq stdout.trim(), "'%d isnt %s';"