Skip to content

Commit 85a4f29

Browse files
authored
Merge pull request #20730 from emberjs/kg-cleanup-extend-prototypes
2 parents 0377da6 + 7260196 commit 85a4f29

File tree

8 files changed

+56
-88
lines changed

8 files changed

+56
-88
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,6 @@ jobs:
9898
- name: "Production build, with optional features"
9999
BUILD: "production"
100100
ENABLE_OPTIONAL_FEATURES: "true"
101-
- name: "Extend prototypes"
102-
EXTEND_PROTOTYPES: "true"
103-
RAISE_ON_DEPRECATION: "false"
104-
- name: "Extend prototypes, with optional features"
105-
EXTEND_PROTOTYPES: "true"
106-
ENABLE_OPTIONAL_FEATURES: "true"
107-
RAISE_ON_DEPRECATION: "false"
108101

109102
steps:
110103
- uses: actions/checkout@v4
@@ -115,7 +108,6 @@ jobs:
115108
env:
116109
ALL_DEPRECATIONS_ENABLED: ${{ matrix.ALL_DEPRECATIONS_ENABLED }}
117110
OVERRIDE_DEPRECATION_VERSION: ${{ matrix.OVERRIDE_DEPRECATION_VERSION }}
118-
EXTEND_PROTOTYPES: ${{ matrix.EXTEND_PROTOTYPES }}
119111
ENABLE_OPTIONAL_FEATURES: ${{ matrix.ENABLE_OPTIONAL_FEATURES }}
120112
RAISE_ON_DEPRECATION: ${{ matrix.RAISE_ON_DEPRECATION }}
121113

bin/run-tests.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ const variants = [
1818
// hit its "until" version, the tests for it will behave correctly.
1919
'OVERRIDE_DEPRECATION_VERSION',
2020

21-
// This enables the legacy Ember feature that causes Ember to extend built-in
22-
// platform features like Array.
23-
'EXTEND_PROTOTYPES',
24-
2521
// This enables all canary feature flags for unreleased feature within Ember
2622
// itself.
2723
'ENABLE_OPTIONAL_FEATURES',

index.html

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@
2424
EmberENV.__test_hook_count__ += object;
2525
});
2626

