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
21 changes: 21 additions & 0 deletions packages/@ember/-internals/deprecations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,27 @@ export const DEPRECATIONS = {
until: '8.0.0',
url: 'https://deprecations.emberjs.com/id/deprecate-native-array-mixin',
}),
DEPRECATE_EMBER_ARRAY_A: deprecation({
id: 'deprecate-ember-array-a',
for: 'ember-source',
since: { available: '7.5.0' },
until: '8.0.0',
url: 'https://deprecations.emberjs.com/id/deprecate-ember-array-a',
}),
DEPRECATE_QUERY_PARAM_EMBER_ARRAY: deprecation({
id: 'deprecate-query-param-ember-array',
for: 'ember-source',
since: { available: '7.5.0' },
until: '8.0.0',
url: 'https://deprecations.emberjs.com/id/deprecate-query-param-ember-array',
}),
DEPRECATE_ARRAY_COMPUTED_MACROS: deprecation({
id: 'deprecate-array-computed-macros',
for: 'ember-source',
since: { available: '7.5.0' },
until: '8.0.0',
url: 'https://deprecations.emberjs.com/id/deprecate-array-computed-macros',
}),
DEPRECATE_CONTROLLER_MIXIN: deprecation({
id: 'deprecate-controller-mixin',
for: 'ember-source',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import Component from '@glimmer/component';
import { precompileTemplate } from '@ember/template-compilation';
import { setComponentTemplate } from '@glimmer/manager';

const EMBER_A = DEPRECATIONS.DEPRECATE_EMBER_ARRAY_A;

moduleFor(
'Component Tracked Properties',
class extends RenderingTestCase {
Expand Down Expand Up @@ -98,9 +100,10 @@ moduleFor(
}

[`${testUnless(
DEPRECATIONS.DEPRECATE_ARRAY_PROXY.isRemoved
DEPRECATIONS.DEPRECATE_ARRAY_PROXY.isRemoved || EMBER_A.isRemoved
)} @test creating an array proxy inside a tracking context and immediately updating its content before usage does not trigger backtracking assertion`]() {
expectDeprecation(/`ArrayProxy` is deprecated/, DEPRECATIONS.DEPRECATE_ARRAY_PROXY.isEnabled);
expectDeprecation(/`A` from `@ember\/array` is deprecated/, EMBER_A.isEnabled);

class LoaderComponent extends Component {
get data() {
Expand Down Expand Up @@ -354,7 +357,9 @@ moduleFor(
this.assertText('1');
}

'@test array properties rerender when updated'() {
[`${testUnless(EMBER_A.isRemoved)} @test array properties rerender when updated`]() {
expectDeprecation(/`A` from `@ember\/array` is deprecated/, EMBER_A.isEnabled);

class NumListComponent extends Component {
@tracked numbers = A([1, 2, 3]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { setComponentTemplate } from '@glimmer/manager';

import Component from '@glimmer/component';

const EMBER_A = DEPRECATIONS.DEPRECATE_EMBER_ARRAY_A;

moduleFor(
'Helper Tracked Properties',
class extends RenderingTestCase {
Expand Down Expand Up @@ -147,7 +149,9 @@ moduleFor(
assert.strictEqual(computeCount, 2, 'compute is called exactly 2 times');
}

'@test array properties rerender when updated'() {
[`${testUnless(EMBER_A.isRemoved)} @test array properties rerender when updated`]() {
expectDeprecation(/`A` from `@ember\/array` is deprecated/, EMBER_A.isEnabled);

class NumListComponent extends Component {
@tracked numbers = A([1, 2, 3]);

Expand Down Expand Up @@ -402,7 +406,9 @@ moduleFor(
this.assertText('sal-value');
}

'@test each-in autotracks arrays acorrectly'() {
[`${testUnless(EMBER_A.isRemoved)} @test each-in autotracks arrays acorrectly`]() {
expectDeprecation(/`A` from `@ember\/array` is deprecated/, EMBER_A.isEnabled);

let obj = EmberObject.create({ arr: A([1]) });

this.owner.register(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import {
runTask,
ignoreDeprecation,
defineSimpleModifier,
testUnless,
} from 'internal-test-helpers';
import { DEPRECATIONS } from '@ember/-internals/deprecations';

import { notifyPropertyChange } from '@ember/-internals/metal';
import { get, set, computed } from '@ember/object';
import { A as emberA } from '@ember/array';
import { A } from '@ember/array';
import ArrayProxy from '@ember/array/proxy';
import { RSVP } from '@ember/-internals/runtime';
import { precompileTemplate } from '@ember/template-compilation';
Expand Down Expand Up @@ -156,19 +157,24 @@ class BasicEachTest extends TogglingEachTest {}
// `ArrayProxy` is deprecated; the deprecation itself is asserted by the
// dedicated `ArrayProxy` tests, so it is silenced in these rendering fixtures.
const ARRAY_PROXY_REMOVED = DEPRECATIONS.DEPRECATE_ARRAY_PROXY.isRemoved;
const EMBER_A_REMOVED = DEPRECATIONS.DEPRECATE_EMBER_ARRAY_A.isRemoved;

// The tests of `A` cover its deprecation.
function emberA(items) {
return ignoreDeprecation(() => A(items));
}

function arrayProxy(props) {
return ignoreDeprecation(() => ArrayProxy.create(props));
}

const TRUTHY_CASES = [
['hello'],
emberA(['hello']),
...(EMBER_A_REMOVED ? [] : [emberA(['hello'])]),
new Set(['hello']),
new ForEachable(['hello']),
...(ARRAY_PROXY_REMOVED
? []
: [arrayProxy({ content: ['hello'] }), arrayProxy({ content: emberA(['hello']) })]),
...(ARRAY_PROXY_REMOVED ? [] : [arrayProxy({ content: ['hello'] })]),
...(ARRAY_PROXY_REMOVED || EMBER_A_REMOVED ? [] : [arrayProxy({ content: emberA(['hello']) })]),
new ArrayIterable(['hello']),
];

Expand All @@ -179,12 +185,11 @@ const FALSY_CASES = [
'',
0,
[],
emberA([]),
...(EMBER_A_REMOVED ? [] : [emberA([])]),
new Set([]),
new ForEachable([]),
...(ARRAY_PROXY_REMOVED
? []
: [arrayProxy({ content: [] }), arrayProxy({ content: emberA([]) })]),
...(ARRAY_PROXY_REMOVED ? [] : [arrayProxy({ content: [] })]),
...(ARRAY_PROXY_REMOVED || EMBER_A_REMOVED ? [] : [arrayProxy({ content: emberA([]) })]),
new ArrayIterable([]),
];

Expand Down Expand Up @@ -1040,15 +1045,17 @@ moduleFor(
}
);

moduleFor(
'Syntax test: {{#each}} with emberA-wrapped arrays',
class extends EachTest {
createList(items) {
let wrapped = emberA(items);
return { list: wrapped, delegate: wrapped };
if (!EMBER_A_REMOVED) {
moduleFor(
'Syntax test: {{#each}} with emberA-wrapped arrays',
class extends EachTest {
createList(items) {
let wrapped = emberA(items);
return { list: wrapped, delegate: wrapped };
}
}
}
);
);
}

moduleFor(
'Syntax test: {{#each}} with native Set',
Expand Down Expand Up @@ -1088,7 +1095,7 @@ moduleFor(
}
);

if (!ARRAY_PROXY_REMOVED) {
if (!ARRAY_PROXY_REMOVED && !EMBER_A_REMOVED) {
moduleFor(
'Syntax test: {{#each}} with array proxies, modifying itself',
class extends EachTest {
Expand Down Expand Up @@ -1187,7 +1194,7 @@ moduleFor(
moduleFor(
'Syntax test: {{#each}} with sparse arrays',
class extends RenderingTestCase {
['@test it should itterate over holes']() {
[`${testUnless(EMBER_A_REMOVED)} @test it should itterate over holes`]() {
let sparseArray = [];
sparseArray[3] = 'foo';
sparseArray[4] = 'bar';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { htmlSafe } from '@ember/-internals/glimmer';
import { get, set } from '@ember/object';
import EmberObject from '@ember/object';
import ObjectProxy from '@ember/object/proxy';
import { A as emberA, removeAt } from '@ember/array';
import { A, removeAt } from '@ember/array';
import ArrayProxy from '@ember/array/proxy';
import { precompileTemplate } from '@ember/template-compilation';
import { setComponentTemplate } from '@glimmer/manager';
Expand All @@ -25,6 +25,12 @@ import Component from '@glimmer/component';
// itself is asserted by the dedicated proxy tests, so it is silenced here.
const OBJECT_PROXY_REMOVED = DEPRECATIONS.DEPRECATE_OBJECT_PROXY.isRemoved;
const ARRAY_PROXY_REMOVED = DEPRECATIONS.DEPRECATE_ARRAY_PROXY.isRemoved;
const EMBER_A_REMOVED = DEPRECATIONS.DEPRECATE_EMBER_ARRAY_A.isRemoved;

// The tests of `A` cover its deprecation.
function emberA(items) {
return ignoreDeprecation(() => A(items));
}

function objectProxy(props) {
return ignoreDeprecation(() => ObjectProxy.create(props));
Expand Down Expand Up @@ -342,7 +348,7 @@ export const ArrayTestCases = {
this.assertText('T1F2');
},

['@test it considers empty Ember arrays falsy']() {
[`${testUnless(EMBER_A_REMOVED)} @test it considers empty Ember arrays falsy`]() {
this.renderValues(emberA(['hello']), emberA());

this.assertText('T1F2');
Expand Down Expand Up @@ -401,7 +407,9 @@ export const ArrayTestCases = {
this.assertText('T1F2');
},

[`${testUnless(ARRAY_PROXY_REMOVED)} @test it considers array proxies with empty arrays falsy`]() {
[`${testUnless(
ARRAY_PROXY_REMOVED || EMBER_A_REMOVED
)} @test it considers array proxies with empty arrays falsy`]() {
this.renderValues(
arrayProxy({ content: emberA(['hello']) }),
arrayProxy({ content: emberA() })
Expand Down Expand Up @@ -443,7 +451,7 @@ const IfUnlessWithTestCases = [
'undefined',
1,
['hello'],
emberA(['hello']),
...unlessRemoved(EMBER_A_REMOVED, () => [emberA(['hello'])]),
{},
{ foo: 'bar' },
EmberObject.create(),
Expand All @@ -467,7 +475,7 @@ const IfUnlessWithTestCases = [
'',
0,
[],
emberA(),
...unlessRemoved(EMBER_A_REMOVED, () => [emberA()]),
...unlessRemoved(OBJECT_PROXY_REMOVED, () => [objectProxy({ content: undefined })]),
htmlSafe(''),
]),
Expand All @@ -481,7 +489,7 @@ const IfUnlessWithTestCases = [
'undefined',
1,
['hello'],
emberA(['hello']),
...unlessRemoved(EMBER_A_REMOVED, () => [emberA(['hello'])]),
...unlessRemoved(ARRAY_PROXY_REMOVED, () => [
arrayProxy({ content: ['hello'] }),
arrayProxy({ content: [] }),
Expand All @@ -505,7 +513,7 @@ const IfUnlessWithTestCases = [
'',
0,
[],
emberA(),
...unlessRemoved(EMBER_A_REMOVED, () => [emberA()]),
]),

ObjectTestCases,
Expand Down
17 changes: 15 additions & 2 deletions packages/@ember/-internals/metal/tests/alias_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,19 @@ import {
} from '..';
import EmberObject from '@ember/object';
import { A } from '@ember/array';
import { moduleFor, AbstractTestCase, runLoopSettled } from 'internal-test-helpers';
import {
moduleFor,
AbstractTestCase,
runLoopSettled,
expectDeprecation,
testUnless,
} from 'internal-test-helpers';
import { DEPRECATIONS } from '@ember/-internals/deprecations';
import { destroy } from '@glimmer/destroyable';
import { valueForTag, validateTag } from '@glimmer/validator';

const EMBER_A = DEPRECATIONS.DEPRECATE_EMBER_ARRAY_A;

let obj, count;

function incrementCount() {
Expand Down Expand Up @@ -69,7 +78,11 @@ moduleFor(
assert.equal(count, 1);
}

['@test nested aliases should trigger computed property invalidation [GH#19279]'](assert) {
[`${testUnless(
EMBER_A.isRemoved
)} @test nested aliases should trigger computed property invalidation [GH#19279]`](assert) {
expectDeprecation(/`A` from `@ember\/array` is deprecated/, EMBER_A.isEnabled);

let AttributeModel = class extends EmberObject {
@alias('additives.length')
countAdditives;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
functions below.
*/

import { A as emberA } from '@ember/array';
import { reportingA } from '@ember/array/index-internal';
import { DEPRECATIONS, deprecateUntil } from '@ember/-internals/deprecations';
import { assert } from '@ember/debug';
import { flushAsyncObservers } from '@ember/-internals/metal/lib/observer';
import { get } from '@ember/-internals/metal/lib/property_get';
Expand All @@ -18,13 +19,27 @@ import type { InternalRouteInfo, Transition } from 'router_js';
import { hasClassicInterop, STATE_SYMBOL } from 'router_js';
import { ClassicRouteBucket } from './bucket';

// Returns a fresh native array when the value is an array so callers cannot
function reportEmberArrayUse(name: string) {
deprecateUntil(
`\`${name}\` was used on the array value of a query param. This value becomes a native array. Use native array methods, and assign a new array to the property to change the query param.`,
DEPRECATIONS.DEPRECATE_QUERY_PARAM_EMBER_ARRAY
);
}

/**
Makes the array that a controller gets as the value of a query param.
*/
export function queryParamArray<T>(value: T[]): T[] {
return reportingA(value, reportEmberArrayUse);
}

// Returns a fresh array when the value is an array so callers cannot
// mutate the shared default. Also used by `@ember/routing/route`'s QP meta
// building.
export function copyDefaultValue<T>(value: T): T {
if (Array.isArray(value)) {
// SAFETY: We lost the type data about the array if we don't cast.
return emberA(value.slice()) as unknown as T;
return queryParamArray(value.slice()) as unknown as T;
}
return value;
}
Expand Down
3 changes: 1 addition & 2 deletions packages/@ember/-internals/runtime/tests/array/any-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { A as emberA } from '@ember/array';
import { AbstractTestCase } from 'internal-test-helpers';
import { runArrayTests } from '../helpers/array';
import { runArrayTests, emberA } from '../helpers/array';

class AnyTests extends AbstractTestCase {
'@test any should should invoke callback on each item as long as you return false'() {
Expand Down
16 changes: 14 additions & 2 deletions packages/@ember/-internals/runtime/tests/helpers/array.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ArrayProxy from '@ember/array/proxy';
import EmberArray, { A as emberA } from '@ember/array';
import EmberArray, { A } from '@ember/array';
import MutableArray from '@ember/array/mutable';
import { generateGuid, guidFor } from '@ember/-internals/utils';
import {
Expand All @@ -12,6 +12,12 @@ import EmberObject, { get, computed } from '@ember/object';
import { moduleFor, ignoreDeprecation } from 'internal-test-helpers';
import { DEPRECATIONS } from '@ember/-internals/deprecations';

// These suites test the shared array APIs.
// The tests of `A` cover its deprecation.
export function emberA(array) {
return ignoreDeprecation(() => A(array));
}

export function newFixture(cnt) {
let ret = [];
while (--cnt >= 0) {
Expand Down Expand Up @@ -156,7 +162,9 @@ class ArrayProxyHelpers extends AbstractArrayHelper {
// These suites exercise the shared array APIs rather than `ArrayProxy`
// itself, so we let the `ArrayProxy` deprecation pass silently here. The
// deprecation itself is covered by the dedicated `ArrayProxy` tests.
return ignoreDeprecation(() => ArrayProxy.create({ content: emberA(super.newObject(ary)) }));
let content = emberA(super.newObject(ary));

return ignoreDeprecation(() => ArrayProxy.create({ content }));
}

mutate(obj) {
Expand Down Expand Up @@ -290,6 +298,10 @@ export function runArrayTests(name, Tests, ...types) {
return;
}

if (DEPRECATIONS.DEPRECATE_EMBER_ARRAY_A.isRemoved) {
return;
}

for (let type of requested) {
moduleFor(`${type}: ${name}`, Tests, ARRAY_TEST_HELPERS[type]);
}
Expand Down
Loading
Loading