Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #4564: indent closes implicit object #4570

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions lib/coffeescript/rewriter.js

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

23 changes: 14 additions & 9 deletions src/rewriter.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,11 @@ exports.Rewriter = class Rewriter
return no unless nextTerminatorIdx?
@looksObjectish nextTerminatorIdx + 1

# Don't end an implicit call on next indent if any of these are in an argument
if inImplicitCall() and tag in ['IF', 'TRY', 'FINALLY', 'CATCH',
'CLASS', 'SWITCH']
# Don't end an implicit call/object on next indent if any of these are in an argument/value
if (
(inImplicitCall() or inImplicitObject()) and tag in CONTROL_IN_IMPLICIT or
inImplicitObject() and prevTag is ':' and tag is 'FOR'
)
stack.push ['CONTROL', i, ours: yes]
return forward(1)

Expand All @@ -206,7 +208,11 @@ exports.Rewriter = class Rewriter
# 2. The last token before the indent is part of the list below
#
if prevTag not in ['=>', '->', '[', '(', ',', '{', 'ELSE', '=']
endImplicitCall() while inImplicitCall()
while inImplicitCall() or inImplicitObject() and prevTag isnt ':'
if inImplicitCall()
endImplicitCall()
else
endImplicitObject()
stack.pop() if inImplicitControl()
stack.push [tag, i]
return forward(1)
Expand Down Expand Up @@ -273,9 +279,6 @@ exports.Rewriter = class Rewriter
else i - 1
s -= 2 while @tag(s - 2) is 'HERECOMMENT'

# Mark if the value is a for loop
@insideForDeclaration = nextTag is 'FOR'

startsLine = s is 0 or @tag(s - 1) in LINEBREAKS or tokens[s - 1].newLine
# Are we just continuing an already declared object?
if stackTop()
Expand Down Expand Up @@ -316,7 +319,7 @@ exports.Rewriter = class Rewriter
endImplicitCall()
# Close implicit objects such as:
# return a: 1, b: 2 unless true
else if inImplicitObject() and not @insideForDeclaration and sameLine and
else if inImplicitObject() and sameLine and
tag isnt 'TERMINATOR' and prevTag isnt ':' and
not (tag is 'POST_IF' and startsLine and implicitObjectContinues(i + 1))
endImplicitObject()
Expand Down Expand Up @@ -344,7 +347,6 @@ exports.Rewriter = class Rewriter
# f a, b: c, d: e, f, g: h: i, j
#
if tag is ',' and not @looksObjectish(i + 1) and inImplicitObject() and
not @insideForDeclaration and
(nextTag isnt 'TERMINATOR' or not @looksObjectish(i + 2))
# When nextTag is OUTDENT the comma is insignificant and
# should just be ignored so embed it in the implicit object.
Expand Down Expand Up @@ -540,3 +542,6 @@ LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT']

# Tokens that close open calls when they follow a newline.
CALL_CLOSERS = ['.', '?.', '::', '?::']

# Tokens that prevent a subsequent indent from ending implicit calls/objects
CONTROL_IN_IMPLICIT = ['IF', 'TRY', 'FINALLY', 'CATCH', 'CLASS', 'SWITCH']
17 changes: 17 additions & 0 deletions test/objects.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,23 @@ test "#1263: Braceless object return", ->
eq 2, obj.b
eq 3, obj.c()

test "#4564: indent should close implicit object", ->
f = (x) -> x

arrayEq ['a'],
for key of f a: 1
key

g = null
if f a: 1
g = 3
eq g, 3

h = null
if a: (i for i in [1, 2, 3])
h = 4
eq h, 4

test "#4544: Postfix conditionals in first line of implicit object literals", ->
two =
foo:
Expand Down