diff --git a/packages/@ember/-internals/glimmer/lib/helpers/-in-element-null-check.ts b/packages/@ember/-internals/glimmer/lib/helpers/-in-element-null-check.ts new file mode 100644 index 00000000000..26b5340443e --- /dev/null +++ b/packages/@ember/-internals/glimmer/lib/helpers/-in-element-null-check.ts @@ -0,0 +1,38 @@ +import { assert } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; +import { Helper, VMArguments } from '@glimmer/interfaces'; +import { VersionedPathReference } from '@glimmer/reference'; +import { Tag } from '@glimmer/validator'; + +let helper: Helper; + +if (DEBUG) { + class InElementNullCheckReference implements VersionedPathReference { + public tag: Tag; + + constructor(private inner: VersionedPathReference) { + this.tag = inner.tag; + } + + value(): unknown { + let value = this.inner.value(); + + assert( + 'You cannot pass a null or undefined destination element to in-element', + value !== null && value !== undefined + ); + + return value; + } + + get(key: string): VersionedPathReference { + return this.inner.get(key); + } + } + + helper = (args: VMArguments) => new InElementNullCheckReference(args.positional.at(0)); +} else { + helper = (args: VMArguments) => args.positional.at(0); +} + +export default helper; diff --git a/packages/@ember/-internals/glimmer/lib/resolver.ts b/packages/@ember/-internals/glimmer/lib/resolver.ts index 90fdedbad1e..3550593bd7c 100644 --- a/packages/@ember/-internals/glimmer/lib/resolver.ts +++ b/packages/@ember/-internals/glimmer/lib/resolver.ts @@ -30,6 +30,7 @@ import InternalComponentManager, { import { TemplateOnlyComponentDefinition } from './component-managers/template-only'; import { isClassHelper, isHelperFactory } from './helper'; import { default as componentAssertionHelper } from './helpers/-assert-implicit-component-helper-argument'; +import { default as inElementNullCheckHelper } from './helpers/-in-element-null-check'; import { default as normalizeClassHelper } from './helpers/-normalize-class'; import { default as trackArray } from './helpers/-track-array'; import { default as action } from './helpers/action'; @@ -262,6 +263,7 @@ const BUILTINS_HELPERS: IBuiltInHelpers = { '-mount': mountHelper, '-outlet': outletHelper, '-assert-implicit-component-helper-argument': componentAssertionHelper, + '-in-el-null': inElementNullCheckHelper, }; interface IBuiltInModifiers { diff --git a/packages/@ember/-internals/glimmer/tests/integration/syntax/public-in-element-test.js b/packages/@ember/-internals/glimmer/tests/integration/syntax/public-in-element-test.js index 9d653c287e7..7a9a6db03be 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/syntax/public-in-element-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/syntax/public-in-element-test.js @@ -119,6 +119,42 @@ moduleFor( }, /Can only pass null to insertBefore in in-element, received:/); } + ['@feature(EMBER_GLIMMER_IN_ELEMENT) does not allow null as a destination element']() { + let someElement = null; + + expectAssertion(() => { + this.render( + strip` + {{#in-element someElement}} + {{text}} + {{/in-element}} + `, + { + someElement, + text: 'Whoop!', + } + ); + }, /You cannot pass a null or undefined destination element to in-element/); + } + + ['@feature(EMBER_GLIMMER_IN_ELEMENT) does not undefined as a destination element']() { + let someElement = undefined; + + expectAssertion(() => { + this.render( + strip` + {{#in-element someElement}} + {{text}} + {{/in-element}} + `, + { + someElement, + text: 'Whoop!', + } + ); + }, /You cannot pass a null or undefined destination element to in-element/); + } + ['@feature(EMBER_GLIMMER_IN_ELEMENT) components are cleaned up properly'](assert) { let hooks = []; diff --git a/packages/ember-template-compiler/lib/plugins/transform-in-element.ts b/packages/ember-template-compiler/lib/plugins/transform-in-element.ts index 5c17597ccb6..9a84aed7b40 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-in-element.ts +++ b/packages/ember-template-compiler/lib/plugins/transform-in-element.ts @@ -55,6 +55,15 @@ export default function transformInElement(env: ASTPluginEnvironment): ASTPlugin if (node.path.original === 'in-element') { if (EMBER_GLIMMER_IN_ELEMENT) { + let originalValue = node.params[0]; + + if (originalValue) { + let subExpr = b.sexpr('-in-el-null', [originalValue]); + + node.params.shift(); + node.params.unshift(subExpr); + } + node.hash.pairs.forEach(pair => { if (pair.key === 'insertBefore') { assert(