Skip to content

Commit

Permalink
[DEPRECATION] Add deprecation for Function.prototype extensions.
Browse files Browse the repository at this point in the history
  • Loading branch information
rwjblue committed Apr 15, 2019
1 parent 8880ba8 commit 0c1f920
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 48 deletions.
9 changes: 7 additions & 2 deletions packages/@ember/-internals/environment/lib/env.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FUNCTION_PROTOTYPE_EXTENSIONS } from '@ember/deprecated-features';
import global from './global';

/**
Expand Down Expand Up @@ -155,12 +156,16 @@ export const ENV = {
if (EXTEND_PROTOTYPES !== undefined) {
if (typeof EXTEND_PROTOTYPES === 'object' && EXTEND_PROTOTYPES !== null) {
ENV.EXTEND_PROTOTYPES.String = EXTEND_PROTOTYPES.String !== false;
ENV.EXTEND_PROTOTYPES.Function = EXTEND_PROTOTYPES.Function !== 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;
ENV.EXTEND_PROTOTYPES.Function = isEnabled;
if (FUNCTION_PROTOTYPE_EXTENSIONS) {
ENV.EXTEND_PROTOTYPES.Function = isEnabled;
}
ENV.EXTEND_PROTOTYPES.Array = isEnabled;
}
}
Expand Down
33 changes: 19 additions & 14 deletions packages/@ember/-internals/metal/tests/observer_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
set,
} from '..';
import { moduleFor, AbstractTestCase } from 'internal-test-helpers';
import { FUNCTION_PROTOTYPE_EXTENSIONS } from '@ember/deprecated-features';

function K() {}

Expand Down Expand Up @@ -103,18 +104,20 @@ moduleFor(
assert.equal(observerCount, 10, 'should continue to fire indefinitely');
}

['@test observer added declaratively via brace expansion should fire when property changes'](
['@test observer added via Function.prototype extensions and brace expansion should fire when property changes'](
assert
) {
if (ENV.EXTEND_PROTOTYPES.Function) {
if (!FUNCTION_PROTOTYPE_EXTENSIONS && ENV.EXTEND_PROTOTYPES.Function) {
let obj = {};
let count = 0;

mixin(obj, {
observeFooAndBar: function() {
count++;
}.observes('{foo,bar}'),
});
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');
assert.equal(count, 1, 'observer specified via brace expansion invoked on property change');
Expand All @@ -129,10 +132,10 @@ moduleFor(
}
}

['@test observer specified declaratively via brace expansion should fire when dependent property changes'](
['@test observer specified via Function.prototype extensions via brace expansion should fire when dependent property changes'](
assert
) {
if (ENV.EXTEND_PROTOTYPES.Function) {
if (!FUNCTION_PROTOTYPE_EXTENSIONS && ENV.EXTEND_PROTOTYPES.Function) {
let obj = { baz: 'Initial' };
let count = 0;

Expand All @@ -152,11 +155,13 @@ moduleFor(
})
);

mixin(obj, {
fooAndBarWatcher: function() {
count++;
}.observes('{foo,bar}'),
});
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');
Expand Down
33 changes: 32 additions & 1 deletion packages/@ember/-internals/runtime/lib/ext/function.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

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 (ENV.EXTEND_PROTOTYPES.Function) {
if (FUNCTION_PROTOTYPE_EXTENSIONS && ENV.EXTEND_PROTOTYPES.Function) {
Object.defineProperties(Function.prototype, {
/**
The `property` extension of Javascript's Function prototype is available
Expand Down Expand Up @@ -77,6 +79,15 @@ if (ENV.EXTEND_PROTOTYPES.Function) {
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',
}
);
return computed(...arguments, this);
},
},
Expand Down Expand Up @@ -113,6 +124,16 @@ if (ENV.EXTEND_PROTOTYPES.Function) {
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',
}
);

return observer(...arguments, this);
},
},
Expand Down Expand Up @@ -147,6 +168,16 @@ if (ENV.EXTEND_PROTOTYPES.Function) {
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',
}
);

return on(...arguments, this);
},
},
Expand Down
75 changes: 44 additions & 31 deletions packages/@ember/-internals/runtime/tests/ext/function_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,30 @@ import { Mixin, mixin, get, set } from '@ember/-internals/metal';
import EmberObject from '../../lib/system/object';
import Evented from '../../lib/mixins/evented';
import { moduleFor, AbstractTestCase } from 'internal-test-helpers';
import { FUNCTION_PROTOTYPE_EXTENSIONS } from '@ember/deprecated-features';

moduleFor(
'Function.prototype.observes() helper',
class extends AbstractTestCase {
['@test global observer helper takes multiple params'](assert) {
if (!ENV.EXTEND_PROTOTYPES.Function) {
if (!FUNCTION_PROTOTYPE_EXTENSIONS || !ENV.EXTEND_PROTOTYPES.Function) {
assert.ok(
'undefined' === typeof Function.prototype.observes,
'Function.prototype helper disabled'
);
return;
}

let MyMixin = Mixin.create({
count: 0,
let MyMixin;
expectDeprecation(() => {
MyMixin = Mixin.create({
count: 0,

foo: function() {
set(this, 'count', get(this, 'count') + 1);
}.observes('bar', 'baz'),
});
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');
Expand All @@ -38,21 +42,24 @@ moduleFor(
'Function.prototype.on() helper',
class extends AbstractTestCase {
['@test sets up an event listener, and can trigger the function on multiple events'](assert) {
if (!ENV.EXTEND_PROTOTYPES.Function) {
if (!FUNCTION_PROTOTYPE_EXTENSIONS || !ENV.EXTEND_PROTOTYPES.Function) {
assert.ok(
'undefined' === typeof Function.prototype.on,
'Function.prototype helper disabled'
);
return;
}

let MyMixin = Mixin.create({
count: 0,
let MyMixin;
expectDeprecation(() => {
MyMixin = Mixin.create({
count: 0,

foo: function() {
set(this, 'count', get(this, 'count') + 1);
}.on('bar', 'baz'),
});
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');
Expand All @@ -63,19 +70,22 @@ moduleFor(
}

['@test can be chained with observes'](assert) {
if (!ENV.EXTEND_PROTOTYPES.Function) {
if (!FUNCTION_PROTOTYPE_EXTENSIONS || !ENV.EXTEND_PROTOTYPES.Function) {
assert.ok('Function.prototype helper disabled');
return;
}

let MyMixin = Mixin.create({
count: 0,
bay: 'bay',
foo: function() {
set(this, 'count', get(this, 'count') + 1);
}
.observes('bay')
.on('bar'),
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);
Expand All @@ -92,21 +102,24 @@ moduleFor(
'Function.prototype.property() helper',
class extends AbstractTestCase {
['@test sets up a ComputedProperty'](assert) {
if (!ENV.EXTEND_PROTOTYPES.Function) {
if (!FUNCTION_PROTOTYPE_EXTENSIONS || !ENV.EXTEND_PROTOTYPES.Function) {
assert.ok(
'undefined' === typeof Function.prototype.property,
'Function.prototype helper disabled'
);
return;
}

let MyClass = EmberObject.extend({
firstName: null,
lastName: null,
fullName: function() {
return get(this, 'firstName') + ' ' + get(this, 'lastName');
}.property('firstName', 'lastName'),
});
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');
Expand Down
1 change: 1 addition & 0 deletions packages/@ember/deprecated-features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export const COMPONENT_MANAGER_STRING_LOOKUP = !!'3.8.0';
export const JQUERY_INTEGRATION = !!'3.9.0';
export const ALIAS_METHOD = !!'3.9.0';
export const APP_CTRL_ROUTER_PROPS = !!'3.10.0-beta.1';
export const FUNCTION_PROTOTYPE_EXTENSIONS = !!'3.11.0-beta.1';

0 comments on commit 0c1f920

Please sign in to comment.