diff --git a/addon/index.js b/addon/index.js index 4cc8c88..f11d828 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,14 +1,14 @@ // eslint-disable-next-line no-unused-vars import EmberCustomElement, { CURRENT_CUSTOM_ELEMENT, INITIALIZERS } from './lib/custom-element'; -import { +import { getCustomElements, addCustomElement, getTargetClass, isSupportedClass, isComponent, - isGlimmerComponent, isApp } from './lib/common'; +import { isGlimmerComponent } from './lib/glimmer-compat'; import { getOwner, setOwner } from '@ember/application'; export { default as EmberOutletElement } from './lib/outlet-element'; @@ -136,7 +136,7 @@ export function customElement() { /** * Gets the custom element node for a component or application instance. - * + * * @param {*} entity * @returns {HTMLElement|null} */ @@ -158,10 +158,10 @@ export function getCustomElement(entity) { * Sets up a property or method to be interfaced via a custom element. * When used, said property will be accessible on a custom element node * and will retain the same binding. - * - * @param {*} target - * @param {String} name - * @param {Object} descriptor + * + * @param {*} target + * @param {String} name + * @param {Object} descriptor */ export function forwarded(target, name, descriptor) { if (typeof target !== 'object') @@ -231,7 +231,7 @@ function constructInstanceForCustomElement() { const customElement = CURRENT_CUSTOM_ELEMENT.element; // There should always be a custom element when the component is // invoked by one, but if a decorated class isn't invoked by a custom - // element, it shouldn't fail when being constructed. + // element, it shouldn't fail when being constructed. if (!customElement) return; CUSTOM_ELEMENTS.set(this, customElement); CURRENT_CUSTOM_ELEMENT.element = null; @@ -263,4 +263,4 @@ function constructInstanceForCustomElement() { } } } -} \ No newline at end of file +} diff --git a/addon/lib/common.js b/addon/lib/common.js index 8223f83..0b2ccfe 100644 --- a/addon/lib/common.js +++ b/addon/lib/common.js @@ -1,6 +1,7 @@ import Application from '@ember/application'; import Route from '@ember/routing/route'; import EmberComponent from '@ember/component'; +import { isGlimmerComponent } from './glimmer-compat'; const EMBER_WEB_COMPONENTS_CUSTOM_ELEMENTS = Symbol('EMBER_WEB_COMPONENTS_CUSTOM_ELEMENTS'); const EMBER_WEB_COMPONENTS_TARGET_CLASS = Symbol('EMBER_WEB_COMPONENTS_TARGET_CLASS'); @@ -84,43 +85,6 @@ export function isComponent(targetClass) { return isAncestorOf(targetClass, EmberComponent); } -/** - * Indicates whether a class is a Glimmer component. - * This function makes a best guess rather than checking - * for a matching import because we can't guarantee that - * the consuming app will be using Glimmer components. - * - * This is acceptable because these checker functions are - * only currently used to throw an error when the developer - * tries to use the decorator on something they shouldn't. - * - * @param {Class} targetClass - * @private - * @returns {Boolean} - */ -export function isGlimmerComponent(targetClass) { - const flattenedPrototypeKeys = new Set(); - - if (!targetClass) return false; - - let ancestor = targetClass; - let hasGlimmerDebugComponentAncestor = false; - - while (ancestor) { - if (ancestor.name === 'GlimmerDebugComponent') hasGlimmerDebugComponentAncestor = true; - ancestor = Object.getPrototypeOf(ancestor); - if (!ancestor || !ancestor.prototype) continue; - for (const key in Object.getOwnPropertyDescriptors(ancestor.prototype)) { - flattenedPrototypeKeys.add(key); - } - } - - return hasGlimmerDebugComponentAncestor && - flattenedPrototypeKeys.has('bounds') && - flattenedPrototypeKeys.has('element') && - flattenedPrototypeKeys.has('debugName'); -} - function isAncestorOf(a, b) { if (!a) return false; @@ -132,4 +96,4 @@ function isAncestorOf(a, b) { } return false; -} \ No newline at end of file +} diff --git a/addon/lib/glimmer-compat.js b/addon/lib/glimmer-compat.js new file mode 100644 index 0000000..ed0b719 --- /dev/null +++ b/addon/lib/glimmer-compat.js @@ -0,0 +1,31 @@ +/* global require */ + +// Import through `require` in case it is not a dependency +const GlimmerComponentModule = require('@glimmer/component'); +const GlimmerComponent = GlimmerComponentModule && GlimmerComponentModule.default; + +/** + * Indicates whether a class is a Glimmer component. + * + * @param {Class} targetClass + * @returns {Boolean} + * @private + */ +export function isGlimmerComponent(targetClass) { + if (!GlimmerComponent) { + return false; + } + + let ancestor = targetClass; + + while (ancestor) { + if (ancestor === GlimmerComponent) { + return true; + } + + ancestor = Object.getPrototypeOf(ancestor); + } + + return false; +} +