Skip to content

Commit 9480f2f

Browse files
committed
Fix jashkenas#2870: If --output ends with a filename, and the input is a file and not a path, save as the desired filename
1 parent a3b08e1 commit 9480f2f

File tree

3 files changed

+98
-82
lines changed

3 files changed

+98
-82
lines changed

lib/coffeescript/command.js

+37-34
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/command.coffee

+60-47
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,25 @@ BANNER = '''
3232

3333
# The list of all the valid option flags that `coffee` knows how to handle.
3434
SWITCHES = [
35-
['-b', '--bare', 'compile without a top-level function wrapper']
36-
['-c', '--compile', 'compile to JavaScript and save as .js files']
37-
['-e', '--eval', 'pass a string from the command line as input']
38-
['-h', '--help', 'display this help message']
39-
['-i', '--interactive', 'run an interactive CoffeeScript REPL']
40-
['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling']
41-
['-m', '--map', 'generate source map and save as .js.map files']
42-
['-M', '--inline-map', 'generate source map and include it directly in output']
43-
['-n', '--nodes', 'print out the parse tree that the parser produces']
44-
[ '--nodejs [ARGS]', 'pass options directly to the "node" binary']
45-
[ '--no-header', 'suppress the "Generated by" header']
46-
['-o', '--output [DIR]', 'set the output directory for compiled JavaScript']
47-
['-p', '--print', 'print out the compiled JavaScript']
35+
['-b', '--bare', 'compile without a top-level function wrapper']
36+
['-c', '--compile', 'compile to JavaScript and save as .js files']
37+
['-e', '--eval', 'pass a string from the command line as input']
38+
['-h', '--help', 'display this help message']
39+
['-i', '--interactive', 'run an interactive CoffeeScript REPL']
40+
['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling']
41+
['-m', '--map', 'generate source map and save as .js.map files']
42+
['-M', '--inline-map', 'generate source map and include it directly in output']
43+
['-n', '--nodes', 'print out the parse tree that the parser produces']
44+
[ '--nodejs [ARGS]', 'pass options directly to the "node" binary']
45+
[ '--no-header', 'suppress the "Generated by" header']
46+
['-o', '--output [PATH]', 'set the output path or path/filename for compiled JavaScript']
47+
['-p', '--print', 'print out the compiled JavaScript']
4848
['-r', '--require [MODULE*]', 'require the given module before eval or REPL']
49-
['-s', '--stdio', 'listen for and compile scripts over stdio']
50-
['-l', '--literate', 'treat stdio as literate style coffeescript']
51-
['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce']
52-
['-v', '--version', 'display the version number']
53-
['-w', '--watch', 'watch scripts for changes and rerun commands']
49+
['-s', '--stdio', 'listen for and compile scripts over stdio']
50+
['-l', '--literate', 'treat stdio as literate style coffeescript']
51+
['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce']
52+
['-v', '--version', 'display the version number']
53+
['-w', '--watch', 'watch scripts for changes and rerun commands']
5454
]
5555

5656
# Top-level objects shared by all the functions.
@@ -102,7 +102,17 @@ exports.run = ->
102102
process.argv = process.argv[0..1].concat literals
103103
process.argv[0] = 'coffee'
104104

105-
opts.output = path.resolve opts.output if opts.output
105+
if opts.output
106+
outputBasename = path.basename opts.output
107+
if '.' in outputBasename
108+
# An output filename was specified, e.g. `/dist/scripts.js`.
109+
opts.outputFilename = outputBasename
110+
opts.outputPath = path.resolve path.dirname opts.output
111+
else
112+
# An output path was specified, e.g. `/dist`.
113+
opts.outputFilename = null
114+
opts.outputPath = path.resolve opts.output
115+
106116
if opts.join
107117
opts.join = path.resolve opts.join
108118
console.error '''
@@ -167,7 +177,7 @@ compilePath = (source, topLevel, base) ->
167177
code = fs.readFileSync source
168178
catch err
169179
if err.code is 'ENOENT' then return else throw err
170-
compileScript(source, code.toString(), base)
180+
compileScript source, code.toString(), base
171181
else
172182
notSources[source] = yes
173183

