From 836175baab1eb0fa58125f703daf6fe296b40cf6 Mon Sep 17 00:00:00 2001 From: Sam Gentle Date: Fri, 20 Feb 2015 02:54:08 +1100 Subject: [PATCH] add -r/--require command line option --- lib/coffee-script/command.js | 22 ++++++++++++++++++++-- lib/coffee-script/repl.js | 18 ++++++++++++++---- src/command.coffee | 11 +++++++++++ src/repl.coffee | 13 ++++++++----- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/lib/coffee-script/command.js b/lib/coffee-script/command.js index cf718829..bab488bb 100644 --- a/lib/coffee-script/command.js +++ b/lib/coffee-script/command.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.9.1 (function() { - var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, jsToSources, mkdirp, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, ref, removeSource, removeSourceDir, silentUnlink, sourceCode, sources, spawn, timeLog, usage, useWinPathSep, version, wait, watch, watchDir, watchedDirs, writeJs, + var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, jsToSources, makePrelude, mkdirp, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, ref, removeSource, removeSourceDir, silentUnlink, sourceCode, sources, spawn, timeLog, usage, useWinPathSep, version, wait, watch, watchDir, watchedDirs, writeJs, 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; }; fs = require('fs'); @@ -35,7 +35,7 @@ BANNER = 'Usage: coffee [options] path/to/script.coffee -- [args]\n\nIf called without options, `coffee` will run your script.'; - 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'], ['-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'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-l', '--literate', 'treat stdio as literate style coffee-script'], ['-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']]; + 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'], ['-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 coffee-script'], ['-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']]; opts = {}; @@ -57,6 +57,10 @@ replCliOpts = { useGlobal: true }; + if (opts.require) { + opts.prelude = makePrelude(opts.require); + } + replCliOpts.prelude = opts.prelude; if (opts.nodejs) { return forkNode(); } @@ -98,6 +102,17 @@ return results; }; + makePrelude = function(requires) { + return requires.map(function(module) { + var _, match, name; + if (match = module.match(/^(.*)=(.*)$/)) { + _ = match[0], name = match[1], module = match[2]; + } + name || (name = helpers.baseFileName(module, true, useWinPathSep)); + return name + " = require('" + module + "')"; + }).join(';'); + }; + compilePath = function(source, topLevel, base) { var code, err, file, files, i, len, results, stats; if (indexOf.call(sources, source) >= 0 || watchedDirs[source] || !topLevel && (notSources[source] || hidden(source))) { @@ -205,6 +220,9 @@ return printLine(CoffeeScript.nodes(t.input, t.options).toString().trim()); } else if (o.run) { CoffeeScript.register(); + if (opts.prelude) { + CoffeeScript["eval"](opts.prelude, t.options); + } return CoffeeScript.run(t.input, t.options); } else if (o.join && t.file !== o.join) { if (helpers.isLiterate(file)) { diff --git a/lib/coffee-script/repl.js b/lib/coffee-script/repl.js index 90e29aab..e0663310 100644 --- a/lib/coffee-script/repl.js +++ b/lib/coffee-script/repl.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.9.1 (function() { - var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, ref, replDefaults, updateSyntaxError, vm; + var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, ref, replDefaults, runInContext, updateSyntaxError, vm; fs = require('fs'); @@ -19,7 +19,7 @@ historyFile: process.env.HOME ? path.join(process.env.HOME, '.coffee_history') : void 0, historyMaxInputSize: 10240, "eval": function(input, context, filename, cb) { - var Assign, Block, Literal, Value, ast, err, js, ref1, referencedVars, result, token, tokens; + var Assign, Block, Literal, Value, ast, err, js, ref1, referencedVars, token, tokens; input = input.replace(/\uFF00/g, '\n'); input = input.replace(/^\(([\s\S]*)\n\)$/m, '$1'); ref1 = require('./nodes'), Block = ref1.Block, Assign = ref1.Assign, Value = ref1.Value, Literal = ref1.Literal; @@ -43,8 +43,7 @@ locals: Object.keys(context), referencedVars: referencedVars }); - result = context === global ? vm.runInThisContext(js, filename) : vm.runInContext(js, context, filename); - return cb(null, result); + return cb(null, runInContext(js, context, filename)); } catch (_error) { err = _error; updateSyntaxError(err, input); @@ -53,6 +52,14 @@ } }; + runInContext = function(js, context, filename) { + if (context === global) { + return vm.runInThisContext(js, filename); + } else { + return vm.runInContext(js, context, filename); + } + }; + addMultilineHandler = function(repl) { var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref1, rli; rli = repl.rli, inputStream = repl.inputStream, outputStream = repl.outputStream; @@ -174,6 +181,9 @@ process.argv = ['coffee'].concat(process.argv.slice(2)); opts = merge(replDefaults, opts); repl = nodeREPL.start(opts); + if (opts.prelude) { + runInContext(opts.prelude, repl.context, 'prelude'); + } repl.on('exit', function() { return repl.outputStream.write('\n'); }); diff --git a/src/command.coffee b/src/command.coffee index 22dad334..5e048b03 100644 --- a/src/command.coffee +++ b/src/command.coffee @@ -44,6 +44,7 @@ SWITCHES = [ [ '--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 coffee-script'] ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce'] @@ -69,6 +70,8 @@ exports.run = -> # `node` REPL CLI and, therefore, (b) make packages that modify native prototypes # (such as 'colors' and 'sugar') work as expected. replCliOpts = useGlobal: yes + opts.prelude = makePrelude opts.require if opts.require + replCliOpts.prelude = opts.prelude return forkNode() if opts.nodejs return usage() if opts.help return version() if opts.version @@ -101,6 +104,13 @@ exports.run = -> source = path.resolve source compilePath source, yes, source +makePrelude = (requires) -> + requires.map (module) -> + [_, name, module] = match if match = module.match(/^(.*)=(.*)$/) + name ||= helpers.baseFileName module, yes, useWinPathSep + "#{name} = require('#{module}')" + .join ';' + # Compile a path, which could be a script or a directory. If a directory # is passed, recursively compile all '.coffee', '.litcoffee', and '.coffee.md' # extension source files in it and all subdirectories. @@ -167,6 +177,7 @@ compileScript = (file, input, base = null) -> printLine CoffeeScript.nodes(t.input, t.options).toString().trim() else if o.run CoffeeScript.register() + CoffeeScript.eval opts.prelude, t.options if opts.prelude CoffeeScript.run t.input, t.options else if o.join and t.file isnt o.join t.input = helpers.invertLiterate t.input if helpers.isLiterate file diff --git a/src/repl.coffee b/src/repl.coffee index f5f2fa5c..7c859fb9 100644 --- a/src/repl.coffee +++ b/src/repl.coffee @@ -33,16 +33,18 @@ replDefaults = new Assign (new Value new Literal '_'), ast, '=' ] js = ast.compile {bare: yes, locals: Object.keys(context), referencedVars} - result = if context is global - vm.runInThisContext js, filename - else - vm.runInContext js, context, filename - cb null, result + cb null, runInContext js, context, filename catch err # AST's `compile` does not add source code information to syntax errors. updateSyntaxError err, input cb err +runInContext = (js, context, filename) -> + if context is global + vm.runInThisContext js, filename + else + vm.runInContext js, context, filename + addMultilineHandler = (repl) -> {rli, inputStream, outputStream} = repl # Node 0.11.12 changed API, prompt is now _prompt. @@ -149,6 +151,7 @@ module.exports = process.argv = ['coffee'].concat process.argv[2..] opts = merge replDefaults, opts repl = nodeREPL.start opts + runInContext opts.prelude, repl.context, 'prelude' if opts.prelude repl.on 'exit', -> repl.outputStream.write '\n' addMultilineHandler repl addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile