diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c377894f24..208e5f263cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,13 +98,6 @@ jobs: - name: "Production build, with optional features" BUILD: "production" ENABLE_OPTIONAL_FEATURES: "true" - - name: "Extend prototypes" - EXTEND_PROTOTYPES: "true" - RAISE_ON_DEPRECATION: "false" - - name: "Extend prototypes, with optional features" - EXTEND_PROTOTYPES: "true" - ENABLE_OPTIONAL_FEATURES: "true" - RAISE_ON_DEPRECATION: "false" steps: - uses: actions/checkout@v4 @@ -115,7 +108,6 @@ jobs: env: ALL_DEPRECATIONS_ENABLED: ${{ matrix.ALL_DEPRECATIONS_ENABLED }} OVERRIDE_DEPRECATION_VERSION: ${{ matrix.OVERRIDE_DEPRECATION_VERSION }} - EXTEND_PROTOTYPES: ${{ matrix.EXTEND_PROTOTYPES }} ENABLE_OPTIONAL_FEATURES: ${{ matrix.ENABLE_OPTIONAL_FEATURES }} RAISE_ON_DEPRECATION: ${{ matrix.RAISE_ON_DEPRECATION }} diff --git a/bin/run-tests.js b/bin/run-tests.js index 83087ed9583..44687d9f46f 100755 --- a/bin/run-tests.js +++ b/bin/run-tests.js @@ -18,10 +18,6 @@ const variants = [ // hit its "until" version, the tests for it will behave correctly. 'OVERRIDE_DEPRECATION_VERSION', - // This enables the legacy Ember feature that causes Ember to extend built-in - // platform features like Array. - 'EXTEND_PROTOTYPES', - // This enables all canary feature flags for unreleased feature within Ember // itself. 'ENABLE_OPTIONAL_FEATURES', diff --git a/index.html b/index.html index c6fad19b48a..81c2569d2ba 100644 --- a/index.html +++ b/index.html @@ -24,9 +24,6 @@ EmberENV.__test_hook_count__ += object; }); - // Handle extending prototypes - EmberENV['EXTEND_PROTOTYPES'] = !!QUnit.urlParams.EXTEND_PROTOTYPES; - // Handle testing feature flags if (QUnit.urlParams.ENABLE_OPTIONAL_FEATURES) { EmberENV.ENABLE_OPTIONAL_FEATURES = true; diff --git a/packages/@ember/-internals/environment/lib/env.ts b/packages/@ember/-internals/environment/lib/env.ts index ae161ca5a39..d64eac6c7d8 100644 --- a/packages/@ember/-internals/environment/lib/env.ts +++ b/packages/@ember/-internals/environment/lib/env.ts @@ -20,22 +20,17 @@ export const ENV = { native object prototypes, a few extra methods in order to provide a more friendly API. - We generally recommend leaving this option set to true however, if you need - to turn it off, you can add the configuration property - `EXTEND_PROTOTYPES` to `EmberENV` and set it to `false`. - - Note, when disabled (the default configuration for Ember Addons), you will - instead have to access all methods and functions from the Ember - namespace. + The behavior from setting this option to `true` was deprecated in Ember 5.10. @property EXTEND_PROTOTYPES @type Boolean @default true @for EmberENV - @public + @private + @deprecated in v5.10 */ EXTEND_PROTOTYPES: { - Array: true, + Array: false, }, /** @@ -201,6 +196,9 @@ export const ENV = { } } + // TODO: Remove in Ember 6.5. This setting code for EXTEND_PROTOTYPES + // should stay for at least an LTS cycle so that users get the explicit + // deprecation exception when it breaks in >= 6.0.0. let { EXTEND_PROTOTYPES } = EmberENV; if (EXTEND_PROTOTYPES !== undefined) { if (typeof EXTEND_PROTOTYPES === 'object' && EXTEND_PROTOTYPES !== null) { diff --git a/packages/@ember/array/index.ts b/packages/@ember/array/index.ts index 4d49c9ae270..ac6130fd320 100644 --- a/packages/@ember/array/index.ts +++ b/packages/@ember/array/index.ts @@ -17,7 +17,6 @@ import { assert } from '@ember/debug'; import Enumerable from '@ember/enumerable'; import MutableEnumerable from '@ember/enumerable/mutable'; import { compare, typeOf } from '@ember/utils'; -import { ENV } from '@ember/-internals/environment'; import Observable from '@ember/object/observable'; import type { MethodNamesOf, MethodParams, MethodReturns } from '@ember/-internals/utility-types'; import type { ComputedPropertyCallback } from '@ember/-internals/metal'; @@ -1858,11 +1857,7 @@ const MutableArray = Mixin.create(EmberArray, MutableEnumerable, { /** Creates an `Ember.NativeArray` from an Array-like object. - Does not modify the original object's contents. `A()` is not needed if - `EmberENV.EXTEND_PROTOTYPES` is `true` (the default value). However, - it is recommended that you use `A()` when creating addons for - ember or when you can not guarantee that `EmberENV.EXTEND_PROTOTYPES` - will be `true`. + Does not modify the original object's contents. Example @@ -2061,10 +2056,7 @@ interface MutableArrayWithoutNative /** The NativeArray mixin contains the properties needed to make the native - Array support MutableArray and all of its dependent APIs. Unless you - have `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Array` set to - false, this will be applied automatically. Otherwise you can apply the mixin - at anytime by calling `Ember.NativeArray.apply(Array.prototype)`. + Array support MutableArray and all of its dependent APIs. @class Ember.NativeArray @uses MutableArray @@ -2101,34 +2093,20 @@ NativeArray = NativeArray.without(...ignore); let A: (arr?: Array) => NativeArray; -if (ENV.EXTEND_PROTOTYPES.Array) { - NativeArray.apply(Array.prototype, true); - - A = function (this: unknown, arr?: Array) { - assert( - 'You cannot create an Ember Array with `new A()`, please update to calling A as a function: `A()`', - !(this instanceof A) - ); - - // SAFTEY: Since we are extending prototypes all true native arrays are Ember NativeArrays - return (arr || []) as NativeArray; - }; -} else { - A = function (this: unknown, arr?: Array) { - assert( - 'You cannot create an Ember Array with `new A()`, please update to calling A as a function: `A()`', - !(this instanceof A) - ); - - if (isEmberArray(arr)) { - // SAFETY: If it's a true native array and it is also an EmberArray then it should be an Ember NativeArray - return arr as unknown as NativeArray; - } else { - // SAFETY: This will return an NativeArray but TS can't infer that. - return NativeArray.apply(arr ?? []) as NativeArray; - } - }; -} +A = function (this: unknown, arr?: Array) { + assert( + 'You cannot create an Ember Array with `new A()`, please update to calling A as a function: `A()`', + !(this instanceof A) + ); + + if (isEmberArray(arr)) { + // SAFETY: If it's a true native array and it is also an EmberArray then it should be an Ember NativeArray + return arr as unknown as NativeArray; + } else { + // SAFETY: This will return an NativeArray but TS can't infer that. + return NativeArray.apply(arr ?? []) as NativeArray; + } +}; export { A, NativeArray, MutableArray }; diff --git a/tests/node/app-boot-test.js b/tests/node/app-boot-test.js index f1bbe0bfaec..80ec9d1a837 100644 --- a/tests/node/app-boot-test.js +++ b/tests/node/app-boot-test.js @@ -13,21 +13,21 @@ QUnit.module('App Boot', function (hooks) { QUnit.test('nested {{component}}', function (assert) { this.template('index', '{{root-component}}'); - this.template( - 'components/root-component', + this.component( + 'root-component', + { + location: 'World', + hasExistence: true, + }, "\ -

Hello {{#if this.hasExistence}}{{this.location}}{{/if}}

\ -
{{component 'foo-bar'}}
\ - " +

Hello {{#if this.hasExistence}}{{this.location}}{{/if}}

\ +
{{component 'foo-bar'}}
\ + " ); - this.component('root-component', { - location: 'World', - hasExistence: true, - }); - - this.template( - 'components/foo-bar', + this.component( + 'foo-bar', + undefined, '\

The files are *inside* the computer?!

\ ' diff --git a/tests/node/helpers/setup-app.js b/tests/node/helpers/setup-app.js index 2e6a1ec4328..0a6738c9168 100644 --- a/tests/node/helpers/setup-app.js +++ b/tests/node/helpers/setup-app.js @@ -61,6 +61,8 @@ module.exports = function (hooks) { this.Ember = Ember; this.compile = compile; + this.setComponentTemplate = Ember._setComponentTemplate; + this.templateOnlyComponent = Ember._templateOnlyComponent; Ember.testing = true; @@ -166,8 +168,11 @@ function registerTemplate(name, template) { this.register('template:' + name, this.compile(template)); } -function registerComponent(name, componentProps) { - let component = this.Ember.Component.extend(componentProps); +function registerComponent(name, componentProps, templateContents) { + let component = this.setComponentTemplate( + this.compile(templateContents), + componentProps ? this.Ember.Component.extend(componentProps) : this.templateOnlyComponent() + ); this.register('component:' + name, component); } diff --git a/tests/node/visit-test.js b/tests/node/visit-test.js index 10619dbbf86..4b7dca9008a 100644 --- a/tests/node/visit-test.js +++ b/tests/node/visit-test.js @@ -51,21 +51,24 @@ QUnit.module('Ember.Application - visit() Integration Tests', function (hooks) { this.template('application', '

Hello world

\n{{outlet}}'); this.template('a', '

Welcome to {{x-foo page="A"}}

'); this.template('b', '

{{x-foo page="B"}}

'); - this.template('components/x-foo', 'Page {{this.page}}'); let initCalled = false; let didInsertElementCalled = false; - this.component('x-foo', { - tagName: 'span', - init: function () { - this._super(); - initCalled = true; - }, - didInsertElement: function () { - didInsertElementCalled = true; + this.component( + 'x-foo', + { + tagName: 'span', + init: function () { + this._super(); + initCalled = true; + }, + didInsertElement: function () { + didInsertElementCalled = true; + }, }, - }); + 'Page {{this.page}}' + ); let App = this.createApplication(); @@ -337,8 +340,7 @@ QUnit.module('Ember.Application - visit() Integration Tests', function (hooks) { QUnit.test('FastBoot: tagless components can render', function (assert) { this.template('application', "
{{my-component}}
"); - this.component('my-component', { tagName: '' }); - this.template('components/my-component', '

hello world

'); + this.component('my-component', { tagName: '' }, '

hello world

'); let App = this.createApplication();