ember-source
Version:
A JavaScript framework for creating ambitious web applications
566 lines (546 loc) • 23.7 kB
JavaScript
import { debugToString as debugToString$1, castToBrowser } from '../util/index.js';
import { associateDestroyableChild, registerDestructor } from '../destroyable/index.js';
import { createComputeRef, createConstRef, UNDEFINED_REFERENCE, valueForRef } from '../reference/index.js';
import { untrack, track, createUpdatableTag } from '../validator/index.js';
import { Op, InternalComponentCapabilities } from '../vm/index.js';
import { isDevelopingApp } from '@embroider/macros';
const CUSTOM_TAG_FOR = new WeakMap();
function getCustomTagFor(obj) {
return CUSTOM_TAG_FOR.get(obj);
}
function setCustomTagFor(obj, customTagFn) {
CUSTOM_TAG_FOR.set(obj, customTagFn);
}
function convertToInt(prop) {
if ("symbol" == typeof prop) return null;
const num = Number(prop);
return isNaN(num) ? null : num % 1 == 0 ? num : null;
}
class NamedArgsProxy {
constructor(named) {
this.named = named;
}
get(_target, prop) {
const ref = this.named[prop];
if (void 0 !== ref) return valueForRef(ref);
}
has(_target, prop) {
return prop in this.named;
}
ownKeys() {
return Object.keys(this.named);
}
isExtensible() {
return !1;
}
getOwnPropertyDescriptor(_target, prop) {
if (isDevelopingApp() && !(prop in this.named)) throw new Error(`args proxies do not have real property descriptors, so you should never need to call getOwnPropertyDescriptor yourself. This code exists for enumerability, such as in for-in loops and Object.keys(). Attempted to get the descriptor for \`${String(prop)}\``);
return {
enumerable: !0,
configurable: !0
};
}
}
class PositionalArgsProxy {
constructor(positional) {
this.positional = positional;
}
get(target, prop) {
let {
positional: positional
} = this;
if ("length" === prop) return positional.length;
const parsed = convertToInt(prop);
return null !== parsed && parsed < positional.length ? valueForRef(positional[parsed]) : target[prop];
}
isExtensible() {
return !1;
}
has(_target, prop) {
const parsed = convertToInt(prop);
return null !== parsed && parsed < this.positional.length;
}
}
const argsProxyFor = (capturedArgs, type) => {
const {
named: named,
positional: positional
} = capturedArgs,
namedHandler = new NamedArgsProxy(named),
positionalHandler = new PositionalArgsProxy(positional),
namedTarget = Object.create(null);
if (isDevelopingApp()) {
const setHandler = function (_target, prop) {
throw new Error(`You attempted to set ${String(prop)} on the arguments of a component, helper, or modifier. Arguments are immutable and cannot be updated directly; they always represent the values that are passed down. If you want to set default values, you should use a getter and local tracked state instead.`);
},
forInDebugHandler = () => {
throw new Error(`Object.keys() was called on the positional arguments array for a ${type}, which is not supported. This function is a low-level function that should not need to be called for positional argument arrays. You may be attempting to iterate over the array using for...in instead of for...of.`);
};
namedHandler.set = setHandler, positionalHandler.set = setHandler, positionalHandler.ownKeys = forInDebugHandler;
}
const namedProxy = new Proxy(namedTarget, namedHandler),
positionalProxy = new Proxy([], positionalHandler);
return setCustomTagFor(namedProxy, (_obj, key) => function (namedArgs, key) {
return track(() => {
key in namedArgs && valueForRef(namedArgs[key]);
});
}(named, key)), setCustomTagFor(positionalProxy, (_obj, key) => function (positionalArgs, key) {
return track(() => {
"[]" === key &&
// consume all of the tags in the positional array
positionalArgs.forEach(valueForRef);
const parsed = convertToInt(key);
null !== parsed && parsed < positionalArgs.length &&
// consume the tag of the referenced index
valueForRef(positionalArgs[parsed]);
});
}(positional, key)), {
named: namedProxy,
positional: positionalProxy
};
};
/* This file is generated by build/debug.js */
new Array(Op.Size).fill(null), new Array(Op.Size).fill(null);
const FROM_CAPABILITIES = isDevelopingApp() ? new WeakSet() : void 0;
function buildCapabilities(capabilities) {
return isDevelopingApp() && (FROM_CAPABILITIES.add(capabilities), Object.freeze(capabilities)), capabilities;
}
const EMPTY = InternalComponentCapabilities.Empty;
/**
* Converts a ComponentCapabilities object into a 32-bit integer representation.
*/
function capabilityFlagsFrom(capabilities) {
return EMPTY | capability(capabilities, "dynamicLayout") | capability(capabilities, "dynamicTag") | capability(capabilities, "prepareArgs") | capability(capabilities, "createArgs") | capability(capabilities, "attributeHook") | capability(capabilities, "elementHook") | capability(capabilities, "dynamicScope") | capability(capabilities, "createCaller") | capability(capabilities, "updateHook") | capability(capabilities, "createInstance") | capability(capabilities, "wrapped") | capability(capabilities, "willDestroy") | capability(capabilities, "hasSubOwner");
}
function capability(capabilities, capability) {
return capabilities[capability] ? InternalComponentCapabilities[capability] : EMPTY;
}
function managerHasCapability(_manager, capabilities, capability) {
return !!(capabilities & capability);
}
function hasCapability(capabilities, capability) {
return !!(capabilities & capability);
}
function helperCapabilities(managerAPI, options = {}) {
if (isDevelopingApp() && "3.23" !== managerAPI) throw new Error("Invalid helper manager compatibility specified");
if (isDevelopingApp() && (!options.hasValue && !options.hasScheduledEffect || options.hasValue && options.hasScheduledEffect)) throw new Error("You must pass either the `hasValue` OR the `hasScheduledEffect` capability when defining a helper manager. Passing neither, or both, is not permitted.");
if (isDevelopingApp() && options.hasScheduledEffect) throw new Error("The `hasScheduledEffect` capability has not yet been implemented for helper managers. Please pass `hasValue` instead");
return buildCapabilities({
hasValue: Boolean(options.hasValue),
hasDestroyable: Boolean(options.hasDestroyable),
hasScheduledEffect: Boolean(options.hasScheduledEffect)
});
}
////////////
function hasValue(manager) {
return manager.capabilities.hasValue;
}
function hasDestroyable(manager) {
return manager.capabilities.hasDestroyable;
}
////////////
class CustomHelperManager {
constructor(factory) {
this.factory = factory;
}
helperManagerDelegates = new WeakMap();
undefinedDelegate = null;
getDelegateForOwner(owner) {
let delegate = this.helperManagerDelegates.get(owner);
if (void 0 === delegate) {
let {
factory: factory
} = this;
if (delegate = factory(owner), isDevelopingApp() && !FROM_CAPABILITIES.has(delegate.capabilities))
// TODO: This error message should make sense in both Ember and Glimmer https://github.com/glimmerjs/glimmer-vm/issues/1200
throw new Error(`Custom helper managers must have a \`capabilities\` property that is the result of calling the \`capabilities('3.23')\` (imported via \`import { capabilities } from '@ember/helper';\`). Received: \`${JSON.stringify(delegate.capabilities)}\` for: \`${delegate}\``);
this.helperManagerDelegates.set(owner, delegate);
}
return delegate;
}
getDelegateFor(owner) {
if (void 0 === owner) {
let {
undefinedDelegate: undefinedDelegate
} = this;
if (null === undefinedDelegate) {
let {
factory: factory
} = this;
this.undefinedDelegate = undefinedDelegate = factory(void 0);
}
return undefinedDelegate;
}
return this.getDelegateForOwner(owner);
}
getHelper(definition) {
return (capturedArgs, owner) => {
let manager = this.getDelegateFor(owner);
const args = argsProxyFor(capturedArgs, "helper"),
bucket = manager.createHelper(definition, args);
if (hasValue(manager)) {
let cache = createComputeRef(() => manager.getValue(bucket), null, isDevelopingApp() && manager.getDebugName && manager.getDebugName(definition));
return hasDestroyable(manager) && associateDestroyableChild(cache, manager.getDestroyable(bucket)), cache;
}
if (hasDestroyable(manager)) {
let ref = createConstRef(void 0, isDevelopingApp() && (manager.getDebugName?.(definition) ?? "unknown helper"));
return associateDestroyableChild(ref, manager.getDestroyable(bucket)), ref;
}
return UNDEFINED_REFERENCE;
};
}
}
class FunctionHelperManager {
capabilities = buildCapabilities({
hasValue: !0,
hasDestroyable: !1,
hasScheduledEffect: !1
});
createHelper(fn, args) {
return {
fn: fn,
args: args
};
}
getValue({
fn: fn,
args: args
}) {
return Object.keys(args.named).length > 0 ? fn(...args.positional, args.named) : fn(...args.positional);
}
getDebugName(fn) {
return fn.name ? `(helper function ${fn.name})` : "(anonymous helper function)";
}
}
const COMPONENT_MANAGERS = new WeakMap(),
MODIFIER_MANAGERS = new WeakMap(),
HELPER_MANAGERS = new WeakMap(),
getPrototypeOf$1 = Object.getPrototypeOf;
function setManager(map, manager, obj) {
if (isDevelopingApp() && ("object" != typeof obj || null === obj) && "function" != typeof obj) throw new Error(`Attempted to set a manager on a non-object value. Managers can only be associated with objects or functions. Value was ${debugToString$1(obj)}`);
if (isDevelopingApp() && map.has(obj)) throw new Error(`Attempted to set the same type of manager multiple times on a value. You can only associate one manager of each type with a given value. Value was ${debugToString$1(obj)}`);
return map.set(obj, manager), obj;
}
function getManager(map, obj) {
let pointer = obj;
for (; null != pointer;) {
const manager = map.get(pointer);
if (void 0 !== manager) return manager;
pointer = getPrototypeOf$1(pointer);
}
}
///////////
function setInternalModifierManager(manager, definition) {
return setManager(MODIFIER_MANAGERS, manager, definition);
}
function getInternalModifierManager(definition, isOptional) {
if (isDevelopingApp() && "function" != typeof definition && ("object" != typeof definition || null === definition)) throw new Error(`Attempted to use a value as a modifier, but it was not an object or function. Modifier definitions must be objects or functions with an associated modifier manager. The value was: ${definition}`);
const manager = getManager(MODIFIER_MANAGERS, definition);
if (void 0 === manager) {
if (!0 === isOptional) return null;
if (isDevelopingApp()) throw new Error(`Attempted to load a modifier, but there wasn't a modifier manager associated with the definition. The definition was: ${debugToString$1(definition)}`);
}
return manager;
}
function setInternalHelperManager(manager, definition) {
return setManager(HELPER_MANAGERS, manager, definition);
}
const DEFAULT_MANAGER = new CustomHelperManager(() => new FunctionHelperManager());
function getInternalHelperManager(definition, isOptional) {
if (isDevelopingApp() && "function" != typeof definition && ("object" != typeof definition || null === definition)) throw new Error(`Attempted to use a value as a helper, but it was not an object or function. Helper definitions must be objects or functions with an associated helper manager. The value was: ${definition}`);
let manager = getManager(HELPER_MANAGERS, definition);
// Functions are special-cased because functions are defined
// as the "default" helper, per: https://github.com/emberjs/rfcs/pull/756
if (void 0 === manager && "function" == typeof definition && (manager = DEFAULT_MANAGER), manager) return manager;
if (!0 === isOptional) return null;
if (isDevelopingApp()) throw new Error(`Attempted to load a helper, but there wasn't a helper manager associated with the definition. The definition was: ${debugToString$1(definition)}`);
return null;
}
function setInternalComponentManager(factory, obj) {
return setManager(COMPONENT_MANAGERS, factory, obj);
}
function getInternalComponentManager(definition, isOptional) {
if (isDevelopingApp() && "function" != typeof definition && ("object" != typeof definition || null === definition)) throw new Error(`Attempted to use a value as a component, but it was not an object or function. Component definitions must be objects or functions with an associated component manager. The value was: ${definition}`);
const manager = getManager(COMPONENT_MANAGERS, definition);
if (void 0 === manager) {
if (!0 === isOptional) return null;
if (isDevelopingApp()) throw new Error(`Attempted to load a component, but there wasn't a component manager associated with the definition. The definition was: ${debugToString$1(definition)}`);
}
return manager;
}
///////////
function hasInternalComponentManager(definition) {
return void 0 !== getManager(COMPONENT_MANAGERS, definition);
}
function hasInternalHelperManager(definition) {
return function (definition) {
return "function" == typeof definition;
}(definition) || void 0 !== getManager(HELPER_MANAGERS, definition);
}
function hasInternalModifierManager(definition) {
return void 0 !== getManager(MODIFIER_MANAGERS, definition);
}
const CAPABILITIES = {
dynamicLayout: !1,
dynamicTag: !1,
prepareArgs: !1,
createArgs: !0,
attributeHook: !1,
elementHook: !1,
createCaller: !1,
dynamicScope: !0,
updateHook: !0,
createInstance: !0,
wrapped: !1,
willDestroy: !1,
hasSubOwner: !1
};
function componentCapabilities(managerAPI, options = {}) {
if (isDevelopingApp() && "3.13" !== managerAPI) throw new Error("Invalid component manager compatibility specified");
let updateHook = Boolean(options.updateHook);
return buildCapabilities({
asyncLifeCycleCallbacks: Boolean(options.asyncLifecycleCallbacks),
destructor: Boolean(options.destructor),
updateHook: updateHook
});
}
function hasAsyncLifeCycleCallbacks(delegate) {
return delegate.capabilities.asyncLifeCycleCallbacks;
}
function hasUpdateHook(delegate) {
return delegate.capabilities.updateHook;
}
/**
The CustomComponentManager allows addons to provide custom component
implementations that integrate seamlessly into Ember. This is accomplished
through a delegate, registered with the custom component manager, which
implements a set of hooks that determine component behavior.
To create a custom component manager, instantiate a new CustomComponentManager
class and pass the delegate as the first argument:
```js
let manager = new CustomComponentManager({
// ...delegate implementation...
});
```
## Delegate Hooks
Throughout the lifecycle of a component, the component manager will invoke
delegate hooks that are responsible for surfacing those lifecycle changes to
the end developer.
* `create()` - invoked when a new instance of a component should be created
* `update()` - invoked when the arguments passed to a component change
* `getContext()` - returns the object that should be
*/
class CustomComponentManager {
componentManagerDelegates = new WeakMap();
constructor(factory) {
this.factory = factory;
}
getDelegateFor(owner) {
let {
componentManagerDelegates: componentManagerDelegates
} = this,
delegate = componentManagerDelegates.get(owner);
if (void 0 === delegate) {
let {
factory: factory
} = this;
if (delegate = factory(owner), isDevelopingApp() && !FROM_CAPABILITIES.has(delegate.capabilities))
// TODO: This error message should make sense in both Ember and Glimmer https://github.com/glimmerjs/glimmer-vm/issues/1200
throw new Error(`Custom component managers must have a \`capabilities\` property that is the result of calling the \`capabilities('3.13')\` (imported via \`import { capabilities } from '@ember/component';\`). Received: \`${JSON.stringify(delegate.capabilities)}\` for: \`${delegate}\``);
componentManagerDelegates.set(owner, delegate);
}
return delegate;
}
create(owner, definition, vmArgs) {
let delegate = this.getDelegateFor(owner),
args = argsProxyFor(vmArgs.capture(), "component"),
component = delegate.createComponent(definition, args);
return new CustomComponentState(component, delegate, args);
}
getDebugName(definition) {
return "function" == typeof definition ? definition.name : definition.toString();
}
update(bucket) {
let {
delegate: delegate
} = bucket;
if (hasUpdateHook(delegate)) {
let {
component: component,
args: args
} = bucket;
delegate.updateComponent(component, args);
}
}
didCreate({
component: component,
delegate: delegate
}) {
hasAsyncLifeCycleCallbacks(delegate) && delegate.didCreateComponent(component);
}
didUpdate({
component: component,
delegate: delegate
}) {
(function (delegate) {
return hasAsyncLifeCycleCallbacks(delegate) && hasUpdateHook(delegate);
})(delegate) && delegate.didUpdateComponent(component);
}
didRenderLayout() {}
didUpdateLayout() {}
getSelf({
component: component,
delegate: delegate
}) {
return createConstRef(delegate.getContext(component), "this");
}
getDestroyable(bucket) {
const {
delegate: delegate
} = bucket;
if (function (delegate) {
return delegate.capabilities.destructor;
}(delegate)) {
const {
component: component
} = bucket;
return registerDestructor(bucket, () => delegate.destroyComponent(component)), bucket;
}
return null;
}
getCapabilities() {
return CAPABILITIES;
}
}
/**
* Stores internal state about a component instance after it's been created.
*/
class CustomComponentState {
constructor(component, delegate, args) {
this.component = component, this.delegate = delegate, this.args = args;
}
}
function modifierCapabilities(managerAPI, optionalFeatures = {}) {
if (isDevelopingApp() && "3.22" !== managerAPI) throw new Error("Invalid modifier manager compatibility specified");
return buildCapabilities({
disableAutoTracking: Boolean(optionalFeatures.disableAutoTracking)
});
}
/**
The CustomModifierManager allows addons to provide custom modifier
implementations that integrate seamlessly into Ember. This is accomplished
through a delegate, registered with the custom modifier manager, which
implements a set of hooks that determine modifier behavior.
To create a custom modifier manager, instantiate a new CustomModifierManager
class and pass the delegate as the first argument:
```js
let manager = new CustomModifierManager({
// ...delegate implementation...
});
```
## Delegate Hooks
Throughout the lifecycle of a modifier, the modifier manager will invoke
delegate hooks that are responsible for surfacing those lifecycle changes to
the end developer.
* `createModifier()` - invoked when a new instance of a modifier should be created
* `installModifier()` - invoked when the modifier is installed on the element
* `updateModifier()` - invoked when the arguments passed to a modifier change
* `destroyModifier()` - invoked when the modifier is about to be destroyed
*/
class CustomModifierManager {
componentManagerDelegates = new WeakMap();
constructor(factory) {
this.factory = factory;
}
getDelegateFor(owner) {
let {
componentManagerDelegates: componentManagerDelegates
} = this,
delegate = componentManagerDelegates.get(owner);
if (void 0 === delegate) {
let {
factory: factory
} = this;
if (delegate = factory(owner), isDevelopingApp() && !FROM_CAPABILITIES.has(delegate.capabilities))
// TODO: This error message should make sense in both Ember and Glimmer https://github.com/glimmerjs/glimmer-vm/issues/1200
throw new Error(`Custom modifier managers must have a \`capabilities\` property that is the result of calling the \`capabilities('3.22')\` (imported via \`import { capabilities } from '@ember/modifier';\`). Received: \`${JSON.stringify(delegate.capabilities)}\` for: \`${delegate}\``);
componentManagerDelegates.set(owner, delegate);
}
return delegate;
}
create(owner, element, definition, capturedArgs) {
let state,
delegate = this.getDelegateFor(owner),
args = argsProxyFor(capturedArgs, "modifier"),
instance = delegate.createModifier(definition, args);
return state = {
tag: createUpdatableTag(),
element: element,
delegate: delegate,
args: args,
modifier: instance
}, registerDestructor(state, () => delegate.destroyModifier(instance, args)), state;
}
getDebugName(definition) {
return "function" == typeof definition ? definition.name || definition.toString() : "<unknown>";
}
getDebugInstance({
modifier: modifier
}) {
return modifier;
}
getTag({
tag: tag
}) {
return tag;
}
install({
element: element,
args: args,
modifier: modifier,
delegate: delegate
}) {
let {
capabilities: capabilities
} = delegate;
!0 === capabilities.disableAutoTracking ? untrack(() => delegate.installModifier(modifier, castToBrowser(element, "ELEMENT"), args)) : delegate.installModifier(modifier, castToBrowser(element, "ELEMENT"), args);
}
update({
args: args,
modifier: modifier,
delegate: delegate
}) {
let {
capabilities: capabilities
} = delegate;
!0 === capabilities.disableAutoTracking ? untrack(() => delegate.updateModifier(modifier, args)) : delegate.updateModifier(modifier, args);
}
getDestroyable(state) {
return state;
}
}
function setComponentManager(factory, obj) {
return setInternalComponentManager(new CustomComponentManager(factory), obj);
}
function setModifierManager(factory, obj) {
return setInternalModifierManager(new CustomModifierManager(factory), obj);
}
function setHelperManager(factory, obj) {
return setInternalHelperManager(new CustomHelperManager(factory), obj);
}
const TEMPLATES = new WeakMap(),
getPrototypeOf = Object.getPrototypeOf;
function setComponentTemplate(factory, obj) {
if (isDevelopingApp() && (null === obj || "object" != typeof obj && "function" != typeof obj)) throw new Error(`Cannot call \`setComponentTemplate\` on \`${debugToString$1(obj)}\``);
if (isDevelopingApp() && TEMPLATES.has(obj)) throw new Error(`Cannot call \`setComponentTemplate\` multiple times on the same class (\`${debugToString$1(obj)}\`)`);
return TEMPLATES.set(obj, factory), obj;
}
function getComponentTemplate(obj) {
let pointer = obj;
for (; null !== pointer;) {
let template = TEMPLATES.get(pointer);
if (void 0 !== template) return template;
pointer = getPrototypeOf(pointer);
}
}
export { CustomComponentManager, CustomHelperManager, CustomModifierManager, capabilityFlagsFrom, componentCapabilities, getComponentTemplate, getCustomTagFor, getInternalComponentManager, getInternalHelperManager, getInternalModifierManager, hasCapability, hasDestroyable, hasInternalComponentManager, hasInternalHelperManager, hasInternalModifierManager, hasValue, helperCapabilities, managerHasCapability, modifierCapabilities, setComponentManager, setComponentTemplate, setCustomTagFor, setHelperManager, setInternalComponentManager, setInternalHelperManager, setInternalModifierManager, setModifierManager };