mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 09:17:55 -05:00
Instead of throwing the syntax errors with their source file location and needing to then catch them and call a `prettyErrorMessage` function in order to get the formatted error message, now syntax errors know how to pretty-print themselves (their `toString` method gets overridden). An intermediate `catch` & re-`throw` is needed at the level of `CoffeeScript.compile` and friends. But the benefit of this approach is that now libraries that use the `CoffeeScript` object directly don't need to bother catching the possible compilation errors and calling a special function in order to get the nice error messages; they can just print the error itself (or let it bubble up) and the error will know how to pretty-print itself.
526 lines
16 KiB
JavaScript
526 lines
16 KiB
JavaScript
// Generated by CoffeeScript 1.6.3
|
|
(function() {
|
|
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, exists, forkNode, fs, helpers, hidden, joinTimeout, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, useWinPathSep, version, wait, watch, watchDir, watchers, writeJs, _ref;
|
|
|
|
fs = require('fs');
|
|
|
|
path = require('path');
|
|
|
|
helpers = require('./helpers');
|
|
|
|
optparse = require('./optparse');
|
|
|
|
CoffeeScript = require('./coffee-script');
|
|
|
|
_ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec;
|
|
|
|
EventEmitter = require('events').EventEmitter;
|
|
|
|
exists = fs.exists || path.exists;
|
|
|
|
useWinPathSep = path.sep === '\\';
|
|
|
|
helpers.extend(CoffeeScript, new EventEmitter);
|
|
|
|
printLine = function(line) {
|
|
return process.stdout.write(line + '\n');
|
|
};
|
|
|
|
printWarn = function(line) {
|
|
return process.stderr.write(line + '\n');
|
|
};
|
|
|
|
hidden = function(file) {
|
|
return /^\.|~$/.test(file);
|
|
};
|
|
|
|
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 .map files'], ['-n', '--nodes', 'print out the parse tree that the parser produces'], ['--nodejs [ARGS]', 'pass options directly to the "node" binary'], ['-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']];
|
|
|
|
opts = {};
|
|
|
|
sources = [];
|
|
|
|
sourceCode = [];
|
|
|
|
notSources = {};
|
|
|
|
watchers = {};
|
|
|
|
optionParser = null;
|
|
|
|
exports.run = function() {
|
|
var literals, source, _i, _len, _results;
|
|
parseOptions();
|
|
if (opts.nodejs) {
|
|
return forkNode();
|
|
}
|
|
if (opts.help) {
|
|
return usage();
|
|
}
|
|
if (opts.version) {
|
|
return version();
|
|
}
|
|
if (opts.interactive) {
|
|
return require('./repl').start();
|
|
}
|
|
if (opts.watch && !fs.watch) {
|
|
return printWarn("The --watch feature depends on Node v0.6.0+. You are running " + process.version + ".");
|
|
}
|
|
if (opts.stdio) {
|
|
return compileStdio();
|
|
}
|
|
if (opts["eval"]) {
|
|
return compileScript(null, sources[0]);
|
|
}
|
|
if (!sources.length) {
|
|
return require('./repl').start();
|
|
}
|
|
literals = opts.run ? sources.splice(1) : [];
|
|
process.argv = process.argv.slice(0, 2).concat(literals);
|
|
process.argv[0] = 'coffee';
|
|
_results = [];
|
|
for (_i = 0, _len = sources.length; _i < _len; _i++) {
|
|
source = sources[_i];
|
|
_results.push(compilePath(source, true, path.normalize(source)));
|
|
}
|
|
return _results;
|
|
};
|
|
|
|
compilePath = function(source, topLevel, base) {
|
|
return fs.stat(source, function(err, stats) {
|
|
if (err && err.code !== 'ENOENT') {
|
|
throw err;
|
|
}
|
|
if ((err != null ? err.code : void 0) === 'ENOENT') {
|
|
console.error("File not found: " + source);
|
|
process.exit(1);
|
|
}
|
|
if (stats.isDirectory() && path.dirname(source) !== 'node_modules') {
|
|
if (opts.watch) {
|
|
watchDir(source, base);
|
|
}
|
|
return fs.readdir(source, function(err, files) {
|
|
var file, index, _ref1, _ref2;
|
|
if (err && err.code !== 'ENOENT') {
|
|
throw err;
|
|
}
|
|
if ((err != null ? err.code : void 0) === 'ENOENT') {
|
|
return;
|
|
}
|
|
index = sources.indexOf(source);
|
|
files = files.filter(function(file) {
|
|
return !hidden(file);
|
|
});
|
|
[].splice.apply(sources, [index, index - index + 1].concat(_ref1 = (function() {
|
|
var _i, _len, _results;
|
|
_results = [];
|
|
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
|
file = files[_i];
|
|
_results.push(path.join(source, file));
|
|
}
|
|
return _results;
|
|
})())), _ref1;
|
|
[].splice.apply(sourceCode, [index, index - index + 1].concat(_ref2 = files.map(function() {
|
|
return null;
|
|
}))), _ref2;
|
|
return files.forEach(function(file) {
|
|
return compilePath(path.join(source, file), false, base);
|
|
});
|
|
});
|
|
} else if (topLevel || helpers.isCoffee(source)) {
|
|
if (opts.watch) {
|
|
watch(source, base);
|
|
}
|
|
return fs.readFile(source, function(err, code) {
|
|
if (err && err.code !== 'ENOENT') {
|
|
throw err;
|
|
}
|
|
if ((err != null ? err.code : void 0) === 'ENOENT') {
|
|
return;
|
|
}
|
|
return compileScript(source, code.toString(), base);
|
|
});
|
|
} else {
|
|
notSources[source] = true;
|
|
return removeSource(source, base);
|
|
}
|
|
});
|
|
};
|
|
|
|
compileScript = function(file, input, base) {
|
|
var compiled, err, message, o, options, t, task;
|
|
if (base == null) {
|
|
base = null;
|
|
}
|
|
o = opts;
|
|
options = compileOptions(file, base);
|
|
try {
|
|
t = task = {
|
|
file: file,
|
|
input: input,
|
|
options: options
|
|
};
|
|
CoffeeScript.emit('compile', task);
|
|
if (o.tokens) {
|
|
return printTokens(CoffeeScript.tokens(t.input, t.options));
|
|
} else if (o.nodes) {
|
|
return printLine(CoffeeScript.nodes(t.input, t.options).toString().trim());
|
|
} else if (o.run) {
|
|
return CoffeeScript.run(t.input, t.options);
|
|
} else if (o.join && t.file !== o.join) {
|
|
if (helpers.isLiterate(file)) {
|
|
t.input = helpers.invertLiterate(t.input);
|
|
}
|
|
sourceCode[sources.indexOf(t.file)] = t.input;
|
|
return compileJoin();
|
|
} else {
|
|
compiled = CoffeeScript.compile(t.input, t.options);
|
|
t.output = compiled;
|
|
if (o.map) {
|
|
t.output = compiled.js;
|
|
t.sourceMap = compiled.v3SourceMap;
|
|
}
|
|
CoffeeScript.emit('success', task);
|
|
if (o.print) {
|
|
return printLine(t.output.trim());
|
|
} else if (o.compile || o.map) {
|
|
return writeJs(base, t.file, t.output, options.jsPath, t.sourceMap);
|
|
}
|
|
}
|
|
} catch (_error) {
|
|
err = _error;
|
|
CoffeeScript.emit('failure', err, task);
|
|
if (CoffeeScript.listeners('failure').length) {
|
|
return;
|
|
}
|
|
message = err.stack || ("" + err);
|
|
if (o.watch) {
|
|
return printLine(message + '\x07');
|
|
} else {
|
|
printWarn(message);
|
|
return process.exit(1);
|
|
}
|
|
}
|
|
};
|
|
|
|
compileStdio = function() {
|
|
var code, stdin;
|
|
code = '';
|
|
stdin = process.openStdin();
|
|
stdin.on('data', function(buffer) {
|
|
if (buffer) {
|
|
return code += buffer.toString();
|
|
}
|
|
});
|
|
return stdin.on('end', function() {
|
|
return compileScript(null, code);
|
|
});
|
|
};
|
|
|
|
joinTimeout = null;
|
|
|
|
compileJoin = function() {
|
|
if (!opts.join) {
|
|
return;
|
|
}
|
|
if (!sourceCode.some(function(code) {
|
|
return code === null;
|
|
})) {
|
|
clearTimeout(joinTimeout);
|
|
return joinTimeout = wait(100, function() {
|
|
return compileScript(opts.join, sourceCode.join('\n'), opts.join);
|
|
});
|
|
}
|
|
};
|
|
|
|
watch = function(source, base) {
|
|
var compile, compileTimeout, e, prevStats, rewatch, watchErr, watcher;
|
|
prevStats = null;
|
|
compileTimeout = null;
|
|
watchErr = function(e) {
|
|
if (e.code === 'ENOENT') {
|
|
if (sources.indexOf(source) === -1) {
|
|
return;
|
|
}
|
|
try {
|
|
rewatch();
|
|
return compile();
|
|
} catch (_error) {
|
|
e = _error;
|
|
removeSource(source, base, true);
|
|
return compileJoin();
|
|
}
|
|
} else {
|
|
throw e;
|
|
}
|
|
};
|
|
compile = function() {
|
|
clearTimeout(compileTimeout);
|
|
return compileTimeout = wait(25, function() {
|
|
return fs.stat(source, function(err, stats) {
|
|
if (err) {
|
|
return watchErr(err);
|
|
}
|
|
if (prevStats && stats.size === prevStats.size && stats.mtime.getTime() === prevStats.mtime.getTime()) {
|
|
return rewatch();
|
|
}
|
|
prevStats = stats;
|
|
return fs.readFile(source, function(err, code) {
|
|
if (err) {
|
|
return watchErr(err);
|
|
}
|
|
compileScript(source, code.toString(), base);
|
|
return rewatch();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
try {
|
|
watcher = fs.watch(source, compile);
|
|
} catch (_error) {
|
|
e = _error;
|
|
watchErr(e);
|
|
}
|
|
return rewatch = function() {
|
|
if (watcher != null) {
|
|
watcher.close();
|
|
}
|
|
return watcher = fs.watch(source, compile);
|
|
};
|
|
};
|
|
|
|
watchDir = function(source, base) {
|
|
var e, readdirTimeout, watcher;
|
|
readdirTimeout = null;
|
|
try {
|
|
return watcher = fs.watch(source, function() {
|
|
clearTimeout(readdirTimeout);
|
|
return readdirTimeout = wait(25, function() {
|
|
return fs.readdir(source, function(err, files) {
|
|
var file, _i, _len, _results;
|
|
if (err) {
|
|
if (err.code !== 'ENOENT') {
|
|
throw err;
|
|
}
|
|
watcher.close();
|
|
return unwatchDir(source, base);
|
|
}
|
|
_results = [];
|
|
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
|
file = files[_i];
|
|
if (!(!hidden(file) && !notSources[file])) {
|
|
continue;
|
|
}
|
|
file = path.join(source, file);
|
|
if (sources.some(function(s) {
|
|
return s.indexOf(file) >= 0;
|
|
})) {
|
|
continue;
|
|
}
|
|
sources.push(file);
|
|
sourceCode.push(null);
|
|
_results.push(compilePath(file, false, base));
|
|
}
|
|
return _results;
|
|
});
|
|
});
|
|
});
|
|
} catch (_error) {
|
|
e = _error;
|
|
if (e.code !== 'ENOENT') {
|
|
throw e;
|
|
}
|
|
}
|
|
};
|
|
|
|
unwatchDir = function(source, base) {
|
|
var file, prevSources, toRemove, _i, _len;
|
|
prevSources = sources.slice(0);
|
|
toRemove = (function() {
|
|
var _i, _len, _results;
|
|
_results = [];
|
|
for (_i = 0, _len = sources.length; _i < _len; _i++) {
|
|
file = sources[_i];
|
|
if (file.indexOf(source) >= 0) {
|
|
_results.push(file);
|
|
}
|
|
}
|
|
return _results;
|
|
})();
|
|
for (_i = 0, _len = toRemove.length; _i < _len; _i++) {
|
|
file = toRemove[_i];
|
|
removeSource(file, base, true);
|
|
}
|
|
if (!sources.some(function(s, i) {
|
|
return prevSources[i] !== s;
|
|
})) {
|
|
return;
|
|
}
|
|
return compileJoin();
|
|
};
|
|
|
|
removeSource = function(source, base, removeJs) {
|
|
var index, jsPath;
|
|
index = sources.indexOf(source);
|
|
sources.splice(index, 1);
|
|
sourceCode.splice(index, 1);
|
|
if (removeJs && !opts.join) {
|
|
jsPath = outputPath(source, base);
|
|
return exists(jsPath, function(itExists) {
|
|
if (itExists) {
|
|
return fs.unlink(jsPath, function(err) {
|
|
if (err && err.code !== 'ENOENT') {
|
|
throw err;
|
|
}
|
|
return timeLog("removed " + source);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
outputPath = function(source, base, extension) {
|
|
var baseDir, basename, dir, srcDir;
|
|
if (extension == null) {
|
|
extension = ".js";
|
|
}
|
|
basename = helpers.baseFileName(source, true, useWinPathSep);
|
|
srcDir = path.dirname(source);
|
|
baseDir = base === '.' || base === './' ? srcDir : srcDir.substring(base.length);
|
|
dir = opts.output ? path.join(opts.output, baseDir) : srcDir;
|
|
return path.join(dir, basename + extension);
|
|
};
|
|
|
|
writeJs = function(base, sourcePath, js, jsPath, generatedSourceMap) {
|
|
var compile, jsDir, sourceMapPath;
|
|
if (generatedSourceMap == null) {
|
|
generatedSourceMap = null;
|
|
}
|
|
sourceMapPath = outputPath(sourcePath, base, ".map");
|
|
jsDir = path.dirname(jsPath);
|
|
compile = function() {
|
|
if (opts.compile) {
|
|
if (js.length <= 0) {
|
|
js = ' ';
|
|
}
|
|
if (generatedSourceMap) {
|
|
js = "" + js + "\n//# sourceMappingURL=" + (helpers.baseFileName(sourceMapPath, false, useWinPathSep)) + "\n";
|
|
}
|
|
fs.writeFile(jsPath, js, function(err) {
|
|
if (err) {
|
|
return printLine(err.message);
|
|
} else if (opts.compile && opts.watch) {
|
|
return timeLog("compiled " + sourcePath);
|
|
}
|
|
});
|
|
}
|
|
if (generatedSourceMap) {
|
|
return fs.writeFile(sourceMapPath, generatedSourceMap, function(err) {
|
|
if (err) {
|
|
return printLine("Could not write source map: " + err.message);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
return exists(jsDir, function(itExists) {
|
|
if (itExists) {
|
|
return compile();
|
|
} else {
|
|
return exec("mkdir -p " + jsDir, compile);
|
|
}
|
|
});
|
|
};
|
|
|
|
wait = function(milliseconds, func) {
|
|
return setTimeout(func, milliseconds);
|
|
};
|
|
|
|
timeLog = function(message) {
|
|
return console.log("" + ((new Date).toLocaleTimeString()) + " - " + message);
|
|
};
|
|
|
|
printTokens = function(tokens) {
|
|
var strings, tag, token, value;
|
|
strings = (function() {
|
|
var _i, _len, _results;
|
|
_results = [];
|
|
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
|
|
token = tokens[_i];
|
|
tag = token[0];
|
|
value = token[1].toString().replace(/\n/, '\\n');
|
|
_results.push("[" + tag + " " + value + "]");
|
|
}
|
|
return _results;
|
|
})();
|
|
return printLine(strings.join(' '));
|
|
};
|
|
|
|
parseOptions = function() {
|
|
var i, o, source, _i, _len;
|
|
optionParser = new optparse.OptionParser(SWITCHES, BANNER);
|
|
o = opts = optionParser.parse(process.argv.slice(2));
|
|
o.compile || (o.compile = !!o.output);
|
|
o.run = !(o.compile || o.print || o.map);
|
|
o.print = !!(o.print || (o["eval"] || o.stdio && o.compile));
|
|
sources = o["arguments"];
|
|
for (i = _i = 0, _len = sources.length; _i < _len; i = ++_i) {
|
|
source = sources[i];
|
|
sourceCode[i] = null;
|
|
}
|
|
};
|
|
|
|
compileOptions = function(filename, base) {
|
|
var answer, cwd, jsDir, jsPath;
|
|
answer = {
|
|
filename: filename,
|
|
literate: opts.literate || helpers.isLiterate(filename),
|
|
bare: opts.bare,
|
|
header: opts.compile,
|
|
sourceMap: opts.map
|
|
};
|
|
if (filename) {
|
|
if (base) {
|
|
cwd = process.cwd();
|
|
jsPath = outputPath(filename, base);
|
|
jsDir = path.dirname(jsPath);
|
|
answer = helpers.merge(answer, {
|
|
jsPath: jsPath,
|
|
sourceRoot: path.relative(jsDir, cwd),
|
|
sourceFiles: [path.relative(cwd, filename)],
|
|
generatedFile: helpers.baseFileName(jsPath, false, useWinPathSep)
|
|
});
|
|
} else {
|
|
answer = helpers.merge(answer, {
|
|
sourceRoot: "",
|
|
sourceFiles: [helpers.baseFileName(filename, false, useWinPathSep)],
|
|
generatedFile: helpers.baseFileName(filename, true, useWinPathSep) + ".js"
|
|
});
|
|
}
|
|
}
|
|
return answer;
|
|
};
|
|
|
|
forkNode = function() {
|
|
var args, nodeArgs;
|
|
nodeArgs = opts.nodejs.split(/\s+/);
|
|
args = process.argv.slice(1);
|
|
args.splice(args.indexOf('--nodejs'), 2);
|
|
return spawn(process.execPath, nodeArgs.concat(args), {
|
|
cwd: process.cwd(),
|
|
env: process.env,
|
|
customFds: [0, 1, 2]
|
|
});
|
|
};
|
|
|
|
usage = function() {
|
|
return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
|
|
};
|
|
|
|
version = function() {
|
|
return printLine("CoffeeScript version " + CoffeeScript.VERSION);
|
|
};
|
|
|
|
}).call(this);
|