diff --git a/packages/ember-htmlbars/lib/keywords/unbound.js b/packages/ember-htmlbars/lib/keywords/unbound.js
index e312b4f026d..af8eae44223 100644
--- a/packages/ember-htmlbars/lib/keywords/unbound.js
+++ b/packages/ember-htmlbars/lib/keywords/unbound.js
@@ -1,6 +1,20 @@
/**
-@module ember
-@submodule ember-htmlbars
+ The `{{unbound}}` helper can be used with bound helper invocations to
+ render them in their unbound form.
+
+ ```handlebars
+ {{unbound (capitalize name)}}
+ ```
+
+ In the aforementioned example, if the `name` property changes, the helper
+ will not re-render.
+
+ @module ember
+ @submodule ember-templates
+
+ @method unbound
+ @for Ember.Templates.helpers
+ @public
*/
export default function unbound(morph, env, scope, originalParams, hash, template, inverse) {
diff --git a/packages/ember-htmlbars/tests/helpers/collection_test.js b/packages/ember-htmlbars/tests/helpers/collection_test.js
index 57f7a00b689..e0ca071614f 100644
--- a/packages/ember-htmlbars/tests/helpers/collection_test.js
+++ b/packages/ember-htmlbars/tests/helpers/collection_test.js
@@ -199,6 +199,7 @@ QUnit.test("empty views should be removed when content is added to the collectio
});
view = EmberView.create({
+ _viewRegistry: {},
listView: ListView,
listController: listController,
template: compile('{{#collection view.listView content=view.listController tagName="table"}}
{{view.content.title}} | {{/collection}}')
diff --git a/packages/ember-htmlbars/tests/helpers/with_test.js b/packages/ember-htmlbars/tests/helpers/with_test.js
index 41797904f1f..827e07b6c5e 100644
--- a/packages/ember-htmlbars/tests/helpers/with_test.js
+++ b/packages/ember-htmlbars/tests/helpers/with_test.js
@@ -249,6 +249,8 @@ QUnit.test("it should wrap context with object controller [DEPRECATED]", functio
name: 'Bob Loblaw'
});
+ expectDeprecation(/Using the {{with}} helper with a `controller` specified/);
+
view = EmberView.create({
container: container,
template: compile('{{#with view.person controller="person"}}{{controllerName}}{{/with}}'),
@@ -379,6 +381,8 @@ QUnit.test("it should wrap keyword with object controller [DEPRECATED]", functio
});
QUnit.test("destroys the controller generated with {{with foo controller='blah'}} [DEPRECATED]", function() {
+ expectDeprecation(/Using the {{with}} helper with a `controller` specified/);
+
var destroyed = false;
var Controller = EmberController.extend({
willDestroy() {
@@ -433,10 +437,15 @@ QUnit.test("destroys the controller generated with {{with foo as bar controller=
name: 'Bob Loblaw'
});
+ var template;
+ expectDeprecation(function() {
+ template = compile('{{#with person controller="person" as |steve|}}{{controllerName}}{{/with}}');
+ }, `Using the {{with}} helper with a \`controller\` specified (L1:C0) is deprecated and will be removed in 2.0.0.`);
+
view = EmberView.create({
- container: container,
- template: compile('{{#with person controller="person" as |steve|}}{{controllerName}}{{/with}}'),
- controller: parentController
+ controller: parentController,
+ template,
+ container
});
registry.register('controller:person', Controller);
diff --git a/packages/ember-metal/lib/computed.js b/packages/ember-metal/lib/computed.js
index 3f0a348d945..34383b5d2bc 100644
--- a/packages/ember-metal/lib/computed.js
+++ b/packages/ember-metal/lib/computed.js
@@ -1,3 +1,4 @@
+import Ember from 'ember-metal/core';
import { set } from "ember-metal/property_set";
import {
meta,
@@ -251,6 +252,13 @@ ComputedPropertyPrototype.property = function() {
var args;
var addArg = function(property) {
+ Ember.deprecate(
+ `Depending on arrays using a dependent key ending with \`@each\` is deprecated. ` +
+ `Please refactor from \`Ember.computed('${property}', function() {});\` to \`Ember.computed('${property.slice(0, -6)}.[]', function() {})\`.`,
+ property.slice(-5) !== '@each',
+ { id: 'ember-metal.@each-dependent-key-leaf', until: '2.0.0' }
+ );
+
args.push(property);
};
diff --git a/packages/ember-metal/lib/core.js b/packages/ember-metal/lib/core.js
index 363c160f660..767f1c19c95 100644
--- a/packages/ember-metal/lib/core.js
+++ b/packages/ember-metal/lib/core.js
@@ -208,7 +208,6 @@ Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true;
An empty function useful for some operations. Always returns `this`.
@method K
- @private
@return {Object}
@public
*/
diff --git a/packages/ember-metal/lib/expand_properties.js b/packages/ember-metal/lib/expand_properties.js
index 28045b053ef..832d85daa4f 100644
--- a/packages/ember-metal/lib/expand_properties.js
+++ b/packages/ember-metal/lib/expand_properties.js
@@ -28,7 +28,8 @@ var SPLIT_REGEX = /\{|\}/;
Ember.expandProperties('{foo}.bar.{baz}') //=> 'foo.bar.baz'
```
- @method
+ @method expandProperties
+ @for Ember
@private
@param {String} pattern The property pattern to expand.
@param {Function} callback The callback to invoke. It is invoked once per
diff --git a/packages/ember-metal/lib/merge.js b/packages/ember-metal/lib/merge.js
index eaf63297ab8..194b93b85d4 100644
--- a/packages/ember-metal/lib/merge.js
+++ b/packages/ember-metal/lib/merge.js
@@ -15,7 +15,7 @@ import keys from 'ember-metal/keys';
@param {Object} original The object to merge into
@param {Object} updates The object to copy properties from
@return {Object}
- @private
+ @public
*/
export default function merge(original, updates) {
if (!updates || typeof updates !== 'object') {
diff --git a/packages/ember-metal/lib/mixin.js b/packages/ember-metal/lib/mixin.js
index 933d45fb17c..b5a7fee2a55 100644
--- a/packages/ember-metal/lib/mixin.js
+++ b/packages/ember-metal/lib/mixin.js
@@ -813,7 +813,16 @@ export function observer(...args) {
var func = args.slice(-1)[0];
var paths;
- var addWatchedProperty = function(path) { paths.push(path); };
+ var addWatchedProperty = function(path) {
+ Ember.deprecate(
+ `Depending on arrays using a dependent key ending with \`@each\` is deprecated. ` +
+ `Please refactor from \`Ember.observer('${path}', function() {});\` to \`Ember.computed('${path.slice(0, -6)}.[]', function() {})\`.`,
+ path.slice(-5) !== '@each',
+ { id: 'ember-metal.@each-dependent-key-leaf', until: '2.0.0' }
+ );
+
+ paths.push(path);
+ };
var _paths = args.slice(0, -1);
if (typeof func !== "function") {
diff --git a/packages/ember-metal/tests/computed_test.js b/packages/ember-metal/tests/computed_test.js
index 1885e320751..6e7e417d870 100644
--- a/packages/ember-metal/tests/computed_test.js
+++ b/packages/ember-metal/tests/computed_test.js
@@ -59,6 +59,16 @@ QUnit.test('defining computed property should invoke property on set', function(
equal(get(obj, 'foo'), 'computed bar', 'should return new value');
});
+QUnit.test('defining a computed property with a dependent key ending with @each is deprecated', function() {
+ expectDeprecation(function() {
+ computed('blazo.@each', function() { });
+ }, `Depending on arrays using a dependent key ending with \`@each\` is deprecated. Please refactor from \`Ember.computed('blazo.@each', function() {});\` to \`Ember.computed('blazo.[]', function() {})\`.`);
+
+ expectDeprecation(function() {
+ computed('qux', 'zoopa.@each', function() { });
+ }, `Depending on arrays using a dependent key ending with \`@each\` is deprecated. Please refactor from \`Ember.computed('zoopa.@each', function() {});\` to \`Ember.computed('zoopa.[]', function() {})\`.`);
+});
+
var objA, objB;
QUnit.module('computed should inherit through prototype', {
setup() {
diff --git a/packages/ember-routing-htmlbars/tests/helpers/element_action_test.js b/packages/ember-routing-htmlbars/tests/helpers/element_action_test.js
index c7bce884760..f0b0002a100 100644
--- a/packages/ember-routing-htmlbars/tests/helpers/element_action_test.js
+++ b/packages/ember-routing-htmlbars/tests/helpers/element_action_test.js
@@ -166,6 +166,8 @@ QUnit.test("should target the current controller inside an {{each}} loop [DEPREC
QUnit.test("should target the with-controller inside an {{#with controller='person'}} [DEPRECATED]", function() {
var registeredTarget;
+ expectDeprecation(/Using the {{with}} helper with a `controller` specified/);
+
ActionHelper.registerAction = function({ node }) {
registeredTarget = node.state.target;
};
diff --git a/packages/ember-runtime/lib/computed/reduce_computed.js b/packages/ember-runtime/lib/computed/reduce_computed.js
index 8ef22b10087..fafcaac782b 100644
--- a/packages/ember-runtime/lib/computed/reduce_computed.js
+++ b/packages/ember-runtime/lib/computed/reduce_computed.js
@@ -203,7 +203,7 @@ DependentArraysObserver.prototype = {
},
resetTransformations(dependentKey, observerContexts) {
- this.trackedArraysByGuid[dependentKey] = new TrackedArray(observerContexts);
+ this.trackedArraysByGuid[dependentKey] = new TrackedArray(observerContexts, true);
},
trackAdd(dependentKey, index, newItems) {
diff --git a/packages/ember-runtime/lib/computed/reduce_computed_macros.js b/packages/ember-runtime/lib/computed/reduce_computed_macros.js
index 0674667dba0..38fc7cebe60 100644
--- a/packages/ember-runtime/lib/computed/reduce_computed_macros.js
+++ b/packages/ember-runtime/lib/computed/reduce_computed_macros.js
@@ -291,7 +291,7 @@ export function filter(dependentKey, callback) {
_suppressDeprecation: true,
initialize(array, changeMeta, instanceMeta) {
- instanceMeta.filteredArrayIndexes = new SubArray();
+ instanceMeta.filteredArrayIndexes = new SubArray(undefined, true);
},
addedItem(array, item, changeMeta, instanceMeta) {
diff --git a/packages/ember-runtime/lib/mixins/enumerable.js b/packages/ember-runtime/lib/mixins/enumerable.js
index 4d10636c68a..f75b7bf96d3 100644
--- a/packages/ember-runtime/lib/mixins/enumerable.js
+++ b/packages/ember-runtime/lib/mixins/enumerable.js
@@ -259,7 +259,7 @@ export default Mixin.create({
@param {Function} callback The callback to execute
@param {Object} [target] The target object to use
@return {Object} receiver
- @private
+ @public
*/
forEach(callback, target) {
if (typeof callback !== 'function') {
@@ -643,7 +643,7 @@ export default Mixin.create({
@param {Function} callback The callback to execute
@param {Object} [target] The target object to use
@return {Boolean}
- @private
+ @public
*/
every(callback, target) {
return !this.find(function(x, idx, i) {
@@ -921,7 +921,7 @@ export default Mixin.create({
@method compact
@return {Array} the array without null and undefined elements.
- @private
+ @public
*/
compact() {
return this.filter(function(value) {
@@ -942,7 +942,7 @@ export default Mixin.create({
@method without
@param {Object} value
@return {Ember.Enumerable}
- @private
+ @public
*/
without(value) {
if (!this.contains(value)) {
@@ -1196,7 +1196,7 @@ export default Mixin.create({
@param {String} property name(s) to sort on
@return {Array} The sorted array.
@since 1.2.0
- @private
+ @public
*/
sortBy() {
var sortKeys = arguments;
diff --git a/packages/ember-runtime/lib/mixins/sortable.js b/packages/ember-runtime/lib/mixins/sortable.js
index d0a7f439c29..65a1f125e16 100644
--- a/packages/ember-runtime/lib/mixins/sortable.js
+++ b/packages/ember-runtime/lib/mixins/sortable.js
@@ -166,7 +166,7 @@ export default Mixin.create(MutableEnumerable, {
@property arrangedContent
@private
*/
- arrangedContent: computed('content', 'sortProperties.@each', {
+ arrangedContent: computed('content', 'sortProperties.[]', {
get(key) {
var content = get(this, 'content');
var isSorted = get(this, 'isSorted');
diff --git a/packages/ember-runtime/lib/system/array_proxy.js b/packages/ember-runtime/lib/system/array_proxy.js
index 9cf7b56cbaa..e94fcf7984e 100644
--- a/packages/ember-runtime/lib/system/array_proxy.js
+++ b/packages/ember-runtime/lib/system/array_proxy.js
@@ -66,7 +66,7 @@ function K() { return this; }
@namespace Ember
@extends Ember.Object
@uses Ember.MutableArray
- @private
+ @public
*/
var ArrayProxy = EmberObject.extend(MutableArray, {
diff --git a/packages/ember-runtime/lib/system/subarray.js b/packages/ember-runtime/lib/system/subarray.js
index d4ef6c7a86f..2b88c9489eb 100644
--- a/packages/ember-runtime/lib/system/subarray.js
+++ b/packages/ember-runtime/lib/system/subarray.js
@@ -1,3 +1,4 @@
+import Ember from 'ember-metal/core';
import EmberError from "ember-metal/error";
import { forEach } from "ember-metal/enumerable_utils";
@@ -20,8 +21,14 @@ export default SubArray;
@namespace Ember
@private
*/
-function SubArray(length) {
- if (arguments.length < 1) { length = 0; }
+function SubArray(length, _suppressDeprecation) {
+ Ember.deprecate(
+ 'Ember.SubArray will be removed in 2.0.0.',
+ _suppressDeprecation,
+ { id: 'ember-metal.sub-array', until: '2.0.0' }
+ );
+
+ if (length === undefined) { length = 0; }
if (length > 0) {
this._operations = [new Operation(RETAIN, length)];
diff --git a/packages/ember-runtime/lib/system/tracked_array.js b/packages/ember-runtime/lib/system/tracked_array.js
index 5cca92c4118..3e4e0b495c7 100644
--- a/packages/ember-runtime/lib/system/tracked_array.js
+++ b/packages/ember-runtime/lib/system/tracked_array.js
@@ -1,3 +1,4 @@
+import Ember from 'ember-metal/core';
import { get } from "ember-metal/property_get";
import { forEach } from "ember-metal/enumerable_utils";
@@ -18,7 +19,13 @@ export default TrackedArray;
the initial items for the starting state of retain:n.
@private
*/
-function TrackedArray(items) {
+function TrackedArray(items, _suppressDeprecation) {
+ Ember.deprecate(
+ 'Ember.TrackedArray will be removed in 2.0.0.',
+ _suppressDeprecation,
+ { id: 'ember-metal.tracked-array', until: '2.0.0' }
+ );
+
if (arguments.length < 1) { items = []; }
var length = get(items, 'length');
diff --git a/packages/ember-runtime/tests/system/subarray_test.js b/packages/ember-runtime/tests/system/subarray_test.js
index 51f5de51d82..981f9f5bd97 100644
--- a/packages/ember-runtime/tests/system/subarray_test.js
+++ b/packages/ember-runtime/tests/system/subarray_test.js
@@ -5,6 +5,7 @@ var subarray;
QUnit.module('SubArray', {
setup() {
+ expectDeprecation('Ember.SubArray will be removed in 2.0.0.');
subarray = new SubArray();
}
});
diff --git a/packages/ember-runtime/tests/system/tracked_array_test.js b/packages/ember-runtime/tests/system/tracked_array_test.js
index 8adbd721680..a66324b1a50 100644
--- a/packages/ember-runtime/tests/system/tracked_array_test.js
+++ b/packages/ember-runtime/tests/system/tracked_array_test.js
@@ -5,7 +5,11 @@ var RETAIN = TrackedArray.RETAIN;
var INSERT = TrackedArray.INSERT;
var DELETE = TrackedArray.DELETE;
-QUnit.module('Ember.TrackedArray');
+QUnit.module('Ember.TrackedArray', {
+ setup: function() {
+ expectDeprecation('Ember.TrackedArray will be removed in 2.0.0.');
+ }
+});
QUnit.test("operations for a tracked array of length n are initially retain:n", function() {
trackedArray = new TrackedArray([1,2,3,4]);
diff --git a/packages/ember-template-compiler/lib/main.js b/packages/ember-template-compiler/lib/main.js
index e0900e02ca9..e040f8997d8 100644
--- a/packages/ember-template-compiler/lib/main.js
+++ b/packages/ember-template-compiler/lib/main.js
@@ -18,6 +18,7 @@ import TransformAngleBracketComponents from "ember-template-compiler/plugins/tra
import TransformInputOnToOnEvent from "ember-template-compiler/plugins/transform-input-on-to-onEvent";
import DeprecateViewAndControllerPaths from "ember-template-compiler/plugins/deprecate-view-and-controller-paths";
import DeprecateViewHelper from "ember-template-compiler/plugins/deprecate-view-helper";
+import DeprecateWithController from 'ember-template-compiler/plugins/deprecate-with-controller';
// used for adding Ember.Handlebars.compile for backwards compat
import "ember-template-compiler/compat";
@@ -36,6 +37,7 @@ registerPlugin('ast', TransformAngleBracketComponents);
registerPlugin('ast', TransformInputOnToOnEvent);
registerPlugin('ast', DeprecateViewAndControllerPaths);
registerPlugin('ast', DeprecateViewHelper);
+registerPlugin('ast', DeprecateWithController);
export {
_Ember,
diff --git a/packages/ember-template-compiler/lib/plugins/deprecate-with-controller.js b/packages/ember-template-compiler/lib/plugins/deprecate-with-controller.js
new file mode 100644
index 00000000000..bb01c167942
--- /dev/null
+++ b/packages/ember-template-compiler/lib/plugins/deprecate-with-controller.js
@@ -0,0 +1,64 @@
+import Ember from 'ember-metal/core';
+import calculateLocationDisplay from 'ember-template-compiler/system/calculate-location-display';
+
+/**
+ @module ember
+ @submodule ember-template-compiler
+*/
+
+/**
+ An HTMLBars AST transformation that deprecates usage of `controller` with the `{{with}}`
+ helper.
+
+ @private
+ @class DeprecateWithController
+*/
+function DeprecateWithController(options) {
+ // set later within HTMLBars to the syntax package
+ this.syntax = null;
+ this.options = options || {};
+}
+
+/**
+ @private
+ @method transform
+ @param {AST} ast The AST to be transformed.
+*/
+DeprecateWithController.prototype.transform = function DeprecateWithController_transform(ast) {
+ const pluginContext = this;
+ const walker = new pluginContext.syntax.Walker();
+ const moduleName = pluginContext.options.moduleName;
+
+ walker.visit(ast, function(node) {
+ if (pluginContext.validate(node)) {
+ let moduleInfo = calculateLocationDisplay(moduleName, node.loc);
+
+ Ember.deprecate(
+ `Using the {{with}} helper with a \`controller\` specified ${moduleInfo}is deprecated and will be removed in 2.0.0.`,
+ false,
+ { id: 'ember-template-compiler.with-controller', until: '2.0.0' }
+ );
+ }
+ });
+
+ return ast;
+};
+
+DeprecateWithController.prototype.validate = function TransformWithAsToHash_validate(node) {
+ return (node.type === 'BlockStatement' || node.type === 'MustacheStatement') &&
+ node.path.original === 'with' &&
+ hashPairForKey(node.hash, 'controller');
+};
+
+function hashPairForKey(hash, key) {
+ for (let i = 0, l = hash.pairs.length; i < l; i++) {
+ let pair = hash.pairs[i];
+ if (pair.key === key) {
+ return pair;
+ }
+ }
+
+ return false;
+}
+
+export default DeprecateWithController;
diff --git a/packages/ember-template-compiler/tests/plugins/deprecate-with-controller-test.js b/packages/ember-template-compiler/tests/plugins/deprecate-with-controller-test.js
new file mode 100644
index 00000000000..8ed20d992f7
--- /dev/null
+++ b/packages/ember-template-compiler/tests/plugins/deprecate-with-controller-test.js
@@ -0,0 +1,13 @@
+import { compile } from 'ember-template-compiler';
+
+QUnit.module('ember-template-compiler: deprecate-with-controller');
+
+QUnit.test('Using `{{with}}` with `controller` hash argument provides a deprecation', function() {
+ expect(1);
+
+ expectDeprecation(function() {
+ compile('{{#with controller="foo"}}{{/with}}', {
+ moduleName: 'foo/bar/baz'
+ });
+ }, `Using the {{with}} helper with a \`controller\` specified ('foo/bar/baz' @ L1:C0) is deprecated and will be removed in 2.0.0.`);
+});
diff --git a/packages/ember-views/lib/views/select.js b/packages/ember-views/lib/views/select.js
index a2e38a488d0..e68680f0332 100644
--- a/packages/ember-views/lib/views/select.js
+++ b/packages/ember-views/lib/views/select.js
@@ -499,7 +499,7 @@ var Select = View.extend({
});
return groupedContent;
- }).property('optionGroupPath', 'content.@each'),
+ }).property('optionGroupPath', 'content.[]'),
/**
The view class for option.
@@ -519,7 +519,7 @@ var Select = View.extend({
}
},
- selectionDidChange: observer('selection.@each', function() {
+ selectionDidChange: observer('selection.[]', function() {
var selection = get(this, 'selection');
if (get(this, 'multiple')) {
if (!isArray(selection)) {
diff --git a/packages/ember-views/tests/views/view/child_views_test.js b/packages/ember-views/tests/views/view/child_views_test.js
index 23431d8d507..f05e1ee2be0 100644
--- a/packages/ember-views/tests/views/view/child_views_test.js
+++ b/packages/ember-views/tests/views/view/child_views_test.js
@@ -103,6 +103,10 @@ QUnit.test('should remove childViews inside {{if}} on destroy', function() {
run(outerView, 'set', 'value', false);
equal(outerView.get('childViews.length'), 0, 'expected no views to be leaked');
+
+ run(function() {
+ outerView.destroy();
+ });
});
QUnit.test('should remove childViews inside {{each}} on destroy', function() {
@@ -151,4 +155,8 @@ QUnit.test('should remove childViews inside {{each}} on destroy', function() {
run(outerView, 'set', 'value', false);
equal(outerView.get('childViews.length'), 0, 'expected no views to be leaked');
+
+ run(function() {
+ outerView.destroy();
+ });
});
diff --git a/tests/index.html b/tests/index.html
index ca718ab752c..63ea29602f0 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -104,7 +104,7 @@
return QUnit.test(string, callback);
};
} else {
- var skip = QUnit.skip;
+ var skip = QUnit.skip || function() { };
QUnit.skip = function(string, callback) {
string = "SKIPPED: " + string;
return skip(string, callback);