Skip to content

Commit

Permalink
Added destructuring to block params definition: inside glimmer compon…
Browse files Browse the repository at this point in the history
…ents and mustache definitions
  • Loading branch information
evgenibir committed Mar 26, 2021
1 parent a58d6a0 commit 4161770
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 16 deletions.
65 changes: 55 additions & 10 deletions lib/parser.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
@import "./pegjs/html/nested-text-nodes.pegjs" as htmlNestedTextNodes

@import "./pegjs/mustache/ast/mustache.pegjs" as mustacheAst
@import "./pegjs/syntax/block-params.pegjs" as blockParams
@import "./pegjs/syntax/block-params.pegjs" as blockParamsRaw
@import "./pegjs/syntax/destructured-block-params.pegjs" as blockParamsDestructured
@import "./pegjs/mustache/attr-statement.pegjs" as mustacheAttrStatement

{
Expand Down Expand Up @@ -86,6 +87,37 @@
return hasItems;
}

function groupBlockParams(blockParams, joiningParams, destructuredParams) {
for (const param of blockParams.filter(p => p.type === 'regular')) {
joiningParams.push(param.mainParam)
}
for (const param of blockParams.filter(p => p.type !== 'regular')) {
joiningParams.push(param.mainParam)
destructuredParams.push(param)
}
}

function createDestructuringBlock(destructuredParams) {
let joinedParams = []
let letAttrs = []
for (const destructuredParam of destructuredParams) {
if (destructuredParam.type === 'array') {
destructuredParam.params.forEach(i => {joinedParams.push(i)})
destructuredParam.params.forEach((param, i) => {
letAttrs.push(`(get ${destructuredParam.mainParam} ${i})`)
})
} else if (destructuredParam.type === 'hash') {
destructuredParam.params.forEach(i => {joinedParams.push(i)})
destructuredParam.params.forEach((param) => {
letAttrs.push(`(get ${destructuredParam.mainParam} "${param}")`)
})
}
}
const mustacheContent = `let ${letAttrs.join(' ')} as |${joinedParams.join(' ')}|`
const block = builder.generateBlock(mustacheContent);
builder.enter(block);
}

