diff --git a/packages/@ember/-internals/metal/lib/cached.ts b/packages/@ember/-internals/metal/lib/cached.ts index 8e6bdfb4d4e..d4867140bdc 100644 --- a/packages/@ember/-internals/metal/lib/cached.ts +++ b/packages/@ember/-internals/metal/lib/cached.ts @@ -4,6 +4,8 @@ import { DEBUG } from '@glimmer/env'; import { createCache, getValue } from '@glimmer/validator'; +const CacheMap = new WeakMap(); + /** * @decorator * @@ -84,7 +86,7 @@ import { createCache, getValue } from '@glimmer/validator'; the subsequent cache invalidations of the `@cached` properties who were using this `trackedProp`. - Remember that setting tracked data should only be done during initialization, + Remember that setting tracked data should only be done during initialization, or as the result of a user action. Setting tracked data during render (such as in a getter), is not supported. @@ -111,6 +113,8 @@ export const cached: PropertyDecorator = (...args: any[]) => { throwCachedGetterOnlyError(key); } + CacheMap.set(target, [...CacheMap.get(target)||[], key]); + const caches = new WeakMap(); const getter = descriptor.get; @@ -144,3 +148,8 @@ function throwCachedInvalidArgsError(args: unknown[] = []): never { )}), which is not supported. Dependencies are automatically tracked, so you can just use ${'`@cached`'}` ); } + + +export function isCachedProperty(object: object, prop: string) { + return (CacheMap.get(object) || []).includes(prop); +} diff --git a/packages/@ember/-internals/metal/lib/tracked.ts b/packages/@ember/-internals/metal/lib/tracked.ts index f5f696997f5..a9d3a8f13f0 100644 --- a/packages/@ember/-internals/metal/lib/tracked.ts +++ b/packages/@ember/-internals/metal/lib/tracked.ts @@ -200,3 +200,8 @@ export class TrackedDescriptor { this._set.call(obj, value); } } + + +export function isTrackedProperty(object: object, prop: string): boolean { + return metaFor(object).peekDescriptors(prop) instanceof TrackedDescriptor; +} diff --git a/packages/@ember/-internals/utils/index.ts b/packages/@ember/-internals/utils/index.ts index 329a6f7e793..433492ad7d5 100644 --- a/packages/@ember/-internals/utils/index.ts +++ b/packages/@ember/-internals/utils/index.ts @@ -32,4 +32,5 @@ export { setupMandatorySetter, teardownMandatorySetter, setWithMandatorySetter, + isMandatorySetter } from './lib/mandatory-setter'; diff --git a/packages/@ember/-internals/utils/lib/mandatory-setter.ts b/packages/@ember/-internals/utils/lib/mandatory-setter.ts index e30fe4c9c21..fa4c12edbcb 100644 --- a/packages/@ember/-internals/utils/lib/mandatory-setter.ts +++ b/packages/@ember/-internals/utils/lib/mandatory-setter.ts @@ -10,6 +10,8 @@ export let setupMandatorySetter: export let teardownMandatorySetter: ((obj: object, keyName: string | symbol) => void) | undefined; export let setWithMandatorySetter: ((obj: object, keyName: string, value: any) => void) | undefined; +export let isMandatorySetter: ((obj: object, keyName: string) => boolean) | undefined; + type PropertyDescriptorWithMeta = PropertyDescriptor & { hadOwnProperty?: boolean }; function isElementKey(key: string | number | symbol) { @@ -25,6 +27,7 @@ function isPositiveInt(num: number) { return num >= 0 && num % 1 === 0; } + if (DEBUG) { let SEEN_TAGS = new WeakSet(); @@ -94,6 +97,11 @@ if (DEBUG) { }); }; + isMandatorySetter = function (obj: object, keyName: string) { + let setters = MANDATORY_SETTERS.get(obj); + return setters !== undefined && setters[keyName] !== undefined; + } + teardownMandatorySetter = function (obj: object, keyName: string | symbol) { let setters = MANDATORY_SETTERS.get(obj); diff --git a/packages/@ember/debug/index.ts b/packages/@ember/debug/index.ts index cb7fc8fb6fa..5919c2c77ee 100644 --- a/packages/@ember/debug/index.ts +++ b/packages/@ember/debug/index.ts @@ -13,6 +13,47 @@ export { default as inspect } from './lib/inspect'; export { isTesting, setTesting } from './lib/testing'; export { default as captureRenderTree } from './lib/capture-render-tree'; +// required for inspector +import { _backburner, cancel, debounce, join, later, scheduleOnce } from '@ember/runloop'; +import { cacheFor, guidFor } from '@ember/object/internals'; +import { default as MutableArray } from '@ember/array/mutable'; +import { default as Namespace } from '@ember/application/namespace'; +import { default as MutableEnumerable } from'@ember/enumerable/mutable'; +import { NativeArray } from '@ember/array'; +import { ControllerMixin } from '@ember/controller'; +import { default as CoreObject } from '@ember/object/core'; +import { default as Application } from '@ember/application'; +import { default as EmberComponent } from '@ember/component'; +import { default as Observable } from '@ember/object/observable'; +import { default as Evented } from '@ember/object/evented'; +import { default as PromiseProxyMixin } from '@ember/object/promise-proxy-mixin'; +import { default as EmberObject } from '@ember/object'; +import { default as VERSION } from 'ember/version'; +import { ComputedProperty, isComputed, descriptorForProperty, descriptorForDecorator, tagForProperty } from '@ember/-internals/metal'; +import { isMandatorySetter } from '@ember/-internals/utils' +import { meta } from '@ember/-internals/meta'; +import { TargetActionSupport } from '@ember/-internals/runtime'; +import { + ViewStateSupport, + ViewMixin, + ActionSupport, + ClassNamesSupport, + ChildViewsSupport, + CoreView +} from '@ember/-internals/views'; +import { set, get } from '@ember/object'; +import { isTrackedProperty } from '@ember/-internals/metal/lib/tracked'; +import { isCachedProperty } from '@ember/-internals/metal/lib/cached'; +import { default as inspect } from './lib/inspect'; +import { subscribe } from '../instrumentation'; +import { default as captureRenderTree } from './lib/capture-render-tree'; +import { registerHandler as registerDeprecationHandler } from './lib/deprecate'; +import * as GlimmerValidator from '@glimmer/validator'; +import * as GlimmerRuntime from '@glimmer/runtime'; +import { getOwner } from '@glimmer/owner'; +import RSVP from 'rsvp'; + + export type DebugFunctionType = | 'assert' | 'info' @@ -342,6 +383,78 @@ if (DEBUG && !isTesting()) { }, false ); + window.addEventListener( + 'ember-inspector-debug-request', + () => { + const event = new CustomEvent("ember-inspector-debug-response", { detail: { + runloop: { + _backburner, + cancel, + debounce, + join, + later, + scheduleOnce, + }, + object: { + cacheFor, + guidFor, + getOwner, + set, + get, + meta + }, + debug: { + isComputed, + isTrackedProperty, + isCachedProperty, + descriptorForProperty, + descriptorForDecorator, + isMandatorySetter, + meta, + captureRenderTree, + isTesting, + inspect, + registerDeprecationHandler, + tagForProperty, + ComputedProperty, + infoForTag: GlimmerValidator.infoForTag + }, + classes: { + EmberObject, + MutableArray, + Namespace, + MutableEnumerable, + NativeArray, + TargetActionSupport, + ControllerMixin, + CoreObject, + Application, + EmberComponent, + Observable, + Evented, + PromiseProxyMixin, + }, + VERSION, + instrumentation: { + subscribe + }, + Views: { + ViewStateSupport, + ViewMixin, + ActionSupport, + ClassNamesSupport, + ChildViewsSupport, + CoreView + }, + GlimmerValidator, + GlimmerRuntime, + RSVP + } + }); + window.dispatchEvent(event); + }, + false + ); } }