From 8ae02f246ce15db41d239a11cc6460d1cb38c416 Mon Sep 17 00:00:00 2001 From: Nathaniel Furniss Date: Sun, 18 Jul 2021 21:27:20 -0700 Subject: [PATCH] Remove function prototype extensions --- .../@ember/-internals/environment/lib/env.ts | 9 +- .../-internals/metal/tests/observer_test.js | 87 -------- packages/@ember/-internals/runtime/index.js | 2 - .../-internals/runtime/lib/ext/function.js | 197 ------------------ .../runtime/tests/ext/function_test.js | 145 ------------- packages/@ember/deprecated-features/index.ts | 1 - tests/docs/expected.js | 1 - 7 files changed, 1 insertion(+), 441 deletions(-) delete mode 100644 packages/@ember/-internals/runtime/lib/ext/function.js delete mode 100644 packages/@ember/-internals/runtime/tests/ext/function_test.js diff --git a/packages/@ember/-internals/environment/lib/env.ts b/packages/@ember/-internals/environment/lib/env.ts index 5de3bf19eb8..27ea7f19e99 100644 --- a/packages/@ember/-internals/environment/lib/env.ts +++ b/packages/@ember/-internals/environment/lib/env.ts @@ -1,4 +1,3 @@ -import { FUNCTION_PROTOTYPE_EXTENSIONS } from '@ember/deprecated-features'; import { DEBUG } from '@glimmer/env'; import global from './global'; @@ -220,16 +219,10 @@ export const ENV = { if (EXTEND_PROTOTYPES !== undefined) { if (typeof EXTEND_PROTOTYPES === 'object' && EXTEND_PROTOTYPES !== null) { ENV.EXTEND_PROTOTYPES.String = EXTEND_PROTOTYPES.String !== false; - if (FUNCTION_PROTOTYPE_EXTENSIONS) { - ENV.EXTEND_PROTOTYPES.Function = EXTEND_PROTOTYPES.Function !== false; - } ENV.EXTEND_PROTOTYPES.Array = EXTEND_PROTOTYPES.Array !== false; } else { let isEnabled = EXTEND_PROTOTYPES !== false; ENV.EXTEND_PROTOTYPES.String = isEnabled; - if (FUNCTION_PROTOTYPE_EXTENSIONS) { - ENV.EXTEND_PROTOTYPES.Function = isEnabled; - } ENV.EXTEND_PROTOTYPES.Array = isEnabled; } } @@ -259,6 +252,6 @@ export const ENV = { } })(global.EmberENV); -export function getENV() { +export function getENV(): object { return ENV; } diff --git a/packages/@ember/-internals/metal/tests/observer_test.js b/packages/@ember/-internals/metal/tests/observer_test.js index 1a78e8ea0c7..ea4dfd1dd02 100644 --- a/packages/@ember/-internals/metal/tests/observer_test.js +++ b/packages/@ember/-internals/metal/tests/observer_test.js @@ -1,4 +1,3 @@ -import { ENV } from '@ember/-internals/environment'; import { changeProperties, addObserver, @@ -15,7 +14,6 @@ import { set, } from '..'; import { moduleFor, AbstractTestCase, runLoopSettled } from 'internal-test-helpers'; -import { FUNCTION_PROTOTYPE_EXTENSIONS } from '@ember/deprecated-features'; import { destroy } from '@glimmer/destroyable'; import { meta as metaFor } from '@ember/-internals/meta'; @@ -192,91 +190,6 @@ moduleFor( assert.equal(observerCount, 10, 'should continue to fire indefinitely'); } - async ['@test observer added via Function.prototype extensions and brace expansion should fire when property changes']( - assert - ) { - if (!FUNCTION_PROTOTYPE_EXTENSIONS && ENV.EXTEND_PROTOTYPES.Function) { - obj = {}; - let count = 0; - - expectDeprecation(() => { - mixin(obj, { - observeFooAndBar: function () { - count++; - }.observes('{foo,bar}'), - }); - }, /Function prototype extensions have been deprecated, please migrate from function\(\){}.observes\('foo'\) to observer\('foo', function\(\) {}\)/); - - set(obj, 'foo', 'foo'); - await runLoopSettled(); - - assert.equal(count, 1, 'observer specified via brace expansion invoked on property change'); - - set(obj, 'bar', 'bar'); - await runLoopSettled(); - - assert.equal(count, 2, 'observer specified via brace expansion invoked on property change'); - - set(obj, 'baz', 'baz'); - await runLoopSettled(); - - assert.equal(count, 2, 'observer not invoked on unspecified property'); - } else { - assert.expect(0); - } - } - - async ['@test observer specified via Function.prototype extensions via brace expansion should fire when dependent property changes']( - assert - ) { - if (!FUNCTION_PROTOTYPE_EXTENSIONS && ENV.EXTEND_PROTOTYPES.Function) { - obj = { baz: 'Initial' }; - let count = 0; - - defineProperty( - obj, - 'foo', - computed('bar', function () { - return get(this, 'bar').toLowerCase(); - }) - ); - - defineProperty( - obj, - 'bar', - computed('baz', function () { - return get(this, 'baz').toUpperCase(); - }) - ); - - expectDeprecation(() => { - mixin(obj, { - fooAndBarWatcher: function () { - count++; - }.observes('{foo,bar}'), - }); - }, /Function prototype extensions have been deprecated, please migrate from function\(\){}.observes\('foo'\) to observer\('foo', function\(\) {}\)/); - - get(obj, 'foo'); - set(obj, 'baz', 'Baz'); - await runLoopSettled(); - - // fire once for foo, once for bar - assert.equal( - count, - 2, - 'observer specified via brace expansion invoked on dependent property change' - ); - - set(obj, 'quux', 'Quux'); - await runLoopSettled(); - - assert.equal(count, 2, 'observer not fired on unspecified property'); - } else { - assert.expect(0); - } - } - async ['@test observers watching multiple properties via brace expansion should fire when the properties change']( assert ) { diff --git a/packages/@ember/-internals/runtime/index.js b/packages/@ember/-internals/runtime/index.js index 6558895952b..9758f67367a 100644 --- a/packages/@ember/-internals/runtime/index.js +++ b/packages/@ember/-internals/runtime/index.js @@ -30,5 +30,3 @@ export { default as PromiseProxyMixin } from './lib/mixins/promise_proxy'; export { default as RSVP, onerrorDefault } from './lib/ext/rsvp'; // just for side effect of extending Ember.RSVP export { typeOf } from './lib/type-of'; - -import './lib/ext/function'; // just for side effect of extending Function.prototype diff --git a/packages/@ember/-internals/runtime/lib/ext/function.js b/packages/@ember/-internals/runtime/lib/ext/function.js deleted file mode 100644 index be2ae54d18e..00000000000 --- a/packages/@ember/-internals/runtime/lib/ext/function.js +++ /dev/null @@ -1,197 +0,0 @@ -/** -@module ember -*/ - -import { ENV } from '@ember/-internals/environment'; -import { on, computed, observer } from '@ember/-internals/metal'; -import { deprecate } from '@ember/debug'; -import { FUNCTION_PROTOTYPE_EXTENSIONS } from '@ember/deprecated-features'; - -if (FUNCTION_PROTOTYPE_EXTENSIONS && ENV.EXTEND_PROTOTYPES.Function) { - Object.defineProperties(Function.prototype, { - /** - The `property` extension of Javascript's Function prototype is available - when `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Function` is - `true`, which is the default. - - Computed properties allow you to treat a function like a property: - - ```app/utils/president.js - import EmberObject from '@ember/object'; - - export default EmberObject.extend({ - firstName: '', - lastName: '', - - fullName: function() { - return this.get('firstName') + ' ' + this.get('lastName'); - }.property() // Call this flag to mark the function as a property - }); - ``` - - ```javascript - let president = President.create({ - firstName: 'Barack', - lastName: 'Obama' - }); - - president.get('fullName'); // 'Barack Obama' - ``` - - Treating a function like a property is useful because they can work with - bindings, just like any other property. - - Many computed properties have dependencies on other properties. For - example, in the above example, the `fullName` property depends on - `firstName` and `lastName` to determine its value. You can tell Ember - about these dependencies like this: - - ```app/utils/president.js - import EmberObject from '@ember/object'; - - export default EmberObject.extend({ - firstName: '', - lastName: '', - - fullName: function() { - return this.get('firstName') + ' ' + this.get('lastName'); - - // Tell Ember.js that this computed property depends on firstName - // and lastName - }.property('firstName', 'lastName') - }); - ``` - - Make sure you list these dependencies so Ember knows when to update - bindings that connect to a computed property. Changing a dependency - will not immediately trigger an update of the computed property, but - will instead clear the cache so that it is updated when the next `get` - is called on the property. - - See [ComputedProperty](/ember/release/classes/ComputedProperty), [@ember/object/computed](/ember/release/classes/@ember%2Fobject%2Fcomputed). - - @method property - @for Function - @public - */ - property: { - configurable: true, - enumerable: false, - writable: true, - value: function () { - deprecate( - `Function prototype extensions have been deprecated, please migrate from function(){}.property('bar') to computed('bar', function() {}).`, - false, - { - id: 'function-prototype-extensions.property', - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_function-prototype-extensions-property', - for: 'ember-source', - since: { - enabled: '3.11.0', - }, - } - ); - return computed(...arguments, this); - }, - }, - - /** - The `observes` extension of Javascript's Function prototype is available - when `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Function` is - true, which is the default. - - You can observe property changes simply by adding the `observes` - call to the end of your method declarations in classes that you write. - For example: - - ```javascript - import EmberObject from '@ember/object'; - - EmberObject.extend({ - valueObserver: function() { - // Executes whenever the "value" property changes - }.observes('value') - }); - ``` - - In the future this method may become asynchronous. - - See `observer`. - - @method observes - @for Function - @public - */ - observes: { - configurable: true, - enumerable: false, - writable: true, - value: function () { - deprecate( - `Function prototype extensions have been deprecated, please migrate from function(){}.observes('foo') to observer('foo', function() {}).`, - false, - { - id: 'function-prototype-extensions.observes', - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_function-prototype-extensions-observes', - for: 'ember-source', - since: { - enabled: '3.11.0', - }, - } - ); - - return observer(...arguments, this); - }, - }, - - /** - The `on` extension of Javascript's Function prototype is available - when `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Function` is - true, which is the default. - - You can listen for events simply by adding the `on` call to the end of - your method declarations in classes or mixins that you write. For example: - - ```javascript - import Mixin from '@ember/mixin'; - - Mixin.create({ - doSomethingWithElement: function() { - // Executes whenever the "didInsertElement" event fires - }.on('didInsertElement') - }); - ``` - - See `@ember/object/evented/on`. - - @method on - @for Function - @public - */ - - on: { - configurable: true, - enumerable: false, - writable: true, - value: function () { - deprecate( - `Function prototype extensions have been deprecated, please migrate from function(){}.on('foo') to on('foo', function() {}).`, - false, - { - id: 'function-prototype-extensions.on', - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_function-prototype-extensions-on', - for: 'ember-source', - since: { - enabled: '3.11.0', - }, - } - ); - - return on(...arguments, this); - }, - }, - }); -} diff --git a/packages/@ember/-internals/runtime/tests/ext/function_test.js b/packages/@ember/-internals/runtime/tests/ext/function_test.js deleted file mode 100644 index f4a4b22c2f4..00000000000 --- a/packages/@ember/-internals/runtime/tests/ext/function_test.js +++ /dev/null @@ -1,145 +0,0 @@ -import { ENV } from '@ember/-internals/environment'; -import { Mixin, mixin, get, set } from '@ember/-internals/metal'; -import EmberObject from '../../lib/system/object'; -import Evented from '../../lib/mixins/evented'; -import { moduleFor, AbstractTestCase, runLoopSettled } from 'internal-test-helpers'; -import { FUNCTION_PROTOTYPE_EXTENSIONS } from '@ember/deprecated-features'; -import { destroy } from '@glimmer/destroyable'; - -moduleFor( - 'Function.prototype.observes() helper', - class extends AbstractTestCase { - async ['@test global observer helper takes multiple params'](assert) { - if (!FUNCTION_PROTOTYPE_EXTENSIONS || !ENV.EXTEND_PROTOTYPES.Function) { - assert.ok( - 'undefined' === typeof Function.prototype.observes, - 'Function.prototype helper disabled' - ); - return; - } - - let MyMixin; - expectDeprecation(() => { - MyMixin = Mixin.create({ - count: 0, - - foo: function () { - set(this, 'count', get(this, 'count') + 1); - }.observes('bar', 'baz'), - }); - }, /Function prototype extensions have been deprecated, please migrate from function\(\){}.observes\('foo'\) to observer\('foo', function\(\) {}\)/); - - let obj = mixin({}, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke observer immediately'); - - set(obj, 'bar', 'BAZ'); - await runLoopSettled(); - - set(obj, 'baz', 'BAZ'); - await runLoopSettled(); - - assert.equal(get(obj, 'count'), 2, 'should invoke observer after change'); - - destroy(obj); - } - } -); - -moduleFor( - 'Function.prototype.on() helper', - class extends AbstractTestCase { - ['@test sets up an event listener, and can trigger the function on multiple events'](assert) { - if (!FUNCTION_PROTOTYPE_EXTENSIONS || !ENV.EXTEND_PROTOTYPES.Function) { - assert.ok( - 'undefined' === typeof Function.prototype.on, - 'Function.prototype helper disabled' - ); - return; - } - - let MyMixin; - expectDeprecation(() => { - MyMixin = Mixin.create({ - count: 0, - - foo: function () { - set(this, 'count', get(this, 'count') + 1); - }.on('bar', 'baz'), - }); - }, /Function prototype extensions have been deprecated, please migrate from function\(\){}.on\('foo'\) to on\('foo', function\(\) {}\)/); - - let obj = mixin({}, Evented, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke listener immediately'); - - obj.trigger('bar'); - obj.trigger('baz'); - assert.equal(get(obj, 'count'), 2, 'should invoke listeners when events trigger'); - } - - async ['@test can be chained with observes'](assert) { - if (!FUNCTION_PROTOTYPE_EXTENSIONS || !ENV.EXTEND_PROTOTYPES.Function) { - assert.ok('Function.prototype helper disabled'); - return; - } - - let MyMixin; - expectDeprecation(function () { - MyMixin = Mixin.create({ - count: 0, - bay: 'bay', - foo: function () { - set(this, 'count', get(this, 'count') + 1); - } - .observes('bay') - .on('bar'), - }); - }); - - let obj = mixin({}, Evented, MyMixin); - assert.equal(get(obj, 'count'), 0, 'should not invoke listener immediately'); - - set(obj, 'bay', 'BAY'); - obj.trigger('bar'); - await runLoopSettled(); - - assert.equal(get(obj, 'count'), 2, 'should invoke observer and listener'); - - destroy(obj); - } - } -); - -moduleFor( - 'Function.prototype.property() helper', - class extends AbstractTestCase { - ['@test sets up a ComputedProperty'](assert) { - if (!FUNCTION_PROTOTYPE_EXTENSIONS || !ENV.EXTEND_PROTOTYPES.Function) { - assert.ok( - 'undefined' === typeof Function.prototype.property, - 'Function.prototype helper disabled' - ); - return; - } - - let MyClass; - expectDeprecation(function () { - MyClass = EmberObject.extend({ - firstName: null, - lastName: null, - fullName: function () { - return get(this, 'firstName') + ' ' + get(this, 'lastName'); - }.property('firstName', 'lastName'), - }); - }, /Function prototype extensions have been deprecated, please migrate from function\(\){}.property\('bar'\) to computed\('bar', function\(\) {}\)/); - - let obj = MyClass.create({ firstName: 'Fred', lastName: 'Flinstone' }); - assert.equal(get(obj, 'fullName'), 'Fred Flinstone', 'should return the computed value'); - - set(obj, 'firstName', 'Wilma'); - assert.equal(get(obj, 'fullName'), 'Wilma Flinstone', 'should return the new computed value'); - - set(obj, 'lastName', ''); - assert.equal(get(obj, 'fullName'), 'Wilma ', 'should return the new computed value'); - } - } -); diff --git a/packages/@ember/deprecated-features/index.ts b/packages/@ember/deprecated-features/index.ts index 67122f2e569..ea8d6037200 100644 --- a/packages/@ember/deprecated-features/index.ts +++ b/packages/@ember/deprecated-features/index.ts @@ -9,7 +9,6 @@ export const ROUTER_EVENTS = !!'4.0.0'; export const COMPONENT_MANAGER_STRING_LOOKUP = !!'3.8.0'; export const JQUERY_INTEGRATION = !!'3.9.0'; export const APP_CTRL_ROUTER_PROPS = !!'3.10.0-beta.1'; -export const FUNCTION_PROTOTYPE_EXTENSIONS = !!'3.11.0-beta.1'; export const MOUSE_ENTER_LEAVE_MOVE_EVENTS = !!'3.13.0-beta.1'; export const PARTIALS = !!'3.15.0-beta.1'; export const GLOBALS_RESOLVER = !!'3.16.0-beta.1'; diff --git a/tests/docs/expected.js b/tests/docs/expected.js index 4a864a88468..354287d995e 100644 --- a/tests/docs/expected.js +++ b/tests/docs/expected.js @@ -390,7 +390,6 @@ module.exports = { 'objectsAt', 'observeModelType', 'observer', - 'observes', 'off', 'on', 'once',