mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
* Fix #2870: If --output ends with a filename, and the input is a file and not a path, save as the desired filename * If an output path ends in a slash, force saving into an output folder even if that folder name would contain a period (e.g. /scripts.js/); if output filename is only periods, treat it as a path * Restrict exceptions
This commit is contained in:
parent
892c4699dd
commit
3dd458267b
3 changed files with 100 additions and 82 deletions
|
@ -45,7 +45,7 @@
|
|||
BANNER = 'Usage: coffee [options] path/to/script.coffee [args]\n\nIf called without options, `coffee` will run your script.';
|
||||
|
||||
// The list of all the valid option flags that `coffee` knows how to handle.
|
||||
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'], ['-M', '--inline-map', 'generate source map and include it directly in output'], ['-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 coffeescript'], ['-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'], ['-M', '--inline-map', 'generate source map and include it directly in output'], ['-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 [PATH]', 'set the output path or path/filename 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 coffeescript'], ['-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']];
|
||||
|
||||
// Top-level objects shared by all the functions.
|
||||
opts = {};
|
||||
|
@ -68,7 +68,7 @@
|
|||
// Many flags cause us to divert before compiling anything. Flags passed after
|
||||
// `--` will be passed verbatim to your script as arguments in `process.argv`
|
||||
exports.run = function() {
|
||||
var err, i, len, literals, ref, replCliOpts, results, source;
|
||||
var err, i, len, literals, outputBasename, ref, replCliOpts, results, source;
|
||||
optionParser = buildCSOptionParser();
|
||||
try {
|
||||
parseOptions();
|
||||
|
@ -117,7 +117,16 @@
|
|||
process.argv = process.argv.slice(0, 2).concat(literals);
|
||||
process.argv[0] = 'coffee';
|
||||
if (opts.output) {
|
||||
opts.output = path.resolve(opts.output);
|
||||
outputBasename = path.basename(opts.output);
|
||||
if (indexOf.call(outputBasename, '.') >= 0 && (outputBasename !== '.' && outputBasename !== '..') && !helpers.ends(opts.output, path.sep)) {
|
||||
// An output filename was specified, e.g. `/dist/scripts.js`.
|
||||
opts.outputFilename = outputBasename;
|
||||
opts.outputPath = path.resolve(path.dirname(opts.output));
|
||||
} else {
|
||||
// An output path was specified, e.g. `/dist`.
|
||||
opts.outputFilename = null;
|
||||
opts.outputPath = path.resolve(opts.output);
|
||||
}
|
||||
}
|
||||
if (opts.join) {
|
||||
opts.join = path.resolve(opts.join);
|
||||
|
@ -235,43 +244,43 @@
|
|||
};
|
||||
|
||||
// Compile a single source script, containing the given code, according to the
|
||||
// requested options. If evaluating the script directly sets `__filename`,
|
||||
// requested options. If evaluating the script directly, set `__filename`,
|
||||
// `__dirname` and `module.filename` to be correct relative to the script's path.
|
||||
compileScript = function(file, input, base = null) {
|
||||
var compiled, err, message, o, options, t, task;
|
||||
o = opts;
|
||||
var compiled, err, message, options, saveTo, task;
|
||||
options = compileOptions(file, base);
|
||||
try {
|
||||
t = task = {file, input, options};
|
||||
task = {file, input, 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) {
|
||||
if (opts.tokens) {
|
||||
return printTokens(CoffeeScript.tokens(task.input, task.options));
|
||||
} else if (opts.nodes) {
|
||||
return printLine(CoffeeScript.nodes(task.input, task.options).toString().trim());
|
||||
} else if (opts.run) {
|
||||
CoffeeScript.register();
|
||||
if (opts.prelude) {
|
||||
CoffeeScript.eval(opts.prelude, t.options);
|
||||
CoffeeScript.eval(opts.prelude, task.options);
|
||||
}
|
||||
return CoffeeScript.run(t.input, t.options);
|
||||
} else if (o.join && t.file !== o.join) {
|
||||
return CoffeeScript.run(task.input, task.options);
|
||||
} else if (opts.join && task.file !== opts.join) {
|
||||
if (helpers.isLiterate(file)) {
|
||||
t.input = helpers.invertLiterate(t.input);
|
||||
task.input = helpers.invertLiterate(task.input);
|
||||
}
|
||||
sourceCode[sources.indexOf(t.file)] = t.input;
|
||||
sourceCode[sources.indexOf(task.file)] = task.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;
|
||||
compiled = CoffeeScript.compile(task.input, task.options);
|
||||
task.output = compiled;
|
||||
if (opts.map) {
|
||||
task.output = compiled.js;
|
||||
task.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);
|
||||
if (opts.print) {
|
||||
return printLine(task.output.trim());
|
||||
} else if (opts.compile || opts.map) {
|
||||
saveTo = opts.outputFilename && sources.length === 1 ? path.join(opts.outputPath, opts.outputFilename) : options.jsPath;
|
||||
return writeJs(base, task.file, task.output, saveTo, task.sourceMap);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -281,7 +290,7 @@
|
|||
return;
|
||||
}
|
||||
message = (err != null ? err.stack : void 0) || `${err}`;
|
||||
if (o.watch) {
|
||||
if (opts.watch) {
|
||||
return printLine(message + '\x07');
|
||||
} else {
|
||||
printWarn(message);
|
||||
|
@ -486,13 +495,7 @@
|
|||
var basename, dir, srcDir;
|
||||
basename = helpers.baseFileName(source, true, useWinPathSep);
|
||||
srcDir = path.dirname(source);
|
||||
if (!opts.output) {
|
||||
dir = srcDir;
|
||||
} else if (source === base) {
|
||||
dir = opts.output;
|
||||
} else {
|
||||
dir = path.join(opts.output, path.relative(base, srcDir));
|
||||
}
|
||||
dir = !opts.outputPath ? srcDir : source === base ? opts.outputPath : path.join(opts.outputPath, path.relative(base, srcDir));
|
||||
return path.join(dir, basename + extension);
|
||||
};
|
||||
|
||||
|
|
|
@ -32,25 +32,25 @@ BANNER = '''
|
|||
|
||||
# The list of all the valid option flags that `coffee` knows how to handle.
|
||||
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']
|
||||
['-M', '--inline-map', 'generate source map and include it directly in output']
|
||||
['-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']
|
||||
['-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']
|
||||
['-M', '--inline-map', 'generate source map and include it directly in output']
|
||||
['-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 [PATH]', 'set the output path or path/filename 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 coffeescript']
|
||||
['-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']
|
||||
['-s', '--stdio', 'listen for and compile scripts over stdio']
|
||||
['-l', '--literate', 'treat stdio as literate style coffeescript']
|
||||
['-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']
|
||||
]
|
||||
|
||||
# Top-level objects shared by all the functions.
|
||||
|
@ -102,7 +102,19 @@ exports.run = ->
|
|||
process.argv = process.argv[0..1].concat literals
|
||||
process.argv[0] = 'coffee'
|
||||
|
||||
opts.output = path.resolve opts.output if opts.output
|
||||
if opts.output
|
||||
outputBasename = path.basename opts.output
|
||||
if '.' in outputBasename and
|
||||
outputBasename not in ['.', '..'] and
|
||||
not helpers.ends(opts.output, path.sep)
|
||||
# An output filename was specified, e.g. `/dist/scripts.js`.
|
||||
opts.outputFilename = outputBasename
|
||||
opts.outputPath = path.resolve path.dirname opts.output
|
||||
else
|
||||
# An output path was specified, e.g. `/dist`.
|
||||
opts.outputFilename = null
|
||||
opts.outputPath = path.resolve opts.output
|
||||
|
||||
if opts.join
|
||||
opts.join = path.resolve opts.join
|
||||
console.error '''
|
||||
|
@ -167,7 +179,7 @@ compilePath = (source, topLevel, base) ->
|
|||
code = fs.readFileSync source
|
||||
catch err
|
||||
if err.code is 'ENOENT' then return else throw err
|
||||
compileScript(source, code.toString(), base)
|
||||
compileScript source, code.toString(), base
|
||||
else
|
||||
notSources[source] = yes
|
||||
|
||||
|
@ -182,43 +194,46 @@ findDirectoryIndex = (source) ->
|
|||
process.exit 1
|
||||
|
||||
# Compile a single source script, containing the given code, according to the
|
||||
# requested options. If evaluating the script directly sets `__filename`,
|
||||
# requested options. If evaluating the script directly, set `__filename`,
|
||||
# `__dirname` and `module.filename` to be correct relative to the script's path.
|
||||
compileScript = (file, input, base = null) ->
|
||||
o = opts
|
||||
options = compileOptions file, base
|
||||
try
|
||||
t = task = {file, input, options}
|
||||
task = {file, input, options}
|
||||
CoffeeScript.emit 'compile', task
|
||||
if o.tokens
|
||||
printTokens CoffeeScript.tokens t.input, t.options
|
||||
else if o.nodes
|
||||
printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
|
||||
else if o.run
|
||||
if opts.tokens
|
||||
printTokens CoffeeScript.tokens task.input, task.options
|
||||
else if opts.nodes
|
||||
printLine CoffeeScript.nodes(task.input, task.options).toString().trim()
|
||||
else if opts.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
|
||||
sourceCode[sources.indexOf(t.file)] = t.input
|
||||
CoffeeScript.eval opts.prelude, task.options if opts.prelude
|
||||
CoffeeScript.run task.input, task.options
|
||||
else if opts.join and task.file isnt opts.join
|
||||
task.input = helpers.invertLiterate task.input if helpers.isLiterate file
|
||||
sourceCode[sources.indexOf(task.file)] = task.input
|
||||
compileJoin()
|
||||
else
|
||||
compiled = CoffeeScript.compile t.input, t.options
|
||||
t.output = compiled
|
||||
if o.map
|
||||
t.output = compiled.js
|
||||
t.sourceMap = compiled.v3SourceMap
|
||||
compiled = CoffeeScript.compile task.input, task.options
|
||||
task.output = compiled
|
||||
if opts.map
|
||||
task.output = compiled.js
|
||||
task.sourceMap = compiled.v3SourceMap
|
||||
|
||||
CoffeeScript.emit 'success', task
|
||||
if o.print
|
||||
printLine t.output.trim()
|
||||
else if o.compile or o.map
|
||||
writeJs base, t.file, t.output, options.jsPath, t.sourceMap
|
||||
if opts.print
|
||||
printLine task.output.trim()
|
||||
else if opts.compile or opts.map
|
||||
saveTo = if opts.outputFilename and sources.length is 1
|
||||
path.join opts.outputPath, opts.outputFilename
|
||||
else
|
||||
options.jsPath
|
||||
writeJs base, task.file, task.output, saveTo, task.sourceMap
|
||||
catch err
|
||||
CoffeeScript.emit 'failure', err, task
|
||||
return if CoffeeScript.listeners('failure').length
|
||||
message = err?.stack or "#{err}"
|
||||
if o.watch
|
||||
if opts.watch
|
||||
printLine message + '\x07'
|
||||
else
|
||||
printWarn message
|
||||
|
@ -352,12 +367,12 @@ silentUnlink = (path) ->
|
|||
outputPath = (source, base, extension=".js") ->
|
||||
basename = helpers.baseFileName source, yes, useWinPathSep
|
||||
srcDir = path.dirname source
|
||||
if not opts.output
|
||||
dir = srcDir
|
||||
dir = unless opts.outputPath
|
||||
srcDir
|
||||
else if source is base
|
||||
dir = opts.output
|
||||
opts.outputPath
|
||||
else
|
||||
dir = path.join opts.output, path.relative base, srcDir
|
||||
path.join opts.outputPath, path.relative base, srcDir
|
||||
path.join dir, basename + extension
|
||||
|
||||
# Recursively mkdir, like `mkdir -p`.
|
||||
|
|
|
@ -130,7 +130,7 @@ If called without options, `coffee` will run your script.
|
|||
-n, --nodes print out the parse tree that the parser produces
|
||||
--nodejs pass options directly to the "node" binary
|
||||
--no-header suppress the "Generated by" header
|
||||
-o, --output set the output directory for compiled JavaScript
|
||||
-o, --output set the output path or path/filename for compiled JavaScript
|
||||
-p, --print print out the compiled JavaScript
|
||||
-r, --require require the given module before eval or REPL
|
||||
-s, --stdio listen for and compile scripts over stdio
|
||||
|
|
Loading…
Reference in a new issue