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

Named Args and Named Blocks Syntax #301

Merged
merged 3 commits into from
Dec 23, 2017
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
2 changes: 1 addition & 1 deletion lib/pegjs/html/boolean-attr.pegjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "../key.pegjs" as key
@import "../non-glimmer-key.pegjs" as key

start = booleanAttribute

Expand Down
2 changes: 1 addition & 1 deletion lib/pegjs/html/tag-string.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ start = tagString

tagString
= c:$tagChar+
tagChar = [_a-zA-Z0-9-] / nonSeparatorColon
tagChar = [_a-zA-Z0-9-] / nonSeparatorColon / '@'
2 changes: 1 addition & 1 deletion lib/pegjs/key.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
start = key

key "Key"
= $((nmchar / ':' / '.')*)
= $((nmchar / ':' / '.' / '@')*)
1 change: 1 addition & 0 deletions lib/pegjs/mustache/attr-statement.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ closeBracket = DEDENT? _ ']'
- key/value pair
- subexpression
- a mustache value (i.e. positional params)
- positional params
*/
mustacheAttr = mustacheKeyValue / subexpression / mustacheAttrValue

Expand Down
2 changes: 1 addition & 1 deletion lib/pegjs/mustache/name-character.pegjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
start = newMustacheNameChar

// a character that can be in a mustache name
newMustacheNameChar = [-_/A-Za-z0-9] / arrayIndex / '.'
newMustacheNameChar = [-_/A-Za-z0-9] / arrayIndex / '.' / '@'

// Ember requires that array indexes have a . before them
arrayIndex = '.[' newMustacheNameChar* ']'
6 changes: 6 additions & 0 deletions lib/pegjs/non-glimmer-key.pegjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@import "./nmchar.pegjs" as nmchar

start = key

key "Key"
= $((nmchar / ':' / '.')*)
56 changes: 39 additions & 17 deletions tests/integration/glimmer-component-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ QUnit.module("glimmer-components");

test("basic syntax", function(){
var emblem = w(
"% my-component value=foo data-hint='not-my-component%%::'"
"% my-component @value=foo data-hint='not-my-component%%::'"
);
compilesTo(emblem,
'<my-component value={{foo}} data-hint=\"not-my-component%%::\"></my-component>');
'<my-component @value={{foo}} data-hint=\"not-my-component%%::\"></my-component>');
});

test("basic syntax with legacy quoting", function(){
Expand All @@ -23,33 +23,41 @@ test("basic syntax with legacy quoting", function(){
});
});

test("boolean attribute passed in as component input", function() {
var emblem = w(
"% my-component @multiselect=false"
);
compilesTo(emblem,
'<my-component @multiselect={{false}}></my-component>');
});

test("names with :", function(){
var emblem = w(
"% inputs:my-component value=foo"
"% inputs:my-component @value=foo"
);
compilesTo(emblem,
'<inputs:my-component value={{foo}}></inputs:my-component>');
'<inputs:my-component @value={{foo}}></inputs:my-component>');
});

// @TODO
// test("names with / turn into :")

test("Blocks", function() {
var emblem = w(
"% my-component value=foo",
"% my-component @value=foo",
" |Hi!"
);
compilesTo(emblem,
'<my-component value={{foo}}>Hi!</my-component>');
'<my-component @value={{foo}}>Hi!</my-component>');
});

test("Block params", function() {
var emblem = w(
"% my-component value=foo as |comp1 comp2|",
"% my-component @value=foo as |comp1 comp2|",
" = comp.name"
);
compilesTo(emblem,
'<my-component value={{foo}} as |comp1 comp2|>{{comp.name}}</my-component>');
'<my-component @value={{foo}} as |comp1 comp2|>{{comp.name}}</my-component>');
});

// @TODO: What should the result of this be?
Expand All @@ -58,10 +66,10 @@ test("Block params", function() {
test('brackets with string', function(){
var emblem = w('',
'%my-component [',
' foo=bar',
' baz=\'food\' ]');
' @foo=bar',
' @baz=\'food\' ]');
compilesTo(
emblem, '<my-component foo={{bar}} baz=\"food\"></my-component>');
emblem, '<my-component @foo={{bar}} @baz=\"food\"></my-component>');
});

