-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[BUGFIX beta] Allow passing a string literal to {{helper}} and {{modi…
…fier}} As per [RFC #432](https://github.com/emberjs/rfcs/blob/master/text/0432-contextual-helpers.md#invoking-contextual-modifiers) However, dynamic string values are currently disallowed per earlier framework team weekly meeting discussion to not make it harder for Embroider to heuristically analyze the dynamic usages. Eventually we will want to do the same for components as well, and this AST transform would work there too. (cherry picked from commit 397d6b9)
- Loading branch information
1 parent
fd1de5c
commit 6d430b6
Showing
8 changed files
with
381 additions
and
3 deletions.
There are no files selected for viewing
57 changes: 57 additions & 0 deletions
57
packages/@ember/-internals/glimmer/lib/helpers/-disallow-dynamic-resolution.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** | ||
@module ember | ||
*/ | ||
import { assert } from '@ember/debug'; | ||
import { CapturedArguments } from '@glimmer/interfaces'; | ||
import { createComputeRef, valueForRef } from '@glimmer/reference'; | ||
import { internalHelper } from './internal-helper'; | ||
|
||
export default internalHelper(({ positional, named }: CapturedArguments) => { | ||
assert( | ||
`[BUG] wrong number of positional arguments, expecting 1, got ${positional.length}`, | ||
positional.length === 1 | ||
); | ||
|
||
let nameOrValueRef = positional[0]; | ||
|
||
assert(`[BUG] expecting \`type\` named argument`, 'type' in named); | ||
assert(`[BUG] expecting \`loc\` named argument`, 'loc' in named); | ||
assert(`[BUG] expecting \`original\` named argument`, 'original' in named); | ||
|
||
let typeRef = named.type; | ||
let locRef = named.loc; | ||
let originalRef = named.original; | ||
|
||
// Bug: why do these fail? | ||
// assert('[BUG] expecting a string literal for the `type` argument', isConstRef(typeRef)); | ||
// assert('[BUG] expecting a string literal for the `loc` argument', isConstRef(locRef)); | ||
// assert('[BUG] expecting a string literal for the `original` argument', isConstRef(originalRef)); | ||
|
||
const type = valueForRef(typeRef); | ||
const loc = valueForRef(locRef); | ||
const original = valueForRef(originalRef); | ||
|
||
assert('[BUG] expecting a string literal for the `type` argument', typeof type === 'string'); | ||
assert('[BUG] expecting a string literal for the `loc` argument', typeof loc === 'string'); | ||
assert( | ||
'[BUG] expecting a string literal for the `original` argument', | ||
typeof original === 'string' | ||
); | ||
|
||
return createComputeRef(() => { | ||
let nameOrValue = valueForRef(nameOrValueRef); | ||
|
||
assert( | ||
`Passing a dynamic string to the \`(${type})\` keyword is disallowed. ` + | ||
`(You specified \`(${type} ${original})\` and \`${original}\` evaluated into "${nameOrValue}".) ` + | ||
`This ensures we can statically analyze the template and determine which ${type}s are used. ` + | ||
`If the ${type} name is always the same, use a string literal instead, i.e. \`(${type} "${nameOrValue}")\`. ` + | ||
`Otherwise, import the ${type}s into JavaScript and pass them to the ${type} keyword. ` + | ||
'See https://github.com/emberjs/rfcs/blob/master/text/0496-handlebars-strict-mode.md#4-no-dynamic-resolution for details. ' + | ||
loc, | ||
typeof nameOrValue !== 'string' | ||
); | ||
|
||
return nameOrValue; | ||
}); | ||
}); |
39 changes: 39 additions & 0 deletions
39
packages/@ember/-internals/glimmer/lib/helpers/-resolve.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/** | ||
@module ember | ||
*/ | ||
import { Owner } from '@ember/-internals/owner'; | ||
import { assert } from '@ember/debug'; | ||
import { DEBUG } from '@glimmer/env'; | ||
import { CapturedArguments } from '@glimmer/interfaces'; | ||
import { createConstRef, isConstRef, valueForRef } from '@glimmer/reference'; | ||
import { internalHelper } from './internal-helper'; | ||
|
||
export default internalHelper(({ positional }: CapturedArguments, owner: Owner | undefined) => { | ||
// why is this allowed to be undefined in the first place? | ||
assert('[BUG] missing owner', owner); | ||
|
||
assert( | ||
`[BUG] wrong number of positional arguments, expecting 1, got ${positional.length}`, | ||
positional.length === 1 | ||
); | ||
|
||
let fullNameRef = positional[0]; | ||
|
||
assert('[BUG] expecting a string literal as argument', isConstRef(fullNameRef)); | ||
|
||
let fullName = valueForRef(fullNameRef); | ||
|
||
assert('[BUG] expecting a string literal as argument', typeof fullName === 'string'); | ||
assert('[BUG] expecting a valid full name', fullName.split(':').length === 2); | ||
|
||
if (DEBUG) { | ||
let [type, name] = fullName.split(':'); | ||
|
||
assert( | ||
`Attempted to invoke \`(-resolve "${fullName}")\`, but ${name} was not a valid ${type} name.`, | ||
owner.hasRegistration(fullName) | ||
); | ||
} | ||
|
||
return createConstRef(owner.factoryFor(fullName)?.class, `(-resolve "${fullName}")`); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.