Skip to content

Commit

Permalink
[CS2] Fix #2870: Allow specifying output filename (#4661)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
GeoffreyBooth authored Aug 24, 2017
1 parent 892c469 commit 3dd4582
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 82 deletions.
71 changes: 37 additions & 34 deletions lib/coffeescript/command.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 62 additions & 47 deletions src/command.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 '''
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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`.
Expand Down
2 changes: 1 addition & 1 deletion test/argument_parsing.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 3dd4582

Please sign in to comment.