// Invalid
Expand All @@ -70,30 +78,30 @@ test('brackets with string', function(){
test('bracketed nested block', function(){
var emblem = w('',
'%my-component [',
' something="false" ]',
' @something="false" ]',
' p Bracketed helper attrs!');
compilesTo(
emblem, '<my-component something=\"false\"><p>Bracketed helper attrs!</p></my-component>');
emblem, '<my-component @something=\"false\"><p>Bracketed helper attrs!</p></my-component>');
});

test('bracketed nested with actions', function(){
var emblem = w('',
'%my-component [',
' onclick={ action \'doSometing\' foo bar }',
' change=\'otherAction\'',
' something="false" ]',
' @something="false" ]',
' p Bracketed helper attrs!');
compilesTo(
emblem, '<my-component onclick={{action \'doSometing\' foo bar}} {{action \"otherAction\" on=\"change\"}} something=\"false\"><p>Bracketed helper attrs!</p></my-component>');
emblem, '<my-component onclick={{action \'doSometing\' foo bar}} {{action \"otherAction\" on=\"change\"}} @something=\"false\"><p>Bracketed helper attrs!</p></my-component>');
});

// @TODO: should these support mustache-like syntax? (i.e. %my-component value=(foo) )
test("Sub-expressions", function() {
var emblem = w(
"% my-component value={ (or (eq foo 'bar') (eq foo 'baz')) }"
"% my-component @value={ (or (eq foo 'bar') (eq foo 'baz')) }"
);
compilesTo(emblem,
'<my-component value={{(or (eq foo \'bar\') (eq foo \'baz\'))}}></my-component>');
'<my-component @value={{(or (eq foo \'bar\') (eq foo \'baz\'))}}></my-component>');
});

test('recursive nesting part 2', function(){
Expand All @@ -103,3 +111,17 @@ test('recursive nesting part 2', function(){
' p Hello');
compilesTo(emblem, '<my-comp-1><my-comp-2><p>Hello</p></my-comp-2></my-comp-1>');
});

test('named block support', function() {
var emblem = w(
'% x-modal',
' % @header as |@title|',
' |Header #{title}',
' % @body',
' |Body',
' % @footer',
' |Footer'
)

compilesTo(emblem, '<x-modal><@header as |@title|>Header {{title}}</@header><@body>Body</@body><@footer>Footer</@footer></x-modal>');
});
27 changes: 27 additions & 0 deletions tests/integration/mustaches-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ test("various one-liners", function(){
'{{foo}}{{arf}}<p>{{foo}}</p><span class="foo"></span><p data-foo="yes">{{goo}}</p>');
});

test('named argument syntax', function() {
compilesTo('= @bar', '{{@bar}}');
});

test("double =='s un-escape", function(){
var emblem = w(
Expand Down Expand Up @@ -526,3 +529,27 @@ test('mustache with else if and complex statements', function() {
compilesTo(emblem,
'{{#if foo}}<p>Hi!</p>{{else if (eq 1 (and-or a=b showHidden=(eq 1 2)))}}<p>Wow what was that?</p>{{/if}}');
});

test('named block support', function() {
var emblem = w(
'= x-modal',
' % @header as |@title|',
' |Header #{title}',
' % @body',
' |Body',
' % @footer',
' |Footer'
)

compilesTo(emblem, '{{#x-modal}}<@header as |@title|>Header {{title}}</@header><@body>Body</@body><@footer>Footer</@footer>{{/x-modal}}');
});

test('named block with block param', function() {
var emblem = w(
'= x-layout as |@widget|',
' = @widget as |a b c|',
' |Hi.'
)

compilesTo(emblem, '{{#x-layout as |@widget|}}{{#@widget as |a b c|}}Hi.{{/@widget}}{{/x-layout}}');
});