/**
@param [<<>, {}>] mustacheTuple
@return
Expand All @@ -106,8 +138,11 @@
mustacheContent += ' ' + attrs.join(' ');
}

if (mustacheBlockParams) {
mustacheContent += ' as |' + mustacheBlockParams.join(' ') + '|';
const destructuredParams = []
if (mustacheBlockParams && mustacheBlockParams.length > 0) {
const joiningParams = []
groupBlockParams(mustacheBlockParams, joiningParams, destructuredParams)
mustacheContent += ' as |' + joiningParams.join(' ') + '|';
}

if (mustache.isViewHelper) {
Expand All @@ -123,9 +158,13 @@
}

if (isArrayWithContent(blockTuple)) {
var block = builder.generateBlock(mustacheContent, escaped);
const block = builder.generateBlock(mustacheContent, escaped);
builder.enter(block);

if (destructuredParams.length) {
createDestructuringBlock(destructuredParams)
}

// Iterate on each tuple and either add it as a child node or an invertible node
blockTuple.forEach(function(tuple) {
if (!tuple)
Expand All @@ -137,6 +176,9 @@
builder.add('childNodes', tuple);
});

if (destructuredParams.length) {
builder.add('childNodes', [builder.exit()])
}
return builder.exit();
} else {
return builder.generateMustache(mustacheContent, escaped);
Expand Down Expand Up @@ -202,12 +244,12 @@ colonContent = ': ' _ c:contentStatement { return c; }
// and any nested content inside of it.
htmlElement = h:inHtmlTag nested:htmlTerminator
{
parseInHtml(...h);
const isDoubleExit = parseInHtml(...h);
if (nested && nested.length > 0) {
nested = castStringsToTextNodes(nested);
builder.add('childNodes', nested);
}

if (isDoubleExit) builder.add('childNodes', [builder.exit()])
return [builder.exit()];
}

Expand Down Expand Up @@ -432,7 +474,7 @@ mustacheEndBracketAndNested
= else
= foo
*/
= _ ']' _ blockParams:blockParams? TERM+ block:contentWithElse DEDENT {
= _ ']' blockParams:blockParams? TERM+ block:contentWithElse DEDENT {
return {
blockParams: blockParams,
blockTuple: block
Expand All @@ -449,7 +491,7 @@ mustacheEndBracketAndNested
= else
= foo
*/
/ _ DEDENT ']' _ blockParams:blockParams? TERM+ INDENT _ block:contentWithElse DEDENT {
/ _ DEDENT ']' blockParams:blockParams? TERM+ INDENT _ block:contentWithElse DEDENT {
return {
blockParams: blockParams,
blockTuple: block
Expand Down Expand Up @@ -510,8 +552,11 @@ invertibleParam
invertibleBlock
= blankLine* indentation c:content { return c; }



blockParams
= _ params:(blockParamsRaw / blockParamsDestructured)
{
return params;
}

/**
Duplicates
Expand Down
13 changes: 10 additions & 3 deletions lib/pegjs/html/in-tag.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,18 @@
}

if (blockParams && blockParams.length > 0) {
var joinedParams = blockParams.join(' ');
var tagString = 'as |' + joinedParams + '|';

const joiningParams = []
const destructuredParams = []
groupBlockParams(blockParams, joiningParams, destructuredParams)
const tagString = 'as |' + joiningParams.join(' ') + '|';
builder.inTagText(tagString);

if (destructuredParams.length) {
createDestructuringBlock(destructuredParams)
return true;
}
}
return false;
}

function isKnownTag(tag) {
Expand Down
3 changes: 2 additions & 1 deletion lib/pegjs/html/tag-component.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@import "../mustache/ast/statement.pegjs" as statement
@import "./helper-with-mustache.pegjs" as helperValue
@import "../syntax/block-params.pegjs" as blockParamsRaw
@import "../syntax/destructured-block-params.pegjs" as blockParamsDestructured
@import "../whitespace.pegjs" as _
@import "../whitespace-req.pegjs" as __
@import "../inline-comment.pegjs" as inlineComment
Expand Down Expand Up @@ -84,7 +85,7 @@ componentTag
}

blockParams
= _ params:blockParamsRaw
= _ params:(blockParamsRaw / blockParamsDestructured)
{
return params;
}
Expand Down
3 changes: 2 additions & 1 deletion lib/pegjs/mustache/ast/mustache.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@import "../../syntax/mustache-shorthand.pegjs" as newMustacheShortHand
@import "../../syntax/modifier-char.pegjs" as modifierChar
@import "../../syntax/block-params.pegjs" as blockParamsRaw
@import "../../syntax/destructured-block-params.pegjs" as blockParamsDestructured
@import "../../whitespace.pegjs" as _

start = newMustache
Expand Down Expand Up @@ -41,7 +42,7 @@ newMustacheName = !invalidNameStartChar name:$mustacheNameChar+ modifier:modifie
}

blockParams
= _ params:blockParamsRaw
= _ params:(blockParamsRaw / blockParamsDestructured)
{
return params;
}
Expand Down
5 changes: 4 additions & 1 deletion lib/pegjs/syntax/block-params.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ blockParams = blockStart _ params:blockParamName+ blockEnd {
}

blockParamName 'block param'
= newMustacheAttrValue
= param:newMustacheAttrValue
{
return {type: 'regular', mainParam: param}
}
46 changes: 46 additions & 0 deletions lib/pegjs/syntax/destructured-block-params.pegjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@import "../mustache/attr-value.pegjs" as newMustacheAttrValue
@import "./block-start.pegjs" as blockStart
@import "./block-end.pegjs" as blockEnd
@import "../whitespace.pegjs" as _

start = destructuredParams

destructuredParams = blockStart _ params:(regularParamName / destructuringArray / destructuringHash)+ _ blockEnd {
return params;
}

blockParamName 'block param'
= newMustacheAttrValue

openBracket
= '[' _

closeBracket
= _ ']'

openMustache
= '{' _

closeMustache
= _ '}'

divider
= _ '=' _

regularParamName 'regular block param'
= param:newMustacheAttrValue
{
return {type: 'regular', mainParam: param}
}

destructuringArray
= openBracket params:blockParamName+ closeBracket divider mainParam:newMustacheAttrValue
{
return {type: 'array', mainParam, params}
}

destructuringHash
= openMustache params:blockParamName+ closeMustache divider mainParam:newMustacheAttrValue
{
return {type: 'hash', mainParam, params}
}
20 changes: 20 additions & 0 deletions tests/integration/ember/blocks-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,25 @@ module('ember: blocks', function (hooks) {
assert.compilesTo(emblem,
'{{#my-component as |item|}}<p>{{item.name}}</p>{{/my-component}}');
});

test("block params with destructuring hash", function (assert) {
const emblem = w(
"= my-component value=foo as |comp1 {subcomp subcomp2}=comp comp2|",
" = subcomp value=foo: = subcomp2"
);

assert.compilesTo(emblem,
'{{#my-component value=foo as |comp1 comp2 comp|}}{{#let (get comp "subcomp") (get comp "subcomp2") as |subcomp subcomp2|}}{{#subcomp value=foo}}{{subcomp2}}{{/subcomp}}{{/let}}{{/my-component}}');
});

test("block params with destructuring array", function (assert) {
const emblem = w(
"= my-component value=foo as |comp1 [subcomp subcomp2]=comp comp2|",
" = subcomp value=foo: = subcomp2"
);

assert.compilesTo(emblem,
'{{#my-component value=foo as |comp1 comp2 comp|}}{{#let (get comp 0) (get comp 1) as |subcomp subcomp2|}}{{#subcomp value=foo}}{{subcomp2}}{{/subcomp}}{{/let}}{{/my-component}}');
});
});
});
20 changes: 20 additions & 0 deletions tests/integration/glimmer/blocks-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,24 @@ module('glimmer: blocks', function (hooks) {
assert.compilesTo(emblem, '<my-comp-1><my-comp-2><p>Hello</p></my-comp-2></my-comp-1>');
});

test("block params with destructuring hash", function (assert) {
const emblem = w(
"%MyComponent @value=foo as |comp1 {subcomp subcomp2}=comp comp2|",
" % subcomp @value=foo: = subcomp2"
);

assert.compilesTo(emblem,
'<MyComponent @value={{foo}} as |comp1 comp2 comp|>{{#let (get comp "subcomp") (get comp "subcomp2") as |subcomp subcomp2|}}<subcomp @value={{foo}}>{{subcomp2}}</subcomp>{{/let}}</MyComponent>');
});

test("block params with destructuring array", function (assert) {
const emblem = w(
"%MyComponent @value=foo as |comp1 [subcomp subcomp2]=comp comp2|",
" % subcomp @value=foo: = subcomp2"
);

assert.compilesTo(emblem,
'<MyComponent @value={{foo}} as |comp1 comp2 comp|>{{#let (get comp 0) (get comp 1) as |subcomp subcomp2|}}<subcomp @value={{foo}}>{{subcomp2}}</subcomp>{{/let}}</MyComponent>');
});

});

0 comments on commit 4161770

Please sign in to comment.