Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions packages/@ember/-internals/deprecations/index.ts
Comment thread
NullVoxPopuli marked this conversation as resolved.
Comment thread
kategengler marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,83 @@ export const DEPRECATIONS = {
until: '8.0.0',
url: 'https://deprecations.emberjs.com/id/deprecate-ember-utils',
}),
DEPRECATE_OBSERVABLE_MIXIN: deprecation({
id: 'deprecate-observable-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '8.0.0',
url: 'https://deprecations.emberjs.com/id/deprecate-observable-mixin',
}),
DEPRECATE_ENUMERABLE_MIXIN: deprecation({
id: 'deprecate-enumerable-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '7.9.0',
url: 'https://deprecations.emberjs.com/id/deprecate-enumerable-mixin',
}),
DEPRECATE_MUTABLE_ENUMERABLE_MIXIN: deprecation({
id: 'deprecate-mutable-enumerable-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '7.9.0',
url: 'https://deprecations.emberjs.com/id/deprecate-mutable-enumerable-mixin',
}),
DEPRECATE_EMBER_ARRAY_MIXIN: deprecation({
id: 'deprecate-ember-array-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '8.0.0',
url: 'https://deprecations.emberjs.com/id/deprecate-ember-array-mixin',
}),
DEPRECATE_MUTABLE_ARRAY_MIXIN: deprecation({
id: 'deprecate-mutable-array-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '8.0.0',
url: 'https://deprecations.emberjs.com/id/deprecate-mutable-array-mixin',
}),
DEPRECATE_NATIVE_ARRAY_MIXIN: deprecation({
id: 'deprecate-native-array-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '8.0.0',
url: 'https://deprecations.emberjs.com/id/deprecate-native-array-mixin',
}),
DEPRECATE_CONTROLLER_MIXIN: deprecation({
id: 'deprecate-controller-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '7.9.0',
url: 'https://deprecations.emberjs.com/id/deprecate-controller-mixin',
}),
DEPRECATE_ACTION_HANDLER_MIXIN: deprecation({
id: 'deprecate-action-handler-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '7.9.0',
url: 'https://deprecations.emberjs.com/id/deprecate-action-handler-mixin',
}),
DEPRECATE_PROXY_MIXIN: deprecation({
id: 'deprecate-proxy-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '7.9.0',
url: 'https://deprecations.emberjs.com/id/deprecate-proxy-mixin',
}),
DEPRECATE_CONTAINER_PROXY_MIXIN: deprecation({
id: 'deprecate-container-proxy-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '7.9.0',
url: 'https://deprecations.emberjs.com/id/deprecate-container-proxy-mixin',
}),
DEPRECATE_REGISTRY_PROXY_MIXIN: deprecation({
id: 'deprecate-registry-proxy-mixin',
for: 'ember-source',
since: { available: '7.5.0' },
until: '7.9.0',
url: 'https://deprecations.emberjs.com/id/deprecate-registry-proxy-mixin',
}),
};

