adding compilation over stdin/stdout. Use --stdio or -s, and pipe away.

This commit is contained in:
Jeremy Ashkenas 2010-02-24 18:18:29 -05:00
parent aba8cb1b08
commit 9f8710b631
4 changed files with 57 additions and 27 deletions

View File

@ -1,11 +1,11 @@
(function(){
var BANNER, SWITCHES, coffee, compile_script, compile_scripts, fs, lint, option_parser, options, optparse, parse_options, path, sources, usage, version, watch_scripts, write_js;
var BANNER, SWITCHES, coffee, compile_options, compile_script, compile_scripts, compile_stdio, 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'], ['-n', '--no-wrap', 'compile without the top-level function wrapper'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
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'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-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'], ['-n', '--no-wrap', 'compile without the top-level function wrapper'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
options = {};
sources = [];
option_parser = null;
@ -22,6 +22,9 @@
if (options.interactive) {
return require('repl');
}
if (options.stdio) {
return compile_stdio();
}
if (options.eval) {
return compile_script('unknown', sources[0]);
}
@ -70,36 +73,46 @@
// 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, o, opts;
opts = options;
o = opts['no-wrap'] ? {
no_wrap: true
} : {};
var js;
try {
if (opts.tokens) {
if (options.tokens) {
return coffee.print_tokens(coffee.tokenize(code));
} else if (opts.tree) {
} else if (options.tree) {
return puts(coffee.tree(code).toString());
} else {
js = coffee.compile(code, o);
if (opts.run) {
js = coffee.compile(code, compile_options());
if (options.run) {
return eval(js);
} else if (opts.lint) {
} else if (options.lint) {
return lint(js);
} else if (opts.print || opts.eval) {
} else if (options.print || options.eval) {
return puts(js);
} else {
return write_js(source, js);
}
}
} catch (err) {
if (opts.watch) {
if (options.watch) {
return puts(err.message);
} else {
throw err;
}
}
};
// Listen for and compile scripts over stdio.
compile_stdio = function compile_stdio() {
var code;
code = '';
process.stdio.open();
process.stdio.addListener('data', function(string) {
if (string) {
return code += string;
}
});
return process.stdio.addListener('close', function() {
return process.stdio.write(coffee.compile(code, compile_options()));
});
};
// Watch a list of source CoffeeScript files, recompiling them every time the
// files are updated.
watch_scripts = function watch_scripts() {
@ -155,4 +168,10 @@
options = option_parser.parse(process.ARGV);
return sources = options.arguments.slice(2, options.arguments.length);
};
// The options to pass to the CoffeeScript compiler.
compile_options = function compile_options() {
return options['no-wrap'] ? {
no_wrap: true
} : {};
};
})();

View File

@ -233,7 +233,7 @@
o.scope = new Scope(null, this, null);
code = o.globals ? this.compile_node(o) : this.compile_with_declarations(o);
code = code.replace(TRAILING_WHITESPACE, '');
return o.no_wrap ? code : "(function(){\n" + code + "\n})();";
return o.no_wrap ? code : "(function(){\n" + code + "\n})();\n";
},
// Compile the expressions body, with declarations of all inner variables
// pushed up to the top.

View File

@ -17,6 +17,7 @@ SWITCHES: [
['-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']
['-t', '--tokens', 'print the tokens that the lexer produces']
['-tr','--tree', 'print the parse tree that Jison produces']
@ -35,6 +36,7 @@ exports.run: ->
return usage() if options.help
return version() if options.version
return require 'repl' if options.interactive
return compile_stdio() if options.stdio
return compile_script 'unknown', sources[0] if options.eval
return usage() unless sources.length
separator: sources.indexOf '--'
@ -64,23 +66,29 @@ compile_scripts: ->
fs.readFile source, (err, code) -> compile_script(source, code)
compile(source) for source in sources
# 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
o: if opts['no-wrap'] then {no_wrap: true} else {}
try
if opts.tokens then coffee.print_tokens coffee.tokenize code
else if opts.tree then puts coffee.tree(code).toString()
if options.tokens then coffee.print_tokens coffee.tokenize code
else if options.tree then puts coffee.tree(code).toString()
else
js: coffee.compile code, o
if opts.run then eval js
else if opts.lint then lint js
else if opts.print or opts.eval then puts js
else write_js source, js
js: coffee.compile code, compile_options()
if options.run then eval js
else if options.lint then lint js
else if options.print or options.eval then puts js
else write_js source, js
catch err
if opts.watch then puts err.message else throw err
if options.watch then puts err.message else throw err
# Listen for and compile scripts over stdio.
compile_stdio: ->
code: ''
process.stdio.open()
process.stdio.addListener 'data', (string) ->
code += string if string
process.stdio.addListener 'close', ->
process.stdio.write coffee.compile code, compile_options()
# Watch a list of source CoffeeScript files, recompiling them every time the
# files are updated.
@ -114,3 +122,6 @@ parse_options: ->
options: option_parser.parse(process.ARGV)
sources: options.arguments[2...options.arguments.length]
# The options to pass to the CoffeeScript compiler.
compile_options: ->
if options['no-wrap'] then {no_wrap: true} else {}

View File

@ -156,7 +156,7 @@ Expressions: exports.Expressions: inherit Node, {
o.scope: new Scope(null, this, null)
code: if o.globals then @compile_node(o) else @compile_with_declarations(o)
code: code.replace(TRAILING_WHITESPACE, '')
if o.no_wrap then code else "(function(){\n"+code+"\n})();"
if o.no_wrap then code else "(function(){\n"+code+"\n})();\n"
# Compile the expressions body, with declarations of all inner variables
# pushed up to the top.