jashkenas--coffeescript/test/csx.coffee

727 lines
15 KiB
CoffeeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# We usually do not check the actual JS output from the compiler, but since
# JSX is not natively supported by Node, we do it in this case.
test 'self closing', ->
eqJS '''
<div />
''', '''
<div />;
'''
test 'self closing formatting', ->
eqJS '''
<div/>
''', '''
<div />;
'''
test 'self closing multiline', ->
eqJS '''
<div
/>
''', '''
<div />;
'''
test 'regex attribute', ->
eqJS '''
<div x={/>asds/} />
''', '''
<div x={/>asds/} />;
'''
test 'string attribute', ->
eqJS '''
<div x="a" />
''', '''
<div x="a" />;
'''
test 'simple attribute', ->
eqJS '''
<div x={42} />
''', '''
<div x={42} />;
'''
test 'assignment attribute', ->
eqJS '''
<div x={y = 42} />
''', '''
var y;
<div x={y = 42} />;
'''
test 'object attribute', ->
eqJS '''
<div x={{y: 42}} />
''', '''
<div x={{
y: 42
}} />;
'''
test 'attribute without value', ->
eqJS '''
<div checked x="hello" />
''', '''
<div checked x="hello" />;
'''
test 'paired', ->
eqJS '''
<div></div>
''', '''
<div></div>;
'''
test 'simple content', ->
eqJS '''
<div>Hello world</div>
''', '''
<div>Hello world</div>;
'''
test 'content interpolation', ->
eqJS '''
<div>Hello {42}</div>
''', '''
<div>Hello {42}</div>;
'''
test 'nested tag', ->
eqJS '''
<div><span /></div>
''', '''
<div><span /></div>;
'''
test 'tag inside interpolation formatting', ->
eqJS '''
<div>Hello {<span />}</div>
''', '''
<div>Hello <span /></div>;
'''
test 'tag inside interpolation, tags are callable', ->
eqJS '''
<div>Hello {<span /> x}</div>
''', '''
<div>Hello {<span />(x)}</div>;
'''
test 'tags inside interpolation, tags trigger implicit calls', ->
eqJS '''
<div>Hello {f <span />}</div>
''', '''
<div>Hello {f(<span />)}</div>;
'''
test 'regex in interpolation', ->
eqJS '''
<div x={/>asds/}><div />{/>asdsad</}</div>
''', '''
<div x={/>asds/}><div />{/>asdsad</}</div>;
'''
test 'interpolation in string attribute value', ->
eqJS '''
<div x="Hello #{world}" />
''', '''
<div x={`Hello ${world}`} />;
'''
# Unlike in `coffee-react-transform`.
test 'bare numbers not allowed', ->
throws -> CoffeeScript.compile '<div x=3 />'
test 'bare expressions not allowed', ->
throws -> CoffeeScript.compile '<div x=y />'
test 'bare complex expressions not allowed', ->
throws -> CoffeeScript.compile '<div x=f(3) />'
test 'unescaped opening tag angle bracket disallowed', ->
throws -> CoffeeScript.compile '<Person><<</Person>'
test 'space around equal sign', ->
eqJS '''
<div popular = "yes" />
''', '''
<div popular="yes" />;
'''
# The following tests were adopted from James Friends
# [https://github.com/jsdf/coffee-react-transform](https://github.com/jsdf/coffee-react-transform).
test 'ambiguous tag-like expression', ->
throws -> CoffeeScript.compile 'x = a <b > c'
test 'ambiguous tag', ->
eqJS '''
a <b > c </b>
''', '''
a(<b> c </b>);
'''
test 'escaped CoffeeScript attribute', ->
eqJS '''
<Person name={if test() then 'yes' else 'no'} />
''', '''
<Person name={test() ? 'yes' : 'no'} />;
'''
test 'escaped CoffeeScript attribute over multiple lines', ->
eqJS '''
<Person name={
if test()
'yes'
else
'no'
} />
''', '''
<Person name={test() ? 'yes' : 'no'} />;
'''
test 'multiple line escaped CoffeeScript with nested CSX', ->
eqJS '''
<Person name={
if test()
'yes'
else
'no'
}>
{
for n in a
<div> a
asf
<li xy={"as"}>{ n+1 }<a /> <a /> </li>
</div>
}
</Person>
''', '''
var n;
<Person name={test() ? 'yes' : 'no'}>
{(function() {
var i, len, results;
results = [];
for (i = 0, len = a.length; i < len; i++) {
n = a[i];
results.push(<div> a
asf
<li xy={"as"}>{n + 1}<a /> <a /> </li>
</div>);
}
return results;
})()}
</Person>;
'''
test 'nested CSX within an attribute, with object attr value', ->
eqJS '''
<Company>
<Person name={<NameComponent attr3={ {'a': {}, b: '{'} } />} />
</Company>
''', '''
<Company>
<Person name={<NameComponent attr3={{
'a': {},
b: '{'
}} />} />
</Company>;
'''
test 'complex nesting', ->
eqJS '''
<div code={someFunc({a:{b:{}, C:'}{}{'}})} />
''', '''
<div code={someFunc({
a: {
b: {},
C: '}{}{'
}
})} />;
'''
test 'multiline tag with nested CSX within an attribute', ->
eqJS '''
<Person
name={
name = formatName(user.name)
<NameComponent name={name.toUppercase()} />
}
>
blah blah blah
</Person>
''', '''
var name;
<Person name={name = formatName(user.name), <NameComponent name={name.toUppercase()} />}>
blah blah blah
</Person>;
'''
test 'escaped CoffeeScript with nested object literals', ->
eqJS '''
<Person>
blah blah blah {
{'a' : {}, 'asd': 'asd'}
}
</Person>
''', '''
<Person>
blah blah blah {{
'a': {},
'asd': 'asd'
}}
</Person>;
'''
test 'multiline tag attributes with escaped CoffeeScript', ->
eqJS '''
<Person name={if isActive() then 'active' else 'inactive'}
someattr='on new line' />
''', '''
<Person name={isActive() ? 'active' : 'inactive'} someattr='on new line' />;
'''
test 'lots of attributes', ->
eqJS '''
<Person eyes={2} friends={getFriends()} popular = "yes"
active={ if isActive() then 'active' else 'inactive' } data-attr='works' checked check={me_out}
/>
''', '''
<Person eyes={2} friends={getFriends()} popular="yes" active={isActive() ? 'active' : 'inactive'} data-attr='works' checked check={me_out} />;
'''
# TODO: fix partially indented CSX
# test 'multiline elements', ->
# eqJS '''
# <div something={
# do ->
# test = /432/gm # this is a regex
# 6 /432/gm # this is division
# }
# >
# <div>
# <div>
# <div>
# <article name={ new Date() } number={203}
# range={getRange()}
# >
# </article>
# </div>
# </div>
# </div>
# </div>
# ''', '''
# bla
# '''
test 'complex regex', ->
eqJS '''
<Person />
/\\/\\/<Person \\/>\\>\\//
''', '''
<Person />;
/\\/\\/<Person \\/>\\>\\//;
'''
test 'heregex', ->
eqJS '''
test = /432/gm # this is a regex
6 /432/gm # this is division
<Tag>
{test = /<Tag>/} this is a regex containing something which looks like a tag
</Tag>
<Person />
REGEX = /// ^
(/ (?! [\s=] ) # comment comment <comment>comment</comment>
[^ [ / \n \\ ]* # comment comment
(?:
<Tag />
(?: \\[\s\S] # comment comment
| \[ # comment comment
[^ \] \n \\ ]*
(?: \\[\s\S] [^ \] \n \\ ]* )*
<Tag>tag</Tag>
]
) [^ [ / \n \\ ]*
)*
/) ([imgy]{0,4}) (?!\w)
///
<Person />
''', '''
var REGEX, test;
test = /432/gm;
6 / 432 / gm;
<Tag>
{(test = /<Tag>/)} this is a regex containing something which looks like a tag
</Tag>;
<Person />;
REGEX = /^(\\/(?![s=])[^[\\/ ]*(?:<Tag\\/>(?:\\[sS]|[[^] ]*(?:\\[sS][^] ]*)*<Tag>tag<\\/Tag>])[^[\\/ ]*)*\\/)([imgy]{0,4})(?!w)/;
<Person />;
'''
test 'comment within CSX is not treated as comment', ->
eqJS '''
<Person>
# i am not a comment
</Person>
''', '''
<Person>
# i am not a comment
</Person>;
'''
test 'comment at start of CSX escape', ->
eqJS '''
<Person>
{# i am a comment
"i am a string"
}
</Person>
''', '''
<Person>
{"i am a string"}
</Person>;
'''
test 'CSX comment cannot be used inside interpolation', ->
throws -> CoffeeScript.compile '''
<Person>
{# i am a comment}
</Person>
'''
test 'comment syntax cannot be used inline', ->
throws -> CoffeeScript.compile '''
<Person>{#comment inline}</Person>
'''
test 'string within CSX is ignored', ->
eqJS '''
<Person> "i am not a string" 'nor am i' </Person>
''', '''
<Person> "i am not a string" 'nor am i' </Person>;
'''
test 'special chars within CSX are ignored', ->
eqJS """
<Person> a,/';][' a\''@$%^&˚¬∑˜˚∆å∂¬˚*()*&^%$>> '"''"'''\'\'m' i </Person>
""", """
<Person> a,/';][' a''@$%^&˚¬∑˜˚∆å∂¬˚*()*&^%$>> '"''"'''''m' i </Person>;
"""
test 'html entities (name, decimal, hex) within CSX', ->
eqJS '''
<Person> &&&&euro; &#8364; &#x20AC;;; </Person>
''', '''
<Person> &&&&euro; &#8364; &#x20AC;;; </Person>;
'''
test 'tag with {{}}', ->
eqJS '''
<Person name={{value: item, key, item}} />
''', '''
<Person name={{
value: item,
key,
item
}} />;
'''
test 'tag with namespace', ->
eqJS '''
<Something.Tag></Something.Tag>
''', '''
<Something.Tag></Something.Tag>;
'''
test 'tag with lowercase namespace', ->
eqJS '''
<something.tag></something.tag>
''', '''
<something.tag></something.tag>;
'''
test 'self closing tag with namespace', ->
eqJS '''
<Something.Tag />
''', '''
<Something.Tag />;
'''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'self closing tag with spread attribute', ->
# eqJS '''
# <Component a={b} {... x } b="c" />
# ''', '''
# React.createElement(Component, Object.assign({"a": (b)}, x , {"b": "c"}))
# '''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'complex spread attribute', ->
# eqJS '''
# <Component {...x} a={b} {... x } b="c" {...$my_xtraCoolVar123 } />
# ''', '''
# React.createElement(Component, Object.assign({}, x, {"a": (b)}, x , {"b": "c"}, $my_xtraCoolVar123 ))
# '''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'multiline spread attribute', ->
# eqJS '''
# <Component {...
# x } a={b} {... x } b="c" {...z }>
# </Component>
# ''', '''
# React.createElement(Component, Object.assign({},
# x , {"a": (b)}, x , {"b": "c"}, z )
# )
# '''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'multiline tag with spread attribute', ->
# eqJS '''
# <Component
# z="1"
# {...x}
# a={b}
# b="c"
# >
# </Component>
# ''', '''
# React.createElement(Component, Object.assign({ \
# "z": "1"
# }, x, { \
# "a": (b), \
# "b": "c"
# })
# )
# '''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'multiline tag with spread attribute first', ->
# eqJS '''
# <Component
# {...
# x}
# z="1"
# a={b}
# b="c"
# >
# </Component>
# ''', '''
# React.createElement(Component, Object.assign({}, \
# x, { \
# "z": "1", \
# "a": (b), \
# "b": "c"
# })
# )
# '''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'complex multiline spread attribute', ->
# eqJS '''
# <Component
# {...
# y} a={b} {... x } b="c" {...z }>
# <div code={someFunc({a:{b:{}, C:'}'}})} />
# </Component>
# ''', '''
# React.createElement(Component, Object.assign({}, \
# y, {"a": (b)}, x , {"b": "c"}, z ),
# React.createElement("div", {"code": (someFunc({a:{b:{}, C:'}'}}))})
# )
# '''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'self closing spread attribute on single line', ->
# eqJS '''
# <Component a="b" c="d" {...@props} />
# ''', '''
# React.createElement(Component, Object.assign({"a": "b", "c": "d"}, @props ))
# '''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'self closing spread attribute on new line', ->
# eqJS '''
# <Component
# a="b"
# c="d"
# {...@props}
# />
# ''', '''
# React.createElement(Component, Object.assign({ \
# "a": "b", \
# "c": "d"
# }, @props
# ))
# '''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'self closing spread attribute on same line', ->
# eqJS '''
# <Component
# a="b"
# c="d"
# {...@props} />
# ''', '''
# React.createElement(Component, Object.assign({ \
# "a": "b", \
# "c": "d"
# }, @props ))
# '''
# TODO: Uncomment the following test once destructured object spreads are supported.
# test 'self closing spread attribute on next line', ->
# eqJS '''
# <Component
# a="b"
# c="d"
# {...@props}
# />
# ''', '''
# React.createElement(Component, Object.assign({ \
# "a": "b", \
# "c": "d"
# }, @props
# ))
# '''
test 'empty strings are not converted to true', ->
eqJS '''
<Component val="" />
''', '''
<Component val="" />;
'''
test 'CoffeeScript @ syntax in tag name', ->
throws -> CoffeeScript.compile '''
<@Component>
<Component />
</@Component>
'''
test 'hyphens in tag names', ->
eqJS '''
<paper-button className="button">{text}</paper-button>
''', '''
<paper-button className="button">{text}</paper-button>;
'''
test 'closing tags must be closed', ->
throws -> CoffeeScript.compile '''
<a></a
'''
# Tests for allowing less than operator without spaces when ther is no CSX
test 'unspaced less than without CSX: identifier', ->
a = 3
div = 5
ok a<div
test 'unspaced less than without CSX: number', ->
div = 5
ok 3<div
test 'unspaced less than without CSX: paren', ->
div = 5
ok (3)<div
test 'unspaced less than without CSX: index', ->
div = 5
a = [3]
ok a[0]<div
test 'tag inside CSX works following: identifier', ->
eqJS '''
<span>a<div /></span>
''', '''
<span>a<div /></span>;
'''
test 'tag inside CSX works following: number', ->
eqJS '''
<span>3<div /></span>
''', '''
<span>3<div /></span>;
'''
test 'tag inside CSX works following: paren', ->
eqJS '''
<span>(3)<div /></span>
''', '''
<span>(3)<div /></span>;
'''
test 'tag inside CSX works following: square bracket', ->
eqJS '''
<span>]<div /></span>
''', '''
<span>]<div /></span>;
'''
test 'unspaced less than inside CSX works but is not encouraged', ->
eqJS '''
a = 3
div = 5
html = <span>{a<div}</span>
''', '''
var a, div, html;
a = 3;
div = 5;
html = <span>{a < div}</span>;
'''
test 'unspaced less than before CSX works but is not encouraged', ->
eqJS '''
div = 5
res = 2<div
html = <span />
''', '''
var div, html, res;
div = 5;
res = 2 < div;
html = <span />;
'''
test 'unspaced less than after CSX works but is not encouraged', ->
eqJS '''
div = 5
html = <span />
res = 2<div
''', '''
var div, html, res;
div = 5;
html = <span />;
res = 2 < div;
'''