diff --git a/lib/command.js b/lib/command.js index fe135401..de74a976 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1,6 +1,5 @@ (function() { var BANNER, CoffeeScript, EventEmitter, SWITCHES, _a, _b, _c, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, options, optparse, parseOptions, path, printTokens, sources, spawn, usage, version, watch, writeJs; - var __hasProp = Object.prototype.hasOwnProperty; fs = require('fs'); path = require('path'); optparse = require('./optparse'); @@ -14,13 +13,7 @@ EventEmitter = _c.EventEmitter; helpers.extend(CoffeeScript, new EventEmitter()); BANNER = 'coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee 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 the library, before executing your script', { - isList: true - } - ], ['--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'] - ]; + 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'], ['--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']]; options = {}; sources = []; optionParser = null; @@ -101,29 +94,14 @@ return _d; }; compileScript = function(source, code, base) { - var _d, _e, _f, _g, _h, _i, codeOpts, file, globalize, js, name, o, ref; + var _d, _e, _f, codeOpts, file, js, o; o = options; codeOpts = compileOptions(source); if (o.require) { - globalize = { - CoffeeScript: CoffeeScript - }; - _d = globalize; - for (name in _d) { - if (!__hasProp.call(_d, name)) continue; - ref = _d[name]; - (global[name] = ref); - } - _f = o.require; - for (_e = 0, _g = _f.length; _e < _g; _e++) { - file = _f[_e]; - require(file.replace(/^(\.+\/)/, ("" + (process.cwd()) + "/$1"))); - } - _i = globalize; - for (name in _i) { - if (!__hasProp.call(_i, name)) continue; - _h = _i[name]; - delete global[name]; + _e = o.require; + for (_d = 0, _f = _e.length; _d < _f; _d++) { + file = _e[_d]; + require(file); } } try { @@ -151,13 +129,14 @@ } } } catch (err) { - CoffeeScript.emit('exception', err); - if (!(o.watch || err.handled)) { + CoffeeScript.emit('failure', err); + if (CoffeeScript.listeners('failure').length) { + return null; + } + if (!(o.watch)) { error(err.stack) && process.exit(1); } - if (!(err.handled)) { - return puts(err.message); - } + return puts(err.message); } }; compileStdio = function() { diff --git a/lib/optparse.js b/lib/optparse.js index e64682a9..138b9a19 100755 --- a/lib/optparse.js +++ b/lib/optparse.js @@ -64,7 +64,7 @@ LONG_FLAG = /^(--\w[\w\-]+)/; SHORT_FLAG = /^(-\w)/; MULTI_FLAG = /^-(\w{2,})/; - OPTIONAL = /\[(.+)\]/; + OPTIONAL = /\[(\w+(\*?))\]/; buildRules = function(rules) { var _a, _b, _c, _d, tuple; _a = []; _c = rules; @@ -90,7 +90,7 @@ longFlag: longFlag, description: description, hasArgument: !!(match && match[1]), - isList: !!options.isList + isList: !!(match && match[2]) }; }; normalizeArguments = function(args) { diff --git a/src/command.coffee b/src/command.coffee index 6411220d..b30d4bf1 100644 --- a/src/command.coffee +++ b/src/command.coffee @@ -25,20 +25,20 @@ BANNER = ''' # The list of all the valid option flags that `coffee` knows how to handle. 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 the library, before executing your script', isList: yes] - [ '--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'] + ['-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'] + [ '--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'] ] # Top-level objects shared by all the functions. @@ -94,10 +94,7 @@ compileScript = (source, code, base) -> o = options codeOpts = compileOptions source if o.require - globalize = {CoffeeScript} - (global[name] = ref) for name, ref of globalize - require file.replace /^(\.+\/)/, "#{ process.cwd() }/$1" for file in o.require - delete global[name] for name of globalize + require file for file in o.require try CoffeeScript.emit 'compile', {source, code, base, options} if o.tokens then printTokens CoffeeScript.tokens code @@ -112,9 +109,10 @@ compileScript = (source, code, base) -> catch err # Avoid using 'error' as it is a special event -- if there is no handler, # node will print a stack trace and exit the program. - CoffeeScript.emit 'exception', err - error(err.stack) and process.exit 1 unless o.watch or err.handled - puts err.message unless err.handled + CoffeeScript.emit 'failure', err + return if CoffeeScript.listeners('failure').length + error(err.stack) and process.exit 1 unless o.watch + puts err.message # Attach the appropriate listeners to compile scripts incoming over **stdin**, # and write them back to **stdout**. diff --git a/src/optparse.coffee b/src/optparse.coffee index 0c8663c8..991e0bbe 100644 --- a/src/optparse.coffee +++ b/src/optparse.coffee @@ -59,7 +59,7 @@ exports.OptionParser = class OptionParser LONG_FLAG = /^(--\w[\w\-]+)/ SHORT_FLAG = /^(-\w)/ MULTI_FLAG = /^-(\w{2,})/ -OPTIONAL = /\[(.+)\]/ +OPTIONAL = /\[(\w+(\*?))\]/ # Build and return the list of option rules. If the optional *short-flag* is # unspecified, leave it out by padding with `null`. @@ -80,7 +80,7 @@ buildRule = (shortFlag, longFlag, description, options) -> longFlag: longFlag description: description hasArgument: !!(match and match[1]) - isList: !!options.isList + isList: !!(match and match[2]) } # Normalize arguments by expanding merged flags into multiple flags. This allows diff --git a/test/test_option_parser.coffee b/test/test_option_parser.coffee index d969518e..97fbf44c 100644 --- a/test/test_option_parser.coffee +++ b/test/test_option_parser.coffee @@ -5,6 +5,7 @@ opt = new OptionParser [ ['-r', '--required [DIR]', 'desc required'] ['-o', '--optional', 'desc optional'] + ['-l', '--list [FILES*]', 'desc list'] ] result = opt.parse ['one', 'two', 'three', '-r', 'dir'] @@ -18,3 +19,9 @@ ok result.optional is true ok result.required is 'folder' ok result.arguments.join(' ') is 'one two' +result = opt.parse ['-l', 'one.txt', '-l', 'two.txt', 'three'] + +ok result.list instanceof Array +ok result.list.join(' ') is 'one.txt two.txt' +ok result.arguments.join(' ') is 'three' +