-
Notifications
You must be signed in to change notification settings - Fork 2k
[CS2] CSX spread attributes: <div {props…} /> #4607
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
Changes from 6 commits
da086b9
8841e47
a6172c0
c62be6b
91a294b
4a318fc
2d06fb1
e3d1546
00861f6
df30657
3bed4a4
9da14a2
5908448
437ff70
b097188
e86285b
7de2eb9
ff8d4f2
bd3fd67
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ | |
# are read by jison in the `parser.lexer` function defined in coffeescript.coffee. | ||
|
||
{Rewriter, INVERSES} = require './rewriter' | ||
|
||
log = console.log | ||
# Import the helpers we need. | ||
{count, starts, compact, repeat, invertLiterate, merge, | ||
locationDataToString, throwSyntaxError} = require './helpers' | ||
|
@@ -49,6 +49,7 @@ exports.Lexer = class Lexer | |
@importSpecifierList = no # Used to identify when in an IMPORT {...} FROM? ... | ||
@exportSpecifierList = no # Used to identify when in an EXPORT {...} FROM? ... | ||
@csxDepth = 0 # Used to optimize CSX checks, how deep in CSX we are. | ||
@csxSpreadProps = no # Used to detect if CSX attributes include spreads (<div {props...} />). | ||
|
||
@chunkLine = | ||
opts.line or 0 # The start line for the current @chunk. | ||
|
@@ -108,6 +109,20 @@ exports.Lexer = class Lexer | |
# though `is` means `===` otherwise. | ||
identifierToken: -> | ||
inCSXTag = @atCSXTag() | ||
# Check CSX properties synatx. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. “syntax” |
||
# Allowed properties: `<div id="someID" name={nameValue} {props...} /> | ||
if inCSXTag and @prev()[1] isnt ':' and @chunk[0] in ['{', '"', "'"] | ||
if @chunk[0] in ['"', "'"] | ||
@error "Unexpected token" | ||
csxSpreadMatch = /^({\.\.\.\S+})|({\S+\.\.\.})/.exec @chunk | ||
unless csxSpreadMatch | ||
if lastBrace = /^({[^}:\.]+)(:|\})/.exec(@chunk) | ||
@error "Unexpected token, expected ...", offset: lastBrace[0].length - 1 | ||
if badSpread = /^({\S+\.\.\.)|({\.\.\.\S+)[^\}]/.exec @chunk | ||
# Offset value for left or right spread dots position. | ||
offset = if badSpread[0][1] is '.' then badSpread[0].length - 1 else badSpread[0].length | ||
@error "Unexpected token, expected }", {offset} | ||
|
||
regex = if inCSXTag then CSX_ATTRIBUTE else IDENTIFIER | ||
return 0 unless match = regex.exec @chunk | ||
[input, id, colon] = match | ||
|
@@ -488,6 +503,8 @@ exports.Lexer = class Lexer | |
# CSX is like JSX but for CoffeeScript. | ||
csxToken: -> | ||
firstChar = @chunk[0] | ||
# Check the previous token to detect if attribute is spread. | ||
prevChar = if @tokens.length > 0 then @tokens[@tokens.length - 1][0] else '' | ||
if firstChar is '<' | ||
match = CSX_IDENTIFIER.exec @chunk[1...] | ||
return 0 unless match and ( | ||
|
@@ -512,8 +529,13 @@ exports.Lexer = class Lexer | |
@csxDepth-- | ||
return 2 | ||
else if firstChar is '{' | ||
token = @token '(', '(' | ||
@ends.push {tag: '}', origin: token} | ||
if prevChar is ':' | ||
token = @token '(', '(' | ||
@ends.push {tag: '}', origin: token} | ||
@csxSpreadProps = no | ||
else | ||
@ends.push {tag: '}'} | ||
@csxSpreadProps = yes | ||
return 1 | ||
else if firstChar is '>' | ||
# Ignore terminators inside a tag. | ||
|
@@ -540,7 +562,7 @@ exports.Lexer = class Lexer | |
else if @atCSXTag 1 | ||
if firstChar is '}' | ||
@pair firstChar | ||
@token ')', ')' | ||
@token ')', ')' unless @csxSpreadProps | ||
@token ',', ',' | ||
return 1 | ||
else | ||
|
@@ -553,6 +575,7 @@ exports.Lexer = class Lexer | |
i = @ends.length - 1 | ||
i-- while @ends[i]?.tag is 'OUTDENT' or depth-- > 0 # Ignore indents. | ||
last = @ends[i] | ||
# log @csxDepth, last?.tag | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove this one as well :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's already removed. |
||
last?.tag is '/>' and last | ||
|
||
# We treat all other single characters as a token. E.g.: `( ) , . !` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1171,7 +1171,7 @@ exports.Obj = class Obj extends Base | |
node.error 'cannot have an implicit value in an implicit object' | ||
|
||
# Object spread properties. https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md | ||
return @compileSpread o if @hasSplat() | ||
return @compileSpread o if @hasSplat() and not @csx | ||
|
||
idt = o.indent += TAB | ||
lastNoncom = @lastNonComment @properties | ||
|
@@ -1195,6 +1195,7 @@ exports.Obj = class Obj extends Base | |
answer = [] | ||
answer.push @makeCode if isCompact then '' else '\n' | ||
for prop, i in props | ||
propHasSplat = prop instanceof Splat | ||
join = if i is props.length - 1 | ||
'' | ||
else if isCompact and @csx | ||
|
@@ -1206,7 +1207,7 @@ exports.Obj = class Obj extends Base | |
else | ||
',\n' | ||
indent = if isCompact or prop instanceof Comment then '' else idt | ||
|
||
log = console.log | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove. |
||
key = if prop instanceof Assign and prop.context is 'object' | ||
prop.variable | ||
else if prop instanceof Assign | ||
|
@@ -1219,12 +1220,30 @@ exports.Obj = class Obj extends Base | |
key = key.properties[0].name | ||
prop = new Assign key, prop, 'object' | ||
if key is prop | ||
if prop.shouldCache() | ||
[key, value] = prop.base.cache o | ||
key = new PropertyName key.value if key instanceof IdentifierLiteral | ||
prop = new Assign key, value, 'object' | ||
else if not prop.bareLiteral?(IdentifierLiteral) | ||
prop = new Assign prop, prop, 'object' | ||
unless propHasSplat | ||
if prop.shouldCache() | ||
[key, value] = prop.base.cache o | ||
key = new PropertyName key.value if key instanceof IdentifierLiteral | ||
prop = new Assign key, value, 'object' | ||
else unless prop.bareLiteral?(IdentifierLiteral) | ||
prop = new Assign prop, prop, 'object' | ||
else | ||
# Spread in CSX. | ||
prop = if propHasSplat then new Literal "{#{prop.compile(o)}}" else prop | ||
# Check if CSX attribute is valid. | ||
# CSX atributes are processed in the `lexer` and converted from | ||
# `<div id={value} name="tag" {props...} title="#{foo()}" src={{a:1, b:2}} />` into | ||
# `{ id:(abc), name:"tags", ...props, title:("" + (foo())), src:{a:1, b:2} }` | ||
if @csx and prop instanceof Assign | ||
# The `prop.variable` must be the instance of `PropertyName` (i.e. `PROPERTY`). | ||
prop.variable.error "Unexpected token" unless prop.variable.unwrap() instanceof PropertyName | ||
propVal = prop.value.unwrap() | ||
# The `prop.value` instance can be: | ||
# - `StringLiteral`, e.g. id:"abc" | ||
# - `Parens` or `StringWithInterpolations`, e.g. id:{abc} or id:"#{abc}" or id:(abc) | ||
unless propVal instanceof StringLiteral or | ||
((propVal instanceof Parens or propVal instanceof StringWithInterpolations) and propVal.body instanceof Block) | ||
prop.value.error "expected wrapped or quoted CSX attribute" | ||
if indent then answer.push @makeCode indent | ||
prop.csx = yes if @csx | ||
answer.push @makeCode ' ' if @csx and i is 0 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn’t be here.