27-
// Handle extending prototypes
28-
EmberENV['EXTEND_PROTOTYPES'] = !!QUnit.urlParams.EXTEND_PROTOTYPES;
29-
3027
// Handle testing feature flags
3128
if (QUnit.urlParams.ENABLE_OPTIONAL_FEATURES) {
3229
EmberENV.ENABLE_OPTIONAL_FEATURES = true;

packages/@ember/-internals/environment/lib/env.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,17 @@ export const ENV = {
2020
native object prototypes, a few extra methods in order to provide a more
2121
friendly API.
2222
23-
We generally recommend leaving this option set to true however, if you need
24-
to turn it off, you can add the configuration property
25-
`EXTEND_PROTOTYPES` to `EmberENV` and set it to `false`.
26-
27-
Note, when disabled (the default configuration for Ember Addons), you will
28-
instead have to access all methods and functions from the Ember
29-
namespace.
23+
The behavior from setting this option to `true` was deprecated in Ember 5.10.
3024
3125
@property EXTEND_PROTOTYPES
3226
@type Boolean
3327
@default true
3428
@for EmberENV
35-
@public
29+
@private
30+
@deprecated in v5.10
3631
*/
3732
EXTEND_PROTOTYPES: {
38-
Array: true,
33+
Array: false,
3934
},
4035

4136
/**
@@ -201,6 +196,9 @@ export const ENV = {
201196
}
202197
}
203198

199+
// TODO: Remove in Ember 6.5. This setting code for EXTEND_PROTOTYPES
200+
// should stay for at least an LTS cycle so that users get the explicit
201+
// deprecation exception when it breaks in >= 6.0.0.
204202
let { EXTEND_PROTOTYPES } = EmberENV;
205203
if (EXTEND_PROTOTYPES !== undefined) {
206204
if (typeof EXTEND_PROTOTYPES === 'object' && EXTEND_PROTOTYPES !== null) {

packages/@ember/array/index.ts

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { assert } from '@ember/debug';
1717
import Enumerable from '@ember/enumerable';
1818
import MutableEnumerable from '@ember/enumerable/mutable';
1919
import { compare, typeOf } from '@ember/utils';
20-
import { ENV } from '@ember/-internals/environment';
2120
import Observable from '@ember/object/observable';
2221
import type { MethodNamesOf, MethodParams, MethodReturns } from '@ember/-internals/utility-types';
2322
import type { ComputedPropertyCallback } from '@ember/-internals/metal';
@@ -1858,11 +1857,7 @@ const MutableArray = Mixin.create(EmberArray, MutableEnumerable, {
18581857

18591858
/**
18601859
Creates an `Ember.NativeArray` from an Array-like object.
1861-
Does not modify the original object's contents. `A()` is not needed if
1862-
`EmberENV.EXTEND_PROTOTYPES` is `true` (the default value). However,
1863-
it is recommended that you use `A()` when creating addons for
1864-
ember or when you can not guarantee that `EmberENV.EXTEND_PROTOTYPES`
1865-
will be `true`.
1860+
Does not modify the original object's contents.
18661861
18671862
Example
18681863
@@ -2061,10 +2056,7 @@ interface MutableArrayWithoutNative<T>
20612056

20622057
/**
20632058
The NativeArray mixin contains the properties needed to make the native
2064-
Array support MutableArray and all of its dependent APIs. Unless you
2065-
have `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Array` set to
2066-
false, this will be applied automatically. Otherwise you can apply the mixin
2067-
at anytime by calling `Ember.NativeArray.apply(Array.prototype)`.
2059+
Array support MutableArray and all of its dependent APIs.
20682060
20692061
@class Ember.NativeArray
20702062
@uses MutableArray
@@ -2101,34 +2093,20 @@ NativeArray = NativeArray.without(...ignore);
21012093

21022094
let A: <T>(arr?: Array<T>) => NativeArray<T>;
21032095

2104-
if (ENV.EXTEND_PROTOTYPES.Array) {
2105-
NativeArray.apply(Array.prototype, true);
2106-
2107-
A = function <T>(this: unknown, arr?: Array<T>) {
2108-
assert(
2109-
'You cannot create an Ember Array with `new A()`, please update to calling A as a function: `A()`',
2110-
!(this instanceof A)
2111-
);
2112-
2113-
// SAFTEY: Since we are extending prototypes all true native arrays are Ember NativeArrays
2114-
return (arr || []) as NativeArray<T>;
2115-
};
2116-
} else {
2117-
A = function <T>(this: unknown, arr?: Array<T>) {
2118-
assert(
2119-
'You cannot create an Ember Array with `new A()`, please update to calling A as a function: `A()`',
2120-
!(this instanceof A)
2121-
);
2122-
2123-
if (isEmberArray(arr)) {
2124-
// SAFETY: If it's a true native array and it is also an EmberArray then it should be an Ember NativeArray
2125-
return arr as unknown as NativeArray<T>;
2126-
} else {
2127-
// SAFETY: This will return an NativeArray but TS can't infer that.
2128-
return NativeArray.apply(arr ?? []) as NativeArray<T>;
2129-
}
2130-
};
2131-
}
2096+
A = function <T>(this: unknown, arr?: Array<T>) {
2097+
assert(
2098+
'You cannot create an Ember Array with `new A()`, please update to calling A as a function: `A()`',
2099+
!(this instanceof A)
2100+
);
2101+
2102+
if (isEmberArray(arr)) {
2103+
// SAFETY: If it's a true native array and it is also an EmberArray then it should be an Ember NativeArray
2104+
return arr as unknown as NativeArray<T>;
2105+
} else {
2106+
// SAFETY: This will return an NativeArray but TS can't infer that.
2107+
return NativeArray.apply(arr ?? []) as NativeArray<T>;
2108+
}
2109+
};
21322110

21332111
export { A, NativeArray, MutableArray };
21342112

tests/node/app-boot-test.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ QUnit.module('App Boot', function (hooks) {
1313
QUnit.test('nested {{component}}', function (assert) {
1414
this.template('index', '{{root-component}}');
1515

16-
this.template(
17-
'components/root-component',
16+
this.component(
17+
'root-component',
18+
{
19+
location: 'World',
20+
hasExistence: true,
21+
},
1822
"\
19-
<h1>Hello {{#if this.hasExistence}}{{this.location}}{{/if}}</h1>\
20-
<div>{{component 'foo-bar'}}</div>\
21-
"
23+
<h1>Hello {{#if this.hasExistence}}{{this.location}}{{/if}}</h1>\
24+
<div>{{component 'foo-bar'}}</div>\
25+
"
2226
);
2327

24-
this.component('root-component', {
25-
location: 'World',
26-
hasExistence: true,
27-
});
28-
29-
this.template(
30-
'components/foo-bar',
28+
this.component(
29+
'foo-bar',
30+
undefined,
3131
'\
3232
<p>The files are *inside* the computer?!</p>\
3333
'

tests/node/helpers/setup-app.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ module.exports = function (hooks) {
6161

6262
this.Ember = Ember;
6363
this.compile = compile;
64+
this.setComponentTemplate = Ember._setComponentTemplate;
65+
this.templateOnlyComponent = Ember._templateOnlyComponent;
6466

6567
Ember.testing = true;
6668

@@ -166,8 +168,11 @@ function registerTemplate(name, template) {
166168
this.register('template:' + name, this.compile(template));
167169
}
168170

169-
function registerComponent(name, componentProps) {
170-
let component = this.Ember.Component.extend(componentProps);
171+
function registerComponent(name, componentProps, templateContents) {
172+
let component = this.setComponentTemplate(
173+
this.compile(templateContents),
174+
componentProps ? this.Ember.Component.extend(componentProps) : this.templateOnlyComponent()
175+
);
171176
this.register('component:' + name, component);
172177
}
173178

tests/node/visit-test.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,24 @@ QUnit.module('Ember.Application - visit() Integration Tests', function (hooks) {
5151
this.template('application', '<h1>Hello world</h1>\n{{outlet}}');
5252
this.template('a', '<h2>Welcome to {{x-foo page="A"}}</h2>');
5353
this.template('b', '<h2>{{x-foo page="B"}}</h2>');
54-
this.template('components/x-foo', 'Page {{this.page}}');
5554

5655
let initCalled = false;
5756
let didInsertElementCalled = false;
5857

59-
this.component('x-foo', {
60-
tagName: 'span',
61-
init: function () {
62-
this._super();
63-
initCalled = true;
64-
},
65-
didInsertElement: function () {
66-
didInsertElementCalled = true;
58+
this.component(
59+
'x-foo',
60+
{
61+
tagName: 'span',
62+
init: function () {
63+
this._super();
64+
initCalled = true;
65+
},
66+
didInsertElement: function () {
67+
didInsertElementCalled = true;
68+
},
6769
},
68-
});
70+
'Page {{this.page}}'
71+
);
6972

7073
let App = this.createApplication();
7174

@@ -337,8 +340,7 @@ QUnit.module('Ember.Application - visit() Integration Tests', function (hooks) {
337340

338341
QUnit.test('FastBoot: tagless components can render', function (assert) {
339342
this.template('application', "<div class='my-context'>{{my-component}}</div>");
340-
this.component('my-component', { tagName: '' });
341-
this.template('components/my-component', '<h1>hello world</h1>');
343+
this.component('my-component', { tagName: '' }, '<h1>hello world</h1>');
342344

343345
let App = this.createApplication();
344346

0 commit comments

Comments
 (0)