diff --git a/README.md b/README.md index f8b464b..2f358f6 100644 --- a/README.md +++ b/README.md @@ -51,23 +51,29 @@ For each `PathExpression` with a `VarHead` that is NOT in the local template sco - If there is NO `tail`: - - If the `MustacheStatement` is the child of an `AttrNode` with a name NOT starting with `@`: + - If the `MustacheStatement` is the child of an `AttrNode` - Wrap the invocation with the `tryLookupHelper` helper to determine if it is a helper at runtime and fall back to the `this` property if not ("ambiguous attribute fallback"). + - And the `AttrNode` represents a component argument (the name starts with `'@'`): - ```hbs - {{! before }} - + Prefix the `head` with `this`, making it a `ThisHead` ("expression fallback"), as shown above. - {{! after }} - {{#let (hash property=(tryLookupHelper "property")) as |maybeHelpers|}} - - {{/let}} - ``` + - And the `AttrNode` represents an attribute (the name does not start with `'@'`): + + Wrap the invocation with the `tryLookupHelper` helper to determine if it is a helper at runtime and fall back to the `this` property if not ("ambiguous attribute fallback"). + + ```hbs + {{! before }} + + + {{! after }} + {{#let (hash property=(tryLookupHelper "property")) as |maybeHelpers|}} + + {{/let}} + ``` - Otherwise: diff --git a/lib/this-fallback-plugin.ts b/lib/this-fallback-plugin.ts index 03f8a15..f5805b3 100644 --- a/lib/this-fallback-plugin.ts +++ b/lib/this-fallback-plugin.ts @@ -92,7 +92,6 @@ class ThisFallbackPlugin implements ASTPlugin { for (const attrNode of elementNode.attributes) { const value = attrNode.value; if ( - !attrNode.name.startsWith('@') && isNode(value, 'MustacheStatement') && mustacheNeedsFallback(value, this.scopeStack) ) { @@ -101,11 +100,15 @@ class ThisFallbackPlugin implements ASTPlugin { 'attrNode.value is not a MustacheStatement', isNode(attrNode.value, 'MustacheStatement') ); - ambiguousHeads.set(value.path.head.name, value.loc); - attrNode.value.path = helperOrExpressionFallback( - blockParamName, - value - ); + if (attrNode.name.startsWith('@')) { + attrNode.value.path = expressionFallback(value.path); + } else { + ambiguousHeads.set(value.path.head.name, value.loc); + attrNode.value.path = helperOrExpressionFallback( + blockParamName, + value + ); + } } else if (isNode(value, 'ConcatStatement')) { for (const part of value.parts) { const p = part; @@ -182,8 +185,7 @@ class ThisFallbackPlugin implements ASTPlugin { if (mustacheNeedsFallback(n, this.scopeStack)) { assert( 'unexpected AmbiguousMustacheExpression in attribute value', - path.parentNode?.type !== 'AttrNode' || - path.parentNode.name.startsWith('@') + path.parentNode?.type !== 'AttrNode' ); if (n.path.tail.length > 0) { node.path = expressionFallback(n.path); diff --git a/tests/integration/plugin/mustache-statement-test.ts b/tests/integration/plugin/mustache-statement-test.ts index 2896c00..66f8a92 100644 --- a/tests/integration/plugin/mustache-statement-test.ts +++ b/tests/integration/plugin/mustache-statement-test.ts @@ -86,6 +86,22 @@ module('Integration | Plugin | MustacheStatement', function (hooks) { }); module('for an @arg', function () { + test('has this-fallback', async function (assert) { + this.set('property', 'property-on-this'); + await render<{ property: string }>(hbs` + {{!-- + @glint-expect-error: + Unknown name 'property' (Glint knows better than to let us do this) + --}} + + {{yielded}} + + `); + assert + .dom() + .hasText('global-component-contents property-on-this'); + }); + test('does nothing to ThisHead PathExpression', async function (assert) { this.set('property', 'property-on-this'); await render<{ property: string }>(hbs`