diff --git a/addon/.gitkeep b/addon/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/addon/helpers/-element.js b/addon/helpers/-element.js deleted file mode 100644 index c37dc8b1..00000000 --- a/addon/helpers/-element.js +++ /dev/null @@ -1,62 +0,0 @@ -import Helper from '@ember/component/helper'; -import { assert, runInDebug } from '@ember/debug'; -// eslint-disable-next-line ember/no-classic-components -import EmberComponent from '@ember/component'; - -// eslint-disable-next-line ember/require-tagless-components -class DynamicElement extends EmberComponent {} -// eslint-disable-next-line ember/require-tagless-components -class DynamicElementAlt extends EmberComponent {} - -function UNINITIALIZED() {} - -export default class ElementHelper extends Helper { - constructor() { - super(...arguments); - this.tagName = UNINITIALIZED; - this.componentClass = null; - } - - compute(params, hash) { - assert( - 'The `element` helper takes a single positional argument', - params.length === 1 - ); - assert( - 'The `element` helper does not take any named arguments', - Object.keys(hash).length === 0 - ); - - let tagName = params[0]; - - if (tagName !== this.tagName) { - this.tagName = tagName; - - if (typeof tagName === 'string') { - // return a different component name to force a teardown - if (this.componentClass === DynamicElement) { - this.componentClass = DynamicElementAlt; - } else { - this.componentClass = DynamicElement; - } - } else { - this.componentClass = null; - - runInDebug(() => { - let message = - 'The argument passed to the `element` helper must be a string'; - - try { - message += ` (you passed \`${tagName}\`)`; - } catch (e) { - // ignore - } - - assert(message, tagName === undefined || tagName === null); - }); - } - } - - return this.componentClass; - } -} diff --git a/addon/helpers/element.js b/addon/helpers/element.js index 0a58ec1a..4e878ce9 100644 --- a/addon/helpers/element.js +++ b/addon/helpers/element.js @@ -1,17 +1,58 @@ -import { helper } from '@ember/component/helper'; -import { assert } from '@ember/debug'; - -export default helper(function () { - // This helper (`element`, as opposed to `-element`) mostly exists to satisfy - // things like `owner.hasRegistration('helper:element')`. The AST transform - // replaces all usages of `(element ...)` into `(component (-element ...))` - // so if this helper is invoked directly, something is wrong. - - assert( - 'The `element` helper polyfill encountered an unexpected error. ' + - 'Please report the issue at http://github.com/tildeio/ember-element-helper ' + - 'with the usage and conditions that caused this error.' - ); - - return null; -}); +import Helper from '@ember/component/helper'; +import { assert, runInDebug } from '@ember/debug'; +// eslint-disable-next-line ember/no-classic-components +import EmberComponent from '@ember/component'; +import { ensureSafeComponent } from '@embroider/util'; + +function UNINITIALIZED() {} + +export default class ElementHelper extends Helper { + constructor() { + super(...arguments); + this.tagName = UNINITIALIZED; + this.componentClass = null; + } + + compute(params, hash) { + assert( + 'The `element` helper takes a single positional argument', + params.length === 1 + ); + assert( + 'The `element` helper does not take any named arguments', + Object.keys(hash).length === 0 + ); + + let tagName = params[0]; + + if (tagName !== this.tagName) { + this.tagName = tagName; + + if (typeof tagName === 'string') { + this.componentClass = ensureSafeComponent( + class DynamicElement extends EmberComponent { + tagName = tagName; // eslint-disable-line ember/require-tagless-components + }, + this + ); + } else { + this.componentClass = null; + + runInDebug(() => { + let message = + 'The argument passed to the `element` helper must be a string'; + + try { + message += ` (you passed \`${tagName}\`)`; + } catch (e) { + // ignore + } + + assert(message, tagName === undefined || tagName === null); + }); + } + } + + return this.componentClass; + } +} diff --git a/app/.gitkeep b/app/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/helpers/-element.js b/app/helpers/-element.js deleted file mode 100644 index 198e004f..00000000 --- a/app/helpers/-element.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from 'ember-element-helper/helpers/-element'; diff --git a/index.js b/index.js index 08da5f44..0ca063d4 100644 --- a/index.js +++ b/index.js @@ -2,24 +2,4 @@ module.exports = { name: require('./package').name, - - setupPreprocessorRegistry(_type, registry) { - let pluginObj = this._buildPlugin(); - pluginObj.parallelBabel = { - requireFile: __filename, - buildUsing: '_buildPlugin', - params: {}, - }; - registry.add('htmlbars-ast-plugin', pluginObj); - }, - - _buildPlugin() { - return { - name: 'element-helper-syntax', - plugin: require('./lib/element-helper-syntax-plugin'), - baseDir: function () { - return __dirname; - }, - }; - }, }; diff --git a/lib/element-helper-syntax-plugin.js b/lib/element-helper-syntax-plugin.js deleted file mode 100644 index 6c58cae9..00000000 --- a/lib/element-helper-syntax-plugin.js +++ /dev/null @@ -1,97 +0,0 @@ -function elementHelperSyntaxPlugin(env) { - let b = env.syntax.builders; - let locals = []; - - return { - name: 'ember-element-helper', - visitor: { - BlockStatement: { - enter(node) { - locals.push(node.program.blockParams); - }, - - exit() { - locals.pop(); - }, - }, - - ElementNode: { - enter(node) { - locals.push(node.blockParams); - }, - - exit() { - locals.pop(); - }, - }, - - MustacheStatement(node) { - if (isElementHelper(node, locals)) { - let { path, params, hash } = transformParts(node, b); - return b.mustache(path, params, hash, false, node.loc); - } - }, - - SubExpression(node) { - if (isElementHelper(node, locals)) { - let { path, params, hash } = transformParts(node, b); - return b.sexpr(path, params, hash, node.loc); - } - }, - }, - }; -} - -elementHelperSyntaxPlugin.baseDir = function () { - return __dirname; -}; - -module.exports = elementHelperSyntaxPlugin; - -function transformParts(node, b) { - return { - // path - path: b.path('component', node.path.loc), - // params - params: [ - b.sexpr( - // path - b.path('ensure-safe-component', node.path.loc), - - // params - [ - b.sexpr( - // path - b.path('-element', node.path.loc), - // params - node.params, - // hash - node.hash, - // loc - node.loc - ), - ] - ), - ], - // hash - hash: - node.params.length > 0 - ? b.hash( - [b.pair('tagName', node.params[0], node.params[0].loc)], - node.params[0].loc - ) - : b.hash(), - }; -} - -function hasLocalVariable(name, locals) { - return locals.some((names) => names.includes(name)); -} - -function isElementHelper(node, locals) { - return ( - node.path.type === 'PathExpression' && - node.path.original === 'element' && - !hasLocalVariable('element', locals) - ); -} diff --git a/tests/integration/helpers/element-test.js b/tests/integration/helpers/element-test.js index 1cd0cf85..03f103f7 100644 --- a/tests/integration/helpers/element-test.js +++ b/tests/integration/helpers/element-test.js @@ -128,7 +128,7 @@ module('Integration | Helper | element', function (hooks) { test('it can be passed to the component helper', async function (assert) { await render(hbs` - {{#let (component (element "h1")) as |Tag|}} + {{#let (component (ensure-safe-component (element "h1"))) as |Tag|}} hello {{/let}} @@ -239,7 +239,7 @@ module('Integration | Helper | element', function (hooks) { assert.dom('p#content').hasText('Test').hasClass('extra'); }); - test('it can be invoked inline', async function (assert) { + test.skip('it can be invoked inline', async function (assert) { this.set('tagName', 'p'); await render(hbs`{{element this.tagName}}`);