@@ -182,43 +192,46 @@ findDirectoryIndex = (source) ->
182192
process.exit 1
183193

184194
# Compile a single source script, containing the given code, according to the
185-
# requested options. If evaluating the script directly sets `__filename`,
195+
# requested options. If evaluating the script directly, set `__filename`,
186196
# `__dirname` and `module.filename` to be correct relative to the script's path.
187197
compileScript = (file, input, base = null) ->
188-
o = opts
189198
options = compileOptions file, base
190199
try
191-
t = task = {file, input, options}
200+
task = {file, input, options}
192201
CoffeeScript.emit 'compile', task
193-
if o.tokens
194-
printTokens CoffeeScript.tokens t.input, t.options
195-
else if o.nodes
196-
printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
197-
else if o.run
202+
if opts.tokens
203+
printTokens CoffeeScript.tokens task.input, task.options
204+
else if opts.nodes
205+
printLine CoffeeScript.nodes(task.input, task.options).toString().trim()
206+
else if opts.run
198207
CoffeeScript.register()
199-
CoffeeScript.eval opts.prelude, t.options if opts.prelude
200-
CoffeeScript.run t.input, t.options
201-
else if o.join and t.file isnt o.join
202-
t.input = helpers.invertLiterate t.input if helpers.isLiterate file
203-
sourceCode[sources.indexOf(t.file)] = t.input
208+
CoffeeScript.eval opts.prelude, task.options if opts.prelude
209+
CoffeeScript.run task.input, task.options
210+
else if opts.join and task.file isnt opts.join
211+
task.input = helpers.invertLiterate task.input if helpers.isLiterate file
212+
sourceCode[sources.indexOf(task.file)] = task.input
204213
compileJoin()
205214
else
206-
compiled = CoffeeScript.compile t.input, t.options
207-
t.output = compiled
208-
if o.map
209-
t.output = compiled.js
210-
t.sourceMap = compiled.v3SourceMap
215+
compiled = CoffeeScript.compile task.input, task.options
216+
task.output = compiled
217+
if opts.map
218+
task.output = compiled.js
219+
task.sourceMap = compiled.v3SourceMap
211220

212221
CoffeeScript.emit 'success', task
213-
if o.print
214-
printLine t.output.trim()
215-
else if o.compile or o.map
216-
writeJs base, t.file, t.output, options.jsPath, t.sourceMap
222+
if opts.print
223+
printLine task.output.trim()
224+
else if opts.compile or opts.map
225+
saveTo = if opts.outputFilename and sources.length is 1
226+
path.join opts.outputPath, opts.outputFilename
227+
else
228+
options.jsPath
229+
writeJs base, task.file, task.output, saveTo, task.sourceMap
217230
catch err
218231
CoffeeScript.emit 'failure', err, task
219232
return if CoffeeScript.listeners('failure').length
220233
message = err?.stack or "#{err}"
221-
if o.watch
234+
if opts.watch
222235
printLine message + '\x07'
223236
else
224237
printWarn message
@@ -352,12 +365,12 @@ silentUnlink = (path) ->
352365
outputPath = (source, base, extension=".js") ->
353366
basename = helpers.baseFileName source, yes, useWinPathSep
354367
srcDir = path.dirname source
355-
if not opts.output
356-
dir = srcDir
368+
dir = unless opts.outputPath
369+
srcDir
357370
else if source is base
358-
dir = opts.output
371+
opts.outputPath
359372
else
360-
dir = path.join opts.output, path.relative base, srcDir
373+
path.join opts.outputPath, path.relative base, srcDir
361374
path.join dir, basename + extension
362375

363376
# Recursively mkdir, like `mkdir -p`.

test/argument_parsing.coffee

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ If called without options, `coffee` will run your script.
130130
-n, --nodes print out the parse tree that the parser produces
131131
--nodejs pass options directly to the "node" binary
132132
--no-header suppress the "Generated by" header
133-
-o, --output set the output directory for compiled JavaScript
133+
-o, --output set the output path or path/filename for compiled JavaScript
134134
-p, --print print out the compiled JavaScript
135135
-r, --require require the given module before eval or REPL
136136
-s, --stdio listen for and compile scripts over stdio

0 commit comments

Comments
 (0)