export function deprecateUntil(message: string, deprecation: DeprecationObject) {
Expand Down
10 changes: 6 additions & 4 deletions packages/@ember/-internals/glimmer/lib/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { get } from '@ember/-internals/metal/lib/property_get';
import { PROPERTY_DID_CHANGE } from '@ember/-internals/metal/lib/property_events';
import type { PropertyDidChange } from '@ember/-internals/metal/lib/property_events';
import { getOwner } from '@ember/-internals/owner';
import TargetActionSupport from '@ember/-internals/runtime/lib/mixins/target_action_support';
import type TargetActionSupport from '@ember/-internals/runtime/lib/mixins/target_action_support';
import InternalTargetActionSupport from '@ember/-internals/runtime/lib/mixins/target_action_support-internal';
import type ViewStates from '@ember/-internals/views/lib/views/states';
import ActionSupport from '@ember/-internals/views/lib/mixins/action_support';
import type ActionSupport from '@ember/-internals/views/lib/mixins/action_support';
import InternalActionSupport from '@ember/-internals/views/lib/mixins/action_support-internal';
import {
addChildView,
getChildViews,
Expand Down Expand Up @@ -803,8 +805,8 @@ interface Component<S = unknown>

class Component<S = unknown>
extends CoreView.extend(
TargetActionSupport,
ActionSupport,
InternalTargetActionSupport,
Comment thread
kategengler marked this conversation as resolved.
InternalActionSupport,
{
// These need to be overridable via extend/create but should still
// have a default. Defining them here is the best way to achieve that.
Expand Down
13 changes: 8 additions & 5 deletions packages/@ember/-internals/glimmer/lib/helpers/each-in.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
@module @ember/helper
*/
import { tagForObject } from '@ember/-internals/metal/lib/tags';
import { contentFor as _contentFor } from '@ember/-internals/runtime/lib/mixins/-proxy';
import { contentFor as _contentFor } from '@ember/-internals/runtime/lib/mixins/-proxy-internal';
Comment thread
kategengler marked this conversation as resolved.
import { isProxy } from '@ember/-internals/utils/lib/is_proxy';
import { assert } from '@ember/debug';
import type { CapturedArguments } from '@glimmer/interfaces';
import { createComputeRef, valueForRef } from '@glimmer/reference/lib/reference';
import { consumeTag } from '@glimmer/validator/lib/tracking';
import { internalHelper } from './internal-helper';
import { DEPRECATIONS } from '../../../deprecations';

/**
The `{{#each}}` keyword loops over elements in a collection. It is an extension
Expand Down Expand Up @@ -311,10 +312,12 @@ export default internalHelper(({ positional }: CapturedArguments) => {

consumeTag(tagForObject(iterable));

if (isProxy(iterable)) {
// this is because the each-in doesn't actually get(proxy, 'key') but bypasses it
// and the proxy's tag is lazy updated on access
iterable = _contentFor(iterable);
if (!DEPRECATIONS.DEPRECATE_PROXY_MIXIN.isRemoved) {
if (isProxy(iterable)) {
// this is because the each-in doesn't actually get(proxy, 'key') but bypasses it
// and the proxy's tag is lazy updated on access
iterable = _contentFor(iterable);
}
}

return new EachInWrapper(iterable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import { A } from '@ember/array';
import MutableArray from '@ember/array/mutable';
import { tracked, notifyPropertyChange } from '@ember/-internals/metal';
import Service, { service } from '@ember/service';
import { moduleFor, RenderingTestCase, runTask } from 'internal-test-helpers';
import {
expectDeprecation,
moduleFor,
RenderingTestCase,
runTask,
testUnless,
} from 'internal-test-helpers';
import { DEPRECATIONS } from '@ember/-internals/deprecations';
import { precompileTemplate } from '@ember/template-compilation';
import { setComponentTemplate } from '@glimmer/manager';

Expand Down Expand Up @@ -172,7 +179,14 @@ moduleFor(
this.assertText('1, 2, 3, 4');
}

'@test custom ember array properties rerender when updated'() {
[`${testUnless(
DEPRECATIONS.DEPRECATE_MUTABLE_ARRAY_MIXIN.isRemoved
)} @test custom ember array properties rerender when updated`]() {
expectDeprecation(
/The `MutableArray` mixin is deprecated/,
DEPRECATIONS.DEPRECATE_MUTABLE_ARRAY_MIXIN.isEnabled
);

let CustomArray = class extends EmberObject.extend(MutableArray) {
init() {
super.init(...arguments);
Expand Down
123 changes: 123 additions & 0 deletions packages/@ember/-internals/runtime/lib/mixins/-proxy-internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
@module ember
*/

import { meta } from '@ember/-internals/meta/lib/meta';
import { InternalMixin } from '@ember/object/mixin-internal';
import { get } from '@ember/-internals/metal/lib/property_get';
import { set } from '@ember/-internals/metal/lib/property_set';
import { defineProperty } from '@ember/-internals/metal/lib/properties';
import { tagForObject, tagForProperty } from '@ember/-internals/metal/lib/tags';
import computed from '@ember/-internals/metal/lib/computed';
import { setProxy, isProxy } from '@ember/-internals/utils/lib/is_proxy';
import { setupMandatorySetter } from '@ember/-internals/utils/lib/mandatory-setter';
import { isObject } from '@ember/-internals/utils/lib/spec';
import { assert } from '@ember/debug';
import { DEBUG } from '@glimmer/env';
import { setCustomTagFor } from '@glimmer/manager/lib/util/args-proxy';
import type { UpdatableTag, Tag } from '@glimmer/interfaces';
import { combine, UPDATE_TAG as updateTag } from '@glimmer/validator/lib/validators';
import { tagFor, tagMetaFor } from '@glimmer/validator/lib/meta';

export function contentFor<T>(proxy: { content: T | null }): T | null {
let content = get(proxy, 'content');
// SAFETY: Ideally we'd assert instead of casting, but @glimmer/validator doesn't give us
// sufficient public types for this. Previously this code was .js and worked correctly so
// hopefully this is sufficiently reliable.
updateTag(tagForObject(proxy) as UpdatableTag, tagForObject(content));
return content;
}

function customTagForProxy(proxy: object, key: string, addMandatorySetter?: boolean): Tag {
assert('Expected a proxy', isProxy(proxy));

let meta = tagMetaFor(proxy);
let tag = tagFor(proxy, key, meta);

if (DEBUG) {
// TODO: Replace this with something more first class for tracking tags in DEBUG
// SAFETY: This is not an officially supported property but setting shouldn't cause issues.
(tag as any)._propertyKey = key;
}

if (key in proxy) {
if (DEBUG && addMandatorySetter) {
assert('[BUG] setupMandatorySetter should be set when debugging', setupMandatorySetter);
setupMandatorySetter(tag, proxy, key);
}

return tag;
} else {
let tags: Tag[] = [tag, tagFor(proxy, 'content', meta)];

let content = contentFor(proxy);

if (isObject(content)) {
tags.push(tagForProperty(content, key, addMandatorySetter));
}

return combine(tags);
}
}

/**
The internal counterpart to the public `ProxyMixin`. Ember's own internals
apply this so that they do not trigger the deprecation that the public
mixin emits. The public API documentation lives on the public copy.

@internal
*/
const InternalProxyMixin = /*@__PURE__*/ InternalMixin.create({
/**
The object whose properties will be forwarded.

@property content
@type {unknown}
@default null
*/
content: null,

init() {
this._super(...arguments);
setProxy(this);
tagForObject(this);
setCustomTagFor(this, customTagForProxy);
},

willDestroy() {
this.set('content', null);
this._super(...arguments);
},

isTruthy: computed('content', function () {
return Boolean(get(this, 'content'));
}),

unknownProperty(key: string) {
let content = contentFor(this);
return content ? get(content, key) : undefined;
},

setUnknownProperty(key: string, value: unknown) {
let m = meta(this);

if (m.isInitializing() || m.isPrototypeMeta(this)) {
// if marked as prototype or object is initializing then just
// defineProperty rather than delegate
defineProperty(this, key, null, value);
return value;
}

let content = contentFor(this);

assert(
`Cannot delegate set('${key}', ${value}) to the 'content' property of object proxy ${this}: its 'content' is undefined.`,
content
);

// SAFETY: We don't actually guarantee that this is an object, so this isn't necessarily safe :(
return set(content as object, key, value);
},
});

export default InternalProxyMixin;
Loading
Loading