1 // Generated by CoffeeScript 1.10.0
3 var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, 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,
4 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; };
8 path = require('path');
10 helpers = require('./helpers');
12 optparse = require('./optparse');
14 CoffeeScript = require('./coffee-script');
16 ref = require('child_process'), spawn = ref.spawn, exec = ref.exec;
18 EventEmitter = require('events').EventEmitter;
20 useWinPathSep = path.sep === '\\';
22 helpers.extend(CoffeeScript, new EventEmitter);
24 printLine = function(line) {
25 return process.stdout.write(line + '\n');
28 printWarn = function(line) {
29 return process.stderr.write(line + '\n');
32 hidden = function(file) {
33 return /^\.|~$/.test(file);
36 BANNER = 'Usage: coffee [options] path/to/script.coffee -- [args]\n\nIf called without options, `coffee` will run your script.';
38 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']];
52 exports.run = function() {
53 var i, len, literals, ref1, replCliOpts, results, source;
59 opts.prelude = makePrelude(opts.require);
61 replCliOpts.prelude = opts.prelude;
71 if (opts.interactive) {
72 return require('./repl').start(replCliOpts);
75 return compileStdio();
78 return compileScript(null, opts["arguments"][0]);
80 if (!opts["arguments"].length) {
81 return require('./repl').start(replCliOpts);
83 literals = opts.run ? opts["arguments"].splice(1) : [];
84 process.argv = process.argv.slice(0, 2).concat(literals);
85 process.argv[0] = 'coffee';
87 opts.output = path.resolve(opts.output);
90 opts.join = path.resolve(opts.join);
91 console.error('\nThe --join option is deprecated and will be removed in a future version.\n\nIf for some reason it\'s necessary to share local variables between files,\nreplace...\n\n $ coffee --compile --join bundle.js -- a.coffee b.coffee c.coffee\n\nwith...\n\n $ cat a.coffee b.coffee c.coffee | coffee --compile --stdio > bundle.js\n');
93 ref1 = opts["arguments"];
95 for (i = 0, len = ref1.length; i < len; i++) {
97 source = path.resolve(source);
98 results.push(compilePath(source, true, source));
103 makePrelude = function(requires) {
104 return requires.map(function(module) {
106 if (match = module.match(/^(.*)=(.*)$/)) {
107 _ = match[0], name = match[1], module = match[2];
109 name || (name = helpers.baseFileName(module, true, useWinPathSep));
110 return name + " = require('" + module + "')";
114 compilePath = function(source, topLevel, base) {
115 var code, err, error, error1, error2, file, files, i, len, results, stats;
116 if (indexOf.call(sources, source) >= 0 || watchedDirs[source] || !topLevel && (notSources[source] || hidden(source))) {
120 stats = fs.statSync(source);
123 if (err.code === 'ENOENT') {
124 console.error("File not found: " + source);
129 if (stats.isDirectory()) {
130 if (path.basename(source) === 'node_modules') {
131 notSources[source] = true;
135 compilePath(findDirectoryIndex(source), topLevel, base);
139 watchDir(source, base);
142 files = fs.readdirSync(source);
145 if (err.code === 'ENOENT') {
152 for (i = 0, len = files.length; i < len; i++) {
154 results.push(compilePath(path.join(source, file), false, base));
157 } else if (topLevel || helpers.isCoffee(source)) {
158 sources.push(source);
159 sourceCode.push(null);
160 delete notSources[source];
165 code = fs.readFileSync(source);
168 if (err.code === 'ENOENT') {
174 return compileScript(source, code.toString(), base);
176 return notSources[source] = true;
180 findDirectoryIndex = function(source) {
181 var err, error, ext, i, index, len, ref1;
182 ref1 = CoffeeScript.FILE_EXTENSIONS;
183 for (i = 0, len = ref1.length; i < len; i++) {
185 index = path.join(source, "index" + ext);
187 if ((fs.statSync(index)).isFile()) {
192 if (err.code !== 'ENOENT') {
197 console.error("Missing index.coffee or index.litcoffee in " + source);
198 return process.exit(1);
201 compileScript = function(file, input, base) {
202 var compiled, err, error, message, o, options, t, task;
207 options = compileOptions(file, base);
214 CoffeeScript.emit('compile', task);
216 return printTokens(CoffeeScript.tokens(t.input, t.options));
217 } else if (o.nodes) {
218 return printLine(CoffeeScript.nodes(t.input, t.options).toString().trim());
220 CoffeeScript.register();
222 CoffeeScript["eval"](opts.prelude, t.options);
224 return CoffeeScript.run(t.input, t.options);
225 } else if (o.join && t.file !== o.join) {
226 if (helpers.isLiterate(file)) {
227 t.input = helpers.invertLiterate(t.input);
229 sourceCode[sources.indexOf(t.file)] = t.input;
230 return compileJoin();
232 compiled = CoffeeScript.compile(t.input, t.options);
235 t.output = compiled.js;
236 t.sourceMap = compiled.v3SourceMap;
238 CoffeeScript.emit('success', task);
240 return printLine(t.output.trim());
241 } else if (o.compile || o.map) {
242 return writeJs(base, t.file, t.output, options.jsPath, t.sourceMap);
247 CoffeeScript.emit('failure', err, task);
248 if (CoffeeScript.listeners('failure').length) {
251 message = err.stack || ("" + err);
253 return printLine(message + '\x07');
256 return process.exit(1);
261 compileStdio = function() {
264 stdin = process.openStdin();
265 stdin.on('data', function(buffer) {
267 return code += buffer.toString();
270 return stdin.on('end', function() {
271 return compileScript(null, code);
277 compileJoin = function() {
281 if (!sourceCode.some(function(code) {
282 return code === null;
284 clearTimeout(joinTimeout);
285 return joinTimeout = wait(100, function() {
286 return compileScript(opts.join, sourceCode.join('\n'), opts.join);
291 watch = function(source, base) {
292 var compile, compileTimeout, err, error, prevStats, rewatch, startWatcher, watchErr, watcher;
295 compileTimeout = null;
296 watchErr = function(err) {
298 if (err.code !== 'ENOENT') {
301 if (indexOf.call(sources, source) < 0) {
308 removeSource(source, base);
309 return compileJoin();
312 compile = function() {
313 clearTimeout(compileTimeout);
314 return compileTimeout = wait(25, function() {
315 return fs.stat(source, function(err, stats) {
317 return watchErr(err);
319 if (prevStats && stats.size === prevStats.size && stats.mtime.getTime() === prevStats.mtime.getTime()) {
323 return fs.readFile(source, function(err, code) {
325 return watchErr(err);
327 compileScript(source, code.toString(), base);
333 startWatcher = function() {
334 return watcher = fs.watch(source).on('change', compile).on('error', function(err) {
335 if (err.code !== 'EPERM') {
338 return removeSource(source, base);
341 rewatch = function() {
342 if (watcher != null) {
345 return startWatcher();
348 return startWatcher();
351 return watchErr(err);
355 watchDir = function(source, base) {
356 var err, error, readdirTimeout, startWatcher, stopWatcher, watcher;
358 readdirTimeout = null;
359 startWatcher = function() {
360 return watcher = fs.watch(source).on('error', function(err) {
361 if (err.code !== 'EPERM') {
364 return stopWatcher();
365 }).on('change', function() {
366 clearTimeout(readdirTimeout);
367 return readdirTimeout = wait(25, function() {
368 var err, error, file, files, i, len, results;
370 files = fs.readdirSync(source);
373 if (err.code !== 'ENOENT') {
376 return stopWatcher();
379 for (i = 0, len = files.length; i < len; i++) {
381 results.push(compilePath(path.join(source, file), false, base));
387 stopWatcher = function() {
389 return removeSourceDir(source, base);
391 watchedDirs[source] = true;
393 return startWatcher();
396 if (err.code !== 'ENOENT') {
402 removeSourceDir = function(source, base) {
403 var file, i, len, sourcesChanged;
404 delete watchedDirs[source];
405 sourcesChanged = false;
406 for (i = 0, len = sources.length; i < len; i++) {
408 if (!(source === path.dirname(file))) {
411 removeSource(file, base);
412 sourcesChanged = true;
414 if (sourcesChanged) {
415 return compileJoin();
419 removeSource = function(source, base) {
421 index = sources.indexOf(source);
422 sources.splice(index, 1);
423 sourceCode.splice(index, 1);
425 silentUnlink(outputPath(source, base));
426 silentUnlink(outputPath(source, base, '.js.map'));
427 return timeLog("removed " + source);
431 silentUnlink = function(path) {
432 var err, error, ref1;
434 return fs.unlinkSync(path);
437 if ((ref1 = err.code) !== 'ENOENT' && ref1 !== 'EPERM') {
443 outputPath = function(source, base, extension) {
444 var basename, dir, srcDir;
445 if (extension == null) {
448 basename = helpers.baseFileName(source, true, useWinPathSep);
449 srcDir = path.dirname(source);
452 } else if (source === base) {
455 dir = path.join(opts.output, path.relative(base, srcDir));
457 return path.join(dir, basename + extension);
460 mkdirp = function(dir, fn) {
462 mode = 0x1ff & ~process.umask();
463 return (mkdirs = function(p, fn) {
464 return fs.exists(p, function(exists) {
468 return mkdirs(path.dirname(p), function() {
469 return fs.mkdir(p, mode, function(err) {
481 writeJs = function(base, sourcePath, js, jsPath, generatedSourceMap) {
482 var compile, jsDir, sourceMapPath;
483 if (generatedSourceMap == null) {
484 generatedSourceMap = null;
486 sourceMapPath = outputPath(sourcePath, base, ".js.map");
487 jsDir = path.dirname(jsPath);
488 compile = function() {
490 if (js.length <= 0) {
493 if (generatedSourceMap) {
494 js = js + "\n//# sourceMappingURL=" + (helpers.baseFileName(sourceMapPath, false, useWinPathSep)) + "\n";
496 fs.writeFile(jsPath, js, function(err) {
498 printLine(err.message);
499 return process.exit(1);
500 } else if (opts.compile && opts.watch) {
501 return timeLog("compiled " + sourcePath);
505 if (generatedSourceMap) {
506 return fs.writeFile(sourceMapPath, generatedSourceMap, function(err) {
508 printLine("Could not write source map: " + err.message);
509 return process.exit(1);
514 return fs.exists(jsDir, function(itExists) {
518 return mkdirp(jsDir, compile);
523 wait = function(milliseconds, func) {
524 return setTimeout(func, milliseconds);
527 timeLog = function(message) {
528 return console.log(((new Date).toLocaleTimeString()) + " - " + message);
531 printTokens = function(tokens) {
532 var strings, tag, token, value;
533 strings = (function() {
536 for (i = 0, len = tokens.length; i < len; i++) {
539 value = token[1].toString().replace(/\n/, '\\n');
540 results.push("[" + tag + " " + value + "]");
544 return printLine(strings.join(' '));
547 parseOptions = function() {
549 optionParser = new optparse.OptionParser(SWITCHES, BANNER);
550 o = opts = optionParser.parse(process.argv.slice(2));
551 o.compile || (o.compile = !!o.output);
552 o.run = !(o.compile || o.print || o.map);
553 return o.print = !!(o.print || (o["eval"] || o.stdio && o.compile));
556 compileOptions = function(filename, base) {
557 var answer, cwd, jsDir, jsPath;
560 literate: opts.literate || helpers.isLiterate(filename),
562 header: opts.compile && !opts['no-header'],
568 jsPath = outputPath(filename, base);
569 jsDir = path.dirname(jsPath);
570 answer = helpers.merge(answer, {
572 sourceRoot: path.relative(jsDir, cwd),
573 sourceFiles: [path.relative(cwd, filename)],
574 generatedFile: helpers.baseFileName(jsPath, false, useWinPathSep)
577 answer = helpers.merge(answer, {
579 sourceFiles: [helpers.baseFileName(filename, false, useWinPathSep)],
580 generatedFile: helpers.baseFileName(filename, true, useWinPathSep) + ".js"
587 forkNode = function() {
588 var args, nodeArgs, p;
589 nodeArgs = opts.nodejs.split(/\s+/);
590 args = process.argv.slice(1);
591 args.splice(args.indexOf('--nodejs'), 2);
592 p = spawn(process.execPath, nodeArgs.concat(args), {
597 return p.on('exit', function(code) {
598 return process.exit(code);
603 return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
606 version = function() {
607 return printLine("CoffeeScript version " + CoffeeScript.VERSION);