From 5c03a454d2987305e891145fc9049b063bc3010a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Kvasni=C4=8Dka?= Date: Thu, 29 Dec 2016 09:28:10 +0100 Subject: [PATCH 001/224] fixed string capitalize for accented characters --- packages/ember-runtime/lib/system/string.js | 2 +- .../ember-runtime/tests/system/string/capitalize_test.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/ember-runtime/lib/system/string.js b/packages/ember-runtime/lib/system/string.js index 307350e05bc..28a01029274 100644 --- a/packages/ember-runtime/lib/system/string.js +++ b/packages/ember-runtime/lib/system/string.js @@ -60,7 +60,7 @@ const UNDERSCORE_CACHE = new Cache(1000, function(str) { replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase(); }); -const STRING_CAPITALIZE_REGEXP = (/(^|\/)([a-z])/g); +const STRING_CAPITALIZE_REGEXP = (/(^|\/)([a-z\u00C0-\u024F])/g); const CAPITALIZE_CACHE = new Cache(1000, function(str) { return str.replace(STRING_CAPITALIZE_REGEXP, function(match, separator, chr) { diff --git a/packages/ember-runtime/tests/system/string/capitalize_test.js b/packages/ember-runtime/tests/system/string/capitalize_test.js index e5701ede117..cc56c37a86a 100644 --- a/packages/ember-runtime/tests/system/string/capitalize_test.js +++ b/packages/ember-runtime/tests/system/string/capitalize_test.js @@ -64,3 +64,10 @@ QUnit.test('capitalize namespaced dasherized string', function() { deepEqual('private-docs/owner-invoice'.capitalize(), 'Private-docs/Owner-invoice'); } }); + +QUnit.test('capitalize string with accent character', function() { + deepEqual(capitalize('šabc'), 'Šabc'); + if (ENV.EXTEND_PROTOTYPES.String) { + deepEqual('šabc'.capitalize(), 'Šabc'); + } +}); From e9f65000e5ad43c2e1c8121f0724c94a2af169ec Mon Sep 17 00:00:00 2001 From: Chris Westra Date: Fri, 3 Mar 2017 12:50:48 -0500 Subject: [PATCH 002/224] Document setupController hook behavior further The default implementation doesn't update the `model` property of the controller if the resolved model is undefined. This isn't currently documented. --- packages/ember-routing/lib/system/route.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index 50d2df4aab7..15d905cf61e 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -1703,7 +1703,8 @@ let Route = EmberObject.extend(ActionHandler, Evented, { model supplied by the `model` hook. By default, the `setupController` hook sets the `model` property of - the controller to the `model`. + the controller to the `model`. If `model` is `undefined`, the default + implementation will _not_ update the `model` property of the controller. If you implement the `setupController` hook in your Route, it will prevent this default behavior. If you want to preserve that behavior From 4c8efd15e5063fcf200abf13950151071369c827 Mon Sep 17 00:00:00 2001 From: Chris Westra Date: Mon, 3 Apr 2017 12:28:38 -0400 Subject: [PATCH 003/224] Better wording for setupController documentation One good sentence is better than two. --- packages/ember-routing/lib/system/route.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index 15d905cf61e..be0232a3614 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -1703,8 +1703,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { model supplied by the `model` hook. By default, the `setupController` hook sets the `model` property of - the controller to the `model`. If `model` is `undefined`, the default - implementation will _not_ update the `model` property of the controller. + the controller to the specified `model` when it is not `undefined`. If you implement the `setupController` hook in your Route, it will prevent this default behavior. If you want to preserve that behavior From 4863d9c143388504943bc94aa99753f5b527f70a Mon Sep 17 00:00:00 2001 From: Elad Shahar Date: Thu, 27 Apr 2017 13:59:45 -0400 Subject: [PATCH 004/224] [DOC release] Make `Ember.expandProperties` public --- packages/ember-metal/lib/expand_properties.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-metal/lib/expand_properties.js b/packages/ember-metal/lib/expand_properties.js index 0f9d3f8c671..327095fae42 100644 --- a/packages/ember-metal/lib/expand_properties.js +++ b/packages/ember-metal/lib/expand_properties.js @@ -29,7 +29,7 @@ var END_WITH_EACH_REGEX = /\.@each$/; @method expandProperties @for Ember - @private + @public @param {String} pattern The property pattern to expand. @param {Function} callback The callback to invoke. It is invoked once per expansion, and is passed the expansion. From 7f57812c16e42cb572c272a17ce5b687b07bbea4 Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 29 Mar 2017 14:02:47 +0500 Subject: [PATCH 005/224] using es6 for trigger method --- packages/ember-views/lib/views/core_view.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/ember-views/lib/views/core_view.js b/packages/ember-views/lib/views/core_view.js index 028cdf9f813..db551e7281e 100644 --- a/packages/ember-views/lib/views/core_view.js +++ b/packages/ember-views/lib/views/core_view.js @@ -67,15 +67,10 @@ const CoreView = FrameworkObject.extend(Evented, ActionHandler, { @param name {String} @private */ - trigger() { + trigger(name, ...args) { this._super(...arguments); - let name = arguments[0]; let method = this[name]; if (method) { - let args = new Array(arguments.length - 1); - for (let i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } return method.apply(this, args); } }, From 62aaae02656ed14859588dc7edfe34118337e161 Mon Sep 17 00:00:00 2001 From: Andreas Solleder Date: Fri, 19 May 2017 20:43:40 +0200 Subject: [PATCH 006/224] fix typos with misspell This PR is part of a campaign to fix a lot of typos on github! You can see the progress on https://github.com/fixTypos/fix_typos/ https://github.com/client9/misspell --- CHANGELOG.md | 10 +++++----- CONTRIBUTING.md | 2 +- packages/container/lib/container.js | 2 +- packages/container/lib/registry.js | 2 +- .../ember-glimmer/lib/components/link-to.js | 2 +- packages/ember-glimmer/lib/helpers/action.js | 2 +- packages/ember-glimmer/lib/helpers/get.js | 2 +- packages/ember-glimmer/lib/renderer.js | 2 +- packages/ember-glimmer/lib/syntax.js | 2 +- .../components/attrs-lookup-test.js | 2 +- .../components/contextual-components-test.js | 12 ++++++------ .../components/curly-components-test.js | 2 +- packages/ember-metal/lib/run_loop.js | 18 +++++++++--------- .../ember-metal/tests/accessors/get_test.js | 6 +++--- packages/ember-metal/tests/events_test.js | 2 +- .../tests/injected_property_test.js | 2 +- .../ember-metal/tests/mixin/observer_test.js | 2 +- packages/ember-routing/lib/ext/controller.js | 2 +- packages/ember-routing/lib/system/router.js | 4 ++-- .../lib/mixins/container_proxy.js | 2 +- .../array_proxy/arranged_content_test.js | 2 +- .../system/array_proxy/content_change_test.js | 2 +- .../ember-views/lib/mixins/text_support.js | 2 +- packages/ember-views/lib/system/utils.js | 2 +- packages/ember/tests/routing/basic_test.js | 2 +- .../ember/tests/routing/query_params_test.js | 2 +- .../lib/external-helpers-dev.js | 2 +- 27 files changed, 47 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 751ee0198ae..e8ca5f8ab2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -604,7 +604,7 @@ ### 1.13.10 (September 6, 2015) - [#12104](https://github.com/emberjs/ember.js/pull/12104) [BUGFIX] Ensure `concatenatedProperties` are not stomped. -- [#12256](https://github.com/emberjs/ember.js/pull/12256) [BUGFIX] Ensure concat streams unsubscribe properly. Fixes memory leak with attributes specified within quotes in the template (i.e. `
`). +- [#12256](https://github.com/emberjs/ember.js/pull/12256) [BUGFIX] Ensure concat streams unsubscribe properly. Fixes memory leak with attributes specified within quotes in the template (i.e. `
`). - [#12272](https://github.com/emberjs/ember.js/pull/12272) [BUGFIX] Update HTMLBars to fix memory leak when an `{{each}}` is inside an `{{if}}`. ### 1.13.9 (August 22, 2015) @@ -878,7 +878,7 @@ * `removeAttribute` fix for IE <11 and SVG. * Disable `cloneNodes` in IE8. * Improve HTML validation and error messages thrown. - * Fix a number of template compliation issues in IE8. + * Fix a number of template compilation issues in IE8. * Use the correct namespace in `parseHTML` (fixes various issues that occur when changing to and from alternate namespaces). * Ensure values are converted to `String`'s when setting attributes (fixes issues in IE10 & IE11). @@ -1116,7 +1116,7 @@ Clearly, `component-a` has subscribed to `some-other-component`'s `action`. Prev ### Ember 1.6.0 (July, 7, 2014) * [BREAKING BUGFIX] An empty array is treated as falsy value in `bind-attr` to be in consistent - with `if` helper. Breaking for apps that relies on the previous behaviour which treats an empty + with `if` helper. Breaking for apps that relies on the previous behavior which treats an empty array as truthy value in `bind-attr`. * [BUGFIX] Ensure itemController's do not leak by tying them to the parent controller lifecycle. * [BUGFIX] Spaces in brace expansion throws an error. @@ -1955,7 +1955,7 @@ Clearly, `component-a` has subscribed to `some-other-component`'s `action`. Prev * Various enhancements to bound helpers: adds multiple property support to bound helpers, adds bind-able options hash properties, adds {{unbound}} helper support to render unbound form of helpers. * Add App.inject * Add Ember.EnumberableUtils.intersection -* Deprecate Controller#controllerFor in favour of Controller#needs +* Deprecate Controller#controllerFor in favor of Controller#needs * Adds `bubbles` property to Ember.TextField * Allow overriding of Ember.Router#handleURL * Allow libraries loaded before Ember to tie into Ember load hooks @@ -1987,7 +1987,7 @@ Clearly, `component-a` has subscribed to `some-other-component`'s `action`. Prev * Add `action` support to Ember.TextField * Warn about using production builds in localhost * Update Metamorph -* Deprecate Ember.alias in favour of Ember.aliasMethod +* Deprecate Ember.alias in favor of Ember.aliasMethod * Add Ember.computed.alias * Allow chaining on DeferredMixin#then * ArrayController learned itemControllerClass. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8073ba64a75..b2becae26f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,7 +56,7 @@ original notice. * If you submit a feature request as an issue, you will be invited to follow the [instructions in this document](https://github.com/emberjs/ember.js/blob/master/CONTRIBUTING.md#requesting-a-feature) and the issue will be closed -* Issues that become inactive will be labelled accordingly +* Issues that become inactive will be labeled accordingly to inform the original poster and Ember contributors that the issue should be closed since the issue is no longer actionable. The issue can be reopened at a later time if needed, e.g. becomes actionable again. diff --git a/packages/container/lib/container.js b/packages/container/lib/container.js index 1994ab8b600..74a2f34313e 100644 --- a/packages/container/lib/container.js +++ b/packages/container/lib/container.js @@ -60,7 +60,7 @@ Container.prototype = { /** Given a fullName return a corresponding instance. - The default behaviour is for lookup to return a singleton instance. + The default behavior is for lookup to return a singleton instance. The singleton is scoped to the container, allowing multiple containers to all have their own locally scoped singletons. ```javascript diff --git a/packages/container/lib/registry.js b/packages/container/lib/registry.js index 54c301250c0..e0df624b15b 100644 --- a/packages/container/lib/registry.js +++ b/packages/container/lib/registry.js @@ -263,7 +263,7 @@ Registry.prototype = { }, /** - A hook to enable custom fullName normalization behaviour + A hook to enable custom fullName normalization behavior @private @method normalizeFullName diff --git a/packages/ember-glimmer/lib/components/link-to.js b/packages/ember-glimmer/lib/components/link-to.js index 780b8f03764..674be41d2df 100644 --- a/packages/ember-glimmer/lib/components/link-to.js +++ b/packages/ember-glimmer/lib/components/link-to.js @@ -75,7 +75,7 @@ any passed value to `disabled` will disable it except `undefined`. to ensure that only `true` disable the `link-to` component you can - override the global behaviour of `Ember.LinkComponent`. + override the global behavior of `Ember.LinkComponent`. ```javascript Ember.LinkComponent.reopen({ diff --git a/packages/ember-glimmer/lib/helpers/action.js b/packages/ember-glimmer/lib/helpers/action.js index bb254cd130e..5fc803f6655 100644 --- a/packages/ember-glimmer/lib/helpers/action.js +++ b/packages/ember-glimmer/lib/helpers/action.js @@ -84,7 +84,7 @@ export const ACTION = symbol('ACTION'); Two options can be passed to the `action` helper when it is used in this way. * `target=someProperty` will look to `someProperty` instead of the current - context for the `actions` hash. This can be useful when targetting a + context for the `actions` hash. This can be useful when targeting a service for actions. * `value="target.value"` will read the path `target.value` off the first argument to the action when it is called and rewrite the first argument diff --git a/packages/ember-glimmer/lib/helpers/get.js b/packages/ember-glimmer/lib/helpers/get.js index 1e6f52e3d08..0583e9e4791 100644 --- a/packages/ember-glimmer/lib/helpers/get.js +++ b/packages/ember-glimmer/lib/helpers/get.js @@ -17,7 +17,7 @@ import { Dynamically look up a property on an object. The second argument to `{{get}}` should have a string value, although it can be bound. - For example, these two usages are equivilent: + For example, these two usages are equivalent: ```handlebars {{person.height}} diff --git a/packages/ember-glimmer/lib/renderer.js b/packages/ember-glimmer/lib/renderer.js index 6b7ad3a0de4..24a041d223e 100644 --- a/packages/ember-glimmer/lib/renderer.js +++ b/packages/ember-glimmer/lib/renderer.js @@ -252,7 +252,7 @@ class Renderer { } getElement(view) { - // overriden in the subclasses + // overridden in the subclasses } getBounds(view) { diff --git a/packages/ember-glimmer/lib/syntax.js b/packages/ember-glimmer/lib/syntax.js index 30edfb1cfd0..f0f7bdc6522 100644 --- a/packages/ember-glimmer/lib/syntax.js +++ b/packages/ember-glimmer/lib/syntax.js @@ -71,7 +71,7 @@ function refineBlockSyntax(sexp, builder) { export const experimentalMacros = []; -// This is a private API to allow for expiremental macros +// This is a private API to allow for experimental macros // to be created in user space. Registering a macro should // should be done in an initializer. export function registerMacros(macro) { diff --git a/packages/ember-glimmer/tests/integration/components/attrs-lookup-test.js b/packages/ember-glimmer/tests/integration/components/attrs-lookup-test.js index 236014cc738..0793fb5ee07 100644 --- a/packages/ember-glimmer/tests/integration/components/attrs-lookup-test.js +++ b/packages/ember-glimmer/tests/integration/components/attrs-lookup-test.js @@ -207,7 +207,7 @@ moduleFor('Components test: attrs lookup', class extends RenderingTest { assert.equal(instance.get('second'), 'second', 'matches known value'); } - ['@test bound computed properties can be overriden in extensions, set during init, and passed in as attrs']() { + ['@test bound computed properties can be overridden in extensions, set during init, and passed in as attrs']() { let FooClass = Component.extend({ attributeBindings: ['style'], style: computed('height', 'color', function() { diff --git a/packages/ember-glimmer/tests/integration/components/contextual-components-test.js b/packages/ember-glimmer/tests/integration/components/contextual-components-test.js index fcc5a358353..005b65a7128 100644 --- a/packages/ember-glimmer/tests/integration/components/contextual-components-test.js +++ b/packages/ember-glimmer/tests/integration/components/contextual-components-test.js @@ -835,14 +835,14 @@ moduleFor('Components test: contextual components', class extends RenderingTest assert.ok(!isEmpty(instance), 'a instance was created'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); - assert.equal(this.$().text(), 'open', 'the componet text is "open"'); + assert.equal(this.$().text(), 'open', 'the components text is "open"'); this.runTask(() => this.rerender()); assert.ok(!isEmpty(instance), 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); - assert.equal(this.$().text(), 'open', 'the componet text is "open"'); + assert.equal(this.$().text(), 'open', 'the components text is "open"'); this.runTask(() => this.context.set('isOpen', false)); @@ -863,7 +863,7 @@ moduleFor('Components test: contextual components', class extends RenderingTest assert.ok(!isEmpty(instance), 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); - assert.equal(this.$().text(), 'open', 'the componet text is "open"'); + assert.equal(this.$().text(), 'open', 'the components text is "open"'); } ['@test GH#13982 contextual component ref is stable even when bound params change (bound name param)'](assert) { @@ -895,14 +895,14 @@ moduleFor('Components test: contextual components', class extends RenderingTest assert.ok(!isEmpty(instance), 'a instance was created'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); - assert.equal(this.$().text(), 'open', 'the componet text is "open"'); + assert.equal(this.$().text(), 'open', 'the components text is "open"'); this.runTask(() => this.rerender()); assert.ok(!isEmpty(instance), 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); - assert.equal(this.$().text(), 'open', 'the componet text is "open"'); + assert.equal(this.$().text(), 'open', 'the components text is "open"'); this.runTask(() => this.context.set('isOpen', false)); @@ -923,7 +923,7 @@ moduleFor('Components test: contextual components', class extends RenderingTest assert.ok(!isEmpty(instance), 'the component instance exists'); assert.equal(previousInstance, undefined, 'no previous component exists'); assert.equal(initCount, 1, 'the component was constructed exactly 1 time'); - assert.equal(this.$().text(), 'open', 'the componet text is "open"'); + assert.equal(this.$().text(), 'open', 'the components text is "open"'); } ['@test GH#13982 contextual component ref is recomputed when component name param changes'](assert) { diff --git a/packages/ember-glimmer/tests/integration/components/curly-components-test.js b/packages/ember-glimmer/tests/integration/components/curly-components-test.js index 1067cec2006..8febd1e5aaf 100644 --- a/packages/ember-glimmer/tests/integration/components/curly-components-test.js +++ b/packages/ember-glimmer/tests/integration/components/curly-components-test.js @@ -1485,7 +1485,7 @@ moduleFor('Components test: curly components', class extends RenderingTest { this.assertComponentElement(this.firstChild, { attrs: { role: 'main' } }); } - ['@test `template` specified in component is overriden by block']() { + ['@test `template` specified in component is overridden by block']() { this.registerComponent('with-template', { ComponentClass: Component.extend({ template: compile('Should not be used') diff --git a/packages/ember-metal/lib/run_loop.js b/packages/ember-metal/lib/run_loop.js index 57a6c65b5e6..c379d6f094c 100644 --- a/packages/ember-metal/lib/run_loop.js +++ b/packages/ember-metal/lib/run_loop.js @@ -259,7 +259,7 @@ run.end = function() { will be resolved on the target object at the time the scheduled item is invoked allowing you to change the target function. @param {Object} [arguments*] Optional arguments to be passed to the queued method. - @return {*} Timer information for use in cancelling, see `run.cancel`. + @return {*} Timer information for use in canceling, see `run.cancel`. @public */ run.schedule = function(/* queue, target, method */) { @@ -328,7 +328,7 @@ run.sync = function() { target at the time the method is invoked. @param {Object} [args*] Optional arguments to pass to the timeout. @param {Number} wait Number of milliseconds to wait. - @return {*} Timer information for use in cancelling, see `run.cancel`. + @return {*} Timer information for use in canceling, see `run.cancel`. @public */ run.later = function(/*target, method*/) { @@ -345,7 +345,7 @@ run.later = function(/*target, method*/) { If you pass a string it will be resolved on the target at the time the method is invoked. @param {Object} [args*] Optional arguments to pass to the timeout. - @return {Object} Timer information for use in cancelling, see `run.cancel`. + @return {Object} Timer information for use in canceling, see `run.cancel`. @public */ run.once = function(...args) { @@ -407,7 +407,7 @@ run.once = function(...args) { If you pass a string it will be resolved on the target at the time the method is invoked. @param {Object} [args*] Optional arguments to pass to the timeout. - @return {Object} Timer information for use in cancelling, see `run.cancel`. + @return {Object} Timer information for use in canceling, see `run.cancel`. @public */ run.scheduleOnce = function(/*queue, target, method*/) { @@ -479,7 +479,7 @@ run.scheduleOnce = function(/*queue, target, method*/) { If you pass a string it will be resolved on the target at the time the method is invoked. @param {Object} [args*] Optional arguments to pass to the timeout. - @return {Object} Timer information for use in cancelling, see `run.cancel`. + @return {Object} Timer information for use in canceling, see `run.cancel`. @public */ run.next = function(...args) { @@ -533,13 +533,13 @@ run.next = function(...args) { // will be executed since we passed in true (immediate) }, 100, true); - // the 100ms delay until this method can be called again will be cancelled + // the 100ms delay until this method can be called again will be canceled run.cancel(debounceImmediate); ``` @method cancel @param {Object} timer Timer object to cancel - @return {Boolean} true if cancelled or false/undefined if it wasn't found + @return {Boolean} true if canceled or false/undefined if it wasn't found @public */ run.cancel = function(timer) { @@ -612,7 +612,7 @@ run.cancel = function(timer) { @param {Number} wait Number of milliseconds to wait. @param {Boolean} immediate Trigger the function on the leading instead of the trailing edge of the wait interval. Defaults to false. - @return {Array} Timer information for use in cancelling, see `run.cancel`. + @return {Array} Timer information for use in canceling, see `run.cancel`. @public */ run.debounce = function() { @@ -655,7 +655,7 @@ run.debounce = function() { @param {Number} spacing Number of milliseconds to space out requests. @param {Boolean} immediate Trigger the function on the leading instead of the trailing edge of the wait interval. Defaults to true. - @return {Array} Timer information for use in cancelling, see `run.cancel`. + @return {Array} Timer information for use in canceling, see `run.cancel`. @public */ run.throttle = function() { diff --git a/packages/ember-metal/tests/accessors/get_test.js b/packages/ember-metal/tests/accessors/get_test.js index 14353ecdf49..086aed20df5 100644 --- a/packages/ember-metal/tests/accessors/get_test.js +++ b/packages/ember-metal/tests/accessors/get_test.js @@ -55,19 +55,19 @@ testBoth('should call unknownProperty on watched values if the value is undefine equal(get(obj, 'foo'), 'FOO', 'should return value from unknown'); }); -QUnit.test('warn on attemps to call get with no arguments', function() { +QUnit.test('warn on attempts to call get with no arguments', function() { expectAssertion(function() { get('aProperty'); }, /Get must be called with two arguments;/i); }); -QUnit.test('warn on attemps to call get with only one argument', function() { +QUnit.test('warn on attempts to call get with only one argument', function() { expectAssertion(function() { get('aProperty'); }, /Get must be called with two arguments;/i); }); -QUnit.test('warn on attemps to call get with more then two arguments', function() { +QUnit.test('warn on attempts to call get with more then two arguments', function() { expectAssertion(function() { get({}, 'aProperty', true); }, /Get must be called with two arguments;/i); diff --git a/packages/ember-metal/tests/events_test.js b/packages/ember-metal/tests/events_test.js index fa44540fa2a..4ce35f05a6b 100644 --- a/packages/ember-metal/tests/events_test.js +++ b/packages/ember-metal/tests/events_test.js @@ -254,7 +254,7 @@ QUnit.test('a listener added as part of a mixin may be overridden', function() { SecondMixin.apply(obj); sendEvent(obj, 'bar'); - equal(triggered, 0, 'should not invoke from overriden property'); + equal(triggered, 0, 'should not invoke from overridden property'); sendEvent(obj, 'baz'); equal(triggered, 1, 'should invoke from subclass property'); diff --git a/packages/ember-metal/tests/injected_property_test.js b/packages/ember-metal/tests/injected_property_test.js index 5437eb86d9d..3de2e066e2d 100644 --- a/packages/ember-metal/tests/injected_property_test.js +++ b/packages/ember-metal/tests/injected_property_test.js @@ -19,7 +19,7 @@ QUnit.test('injected properties should be overridable', function() { set(obj, 'foo', 'bar'); - equal(get(obj, 'foo'), 'bar', 'should return the overriden value'); + equal(get(obj, 'foo'), 'bar', 'should return the overridden value'); }); QUnit.test('getting on an object without an owner or container should fail assertion', function() { diff --git a/packages/ember-metal/tests/mixin/observer_test.js b/packages/ember-metal/tests/mixin/observer_test.js index 71c29417f17..291dc153396 100644 --- a/packages/ember-metal/tests/mixin/observer_test.js +++ b/packages/ember-metal/tests/mixin/observer_test.js @@ -184,7 +184,7 @@ testBoth('observing chain with property in mixin after', function(get, set) { equal(get(obj, 'count'), 1, 'should invoke observer after change'); }); -testBoth('observing chain with overriden property', function(get, set) { +testBoth('observing chain with overridden property', function(get, set) { let obj2 = { baz: 'baz' }; let obj3 = { baz: 'foo' }; diff --git a/packages/ember-routing/lib/ext/controller.js b/packages/ember-routing/lib/ext/controller.js index c4687637d65..28187b4d4e0 100644 --- a/packages/ember-routing/lib/ext/controller.js +++ b/packages/ember-routing/lib/ext/controller.js @@ -17,7 +17,7 @@ ControllerMixin.reopen({ `this.category` and `this.page`. By default, Ember coerces query parameter values using `toggleProperty`. This behavior may lead to unexpected results. - To explicity configure a query parameter property so it coerces as expected, you must define a type property: + To explicitly configure a query parameter property so it coerces as expected, you must define a type property: ```javascript queryParams: [{ category: { diff --git a/packages/ember-routing/lib/system/router.js b/packages/ember-routing/lib/system/router.js index 9e20d1e4b64..38bed836812 100644 --- a/packages/ember-routing/lib/system/router.js +++ b/packages/ember-routing/lib/system/router.js @@ -71,7 +71,7 @@ const EmberRouter = EmberObject.extend(Evented, { * `history` - use the browser's history API to make the URLs look just like any standard URL * `hash` - use `#` to separate the server part of the URL from the Ember part: `/blog/#/posts/new` * `none` - do not store the Ember URL in the actual browser URL (mainly used for testing) - * `auto` - use the best option based on browser capabilites: `history` if possible, then `hash` if possible, otherwise `none` + * `auto` - use the best option based on browser capabilities: `history` if possible, then `hash` if possible, otherwise `none` Note: If using ember-cli, this value is defaulted to `auto` by the `locationType` setting of `/config/environment.js` @@ -828,7 +828,7 @@ const EmberRouter = EmberObject.extend(Evented, { /** Returns the meta information for the query params of a given route. This - will be overriden to allow support for lazy routes. + will be overridden to allow support for lazy routes. @private @method _getQPMeta diff --git a/packages/ember-runtime/lib/mixins/container_proxy.js b/packages/ember-runtime/lib/mixins/container_proxy.js index 730d6060dcd..3e0c019887c 100644 --- a/packages/ember-runtime/lib/mixins/container_proxy.js +++ b/packages/ember-runtime/lib/mixins/container_proxy.js @@ -50,7 +50,7 @@ let containerProxyMixin = { /** Given a fullName return a corresponding instance. - The default behaviour is for lookup to return a singleton instance. + The default behavior is for lookup to return a singleton instance. The singleton is scoped to the container, allowing multiple containers to all have their own locally scoped singletons. diff --git a/packages/ember-runtime/tests/system/array_proxy/arranged_content_test.js b/packages/ember-runtime/tests/system/array_proxy/arranged_content_test.js index 79f08fe5fc9..bcd245a16cc 100644 --- a/packages/ember-runtime/tests/system/array_proxy/arranged_content_test.js +++ b/packages/ember-runtime/tests/system/array_proxy/arranged_content_test.js @@ -300,7 +300,7 @@ QUnit.test('firstObject - returns first arranged object', function() { }); QUnit.test('arrangedContentArray{Will,Did}Change are called when the arranged content changes', function() { - // The behaviour covered by this test may change in the future if we decide + // The behavior covered by this test may change in the future if we decide // that built-in array methods are not overridable. let willChangeCallCount = 0; diff --git a/packages/ember-runtime/tests/system/array_proxy/content_change_test.js b/packages/ember-runtime/tests/system/array_proxy/content_change_test.js index af9881a54c4..809a201cf1e 100644 --- a/packages/ember-runtime/tests/system/array_proxy/content_change_test.js +++ b/packages/ember-runtime/tests/system/array_proxy/content_change_test.js @@ -95,7 +95,7 @@ QUnit.test('The ArrayProxy doesn\'t explode when assigned a destroyed object', f }); QUnit.test('arrayContent{Will,Did}Change are called when the content changes', function() { - // The behaviour covered by this test may change in the future if we decide + // The behavior covered by this test may change in the future if we decide // that built-in array methods are not overridable. let willChangeCallCount = 0; diff --git a/packages/ember-views/lib/mixins/text_support.js b/packages/ember-views/lib/mixins/text_support.js index 5dc95bf9c64..23e239a59a8 100644 --- a/packages/ember-views/lib/mixins/text_support.js +++ b/packages/ember-views/lib/mixins/text_support.js @@ -19,7 +19,7 @@ const KEY_EVENTS = { `TextSupport` is a shared mixin used by both `Ember.TextField` and `Ember.TextArea`. `TextSupport` adds a number of methods that allow you to specify a controller action to invoke when a certain event is fired on your - text field or textarea. The specifed controller action would get the current + text field or textarea. The specified controller action would get the current value of the field passed in as the only argument unless the value of the field is empty. In that case, the instance of the field itself is passed in as the only argument. diff --git a/packages/ember-views/lib/system/utils.js b/packages/ember-views/lib/system/utils.js index a50a98c8dbc..5e02ff8a9f5 100644 --- a/packages/ember-views/lib/system/utils.js +++ b/packages/ember-views/lib/system/utils.js @@ -158,7 +158,7 @@ export function getViewClientRects(view) { `getViewBoundingClientRect` provides information about the position of the bounding border box edges of a view relative to the viewport. - It is only intended to be used by development tools like the Ember Inpsector + It is only intended to be used by development tools like the Ember Inspector and may not work on older browsers. @private diff --git a/packages/ember/tests/routing/basic_test.js b/packages/ember/tests/routing/basic_test.js index c657dd77ce3..866f8173672 100644 --- a/packages/ember/tests/routing/basic_test.js +++ b/packages/ember/tests/routing/basic_test.js @@ -2032,7 +2032,7 @@ QUnit.test('Generated route should be an instance of App.Route if provided', fun ok(generatedRoute instanceof App.Route, 'should extend the correct route'); }); -QUnit.test('Nested index route is not overriden by parent\'s implicit index route', function() { +QUnit.test('Nested index route is not overridden by parent\'s implicit index route', function() { Router.map(function() { this.route('posts', function() { this.route('index', { path: ':category' }); diff --git a/packages/ember/tests/routing/query_params_test.js b/packages/ember/tests/routing/query_params_test.js index 9d9770c5909..279b23dd20c 100644 --- a/packages/ember/tests/routing/query_params_test.js +++ b/packages/ember/tests/routing/query_params_test.js @@ -204,7 +204,7 @@ moduleFor('Query Params - main', class extends QueryParamTestCase { this.assertCurrentPath('/', 'QP did not update due to being overriden'); this.setAndFlush(indexController, 'c', false); - this.assertCurrentPath('/?c=false', 'QP updated with overriden param'); + this.assertCurrentPath('/?c=false', 'QP updated with overridden param'); }); } diff --git a/packages/external-helpers/lib/external-helpers-dev.js b/packages/external-helpers/lib/external-helpers-dev.js index c71b20f228f..835a162fe24 100644 --- a/packages/external-helpers/lib/external-helpers-dev.js +++ b/packages/external-helpers/lib/external-helpers-dev.js @@ -56,7 +56,7 @@ export function defaults(obj, defaults) { export const possibleConstructorReturn = (function (self, call) { if (!self) { - throw new ReferenceError(`this hasn't been initialised - super() hasn't been called`); + throw new ReferenceError(`this hasn't been initialized - super() hasn't been called`); } return call && (typeof call === 'object' || typeof call === 'function') ? call : self; }); From 07b28cf21afc7b7219d7c3b51c78c7552c29453b Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 20 May 2017 14:28:50 +0500 Subject: [PATCH 007/224] avoid creating array in qualifiedRouteName --- packages/ember-glimmer/lib/components/link-to.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/ember-glimmer/lib/components/link-to.js b/packages/ember-glimmer/lib/components/link-to.js index 780b8f03764..f6253fda8f0 100644 --- a/packages/ember-glimmer/lib/components/link-to.js +++ b/packages/ember-glimmer/lib/components/link-to.js @@ -662,12 +662,13 @@ const LinkComponent = EmberComponent.extend({ queryParams: null, qualifiedRouteName: computed('targetRouteName', '_routing.currentState', function computeLinkToComponentQualifiedRouteName() { - let params = get(this, 'params').slice(); - let lastParam = params[params.length - 1]; + let params = get(this, 'params'); + let paramsLength = params.length; + let lastParam = params[paramsLength - 1]; if (lastParam && lastParam.isQueryParams) { - params.pop(); + paramsLength--; } - let onlyQueryParamsSupplied = (this[HAS_BLOCK] ? params.length === 0 : params.length === 1); + let onlyQueryParamsSupplied = (this[HAS_BLOCK] ? paramsLength === 0 : paramsLength === 1); if (onlyQueryParamsSupplied) { return get(this, '_routing.currentRouteName'); } From c9864f536bf6210389364c373630bcb50cef1122 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Thu, 1 Jun 2017 20:11:22 +0200 Subject: [PATCH 008/224] [FEATURE beta] Add minlength to TextSupport Add `minlength` attribute binding to `TextSupport`. Fixes #15243 --- .../tests/integration/helpers/input-test.js | 11 +++++++++++ packages/ember-views/lib/mixins/text_support.js | 1 + 2 files changed, 12 insertions(+) diff --git a/packages/ember-glimmer/tests/integration/helpers/input-test.js b/packages/ember-glimmer/tests/integration/helpers/input-test.js index c64a6417184..36150bb024a 100644 --- a/packages/ember-glimmer/tests/integration/helpers/input-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/input-test.js @@ -125,6 +125,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { placeholder=placeholder name=name maxlength=maxlength + minlength=minlength size=size tabindex=tabindex }}`, { @@ -133,6 +134,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { placeholder: 'Original placeholder', name: 'original-name', maxlength: 10, + minlength: 5, size: 20, tabindex: 30 } @@ -143,6 +145,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { this.assertAttr('placeholder', 'Original placeholder'); this.assertAttr('name', 'original-name'); this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) @@ -153,6 +156,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { this.assertAttr('placeholder', 'Original placeholder'); this.assertAttr('name', 'original-name'); this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) @@ -162,6 +166,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { set(this.context, 'placeholder', 'Updated placeholder'); set(this.context, 'name', 'updated-name'); set(this.context, 'maxlength', 11); + set(this.context, 'minlength', 6); // set(this.context, 'size', 21); //NOTE: failing in IE (TEST_SUITE=sauce) // set(this.context, 'tabindex', 31); //NOTE: failing in IE (TEST_SUITE=sauce) }); @@ -171,6 +176,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { this.assertAttr('placeholder', 'Updated placeholder'); this.assertAttr('name', 'updated-name'); this.assertAttr('maxlength', '11'); + this.assertAttr('minlength', '6'); // this.assertAttr('size', '21'); //NOTE: failing in IE (TEST_SUITE=sauce) // this.assertAttr('tabindex', '31'); //NOTE: failing in IE (TEST_SUITE=sauce) @@ -180,6 +186,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { set(this.context, 'placeholder', 'Original placeholder'); set(this.context, 'name', 'original-name'); set(this.context, 'maxlength', 10); + set(this.context, 'minlength', 5); // set(this.context, 'size', 20); //NOTE: failing in IE (TEST_SUITE=sauce) // set(this.context, 'tabindex', 30); //NOTE: failing in IE (TEST_SUITE=sauce) }); @@ -189,6 +196,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { this.assertAttr('placeholder', 'Original placeholder'); this.assertAttr('name', 'original-name'); this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) } @@ -201,6 +209,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { placeholder="Original placeholder" name="original-name" maxlength=10 + minlength=5 size=20 tabindex=30 }}` @@ -211,6 +220,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { this.assertAttr('placeholder', 'Original placeholder'); this.assertAttr('name', 'original-name'); this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) @@ -221,6 +231,7 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { this.assertAttr('placeholder', 'Original placeholder'); this.assertAttr('name', 'original-name'); this.assertAttr('maxlength', '10'); + this.assertAttr('minlength', '5'); // this.assertAttr('size', '20'); //NOTE: failing in IE (TEST_SUITE=sauce) // this.assertAttr('tabindex', '30'); //NOTE: failing in IE (TEST_SUITE=sauce) } diff --git a/packages/ember-views/lib/mixins/text_support.js b/packages/ember-views/lib/mixins/text_support.js index 5dc95bf9c64..0de118694c7 100644 --- a/packages/ember-views/lib/mixins/text_support.js +++ b/packages/ember-views/lib/mixins/text_support.js @@ -123,6 +123,7 @@ export default Mixin.create(TargetActionSupport, { 'disabled', 'form', 'maxlength', + 'minlength', 'placeholder', 'readonly', 'required', From 8a0a9f0f2b88c6ab0c53601d3b0a3c26dd670b3d Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Thu, 1 Jun 2017 21:00:10 +0200 Subject: [PATCH 009/224] [DOCUMENTATION] Add return types whenever possible to promises Addresses #15114 in emberjs/ember.js --- .../ember-application/lib/system/application-instance.js | 2 +- packages/ember-routing/lib/system/route.js | 8 ++++---- packages/ember-testing/lib/helpers/click.js | 2 +- packages/ember-testing/lib/helpers/fill_in.js | 2 +- packages/ember-testing/lib/helpers/key_event.js | 2 +- packages/ember-testing/lib/helpers/trigger_event.js | 2 +- packages/ember-testing/lib/helpers/visit.js | 2 +- packages/ember-testing/lib/helpers/wait.js | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/ember-application/lib/system/application-instance.js b/packages/ember-application/lib/system/application-instance.js index 40a0bb9a457..989ae769f3b 100644 --- a/packages/ember-application/lib/system/application-instance.js +++ b/packages/ember-application/lib/system/application-instance.js @@ -235,7 +235,7 @@ const ApplicationInstance = EngineInstance.extend({ @public @param url {String} the destination URL - @return {Promise} + @return {Promise} */ visit(url) { this.setupRouter(); diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index 8ba8025021c..d007524e21b 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -1371,7 +1371,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @method beforeModel @param {Transition} transition - @return {Promise} if the value returned from this hook is + @return {Promise} if the value returned from this hook is a promise, the transition will pause until the transition resolves. Otherwise, non-promise return values are not utilized in any way. @@ -1408,7 +1408,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @param {Object} resolvedModel the value returned from `model`, or its resolved value if it was a promise @param {Transition} transition - @return {Promise} if the value returned from this hook is + @return {Promise} if the value returned from this hook is a promise, the transition will pause until the transition resolves. Otherwise, non-promise return values are not utilized in any way. @@ -1527,7 +1527,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @method model @param {Object} params the parameters extracted from the URL @param {Transition} transition - @return {Object|Promise} the model for this route. If + @return {Object|Promise} the model for this route. If a promise is returned, the transition will pause until the promise resolves, and the resolved value of the promise will be used as the model for this route. @@ -1568,7 +1568,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @method deserialize @param {Object} params the parameters extracted from the URL @param {Transition} transition - @return {Object|Promise} the model for this route. + @return {Object|Promise} the model for this route. Router.js hook. */ diff --git a/packages/ember-testing/lib/helpers/click.js b/packages/ember-testing/lib/helpers/click.js index 6021efbf64d..11f7a27c3cf 100644 --- a/packages/ember-testing/lib/helpers/click.js +++ b/packages/ember-testing/lib/helpers/click.js @@ -19,7 +19,7 @@ import { focus, fireEvent } from '../events'; @method click @param {String} selector jQuery selector for finding element on the DOM @param {Object} context A DOM Element, Document, or jQuery to use as context - @return {RSVP.Promise} + @return {RSVP.Promise} @public */ export default function click(app, selector, context) { diff --git a/packages/ember-testing/lib/helpers/fill_in.js b/packages/ember-testing/lib/helpers/fill_in.js index 3e9dafc56bf..38bffd752b6 100644 --- a/packages/ember-testing/lib/helpers/fill_in.js +++ b/packages/ember-testing/lib/helpers/fill_in.js @@ -19,7 +19,7 @@ import { focus, fireEvent } from '../events'; @param {String} selector jQuery selector finding an input element on the DOM to fill text with @param {String} text text to place inside the input element - @return {RSVP.Promise} + @return {RSVP.Promise} @public */ export default function fillIn(app, selector, contextOrText, text) { diff --git a/packages/ember-testing/lib/helpers/key_event.js b/packages/ember-testing/lib/helpers/key_event.js index d713a741c65..c98d89976bb 100644 --- a/packages/ember-testing/lib/helpers/key_event.js +++ b/packages/ember-testing/lib/helpers/key_event.js @@ -14,7 +14,7 @@ @param {String} selector jQuery selector for finding element on the DOM @param {String} type the type of key event, e.g. `keypress`, `keydown`, `keyup` @param {Number} keyCode the keyCode of the simulated key event - @return {RSVP.Promise} + @return {RSVP.Promise} @since 1.5.0 @public */ diff --git a/packages/ember-testing/lib/helpers/trigger_event.js b/packages/ember-testing/lib/helpers/trigger_event.js index aed22b16f78..d9e70a2a9e3 100644 --- a/packages/ember-testing/lib/helpers/trigger_event.js +++ b/packages/ember-testing/lib/helpers/trigger_event.js @@ -19,7 +19,7 @@ import { fireEvent } from '../events'; argument to find only within the context's children @param {String} type The event type to be triggered. @param {Object} [options] The options to be passed to jQuery.Event. - @return {RSVP.Promise} + @return {RSVP.Promise} @since 1.5.0 @public */ diff --git a/packages/ember-testing/lib/helpers/visit.js b/packages/ember-testing/lib/helpers/visit.js index fd3d9f34a29..39c7dbc8308 100644 --- a/packages/ember-testing/lib/helpers/visit.js +++ b/packages/ember-testing/lib/helpers/visit.js @@ -19,7 +19,7 @@ import { run } from 'ember-metal'; @method visit @param {String} url the name of the route - @return {RSVP.Promise} + @return {RSVP.Promise} @public */ export default function visit(app, url) { diff --git a/packages/ember-testing/lib/helpers/wait.js b/packages/ember-testing/lib/helpers/wait.js index 165c2ee9a42..825a95f23c1 100644 --- a/packages/ember-testing/lib/helpers/wait.js +++ b/packages/ember-testing/lib/helpers/wait.js @@ -30,7 +30,7 @@ import { pendingRequests } from '../test/pending_requests'; @method wait @param {Object} value The value to be returned. - @return {RSVP.Promise} + @return {RSVP.Promise} Promise that resolves to the passed value. @public @since 1.0.0 */ From eb2559f96e9e5300807e976702111fa27836bfa2 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Fri, 2 Jun 2017 01:03:23 +0200 Subject: [PATCH 010/224] Change Object to any --- packages/ember-testing/lib/helpers/wait.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-testing/lib/helpers/wait.js b/packages/ember-testing/lib/helpers/wait.js index 825a95f23c1..70e52639476 100644 --- a/packages/ember-testing/lib/helpers/wait.js +++ b/packages/ember-testing/lib/helpers/wait.js @@ -30,7 +30,7 @@ import { pendingRequests } from '../test/pending_requests'; @method wait @param {Object} value The value to be returned. - @return {RSVP.Promise} Promise that resolves to the passed value. + @return {RSVP.Promise} Promise that resolves to the passed value. @public @since 1.0.0 */ From 9e7b57181d6b81ebb500e4c873d9d7fb13bbedc0 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Thu, 1 Jun 2017 18:08:49 -0700 Subject: [PATCH 011/224] Decouple reset_test from globals resolver --- .../tests/system/reset_test.js | 276 ++++++------------ .../lib/test-cases/autoboot-application.js | 23 +- 2 files changed, 113 insertions(+), 186 deletions(-) diff --git a/packages/ember-application/tests/system/reset_test.js b/packages/ember-application/tests/system/reset_test.js index c93602a22b1..cc442f173a3 100644 --- a/packages/ember-application/tests/system/reset_test.js +++ b/packages/ember-application/tests/system/reset_test.js @@ -1,234 +1,142 @@ import { run, get, set } from 'ember-metal'; -import EmberApplication from '../../system/application'; import { Object as EmberObject, Controller } from 'ember-runtime'; import { Router } from 'ember-routing'; -import { Registry } from 'container'; +import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; let application, Application; -QUnit.module('Ember.Application - resetting', { - setup() { - Application = EmberApplication.extend({ - name: 'App', - rootElement: '#qunit-fixture' - }); - }, - teardown() { - Application = null; - if (application) { - run(application, 'destroy'); - } - } -}); +moduleFor('Ember.Application - resetting', class extends AutobootApplicationTestCase { -QUnit.test('Brings its own run-loop if not provided', function() { - application = run(Application, 'create'); - application.ready = function() { - QUnit.start(); - ok(true, 'app booted'); - }; - - QUnit.stop(); - application.reset(); -}); + ['@test Brings its own run-loop if not provided'](assert) { + assert.expect(0); + run(() => this.createApplication()); + this.application.reset(); + } -QUnit.test('Does not bring its own run loop if one is already provided', function() { - expect(3); + ['@test Does not bring its own run loop if one is already provided'](assert) { + assert.expect(3); - var didBecomeReady = false; + let didBecomeReady = false; - application = run(Application, 'create'); + run(() => this.createApplication()); - run(() => { - application.ready = function() { - didBecomeReady = true; - }; + run(() => { + this.application.ready = () => { + didBecomeReady = true; + }; - application.reset(); + this.application.reset(); - application.deferReadiness(); - ok(!didBecomeReady, 'app is not ready'); - }); + this.application.deferReadiness(); + assert.ok(!didBecomeReady, 'app is not ready'); + }); - ok(!didBecomeReady, 'app is not ready'); - run(application, 'advanceReadiness'); - ok(didBecomeReady, 'app is ready'); -}); + assert.ok(!didBecomeReady, 'app is not ready'); + run(this.application, 'advanceReadiness'); + assert.ok(didBecomeReady, 'app is ready'); + } -QUnit.test('When an application is reset, new instances of controllers are generated', function() { - run(() => { - application = Application.create(); - application.AcademicController = Controller.extend(); - }); + ['@test When an application is reset, new instances of controllers are generated'](assert) { + run(() => { + this.createApplication(); + this.add('controller:academic', Controller.extend()); + }); - let firstController = application.__container__.lookup('controller:academic'); - let secondController = application.__container__.lookup('controller:academic'); + let firstController = this.applicationInstance.lookup('controller:academic'); + let secondController = this.applicationInstance.lookup('controller:academic'); - application.reset(); + this.application.reset(); - let thirdController = application.__container__.lookup('controller:academic'); + let thirdController = this.applicationInstance.lookup('controller:academic'); - strictEqual(firstController, secondController, 'controllers looked up in succession should be the same instance'); + assert.strictEqual(firstController, secondController, 'controllers looked up in succession should be the same instance'); - ok(firstController.isDestroying, 'controllers are destroyed when their application is reset'); + ok(firstController.isDestroying, 'controllers are destroyed when their application is reset'); - notStrictEqual(firstController, thirdController, 'controllers looked up after the application is reset should not be the same instance'); -}); + assert.notStrictEqual(firstController, thirdController, 'controllers looked up after the application is reset should not be the same instance'); + } -QUnit.test('When an application is reset, the eventDispatcher is destroyed and recreated', function() { - let eventDispatcherWasSetup, eventDispatcherWasDestroyed; + ['@test When an application is reset, the eventDispatcher is destroyed and recreated'](assert) { + let eventDispatcherWasSetup = 0; + let eventDispatcherWasDestroyed = 0; - eventDispatcherWasSetup = 0; - eventDispatcherWasDestroyed = 0; + let mockEventDispatcher = { + setup() { + eventDispatcherWasSetup++; + }, + destroy() { + eventDispatcherWasDestroyed++; + } + }; - let mock_event_dispatcher = { - create() { - return { - setup() { - eventDispatcherWasSetup++; - }, - destroy() { - eventDispatcherWasDestroyed++; - } - }; - } - }; - - // this is pretty awful. We should make this less Global-ly. - let originalRegister = Registry.prototype.register; - Registry.prototype.register = function(name, type, options) { - if (name === 'event_dispatcher:main') { - return mock_event_dispatcher; - } else { - return originalRegister.call(this, name, type, options); - } - }; - - try { run(() => { - application = Application.create(); + this.createApplication(); + this.add('event_dispatcher:main', {create: () => mockEventDispatcher}); - equal(eventDispatcherWasSetup, 0); - equal(eventDispatcherWasDestroyed, 0); + assert.equal(eventDispatcherWasSetup, 0); + assert.equal(eventDispatcherWasDestroyed, 0); }); - equal(eventDispatcherWasSetup, 1); - equal(eventDispatcherWasDestroyed, 0); + assert.equal(eventDispatcherWasSetup, 1); + assert.equal(eventDispatcherWasDestroyed, 0); - application.reset(); + this.application.reset(); - equal(eventDispatcherWasDestroyed, 1); - equal(eventDispatcherWasSetup, 2, 'setup called after reset'); - } catch (error) { Registry.prototype.register = originalRegister; } - - Registry.prototype.register = originalRegister; -}); + assert.equal(eventDispatcherWasDestroyed, 1); + assert.equal(eventDispatcherWasSetup, 2, 'setup called after reset'); + } -QUnit.test('When an application is reset, the router URL is reset to `/`', function() { - let location, router; + ['@test When an application is reset, the router URL is reset to `/`'](assert) { + run(() => { + this.createApplication(); - run(() => { - application = Application.create(); - application.Router = Router.extend({ - location: 'none' - }); + this.add('router:main', Router.extend({ + location: 'none' + })); - application.Router.map(function() { - this.route('one'); - this.route('two'); + this.router.map(function() { + this.route('one'); + this.route('two'); + }); }); - }); - - router = application.__container__.lookup('router:main'); - - location = router.get('location'); - - run(() => { - location.handleURL('/one'); - }); - - application.reset(); - - let applicationController = application.__container__.lookup('controller:application'); - router = application.__container__.lookup('router:main'); - location = router.get('location'); - - equal(location.getURL(), ''); - - equal(get(applicationController, 'currentPath'), 'index'); - - location = application.__container__.lookup('router:main').get('location'); - run(() => { - location.handleURL('/one'); - }); - - equal(get(applicationController, 'currentPath'), 'one'); -}); -QUnit.test('When an application with advance/deferReadiness is reset, the app does correctly become ready after reset', function() { - var readyCallCount; + this.visit('/one'); - readyCallCount = 0; + this.application.reset(); - run(() => { - application = Application.create({ - ready() { - readyCallCount++; - } - }); - - application.deferReadiness(); - equal(readyCallCount, 0, 'ready has not yet been called'); - }); + let applicationController = this.applicationInstance.lookup('controller:application'); + let router = this.applicationInstance.lookup('router:main'); + let location = router.get('location'); - run(() => { - application.advanceReadiness(); - }); + assert.equal(location.getURL(), ''); + assert.equal(get(applicationController, 'currentPath'), 'index'); - equal(readyCallCount, 1, 'ready was called once'); + this.visit('/one'); - application.reset(); - - equal(readyCallCount, 2, 'ready was called twice'); -}); + assert.equal(get(applicationController, 'currentPath'), 'one'); + } -QUnit.test('With ember-data like initializer and constant', function() { - let DS = { - Store: EmberObject.extend({ - init() { - if (!get(DS, 'defaultStore')) { - set(DS, 'defaultStore', this); - } + ['@test When an application with advance/deferReadiness is reset, the app does correctly become ready after reset'](assert) { + let readyCallCount = 0; - this._super(...arguments); - }, - willDestroy() { - if (get(DS, 'defaultStore') === this) { - set(DS, 'defaultStore', null); + run(() => { + this.createApplication({ + ready() { + readyCallCount++; } - } - }) - }; + }); - Application.initializer({ - name: 'store', - initialize(application) { - application.unregister('store:main'); - application.register('store:main', application.Store); + this.application.deferReadiness(); + assert.equal(readyCallCount, 0, 'ready has not yet been called'); + }); - application.__container__.lookup('store:main'); - } - }); + run(this.application, 'advanceReadiness'); - run(() => { - application = Application.create(); - application.Store = DS.Store; - }); + assert.equal(readyCallCount, 1, 'ready was called once'); - ok(DS.defaultStore, 'has defaultStore'); + this.application.reset(); - application.reset(); + assert.equal(readyCallCount, 2, 'ready was called twice'); + } - ok(DS.defaultStore, 'still has defaultStore'); - ok(application.__container__.lookup('store:main'), 'store is still present'); }); diff --git a/packages/internal-test-helpers/lib/test-cases/autoboot-application.js b/packages/internal-test-helpers/lib/test-cases/autoboot-application.js index ec923c1a17c..cee242b8191 100644 --- a/packages/internal-test-helpers/lib/test-cases/autoboot-application.js +++ b/packages/internal-test-helpers/lib/test-cases/autoboot-application.js @@ -3,6 +3,8 @@ import TestResolver from '../test-resolver'; import { Application } from 'ember-application'; import { assign } from 'ember-utils'; import { runDestroy } from '../run'; +import { run } from 'ember-metal'; +import { compile } from 'ember-template-compiler'; export default class AutobootApplicationTestCase extends AbstractTestCase { @@ -25,9 +27,26 @@ export default class AutobootApplicationTestCase extends AbstractTestCase { this.resolver.add(specifier, factory); } + get router() { + return this.application.resolveRegistration('router:main'); + } + + visit(url, options) { + return run(this.applicationInstance, 'visit', url, options); + } + + get applicationInstance() { + return this.application.__deprecatedInstance__; + } + + compile(string, options) { + return compile(...arguments); + } + addTemplate(templateName, templateString) { - this.resolver.addTemplate(templateName, templateString); + this.resolver.add(`template:${templateName}`, this.compile(templateString, { + moduleName: templateName + })); } } - From c7d6a0da389245fda85107dcb508fe36d3cc258c Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 2 Jun 2017 12:27:21 -0700 Subject: [PATCH 012/224] [BUGFIX] Improve fastboot debugger/repl experience remove the getter entirely --- packages/container/lib/container.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/container/lib/container.js b/packages/container/lib/container.js index 55c96f72f3a..a75af3afa3e 100644 --- a/packages/container/lib/container.js +++ b/packages/container/lib/container.js @@ -189,13 +189,6 @@ Container.prototype = { function wrapManagerInDeprecationProxy(manager) { if (HAS_NATIVE_PROXY) { let validator = { - get(obj, prop) { - if (prop !== 'class' && prop !== 'create') { - throw new Error(`You attempted to access "${prop}" on a factory manager created by container#factoryFor. "${prop}" is not a member of a factory manager."`); - } - - return obj[prop]; - }, set(obj, prop, value) { throw new Error(`You attempted to set "${prop}" on a factory manager created by container#factoryFor. A factory manager is a read-only construct.`); } From e66261dfe126b08d292a7e76665a820f36ac0920 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 3 Jun 2017 21:43:55 -0400 Subject: [PATCH 013/224] [FEATURE ember-engines-mount-params] Constrain to `model` hash arg. After discussion during a recent core team meeting, the original implementation (and RFC) were determined to be a bit future hostile. Specifically, with the implementation prior to this PR it would have been impossible to add any additional hash arguments that were targeting the `{{mount` syntax directly (e.g. namespacing for use with tree shaking) without breaking changes (since all hash arg names were allowed to be passed through before). This change updates things a bit to limit the pass through to the `model` hash argument, which actually makes things a tad bit more teachable anyways. The ability to pass down arbitrary named values is absolutely still present through the usage of the `(hash` helper. --- .../lib/component-managers/mount.js | 16 ++++++++-------- .../tests/integration/mount-test.js | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/ember-glimmer/lib/component-managers/mount.js b/packages/ember-glimmer/lib/component-managers/mount.js index 0f18fe88bcd..a30a90ce4d2 100644 --- a/packages/ember-glimmer/lib/component-managers/mount.js +++ b/packages/ember-glimmer/lib/component-managers/mount.js @@ -29,7 +29,7 @@ class MountManager extends AbstractManager { let bucket = { engine }; if (EMBER_ENGINES_MOUNT_PARAMS) { - bucket.args = args.capture(); + bucket.modelReference = args.named.get('model'); } return bucket; @@ -41,15 +41,15 @@ class MountManager extends AbstractManager { } getSelf(bucket) { - let { engine, args } = bucket; + let { engine, modelReference } = bucket; let applicationFactory = engine.factoryFor(`controller:application`); let controllerFactory = applicationFactory || generateControllerFactory(engine, 'application'); let controller = bucket.controller = controllerFactory.create(); if (EMBER_ENGINES_MOUNT_PARAMS) { - let model = args.named.value(); - bucket.argsRevision = args.tag.value(); + let model = modelReference.value(); + bucket.modelRevision = modelReference.tag.value(); controller.set('model', model); } @@ -68,11 +68,11 @@ class MountManager extends AbstractManager { update(bucket) { if (EMBER_ENGINES_MOUNT_PARAMS) { - let { controller, args, argsRevision } = bucket; + let { controller, modelReference, modelRevision } = bucket; - if (!args.tag.validate(argsRevision)) { - let model = args.named.value(); - bucket.argsRevision = args.tag.value(); + if (!modelReference.tag.validate(modelRevision)) { + let model = modelReference.value(); + bucket.modelRevision = modelReference.tag.value(); controller.set('model', model); } } diff --git a/packages/ember-glimmer/tests/integration/mount-test.js b/packages/ember-glimmer/tests/integration/mount-test.js index 0cd47c54127..dcb9fa92d0b 100644 --- a/packages/ember-glimmer/tests/integration/mount-test.js +++ b/packages/ember-glimmer/tests/integration/mount-test.js @@ -208,7 +208,7 @@ if (EMBER_ENGINES_MOUNT_PARAMS) { this.router.map(function() { this.route('engine-params-static'); }); - this.addTemplate('engine-params-static', '{{mount "paramEngine" foo="bar"}}'); + this.addTemplate('engine-params-static', '{{mount "paramEngine" model=(hash foo="bar")}}'); return this.visit('/engine-params-static').then(() => { this.assertComponentElement(this.firstChild, { content: '

Param Engine: bar

' }); @@ -227,7 +227,7 @@ if (EMBER_ENGINES_MOUNT_PARAMS) { controller = this; } })); - this.addTemplate('engine-params-bound', '{{mount "paramEngine" foo=boundParamValue}}'); + this.addTemplate('engine-params-bound', '{{mount "paramEngine" model=(hash foo=boundParamValue)}}'); return this.visit('/engine-params-bound').then(() => { this.assertComponentElement(this.firstChild, { content: '

Param Engine:

' }); @@ -277,7 +277,7 @@ if (EMBER_ENGINES_MOUNT_PARAMS) { this.register('template:application', compile('{{model.foo}}', { moduleName: 'application' })); } })); - this.addTemplate('engine-params-contextual-component', '{{mount "componentParamEngine" foo=(component "foo-component")}}'); + this.addTemplate('engine-params-contextual-component', '{{mount "componentParamEngine" model=(hash foo=(component "foo-component"))}}'); return this.visit('/engine-params-contextual-component').then(() => { this.assertComponentElement(this.firstChild.firstChild, { content: 'foo-component rendered! - rendered app-bar-component from the app' }); From 33dc36922f5b9619bce6f4fc1b1503b60c050e72 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 3 Jun 2017 22:07:15 -0400 Subject: [PATCH 014/224] [FEATURE ember-engines-mount-params] Enable by default. As discussed during the 2017-06-02 core team meeting, once the feature was restricted to the `model` named argument (as opposed to passing through all named args) this feature was good to go. This enables the feature by default. --- features.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features.json b/features.json index c8cb2780422..7622a80e070 100644 --- a/features.json +++ b/features.json @@ -6,7 +6,7 @@ "ember-metal-weakmap": null, "ember-glimmer-allow-backtracking-rerender": null, "ember-routing-router-service": null, - "ember-engines-mount-params": null, + "ember-engines-mount-params": true, "glimmer-custom-component-manager": null }, "deprecations": { From 64dea34f69d6d7c5635d07115d5e75c95c2452d6 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Thu, 1 Jun 2017 22:10:43 -0700 Subject: [PATCH 015/224] Decouple ember link_to_test from globals resolver --- packages/ember/tests/helpers/link_to_test.js | 2270 +++++++++-------- .../lib/test-cases/abstract-application.js | 8 +- .../lib/test-cases/abstract.js | 8 +- 3 files changed, 1195 insertions(+), 1091 deletions(-) diff --git a/packages/ember/tests/helpers/link_to_test.js b/packages/ember/tests/helpers/link_to_test.js index 077f6c5e819..8b8baa0fae3 100644 --- a/packages/ember/tests/helpers/link_to_test.js +++ b/packages/ember/tests/helpers/link_to_test.js @@ -1,1459 +1,1557 @@ import Logger from 'ember-console'; +import { + moduleFor, + ApplicationTestCase, + AutobootApplicationTestCase +} from 'internal-test-helpers'; import { Controller, - Object as EmberObject, inject, A as emberA } from 'ember-runtime'; import { - set, - run, instrumentationSubscribe as subscribe, - instrumentationReset as reset, alias } from 'ember-metal'; -import { Route, NoneLocation } from 'ember-routing'; -import { Application } from 'ember-application'; +import { Router, Route, NoneLocation } from 'ember-routing'; import { jQuery } from 'ember-views'; -import { compile } from 'ember-template-compiler'; -import { setTemplates, setTemplate } from 'ember-glimmer'; -import { EMBER_IMPROVED_INSTRUMENTATION } from 'ember-debug'; - -let Router, App, router, appInstance; - -function bootApplication() { - router = appInstance.lookup('router:main'); - run(App, 'advanceReadiness'); -} +import { EMBER_IMPROVED_INSTRUMENTATION } from 'ember/features'; // IE includes the host name function normalizeUrl(url) { return url.replace(/https?:\/\/[^\/]+/, ''); } -function shouldNotBeActive(selector) { - checkActive(selector, false); +function shouldNotBeActive(assert, element) { + checkActive(assert, element, false); } -function shouldBeActive(selector) { - checkActive(selector, true); +function shouldBeActive(assert, element) { + checkActive(assert, element, true); } -function checkActive(selector, active) { - let classList = jQuery(selector, '#qunit-fixture')[0].className; - equal(classList.indexOf('active') > -1, active, selector + ' active should be ' + active.toString()); +function checkActive(assert, element, active) { + let classList = element.attr('class'); + assert.equal(classList.indexOf('active') > -1, active, `${element} active should be ${active}`); } -let updateCount, replaceCount; - -function sharedSetup() { - App = Application.create({ - name: 'App', - rootElement: '#qunit-fixture' - }); - - App.deferReadiness(); - - updateCount = replaceCount = 0; - App.Router.reopen({ - location: NoneLocation.create({ - setURL(path) { - updateCount++; - set(this, 'path', path); - }, - - replaceURL(path) { - replaceCount++; - set(this, 'path', path); - } - }) - }); - - Router = App.Router; - appInstance = App.__deprecatedInstance__; -} - -function sharedTeardown() { - run(() => App.destroy()); - setTemplates({}); - reset(); -} - -QUnit.module('The {{link-to}} helper', { - setup() { - run(() => { - sharedSetup(); - - setTemplate('app', compile('{{outlet}}')); - setTemplate('index', compile(`

Home

{{#link-to 'about' id='about-link'}}About{{/link-to}}{{#link-to 'index' id='self-link'}}Self{{/link-to}}`)); - setTemplate('about', compile(`

About

{{#link-to 'index' id='home-link'}}Home{{/link-to}}{{#link-to 'about' id='self-link'}}Self{{/link-to}}`)); - setTemplate('item', compile(`

Item

{{model.name}}

{{#link-to 'index' id='home-link'}}Home{{/link-to}}`)); - - appInstance.unregister('router:main'); - appInstance.register('router:main', Router); - }); - }, - - teardown: sharedTeardown -}); - -QUnit.test('The {{link-to}} helper moves into the named route', function() { - Router.map(function(match) { - this.route('about'); - }); - - bootApplication(); - - run(() => router.handleURL('/')); - - equal(jQuery('h3:contains(Home)', '#qunit-fixture').length, 1, 'The home template was rendered'); - equal(jQuery('#self-link.active', '#qunit-fixture').length, 1, 'The self-link was rendered with active class'); - equal(jQuery('#about-link:not(.active)', '#qunit-fixture').length, 1, 'The other link was rendered without active class'); - - run(() => jQuery('#about-link', '#qunit-fixture').click()); - - equal(jQuery('h3:contains(About)', '#qunit-fixture').length, 1, 'The about template was rendered'); - equal(jQuery('#self-link.active', '#qunit-fixture').length, 1, 'The self-link was rendered with active class'); - equal(jQuery('#home-link:not(.active)', '#qunit-fixture').length, 1, 'The other link was rendered without active class'); -}); - -if (EMBER_IMPROVED_INSTRUMENTATION) { - QUnit.test('The {{link-to}} helper fires an interaction event', function(assert) { - assert.expect(2); - Router.map(function(match) { - this.route('about'); - }); - - bootApplication(); - - run(() => router.handleURL('/')); - - subscribe('interaction.link-to', { - before() { - assert.ok(true, 'instrumentation subscriber was called'); - }, - after() { - assert.ok(true, 'instrumentation subscriber was called'); - } - }); - - jQuery('#about-link', '#qunit-fixture').click(); - }); - - QUnit.test('The {{link-to}} helper interaction event includes the route name', function(assert) { - assert.expect(2); - Router.map(function(match) { - this.route('about'); - }); - - bootApplication(); - - run(() => router.handleURL('/')); - - subscribe('interaction.link-to', { - before(name, timestamp, { routeName }) { - assert.equal(routeName, 'about', 'instrumentation subscriber was passed route name'); - }, - after(name, timestamp, { routeName }) { - assert.equal(routeName, 'about', 'instrumentation subscriber was passed route name'); - } - }); +moduleFor('The {{link-to}} helper - basic tests', class extends ApplicationTestCase { - jQuery('#about-link', '#qunit-fixture').click(); - }); + constructor() { + super(); - QUnit.test('The {{link-to}} helper interaction event includes the transition in the after hook', function(assert) { - assert.expect(1); - Router.map(function(match) { + this.router.map(function() { this.route('about'); }); - bootApplication(); - - run(() => router.handleURL('/')); - - subscribe('interaction.link-to', { - before() {}, - after(name, timestamp, { transition }) { - assert.equal(transition.targetName, 'about', 'instrumentation subscriber was passed route name'); - } - }); - - jQuery('#about-link', '#qunit-fixture').click(); - }); -} - -QUnit.test('The {{link-to}} helper supports URL replacement', function() { - setTemplate('index', compile(`

Home

{{#link-to 'about' id='about-link' replace=true}}About{{/link-to}}`)); - - Router.map(function() { - this.route('about'); - }); - - bootApplication(); - - run(() => router.handleURL('/')); - - equal(updateCount, 0, 'precond: setURL has not been called'); - equal(replaceCount, 0, 'precond: replaceURL has not been called'); - - run(() => jQuery('#about-link', '#qunit-fixture').click()); - - equal(updateCount, 0, 'setURL should not be called'); - equal(replaceCount, 1, 'replaceURL should be called once'); -}); - -QUnit.test('The {{link-to}} helper supports URL replacement via replace=boundTruthyThing', function() { - setTemplate('index', compile(`

Home

{{#link-to 'about' id='about-link' replace=boundTruthyThing}}About{{/link-to}}`)); - - App.IndexController = Controller.extend({ - boundTruthyThing: true - }); - - Router.map(function() { - this.route('about'); - }); + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link'}}About{{/link-to}} + {{#link-to 'index' id='self-link'}}Self{{/link-to}} + `); + this.addTemplate('about', ` +

About

+ {{#link-to 'index' id='home-link'}}Home{{/link-to}} + {{#link-to 'about' id='self-link'}}Self{{/link-to}} + `); + } - bootApplication(); + ['@test The {{link-to}} helper moves into the named route'](assert) { + this.visit('/'); + assert.equal(this.$('h3:contains(Home)').length, 1, 'The home template was rendered'); + assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class'); + assert.equal(this.$('#about-link:not(.active)').length, 1, 'The other link was rendered without active class'); - run(() => router.handleURL('/')); + this.click('#about-link'); - equal(updateCount, 0, 'precond: setURL has not been called'); - equal(replaceCount, 0, 'precond: replaceURL has not been called'); + assert.equal(this.$('h3:contains(About)').length, 1, 'The about template was rendered'); + assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class'); + assert.equal(this.$('#home-link:not(.active)').length, 1, 'The other link was rendered without active class'); + } - run(() => jQuery('#about-link', '#qunit-fixture').click()); + [`@test the {{link-to}} helper doesn't add an href when the tagName isn't 'a'`](assert) { + this.addTemplate('index', ` + {{#link-to 'about' id='about-link' tagName='div'}}About{{/link-to}} + `); - equal(updateCount, 0, 'setURL should not be called'); - equal(replaceCount, 1, 'replaceURL should be called once'); -}); + this.visit('/'); -QUnit.test('The {{link-to}} helper supports setting replace=boundFalseyThing', function() { - setTemplate('index', compile(`

Home

{{#link-to 'about' id='about-link' replace=boundFalseyThing}}About{{/link-to}}`)); + assert.equal(this.$('#about-link').attr('href'), undefined, 'there is no href attribute'); + } - App.IndexController = Controller.extend({ - boundFalseyThing: false - }); + [`@test the {{link-to}} applies a 'disabled' class when disabled`](assert) { + this.addTemplate('index', ` + {{#link-to "about" id="about-link-static" disabledWhen="shouldDisable"}}About{{/link-to}} + {{#link-to "about" id="about-link-dynamic" disabledWhen=dynamicDisabledWhen}}About{{/link-to}} + `); - Router.map(function() { - this.route('about'); - }); + this.add('controller:index', Controller.extend({ + shouldDisable: true, + dynamicDisabledWhen: 'shouldDisable' + })); - bootApplication(); + this.visit('/'); - run(() => router.handleURL('/')); + assert.equal(this.$('#about-link-static.disabled').length, 1, 'The static link is disabled when its disabledWhen is true'); + assert.equal(this.$('#about-link-dynamic.disabled').length, 1, 'The dynamic link is disabled when its disabledWhen is true'); - equal(updateCount, 0, 'precond: setURL has not been called'); - equal(replaceCount, 0, 'precond: replaceURL has not been called'); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('dynamicDisabledWhen', false)); - run(() => jQuery('#about-link', '#qunit-fixture').click()); - - equal(updateCount, 1, 'setURL should be called'); - equal(replaceCount, 0, 'replaceURL should not be called'); -}); + assert.equal(this.$('#about-link-dynamic.disabled').length, 0, 'The dynamic link is re-enabled when its disabledWhen becomes false'); + } -// jscs:disable + [`@test the {{link-to}} doesn't apply a 'disabled' class if disabledWhen is not provided`](assert) { + this.addTemplate('index', `{{#link-to "about" id="about-link"}}About{{/link-to}}`); -QUnit.test("the {{link-to}} helper doesn't add an href when the tagName isn't 'a'", function() { - setTemplate('index', compile(`{{#link-to 'about' id='about-link' tagName='div'}}About{{/link-to}}`)); + this.visit('/'); - Router.map(function() { - this.route('about'); - }); + assert.ok(!this.$('#about-link').hasClass('disabled'), 'The link is not disabled if disabledWhen not provided'); + } - bootApplication(); + [`@test the {{link-to}} helper supports a custom disabledClass`](assert) { + this.addTemplate('index', ` + {{#link-to "about" id="about-link" disabledWhen=true disabledClass="do-not-want"}}About{{/link-to}} + `); - run(() => router.handleURL('/')); - - equal(jQuery('#about-link').attr('href'), undefined, 'there is no href attribute'); -}); + this.visit('/'); + assert.equal(this.$('#about-link.do-not-want').length, 1, 'The link can apply a custom disabled class'); + } -QUnit.test("the {{link-to}} applies a 'disabled' class when disabled", function () { - setTemplate('index', compile(` - {{#link-to "about" id="about-link-static" disabledWhen="shouldDisable"}}About{{/link-to}} - {{#link-to "about" id="about-link-dynamic" disabledWhen=dynamicDisabledWhen}}About{{/link-to}} - `)); + [`@test the {{link-to}} helper supports a custom disabledClass set via bound param`](assert) { + this.addTemplate('index', ` + {{#link-to "about" id="about-link" disabledWhen=true disabledClass=disabledClass}}About{{/link-to}} + `); - App.IndexController = Controller.extend({ - shouldDisable: true, - dynamicDisabledWhen: 'shouldDisable' - }); + this.add('controller:index', Controller.extend({ + disabledClass: 'do-not-want' + })); - Router.map(function() { - this.route('about'); - }); + this.visit('/'); - bootApplication(); + assert.equal(this.$('#about-link.do-not-want').length, 1, 'The link can apply a custom disabled class via bound param'); + } - run(() => router.handleURL('/')); + [`@test the {{link-to}} helper does not respond to clicks when disabled`](assert) { + this.addTemplate('index', ` + {{#link-to "about" id="about-link" disabledWhen=true}}About{{/link-to}} + `); - equal(jQuery('#about-link-static.disabled', '#qunit-fixture').length, 1, 'The static link is disabled when its disabledWhen is true'); - equal(jQuery('#about-link-dynamic.disabled', '#qunit-fixture').length, 1, 'The dynamic link is disabled when its disabledWhen is true'); + this.visit('/'); + this.click('#about-link'); - run(() => set(appInstance.lookup('controller:index'), 'dynamicDisabledWhen', false)); + assert.equal(this.$('h3:contains(About)').length, 0, 'Transitioning did not occur'); + } - equal(jQuery('#about-link-dynamic.disabled', '#qunit-fixture').length, 0, 'The dynamic link is re-enabled when its disabledWhen becomes false'); -}); + [`@test the {{link-to}} helper responds to clicks according to its disabledWhen bound param`](assert) { + this.addTemplate('index', ` + {{#link-to "about" id="about-link" disabledWhen=disabledWhen}}About{{/link-to}} + `); -QUnit.test("the {{link-to}} doesn't apply a 'disabled' class if disabledWhen is not provided", function () { - setTemplate('index', compile(`{{#link-to "about" id="about-link"}}About{{/link-to}}`)); + this.add('controller:index', Controller.extend({ + disabledWhen: true + })); - Router.map(function() { - this.route('about'); - }); + this.visit('/'); - bootApplication(); + this.click('#about-link'); - run(() => router.handleURL('/')); + assert.equal(this.$('h3:contains(About)').length, 0, 'Transitioning did not occur'); - ok(!jQuery('#about-link', '#qunit-fixture').hasClass('disabled'), 'The link is not disabled if disabledWhen not provided'); -}); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('disabledWhen', false)); -QUnit.test('the {{link-to}} helper supports a custom disabledClass', function () { - setTemplate('index', compile('{{#link-to "about" id="about-link" disabledWhen=true disabledClass="do-not-want"}}About{{/link-to}}')); + this.click('#about-link'); - Router.map(function() { - this.route('about'); - }); + assert.equal(this.$('h3:contains(About)').length, 1, 'Transitioning did occur when disabledWhen became false'); + } - bootApplication(); + [`@test The {{link-to}} helper supports a custom activeClass`](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link'}}About{{/link-to}} + {{#link-to 'index' id='self-link' activeClass='zomg-active'}}Self{{/link-to}} + `); - run(() => router.handleURL('/')); + this.visit('/'); - equal(jQuery('#about-link.do-not-want', '#qunit-fixture').length, 1, 'The link can apply a custom disabled class'); -}); + assert.equal(this.$('h3:contains(Home)').length, 1, 'The home template was rendered'); + assert.equal(this.$('#self-link.zomg-active').length, 1, 'The self-link was rendered with active class'); + assert.equal(this.$('#about-link:not(.active)').length, 1, 'The other link was rendered without active class'); + } -QUnit.test('the {{link-to}} helper supports a custom disabledClass set via bound param', function () { - setTemplate('index', compile('{{#link-to "about" id="about-link" disabledWhen=true disabledClass=disabledClass}}About{{/link-to}}')); + [`@test The {{link-to}} helper supports a custom activeClass from a bound param`](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link'}}About{{/link-to}} + {{#link-to 'index' id='self-link' activeClass=activeClass}}Self{{/link-to}} + `); - Router.map(function() { - this.route('about'); - }); + this.add('controller:index', Controller.extend({ + activeClass: 'zomg-active' + })); - App.IndexController = Controller.extend({ - disabledClass: 'do-not-want' - }); + this.visit('/'); - bootApplication(); + assert.equal(this.$('h3:contains(Home)').length, 1, 'The home template was rendered'); + assert.equal(this.$('#self-link.zomg-active').length, 1, 'The self-link was rendered with active class'); + assert.equal(this.$('#about-link:not(.active)').length, 1, 'The other link was rendered without active class'); + } - run(() => router.handleURL('/')); + [`@test The {{link-to}} helper supports 'classNameBindings' with custom values [GH #11699]`](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link' classNameBindings='foo:foo-is-true:foo-is-false'}}About{{/link-to}} + `); - equal(jQuery('#about-link.do-not-want', '#qunit-fixture').length, 1, 'The link can apply a custom disabled class via bound param'); -}); + this.add('controller:index', Controller.extend({ + foo: false + })); -QUnit.test('the {{link-to}} helper does not respond to clicks when disabled', function () { - setTemplate('index', compile('{{#link-to "about" id="about-link" disabledWhen=true}}About{{/link-to}}')); + this.visit('/'); - Router.map(function() { - this.route('about'); - }); + assert.equal(this.$('#about-link.foo-is-false').length, 1, 'The about-link was rendered with the falsy class'); - bootApplication(); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('foo', true)); - run(() => router.handleURL('/')); + assert.equal(this.$('#about-link.foo-is-true').length, 1, 'The about-link was rendered with the truthy class after toggling the property'); + } +}) - run(() => jQuery('#about-link', '#qunit-fixture').click()); +moduleFor('The {{link-to}} helper - location hooks', class extends ApplicationTestCase { - equal(jQuery('h3:contains(About)', '#qunit-fixture').length, 0, 'Transitioning did not occur'); -}); + constructor() { + super(); -QUnit.test('the {{link-to}} helper responds to clicks according to its disabledWhen bound param', function () { - setTemplate('index', compile('{{#link-to "about" id="about-link" disabledWhen=disabledWhen}}About{{/link-to}}')); + this.updateCount = 0; + this.replaceCount = 0; - Router.map(function() { - this.route('about'); - }); + let testContext = this; + this.add('location:none', NoneLocation.extend({ + setURL() { + testContext.updateCount++; + return this._super(...arguments); + }, + replaceURL() { + testContext.replaceCount++; + return this._super(...arguments); + } + })); - App.IndexController = Controller.extend({ - disabledWhen: true - }); + this.router.map(function() { + this.route('about'); + }); - bootApplication(); + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link'}}About{{/link-to}} + {{#link-to 'index' id='self-link'}}Self{{/link-to}} + `); + this.addTemplate('about', ` +

About

+ {{#link-to 'index' id='home-link'}}Home{{/link-to}} + {{#link-to 'about' id='self-link'}}Self{{/link-to}} + `); + } - run(() => router.handleURL('/')); + visit() { + super.visit(...arguments); + this.updateCountAfterVisit = this.updateCount; + this.replaceCountAfterVisit = this.replaceCount; + } - run(() => jQuery('#about-link', '#qunit-fixture').click()); + ['@test The {{link-to}} helper supports URL replacement'](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link' replace=true}}About{{/link-to}} + `); + + this.visit('/'); + this.click('#about-link'); + + assert.equal( + this.updateCount, this.updateCountAfterVisit, + 'setURL should not be called' + ); + assert.equal( + this.replaceCount, this.replaceCountAfterVisit + 1, + 'replaceURL should be called once' + ); + } - equal(jQuery('h3:contains(About)', '#qunit-fixture').length, 0, 'Transitioning did not occur'); + ['@test The {{link-to}} helper supports URL replacement via replace=boundTruthyThing'](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link' replace=boundTruthyThing}}About{{/link-to}} + `); + + this.add('controller:index', Controller.extend({ + boundTruthyThing: true + })); + + this.visit('/'); + this.click('#about-link'); + + assert.equal( + this.updateCount, this.updateCountAfterVisit, + 'setURL should not be called' + ); + assert.equal( + this.replaceCount, this.replaceCountAfterVisit + 1, + 'replaceURL should be called once' + ); + } - run(() => set(appInstance.lookup('controller:index'), 'disabledWhen', false)); - run(() => jQuery('#about-link', '#qunit-fixture').click()); + ['@test The {{link-to}} helper supports setting replace=boundFalseyThing'](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link' replace=boundFalseyThing}}About{{/link-to}} + `); + + this.add('controller:index', Controller.extend({ + boundFalseyThing: false + })); + + this.visit('/'); + this.click('#about-link'); + + assert.equal( + this.updateCount, this.updateCountAfterVisit + 1, + 'setURL should be called' + ); + assert.equal( + this.replaceCount, this.replaceCountAfterVisit, + 'replaceURL should not be called' + ); + } - equal(jQuery('h3:contains(About)', '#qunit-fixture').length, 1, 'Transitioning did occur when disabledWhen became false'); }); -QUnit.test('The {{link-to}} helper supports a custom activeClass', function() { - setTemplate('index', compile("

Home

{{#link-to 'about' id='about-link'}}About{{/link-to}}{{#link-to 'index' id='self-link' activeClass='zomg-active'}}Self{{/link-to}}")); - - Router.map(function() { - this.route('about'); - }); - - bootApplication(); - - run(() => router.handleURL('/')); - - equal(jQuery('h3:contains(Home)', '#qunit-fixture').length, 1, 'The home template was rendered'); - equal(jQuery('#self-link.zomg-active', '#qunit-fixture').length, 1, 'The self-link was rendered with active class'); - equal(jQuery('#about-link:not(.active)', '#qunit-fixture').length, 1, 'The other link was rendered without active class'); -}); +if (EMBER_IMPROVED_INSTRUMENTATION) { + moduleFor('The {{link-to}} helper with EMBER_IMPROVED_INSTRUMENTATION', class extends ApplicationTestCase { + + constructor() { + super(); + + this.router.map(function() { + this.route('about'); + }); + + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link'}}About{{/link-to}} + {{#link-to 'index' id='self-link'}}Self{{/link-to}} + `); + this.addTemplate('about', ` +

About

+ {{#link-to 'index' id='home-link'}}Home{{/link-to}} + {{#link-to 'about' id='self-link'}}Self{{/link-to}} + `); + + this.visit('/'); + } -QUnit.test('The {{link-to}} helper supports a custom activeClass from a bound param', function() { - setTemplate('index', compile(`

Home

{{#link-to 'about' id='about-link'}}About{{/link-to}}{{#link-to 'index' id='self-link' activeClass=activeClass}}Self{{/link-to}}`)); + ['@test The {{link-to}} helper fires an interaction event'](assert) { + assert.expect(2); - Router.map(function() { - this.route('about'); - }); + subscribe('interaction.link-to', { + before() { + assert.ok(true, 'instrumentation subscriber was called'); + }, + after() { + assert.ok(true, 'instrumentation subscriber was called'); + } + }); - App.IndexController = Controller.extend({ - activeClass: 'zomg-active' - }); + this.click('#about-link'); + } - bootApplication(); + ['@test The {{link-to}} helper interaction event includes the route name'](assert) { + assert.expect(2); - run(() => router.handleURL('/')); + subscribe('interaction.link-to', { + before(name, timestamp, { routeName }) { + assert.equal(routeName, 'about', 'instrumentation subscriber was passed route name'); + }, + after(name, timestamp, { routeName }) { + assert.equal(routeName, 'about', 'instrumentation subscriber was passed route name'); + } + }); - equal(jQuery('h3:contains(Home)', '#qunit-fixture').length, 1, 'The home template was rendered'); - equal(jQuery('#self-link.zomg-active', '#qunit-fixture').length, 1, 'The self-link was rendered with active class'); - equal(jQuery('#about-link:not(.active)', '#qunit-fixture').length, 1, 'The other link was rendered without active class'); -}); + this.click('#about-link'); + } -QUnit.test("The {{link-to}} helper supports 'classNameBindings' with custom values [GH #11699]", function() { - setTemplate('index', compile(`

Home

{{#link-to 'about' id='about-link' classNameBindings='foo:foo-is-true:foo-is-false'}}About{{/link-to}}`)); + ['@test The {{link-to}} helper interaction event includes the transition in the after hook'](assert) { + assert.expect(1); - Router.map(function() { - this.route('about'); - }); + subscribe('interaction.link-to', { + before() {}, + after(name, timestamp, { transition }) { + assert.equal(transition.targetName, 'about', 'instrumentation subscriber was passed route name'); + } + }); - App.IndexController = Controller.extend({ - foo: false + this.click('#about-link'); + } }); +} - bootApplication(); +moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class extends ApplicationTestCase { - run(() => router.handleURL('/')); + ['@test The {{link-to}} helper supports leaving off .index for nested routes'](assert) { + this.router.map(function() { + this.route('about', function() { + this.route('item'); + }); + }); - equal(jQuery('#about-link.foo-is-false', '#qunit-fixture').length, 1, 'The about-link was rendered with the falsy class'); + this.addTemplate('about', `

About

{{outlet}}`); + this.addTemplate('about.index', `
Index
`); + this.addTemplate('about.item', `
{{#link-to 'about'}}About{{/link-to}}
`); - let controller = appInstance.lookup('controller:index'); + this.visit('/about/item'); - run(() => controller.set('foo', true)); + assert.equal(normalizeUrl(this.$('#item a').attr('href')), '/about'); + } - equal(jQuery('#about-link.foo-is-true', '#qunit-fixture').length, 1, 'The about-link was rendered with the truthy class after toggling the property'); -}); + ['@test The {{link-to}} helper supports currentWhen (DEPRECATED)'](assert) { + expectDeprecation('Usage of `currentWhen` is deprecated, use `current-when` instead.'); -QUnit.test('The {{link-to}} helper supports leaving off .index for nested routes', function() { - Router.map(function() { - this.route('about', function() { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); this.route('item'); }); - }); - - setTemplate('about', compile('

About

{{outlet}}')); - setTemplate('about/index', compile("
Index
")); - setTemplate('about/item', compile("
{{#link-to 'about'}}About{{/link-to}}
")); - bootApplication(); + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate('index.about', ` + {{#link-to 'item' id='other-link' currentWhen='index'}}ITEM{{/link-to}} + `); - run(router, 'handleURL', '/about/item'); + this.visit('/about'); - equal(normalizeUrl(jQuery('#item a', '#qunit-fixture').attr('href')), '/about'); -}); + assert.equal(this.$('#other-link.active').length, 1, 'The link is active since current-when is a parent route'); + } -QUnit.test('The {{link-to}} helper supports currentWhen (DEPRECATED)', function() { - expectDeprecation('Usage of `currentWhen` is deprecated, use `current-when` instead.'); + [`@test The {{link-to}} helper supports custom, nested, current-when`](assert) { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); - Router.map(function(match) { - this.route('index', { path: '/' }, function() { - this.route('about'); + this.route('item'); }); - this.route('item'); - }); - - setTemplate('index', compile('

Home

{{outlet}}')); - setTemplate('index/about', compile("{{#link-to 'item' id='other-link' currentWhen='index'}}ITEM{{/link-to}}")); + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate('index.about', ` + {{#link-to 'item' id='other-link' current-when='index'}}ITEM{{/link-to}} + `); - bootApplication(); + this.visit('/about'); - run(() => router.handleURL('/about')); + equal(this.$('#other-link.active').length, 1, 'The link is active since current-when is a parent route'); + } - equal(jQuery('#other-link.active', '#qunit-fixture').length, 1, 'The link is active since current-when is a parent route'); -}); + [`@test The {{link-to}} helper does not disregard current-when when it is given explicitly for a route`](assert) { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); -QUnit.test('The {{link-to}} helper supports custom, nested, current-when', function() { - Router.map(function(match) { - this.route('index', { path: '/' }, function() { - this.route('about'); + this.route('items', function() { + this.route('item'); + }); }); - this.route('item'); - }); + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate('index.about', ` + {{#link-to 'items' id='other-link' current-when='index'}}ITEM{{/link-to}} + `); - setTemplate('index', compile('

Home

{{outlet}}')); - setTemplate('index/about', compile("{{#link-to 'item' id='other-link' current-when='index'}}ITEM{{/link-to}}")); + this.visit('/about'); - bootApplication(); - - run(() => router.handleURL('/about')); + assert.equal(this.$('#other-link.active').length, 1, 'The link is active when current-when is given for explicitly for a route'); + } - equal(jQuery('#other-link.active', '#qunit-fixture').length, 1, 'The link is active since current-when is a parent route'); -}); + ['@test The {{link-to}} helper does not disregard current-when when it is set via a bound param'](assert) { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); -QUnit.test('The {{link-to}} helper does not disregard current-when when it is given explicitly for a route', function() { - Router.map(function(match) { - this.route('index', { path: '/' }, function() { - this.route('about'); + this.route('items', function() { + this.route('item'); + }); }); - this.route('items', function() { - this.route('item'); - }); - }); + this.add('controller:index.about', Controller.extend({ + currentWhen: 'index' + })); - setTemplate('index', compile('

Home

{{outlet}}')); - setTemplate('index/about', compile("{{#link-to 'items' id='other-link' current-when='index'}}ITEM{{/link-to}}")); + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate('index.about', `{{#link-to 'items' id='other-link' current-when=currentWhen}}ITEM{{/link-to}}`); - bootApplication(); + this.visit('/about'); - run(() => router.handleURL('/about')); - - equal(jQuery('#other-link.active', '#qunit-fixture').length, 1, 'The link is active when current-when is given for explicitly for a route'); -}); - -QUnit.test('The {{link-to}} helper does not disregard current-when when it is set via a bound param', function() { - Router.map(function(match) { - this.route('index', { path: '/' }, function() { - this.route('about'); - }); + assert.equal(this.$('#other-link.active').length, 1, 'The link is active when current-when is given for explicitly for a route'); + } - this.route('items', function() { + ['@test The {{link-to}} helper supports multiple current-when routes'](assert) { + this.router.map(function() { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); this.route('item'); + this.route('foo'); }); - }); - - App.IndexAboutController = Controller.extend({ - currentWhen: 'index' - }); - setTemplate('index', compile('

Home

{{outlet}}')); - setTemplate('index/about', compile("{{#link-to 'items' id='other-link' current-when=currentWhen}}ITEM{{/link-to}}")); + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate('index.about', `{{#link-to 'item' id='link1' current-when='item index'}}ITEM{{/link-to}}`); + this.addTemplate('item', `{{#link-to 'item' id='link2' current-when='item index'}}ITEM{{/link-to}}`); + this.addTemplate('foo', `{{#link-to 'item' id='link3' current-when='item index'}}ITEM{{/link-to}}`); - bootApplication(); + this.visit('/about'); - run(() => router.handleURL('/about')); + assert.equal(this.$('#link1.active').length, 1, 'The link is active since current-when contains the parent route'); - equal(jQuery('#other-link.active', '#qunit-fixture').length, 1, 'The link is active when current-when is given for explicitly for a route'); -}); + this.visit('/item'); -QUnit.test('The {{link-to}} helper supports multiple current-when routes', function() { - Router.map(function(match) { - this.route('index', { path: '/' }, function() { - this.route('about'); - }); - this.route('item'); - this.route('foo'); - }); + assert.equal(this.$('#link2.active').length, 1, 'The link is active since you are on the active route'); - setTemplate('index', compile('

Home

{{outlet}}')); - setTemplate('index/about', compile("{{#link-to 'item' id='link1' current-when='item index'}}ITEM{{/link-to}}")); - setTemplate('item', compile("{{#link-to 'item' id='link2' current-when='item index'}}ITEM{{/link-to}}")); - setTemplate('foo', compile("{{#link-to 'item' id='link3' current-when='item index'}}ITEM{{/link-to}}")); + this.visit('/foo'); - bootApplication(); + assert.equal(this.$('#link3.active').length, 0, 'The link is not active since current-when does not contain the active route'); + } - run(() => router.handleURL('/about')); + ['@test The {{link-to}} helper defaults to bubbling'](assert) { + this.addTemplate('about', ` +
+ {{#link-to 'about.contact' id='about-contact'}}About{{/link-to}} +
+ {{outlet}} + `); + this.addTemplate('about.contact', ` +

Contact

+ `); + + this.router.map(function() { + this.route('about', function() { + this.route('contact'); + }); + }); - equal(jQuery('#link1.active', '#qunit-fixture').length, 1, 'The link is active since current-when contains the parent route'); + let hidden = 0; - run(() => router.handleURL('/item')); + this.add('route:about', Route.extend({ + actions: { + hide() { + hidden++; + } + } + })); - equal(jQuery('#link2.active', '#qunit-fixture').length, 1, 'The link is active since you are on the active route'); + this.visit('/about'); - run(() => router.handleURL('/foo')); + this.click('#about-contact'); - equal(jQuery('#link3.active', '#qunit-fixture').length, 0, 'The link is not active since current-when does not contain the active route'); -}); + assert.equal(this.$('#contact').text(), 'Contact', 'precond - the link worked'); -QUnit.test('The {{link-to}} helper defaults to bubbling', function() { - setTemplate('about', compile("
{{#link-to 'about.contact' id='about-contact'}}About{{/link-to}}
{{outlet}}")); - setTemplate('about/contact', compile("

Contact

")); + assert.equal(hidden, 1, 'The link bubbles'); + } - Router.map(function() { - this.route('about', function() { - this.route('contact'); + [`@test The {{link-to}} helper supports bubbles=false`](assert) { + this.addTemplate('about', ` +
+ {{#link-to 'about.contact' id='about-contact' bubbles=false}} + About + {{/link-to}} +
+ {{outlet}} + `); + this.addTemplate('about.contact', `

Contact

`); + + this.router.map(function() { + this.route('about', function() { + this.route('contact'); + }); }); - }); - let hidden = 0; + let hidden = 0; - App.AboutRoute = Route.extend({ - actions: { - hide() { - hidden++; + this.add('route:about', Route.extend({ + actions: { + hide() { + hidden++; + } } - } - }); - - bootApplication(); - - run(() => router.handleURL('/about')); + })); - run(() => jQuery('#about-contact', '#qunit-fixture').click()); + this.visit('/about'); - equal(jQuery('#contact', '#qunit-fixture').text(), 'Contact', 'precond - the link worked'); + this.click('#about-contact'); - equal(hidden, 1, 'The link bubbles'); -}); + assert.equal(this.$('#contact').text(), 'Contact', 'precond - the link worked'); -QUnit.test('The {{link-to}} helper supports bubbles=false', function() { - setTemplate('about', compile("
{{#link-to 'about.contact' id='about-contact' bubbles=false}}About{{/link-to}}
{{outlet}}")); - setTemplate('about/contact', compile("

Contact

")); + assert.equal(hidden, 0, "The link didn't bubble"); + } - Router.map(function() { - this.route('about', function() { - this.route('contact'); + [`@test The {{link-to}} helper supports bubbles=boundFalseyThing`](assert) { + this.addTemplate('about', ` +
+ {{#link-to 'about.contact' id='about-contact' bubbles=boundFalseyThing}} + About + {{/link-to}} +
+ {{outlet}} + `); + this.addTemplate('about.contact', `

Contact

`); + + this.add('controller:about', Controller.extend({ + boundFalseyThing: false + })); + + this.router.map(function() { + this.route('about', function() { + this.route('contact'); + }); }); - }); - let hidden = 0; + let hidden = 0; - App.AboutRoute = Route.extend({ - actions: { - hide() { - hidden++; + this.add('route:about', Route.extend({ + actions: { + hide() { + hidden++; + } } - } - }); + })); - bootApplication(); + this.visit('/about'); + this.click('#about-contact'); - run(() => router.handleURL('/about')); - - run(() => jQuery('#about-contact', '#qunit-fixture').click()); - - equal(jQuery('#contact', '#qunit-fixture').text(), 'Contact', 'precond - the link worked'); - - equal(hidden, 0, "The link didn't bubble"); -}); - -QUnit.test('The {{link-to}} helper supports bubbles=boundFalseyThing', function() { - setTemplate('about', compile("
{{#link-to 'about.contact' id='about-contact' bubbles=boundFalseyThing}}About{{/link-to}}
{{outlet}}")); - setTemplate('about/contact', compile("

Contact

")); - - App.AboutController = Controller.extend({ - boundFalseyThing: false - }); + assert.equal(this.$('#contact').text(), 'Contact', 'precond - the link worked'); + assert.equal(hidden, 0, "The link didn't bubble"); + } - Router.map(function() { - this.route('about', function() { - this.route('contact'); + [`@test The {{link-to}} helper moves into the named route with context`](assert) { + this.router.map(function() { + this.route('about'); + this.route('item', { path: '/item/:id' }); }); - }); - - let hidden = 0; - App.AboutRoute = Route.extend({ - actions: { - hide() { - hidden++; + this.addTemplate('about', ` +

List

+
    + {{#each model as |person|}} +
  • + {{#link-to 'item' person}} + {{person.name}} + {{/link-to}} +
  • + {{/each}} +
+ {{#link-to 'index' id='home-link'}}Home{{/link-to}} + `); + + this.addTemplate('item', ` +

Item

+

{{model.name}}

+ {{#link-to 'index' id='home-link'}}Home{{/link-to}} + `); + + this.addTemplate('index', ` +

Home

+ {{#link-to 'about' id='about-link'}}About{{/link-to}} + `); + + this.add('route:about', Route.extend({ + model() { + return [ + { id: 'yehuda', name: 'Yehuda Katz' }, + { id: 'tom', name: 'Tom Dale' }, + { id: 'erik', name: 'Erik Brynroflsson' } + ]; } - } - }); + })); - bootApplication(); + this.visit('/about'); - run(() => router.handleURL('/about')); - run(() => jQuery('#about-contact', '#qunit-fixture').click()); + assert.equal(this.$('h3:contains(List)').length, 1, 'The home template was rendered'); + assert.equal(normalizeUrl(this.$('#home-link').attr('href')), '/', 'The home link points back at /'); - equal(jQuery('#contact', '#qunit-fixture').text(), 'Contact', 'precond - the link worked'); + this.click('li a:contains(Yehuda)'); - equal(hidden, 0, "The link didn't bubble"); -}); + assert.equal(this.$('h3:contains(Item)').length, 1, 'The item template was rendered'); + assert.equal(this.$('p').text(), 'Yehuda Katz', 'The name is correct'); -QUnit.test('The {{link-to}} helper moves into the named route with context', function() { - Router.map(function(match) { - this.route('about'); - this.route('item', { path: '/item/:id' }); - }); + this.click('#home-link'); + this.click('#about-link'); - setTemplate('about', compile("

List

    {{#each model as |person|}}
  • {{#link-to 'item' person}}{{person.name}}{{/link-to}}
  • {{/each}}
{{#link-to 'index' id='home-link'}}Home{{/link-to}}")); + assert.equal(normalizeUrl(this.$('li a:contains(Yehuda)').attr('href')), '/item/yehuda'); + assert.equal(normalizeUrl(this.$('li a:contains(Tom)').attr('href')), '/item/tom'); + assert.equal(normalizeUrl(this.$('li a:contains(Erik)').attr('href')), '/item/erik'); - App.AboutRoute = Route.extend({ - model() { - return emberA([ - { id: 'yehuda', name: 'Yehuda Katz' }, - { id: 'tom', name: 'Tom Dale' }, - { id: 'erik', name: 'Erik Brynroflsson' } - ]); - } - }); + this.click('li a:contains(Erik)'); - bootApplication(); - - run(() => router.handleURL('/about')); - - equal(jQuery('h3:contains(List)', '#qunit-fixture').length, 1, 'The home template was rendered'); - equal(normalizeUrl(jQuery('#home-link').attr('href')), '/', 'The home link points back at /'); - - run(() => jQuery('li a:contains(Yehuda)', '#qunit-fixture').click()); + assert.equal(this.$('h3:contains(Item)').length, 1, 'The item template was rendered'); + assert.equal(this.$('p').text(), 'Erik Brynroflsson', 'The name is correct'); + } - equal(jQuery('h3:contains(Item)', '#qunit-fixture').length, 1, 'The item template was rendered'); - equal(jQuery('p', '#qunit-fixture').text(), 'Yehuda Katz', 'The name is correct'); + [`@test The {{link-to}} helper binds some anchor html tag common attributes`](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'index' id='self-link' title='title-attr' rel='rel-attr' tabindex='-1'}} + Self + {{/link-to}} + `); - run(() => jQuery('#home-link').click()); - run(() => jQuery('#about-link').click()); + this.visit('/'); - equal(normalizeUrl(jQuery('li a:contains(Yehuda)').attr('href')), '/item/yehuda'); - equal(normalizeUrl(jQuery('li a:contains(Tom)').attr('href')), '/item/tom'); - equal(normalizeUrl(jQuery('li a:contains(Erik)').attr('href')), '/item/erik'); + let link = this.$('#self-link'); + assert.equal(link.attr('title'), 'title-attr', 'The self-link contains title attribute'); + assert.equal(link.attr('rel'), 'rel-attr', 'The self-link contains rel attribute'); + assert.equal(link.attr('tabindex'), '-1', 'The self-link contains tabindex attribute'); + } - run(() => jQuery('li a:contains(Erik)', '#qunit-fixture').click()); + [`@test The {{link-to}} helper supports 'target' attribute`](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'index' id='self-link' target='_blank'}}Self{{/link-to}} + `); - equal(jQuery('h3:contains(Item)', '#qunit-fixture').length, 1, 'The item template was rendered'); - equal(jQuery('p', '#qunit-fixture').text(), 'Erik Brynroflsson', 'The name is correct'); -}); + this.visit('/'); -QUnit.test('The {{link-to}} helper binds some anchor html tag common attributes', function() { - setTemplate('index', compile("

Home

{{#link-to 'index' id='self-link' title='title-attr' rel='rel-attr' tabindex='-1'}}Self{{/link-to}}")); - bootApplication(); + let link = this.$('#self-link'); + assert.equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute'); + } - run(() => router.handleURL('/')); + [`@test The {{link-to}} helper supports 'target' attribute specified as a bound param`](assert) { + this.addTemplate('index', `

Home

{{#link-to 'index' id='self-link' target=boundLinkTarget}}Self{{/link-to}}`); - let link = jQuery('#self-link', '#qunit-fixture'); - equal(link.attr('title'), 'title-attr', 'The self-link contains title attribute'); - equal(link.attr('rel'), 'rel-attr', 'The self-link contains rel attribute'); - equal(link.attr('tabindex'), '-1', 'The self-link contains tabindex attribute'); -}); + this.add('controller:index', Controller.extend({ + boundLinkTarget: '_blank' + })); -QUnit.test('The {{link-to}} helper supports `target` attribute', function() { - setTemplate('index', compile("

Home

{{#link-to 'index' id='self-link' target='_blank'}}Self{{/link-to}}")); - bootApplication(); + this.visit('/'); - run(() => router.handleURL('/')); + let link = this.$('#self-link'); + assert.equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute'); + } - let link = jQuery('#self-link', '#qunit-fixture'); - equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute'); -}); + [`@test the {{link-to}} helper calls preventDefault`](assert) { + this.router.map(function() { + this.route('about'); + }); -QUnit.test('The {{link-to}} helper supports `target` attribute specified as a bound param', function() { - setTemplate('index', compile("

Home

{{#link-to 'index' id='self-link' target=boundLinkTarget}}Self{{/link-to}}")); + this.addTemplate('index', ` + {{#link-to 'about' id='about-link'}}About{{/link-to}} + `); - App.IndexController = Controller.extend({ - boundLinkTarget: '_blank' - }); + this.visit('/'); - bootApplication(); + let event = jQuery.Event('click'); + this.$('#about-link').trigger(event); - run(() => router.handleURL('/')); + assert.equal(event.isDefaultPrevented(), true, 'should preventDefault'); + } - let link = jQuery('#self-link', '#qunit-fixture'); - equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute'); -}); + [`@test the {{link-to}} helper does not call preventDefault if 'preventDefault=false' is passed as an option`](assert) { + this.router.map(function() { + this.route('about'); + }); -QUnit.test('The {{link-to}} helper does not call preventDefault if `target` attribute is provided', function() { - setTemplate('index', compile("

Home

{{#link-to 'index' id='self-link' target='_blank'}}Self{{/link-to}}")); - bootApplication(); + this.addTemplate('index', ` + {{#link-to 'about' id='about-link' preventDefault=false}}About{{/link-to}} + `); - run(() => router.handleURL('/')); + this.visit('/'); - let event = jQuery.Event('click'); - jQuery('#self-link', '#qunit-fixture').trigger(event); + let event = jQuery.Event('click'); + this.$('#about-link').trigger(event); - equal(event.isDefaultPrevented(), false, 'should not preventDefault when target attribute is specified'); -}); + assert.equal(event.isDefaultPrevented(), false, 'should not preventDefault'); + } -QUnit.test('The {{link-to}} helper should preventDefault when `target = _self`', function() { - setTemplate('index', compile("

Home

{{#link-to 'index' id='self-link' target='_self'}}Self{{/link-to}}")); - bootApplication(); + [`@test the {{link-to}} helper does not call preventDefault if 'preventDefault=boundFalseyThing' is passed as an option`](assert) { + this.router.map(function() { + this.route('about'); + }); - run(() => router.handleURL('/')); + this.addTemplate('index', ` + {{#link-to 'about' id='about-link' preventDefault=boundFalseyThing}}About{{/link-to}} + `); - let event = jQuery.Event('click'); - jQuery('#self-link', '#qunit-fixture').trigger(event); + this.add('controller:index', Controller.extend({ + boundFalseyThing: false + })); - equal(event.isDefaultPrevented(), true, 'should preventDefault when target attribute is `_self`'); -}); + this.visit('/'); -QUnit.test('The {{link-to}} helper should not transition if target is not equal to _self or empty', function() { - setTemplate('index', compile("{{#link-to 'about' id='about-link' replace=true target='_blank'}}About{{/link-to}}")); + let event = jQuery.Event('click'); + this.$('#about-link').trigger(event); - Router.map(function() { - this.route('about'); - }); + equal(event.isDefaultPrevented(), false, 'should not preventDefault'); + } - bootApplication(); + [`@test The {{link-to}} helper does not call preventDefault if 'target' attribute is provided`](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'index' id='self-link' target='_blank'}}Self{{/link-to}} + `); - run(() => router.handleURL('/')); - run(() => jQuery('#about-link', '#qunit-fixture').click()); + this.visit('/'); - notEqual(appInstance.lookup('controller:application').get('currentRouteName'), 'about', 'link-to should not transition if target is not equal to _self or empty'); -}); + let event = jQuery.Event('click'); + this.$('#self-link').trigger(event); -QUnit.test('The {{link-to}} helper accepts string/numeric arguments', function() { - Router.map(function() { - this.route('filter', { path: '/filters/:filter' }); - this.route('post', { path: '/post/:post_id' }); - this.route('repo', { path: '/repo/:owner/:name' }); - }); + assert.equal(event.isDefaultPrevented(), false, 'should not preventDefault when target attribute is specified'); + } - App.FilterController = Controller.extend({ - filter: 'unpopular', - repo: EmberObject.create({ owner: 'ember', name: 'ember.js' }), - post_id: 123 - }); - setTemplate('filter', compile('

{{filter}}

{{#link-to "filter" "unpopular" id="link"}}Unpopular{{/link-to}}{{#link-to "filter" filter id="path-link"}}Unpopular{{/link-to}}{{#link-to "post" post_id id="post-path-link"}}Post{{/link-to}}{{#link-to "post" 123 id="post-number-link"}}Post{{/link-to}}{{#link-to "repo" repo id="repo-object-link"}}Repo{{/link-to}}')); + [`@test The {{link-to}} helper should preventDefault when 'target = _self'`](assert) { + this.addTemplate('index', ` +

Home

+ {{#link-to 'index' id='self-link' target='_self'}}Self{{/link-to}} + `); - setTemplate('index', compile(' ')); + this.visit('/'); - bootApplication(); + let event = jQuery.Event('click'); + this.$('#self-link').trigger(event); - run(() => router.handleURL('/filters/popular')); + equal(event.isDefaultPrevented(), true, 'should preventDefault when target attribute is `_self`'); + } - equal(normalizeUrl(jQuery('#link', '#qunit-fixture').attr('href')), '/filters/unpopular'); - equal(normalizeUrl(jQuery('#path-link', '#qunit-fixture').attr('href')), '/filters/unpopular'); - equal(normalizeUrl(jQuery('#post-path-link', '#qunit-fixture').attr('href')), '/post/123'); - equal(normalizeUrl(jQuery('#post-number-link', '#qunit-fixture').attr('href')), '/post/123'); - equal(normalizeUrl(jQuery('#repo-object-link', '#qunit-fixture').attr('href')), '/repo/ember/ember.js'); -}); + [`@test The {{link-to}} helper should not transition if target is not equal to _self or empty`](assert) { + this.addTemplate('index', ` + {{#link-to 'about' id='about-link' replace=true target='_blank'}} + About + {{/link-to}} + `); -QUnit.test("Issue 4201 - Shorthand for route.index shouldn't throw errors about context arguments", function() { - expect(2); - Router.map(function() { - this.route('lobby', function() { - this.route('index', { path: ':lobby_id' }); - this.route('list'); + this.router.map(function() { + this.route('about'); }); - }); - - App.LobbyIndexRoute = Route.extend({ - model(params) { - equal(params.lobby_id, 'foobar'); - return params.lobby_id; - } - }); - - setTemplate('lobby/index', compile("{{#link-to 'lobby' 'foobar' id='lobby-link'}}Lobby{{/link-to}}")); - setTemplate('index', compile('')); - setTemplate('lobby/list', compile("{{#link-to 'lobby' 'foobar' id='lobby-link'}}Lobby{{/link-to}}")); - bootApplication(); - run(router, 'handleURL', '/lobby/list'); - run(jQuery('#lobby-link'), 'click'); - shouldBeActive('#lobby-link'); -}); -QUnit.test('Quoteless route param performs property lookup', function() { - setTemplate('index', compile("{{#link-to 'index' id='string-link'}}string{{/link-to}}{{#link-to foo id='path-link'}}path{{/link-to}}")); + this.visit('/'); + this.click('#about-link'); - function assertEquality(href) { - equal(normalizeUrl(jQuery('#string-link', '#qunit-fixture').attr('href')), '/'); - equal(normalizeUrl(jQuery('#path-link', '#qunit-fixture').attr('href')), href); + let currentRouteName = this.applicationInstance.lookup('controller:application').get('currentRouteName'); + assert.notEqual(currentRouteName, 'about', 'link-to should not transition if target is not equal to _self or empty'); } - App.IndexController = Controller.extend({ - foo: 'index' - }); - - App.Router.map(function() { - this.route('about'); - }); + [`@test The {{link-to}} helper accepts string/numeric arguments`](assert) { + this.router.map(function() { + this.route('filter', { path: '/filters/:filter' }); + this.route('post', { path: '/post/:post_id' }); + this.route('repo', { path: '/repo/:owner/:name' }); + }); - bootApplication(); + this.add('controller:filter', Controller.extend({ + filter: 'unpopular', + repo: { owner: 'ember', name: 'ember.js' }, + post_id: 123 + })); + + this.addTemplate('filter', ` +

{{filter}}

+ {{#link-to "filter" "unpopular" id="link"}}Unpopular{{/link-to}} + {{#link-to "filter" filter id="path-link"}}Unpopular{{/link-to}} + {{#link-to "post" post_id id="post-path-link"}}Post{{/link-to}} + {{#link-to "post" 123 id="post-number-link"}}Post{{/link-to}} + {{#link-to "repo" repo id="repo-object-link"}}Repo{{/link-to}} + `); + + this.visit('/filters/popular'); + + assert.equal(normalizeUrl(this.$('#link').attr('href')), '/filters/unpopular'); + assert.equal(normalizeUrl(this.$('#path-link').attr('href')), '/filters/unpopular'); + assert.equal(normalizeUrl(this.$('#post-path-link').attr('href')), '/post/123'); + assert.equal(normalizeUrl(this.$('#post-number-link').attr('href')), '/post/123'); + assert.equal(normalizeUrl(this.$('#repo-object-link').attr('href')), '/repo/ember/ember.js'); + } - run(router, 'handleURL', '/'); + [`@test Issue 4201 - Shorthand for route.index shouldn't throw errors about context arguments`](assert) { + assert.expect(2); + this.router.map(function() { + this.route('lobby', function() { + this.route('index', { path: ':lobby_id' }); + this.route('list'); + }); + }); - assertEquality('/'); + this.add('route:lobby.index', Route.extend({ + model(params) { + assert.equal(params.lobby_id, 'foobar'); + return params.lobby_id; + } + })); - let controller = appInstance.lookup('controller:index'); - run(() => controller.set('foo', 'about')); + this.addTemplate('lobby.index', ` + {{#link-to 'lobby' 'foobar' id='lobby-link'}}Lobby{{/link-to}} + `); + this.addTemplate('lobby.list', ` + {{#link-to 'lobby' 'foobar' id='lobby-link'}}Lobby{{/link-to}} + `); - assertEquality('/about'); -}); + this.visit('/lobby/list'); + this.click('#lobby-link'); -QUnit.test('link-to with null/undefined dynamic parameters are put in a loading state', function() { - expect(19); + shouldBeActive(assert, this.$('#lobby-link')); + } - let oldWarn = Logger.warn; - let warnCalled = false; - Logger.warn = function() { warnCalled = true; }; - setTemplate('index', compile("{{#link-to destinationRoute routeContext loadingClass='i-am-loading' id='context-link'}}string{{/link-to}}{{#link-to secondRoute loadingClass=loadingClass id='static-link'}}string{{/link-to}}")); + [`@test Quoteless route param performs property lookup`](assert) { + this.router.map(function() { + this.route('about'); + }); - let thing = EmberObject.create({ id: 123 }); + this.addTemplate('index', ` + {{#link-to 'index' id='string-link'}}string{{/link-to}} + {{#link-to foo id='path-link'}}path{{/link-to}} + `); - App.IndexController = Controller.extend({ - destinationRoute: null, - routeContext: null, - loadingClass: 'i-am-loading' - }); + this.add('controller:index', Controller.extend({ + foo: 'index' + })); - App.AboutRoute = Route.extend({ - activate() { - ok(true, 'About was entered'); + let assertEquality = href => { + assert.equal(normalizeUrl(this.$('#string-link').attr('href')), '/'); + assert.equal(normalizeUrl(this.$('#path-link').attr('href')), href); } - }); - App.Router.map(function() { - this.route('thing', { path: '/thing/:thing_id' }); - this.route('about'); - }); + this.visit('/'); - bootApplication(); + assertEquality('/'); - run(router, 'handleURL', '/'); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('foo', 'about')); - function assertLinkStatus($link, url) { - if (url) { - equal(normalizeUrl($link.attr('href')), url, 'loaded link-to has expected href'); - ok(!$link.hasClass('i-am-loading'), 'loaded linkComponent has no loadingClass'); - } else { - equal(normalizeUrl($link.attr('href')), '#', "unloaded link-to has href='#'"); - ok($link.hasClass('i-am-loading'), 'loading linkComponent has loadingClass'); - } + assertEquality('/about'); } - let $contextLink = jQuery('#context-link', '#qunit-fixture'); - let $staticLink = jQuery('#static-link', '#qunit-fixture'); - let controller = appInstance.lookup('controller:index'); - - assertLinkStatus($contextLink); - assertLinkStatus($staticLink); - - run(() => { - warnCalled = false; - $contextLink.click(); - ok(warnCalled, 'Logger.warn was called from clicking loading link'); - }); - - // Set the destinationRoute (context is still null). - run(controller, 'set', 'destinationRoute', 'thing'); - assertLinkStatus($contextLink); - - // Set the routeContext to an id - run(controller, 'set', 'routeContext', '456'); - assertLinkStatus($contextLink, '/thing/456'); - - // Test that 0 isn't interpreted as falsy. - run(controller, 'set', 'routeContext', 0); - assertLinkStatus($contextLink, '/thing/0'); - - // Set the routeContext to an object - run(controller, 'set', 'routeContext', thing); - assertLinkStatus($contextLink, '/thing/123'); - - // Set the destinationRoute back to null. - run(controller, 'set', 'destinationRoute', null); - assertLinkStatus($contextLink); - - run(() => { - warnCalled = false; - $staticLink.click(); - ok(warnCalled, 'Logger.warn was called from clicking loading link'); - }); - - run(controller, 'set', 'secondRoute', 'about'); - assertLinkStatus($staticLink, '/about'); - - // Click the now-active link - run($staticLink, 'click'); - - Logger.warn = oldWarn; -}); - -QUnit.test('The {{link-to}} helper refreshes href element when one of params changes', function() { - Router.map(function() { - this.route('post', { path: '/posts/:post_id' }); - }); - - let post = EmberObject.create({ id: '1' }); - let secondPost = EmberObject.create({ id: '2' }); - - setTemplate('index', compile('{{#link-to "post" post id="post"}}post{{/link-to}}')); + [`@test The {{link-to}} helper refreshes href element when one of params changes`](assert) { + this.router.map(function() { + this.route('post', { path: '/posts/:post_id' }); + }); - App.IndexController = Controller.extend(); - let indexController = appInstance.lookup('controller:index'); + let post = { id: '1' }; + let secondPost = { id: '2' }; - run(() => indexController.set('post', post)); + this.addTemplate('index', ` + {{#link-to "post" post id="post"}}post{{/link-to}} + `); - bootApplication(); + this.add('controller:index', Controller.extend()); - run(() => router.handleURL('/')); + this.visit('/'); - equal(normalizeUrl(jQuery('#post', '#qunit-fixture').attr('href')), '/posts/1', 'precond - Link has rendered href attr properly'); + let indexController = this.applicationInstance.lookup('controller:index'); + this.runTask(() => indexController.set('post', post)); - run(() => indexController.set('post', secondPost)); + assert.equal(normalizeUrl(this.$('#post').attr('href')), '/posts/1', 'precond - Link has rendered href attr properly'); - equal(jQuery('#post', '#qunit-fixture').attr('href'), '/posts/2', 'href attr was updated after one of the params had been changed'); + this.runTask(() => indexController.set('post', secondPost)); - run(() => indexController.set('post', null)); + assert.equal(this.$('#post').attr('href'), '/posts/2', 'href attr was updated after one of the params had been changed'); - equal(jQuery('#post', '#qunit-fixture').attr('href'), '#', 'href attr becomes # when one of the arguments in nullified'); -}); + this.runTask(() => indexController.set('post', null)); + assert.equal(this.$('#post').attr('href'), '#', 'href attr becomes # when one of the arguments in nullified'); + } -QUnit.test('The {{link-to}} helper is active when a route is active', function() { - Router.map(function() { - this.route('about', function() { - this.route('item'); + [`@test The {{link-to}} helper is active when a route is active`](assert) { + this.router.map(function() { + this.route('about', function() { + this.route('item'); + }); }); - }); - setTemplate('about', compile("
{{#link-to 'about' id='about-link'}}About{{/link-to}} {{#link-to 'about.item' id='item-link'}}Item{{/link-to}} {{outlet}}
")); - setTemplate('about/item', compile(' ')); - setTemplate('about/index', compile(' ')); + this.addTemplate('about', ` +
+ {{#link-to 'about' id='about-link'}}About{{/link-to}} + {{#link-to 'about.item' id='item-link'}}Item{{/link-to}} + {{outlet}} +
+ `); - bootApplication(); + this.visit('/about'); - run(router, 'handleURL', '/about'); + assert.equal(this.$('#about-link.active').length, 1, 'The about route link is active'); + assert.equal(this.$('#item-link.active').length, 0, 'The item route link is inactive'); - equal(jQuery('#about-link.active', '#qunit-fixture').length, 1, 'The about route link is active'); - equal(jQuery('#item-link.active', '#qunit-fixture').length, 0, 'The item route link is inactive'); + this.visit('/about/item'); - run(router, 'handleURL', '/about/item'); + assert.equal(this.$('#about-link.active').length, 1, 'The about route link is active'); + assert.equal(this.$('#item-link.active').length, 1, 'The item route link is active'); + } - equal(jQuery('#about-link.active', '#qunit-fixture').length, 1, 'The about route link is active'); - equal(jQuery('#item-link.active', '#qunit-fixture').length, 1, 'The item route link is active'); -}); + [`@test The {{link-to}} helper works in an #each'd array of string route names`](assert) { + this.router.map(function() { + this.route('foo'); + this.route('bar'); + this.route('rar'); + }); -QUnit.test("The {{link-to}} helper works in an #each'd array of string route names", function() { - Router.map(function() { - this.route('foo'); - this.route('bar'); - this.route('rar'); - }); + this.add('controller:index', Controller.extend({ + routeNames: emberA(['foo', 'bar', 'rar']), + route1: 'bar', + route2: 'foo' + })); + + this.addTemplate('index', ` + {{#each routeNames as |routeName|}} + {{#link-to routeName}}{{routeName}}{{/link-to}} + {{/each}} + {{#each routeNames as |r|}} + {{#link-to r}}{{r}}{{/link-to}} + {{/each}} + {{#link-to route1}}a{{/link-to}} + {{#link-to route2}}b{{/link-to}} + `); + + this.visit('/'); + + let linksEqual = (links, expected) => { + equal(links.length, expected.length, 'Has correct number of links'); + + let idx; + for (idx = 0; idx < links.length; idx++) { + let href = this.$(links[idx]).attr('href'); + // Old IE includes the whole hostname as well + assert.equal(href.slice(-expected[idx].length), expected[idx], `Expected link to be '${expected[idx]}', but was '${href}'`); + } + } - App.IndexController = Controller.extend({ - routeNames: emberA(['foo', 'bar', 'rar']), - route1: 'bar', - route2: 'foo' - }); + linksEqual(this.$('a'), ['/foo', '/bar', '/rar', '/foo', '/bar', '/rar', '/bar', '/foo']); - setTemplate('index', compile('{{#each routeNames as |routeName|}}{{#link-to routeName}}{{routeName}}{{/link-to}}{{/each}}{{#each routeNames as |r|}}{{#link-to r}}{{r}}{{/link-to}}{{/each}}{{#link-to route1}}a{{/link-to}}{{#link-to route2}}b{{/link-to}}')); + let indexController = this.applicationInstance.lookup('controller:index'); + this.runTask(() => indexController.set('route1', 'rar')); - bootApplication(); + linksEqual(this.$('a'), ['/foo', '/bar', '/rar', '/foo', '/bar', '/rar', '/rar', '/foo']); - function linksEqual($links, expected) { - equal($links.length, expected.length, 'Has correct number of links'); + this.runTask(() => indexController.routeNames.shiftObject()); - let idx; - for (idx = 0; idx < $links.length; idx++) { - let href = jQuery($links[idx]).attr('href'); - // Old IE includes the whole hostname as well - equal(href.slice(-expected[idx].length), expected[idx], `Expected link to be '${expected[idx]}', but was '${href}'`); - } + linksEqual(this.$('a'), ['/bar', '/rar', '/bar', '/rar', '/rar', '/foo']); } - linksEqual(jQuery('a', '#qunit-fixture'), ['/foo', '/bar', '/rar', '/foo', '/bar', '/rar', '/bar', '/foo']); - - let indexController = appInstance.lookup('controller:index'); - run(indexController, 'set', 'route1', 'rar'); + [`@test The non-block form {{link-to}} helper moves into the named route`](assert) { + assert.expect(3); + this.router.map(function() { + this.route('contact'); + }); - linksEqual(jQuery('a', '#qunit-fixture'), ['/foo', '/bar', '/rar', '/foo', '/bar', '/rar', '/rar', '/foo']); + this.addTemplate('index', ` +

Home

+ {{link-to 'Contact us' 'contact' id='contact-link'}} + {{#link-to 'index' id='self-link'}}Self{{/link-to}} + `); + this.addTemplate('contact', ` +

Contact

+ {{link-to 'Home' 'index' id='home-link'}} + {{link-to 'Self' 'contact' id='self-link'}} + `); - run(indexController.routeNames, 'shiftObject'); + this.visit('/'); - linksEqual(jQuery('a', '#qunit-fixture'), ['/bar', '/rar', '/bar', '/rar', '/rar', '/foo']); -}); + this.click('#contact-link'); -QUnit.test('The non-block form {{link-to}} helper moves into the named route', function() { - expect(3); - Router.map(function(match) { - this.route('contact'); - }); + assert.equal(this.$('h3:contains(Contact)').length, 1, 'The contact template was rendered'); + assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class'); + assert.equal(this.$('#home-link:not(.active)').length, 1, 'The other link was rendered without active class'); + } - setTemplate('index', compile("

Home

{{link-to 'Contact us' 'contact' id='contact-link'}}{{#link-to 'index' id='self-link'}}Self{{/link-to}}")); - setTemplate('contact', compile("

Contact

{{link-to 'Home' 'index' id='home-link'}}{{link-to 'Self' 'contact' id='self-link'}}")); + [`@test The non-block form {{link-to}} helper updates the link text when it is a binding`](assert) { + assert.expect(8); + this.router.map(function() { + this.route('contact'); + }); - bootApplication(); + this.add('controller:index', Controller.extend({ + contactName: 'Jane' + })); - run(() => jQuery('#contact-link', '#qunit-fixture').click()); + this.addTemplate('index', ` +

Home

+ {{link-to contactName 'contact' id='contact-link'}} + {{#link-to 'index' id='self-link'}}Self{{/link-to}} + `); + this.addTemplate('contact', ` +

Contact

+ {{link-to 'Home' 'index' id='home-link'}} + {{link-to 'Self' 'contact' id='self-link'}} + `); - equal(jQuery('h3:contains(Contact)', '#qunit-fixture').length, 1, 'The contact template was rendered'); - equal(jQuery('#self-link.active', '#qunit-fixture').length, 1, 'The self-link was rendered with active class'); - equal(jQuery('#home-link:not(.active)', '#qunit-fixture').length, 1, 'The other link was rendered without active class'); -}); + this.visit('/'); -QUnit.test('The non-block form {{link-to}} helper updates the link text when it is a binding', function() { - expect(8); - Router.map(function(match) { - this.route('contact'); - }); - App.IndexController = Controller.extend({ - contactName: 'Jane' - }); + assert.equal(this.$('#contact-link:contains(Jane)').length, 1, 'The link title is correctly resolved'); - setTemplate('index', compile("

Home

{{link-to contactName 'contact' id='contact-link'}}{{#link-to 'index' id='self-link'}}Self{{/link-to}}")); - setTemplate('contact', compile("

Contact

{{link-to 'Home' 'index' id='home-link'}}{{link-to 'Self' 'contact' id='self-link'}}")); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('contactName', 'Joe')); - bootApplication(); + assert.equal(this.$('#contact-link:contains(Joe)').length, 1, 'The link title is correctly updated when the bound property changes'); - run(() => router.handleURL('/')); + this.runTask(() => controller.set('contactName', 'Robert')); - let controller = appInstance.lookup('controller:index'); + assert.equal(this.$('#contact-link:contains(Robert)').length, 1, 'The link title is correctly updated when the bound property changes a second time'); - equal(jQuery('#contact-link:contains(Jane)', '#qunit-fixture').length, 1, 'The link title is correctly resolved'); + this.click('#contact-link'); - run(() => controller.set('contactName', 'Joe')); + assert.equal(this.$('h3:contains(Contact)').length, 1, 'The contact template was rendered'); + assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class'); + assert.equal(this.$('#home-link:not(.active)').length, 1, 'The other link was rendered without active class'); - equal(jQuery('#contact-link:contains(Joe)', '#qunit-fixture').length, 1, 'The link title is correctly updated when the bound property changes'); + this.click('#home-link'); - run(() => controller.set('contactName', 'Robert')); + assert.equal(this.$('h3:contains(Home)').length, 1, 'The index template was rendered'); + assert.equal(this.$('#contact-link:contains(Robert)').length, 1, 'The link title is correctly updated when the route changes'); + } - equal(jQuery('#contact-link:contains(Robert)', '#qunit-fixture').length, 1, 'The link title is correctly updated when the bound property changes a second time'); + [`@test The non-block form {{link-to}} helper moves into the named route with context`](assert) { + assert.expect(5); - run(() => jQuery('#contact-link', '#qunit-fixture').click()); + this.router.map(function() { + this.route('item', { path: '/item/:id' }); + }); - equal(jQuery('h3:contains(Contact)', '#qunit-fixture').length, 1, 'The contact template was rendered'); - equal(jQuery('#self-link.active', '#qunit-fixture').length, 1, 'The self-link was rendered with active class'); - equal(jQuery('#home-link:not(.active)', '#qunit-fixture').length, 1, 'The other link was rendered without active class'); + this.add('route:index', Route.extend({ + model() { + return [ + { id: 'yehuda', name: 'Yehuda Katz' }, + { id: 'tom', name: 'Tom Dale' }, + { id: 'erik', name: 'Erik Brynroflsson' } + ]; + } + })); + + this.addTemplate('index', ` +

Home

+
    + {{#each model as |person|}} +
  • + {{link-to person.name 'item' person}} +
  • + {{/each}} +
+ `); + this.addTemplate('item', ` +

Item

+

{{model.name}}

+ {{#link-to 'index' id='home-link'}}Home{{/link-to}} + `); + + this.visit('/'); + + this.click('li a:contains(Yehuda)'); + + assert.equal(this.$('h3:contains(Item)').length, 1, 'The item template was rendered'); + assert.equal(this.$('p').text(), 'Yehuda Katz', 'The name is correct'); + + this.click('#home-link'); + + assert.equal(normalizeUrl(this.$('li a:contains(Yehuda)').attr('href')), '/item/yehuda'); + assert.equal(normalizeUrl(this.$('li a:contains(Tom)').attr('href')), '/item/tom'); + assert.equal(normalizeUrl(this.$('li a:contains(Erik)').attr('href')), '/item/erik'); + } - run(() => jQuery('#home-link', '#qunit-fixture').click()); + [`@test The non-block form {{link-to}} performs property lookup`](assert) { + this.router.map(function() { + this.route('about'); + }); - equal(jQuery('h3:contains(Home)', '#qunit-fixture').length, 1, 'The index template was rendered'); - equal(jQuery('#contact-link:contains(Robert)', '#qunit-fixture').length, 1, 'The link title is correctly updated when the route changes'); -}); + this.addTemplate('index', ` + {{link-to 'string' 'index' id='string-link'}} + {{link-to path foo id='path-link'}} + `); -QUnit.test('The non-block form {{link-to}} helper moves into the named route with context', function() { - expect(5); + this.add('controller:index', Controller.extend({ + foo: 'index' + })); - Router.map(function(match) { - this.route('item', { path: '/item/:id' }); - }); + this.visit('/'); - App.IndexRoute = Route.extend({ - model() { - return emberA([ - { id: 'yehuda', name: 'Yehuda Katz' }, - { id: 'tom', name: 'Tom Dale' }, - { id: 'erik', name: 'Erik Brynroflsson' } - ]); + let assertEquality = href => { + assert.equal(normalizeUrl(this.$('#string-link').attr('href')), '/'); + assert.equal(normalizeUrl(this.$('#path-link').attr('href')), href); } - }); - setTemplate('index', compile("

Home

    {{#each model as |person|}}
  • {{link-to person.name 'item' person}}
  • {{/each}}
")); - setTemplate('item', compile("

Item

{{model.name}}

{{#link-to 'index' id='home-link'}}Home{{/link-to}}")); + assertEquality('/'); - bootApplication(); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => controller.set('foo', 'about')); - run(() => jQuery('li a:contains(Yehuda)', '#qunit-fixture').click()); - - equal(jQuery('h3:contains(Item)', '#qunit-fixture').length, 1, 'The item template was rendered'); - equal(jQuery('p', '#qunit-fixture').text(), 'Yehuda Katz', 'The name is correct'); - - run(() => jQuery('#home-link').click()); - - equal(normalizeUrl(jQuery('li a:contains(Yehuda)').attr('href')), '/item/yehuda'); - equal(normalizeUrl(jQuery('li a:contains(Tom)').attr('href')), '/item/tom'); - equal(normalizeUrl(jQuery('li a:contains(Erik)').attr('href')), '/item/erik'); -}); - -QUnit.test('The non-block form {{link-to}} performs property lookup', function() { - setTemplate('index', compile("{{link-to 'string' 'index' id='string-link'}}{{link-to path foo id='path-link'}}")); - - function assertEquality(href) { - equal(normalizeUrl(jQuery('#string-link', '#qunit-fixture').attr('href')), '/'); - equal(normalizeUrl(jQuery('#path-link', '#qunit-fixture').attr('href')), href); + assertEquality('/about'); } - App.IndexController = Controller.extend({ - foo: 'index' - }); - - App.Router.map(function() { - this.route('about'); - }); + [`@test The non-block form {{link-to}} protects against XSS`](assert) { + this.addTemplate('application', `{{link-to display 'index' id='link'}}`); - bootApplication(); + this.add('controller:application', Controller.extend({ + display: 'blahzorz' + })); - run(router, 'handleURL', '/'); + this.visit('/'); - assertEquality('/'); + assert.equal(this.$('#link').text(), 'blahzorz'); - let controller = appInstance.lookup('controller:index'); - run(() => controller.set('foo', 'about')); + let controller = this.applicationInstance.lookup('controller:application'); + this.runTask(() => controller.set('display', 'BLAMMO')); - assertEquality('/about'); -}); - -QUnit.test('The non-block form {{link-to}} protects against XSS', function() { - setTemplate('application', compile("{{link-to display 'index' id='link'}}")); + assert.equal(this.$('#link').text(), 'BLAMMO'); + assert.equal(this.$('b').length, 0); + } - App.ApplicationController = Controller.extend({ - display: 'blahzorz' - }); + [`@test the {{link-to}} helper does not throw an error if its route has exited`](assert) { + assert.expect(0); - bootApplication(); + this.router.map(function() { + this.route('post', { path: 'post/:post_id' }); + }); - run(router, 'handleURL', '/'); + this.addTemplate('application', ` + {{#link-to 'index' id='home-link'}}Home{{/link-to}} + {{#link-to 'post' defaultPost id='default-post-link'}}Default Post{{/link-to}} + {{#if currentPost}} + {{#link-to 'post' currentPost id='current-post-link'}}Current Post{{/link-to}} + {{/if}} + `); + + this.add('controller:application', Controller.extend({ + defaultPost: { id: 1 }, + postController: inject.controller('post'), + currentPost: alias('postController.model') + })); + + this.add('controller:post', Controller.extend()); + + this.add('route:post', Route.extend({ + model() { + return { id: 2 }; + }, + serialize(model) { + return { post_id: model.id }; + } + })); - let controller = appInstance.lookup('controller:application'); + this.visit('/'); - equal(jQuery('#link', '#qunit-fixture').text(), 'blahzorz'); - run(() => controller.set('display', 'BLAMMO')); + this.click('#default-post-link'); + this.click('#home-link'); + this.click('#current-post-link'); + this.click('#home-link'); + } - equal(jQuery('#link', '#qunit-fixture').text(), 'BLAMMO'); - equal(jQuery('b', '#qunit-fixture').length, 0); -}); + [`@test {{link-to}} active property respects changing parent route context`](assert) { + this.router.map(function() { + this.route('things', { path: '/things/:name' }, function() { + this.route('other'); + }); + }); -QUnit.test('the {{link-to}} helper calls preventDefault', function() { - Router.map(function() { - this.route('about'); - }); + this.addTemplate('application', ` + {{link-to 'OMG' 'things' 'omg' id='omg-link'}} + {{link-to 'LOL' 'things' 'lol' id='lol-link'}} + `); - bootApplication(); + this.visit('/things/omg'); - run(router, 'handleURL', '/'); + shouldBeActive(assert, this.$('#omg-link')); + shouldNotBeActive(assert, this.$('#lol-link')); - let event = jQuery.Event('click'); - jQuery('#about-link', '#qunit-fixture').trigger(event); + this.visit('/things/omg/other'); - equal(event.isDefaultPrevented(), true, 'should preventDefault'); -}); + shouldBeActive(assert, this.$('#omg-link')); + shouldNotBeActive(assert, this.$('#lol-link')); + } -QUnit.test('the {{link-to}} helper does not call preventDefault if `preventDefault=false` is passed as an option', function() { - setTemplate('index', compile("{{#link-to 'about' id='about-link' preventDefault=false}}About{{/link-to}}")); + [`@test {{link-to}} populates href with default query param values even without query-params object`](assert) { + this.add('controller:index', Controller.extend({ + queryParams: ['foo'], + foo: '123' + })); - Router.map(function() { - this.route('about'); - }); + this.addTemplate('index', `{{#link-to 'index' id='the-link'}}Index{{/link-to}}`); - bootApplication(); + this.visit('/'); - run(router, 'handleURL', '/'); + assert.equal(this.$('#the-link').attr('href'), '/', 'link has right href'); + } - let event = jQuery.Event('click'); - jQuery('#about-link', '#qunit-fixture').trigger(event); + [`@test {{link-to}} populates href with default query param values with empty query-params object`](assert) { + this.add('controller:index', Controller.extend({ + queryParams: ['foo'], + foo: '123' + })); - equal(event.isDefaultPrevented(), false, 'should not preventDefault'); -}); + this.addTemplate('index', ` + {{#link-to 'index' (query-params) id='the-link'}}Index{{/link-to}} + `); -QUnit.test('the {{link-to}} helper does not call preventDefault if `preventDefault=boundFalseyThing` is passed as an option', function() { - setTemplate('index', compile("{{#link-to 'about' id='about-link' preventDefault=boundFalseyThing}}About{{/link-to}}")); + this.visit('/'); - App.IndexController = Controller.extend({ - boundFalseyThing: false - }); + assert.equal(this.$('#the-link').attr('href'), '/', 'link has right href'); + } - Router.map(function() { - this.route('about'); - }); + [`@test {{link-to}} with only query-params and a block updates when route changes`](assert) { + this.router.map(function() { + this.route('about'); + }); - bootApplication(); + this.add('controller:application', Controller.extend({ + queryParams: ['foo', 'bar'], + foo: '123', + bar: 'yes' + })); - run(router, 'handleURL', '/'); + this.addTemplate('application', ` + {{#link-to (query-params foo='456' bar='NAW') id='the-link'}}Index{{/link-to}} + `); - let event = jQuery.Event('click'); - jQuery('#about-link', '#qunit-fixture').trigger(event); + this.visit('/'); - equal(event.isDefaultPrevented(), false, 'should not preventDefault'); -}); + assert.equal(this.$('#the-link').attr('href'), '/?bar=NAW&foo=456', 'link has right href'); -QUnit.test('the {{link-to}} helper throws a useful error if you invoke it wrong', function() { - expect(1); + this.visit('/about'); - setTemplate('application', compile("{{#link-to 'post'}}Post{{/link-to}}")); + assert.equal(this.$('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href'); + } - Router.map(function() { - this.route('post', { path: 'post/:post_id' }); - }); + [`@test Block-less {{link-to}} with only query-params updates when route changes`](assert) { + this.router.map(function() { + this.route('about'); + }); - QUnit.throws(function() { - bootApplication(); - }, /(You attempted to define a `\{\{link-to "post"\}\}` but did not pass the parameters required for generating its dynamic segments.|You must provide param `post_id` to `generate`)/); -}); + this.add('controller:application', Controller.extend({ + queryParams: ['foo', 'bar'], + foo: '123', + bar: 'yes' + })); -QUnit.test('the {{link-to}} helper does not throw an error if its route has exited', function() { - expect(0); + this.addTemplate('application', ` + {{link-to "Index" (query-params foo='456' bar='NAW') id='the-link'}} + `); - setTemplate('application', compile("{{#link-to 'index' id='home-link'}}Home{{/link-to}}{{#link-to 'post' defaultPost id='default-post-link'}}Default Post{{/link-to}}{{#if currentPost}}{{#link-to 'post' currentPost id='current-post-link'}}Current Post{{/link-to}}{{/if}}")); + this.visit('/'); - App.ApplicationController = Controller.extend({ - defaultPost: { id: 1 }, - postController: inject.controller('post'), - currentPost: alias('postController.model') - }); + assert.equal(this.$('#the-link').attr('href'), '/?bar=NAW&foo=456', 'link has right href'); - App.PostController = Controller.extend(); + this.visit('/about'); - App.PostRoute = Route.extend({ - model: function() { - return { id: 2 }; - }, - serialize: function(model) { - return { post_id: model.id }; - } - }); + assert.equal(this.$('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href'); + } - Router.map(function() { - this.route('post', { path: 'post/:post_id' }); - }); + [`@test The {{link-to}} helper can use dynamic params`](assert) { + this.router.map(function() { + this.route('foo', { path: 'foo/:some/:thing' }); + this.route('bar', { path: 'bar/:some/:thing/:else' }); + }); - bootApplication(); + this.add('controller:index', Controller.extend({ + init() { + this._super(...arguments); + this.dynamicLinkParams = [ + 'foo', + 'one', + 'two' + ]; + } + })); - run(router, 'handleURL', '/'); + this.addTemplate('index', ` +

Home

+ {{#link-to params=dynamicLinkParams id="dynamic-link"}}Dynamic{{/link-to}} + `); - run(() => jQuery('#default-post-link', '#qunit-fixture').click()); - run(() => jQuery('#home-link', '#qunit-fixture').click()); - run(() => jQuery('#current-post-link', '#qunit-fixture').click()); - run(() => jQuery('#home-link', '#qunit-fixture').click()); -}); + this.visit('/'); -QUnit.test('{{link-to}} active property respects changing parent route context', function() { - setTemplate('application', compile( - "{{link-to 'OMG' 'things' 'omg' id='omg-link'}} " + - "{{link-to 'LOL' 'things' 'lol' id='lol-link'}} ")); + let link = this.$('#dynamic-link'); + assert.equal(link.attr('href'), '/foo/one/two'); - Router.map(function() { - this.route('things', { path: '/things/:name' }, function() { - this.route('other'); + let controller = this.applicationInstance.lookup('controller:index'); + this.runTask(() => { + controller.set('dynamicLinkParams', [ + 'bar', + 'one', + 'two', + 'three' + ]); }); - }); - bootApplication(); - - run(router, 'handleURL', '/things/omg'); - shouldBeActive('#omg-link'); - shouldNotBeActive('#lol-link'); + assert.equal(link.attr('href'), '/bar/one/two/three'); + } - run(router, 'handleURL', '/things/omg/other'); - shouldBeActive('#omg-link'); - shouldNotBeActive('#lol-link'); -}); + [`@test GJ: {{link-to}} to a parent root model hook which performs a 'transitionTo' has correct active class #13256`](assert) { + assert.expect(1); + this.router.map(function() { + this.route('parent', function() { + this.route('child'); + }); + }); -QUnit.test('{{link-to}} populates href with default query param values even without query-params object', function() { - App.IndexController = Controller.extend({ - queryParams: ['foo'], - foo: '123' - }); + this.add('route:parent', Route.extend({ + afterModel(transition) { + this.transitionTo('parent.child'); + } + })); - setTemplate('index', compile("{{#link-to 'index' id='the-link'}}Index{{/link-to}}")); - bootApplication(); - equal(jQuery('#the-link').attr('href'), '/', 'link has right href'); -}); + this.addTemplate('application', ` + {{link-to 'Parent' 'parent' id='parent-link'}} + `); -QUnit.test('{{link-to}} populates href with default query param values with empty query-params object', function() { - App.IndexController = Controller.extend({ - queryParams: ['foo'], - foo: '123' - }); + this.visit('/'); - setTemplate('index', compile("{{#link-to 'index' (query-params) id='the-link'}}Index{{/link-to}}")); - bootApplication(); - equal(jQuery('#the-link').attr('href'), '/', 'link has right href'); -}); + this.click('#parent-link'); -QUnit.test('{{link-to}} with only query-params and a block updates when route changes', function() { - Router.map(function() { - this.route('about'); - }); + shouldBeActive(assert, this.$('#parent-link')); + } - App.ApplicationController = Controller.extend({ - queryParams: ['foo', 'bar'], - foo: '123', - bar: 'yes' - }); +}); - setTemplate('application', compile(`{{#link-to (query-params foo='456' bar='NAW') id='the-link'}}Index{{/link-to}}`)); - bootApplication(); - equal(jQuery('#the-link').attr('href'), '/?bar=NAW&foo=456', 'link has right href'); +moduleFor('The {{link-to}} helper - loading states and warnings', class extends ApplicationTestCase { - run(() => router.handleURL('/about')); + constructor() { + super(); + this._oldWarn = Logger.warn; + this.warnCalled = false; + Logger.warn = () => this.warnCalled = true; + } - equal(jQuery('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href'); -}); + teardown() { + Logger.warn = this._oldWarn; + super.teardown(); + } -QUnit.test('Block-less {{link-to}} with only query-params updates when route changes', function() { - Router.map(function() { - this.route('about'); - }); + [`@test link-to with null/undefined dynamic parameters are put in a loading state`](assert) { + assert.expect(19); - App.ApplicationController = Controller.extend({ - queryParams: ['foo', 'bar'], - foo: '123', - bar: 'yes' - }); + this.router.map(function() { + this.route('thing', { path: '/thing/:thing_id' }); + this.route('about'); + }); - setTemplate('application', compile(`{{link-to "Index" (query-params foo='456' bar='NAW') id='the-link'}}`)); - bootApplication(); - equal(jQuery('#the-link').attr('href'), '/?bar=NAW&foo=456', 'link has right href'); + this.addTemplate('index', ` + {{#link-to destinationRoute routeContext loadingClass='i-am-loading' id='context-link'}} + string + {{/link-to}} + {{#link-to secondRoute loadingClass=loadingClass id='static-link'}} + string + {{/link-to}} + `); + + this.add('controller:index', Controller.extend({ + destinationRoute: null, + routeContext: null, + loadingClass: 'i-am-loading' + })); + + this.add('route:about', Route.extend({ + activate() { + assert.ok(true, 'About was entered'); + } + })); - run(() => router.handleURL('/about')); + this.visit('/'); - equal(jQuery('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href'); -}); + function assertLinkStatus(link, url) { + if (url) { + assert.equal(normalizeUrl(link.attr('href')), url, 'loaded link-to has expected href'); + assert.ok(!link.hasClass('i-am-loading'), 'loaded linkComponent has no loadingClass'); + } else { + assert.equal(normalizeUrl(link.attr('href')), '#', "unloaded link-to has href='#'"); + assert.ok(link.hasClass('i-am-loading'), 'loading linkComponent has loadingClass'); + } + } -QUnit.test('The {{link-to}} helper can use dynamic params', function() { - Router.map(function(match) { - this.route('foo', { path: 'foo/:some/:thing' }); - this.route('bar', { path: 'bar/:some/:thing/:else' }); - }); + let contextLink = this.$('#context-link'); + let staticLink = this.$('#static-link'); + let controller = this.applicationInstance.lookup('controller:index'); - let controller; - App.IndexController = Controller.extend({ - init() { - this._super(...arguments); + assertLinkStatus(contextLink); + assertLinkStatus(staticLink); - controller = this; + this.warnCalled = false; + this.click(contextLink); + assert.ok(this.warnCalled, 'Logger.warn was called from clicking loading link'); - this.dynamicLinkParams = [ - 'foo', - 'one', - 'two' - ]; - } - }); + // Set the destinationRoute (context is still null). + this.runTask(() => controller.set('destinationRoute', 'thing')); + assertLinkStatus(contextLink); - setTemplate('index', compile(` -

Home

+ // Set the routeContext to an id + this.runTask(() => controller.set('routeContext', '456')); + assertLinkStatus(contextLink, '/thing/456'); - {{#link-to params=dynamicLinkParams id="dynamic-link"}}Dynamic{{/link-to}} - `)); + // Test that 0 isn't interpreted as falsy. + this.runTask(() => controller.set('routeContext', 0)); + assertLinkStatus(contextLink, '/thing/0'); - bootApplication(); + // Set the routeContext to an object + this.runTask(() => { + controller.set('routeContext', { id: 123 }); + }); + assertLinkStatus(contextLink, '/thing/123'); - run(() => router.handleURL('/')); + // Set the destinationRoute back to null. + this.runTask(() => controller.set('destinationRoute', null)); + assertLinkStatus(contextLink); - let link = jQuery('#dynamic-link', '#qunit-fixture'); + this.warnCalled = false; + this.click(staticLink); + assert.ok(this.warnCalled, 'Logger.warn was called from clicking loading link'); - equal(link.attr('href'), '/foo/one/two'); + this.runTask(() => controller.set('secondRoute', 'about')); + assertLinkStatus(staticLink, '/about'); - run(() => { - controller.set('dynamicLinkParams', [ - 'bar', - 'one', - 'two', - 'three' - ]); - }); + // Click the now-active link + this.click(staticLink); + } - equal(link.attr('href'), '/bar/one/two/three'); }); -QUnit.test('GJ: {{link-to}} to a parent root model hook which performs a `transitionTo` has correct active class #13256', function() { - expect(1); - - Router.map(function() { - this.route('parent', function() { - this.route('child'); - }); - }); +moduleFor('The {{link-to}} helper - globals mode app', class extends AutobootApplicationTestCase { + + /* + * When an exception is thrown during the initial rendering phase, the + * `visit` promise is not resolved or rejected. This means the `applicationInstance` + * is never torn down and tests running after this one will fail. + * + * It is ugly, but since this test intentionally causes an initial render + * error, it requires globals mode to access the `applicationInstance` + * for teardown after test completion. + * + * Application "globals mode" is trigged by `autoboot: true`. It doesn't + * have anything to do with the resolver. + * + * We should be able to fix this by having the application eagerly stash a + * copy of each application instance it creates. When the application is + * destroyed, it can also destroy the instances (this is how the globals + * mode avoid the problem). + * + * See: https://github.com/emberjs/ember.js/issues/15327 + */ + [`@test the {{link-to}} helper throws a useful error if you invoke it wrong`](assert) { + assert.expect(1); - App.ParentRoute = Route.extend({ - afterModel(transition) { - this.transitionTo('parent.child'); - } - }); + assert.throws(() => { + this.runTask(() => { + this.createApplication(); - setTemplate('application', compile(` - {{link-to 'Parent' 'parent' id='parent-link'}} - `)); + this.add('router:main', Router.extend({ + location: 'none' + })); - bootApplication(); + this.router.map(function() { + this.route('post', { path: 'post/:post_id' }); + }); - run(jQuery('#parent-link'), 'click'); + this.addTemplate('application', `{{#link-to 'post'}}Post{{/link-to}}`); + }); + }, /(You attempted to define a `\{\{link-to "post"\}\}` but did not pass the parameters required for generating its dynamic segments.|You must provide param `post_id` to `generate`)/); + } - shouldBeActive('#parent-link'); }); diff --git a/packages/internal-test-helpers/lib/test-cases/abstract-application.js b/packages/internal-test-helpers/lib/test-cases/abstract-application.js index 9d8104b5b18..897d958dea2 100644 --- a/packages/internal-test-helpers/lib/test-cases/abstract-application.js +++ b/packages/internal-test-helpers/lib/test-cases/abstract-application.js @@ -57,10 +57,12 @@ export default class AbstractApplicationTestCase extends AbstractTestCase { let { applicationInstance } = this; if (applicationInstance) { - return run(applicationInstance, 'visit', url, options); + return this.runTask(() => applicationInstance.visit(url, options)); } else { - return run(this.application, 'visit', url, options).then(instance => { - this.applicationInstance = instance; + return this.runTask(() => { + return this.application.visit(url, options).then(instance => { + this.applicationInstance = instance; + }); }); } } diff --git a/packages/internal-test-helpers/lib/test-cases/abstract.js b/packages/internal-test-helpers/lib/test-cases/abstract.js index 48d3f92bf6b..3e56714741e 100644 --- a/packages/internal-test-helpers/lib/test-cases/abstract.js +++ b/packages/internal-test-helpers/lib/test-cases/abstract.js @@ -36,11 +36,11 @@ export default class AbstractTestCase { teardown() {} runTask(callback) { - run(callback); + return run(callback); } runTaskNext(callback) { - run.next(callback); + return run.next(callback); } // The following methods require `this.element` to work @@ -87,6 +87,10 @@ export default class AbstractTestCase { return sel ? jQuery(sel, this.element) : jQuery(this.element); } + click(selector) { + this.runTask(() => this.$(selector).click()); + } + textValue() { return this.$().text(); } From ad446bc0a5975bdbfd06da3e77d2e270fe3cfda9 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Mon, 5 Jun 2017 22:37:17 -0700 Subject: [PATCH 016/224] Decouple application_lifecycle_test from global resolver --- .../ember/tests/application_lifecycle_test.js | 311 ++++++++---------- 1 file changed, 130 insertions(+), 181 deletions(-) diff --git a/packages/ember/tests/application_lifecycle_test.js b/packages/ember/tests/application_lifecycle_test.js index 25fdb8367a4..72412898a46 100644 --- a/packages/ember/tests/application_lifecycle_test.js +++ b/packages/ember/tests/application_lifecycle_test.js @@ -1,220 +1,169 @@ +import { + moduleFor, + AutobootApplicationTestCase +} from 'internal-test-helpers'; import { Application } from 'ember-application'; -import { Route, controllerFor } from 'ember-routing'; -import { run } from 'ember-metal'; +import { Route, Router } from 'ember-routing'; import { Component, - setTemplates, - getTemplates } from 'ember-glimmer'; -import { jQuery } from 'ember-views'; -import { compile } from 'ember-template-compiler'; - -let App, TEMPLATES, appInstance, router; -function setupApp(klass) { - run(function() { - App = klass.create({ - rootElement: '#qunit-fixture' - }); +moduleFor('Application Lifecycle - route hooks', class extends AutobootApplicationTestCase { - App.Router = App.Router.extend({ + createApplication() { + let application = super.createApplication(...arguments); + this.add('router:main', Router.extend({ location: 'none' - }); - - App.deferReadiness(); - - appInstance = App.__deprecatedInstance__; - }); -} - -QUnit.module('Application Lifecycle', { - setup() { - TEMPLATES = getTemplates(); - setupApp(Application.extend()); - }, - - teardown() { - router = null; - run(App, 'destroy'); - setTemplates({}); + })); + return application; } -}); -function handleURL(path) { - router = appInstance.lookup('router:main'); - return run(function() { - return router.handleURL(path).then(function(value) { - ok(true, 'url: `' + path + '` was handled'); - return value; - }, function(reason) { - ok(false, reason); - throw reason; + constructor() { + super(); + let menuItem = this.menuItem = {}; + + this.runTask(() => { + this.createApplication(); + + let SettingRoute = Route.extend({ + setupController() { + this.controller.set('selectedMenuItem', menuItem); + }, + deactivate() { + this.controller.set('selectedMenuItem', null); + } + }); + this.add('route:index', SettingRoute); + this.add('route:application', SettingRoute); }); - }); -} - -QUnit.test('Resetting the application allows controller properties to be set when a route deactivates', function() { - App.Router.map(function() { - this.route('home', { path: '/' }); - }); - - App.HomeRoute = Route.extend({ - setupController() { - this.controllerFor('home').set('selectedMenuItem', 'home'); - }, - deactivate() { - this.controllerFor('home').set('selectedMenuItem', null); - } - }); - App.ApplicationRoute = Route.extend({ - setupController() { - this.controllerFor('application').set('selectedMenuItem', 'home'); - }, - deactivate() { - this.controllerFor('application').set('selectedMenuItem', null); - } - }); - - appInstance.lookup('router:main'); - - run(App, 'advanceReadiness'); - - handleURL('/'); - - equal(controllerFor(appInstance, 'home').get('selectedMenuItem'), 'home'); - equal(controllerFor(appInstance, 'application').get('selectedMenuItem'), 'home'); - - App.reset(); - - equal(controllerFor(appInstance, 'home').get('selectedMenuItem'), null); - equal(controllerFor(appInstance, 'application').get('selectedMenuItem'), null); -}); + } -QUnit.test('Destroying the application resets the router before the appInstance is destroyed', function() { - App.Router.map(function() { - this.route('home', { path: '/' }); - }); - - App.HomeRoute = Route.extend({ - setupController() { - this.controllerFor('home').set('selectedMenuItem', 'home'); - }, - deactivate() { - this.controllerFor('home').set('selectedMenuItem', null); - } - }); - App.ApplicationRoute = Route.extend({ - setupController() { - this.controllerFor('application').set('selectedMenuItem', 'home'); - }, - deactivate() { - this.controllerFor('application').set('selectedMenuItem', null); - } - }); - - appInstance.lookup('router:main'); - - run(App, 'advanceReadiness'); - - handleURL('/'); - - equal(controllerFor(appInstance, 'home').get('selectedMenuItem'), 'home'); - equal(controllerFor(appInstance, 'application').get('selectedMenuItem'), 'home'); - - run(App, 'destroy'); - - equal(controllerFor(appInstance, 'home').get('selectedMenuItem'), null); - equal(controllerFor(appInstance, 'application').get('selectedMenuItem'), null); -}); + get indexController() { + return this.applicationInstance.lookup('controller:index'); + } -QUnit.test('Destroying a route after the router does create an undestroyed `toplevelView`', function() { - App.Router.map(function() { - this.route('home', { path: '/' }); - }); + get applicationController() { + return this.applicationInstance.lookup('controller:application'); + } - setTemplates({ - index: compile('Index!'), - application: compile('Application! {{outlet}}') - }); + [`@test Resetting the application allows controller properties to be set when a route deactivates`](assert) { + let { + indexController, + applicationController + } = this; + assert.equal(indexController.get('selectedMenuItem'), this.menuItem); + assert.equal(applicationController.get('selectedMenuItem'), this.menuItem); - App.IndexRoute = Route.extend(); - run(App, 'advanceReadiness'); + this.application.reset(); - handleURL('/'); + assert.equal(indexController.get('selectedMenuItem'), null); + assert.equal(applicationController.get('selectedMenuItem'), null); + } - let router = appInstance.lookup('router:main'); - let route = appInstance.lookup('route:index'); + [`@test Destroying the application resets the router before the appInstance is destroyed`](assert) { + let { + indexController, + applicationController + } = this; + assert.equal(indexController.get('selectedMenuItem'), this.menuItem); + assert.equal(applicationController.get('selectedMenuItem'), this.menuItem); - run(router, 'destroy'); - equal(router._toplevelView, null, 'the toplevelView was cleared'); + this.runTask(() => { + this.application.destroy(); + }); - run(route, 'destroy'); - equal(router._toplevelView, null, 'the toplevelView was not reinitialized'); + assert.equal(indexController.get('selectedMenuItem'), null); + assert.equal(applicationController.get('selectedMenuItem'), null); + } - run(App, 'destroy'); - equal(router._toplevelView, null, 'the toplevelView was not reinitialized'); }); -QUnit.test('initializers can augment an applications customEvents hash', function(assert) { - assert.expect(1); +moduleFor('Application Lifecycle', class extends AutobootApplicationTestCase { - run(App, 'destroy'); + createApplication() { + let application = super.createApplication(...arguments); + this.add('router:main', Router.extend({ + location: 'none' + })); + return application; + } - let ApplicationSubclass = Application.extend(); + [`@test Destroying a route after the router does create an undestroyed 'toplevelView'`](assert) { + this.runTask(() => { + this.createApplication(); + this.addTemplate('index', `Index!`); + this.addTemplate('application', `Application! {{outlet}}`); + }); - ApplicationSubclass.initializer({ - name: 'customize-things', - initialize(application) { - application.customEvents = { - wowza: 'wowza' - }; - } - }); + let router = this.applicationInstance.lookup('router:main'); + let route = this.applicationInstance.lookup('route:index'); - setupApp(ApplicationSubclass); + this.runTask(() => router.destroy()); + equal(router._toplevelView, null, 'the toplevelView was cleared'); - App.FooBarComponent = Component.extend({ - wowza() { - assert.ok(true, 'fired the event!'); - } - }); + this.runTask(() => route.destroy()); + equal(router._toplevelView, null, 'the toplevelView was not reinitialized'); - TEMPLATES['application'] = compile(`{{foo-bar}}`); - TEMPLATES['components/foo-bar'] = compile(`
`); + this.runTask(() => this.application.destroy()); + equal(router._toplevelView, null, 'the toplevelView was not reinitialized'); + } - run(App, 'advanceReadiness'); + [`@test initializers can augment an applications customEvents hash`](assert) { + assert.expect(1); - run(() => jQuery('#wowza-thingy').trigger('wowza')); -}); + let MyApplication = Application.extend(); -QUnit.test('instanceInitializers can augment an the customEvents hash', function(assert) { - assert.expect(1); + MyApplication.initializer({ + name: 'customize-things', + initialize(application) { + application.customEvents = { + wowza: 'wowza' + }; + } + }); - run(App, 'destroy'); + this.runTask(() => { + this.createApplication({}, MyApplication); - let ApplicationSubclass = Application.extend(); + this.add('component:foo-bar', Component.extend({ + wowza() { + assert.ok(true, 'fired the event!'); + } + })); - ApplicationSubclass.instanceInitializer({ - name: 'customize-things', - initialize(application) { - application.customEvents = { - herky: 'jerky' - }; - } - }); + this.addTemplate('application', `{{foo-bar}}`); + this.addTemplate('components/foo-bar', `
`); + }); + + this.$('#wowza-thingy').trigger('wowza'); + } - setupApp(ApplicationSubclass); + [`@test instanceInitializers can augment an the customEvents hash`](assert) { + assert.expect(1); - App.FooBarComponent = Component.extend({ - jerky() { - assert.ok(true, 'fired the event!'); - } - }); + let MyApplication = Application.extend(); - TEMPLATES['application'] = compile(`{{foo-bar}}`); - TEMPLATES['components/foo-bar'] = compile(`
`); + MyApplication.instanceInitializer({ + name: 'customize-things', + initialize(application) { + application.customEvents = { + herky: 'jerky' + }; + } + }); + this.runTask(() => { + this.createApplication({}, MyApplication); - run(App, 'advanceReadiness'); + this.add('component:foo-bar', Component.extend({ + jerky() { + assert.ok(true, 'fired the event!'); + } + })); - run(() => jQuery('#herky-thingy').trigger('herky')); + this.addTemplate('application', `{{foo-bar}}`); + this.addTemplate('components/foo-bar', `
`); + }); + + this.$('#herky-thingy').trigger('herky'); + } }); From 7342deec1113ff9784bb6eb7aeac60c3a3a1719b Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Tue, 6 Jun 2017 09:50:49 -0700 Subject: [PATCH 017/224] Decouple logging_test from the globals resolver --- .../tests/system/logging_test.js | 261 +++++++----------- 1 file changed, 97 insertions(+), 164 deletions(-) diff --git a/packages/ember-application/tests/system/logging_test.js b/packages/ember-application/tests/system/logging_test.js index 867cf1b8900..936c970a920 100644 --- a/packages/ember-application/tests/system/logging_test.js +++ b/packages/ember-application/tests/system/logging_test.js @@ -1,214 +1,147 @@ /*globals EmberDev */ +import { + moduleFor, + ApplicationTestCase +} from 'internal-test-helpers'; + import Logger from 'ember-console'; -import { run } from 'ember-metal'; -import Application from '../../system/application'; -import { Controller, RSVP } from 'ember-runtime'; +import { Controller } from 'ember-runtime'; import { Route } from 'ember-routing'; -import { compile } from 'ember-template-compiler'; +import { assign } from 'ember-utils'; -let App, logs, originalLogger; -QUnit.module('Ember.Application – logging of generated classes', { - setup() { - logs = {}; +class LoggingApplicationTestCase extends ApplicationTestCase { + constructor() { + super(); - originalLogger = Logger.info; + this.logs = {}; - Logger.info = function() { - let fullName = arguments[1].fullName; + this._originalLogger = Logger.info; - logs[fullName] = logs[fullName] || 0; - logs[fullName]++; + Logger.info = (_, {fullName}) => { + if (!this.logs.hasOwnProperty(fullName)) { + this.logs[fullName] = 0; + } + this.logs[fullName]++; }; - run(() => { - App = Application.create({ - LOG_ACTIVE_GENERATION: true - }); - - App.Router.reopen({ - location: 'none' - }); - - App.Router.map(function() { - this.route('posts', { resetNamespace: true }); - }); - - App.deferReadiness(); + this.router.map(function() { + this.route('posts', { resetNamespace: true }); }); - }, + } teardown() { - Logger.info = originalLogger; - - run(App, 'destroy'); - - logs = App = null; + Logger.info = this._originalLogger; + super.teardown(); } -}); +} -function visit(path) { - QUnit.stop(); - - var promise = run(() => { - return new RSVP.Promise((resolve, reject) => { - var router = App.__container__.lookup('router:main'); - - resolve(router.handleURL(path).then(value => { - QUnit.start(); - ok(true, 'visited: `' + path + '`'); - return value; - }, reason => { - QUnit.start(); - ok(false, 'failed to visit:`' + path + '` reason: `' + QUnit.jsDump.parse(reason)); - throw reason; - })); +moduleFor('Ember.Application with LOG_ACTIVE_GENERATION=true', class extends LoggingApplicationTestCase { + + get applicationOptions() { + return assign(super.applicationOptions, { + LOG_ACTIVE_GENERATION: true }); - }); + } - return { - then(resolve, reject) { - run(promise, 'then', resolve, reject); + ['@test log class generation if logging enabled'](assert) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; } - }; -} -QUnit.test('log class generation if logging enabled', function() { - if (EmberDev && EmberDev.runningProdBuild) { - ok(true, 'Logging does not occur in production builds'); - return; + this.visit('/posts'); + assert.equal(Object.keys(this.logs).length, 4, 'expected logs'); } - run(App, 'advanceReadiness'); - - visit('/posts').then(function() { - equal(Object.keys(logs).length, 6, 'expected logs'); - }); -}); - -QUnit.test('do NOT log class generation if logging disabled', function() { - App.reopen({ - LOG_ACTIVE_GENERATION: false - }); + ['@test actively generated classes get logged'](assert) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; + } - run(App, 'advanceReadiness'); + this.visit('/posts'); + assert.equal(this.logs['controller:application'], 1, 'expected: ApplicationController was generated'); + assert.equal(this.logs['controller:posts'], 1, 'expected: PostsController was generated'); - visit('/posts').then(() => { - equal(Object.keys(logs).length, 0, 'expected no logs'); - }); -}); - -QUnit.test('actively generated classes get logged', function() { - if (EmberDev && EmberDev.runningProdBuild) { - ok(true, 'Logging does not occur in production builds'); - return; + assert.equal(this.logs['route:application'], 1, 'expected: ApplicationRoute was generated'); + assert.equal(this.logs['route:posts'], 1, 'expected: PostsRoute was generated'); } - run(App, 'advanceReadiness'); - - visit('/posts').then(() => { - equal(logs['controller:application'], 1, 'expected: ApplicationController was generated'); - equal(logs['controller:posts'], 1, 'expected: PostsController was generated'); - - equal(logs['route:application'], 1, 'expected: ApplicationRoute was generated'); - equal(logs['route:posts'], 1, 'expected: PostsRoute was generated'); - }); -}); - -QUnit.test('predefined classes do not get logged', function() { - App.ApplicationController = Controller.extend(); - App.PostsController = Controller.extend(); + ['@test predefined classes do not get logged'](assert) { + this.add('controller:application', Controller.extend()); + this.add('controller:posts', Controller.extend()); + this.add('route:application', Route.extend()); + this.add('route:posts', Route.extend()); - App.ApplicationRoute = Route.extend(); - App.PostsRoute = Route.extend(); + this.visit('/posts'); - run(App, 'advanceReadiness'); + assert.ok(!this.logs['controller:application'], 'did not expect: ApplicationController was generated'); + assert.ok(!this.logs['controller:posts'], 'did not expect: PostsController was generated'); - visit('/posts').then(() => { - ok(!logs['controller:application'], 'did not expect: ApplicationController was generated'); - ok(!logs['controller:posts'], 'did not expect: PostsController was generated'); + assert.ok(!this.logs['route:application'], 'did not expect: ApplicationRoute was generated'); + assert.ok(!this.logs['route:posts'], 'did not expect: PostsRoute was generated'); + } - ok(!logs['route:application'], 'did not expect: ApplicationRoute was generated'); - ok(!logs['route:posts'], 'did not expect: PostsRoute was generated'); - }); }); -QUnit.module('Ember.Application – logging of view lookups', { - setup() { - logs = {}; - - originalLogger = Logger.info; - - Logger.info = function() { - var fullName = arguments[1].fullName; +moduleFor('Ember.Application when LOG_ACTIVE_GENERATION=false', class extends LoggingApplicationTestCase { - logs[fullName] = logs[fullName] || 0; - logs[fullName]++; - }; + get applicationOptions() { + return assign(super.applicationOptions, { + LOG_ACTIVE_GENERATION: false + }); + } - run(() => { - App = Application.create({ - LOG_VIEW_LOOKUPS: true - }); + [`@test do NOT log class generation if logging disabled`](assert) { + this.visit('/posts'); + assert.equal(Object.keys(this.logs).length, 0, 'expected logs'); + } - App.Router.reopen({ - location: 'none' - }); +}); - App.Router.map(function() { - this.route('posts', { resetNamespace: true }); - }); +moduleFor('Ember.Application with LOG_VIEW_LOOKUPS=true', class extends LoggingApplicationTestCase { - App.deferReadiness(); + get applicationOptions() { + return assign(super.applicationOptions, { + LOG_VIEW_LOOKUPS: true }); - }, + } - teardown() { - Logger.info = originalLogger; + [`@test log when template and view are missing when flag is active`](assert) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; + } - run(App, 'destroy'); + this.addTemplate('application', '{{outlet}}'); - logs = App = null; - } -}); + this.visit('/'); + this.visit('/posts'); -QUnit.test('log when template and view are missing when flag is active', function() { - if (EmberDev && EmberDev.runningProdBuild) { - ok(true, 'Logging does not occur in production builds'); - return; + assert.equal(this.logs['template:application'], undefined, 'expected: Should not log template:application since it exists.'); + assert.equal(this.logs['template:index'], 1, 'expected: Could not find "index" template or view.'); + assert.equal(this.logs['template:posts'], 1, 'expected: Could not find "posts" template or view.'); } - App.register('template:application', compile('{{outlet}}')); - run(App, 'advanceReadiness'); - - visit('/posts').then(() => { - equal(logs['template:application'], undefined, 'expected: Should not log template:application since it exists.'); - equal(logs['template:index'], 1, 'expected: Could not find "index" template or view.'); - equal(logs['template:posts'], 1, 'expected: Could not find "posts" template or view.'); - }); }); -QUnit.test('do not log when template and view are missing when flag is not true', function() { - App.reopen({ - LOG_VIEW_LOOKUPS: false - }); - - run(App, 'advanceReadiness'); - - visit('/posts').then(() => { - equal(Object.keys(logs).length, 0, 'expected no logs'); - }); -}); +moduleFor('Ember.Application with LOG_VIEW_LOOKUPS=false', class extends LoggingApplicationTestCase { -QUnit.test('do not log which views are used with templates when flag is not true', function() { - App.reopen({ - LOG_VIEW_LOOKUPS: false - }); + get applicationOptions() { + return assign(super.applicationOptions, { + LOG_VIEW_LOOKUPS: false + }); + } - run(App, 'advanceReadiness'); + [`@test do not log when template and view are missing when flag is not true`](assert) { + this.visit('/posts'); + assert.equal(Object.keys(this.logs).length, 0, 'expected no logs'); + } - visit('/posts').then(() => { - equal(Object.keys(logs).length, 0, 'expected no logs'); - }); + [`@test do not log which views are used with templates when flag is not true`](assert) { + this.visit('/posts'); + assert.equal(Object.keys(this.logs).length, 0, 'expected no logs'); + } }); From 271d8cd7b6987f177318081925a5e3c74abe9762 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 8 Jun 2017 13:17:43 +0500 Subject: [PATCH 018/224] use flat array in `meta/_forEachIn` --- packages/ember-metal/lib/meta.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index e07e3647fb7..db1e57ae44d 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -305,17 +305,17 @@ export class Meta { if (seen[innerKey] === undefined) { seen[innerKey] = true; calls = calls || []; - calls.push([innerKey, innerMap[innerKey]]); + calls.push(innerKey, innerMap[innerKey]); } } } } pointer = pointer.parent; } + if (calls !== undefined) { - for (let i = 0; i < calls.length; i++) { - let [innerKey, value] = calls[i]; - fn(innerKey, value); + for (let i = 0; i < calls.length; i+=2) { + fn(calls[i], calls[i + 1]); } } } @@ -341,7 +341,7 @@ export class Meta { writeValue(obj, key, value) { let descriptor = lookupDescriptor(obj, key); - let isMandatorySetter = descriptor !== undefined&& descriptor.set && descriptor.set.isMandatorySetter; + let isMandatorySetter = descriptor !== undefined && descriptor.set && descriptor.set.isMandatorySetter; if (isMandatorySetter) { this.writeValues(key, value); From e2b43496b16c0be85a81429c038157b02ad70d50 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 8 Jun 2017 17:19:32 +0500 Subject: [PATCH 019/224] calling `memberProperty`, `capitalize` inside for loop, to avoid repetition --- packages/ember-metal/lib/meta.js | 61 +++++++++++++++----------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index e07e3647fb7..ef4b7c669d1 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -78,7 +78,6 @@ if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER || EMBER_GLIMMER_ALLOW_BACKTRACKI } } -let memberNames = Object.keys(members); const META_FIELD = '__ember_meta__'; export class Meta { @@ -364,37 +363,37 @@ const NODE_STACK = []; for (let name in listenerMethods) { Meta.prototype[name] = listenerMethods[name]; } -memberNames.forEach(name => members[name](name, Meta)); -// Implements a member that is a lazily created, non-inheritable -// POJO. -function ownMap(name, Meta) { +Object.keys(members).forEach(name => { let key = memberProperty(name); let capitalized = capitalize(name); - Meta.prototype[`writable${capitalized}`] = function() { + members[name](capitalized, key, Meta); +}); + +// Implements a member that is a lazily created, non-inheritable +// POJO. +function ownMap(name, key, Meta) { + Meta.prototype[`writable${name}`] = function() { return this._getOrCreateOwnMap(key); }; - Meta.prototype[`readable${capitalized}`] = function() { return this[key]; }; + Meta.prototype[`readable${name}`] = function() { return this[key]; }; } // Implements a member that is a lazily created POJO with inheritable // values. -function inheritedMap(name, Meta) { - let key = memberProperty(name); - let capitalized = capitalize(name); - - Meta.prototype[`write${capitalized}`] = function(subkey, value) { - assert(`Cannot call write${capitalized} after the object is destroyed.`, !this.isMetaDestroyed()); +function inheritedMap(name, key, Meta) { + Meta.prototype[`write${name}`] = function(subkey, value) { + assert(`Cannot call write${name} after the object is destroyed.`, !this.isMetaDestroyed()); let map = this._getOrCreateOwnMap(key); map[subkey] = value; }; - Meta.prototype[`peek${capitalized}`] = function(subkey) { + Meta.prototype[`peek${name}`] = function(subkey) { return this._findInherited(key, subkey); }; - Meta.prototype[`forEach${capitalized}`] = function(fn) { + Meta.prototype[`forEach${name}`] = function(fn) { let pointer = this; let seen; while (pointer !== undefined) { @@ -412,17 +411,17 @@ function inheritedMap(name, Meta) { } }; - Meta.prototype[`clear${capitalized}`] = function() { - assert(`Cannot call clear${capitalized} after the object is destroyed.`, !this.isMetaDestroyed()); + Meta.prototype[`clear${name}`] = function() { + assert(`Cannot call clear${name} after the object is destroyed.`, !this.isMetaDestroyed()); this[key] = undefined; }; - Meta.prototype[`deleteFrom${capitalized}`] = function(subkey) { + Meta.prototype[`deleteFrom${name}`] = function(subkey) { delete this._getOrCreateOwnMap(key)[subkey]; }; - Meta.prototype[`hasIn${capitalized}`] = function(subkey) { + Meta.prototype[`hasIn${name}`] = function(subkey) { return this._findInherited(key, subkey) !== undefined; }; } @@ -431,11 +430,9 @@ export const UNDEFINED = symbol('undefined'); // Implements a member that provides a non-heritable, lazily-created // object using the method you provide. -function ownCustomObject(name, Meta) { - let key = memberProperty(name); - let capitalized = capitalize(name); - Meta.prototype[`writable${capitalized}`] = function(create) { - assert(`Cannot call writable${capitalized} after the object is destroyed.`, !this.isMetaDestroyed()); +function ownCustomObject(name, key, Meta) { + Meta.prototype[`writable${name}`] = function(create) { + assert(`Cannot call writable${name} after the object is destroyed.`, !this.isMetaDestroyed()); let ret = this[key]; if (ret === undefined) { @@ -443,7 +440,8 @@ function ownCustomObject(name, Meta) { } return ret; }; - Meta.prototype[`readable${capitalized}`] = function() { + + Meta.prototype[`readable${name}`] = function() { return this[key]; }; } @@ -451,23 +449,22 @@ function ownCustomObject(name, Meta) { // Implements a member that provides an inheritable, lazily-created // object using the method you provide. We will derived children from // their parents by calling your object's `copy()` method. -function inheritedCustomObject(name, Meta) { - let key = memberProperty(name); - let capitalized = capitalize(name); - Meta.prototype[`writable${capitalized}`] = function(create) { - assert(`Cannot call writable${capitalized} after the object is destroyed.`, !this.isMetaDestroyed()); +function inheritedCustomObject(name, key, Meta) { + Meta.prototype[`writable${name}`] = function(create) { + assert(`Cannot call writable${name} after the object is destroyed.`, !this.isMetaDestroyed()); let ret = this[key]; if (ret === undefined) { if (this.parent) { - ret = this[key] = this.parent[`writable${capitalized}`](create).copy(this.source); + ret = this[key] = this.parent[`writable${name}`](create).copy(this.source); } else { ret = this[key] = create(this.source); } } return ret; }; - Meta.prototype[`readable${capitalized}`] = function() { + + Meta.prototype[`readable${name}`] = function() { return this._getInherited(key); }; } From 76d18aeeff00d88f7a18a32bc251c4de43f4cc03 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 8 Jun 2017 17:43:53 +0500 Subject: [PATCH 020/224] wrap `counters` in DEBUG --- packages/ember-metal/lib/meta.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index e07e3647fb7..1353945c99f 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -16,15 +16,18 @@ import { } from './chains'; import { has } from 'require'; -let counters = { - peekCalls: 0, - peekParentCalls: 0, - peekPrototypeWalks: 0, - setCalls: 0, - deleteCalls: 0, - metaCalls: 0, - metaInstantiated: 0 -}; +let counters; +if (DEBUG) { + counters = { + peekCalls: 0, + peekParentCalls: 0, + peekPrototypeWalks: 0, + setCalls: 0, + deleteCalls: 0, + metaCalls: 0, + metaInstantiated: 0 + }; +} /** @module ember-metal From 3cb316949e7c3f28f87467a4893e5575e7a539e7 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 8 Jun 2017 18:41:06 +0500 Subject: [PATCH 021/224] cleanup `metal/chain` --- packages/ember-metal/lib/chains.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/ember-metal/lib/chains.js b/packages/ember-metal/lib/chains.js index 88c1e1fdcda..9046bb93db7 100644 --- a/packages/ember-metal/lib/chains.js +++ b/packages/ember-metal/lib/chains.js @@ -10,7 +10,7 @@ function firstKey(path) { } function isObject(obj) { - return typeof obj === 'object' && obj; + return typeof obj === 'object' && obj !== null; } function isVolatile(obj) { @@ -176,10 +176,7 @@ class ChainNode { destroy() { if (this._watching === true) { - let obj = this._object; - if (obj) { - removeChainWatcher(obj, this._key, this); - } + removeChainWatcher(this._object, this._key, this); this._watching = false; // so future calls do nothing } } @@ -275,9 +272,7 @@ class ChainNode { let parentValue = this._parent.value(); if (parentValue !== this._object) { - if (this._object !== undefined) { - removeChainWatcher(this._object, this._key, this); - } + removeChainWatcher(this._object, this._key, this); if (isObject(parentValue)) { this._object = parentValue; @@ -339,7 +334,7 @@ function lazyGet(obj, key) { // Otherwise attempt to get the cached value of the computed property } else { let cache = meta.readableCache(); - if (cache) { + if (cache !== undefined) { return cacheFor.get(cache, key); } } From ef846de98b6b8bff317e87d388556dd0906756b9 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 8 Jun 2017 19:31:36 +0500 Subject: [PATCH 022/224] unrolled ownMap --- packages/ember-metal/lib/meta.js | 49 +++++++++++++++----------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 0ecc9a1012a..bdda501b161 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -55,8 +55,6 @@ if (DEBUG) { readableTags */ let members = { - cache: ownMap, - weak: ownMap, watching: inheritedMap, mixins: inheritedMap, bindings: inheritedMap, @@ -64,7 +62,6 @@ let members = { chainWatchers: ownCustomObject, chains: inheritedCustomObject, tag: ownCustomObject, - tags: ownMap }; // FLAGS @@ -73,15 +70,9 @@ const SOURCE_DESTROYED = 1 << 2; const META_DESTROYED = 1 << 3; const IS_PROXY = 1 << 4; -if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER || EMBER_GLIMMER_ALLOW_BACKTRACKING_RERENDER) { - members.lastRendered = ownMap; - if (has('ember-debug')) { //https://github.com/emberjs/ember.js/issues/14732 - members.lastRenderedReferenceMap = ownMap; - members.lastRenderedTemplateMap = ownMap; - } -} - +let memberNames = Object.keys(members); const META_FIELD = '__ember_meta__'; +const NODE_STACK = []; export class Meta { constructor(obj, parentMeta) { @@ -359,28 +350,34 @@ export class Meta { get factory() { return this._factory; } + + writableCache() { return this._getOrCreateOwnMap('_cache'); } + readableCache() { return this._cache; } + + writableWeak() { return this._getOrCreateOwnMap('_weak'); } + readableWeak() { return this._weak; } + + writableTags() { return this._getOrCreateOwnMap('_tags'); } + readableTags() { return this._tags; } + } -const NODE_STACK = []; +if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER || EMBER_GLIMMER_ALLOW_BACKTRACKING_RERENDER) { + Meta.prototype.writableLastRendered = function() { return this._getOrCreateOwnMap('_lastRendered'); }; + Meta.prototype.readableLastRendered = function() { return this._lastRendered; }; + if (has('ember-debug')) { //https://github.com/emberjs/ember.js/issues/14732 + Meta.prototype.writableLastRenderedReferenceMap = function() { return this._getOrCreateOwnMap('_lastRenderedReferenceMap'); }; + Meta.prototype.readableLastRenderedReferenceMap = function() { return this._lastRenderedReferenceMap; }; + Meta.prototype.writableLastRenderedTemplateMap = function() { return this._getOrCreateOwnMap('_lastRenderedTemplateMap'); }; + Meta.prototype.readableLastRenderedTemplateMap = function() { return this._lastRenderedTemplateMap; }; + } +} for (let name in listenerMethods) { Meta.prototype[name] = listenerMethods[name]; } -Object.keys(members).forEach(name => { - let key = memberProperty(name); - let capitalized = capitalize(name); - members[name](capitalized, key, Meta); -}); - -// Implements a member that is a lazily created, non-inheritable -// POJO. -function ownMap(name, key, Meta) { - Meta.prototype[`writable${name}`] = function() { - return this._getOrCreateOwnMap(key); - }; - Meta.prototype[`readable${name}`] = function() { return this[key]; }; -} +memberNames.forEach(name => members[name](name, Meta)); // Implements a member that is a lazily created POJO with inheritable // values. From 37f1efa2f39f03edf34eca4289460a784d4dcbdf Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 8 Jun 2017 20:00:00 +0500 Subject: [PATCH 023/224] unrolled `ownCustomObject` --- packages/ember-metal/lib/meta.js | 48 ++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index bdda501b161..6ec390580ab 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -59,9 +59,7 @@ let members = { mixins: inheritedMap, bindings: inheritedMap, values: inheritedMap, - chainWatchers: ownCustomObject, - chains: inheritedCustomObject, - tag: ownCustomObject, + chains: inheritedCustomObject }; // FLAGS @@ -360,6 +358,32 @@ export class Meta { writableTags() { return this._getOrCreateOwnMap('_tags'); } readableTags() { return this._tags; } + writableTag(create) { + assert(`Cannot call writableTag after the object is destroyed.`, !this.isMetaDestroyed()); + let ret = this._tag; + if (ret === undefined) { + ret = this._tag = create(this.source); + } + return ret; + } + + readableTag() { + return this._tag; + } + + writableChainWatchers(create) { + assert(`Cannot call writableChainWatchers after the object is destroyed.`, !this.isMetaDestroyed()); + let ret = this._chainWatchers; + if (ret === undefined) { + ret = this._chainWatchers = create(this.source); + } + return ret; + } + + readableChainWatchers() { + return this._chainWatchers; + } + } if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER || EMBER_GLIMMER_ALLOW_BACKTRACKING_RERENDER) { @@ -428,24 +452,6 @@ function inheritedMap(name, key, Meta) { export const UNDEFINED = symbol('undefined'); -// Implements a member that provides a non-heritable, lazily-created -// object using the method you provide. -function ownCustomObject(name, key, Meta) { - Meta.prototype[`writable${name}`] = function(create) { - assert(`Cannot call writable${name} after the object is destroyed.`, !this.isMetaDestroyed()); - - let ret = this[key]; - if (ret === undefined) { - ret = this[key] = create(this.source); - } - return ret; - }; - - Meta.prototype[`readable${name}`] = function() { - return this[key]; - }; -} - // Implements a member that provides an inheritable, lazily-created // object using the method you provide. We will derived children from // their parents by calling your object's `copy()` method. From 51556355a391f6a8f0fa003e1ef06916e68c408e Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 8 Jun 2017 20:05:08 +0500 Subject: [PATCH 024/224] unrolled `inheritedCustomObject` --- packages/ember-metal/lib/meta.js | 48 +++++++++++++------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 6ec390580ab..72e4008e5ce 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -58,10 +58,11 @@ let members = { watching: inheritedMap, mixins: inheritedMap, bindings: inheritedMap, - values: inheritedMap, - chains: inheritedCustomObject + values: inheritedMap }; +export const UNDEFINED = symbol('undefined'); + // FLAGS const SOURCE_DESTROYING = 1 << 1; const SOURCE_DESTROYED = 1 << 2; @@ -384,6 +385,23 @@ export class Meta { return this._chainWatchers; } + writableChains(create) { + assert(`Cannot call writableChains after the object is destroyed.`, !this.isMetaDestroyed()); + let ret = this._chains; + if (ret === undefined) { + if (this.parent) { + ret = this._chains = this.parent.writableChains(create).copy(this.source); + } else { + ret = this._chains = create(this.source); + } + } + return ret; + } + + readableChains() { + return this._getInherited('_chains'); + } + } if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER || EMBER_GLIMMER_ALLOW_BACKTRACKING_RERENDER) { @@ -450,32 +468,6 @@ function inheritedMap(name, key, Meta) { }; } -export const UNDEFINED = symbol('undefined'); - -// Implements a member that provides an inheritable, lazily-created -// object using the method you provide. We will derived children from -// their parents by calling your object's `copy()` method. -function inheritedCustomObject(name, key, Meta) { - Meta.prototype[`writable${name}`] = function(create) { - assert(`Cannot call writable${name} after the object is destroyed.`, !this.isMetaDestroyed()); - - let ret = this[key]; - if (ret === undefined) { - if (this.parent) { - ret = this[key] = this.parent[`writable${name}`](create).copy(this.source); - } else { - ret = this[key] = create(this.source); - } - } - return ret; - }; - - Meta.prototype[`readable${name}`] = function() { - return this._getInherited(key); - }; -} - - function memberProperty(name) { return `_${name}`; } From 17079e75429e0335c7f94920e57dc1ed3b84a831 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 8 Jun 2017 20:25:13 +0500 Subject: [PATCH 025/224] unrolled `inheritedMap` --- packages/ember-metal/lib/meta.js | 251 ++++++++++++++++++++----------- 1 file changed, 166 insertions(+), 85 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 72e4008e5ce..2d554208e8b 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -33,34 +33,6 @@ if (DEBUG) { @module ember-metal */ -/* - This declares several meta-programmed members on the Meta class. Such - meta! - - In general, the `readable` variants will give you an object (if it - already exists) that you can read but should not modify. The - `writable` variants will give you a mutable object, and they will - create it if it didn't already exist. - - The following methods will get generated metaprogrammatically, and - I'm including them here for greppability: - - writableCache, readableCache, writeWatching, - peekWatching, clearWatching, writeMixins, - peekMixins, clearMixins, writeBindings, - peekBindings, clearBindings, writeValues, - peekValues, clearValues, writeDeps, forEachInDeps - writableChainWatchers, readableChainWatchers, writableChains, - readableChains, writableTag, readableTag, writableTags, - readableTags -*/ -let members = { - watching: inheritedMap, - mixins: inheritedMap, - bindings: inheritedMap, - values: inheritedMap -}; - export const UNDEFINED = symbol('undefined'); // FLAGS @@ -69,7 +41,6 @@ const SOURCE_DESTROYED = 1 << 2; const META_DESTROYED = 1 << 3; const IS_PROXY = 1 << 4; -let memberNames = Object.keys(members); const META_FIELD = '__ember_meta__'; const NODE_STACK = []; @@ -386,60 +357,122 @@ export class Meta { } writableChains(create) { - assert(`Cannot call writableChains after the object is destroyed.`, !this.isMetaDestroyed()); - let ret = this._chains; - if (ret === undefined) { - if (this.parent) { - ret = this._chains = this.parent.writableChains(create).copy(this.source); - } else { - ret = this._chains = create(this.source); + assert(`Cannot call writableChains after the object is destroyed.`, !this.isMetaDestroyed()); + let ret = this._chains; + if (ret === undefined) { + if (this.parent) { + ret = this._chains = this.parent.writableChains(create).copy(this.source); + } else { + ret = this._chains = create(this.source); + } + } + return ret; + } + + readableChains() { + return this._getInherited('_chains'); + } + + writeWatching(subkey, value) { + assert(`Cannot call writeWatching after the object is destroyed.`, !this.isMetaDestroyed()); + let map = this._getOrCreateOwnMap('_watching'); + map[subkey] = value; + } + + peekWatching(subkey) { + return this._findInherited('_watching', subkey); + } + + forEachWatching(fn) { + let pointer = this; + let seen; + while (pointer !== undefined) { + let map = pointer._watching; + if (map !== undefined) { + for (let key in map) { + seen = seen || Object.create(null); + if (seen[key] === undefined) { + seen[key] = true; + fn(key, map[key]); + } } - } - return ret; - } + } + pointer = pointer.parent; + } + } - readableChains() { - return this._getInherited('_chains'); - } + clearWatching() { + assert(`Cannot call clearWatching after the object is destroyed.`, !this.isMetaDestroyed()); -} + this._watching = undefined; + } -if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER || EMBER_GLIMMER_ALLOW_BACKTRACKING_RERENDER) { - Meta.prototype.writableLastRendered = function() { return this._getOrCreateOwnMap('_lastRendered'); }; - Meta.prototype.readableLastRendered = function() { return this._lastRendered; }; - if (has('ember-debug')) { //https://github.com/emberjs/ember.js/issues/14732 - Meta.prototype.writableLastRenderedReferenceMap = function() { return this._getOrCreateOwnMap('_lastRenderedReferenceMap'); }; - Meta.prototype.readableLastRenderedReferenceMap = function() { return this._lastRenderedReferenceMap; }; - Meta.prototype.writableLastRenderedTemplateMap = function() { return this._getOrCreateOwnMap('_lastRenderedTemplateMap'); }; - Meta.prototype.readableLastRenderedTemplateMap = function() { return this._lastRenderedTemplateMap; }; + deleteFromWatching(subkey) { + delete this._getOrCreateOwnMap('_watching')[subkey]; } -} -for (let name in listenerMethods) { - Meta.prototype[name] = listenerMethods[name]; -} + hasInWatching(subkey) { + return this._findInherited('_watching', subkey) !== undefined; + } + + writeMixins(subkey, value) { + assert(`Cannot call writeMixins after the object is destroyed.`, !this.isMetaDestroyed()); + let map = this._getOrCreateOwnMap('_mixins'); + map[subkey] = value; + } + + peekMixins(subkey) { + return this._findInherited('_mixins', subkey); + } -memberNames.forEach(name => members[name](name, Meta)); + forEachMixins(fn) { + let pointer = this; + let seen; + while (pointer !== undefined) { + let map = pointer._mixins; + if (map !== undefined) { + for (let key in map) { + seen = seen || Object.create(null); + if (seen[key] === undefined) { + seen[key] = true; + fn(key, map[key]); + } + } + } + pointer = pointer.parent; + } + } -// Implements a member that is a lazily created POJO with inheritable -// values. -function inheritedMap(name, key, Meta) { - Meta.prototype[`write${name}`] = function(subkey, value) { - assert(`Cannot call write${name} after the object is destroyed.`, !this.isMetaDestroyed()); + clearMixins() { + assert(`Cannot call clearMixins after the object is destroyed.`, !this.isMetaDestroyed()); - let map = this._getOrCreateOwnMap(key); + this._mixins = undefined; + } + + deleteFromMixins(subkey) { + delete this._getOrCreateOwnMap('_mixins')[subkey]; + } + + hasInMixins(subkey) { + return this._findInherited('_mixins', subkey) !== undefined; + } + + writeBindings(subkey, value) { + assert(`Cannot call writeBindings after the object is destroyed.`, !this.isMetaDestroyed()); + + let map = this._getOrCreateOwnMap('_bindings'); map[subkey] = value; - }; + } - Meta.prototype[`peek${name}`] = function(subkey) { - return this._findInherited(key, subkey); - }; + peekBindings(subkey) { + return this._findInherited('_bindings', subkey); + } - Meta.prototype[`forEach${name}`] = function(fn) { + forEachBindings(fn) { let pointer = this; let seen; while (pointer !== undefined) { - let map = pointer[key]; + let map = pointer._bindings; if (map !== undefined) { for (let key in map) { seen = seen || Object.create(null); @@ -451,31 +484,79 @@ function inheritedMap(name, key, Meta) { } pointer = pointer.parent; } - }; + } + + clearBindings() { + assert(`Cannot call clearBindings after the object is destroyed.`, !this.isMetaDestroyed()); + this._bindings = undefined; + } - Meta.prototype[`clear${name}`] = function() { - assert(`Cannot call clear${name} after the object is destroyed.`, !this.isMetaDestroyed()); + deleteFromBindings(subkey) { + delete this._getOrCreateOwnMap('_bindings')[subkey]; + } - this[key] = undefined; - }; + hasInBindings(subkey) { + return this._findInherited('_bindings', subkey) !== undefined; + } - Meta.prototype[`deleteFrom${name}`] = function(subkey) { - delete this._getOrCreateOwnMap(key)[subkey]; - }; + writeValues(subkey, value) { + assert(`Cannot call writeValues after the object is destroyed.`, !this.isMetaDestroyed()); + + let map = this._getOrCreateOwnMap('_values'); + map[subkey] = value; + } + + peekValues(subkey) { + return this._findInherited('_values', subkey); + } + + forEachValues(fn) { + let pointer = this; + let seen; + while (pointer !== undefined) { + let map = pointer._values; + if (map !== undefined) { + for (let key in map) { + seen = seen || Object.create(null); + if (seen[key] === undefined) { + seen[key] = true; + fn(key, map[key]); + } + } + } + pointer = pointer.parent; + } + } + + clearValues() { + assert(`Cannot call clearValues after the object is destroyed.`, !this.isMetaDestroyed()); + + this._values = undefined; + } + + deleteFromValues(subkey) { + delete this._getOrCreateOwnMap('_values')[subkey]; + } + + hasInValues(subkey) { + return this._findInherited('_values', subkey) !== undefined; + } - Meta.prototype[`hasIn${name}`] = function(subkey) { - return this._findInherited(key, subkey) !== undefined; - }; } -function memberProperty(name) { - return `_${name}`; +if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER || EMBER_GLIMMER_ALLOW_BACKTRACKING_RERENDER) { + Meta.prototype.writableLastRendered = function() { return this._getOrCreateOwnMap('_lastRendered'); }; + Meta.prototype.readableLastRendered = function() { return this._lastRendered; }; + if (DEBUG) { + Meta.prototype.writableLastRenderedReferenceMap = function() { return this._getOrCreateOwnMap('_lastRenderedReferenceMap'); }; + Meta.prototype.readableLastRenderedReferenceMap = function() { return this._lastRenderedReferenceMap; }; + Meta.prototype.writableLastRenderedTemplateMap = function() { return this._getOrCreateOwnMap('_lastRenderedTemplateMap'); }; + Meta.prototype.readableLastRenderedTemplateMap = function() { return this._lastRenderedTemplateMap; }; + } } -// there's a more general-purpose capitalize in ember-runtime, but we -// don't want to make ember-metal depend on ember-runtime. -function capitalize(name) { - return name.replace(/^\w/, m => m.toUpperCase()); +for (let name in listenerMethods) { + Meta.prototype[name] = listenerMethods[name]; } export const META_DESC = { From 576df4f814325585c0792aab8411e4a641c5e9ec Mon Sep 17 00:00:00 2001 From: Brian Runnells Date: Fri, 9 Jun 2017 06:47:51 -0500 Subject: [PATCH 026/224] fix factory injection deprecation link --- packages/ember/lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember/lib/index.js b/packages/ember/lib/index.js index abc8ac4339c..3900d0f05ec 100644 --- a/packages/ember/lib/index.js +++ b/packages/ember/lib/index.js @@ -185,7 +185,7 @@ if (DEBUG) { { id: 'ember-metal.model_factory_injections', until: '2.17.0', - url: 'https://emberjs.com/deprecations/v2.x#toc_code-ember-model-factory-injections' + url: 'https://emberjs.com/deprecations/v2.x/#toc_ember-model-em-factory-em-injections-removed' } ); }, From 1f107d182c193c237fbceaf8a66a051ae6b2bf8b Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 10 Jun 2017 13:35:27 +0500 Subject: [PATCH 027/224] wrap `validationCache` and `.validateInjections` and in DEBUG --- packages/container/lib/container.js | 7 ++++--- packages/container/lib/registry.js | 27 +++++++++++++++------------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/packages/container/lib/container.js b/packages/container/lib/container.js index a75af3afa3e..60b9e06bdca 100644 --- a/packages/container/lib/container.js +++ b/packages/container/lib/container.js @@ -32,10 +32,13 @@ export default function Container(registry, options = {}) { this.registry = registry; this.owner = options.owner || null; this.cache = dictionary(options.cache || null); - this.validationCache = dictionary(options.validationCache || null); this.factoryManagerCache = dictionary(options.factoryManagerCache || null); this[CONTAINER_OVERRIDE] = undefined; this.isDestroyed = false; + + if (DEBUG) { + this.validationCache = dictionary(options.validationCache || null); + } } Container.prototype = { @@ -385,7 +388,6 @@ class FactoryManager { } create(options = {}) { - let injections = this.injections; if (injections === undefined) { injections = injectionsFor(this.container, this.normalizedName); @@ -395,7 +397,6 @@ class FactoryManager { } let props = assign({}, injections, options); - if (DEBUG) { let lazyInjections; let validationCache = this.container.validationCache; diff --git a/packages/container/lib/registry.js b/packages/container/lib/registry.js index 73064324316..e12cb57ef9f 100644 --- a/packages/container/lib/registry.js +++ b/packages/container/lib/registry.js @@ -1,6 +1,7 @@ import { dictionary, assign, intern } from 'ember-utils'; import { assert, deprecate } from 'ember-debug'; import Container from './container'; +import { DEBUG } from 'ember-env-flags'; const VALID_FULL_NAME_REGEXP = /^[^:]+:[^:]+$/; @@ -572,18 +573,6 @@ Registry.prototype = { return VALID_FULL_NAME_REGEXP.test(fullName); }, - validateInjections(injections) { - if (!injections) { return; } - - let fullName; - - for (let i = 0; i < injections.length; i++) { - fullName = injections[i].fullName; - - assert(`Attempting to inject an unknown injection: '${fullName}'`, this.has(fullName)); - } - }, - normalizeInjectionsHash(hash) { let injections = []; @@ -627,6 +616,20 @@ function deprecateResolverFunction(registry) { }; } +if (DEBUG) { + Registry.prototype.validateInjections = function(injections) { + if (!injections) { return; } + + let fullName; + + for (let i = 0; i < injections.length; i++) { + fullName = injections[i].fullName; + + assert(`Attempting to inject an unknown injection: '${fullName}'`, this.has(fullName)); + } + } +} + /** Given a fullName and a source fullName returns the fully resolved fullName. Used to allow for local lookup. From 039246156975da845c3fc1d9da87d4469fcf0964 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 10 Jun 2017 11:16:43 -0400 Subject: [PATCH 028/224] [BUGFIX beta] Make better errors for meta updates after object destruction. Prior to this change the errors being thrown by `Meta` were extremely hard to track down since no "real" information was given. After this change, all errors include the `object.toString` and property name in question (if applicable). --- packages/ember-metal/lib/meta.js | 25 +++--- packages/ember-metal/tests/computed_test.js | 18 ++++- packages/ember-metal/tests/meta_test.js | 90 +++++++++++++++++++++ 3 files changed, 120 insertions(+), 13 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 2d554208e8b..0e7167c8a37 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -1,7 +1,8 @@ import { HAS_NATIVE_WEAKMAP, lookupDescriptor, - symbol + symbol, + toString } from 'ember-utils'; import { protoMethods as listenerMethods } from './meta_listeners'; import { assert } from 'ember-debug'; @@ -211,7 +212,7 @@ export class Meta { // Implements a member that provides a lazily created map of maps, // with inheritance at both levels. writeDeps(subkey, itemkey, value) { - assert(`Cannot call writeDeps after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot modify dependent keys for \`${itemkey}\` on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); let outerMap = this._getOrCreateOwnMap('_deps'); let innerMap = outerMap[subkey]; @@ -331,7 +332,7 @@ export class Meta { readableTags() { return this._tags; } writableTag(create) { - assert(`Cannot call writableTag after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot create a new tag for \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); let ret = this._tag; if (ret === undefined) { ret = this._tag = create(this.source); @@ -344,7 +345,7 @@ export class Meta { } writableChainWatchers(create) { - assert(`Cannot call writableChainWatchers after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot create a new chain watcher for \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); let ret = this._chainWatchers; if (ret === undefined) { ret = this._chainWatchers = create(this.source); @@ -357,7 +358,7 @@ export class Meta { } writableChains(create) { - assert(`Cannot call writableChains after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot create a new chains for \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); let ret = this._chains; if (ret === undefined) { if (this.parent) { @@ -374,7 +375,7 @@ export class Meta { } writeWatching(subkey, value) { - assert(`Cannot call writeWatching after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot update watchers for \`hello\` on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); let map = this._getOrCreateOwnMap('_watching'); map[subkey] = value; } @@ -402,7 +403,7 @@ export class Meta { } clearWatching() { - assert(`Cannot call clearWatching after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot clear watchers on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); this._watching = undefined; } @@ -416,7 +417,7 @@ export class Meta { } writeMixins(subkey, value) { - assert(`Cannot call writeMixins after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot add mixins for \`${subkey}\` on \`${toString(this.source)}\` call writeMixins after it has been destroyed.`, !this.isMetaDestroyed()); let map = this._getOrCreateOwnMap('_mixins'); map[subkey] = value; } @@ -444,7 +445,7 @@ export class Meta { } clearMixins() { - assert(`Cannot call clearMixins after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot clear mixins on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); this._mixins = undefined; } @@ -458,7 +459,7 @@ export class Meta { } writeBindings(subkey, value) { - assert(`Cannot call writeBindings after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot add a binding for \`${subkey}\` on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); let map = this._getOrCreateOwnMap('_bindings'); map[subkey] = value; @@ -487,7 +488,7 @@ export class Meta { } clearBindings() { - assert(`Cannot call clearBindings after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot clear bindings on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); this._bindings = undefined; } @@ -500,7 +501,7 @@ export class Meta { } writeValues(subkey, value) { - assert(`Cannot call writeValues after the object is destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot set the value of \`${subkey}\` on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); let map = this._getOrCreateOwnMap('_values'); map[subkey] = value; diff --git a/packages/ember-metal/tests/computed_test.js b/packages/ember-metal/tests/computed_test.js index b48b4b7adc8..3711d227ff3 100644 --- a/packages/ember-metal/tests/computed_test.js +++ b/packages/ember-metal/tests/computed_test.js @@ -10,7 +10,8 @@ import { set, isWatching, addObserver, - _addBeforeObserver + _addBeforeObserver, + meta as metaFor } from '..'; let obj, count; @@ -481,6 +482,21 @@ testBoth('throws assertion if brace expansion notation has spaces', function (ge }, /cannot contain spaces/); }); +testBoth('throws an assertion if an uncached `get` is called after object is destroyed', function(get, set) { + equal(isWatching(obj, 'bar'), false, 'precond not watching dependent key'); + + let meta = metaFor(obj); + meta.destroy(); + + obj.toString = () => ''; + + expectAssertion(() => { + get(obj, 'foo', 'bar'); + }, 'Cannot modify dependent keys for `foo` on `` after it has been destroyed.'); + + equal(isWatching(obj, 'bar'), false, 'deps were not updated'); +}); + // .......................................................... // CHAINED DEPENDENT KEYS // diff --git a/packages/ember-metal/tests/meta_test.js b/packages/ember-metal/tests/meta_test.js index 2c732b53861..c31c7fd5ebf 100644 --- a/packages/ember-metal/tests/meta_test.js +++ b/packages/ember-metal/tests/meta_test.js @@ -75,3 +75,93 @@ QUnit.test('meta.listeners deduplication', function(assert) { assert.equal(matching.length, 3); assert.equal(matching[0], t); }); + +QUnit.test('meta.writeWatching issues useful error after destroy', function(assert) { + let target = { + toString() { return ''; } + }; + let targetMeta = meta(target); + + targetMeta.destroy(); + + expectAssertion(() => { + targetMeta.writeWatching('hello', 1); + }, 'Cannot update watchers for `hello` on `` after it has been destroyed.'); +}); + +QUnit.test('meta.clearWatching issues useful error after destroy', function(assert) { + let target = { + toString() { return ''; } + }; + let targetMeta = meta(target); + + targetMeta.destroy(); + + expectAssertion(() => { + targetMeta.clearWatching(); + }, 'Cannot clear watchers on `` after it has been destroyed.'); +}); +QUnit.test('meta.writableTag issues useful error after destroy', function(assert) { + let target = { + toString() { return ''; } + }; + let targetMeta = meta(target); + + targetMeta.destroy(); + + expectAssertion(() => { + targetMeta.writableTag(() => {}); + }, 'Cannot create a new tag for `` after it has been destroyed.'); +}); + +QUnit.test('meta.writableChainWatchers issues useful error after destroy', function(assert) { + let target = { + toString() { return ''; } + }; + let targetMeta = meta(target); + + targetMeta.destroy(); + + expectAssertion(() => { + targetMeta.writableChainWatchers(() => {}); + }, 'Cannot create a new chain watcher for `` after it has been destroyed.'); +}); + +QUnit.test('meta.writableChains issues useful error after destroy', function(assert) { + let target = { + toString() { return ''; } + }; + let targetMeta = meta(target); + + targetMeta.destroy(); + + expectAssertion(() => { + targetMeta.writableChains(() => {}); + }, 'Cannot create a new chains for `` after it has been destroyed.'); +}); + +QUnit.test('meta.writeValues issues useful error after destroy', function(assert) { + let target = { + toString() { return ''; } + }; + let targetMeta = meta(target); + + targetMeta.destroy(); + + expectAssertion(() => { + targetMeta.writeValues('derp', 'ohai'); + }, 'Cannot set the value of `derp` on `` after it has been destroyed.'); +}); + +QUnit.test('meta.writeDeps issues useful error after destroy', function(assert) { + let target = { + toString() { return ''; } + }; + let targetMeta = meta(target); + + targetMeta.destroy(); + + expectAssertion(() => { + targetMeta.writeDeps('derp', 'ohai', 1); + }, 'Cannot modify dependent keys for `ohai` on `` after it has been destroyed.'); +}); From 3540bd39a36d80b1639dae2314af4a3454bce334 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Wed, 7 Jun 2017 22:55:10 -0700 Subject: [PATCH 029/224] Non-globals-resolver friendly `setupForTesting()` 1) Update `setupForTesting` to reference the router factory in the registry instead of the globally resolved one on the application instance. 2) Extend the Router during application registry setup to isolate `reopen` calls. --- packages/ember-application/lib/system/application.js | 2 +- packages/ember-testing/lib/ext/application.js | 5 +++-- packages/ember-testing/tests/helpers_test.js | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/ember-application/lib/system/application.js b/packages/ember-application/lib/system/application.js index bd40720d1dc..a9cfa3d870d 100644 --- a/packages/ember-application/lib/system/application.js +++ b/packages/ember-application/lib/system/application.js @@ -1028,7 +1028,7 @@ Application.reopenClass({ }); function commonSetupRegistry(registry) { - registry.register('router:main', Router); + registry.register('router:main', Router.extend()); registry.register('-view-registry:main', { create() { return dictionary(null); } }); registry.register('route:basic', Route); diff --git a/packages/ember-testing/lib/ext/application.js b/packages/ember-testing/lib/ext/application.js index afcbd713354..6dd6d017e55 100644 --- a/packages/ember-testing/lib/ext/application.js +++ b/packages/ember-testing/lib/ext/application.js @@ -60,7 +60,8 @@ EmberApplication.reopen({ the app when your tests are ready to run. It also sets the router's location to 'none', so that the window's location will not be modified (preventing both accidental leaking of state between tests and interference - with your testing framework). + with your testing framework). `setupForTesting` should only be called after + setting a custom `router` class (for example `App.Router = Router.extend(`). Example: @@ -76,7 +77,7 @@ EmberApplication.reopen({ this.testing = true; - this.Router.reopen({ + this.resolveRegistration('router:main').reopen({ location: 'none' }); }, diff --git a/packages/ember-testing/tests/helpers_test.js b/packages/ember-testing/tests/helpers_test.js index deb99871202..3679a2884dc 100644 --- a/packages/ember-testing/tests/helpers_test.js +++ b/packages/ember-testing/tests/helpers_test.js @@ -830,7 +830,6 @@ QUnit.module('ember-testing routing helpers', { setup() { run(function() { App = EmberApplication.create(); - App.setupForTesting(); App.injectTestHelpers(); @@ -843,6 +842,8 @@ QUnit.module('ember-testing routing helpers', { this.route('new'); }); }); + + App.setupForTesting(); }); run(App, 'advanceReadiness'); From 764e43faec890c39671da08f2869edd9f5ac4944 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Wed, 7 Jun 2017 16:38:42 -0700 Subject: [PATCH 030/224] Decouple acceptance_test, helpers_test frm globals References #15058 --- .../ember-testing/tests/acceptance_test.js | 580 +++--- packages/ember-testing/tests/helpers_test.js | 1771 +++++++++-------- 2 files changed, 1250 insertions(+), 1101 deletions(-) diff --git a/packages/ember-testing/tests/acceptance_test.js b/packages/ember-testing/tests/acceptance_test.js index d1f91dfa4b0..f465281c335 100644 --- a/packages/ember-testing/tests/acceptance_test.js +++ b/packages/ember-testing/tests/acceptance_test.js @@ -1,33 +1,22 @@ +import { + moduleFor, + AutobootApplicationTestCase +} from 'internal-test-helpers'; + import { run } from 'ember-metal'; -import { jQuery } from 'ember-views'; import Test from '../test'; import QUnitAdapter from '../adapters/qunit'; -import '../initializers'; // ensure the initializer is setup -import { Application as EmberApplication } from 'ember-application'; -import { Route as EmberRoute } from 'ember-routing'; -import { compile } from 'ember-template-compiler'; +import { Route } from 'ember-routing'; import { RSVP } from 'ember-runtime'; -import { setTemplates, setTemplate } from 'ember-glimmer'; - -//ES6TODO: we need {{link-to}} and {{outlet}} to exist here - -var App, find, click, fillIn, currentRoute, currentURL, visit, originalAdapter, andThen, indexHitCount; -QUnit.module('ember-testing Acceptance', { - setup() { - jQuery('').appendTo('head'); - jQuery('
').appendTo('body'); +moduleFor('ember-testing Acceptance', class extends AutobootApplicationTestCase { + constructor() { + super(); + this._originalAdapter = Test.adapter; - originalAdapter = Test.adapter; - - run(function() { - indexHitCount = 0; - - App = EmberApplication.create({ - rootElement: '#ember-testing' - }); - - App.Router.map(function() { + this.runTask(() => { + this.createApplication(); + this.router.map(function() { this.route('posts'); this.route('comments'); @@ -36,376 +25,365 @@ QUnit.module('ember-testing Acceptance', { this.route('redirect'); }); - App.IndexRoute = EmberRoute.extend({ + this.indexHitCount = 0; + this.currentRoute = 'index'; + let testContext = this; + + this.add('route:index', Route.extend({ model() { - indexHitCount += 1; + testContext.indexHitCount += 1; } - }); + })); - App.PostsRoute = EmberRoute.extend({ + this.add('route:posts', Route.extend({ renderTemplate() { - currentRoute = 'posts'; + testContext.currentRoute = 'posts'; this._super(...arguments); } - }); - - setTemplate('posts', compile('
')); - - App.CommentsRoute = EmberRoute.extend({ + })); + + this.addTemplate('posts', ` +
+ + +
+ `); + + this.add('route:comments', Route.extend({ renderTemplate() { - currentRoute = 'comments'; + testContext.currentRoute = 'comments'; this._super(...arguments); } - }); + })); - setTemplate('comments', compile('
{{input type="text"}}
')); + this.addTemplate('comments', `
{{input type="text"}}
`); - App.AbortTransitionRoute = EmberRoute.extend({ + this.add('route:abort_transition', Route.extend({ beforeModel(transition) { transition.abort(); } - }); + })); - App.RedirectRoute = EmberRoute.extend({ + this.add('route:redirect', Route.extend({ beforeModel() { this.transitionTo('comments'); } - }); + })); - App.setupForTesting(); - }); + this.application.setupForTesting(); - Test.registerAsyncHelper('slowHelper', function() { - return new RSVP.Promise(function(resolve) { - setTimeout(resolve, 10); + Test.registerAsyncHelper('slowHelper', () => { + return new RSVP.Promise(resolve => run.later(resolve, 10)); }); - }); - App.injectTestHelpers(); - - find = window.find; - click = window.click; - fillIn = window.fillIn; - visit = window.visit; - andThen = window.andThen; - currentURL = window.currentURL; - }, + this.application.injectTestHelpers(); + }); + } teardown() { - Test.unregisterHelper('slowHelper'); - setTemplates({}); - jQuery('#ember-testing-container, #ember-testing').remove(); - run(App, App.destroy); - App = null; - Test.adapter = originalAdapter; - indexHitCount = 0; + Test.adapter = this._originalAdapter; + super.teardown(); } -}); -QUnit.test('helpers can be chained with then', function() { - expect(6); - - currentRoute = 'index'; - - visit('/posts').then(function() { - equal(currentRoute, 'posts', 'Successfully visited posts route'); - equal(currentURL(), '/posts', 'posts URL is correct'); - return click('a:contains("Comments")'); - }).then(function() { - equal(currentRoute, 'comments', 'visit chained with click'); - return fillIn('.ember-text-field', 'yeah'); - }).then(function() { - equal(jQuery('.ember-text-field').val(), 'yeah', 'chained with fillIn'); - return fillIn('.ember-text-field', '#ember-testing-container', 'context working'); - }).then(function() { - equal(jQuery('.ember-text-field').val(), 'context working', 'chained with fillIn'); - return click('.does-not-exist'); - }).then(null, function(e) { - equal(e.message, 'Element .does-not-exist not found.', 'Non-existent click exception caught'); - }); -}); + [`@test helpers can be chained with then`](assert) { + assert.expect(6); + + window.visit('/posts').then(() => { + assert.equal(this.currentRoute, 'posts', 'Successfully visited posts route'); + assert.equal(window.currentURL(), '/posts', 'posts URL is correct'); + return window.click('a:contains("Comments")'); + }).then(() => { + assert.equal(this.currentRoute, 'comments', 'visit chained with click'); + return window.fillIn('.ember-text-field', 'yeah'); + }).then(() => { + assert.equal(this.$('.ember-text-field').val(), 'yeah', 'chained with fillIn'); + return window.fillIn('.ember-text-field', '#qunit-fixture', 'context working'); + }).then(() => { + assert.equal(this.$('.ember-text-field').val(), 'context working', 'chained with fillIn'); + return window.click('.does-not-exist'); + }).catch(e => { + assert.equal(e.message, 'Element .does-not-exist not found.', 'Non-existent click exception caught'); + }); + } + [`@test helpers can be chained to each other (legacy)`](assert) { + assert.expect(7); + + window.visit('/posts') + .click('a:first', '#comments-link') + .fillIn('.ember-text-field', 'hello') + .then(() => { + assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); + assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); + assert.equal(this.$('.ember-text-field').val(), 'hello', 'Fillin successfully works'); + window.find('.ember-text-field').one('keypress', e => { + assert.equal(e.keyCode, 13, 'keyevent chained with correct keyCode.'); + assert.equal(e.which, 13, 'keyevent chained with correct which.'); + }); + }) + .keyEvent('.ember-text-field', 'keypress', 13) + .visit('/posts') + .then(() => { + assert.equal(this.currentRoute, 'posts', 'Thens can also be chained to helpers'); + assert.equal(window.currentURL(), '/posts', 'URL is set correct on chained helpers'); + }); + } + [`@test helpers don't need to be chained`](assert) { + assert.expect(5); -// Keep this for backwards compatibility + window.visit('/posts'); -QUnit.test('helpers can be chained to each other', function() { - expect(7); + window.click('a:first', '#comments-link'); - currentRoute = 'index'; + window.fillIn('.ember-text-field', 'hello'); - visit('/posts') - .click('a:first', '#comments-link') - .fillIn('.ember-text-field', 'hello') - .then(function() { - equal(currentRoute, 'comments', 'Successfully visited comments route'); - equal(currentURL(), '/comments', 'Comments URL is correct'); - equal(jQuery('.ember-text-field').val(), 'hello', 'Fillin successfully works'); - find('.ember-text-field').one('keypress', function(e) { - equal(e.keyCode, 13, 'keyevent chained with correct keyCode.'); - equal(e.which, 13, 'keyevent chained with correct which.'); + window.andThen(() => { + assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); + assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); + assert.equal(window.find('.ember-text-field').val(), 'hello', 'Fillin successfully works'); }); - }) - .keyEvent('.ember-text-field', 'keypress', 13) - .visit('/posts') - .then(function() { - equal(currentRoute, 'posts', 'Thens can also be chained to helpers'); - equal(currentURL(), '/posts', 'URL is set correct on chained helpers'); - }); -}); - -QUnit.test('helpers don\'t need to be chained', function() { - expect(5); - currentRoute = 'index'; + window.visit('/posts'); - visit('/posts'); - - click('a:first', '#comments-link'); + window.andThen(() => { + assert.equal(this.currentRoute, 'posts'); + assert.equal(window.currentURL(), '/posts'); + }); + } - fillIn('.ember-text-field', 'hello'); + [`@test Nested async helpers`](assert) { + assert.expect(5); - andThen(function() { - equal(currentRoute, 'comments', 'Successfully visited comments route'); - equal(currentURL(), '/comments', 'Comments URL is correct'); - equal(find('.ember-text-field').val(), 'hello', 'Fillin successfully works'); - }); + window.visit('/posts'); - visit('/posts'); + window.andThen(() => { + window.click('a:first', '#comments-link'); + window.fillIn('.ember-text-field', 'hello'); + }); - andThen(function() { - equal(currentRoute, 'posts'); - equal(currentURL(), '/posts'); - }); -}); + window.andThen(() => { + assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); + assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); + assert.equal(window.find('.ember-text-field').val(), 'hello', 'Fillin successfully works'); + }); -QUnit.test('Nested async helpers', function() { - expect(5); + window.visit('/posts'); - currentRoute = 'index'; + window.andThen(() => { + assert.equal(this.currentRoute, 'posts'); + assert.equal(window.currentURL(), '/posts'); + }); + } - visit('/posts'); + [`@test Multiple nested async helpers`](assert) { + assert.expect(3); - andThen(function() { - click('a:first', '#comments-link'); + window.visit('/posts'); - fillIn('.ember-text-field', 'hello'); - }); + window.andThen(() => { + window.click('a:first', '#comments-link'); - andThen(function() { - equal(currentRoute, 'comments', 'Successfully visited comments route'); - equal(currentURL(), '/comments', 'Comments URL is correct'); - equal(find('.ember-text-field').val(), 'hello', 'Fillin successfully works'); - }); + window.fillIn('.ember-text-field', 'hello'); + window.fillIn('.ember-text-field', 'goodbye'); + }); - visit('/posts'); + window.andThen(() => { + assert.equal(window.find('.ember-text-field').val(), 'goodbye', 'Fillin successfully works'); + assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); + assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); + }); + } - andThen(function() { - equal(currentRoute, 'posts'); - equal(currentURL(), '/posts'); - }); -}); + [`@test Helpers nested in thens`](assert) { + assert.expect(5); -QUnit.test('Multiple nested async helpers', function() { - expect(3); + window.visit('/posts').then(() => { + window.click('a:first', '#comments-link'); + }); - visit('/posts'); + window.andThen(() => { + window.fillIn('.ember-text-field', 'hello'); + }); - andThen(function() { - click('a:first', '#comments-link'); + window.andThen(() => { + assert.equal(this.currentRoute, 'comments', 'Successfully visited comments route'); + assert.equal(window.currentURL(), '/comments', 'Comments URL is correct'); + assert.equal(window.find('.ember-text-field').val(), 'hello', 'Fillin successfully works'); + }); - fillIn('.ember-text-field', 'hello'); - fillIn('.ember-text-field', 'goodbye'); - }); + window.visit('/posts'); - andThen(function() { - equal(find('.ember-text-field').val(), 'goodbye', 'Fillin successfully works'); - equal(currentRoute, 'comments', 'Successfully visited comments route'); - equal(currentURL(), '/comments', 'Comments URL is correct'); - }); -}); + window.andThen(() => { + assert.equal(this.currentRoute, 'posts'); + assert.equal(window.currentURL(), '/posts', 'Posts URL is correct'); + }); + } -QUnit.test('Helpers nested in thens', function() { - expect(5); + [`@test Aborted transitions are not logged via Ember.Test.adapter#exception`](assert) { + assert.expect(0); - currentRoute = 'index'; + Test.adapter = QUnitAdapter.create({ + exception(error) { + assert.ok(false, 'aborted transitions are not logged'); + } + }); - visit('/posts').then(function() { - click('a:first', '#comments-link'); - }); + window.visit('/abort_transition'); + } - andThen(function() { - fillIn('.ember-text-field', 'hello'); - }); + [`@test Unhandled exceptions are logged via Ember.Test.adapter#exception`](assert) { + assert.expect(2); + + let asyncHandled; + Test.adapter = QUnitAdapter.create({ + exception(error) { + assert.equal( + error.message, 'Element .does-not-exist not found.', + 'Exception successfully caught and passed to Ember.Test.adapter.exception' + ); + // handle the rejection so it doesn't leak later. + asyncHandled.catch(() => { }); + } + }); - andThen(function() { - equal(currentRoute, 'comments', 'Successfully visited comments route'); - equal(currentURL(), '/comments', 'Comments URL is correct'); - equal(find('.ember-text-field').val(), 'hello', 'Fillin successfully works'); - }); + window.visit('/posts'); - visit('/posts'); + window.click('.invalid-element').catch(error => { + assert.equal( + error.message, 'Element .invalid-element not found.', + 'Exception successfully handled in the rejection handler' + ); + }); - andThen(function() { - equal(currentRoute, 'posts'); - equal(currentURL(), '/posts', 'Posts URL is correct'); - }); -}); + asyncHandled = window.click('.does-not-exist'); + } -QUnit.test('Aborted transitions are not logged via Ember.Test.adapter#exception', function () { - expect(0); + [`@test Unhandled exceptions in 'andThen' are logged via Ember.Test.adapter#exception`](assert) { + assert.expect(1); - Test.adapter = QUnitAdapter.create({ - exception(error) { - ok(false, 'aborted transitions are not logged'); - } - }); + Test.adapter = QUnitAdapter.create({ + exception(error) { + assert.equal( + error.message, 'Catch me', + 'Exception successfully caught and passed to Ember.Test.adapter.exception' + ); + } + }); - visit('/abort_transition'); -}); + window.visit('/posts'); -QUnit.test('Unhandled exceptions are logged via Ember.Test.adapter#exception', function () { - expect(2); + window.andThen(() => { + throw new Error('Catch me'); + }); + } - var asyncHandled; - Test.adapter = QUnitAdapter.create({ - exception(error) { - equal(error.message, 'Element .does-not-exist not found.', 'Exception successfully caught and passed to Ember.Test.adapter.exception'); - asyncHandled['catch'](function() { }); // handle the rejection so it doesn't leak later. - } - }); + [`@test should not start routing on the root URL when visiting another`](assert) { + assert.expect(4); - visit('/posts'); + window.visit('/posts'); - click('.invalid-element').then(null, function(error) { - equal(error.message, 'Element .invalid-element not found.', 'Exception successfully handled in the rejection handler'); - }); + window.andThen(() => { + assert.ok(window.find('#comments-link'), 'found comments-link'); + assert.equal(this.currentRoute, 'posts', 'Successfully visited posts route'); + assert.equal(window.currentURL(), '/posts', 'Posts URL is correct'); + assert.equal(this.indexHitCount, 0, 'should not hit index route when visiting another route'); + }); + } - asyncHandled = click('.does-not-exist'); -}); + [`@test only enters the index route once when visiting `](assert) { + assert.expect(1); -QUnit.test('Unhandled exceptions in `andThen` are logged via Ember.Test.adapter#exception', function () { - expect(1); + window.visit('/'); - Test.adapter = QUnitAdapter.create({ - exception(error) { - equal(error.message, 'Catch me', 'Exception successfully caught and passed to Ember.Test.adapter.exception'); - } - }); + window.andThen(() => { + assert.equal(this.indexHitCount, 1, 'should hit index once when visiting /'); + }); + } - visit('/posts'); + [`@test test must not finish while asyncHelpers are pending`](assert) { + assert.expect(2); - andThen(function() { - throw new Error('Catch me'); - }); -}); + let async = 0; + let innerRan = false; -QUnit.test('should not start routing on the root URL when visiting another', function() { - expect(4); + Test.adapter = QUnitAdapter.extend({ + asyncStart() { + async++; + this._super(); + }, + asyncEnd() { + async--; + this._super(); + } + }).create(); - visit('/posts'); + this.application.testHelpers.slowHelper(); - andThen(function() { - ok(find('#comments-link'), 'found comments-link'); - equal(currentRoute, 'posts', 'Successfully visited posts route'); - equal(currentURL(), '/posts', 'Posts URL is correct'); - equal(indexHitCount, 0, 'should not hit index route when visiting another route'); - }); -}); + window.andThen(() => { + innerRan = true; + }); -QUnit.test('only enters the index route once when visiting /', function() { - expect(1); + assert.equal(innerRan, false, 'should not have run yet'); + assert.ok(async > 0, 'should have told the adapter to pause'); - visit('/'); + if (async === 0) { + // If we failed the test, prevent zalgo from escaping and breaking + // our other tests. + Test.adapter.asyncStart(); + Test.resolve().then(() => { + Test.adapter.asyncEnd(); + }); + } + } - andThen(function() { - equal(indexHitCount, 1, 'should hit index once when visiting /'); - }); -}); + [`@test visiting a URL that causes another transition should yield the correct URL`](assert) { + assert.expect(1); -QUnit.test('test must not finish while asyncHelpers are pending', function () { - expect(2); + window.visit('/redirect'); - var async = 0; - var innerRan = false; + window.andThen(() => { + assert.equal(window.currentURL(), '/comments', 'Redirected to Comments URL'); + }); + } - Test.adapter = QUnitAdapter.extend({ - asyncStart() { - async++; - this._super(); - }, - asyncEnd() { - async--; - this._super(); - } - }).create(); + [`@test visiting a URL and then visiting a second URL with a transition should yield the correct URL`](assert) { + assert.expect(2); - App.testHelpers.slowHelper(); - andThen(function() { - innerRan = true; - }); + window.visit('/posts'); + window.andThen(function () { + assert.equal(window.currentURL(), '/posts', 'First visited URL is correct'); + }); - equal(innerRan, false, 'should not have run yet'); - ok(async > 0, 'should have told the adapter to pause'); + window.visit('/redirect'); - if (async === 0) { - // If we failed the test, prevent zalgo from escaping and breaking - // our other tests. - Test.adapter.asyncStart(); - Test.resolve().then(function() { - Test.adapter.asyncEnd(); + window.andThen(() => { + assert.equal(window.currentURL(), '/comments', 'Redirected to Comments URL'); }); } -}); - -QUnit.test('visiting a URL that causes another transition should yield the correct URL', function () { - expect(1); - - visit('/redirect'); - andThen(function () { - equal(currentURL(), '/comments', 'Redirected to Comments URL'); - }); }); -QUnit.test('visiting a URL and then visiting a second URL with a transition should yield the correct URL', function () { - expect(2); - - visit('/posts'); - - andThen(function () { - equal(currentURL(), '/posts', 'First visited URL is correct'); - }); +moduleFor('ember-testing Acceptance - teardown', class extends AutobootApplicationTestCase { - visit('/redirect'); + [`@test that the setup/teardown happens correctly`](assert) { + assert.expect(2); - andThen(function () { - equal(currentURL(), '/comments', 'Redirected to Comments URL'); - }); -}); + this.runTask(() => { + this.createApplication(); + }); + this.application.injectTestHelpers(); -QUnit.module('ember-testing Acceptance – teardown'); + assert.ok(typeof Test.Promise.prototype.click === 'function'); -QUnit.test('that the setup/teardown happens correct', function() { - expect(2); + this.runTask(() => { + this.application.destroy(); + }); - jQuery('').appendTo('head'); - jQuery('
').appendTo('body'); + assert.equal(Test.Promise.prototype.click, undefined); + } - run(function() { - indexHitCount = 0; - App = EmberApplication.create({ - rootElement: '#ember-testing' - }); - }); - App.injectTestHelpers(); - - jQuery('#ember-testing-container, #ember-testing').remove(); - ok(typeof Test.Promise.prototype.click === 'function'); - run(App, App.destroy); - equal(Test.Promise.prototype.click, undefined); - App = null; - Test.adapter = originalAdapter; - indexHitCount = 0; }); diff --git a/packages/ember-testing/tests/helpers_test.js b/packages/ember-testing/tests/helpers_test.js index 3679a2884dc..2cd9215d37e 100644 --- a/packages/ember-testing/tests/helpers_test.js +++ b/packages/ember-testing/tests/helpers_test.js @@ -1,23 +1,21 @@ -import { Route, Router } from 'ember-routing'; +import { + moduleFor, + AutobootApplicationTestCase +} from 'internal-test-helpers'; + +import { Route } from 'ember-routing'; import { Controller, - Object as EmberObject, RSVP } from 'ember-runtime'; import { run } from 'ember-metal'; import { jQuery } from 'ember-views'; import { Component, - setTemplates, - setTemplate } from 'ember-glimmer'; import Test from '../test'; -import '../helpers'; // ensure that the helpers are loaded -import '../initializers'; // ensure the initializer is setup import setupForTesting from '../setup_for_testing'; -import { Application as EmberApplication } from 'ember-application'; -import { compile } from 'ember-template-compiler'; import { pendingRequests, @@ -33,32 +31,11 @@ import { unregisterWaiter } from '../test/waiters'; -var App; -var originalAdapter = getAdapter(); - -function cleanup() { - // Teardown setupForTesting - - setAdapter(originalAdapter); - run(function() { - jQuery(document).off('ajaxSend'); - jQuery(document).off('ajaxComplete'); - }); - clearPendingRequests(); - // Test.waiters = null; - - // Other cleanup - - if (App) { - run(App, App.destroy); - App.removeTestHelpers(); - App = null; - } - - setTemplates({}); +function registerHelper() { + Test.registerHelper('LeakyMcLeakLeak', () => {}); } -function assertHelpers(application, helperContainer, expected) { +function assertHelpers(assert, application, helperContainer, expected) { if (!helperContainer) { helperContainer = window; } if (expected === undefined) { expected = true; } @@ -66,8 +43,14 @@ function assertHelpers(application, helperContainer, expected) { var presentInHelperContainer = !!helperContainer[helper]; var presentInTestHelpers = !!application.testHelpers[helper]; - ok(presentInHelperContainer === expected, 'Expected \'' + helper + '\' to be present in the helper container (defaults to window).'); - ok(presentInTestHelpers === expected, 'Expected \'' + helper + '\' to be present in App.testHelpers.'); + assert.ok( + presentInHelperContainer === expected, + 'Expected \'' + helper + '\' to be present in the helper container (defaults to window).' + ); + assert.ok( + presentInTestHelpers === expected, + 'Expected \'' + helper + '\' to be present in App.testHelpers.' + ); } checkHelperPresent('visit', expected); @@ -78,994 +61,1182 @@ function assertHelpers(application, helperContainer, expected) { checkHelperPresent('triggerEvent', expected); } -function assertNoHelpers(application, helperContainer) { - assertHelpers(application, helperContainer, false); -} - -function currentRouteName(app) { - return app.testHelpers.currentRouteName(); +function assertNoHelpers(assert, application, helperContainer) { + assertHelpers(assert, application, helperContainer, false); } -function currentPath(app) { - return app.testHelpers.currentPath(); -} +class HelpersTestCase extends AutobootApplicationTestCase { -function currentURL(app) { - return app.testHelpers.currentURL(); -} + constructor() { + super(); + this._originalAdapter = getAdapter(); + } -function setupApp() { - run(function() { - App = EmberApplication.create(); - App.setupForTesting(); + teardown() { + setAdapter(this._originalAdapter); + jQuery(document).off('ajaxSend'); + jQuery(document).off('ajaxComplete'); + clearPendingRequests(); + if (this.application) { + this.application.removeTestHelpers(); + } + super.teardown(); + } - App.injectTestHelpers(); - }); } -QUnit.module('ember-testing: Helper setup', { - setup() { cleanup(); }, - teardown() { cleanup(); } -}); - -function registerHelper() { - Test.registerHelper('LeakyMcLeakLeak', function(app) { - }); +class HelpersApplicationTestCase extends HelpersTestCase { + constructor() { + super(); + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + this.application.injectTestHelpers(); + }); + } } -QUnit.test('Ember.Application#injectTestHelpers/#removeTestHelpers', function() { - App = run(EmberApplication, EmberApplication.create); - assertNoHelpers(App); - - registerHelper(); +moduleFor('ember-testing: Helper setup', class extends HelpersTestCase { - App.injectTestHelpers(); - assertHelpers(App); - ok(Test.Promise.prototype.LeakyMcLeakLeak, 'helper in question SHOULD be present'); - - App.removeTestHelpers(); - assertNoHelpers(App); + [`@test Ember.Application#injectTestHelpers/#removeTestHelper`](assert) { + this.runTask(() => { + this.createApplication(); + }); - equal(Test.Promise.prototype.LeakyMcLeakLeak, undefined, 'should NOT leak test promise extensions'); -}); + assertNoHelpers(assert, this.application); + registerHelper(); -QUnit.test('Ember.Application#setupForTesting', function() { - run(function() { - App = EmberApplication.create(); - App.setupForTesting(); - }); + this.application.injectTestHelpers(); - equal(App.__container__.lookup('router:main').location, 'none'); -}); + assertHelpers(assert, this.application); -QUnit.test('Ember.Application.setupForTesting sets the application to `testing`.', function() { - run(function() { - App = EmberApplication.create(); - App.setupForTesting(); - }); + assert.ok( + Test.Promise.prototype.LeakyMcLeakLeak, + 'helper in question SHOULD be present' + ); - equal(App.testing, true, 'Application instance is set to testing.'); -}); + this.application.removeTestHelpers(); -QUnit.test('Ember.Application.setupForTesting leaves the system in a deferred state.', function() { - run(function() { - App = EmberApplication.create(); - App.setupForTesting(); - }); + assertNoHelpers(assert, this.application); - equal(App._readinessDeferrals, 1, 'App is in deferred state after setupForTesting.'); -}); - -QUnit.test('App.reset() after Application.setupForTesting leaves the system in a deferred state.', function() { - run(function() { - App = EmberApplication.create(); - App.setupForTesting(); - }); - - equal(App._readinessDeferrals, 1, 'App is in deferred state after setupForTesting.'); + assert.equal( + Test.Promise.prototype.LeakyMcLeakLeak, undefined, + 'should NOT leak test promise extensions' + ); + } - App.reset(); - equal(App._readinessDeferrals, 1, 'App is in deferred state after setupForTesting.'); -}); + [`@test Ember.Application#setupForTesting`](assert) { + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); -QUnit.test('Ember.Application#setupForTesting attaches ajax listeners', function() { - var documentEvents; + let routerInstance = this.applicationInstance.lookup('router:main'); + assert.equal(routerInstance.location, 'none'); + } - documentEvents = jQuery._data(document, 'events'); + [`@test Ember.Application.setupForTesting sets the application to 'testing'`](assert) { + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - if (!documentEvents) { - documentEvents = {}; + assert.equal( + this.application.testing, true, + 'Application instance is set to testing.' + ); } - ok(documentEvents['ajaxSend'] === undefined, 'there are no ajaxSend listers setup prior to calling injectTestHelpers'); - ok(documentEvents['ajaxComplete'] === undefined, 'there are no ajaxComplete listers setup prior to calling injectTestHelpers'); - - run(function() { - setupForTesting(); - }); + [`@test Ember.Application.setupForTesting leaves the system in a deferred state.`](assert) { + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - documentEvents = jQuery._data(document, 'events'); + assert.equal( + this.application._readinessDeferrals, 1, + 'App is in deferred state after setupForTesting.' + ); + } - equal(documentEvents['ajaxSend'].length, 1, 'calling injectTestHelpers registers an ajaxSend handler'); - equal(documentEvents['ajaxComplete'].length, 1, 'calling injectTestHelpers registers an ajaxComplete handler'); -}); + [`@test App.reset() after Application.setupForTesting leaves the system in a deferred state.`](assert) { + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); -QUnit.test('Ember.Application#setupForTesting attaches ajax listeners only once', function() { - var documentEvents; + assert.equal( + this.application._readinessDeferrals, 1, + 'App is in deferred state after setupForTesting.' + ); - documentEvents = jQuery._data(document, 'events'); + this.application.reset(); - if (!documentEvents) { - documentEvents = {}; + assert.equal( + this.application._readinessDeferrals, 1, + 'App is in deferred state after setupForTesting.' + ); } - ok(documentEvents['ajaxSend'] === undefined, 'there are no ajaxSend listeners setup prior to calling injectTestHelpers'); - ok(documentEvents['ajaxComplete'] === undefined, 'there are no ajaxComplete listeners setup prior to calling injectTestHelpers'); - - run(function() { - setupForTesting(); - }); - run(function() { - setupForTesting(); - }); - - documentEvents = jQuery._data(document, 'events'); + [`@test #setupForTesting attaches ajax listeners`](assert) { + let documentEvents = jQuery._data(document, 'events') || {}; - equal(documentEvents['ajaxSend'].length, 1, 'calling injectTestHelpers registers an ajaxSend handler'); - equal(documentEvents['ajaxComplete'].length, 1, 'calling injectTestHelpers registers an ajaxComplete handler'); -}); + assert.ok( + documentEvents['ajaxSend'] === undefined, + 'there are no ajaxSend listers setup prior to calling injectTestHelpers' + ); + assert.ok( + documentEvents['ajaxComplete'] === undefined, + 'there are no ajaxComplete listers setup prior to calling injectTestHelpers' + ); -QUnit.test('Ember.Application#injectTestHelpers calls callbacks registered with onInjectHelpers', function() { - var injected = 0; + setupForTesting(); - Test.onInjectHelpers(function() { - injected++; - }); + documentEvents = jQuery._data(document, 'events'); - run(function() { - App = EmberApplication.create(); - App.setupForTesting(); - }); + assert.equal( + documentEvents['ajaxSend'].length, 1, + 'calling injectTestHelpers registers an ajaxSend handler' + ); + assert.equal( + documentEvents['ajaxComplete'].length, 1, + 'calling injectTestHelpers registers an ajaxComplete handler' + ); + } - equal(injected, 0, 'onInjectHelpers are not called before injectTestHelpers'); + [`@test #setupForTesting attaches ajax listeners only once`](assert) { + let documentEvents = jQuery._data(document, 'events') || {}; - App.injectTestHelpers(); + assert.ok( + documentEvents['ajaxSend'] === undefined, + 'there are no ajaxSend listeners setup prior to calling injectTestHelpers' + ); + assert.ok( + documentEvents['ajaxComplete'] === undefined, + 'there are no ajaxComplete listeners setup prior to calling injectTestHelpers' + ); - equal(injected, 1, 'onInjectHelpers are called after injectTestHelpers'); -}); + setupForTesting(); + setupForTesting(); -QUnit.test('Ember.Application#injectTestHelpers adds helpers to provided object.', function() { - var helpers = {}; + documentEvents = jQuery._data(document, 'events'); - run(function() { - App = EmberApplication.create(); - App.setupForTesting(); - }); + assert.equal( + documentEvents['ajaxSend'].length, 1, + 'calling injectTestHelpers registers an ajaxSend handler' + ); + assert.equal( + documentEvents['ajaxComplete'].length, 1, + 'calling injectTestHelpers registers an ajaxComplete handler' + ); + } - App.injectTestHelpers(helpers); - assertHelpers(App, helpers); + [`@test Ember.Application#injectTestHelpers calls callbacks registered with onInjectHelpers`](assert) { + let injected = 0; - App.removeTestHelpers(); - assertNoHelpers(App, helpers); -}); + Test.onInjectHelpers(() => { + injected++; + }); -QUnit.test('Ember.Application#removeTestHelpers resets the helperContainer\'s original values', function() { - var helpers = { visit: 'snazzleflabber' }; + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); - run(function() { - App = EmberApplication.create(); - App.setupForTesting(); - }); + assert.equal( + injected, 0, + 'onInjectHelpers are not called before injectTestHelpers' + ); - App.injectTestHelpers(helpers); + this.application.injectTestHelpers(); - ok(helpers.visit !== 'snazzleflabber', 'helper added to container'); - App.removeTestHelpers(); + assert.equal( + injected, 1, + 'onInjectHelpers are called after injectTestHelpers' + ); + } - ok(helpers.visit === 'snazzleflabber', 'original value added back to container'); -}); + [`@test Ember.Application#injectTestHelpers adds helpers to provided object.`](assert) { + let helpers = {}; -QUnit.module('ember-testing: Helper methods', { - setup() { - setupApp(); - }, - teardown() { - cleanup(); - } -}); + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + }); -QUnit.test('`wait` respects registerWaiters', function(assert) { - assert.expect(3); + this.application.injectTestHelpers(helpers); - let done = assert.async(); + assertHelpers(assert, this.application, helpers); - let counter = 0; - function waiter() { - return ++counter > 2; - } + this.application.removeTestHelpers(); - let other = 0; - function otherWaiter() { - return ++other > 2; + assertNoHelpers(assert, this.application, helpers); } - run(App, App.advanceReadiness); - registerWaiter(waiter); - registerWaiter(otherWaiter); + [`@test Ember.Application#removeTestHelpers resets the helperContainer\'s original values`](assert) { + let helpers = { visit: 'snazzleflabber' }; - App.testHelpers.wait() - .then(function() { - equal(waiter(), true, 'should not resolve until our waiter is ready'); - unregisterWaiter(waiter); - counter = 0; - return App.testHelpers.wait(); - }) - .then(function() { - equal(counter, 0, 'unregistered waiter was not checked'); - equal(otherWaiter(), true, 'other waiter is still registered'); - }) - .finally(() => { - unregisterWaiter(otherWaiter); - done(); + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); }); -}); - -QUnit.test('`visit` advances readiness.', function() { - expect(2); - - equal(App._readinessDeferrals, 1, 'App is in deferred state after setupForTesting.'); - return App.testHelpers.visit('/').then(function() { - equal(App._readinessDeferrals, 0, 'App\'s readiness was advanced by visit.'); - }); -}); - -QUnit.test('`wait` helper can be passed a resolution value', function() { - expect(4); - - var promise, wait; - - promise = new RSVP.Promise(function(resolve) { - run(null, resolve, 'promise'); - }); + this.application.injectTestHelpers(helpers); - run(App, App.advanceReadiness); + assert.notEqual( + helpers.visit, 'snazzleflabber', + 'helper added to container' + ); + this.application.removeTestHelpers(); - wait = App.testHelpers.wait; + assert.equal( + helpers.visit, 'snazzleflabber', + 'original value added back to container' + ); + } - return wait('text').then(function(val) { - equal(val, 'text', 'can resolve to a string'); - return wait(1); - }).then(function(val) { - equal(val, 1, 'can resolve to an integer'); - return wait({ age: 10 }); - }).then(function(val) { - deepEqual(val, { age: 10 }, 'can resolve to an object'); - return wait(promise); - }).then(function(val) { - equal(val, 'promise', 'can resolve to a promise resolution value'); - }); }); -QUnit.test('`click` triggers appropriate events in order', function() { - expect(5); - - var click, wait, events; +moduleFor('ember-testing: Helper methods', class extends HelpersApplicationTestCase { - App.IndexWrapperComponent = Component.extend({ - classNames: 'index-wrapper', + [`@test 'wait' respects registerWaiters`](assert) { + assert.expect(3); - didInsertElement() { - this.$().on('mousedown focusin mouseup click', function(e) { - events.push(e.type); - }); - } - }); - - App.XCheckboxComponent = Component.extend({ - tagName: 'input', - attributeBindings: ['type'], - type: 'checkbox', - click() { - events.push('click:' + this.get('checked')); - }, - change() { - events.push('change:' + this.get('checked')); + let counter = 0; + function waiter() { + return ++counter > 2; } - }); - - setTemplate('index', compile('{{#index-wrapper}}{{input type="text"}} {{x-checkbox type="checkbox"}} {{textarea}}
{{/index-wrapper}}')); - - run(App, App.advanceReadiness); - - click = App.testHelpers.click; - wait = App.testHelpers.wait; - - return wait().then(function() { - events = []; - return click('.index-wrapper'); - }).then(function() { - deepEqual(events, - ['mousedown', 'mouseup', 'click'], - 'fires events in order'); - }).then(function() { - events = []; - return click('.index-wrapper input[type=text]'); - }).then(function() { - deepEqual(events, - ['mousedown', 'focusin', 'mouseup', 'click'], - 'fires focus events on inputs'); - }).then(function() { - events = []; - return click('.index-wrapper textarea'); - }).then(function() { - deepEqual(events, - ['mousedown', 'focusin', 'mouseup', 'click'], - 'fires focus events on textareas'); - }).then(function() { - events = []; - return click('.index-wrapper div'); - }).then(function() { - deepEqual(events, - ['mousedown', 'focusin', 'mouseup', 'click'], - 'fires focus events on contenteditable'); - }).then(function() { - events = []; - return click('.index-wrapper input[type=checkbox]'); - }).then(function() { - // i.e. mousedown, mouseup, change:true, click, click:true - // Firefox differs so we can't assert the exact ordering here. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=843554. - equal(events.length, 5, 'fires click and change on checkboxes'); - }); -}); - -QUnit.test('`click` triggers native events with simulated X/Y coordinates', function() { - expect(15); - - var click, wait, events; - - App.IndexWrapperComponent = Component.extend({ - classNames: 'index-wrapper', - didInsertElement() { - let pushEvent = e => events.push(e); - this.element.addEventListener('mousedown', pushEvent); - this.element.addEventListener('mouseup', pushEvent); - this.element.addEventListener('click', pushEvent); + let other = 0; + function otherWaiter() { + return ++other > 2; } - }); - - - setTemplate('index', compile('{{#index-wrapper}}some text{{/index-wrapper}}')); - - run(App, App.advanceReadiness); - - click = App.testHelpers.click; - wait = App.testHelpers.wait; - return wait().then(function() { - events = []; - return click('.index-wrapper'); - }).then(function() { - events.forEach(e => { - ok(e instanceof window.Event, 'The event is an instance of MouseEvent'); - ok(typeof e.screenX === 'number' && e.screenX > 0, 'screenX is correct'); - ok(typeof e.screenY === 'number' && e.screenY > 0, 'screenY is correct'); - ok(typeof e.clientX === 'number' && e.clientX > 0, 'clientX is correct'); - ok(typeof e.clientY === 'number' && e.clientY > 0, 'clientY is correct'); + this.runTask(() => { + this.application.advanceReadiness(); }); - }); -}); - -QUnit.test('`triggerEvent` with mouseenter triggers native events with simulated X/Y coordinates', function() { - expect(5); - var triggerEvent, wait, evt; + registerWaiter(waiter); + registerWaiter(otherWaiter); - App.IndexWrapperComponent = Component.extend({ - classNames: 'index-wrapper', + let {application: {testHelpers}} = this; + return testHelpers.wait().then(() => { + assert.equal( + waiter(), true, + 'should not resolve until our waiter is ready' + ); + unregisterWaiter(waiter); + counter = 0; + return testHelpers.wait(); + }).then(() => { + assert.equal( + counter, 0, + 'unregistered waiter was not checked' + ); + assert.equal( + otherWaiter(), true, + 'other waiter is still registered' + ); + }).finally(() => { + unregisterWaiter(otherWaiter); + }); + } - didInsertElement() { - this.element.addEventListener('mouseenter', e => evt = e); - } - }); + [`@test 'visit' advances readiness.`](assert) { + assert.expect(2); + assert.equal( + this.application._readinessDeferrals, 1, + 'App is in deferred state after setupForTesting.' + ); - setTemplate('index', compile('{{#index-wrapper}}some text{{/index-wrapper}}')); + return this.application.testHelpers.visit('/').then(() => { + assert.equal( + this.application._readinessDeferrals, 0, + `App's readiness was advanced by visit.` + ); + }); + } - run(App, App.advanceReadiness); + [`@test 'wait' helper can be passed a resolution value`](assert) { + assert.expect(4); - triggerEvent = App.testHelpers.triggerEvent; - wait = App.testHelpers.wait; + this.runTask(() => { + this.application.advanceReadiness(); + }); - return wait().then(function() { - return triggerEvent('.index-wrapper', 'mouseenter'); - }).then(function() { - ok(evt instanceof window.Event, 'The event is an instance of MouseEvent'); - ok(typeof evt.screenX === 'number' && evt.screenX > 0, 'screenX is correct'); - ok(typeof evt.screenY === 'number' && evt.screenY > 0, 'screenY is correct'); - ok(typeof evt.clientX === 'number' && evt.clientX > 0, 'clientX is correct'); - ok(typeof evt.clientY === 'number' && evt.clientY > 0, 'clientY is correct'); - }); -}); + let promiseObjectValue = {}; + let objectValue = {}; + let {application: {testHelpers}} = this; + return testHelpers.wait('text').then(val => { + assert.equal( + val, 'text', + 'can resolve to a string' + ); + return testHelpers.wait(1); + }).then(val => { + assert.equal( + val, 1, + 'can resolve to an integer' + ); + return testHelpers.wait(objectValue); + }).then(val => { + assert.equal( + val, objectValue, + 'can resolve to an object' + ); + return testHelpers.wait(RSVP.resolve(promiseObjectValue)); + }).then(val => { + assert.equal( + val, promiseObjectValue, + 'can resolve to a promise resolution value' + ); + }); + } -QUnit.test('`wait` waits for outstanding timers', function() { - expect(1); + [`@test 'click' triggers appropriate events in order`](assert) { + assert.expect(5); - var wait_done = false; + this.add('component:index-wrapper', Component.extend({ + classNames: 'index-wrapper', - run(App, App.advanceReadiness); + didInsertElement() { + this.$().on('mousedown focusin mouseup click', e => { + events.push(e.type); + }); + } + })); + + this.add('component:x-checkbox', Component.extend({ + tagName: 'input', + attributeBindings: ['type'], + type: 'checkbox', + click() { + events.push('click:' + this.get('checked')); + }, + change() { + events.push('change:' + this.get('checked')); + } + })); + + this.addTemplate('index', ` + {{#index-wrapper}} + {{input type="text"}} + {{x-checkbox type="checkbox"}} + {{textarea}} +
+ {{/index-wrapper}}')); + `); + + this.runTask(() => { + this.application.advanceReadiness(); + }); - run.later(this, function() { - wait_done = true; - }, 500); + let events; + let {application: {testHelpers}} = this; + return testHelpers.wait().then(() => { + events = []; + return testHelpers.click('.index-wrapper'); + }).then(() => { + assert.deepEqual( + events, ['mousedown', 'mouseup', 'click'], + 'fires events in order' + ); + }).then(() => { + events = []; + return testHelpers.click('.index-wrapper input[type=text]'); + }).then(() => { + assert.deepEqual( + events, ['mousedown', 'focusin', 'mouseup', 'click'], + 'fires focus events on inputs' + ); + }).then(() => { + events = []; + return testHelpers.click('.index-wrapper textarea'); + }).then(() => { + assert.deepEqual( + events, ['mousedown', 'focusin', 'mouseup', 'click'], + 'fires focus events on textareas' + ); + }).then(() => { + events = []; + return testHelpers.click('.index-wrapper div'); + }).then(() => { + assert.deepEqual( + events, ['mousedown', 'focusin', 'mouseup', 'click'], + 'fires focus events on contenteditable' + ); + }).then(() => { + events = []; + return testHelpers.click('.index-wrapper input[type=checkbox]'); + }).then(() => { + // i.e. mousedown, mouseup, change:true, click, click:true + // Firefox differs so we can't assert the exact ordering here. + // See https://bugzilla.mozilla.org/show_bug.cgi?id=843554. + assert.equal( + events.length, 5, + 'fires click and change on checkboxes' + ); + }); + } - return App.testHelpers.wait().then(function() { - equal(wait_done, true, 'should wait for the timer to be fired.'); - }); -}); + [`@test 'click' triggers native events with simulated X/Y coordinates`](assert) { + assert.expect(15); -QUnit.test('`wait` respects registerWaiters with optional context', function() { - expect(3); + this.add('component:index-wrapper', Component.extend({ + classNames: 'index-wrapper', - let obj = { - counter: 0, - ready() { - return ++this.counter > 2; - } - }; + didInsertElement() { + let pushEvent = e => events.push(e); + this.element.addEventListener('mousedown', pushEvent); + this.element.addEventListener('mouseup', pushEvent); + this.element.addEventListener('click', pushEvent); + } + })); - let other = 0; - function otherWaiter() { - return ++other > 2; - } + this.addTemplate('index', ` + {{#index-wrapper}}some text{{/index-wrapper}} + `); - run(App, App.advanceReadiness); - registerWaiter(obj, obj.ready); - registerWaiter(otherWaiter); - - return App.testHelpers.wait().then(function() { - equal(obj.ready(), true, 'should not resolve until our waiter is ready'); - unregisterWaiter(obj, obj.ready); - obj.counter = 0; - return App.testHelpers.wait(); - }).then(function() { - equal(obj.counter, 0, 'the unregistered waiter should still be at 0'); - equal(otherWaiter(), true, 'other waiter should still be registered'); - }) - .finally(() => { - unregisterWaiter(otherWaiter); + this.runTask(() => { + this.application.advanceReadiness(); }); -}); -QUnit.test('`wait` does not error if routing has not begun', function() { - expect(1); + let events; + let {application: {testHelpers: {wait, click}}} = this; + return wait().then(() => { + events = []; + return click('.index-wrapper'); + }).then(() => { + events.forEach(e => { + assert.ok( + e instanceof window.Event, + 'The event is an instance of MouseEvent' + ); + assert.ok( + typeof e.screenX === 'number', + 'screenX is correct' + ); + assert.ok( + typeof e.screenY === 'number', + 'screenY is correct' + ); + assert.ok( + typeof e.clientX === 'number', + 'clientX is correct' + ); + assert.ok( + typeof e.clientY === 'number', + 'clientY is correct' + ); + }); + }); + } - return App.testHelpers.wait().then(function() { - ok(true, 'should not error without `visit`'); - }); -}); + [`@test 'triggerEvent' with mouseenter triggers native events with simulated X/Y coordinates`](assert) { + assert.expect(5); -QUnit.test('`triggerEvent accepts an optional options hash without context', function() { - expect(3); + let evt; + this.add('component:index-wrapper', Component.extend({ + classNames: 'index-wrapper', + didInsertElement() { + this.element.addEventListener('mouseenter', e => evt = e); + } + })); - var triggerEvent, wait, event; + this.addTemplate('index', `{{#index-wrapper}}some text{{/index-wrapper}}`); - App.IndexWrapperComponent = Component.extend({ - didInsertElement() { - this.$('.input').on('keydown change', function(e) { - event = e; - }); - } - }); + this.runTask(() => { + this.application.advanceReadiness(); + }); - setTemplate('index', compile('{{index-wrapper}}')); - setTemplate('components/index-wrapper', compile('{{input type="text" id="scope" class="input"}}')); + let {application: {testHelpers: {wait, triggerEvent}}} = this; + return wait().then(() => { + return triggerEvent('.index-wrapper', 'mouseenter'); + }).then(() => { + assert.ok( + evt instanceof window.Event, + 'The event is an instance of MouseEvent' + ); + assert.ok( + typeof evt.screenX === 'number', + 'screenX is correct' + ); + assert.ok( + typeof evt.screenY === 'number', + 'screenY is correct' + ); + assert.ok( + typeof evt.clientX === 'number', + 'clientX is correct' + ); + assert.ok( + typeof evt.clientY === 'number', + 'clientY is correct' + ); + }); + } - run(App, App.advanceReadiness); + [`@test 'wait' waits for outstanding timers`](assert) { + assert.expect(1); - triggerEvent = App.testHelpers.triggerEvent; - wait = App.testHelpers.wait; + this.runTask(() => { + this.application.advanceReadiness(); + }); - return wait().then(function() { - return triggerEvent('.input', 'keydown', { keyCode: 13 }); - }).then(function() { - equal(event.keyCode, 13, 'options were passed'); - equal(event.type, 'keydown', 'correct event was triggered'); - equal(event.target.getAttribute('id'), 'scope', 'triggered on the correct element'); - }); -}); + let waitDone = false; + run.later(() => { + waitDone = true; + }, 20); -QUnit.test('`triggerEvent can limit searching for a selector to a scope', function() { - expect(2); + return this.application.testHelpers.wait().then(() => { + assert.equal(waitDone, true, 'should wait for the timer to be fired.'); + }); + } - var triggerEvent, wait, event; + [`@test 'wait' respects registerWaiters with optional context`](assert) { + assert.expect(3); - App.IndexWrapperComponent = Component.extend({ + let obj = { + counter: 0, + ready() { + return ++this.counter > 2; + } + }; - didInsertElement() { - this.$('.input').on('blur change', function(e) { - event = e; - }); + let other = 0; + function otherWaiter() { + return ++other > 2; } - }); - - setTemplate('components/index-wrapper', compile('{{input type="text" id="outside-scope" class="input"}}
{{input type="text" id="inside-scope" class="input"}}
')); - setTemplate('index', compile('{{index-wrapper}}')); - - run(App, App.advanceReadiness); - triggerEvent = App.testHelpers.triggerEvent; - wait = App.testHelpers.wait; + this.runTask(() => { + this.application.advanceReadiness(); + }); - return wait().then(function() { - return triggerEvent('.input', '#limited', 'blur'); - }).then(function() { - equal(event.type, 'blur', 'correct event was triggered'); - equal(event.target.getAttribute('id'), 'inside-scope', 'triggered on the correct element'); - }); -}); + registerWaiter(obj, obj.ready); + registerWaiter(otherWaiter); + + let {application: {testHelpers: {wait}}} = this; + return wait().then(() => { + assert.equal( + obj.ready(), true, + 'should not resolve until our waiter is ready' + ); + unregisterWaiter(obj, obj.ready); + obj.counter = 0; + return wait(); + }).then(() => { + assert.equal( + obj.counter, 0, + 'the unregistered waiter should still be at 0' + ); + assert.equal( + otherWaiter(), true, + 'other waiter should still be registered' + ); + }).finally(() => { + unregisterWaiter(otherWaiter); + }); + } -QUnit.test('`triggerEvent` can be used to trigger arbitrary events', function() { - expect(2); + [`@test 'wait' does not error if routing has not begun`](assert) { + assert.expect(1); - var triggerEvent, wait, event; + return this.application.testHelpers.wait().then(() => { + ok(true, 'should not error without `visit`'); + }); + } - App.IndexWrapperComponent = Component.extend({ - didInsertElement() { - this.$('#foo').on('blur change', function(e) { - event = e; - }); - } - }); + [`@test 'triggerEvent' accepts an optional options hash without context`](assert) { + assert.expect(3); - setTemplate('components/index-wrapper', compile('{{input type="text" id="foo"}}')); - setTemplate('index', compile('{{index-wrapper}}')); + let event; + this.add('component:index-wrapper', Component.extend({ + didInsertElement() { + this.$('.input').on('keydown change', e => event = e); + } + })); - run(App, App.advanceReadiness); + this.addTemplate('index', `{{index-wrapper}}`); + this.addTemplate('components/index-wrapper', ` + {{input type="text" id="scope" class="input"}} + `); - triggerEvent = App.testHelpers.triggerEvent; - wait = App.testHelpers.wait; + this.runTask(() => { + this.application.advanceReadiness(); + }); - return wait().then(function() { - return triggerEvent('#foo', 'blur'); - }).then(function() { - equal(event.type, 'blur', 'correct event was triggered'); - equal(event.target.getAttribute('id'), 'foo', 'triggered on the correct element'); - }); -}); + let {application: {testHelpers: {wait, triggerEvent}}} = this; + return wait().then(() => { + return triggerEvent('.input', 'keydown', { keyCode: 13 }); + }).then(() => { + assert.equal(event.keyCode, 13, 'options were passed'); + assert.equal(event.type, 'keydown', 'correct event was triggered'); + assert.equal(event.target.getAttribute('id'), 'scope', 'triggered on the correct element'); + }); + } -QUnit.test('`fillIn` takes context into consideration', function() { - expect(2); - var fillIn, find, visit, andThen; + [`@test 'triggerEvent' can limit searching for a selector to a scope`](assert) { + assert.expect(2); - setTemplate('index', compile('
{{input type="text" id="first" class="current"}}
{{input type="text" id="second" class="current"}}')); + let event; + this.add('component:index-wrapper', Component.extend({ + didInsertElement() { + this.$('.input').on('blur change', e => event = e); + } + })); + + this.addTemplate('components/index-wrapper', ` + {{input type="text" id="outside-scope" class="input"}} +
+ {{input type="text" id="inside-scope" class="input"}} +
+ `); + this.addTemplate('index', `{{index-wrapper}}`); + + this.runTask(() => { + this.application.advanceReadiness(); + }); - run(App, App.advanceReadiness); + let {application: {testHelpers: {wait, triggerEvent}}} = this; + return wait().then(() => { + return triggerEvent('.input', '#limited', 'blur'); + }).then(() => { + assert.equal( + event.type, 'blur', + 'correct event was triggered' + ); + assert.equal( + event.target.getAttribute('id'), 'inside-scope', + 'triggered on the correct element' + ); + }); + } - fillIn = App.testHelpers.fillIn; - find = App.testHelpers.find; - visit = App.testHelpers.visit; - andThen = App.testHelpers.andThen; + [`@test 'triggerEvent' can be used to trigger arbitrary events`](assert) { + assert.expect(2); - visit('/'); - fillIn('.current', '#parent', 'current value'); + let event; + this.add('component:index-wrapper', Component.extend({ + didInsertElement() { + this.$('#foo').on('blur change', e => event = e); + } + })); - return andThen(function() { - equal(find('#first').val(), 'current value'); - equal(find('#second').val(), ''); - }); -}); + this.addTemplate('components/index-wrapper', ` + {{input type="text" id="foo"}} + `); + this.addTemplate('index', `{{index-wrapper}}`); -QUnit.test('`fillIn` focuses on the element', function() { - expect(2); - var fillIn, find, visit, andThen, wait; + this.runTask(() => { + this.application.advanceReadiness(); + }); - App.ApplicationRoute = Route.extend({ - actions: { - wasFocused() { - ok(true, 'focusIn event was triggered'); - } - } - }); + let {application: {testHelpers: {wait, triggerEvent}}} = this; + return wait().then(() => { + return triggerEvent('#foo', 'blur'); + }).then(() => { + assert.equal( + event.type, 'blur', + 'correct event was triggered' + ); + assert.equal( + event.target.getAttribute('id'), 'foo', + 'triggered on the correct element' + ); + }); + } - setTemplate('index', compile('
{{input type="text" id="first" focus-in="wasFocused"}}
')); + [`@test 'fillIn' takes context into consideration`](assert) { + assert.expect(2); - run(App, App.advanceReadiness); + this.addTemplate('index', ` +
+ {{input type="text" id="first" class="current"}} +
+ {{input type="text" id="second" class="current"}} + `); - fillIn = App.testHelpers.fillIn; - find = App.testHelpers.find; - visit = App.testHelpers.visit; - andThen = App.testHelpers.andThen; - wait = App.testHelpers.wait; + this.runTask(() => { + this.application.advanceReadiness(); + }); - visit('/'); - fillIn('#first', 'current value'); - andThen(function() { - equal(find('#first').val(), 'current value'); - }); + let {application: {testHelpers: {visit, fillIn, andThen, find}}} = this; + visit('/'); + fillIn('.current', '#parent', 'current value'); - return wait(); -}); + return andThen(() => { + assert.equal(find('#first').val(), 'current value'); + assert.equal(find('#second').val(), ''); + }); + } -QUnit.test('`fillIn` fires `input` and `change` events in the proper order', function() { - expect(1); + [`@test 'fillIn' focuses on the element`](assert) { + assert.expect(2); - var fillIn, visit, andThen, wait; - var events = []; - App.IndexController = Controller.extend({ - actions: { - oninputHandler(e) { - events.push(e.type); - }, - onchangeHandler(e) { - events.push(e.type); + this.add('route:application', Route.extend({ + actions: { + wasFocused() { + assert.ok(true, 'focusIn event was triggered'); + } } - } - }); + })); - setTemplate('index', compile('')); + this.addTemplate('index', ` +
+ {{input type="text" id="first" focus-in="wasFocused"}} +
' + `); - run(App, App.advanceReadiness); + this.runTask(() => { + this.application.advanceReadiness(); + }); - fillIn = App.testHelpers.fillIn; - visit = App.testHelpers.visit; - andThen = App.testHelpers.andThen; - wait = App.testHelpers.wait; + let {application: {testHelpers: {visit, fillIn, andThen, find, wait}}} = this; + visit('/'); + fillIn('#first', 'current value'); + andThen(() => { + assert.equal( + find('#first').val(),'current value' + ); + }); - visit('/'); - fillIn('#first', 'current value'); - andThen(function() { - deepEqual(events, ['input', 'change'], '`input` and `change` events are fired in the proper order'); - }); + return wait(); + } - return wait(); -}); + [`@test 'fillIn' fires 'input' and 'change' events in the proper order`](assert) { + assert.expect(1); + + let events = []; + this.add('controller:index', Controller.extend({ + actions: { + oninputHandler(e) { + events.push(e.type); + }, + onchangeHandler(e) { + events.push(e.type); + } + } + })); -QUnit.test('`fillIn` only sets the value in the first matched element', function() { - let fillIn, find, visit, andThen, wait; + this.addTemplate('index', ` + + `); - setTemplate('index', compile('')); - run(App, App.advanceReadiness); + this.runTask(() => { + this.application.advanceReadiness(); + }); - fillIn = App.testHelpers.fillIn; - find = App.testHelpers.find; - visit = App.testHelpers.visit; - andThen = App.testHelpers.andThen; - wait = App.testHelpers.wait; + let {application: {testHelpers: {visit, fillIn, andThen, wait}}} = this; - visit('/'); - fillIn('input.in-test', 'new value'); - andThen(function() { - equal(find('#first').val(), 'new value'); - equal(find('#second').val(), ''); - }); + visit('/'); + fillIn('#first', 'current value'); + andThen(() => { + assert.deepEqual(events, ['input', 'change'], '`input` and `change` events are fired in the proper order'); + }); - return wait(); -}); + return wait(); + } -QUnit.test('`triggerEvent accepts an optional options hash and context', function() { - expect(3); + [`@test 'fillIn' only sets the value in the first matched element`](assert) { + this.addTemplate('index', ` + + + `); - var triggerEvent, wait, event; + this.runTask(() => { + this.application.advanceReadiness(); + }); - App.IndexWrapperComponent = Component.extend({ - didInsertElement() { - this.$('.input').on('keydown change', function(e) { - event = e; - }); - } - }); + let {application: {testHelpers: {visit, fillIn, find, andThen, wait}}} = this; + + visit('/'); + fillIn('input.in-test', 'new value'); + andThen(() => { + assert.equal( + find('#first').val(), 'new value' + ); + assert.equal( + find('#second').val(), '' + ); + }); - setTemplate('components/index-wrapper', compile('{{input type="text" id="outside-scope" class="input"}}
{{input type="text" id="inside-scope" class="input"}}
')); - setTemplate('index', compile('{{index-wrapper}}')); + return wait(); + } - run(App, App.advanceReadiness); + [`@test 'triggerEvent' accepts an optional options hash and context`](assert) { + assert.expect(3); - triggerEvent = App.testHelpers.triggerEvent; - wait = App.testHelpers.wait; + let event; + this.add('component:index-wrapper', Component.extend({ + didInsertElement() { + this.$('.input').on('keydown change', e => event = e); + } + })); + + this.addTemplate('components/index-wrapper', ` + {{input type="text" id="outside-scope" class="input"}} +
+ {{input type="text" id="inside-scope" class="input"}} +
+ `); + this.addTemplate('index', `{{index-wrapper}}`); + + this.runTask(() => { + this.application.advanceReadiness(); + }); - return wait() - .then(function() { + let {application: {testHelpers: {wait, triggerEvent}}} = this; + return wait().then(() => { return triggerEvent('.input', '#limited', 'keydown', { keyCode: 13 }); - }) - .then(function() { - equal(event.keyCode, 13, 'options were passed'); - equal(event.type, 'keydown', 'correct event was triggered'); - equal(event.target.getAttribute('id'), 'inside-scope', 'triggered on the correct element'); + }).then(() => { + assert.equal(event.keyCode, 13, 'options were passed'); + assert.equal(event.type, 'keydown', 'correct event was triggered'); + assert.equal(event.target.getAttribute('id'), 'inside-scope', 'triggered on the correct element'); }); -}); + } +}); -QUnit.module('ember-testing debugging helpers', { - setup() { - setupApp(); +moduleFor('ember-testing: debugging helpers', class extends HelpersApplicationTestCase { - run(function() { - App.Router = Router.extend({ - location: 'none' - }); + constructor() { + super(); + this.runTask(() => { + this.application.advanceReadiness(); }); - - run(App, 'advanceReadiness'); - }, - - teardown() { - cleanup(); } -}); -QUnit.test('pauseTest pauses', function() { - expect(1); + [`@test pauseTest pauses`](assert) { + assert.expect(1); + + let {application: {testHelpers: {andThen, pauseTest}}} = this; + andThen(() => { + Test.adapter.asyncStart = () => { + assert.ok( + true, + 'Async start should be called after waiting for other helpers' + ); + }; + }); - function fakeAdapterAsyncStart() { - ok(true, 'Async start should be called after waiting for other helpers'); + pauseTest(); } - App.testHelpers.andThen(() => { - Test.adapter.asyncStart = fakeAdapterAsyncStart; - }); - - App.testHelpers.pauseTest(); -}); + [`@test resumeTest resumes paused tests`](assert) { + assert.expect(1); -QUnit.test('resumeTest resumes paused tests', function() { - expect(1); + let {application: {testHelpers: {pauseTest, resumeTest}}} = this; - let pausePromise = App.testHelpers.pauseTest(); - setTimeout(() => App.testHelpers.resumeTest(), 0); + run.later(() => resumeTest(), 20); + return pauseTest().then(() => { + assert.ok(true, 'pauseTest promise was resolved'); + }); + } - return pausePromise.then(() => ok(true, 'pauseTest promise was resolved')); -}); + [`@test resumeTest throws if nothing to resume`](assert) { + assert.expect(1); -QUnit.test('resumeTest throws if nothing to resume', function() { - expect(1); + assert.throws(() => { + this.application.testHelpers.resumeTest(); + }, /Testing has not been paused. There is nothing to resume./); + } - throws(() => App.testHelpers.resumeTest(), /Testing has not been paused. There is nothing to resume./); }); -QUnit.module('ember-testing routing helpers', { - setup() { - run(function() { - App = EmberApplication.create(); +moduleFor('ember-testing: routing helpers', class extends HelpersTestCase { - App.injectTestHelpers(); - - App.Router = Router.extend({ - location: 'none' - }); - - App.Router.map(function() { - this.route('posts', { resetNamespace: true }, function() { + constructor() { + super(); + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); + this.application.injectTestHelpers(); + this.router.map(function() { + this.route('posts', {resetNamespace: true}, function() { this.route('new'); }); }); + }); + this.runTask(() => { + this.application.advanceReadiness(); + }); + } - App.setupForTesting(); + [`@test currentRouteName for '/'`](assert) { + assert.expect(3); + + let {application: {testHelpers}} = this; + return testHelpers.visit('/').then(() => { + assert.equal( + testHelpers.currentRouteName(), 'index', + `should equal 'index'.` + ); + assert.equal( + testHelpers.currentPath(), 'index', + `should equal 'index'.` + ); + assert.equal( + testHelpers.currentURL(), '/', + `should equal '/'.` + ); }); + } - run(App, 'advanceReadiness'); - }, + [`@test currentRouteName for '/posts'`](assert) { + assert.expect(3); + + let {application: {testHelpers}} = this; + return testHelpers.visit('/posts').then(() => { + assert.equal( + testHelpers.currentRouteName(), 'posts.index', + `should equal 'posts.index'.` + ); + assert.equal( + testHelpers.currentPath(), 'posts.index', + `should equal 'posts.index'.` + ); + assert.equal( + testHelpers.currentURL(), '/posts', + `should equal '/posts'.` + ); + }); + } - teardown() { - cleanup(); + [`@test currentRouteName for '/posts/new'`](assert) { + assert.expect(3); + + let {application: {testHelpers}} = this; + return testHelpers.visit('/posts/new').then(() => { + assert.equal( + testHelpers.currentRouteName(), 'posts.new', + `should equal 'posts.new'.` + ); + assert.equal( + testHelpers.currentPath(), 'posts.new', + `should equal 'posts.new'.` + ); + assert.equal( + testHelpers.currentURL(), '/posts/new', + `should equal '/posts/new'.` + ); + }); } + }); -QUnit.test('currentRouteName for \'/\'', function() { - expect(3); +moduleFor('ember-testing: pendingRequests', class extends HelpersApplicationTestCase { - return App.testHelpers.visit('/').then(function() { - equal(App.testHelpers.currentRouteName(), 'index', 'should equal \'index\'.'); - equal(App.testHelpers.currentPath(), 'index', 'should equal \'index\'.'); - equal(App.testHelpers.currentURL(), '/', 'should equal \'/\'.'); - }); -}); + [`@test pendingRequests is maintained for ajaxSend and ajaxComplete events`](assert) { + assert.equal( + pendingRequests(), 0 + ); + let xhr = { some: 'xhr' }; -QUnit.test('currentRouteName for \'/posts\'', function() { - expect(3); + jQuery(document).trigger('ajaxSend', xhr); + assert.equal( + pendingRequests(), 1, + 'Ember.Test.pendingRequests was incremented' + ); - return App.testHelpers.visit('/posts').then(function() { - equal(App.testHelpers.currentRouteName(), 'posts.index', 'should equal \'posts.index\'.'); - equal(App.testHelpers.currentPath(), 'posts.index', 'should equal \'posts.index\'.'); - equal(App.testHelpers.currentURL(), '/posts', 'should equal \'/posts\'.'); - }); -}); + jQuery(document).trigger('ajaxComplete', xhr); + assert.equal( + pendingRequests(), 0, + 'Ember.Test.pendingRequests was decremented' + ); + } -QUnit.test('currentRouteName for \'/posts/new\'', function() { - expect(3); + [`@test pendingRequests is ignores ajaxComplete events from past setupForTesting calls`](assert) { + assert.equal( + pendingRequests(), 0 + ); - return App.testHelpers.visit('/posts/new').then(function() { - equal(App.testHelpers.currentRouteName(), 'posts.new', 'should equal \'posts.new\'.'); - equal(App.testHelpers.currentPath(), 'posts.new', 'should equal \'posts.new\'.'); - equal(App.testHelpers.currentURL(), '/posts/new', 'should equal \'/posts/new\'.'); - }); -}); + let xhr = { some: 'xhr' }; -QUnit.module('ember-testing pendingRequests', { - setup() { - setupApp(); - }, + jQuery(document).trigger('ajaxSend', xhr); + assert.equal( + pendingRequests(), 1, + 'Ember.Test.pendingRequests was incremented' + ); - teardown() { - cleanup(); - } -}); + setupForTesting(); -QUnit.test('pendingRequests is maintained for ajaxSend and ajaxComplete events', function() { - equal(pendingRequests(), 0); - var xhr = { some: 'xhr' }; - jQuery(document).trigger('ajaxSend', xhr); - equal(pendingRequests(), 1, 'Ember.Test.pendingRequests was incremented'); - jQuery(document).trigger('ajaxComplete', xhr); - equal(pendingRequests(), 0, 'Ember.Test.pendingRequests was decremented'); -}); + assert.equal( + pendingRequests(), 0, + 'Ember.Test.pendingRequests was reset' + ); -QUnit.test('pendingRequests is ignores ajaxComplete events from past setupForTesting calls', function() { - equal(pendingRequests(), 0); - var xhr = { some: 'xhr' }; - jQuery(document).trigger('ajaxSend', xhr); - equal(pendingRequests(), 1, 'Ember.Test.pendingRequests was incremented'); + let altXhr = { some: 'more xhr' }; - run(function() { - setupForTesting(); - }); - equal(pendingRequests(), 0, 'Ember.Test.pendingRequests was reset'); - - var altXhr = { some: 'more xhr' }; - jQuery(document).trigger('ajaxSend', altXhr); - equal(pendingRequests(), 1, 'Ember.Test.pendingRequests was incremented'); - jQuery(document).trigger('ajaxComplete', xhr); - equal(pendingRequests(), 1, 'Ember.Test.pendingRequests is not impressed with your unexpected complete'); -}); + jQuery(document).trigger('ajaxSend', altXhr); + assert.equal( + pendingRequests(), 1, + 'Ember.Test.pendingRequests was incremented' + ); + + jQuery(document).trigger('ajaxComplete', xhr); + assert.equal( + pendingRequests(), 1, + 'Ember.Test.pendingRequests is not impressed with your unexpected complete' + ); + } + + [`@test pendingRequests is reset by setupForTesting`](assert) { + incrementPendingRequests(); -QUnit.test('pendingRequests is reset by setupForTesting', function() { - incrementPendingRequests(); - run(function() { setupForTesting(); - }); - equal(pendingRequests(), 0, 'pendingRequests is reset'); + + assert.equal( + pendingRequests(), 0, + 'pendingRequests is reset' + ); + } + }); -QUnit.module('ember-testing async router', { - setup() { - cleanup(); +moduleFor('ember-testing: async router', class extends HelpersTestCase { + constructor() { + super(); - run(function() { - App = EmberApplication.create(); - App.Router = Router.extend({ - location: 'none' - }); + this.runTask(() => { + this.createApplication(); - App.Router.map(function() { + this.router.map(function() { this.route('user', { resetNamespace: true }, function() { this.route('profile'); this.route('edit'); }); }); - App.UserRoute = Route.extend({ + // Emulate a long-running unscheduled async operation. + let resolveLater = () => new RSVP.Promise(resolve => { + /* + * The wait() helper has a 10ms tick. We should resolve() after + * at least one tick to test whether wait() held off while the + * async router was still loading. 20ms should be enough. + */ + run.later(resolve, {firstName: 'Tom'}, 20); + }); + + this.add('route:user', Route.extend({ model() { return resolveLater(); } - }); + })); - App.UserProfileRoute = Route.extend({ + this.add('route:user.profile', Route.extend({ beforeModel() { - var self = this; - return resolveLater().then(function() { - self.transitionTo('user.edit'); - }); + return resolveLater().then(() => this.transitionTo('user.edit')); } - }); - - // Emulates a long-running unscheduled async operation. - function resolveLater() { - var promise; - - run(function() { - promise = new RSVP.Promise(function(resolve) { - // The wait() helper has a 10ms tick. We should resolve() after at least one tick - // to test whether wait() held off while the async router was still loading. 20ms - // should be enough. - setTimeout(function() { - run(function() { - resolve(EmberObject.create({ firstName: 'Tom' })); - }); - }, 20); - }); - }); + })); - return promise; - } - - App.setupForTesting(); + this.application.setupForTesting(); }); - App.injectTestHelpers(); - run(App, 'advanceReadiness'); - }, - - teardown() { - cleanup(); + this.application.injectTestHelpers(); + this.runTask(() => { + this.application.advanceReadiness(); + }); } -}); -QUnit.test('currentRouteName for \'/user\'', function() { - expect(4); - - return App.testHelpers.visit('/user').then(function() { - equal(currentRouteName(App), 'user.index', 'should equal \'user.index\'.'); - equal(currentPath(App), 'user.index', 'should equal \'user.index\'.'); - equal(currentURL(App), '/user', 'should equal \'/user\'.'); - equal(App.__container__.lookup('route:user').get('controller.model.firstName'), 'Tom', 'should equal \'Tom\'.'); - }); -}); + [`@test currentRouteName for '/user'`](assert) { + assert.expect(4); + + let {application: {testHelpers}} = this; + return testHelpers.visit('/user').then(() => { + assert.equal( + testHelpers.currentRouteName(), 'user.index', + `should equal 'user.index'.` + ); + assert.equal( + testHelpers.currentPath(), 'user.index', + `should equal 'user.index'.` + ); + assert.equal( + testHelpers.currentURL(), '/user', + `should equal '/user'.` + ); + let userRoute = this.applicationInstance.lookup('route:user'); + assert.equal( + userRoute.get('controller.model.firstName'), 'Tom', + `should equal 'Tom'.` + ); + }); + } -QUnit.test('currentRouteName for \'/user/profile\'', function() { - expect(4); + [`@test currentRouteName for '/user/profile'`](assert) { + assert.expect(4); + + let {application: {testHelpers}} = this; + return testHelpers.visit('/user/profile').then(() => { + assert.equal( + testHelpers.currentRouteName(), 'user.edit', + `should equal 'user.edit'.` + ); + assert.equal( + testHelpers.currentPath(), 'user.edit', + `should equal 'user.edit'.` + ); + assert.equal( + testHelpers.currentURL(), '/user/edit', + `should equal '/user/edit'.` + ); + let userRoute = this.applicationInstance.lookup('route:user'); + assert.equal( + userRoute.get('controller.model.firstName'), 'Tom', + `should equal 'Tom'.` + ); + }); + } - return App.testHelpers.visit('/user/profile').then(function() { - equal(currentRouteName(App), 'user.edit', 'should equal \'user.edit\'.'); - equal(currentPath(App), 'user.edit', 'should equal \'user.edit\'.'); - equal(currentURL(App), '/user/edit', 'should equal \'/user/edit\'.'); - equal(App.__container__.lookup('route:user').get('controller.model.firstName'), 'Tom', 'should equal \'Tom\'.'); - }); }); -var originalVisitHelper, originalFindHelper, originalWaitHelper; +moduleFor('ember-testing: can override built-in helpers', class extends HelpersTestCase { -QUnit.module('can override built-in helpers', { - setup() { - originalVisitHelper = Test._helpers.visit; - originalFindHelper = Test._helpers.find; - originalWaitHelper = Test._helpers.wait; - - jQuery('').appendTo('head'); - jQuery('
').appendTo('body'); - run(function() { - App = EmberApplication.create({ - rootElement: '#ember-testing' - }); - - App.setupForTesting(); + constructor() { + super(); + this.runTask(() => { + this.createApplication(); + this.application.setupForTesting(); }); - }, + this._originalVisitHelper = Test._helpers.visit; + this._originalFindHelper = Test._helpers.find; + } teardown() { - cleanup(); - - Test._helpers.visit = originalVisitHelper; - Test._helpers.find = originalFindHelper; - Test._helpers.wait = originalWaitHelper; + Test._helpers.visit = this._originalVisitHelper; + Test._helpers.find = this._originalFindHelper; + super.teardown(); } -}); -QUnit.test('can override visit helper', function() { - expect(1); + [`@test can override visit helper`](assert) { + assert.expect(1); - Test.registerHelper('visit', function() { - ok(true, 'custom visit helper was called'); - }); + Test.registerHelper('visit', () => { + assert.ok(true, 'custom visit helper was called'); + }); - App.injectTestHelpers(); + this.application.injectTestHelpers(); - return App.testHelpers.visit(); -}); + return this.application.testHelpers.visit(); + } + + [`@test can override find helper`](assert) { + assert.expect(1); -QUnit.test('can override find helper', function() { - expect(1); + Test.registerHelper('find', () => { + assert.ok(true, 'custom find helper was called'); - Test.registerHelper('find', function() { - ok(true, 'custom find helper was called'); + return ['not empty array']; + }); - return ['not empty array']; - }); + this.application.injectTestHelpers(); - App.injectTestHelpers(); + return this.application.testHelpers.findWithAssert('.who-cares'); + } - return App.testHelpers.findWithAssert('.who-cares'); }); From 73d47338a175df1334a978ff756b7d06dac0ba3a Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Sat, 10 Jun 2017 12:02:04 -0700 Subject: [PATCH 031/224] Some test cleanup --- .../tests/system/application_test.js | 12 ++++++------ .../lib/test-cases/abstract-application.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/ember-application/tests/system/application_test.js b/packages/ember-application/tests/system/application_test.js index 66b3d72e8d8..b4f63a4eb4f 100644 --- a/packages/ember-application/tests/system/application_test.js +++ b/packages/ember-application/tests/system/application_test.js @@ -60,7 +60,7 @@ moduleFor('Ember.Application, autobooting multiple apps', class extends Applicat }); } - buildSecondApplication(options) { + createSecondApplication(options) { let myOptions = assign(this.applicationOptions, options); return this.secondApp = Application.create(myOptions); } @@ -74,7 +74,7 @@ moduleFor('Ember.Application, autobooting multiple apps', class extends Applicat } [`@test you can make a new application in a non-overlapping element`](assert) { - let app = run(() => this.buildSecondApplication({ + let app = run(() => this.createSecondApplication({ rootElement: '#two' })); @@ -84,7 +84,7 @@ moduleFor('Ember.Application, autobooting multiple apps', class extends Applicat [`@test you cannot make a new application that is a parent of an existing application`]() { expectAssertion(() => { - run(() => this.buildSecondApplication({ + run(() => this.createSecondApplication({ rootElement: '#qunit-fixture' })); }); @@ -92,7 +92,7 @@ moduleFor('Ember.Application, autobooting multiple apps', class extends Applicat [`@test you cannot make a new application that is a descendant of an existing application`]() { expectAssertion(() => { - run(() => this.buildSecondApplication({ + run(() => this.createSecondApplication({ rootElement: '#one-child' })); }); @@ -100,7 +100,7 @@ moduleFor('Ember.Application, autobooting multiple apps', class extends Applicat [`@test you cannot make a new application that is a duplicate of an existing application`]() { expectAssertion(() => { - run(() => this.buildSecondApplication({ + run(() => this.createSecondApplication({ rootElement: '#one' })); }); @@ -108,7 +108,7 @@ moduleFor('Ember.Application, autobooting multiple apps', class extends Applicat [`@test you cannot make two default applications without a rootElement error`]() { expectAssertion(() => { - run(() => this.buildSecondApplication()); + run(() => this.createSecondApplication()); }); } }); diff --git a/packages/internal-test-helpers/lib/test-cases/abstract-application.js b/packages/internal-test-helpers/lib/test-cases/abstract-application.js index 897d958dea2..5e2b519bf97 100644 --- a/packages/internal-test-helpers/lib/test-cases/abstract-application.js +++ b/packages/internal-test-helpers/lib/test-cases/abstract-application.js @@ -15,7 +15,7 @@ export default class AbstractApplicationTestCase extends AbstractTestCase { this.element = jQuery('#qunit-fixture')[0]; let { applicationOptions } = this; - this.application = run(Application, 'create', applicationOptions); + this.application = this.runTask(() => Application.create(applicationOptions)); this.resolver = applicationOptions.Resolver.lastInstance; From 57589cfcc4beede6f88316ff667915e30aaacf95 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Sat, 10 Jun 2017 12:02:28 -0700 Subject: [PATCH 032/224] Decouple multiple-test-app from globals --- .../tests/integration/multiple-app-test.js | 119 +++++++++++------- 1 file changed, 72 insertions(+), 47 deletions(-) diff --git a/packages/ember/tests/integration/multiple-app-test.js b/packages/ember/tests/integration/multiple-app-test.js index 28022b3053d..a0e19125b03 100644 --- a/packages/ember/tests/integration/multiple-app-test.js +++ b/packages/ember/tests/integration/multiple-app-test.js @@ -1,70 +1,95 @@ -import { run } from 'ember-metal'; -import { compile } from 'ember-template-compiler'; +import { + moduleFor, + ApplicationTestCase +} from 'internal-test-helpers'; import { Application } from 'ember-application'; import { Component } from 'ember-glimmer'; import { jQuery } from 'ember-views'; +import { assign, getOwner } from 'ember-utils'; -let App1, App2, actions; +moduleFor('View Integration', class extends ApplicationTestCase { -function startApp(rootElement) { - let application; - - run(() => { - application = Application.create({ - rootElement + constructor() { + jQuery('#qunit-fixture').html(` +
+
+ `); + super(); + this.runTask(() => { + this.createSecondApplication(); }); - application.deferReadiness(); + } - application.Router.reopen({ - location: 'none' + get applicationOptions() { + return assign(super.applicationOptions, { + rootElement: '#one', + router: null }); + } - let registry = application.__registry__; + createSecondApplication(options) { + let {applicationOptions} = this; + let secondApplicationOptions = {rootElement: '#two'}; + let myOptions = assign(applicationOptions, secondApplicationOptions, options); + this.secondApp = Application.create(myOptions); + this.secondResolver = myOptions.Resolver.lastInstance; + return this.secondApp; + } - registry.register('component:special-button', Component.extend({ + teardown() { + super.teardown(); + + if (this.secondApp) { + this.runTask(() => { + this.secondApp.destroy(); + }); + } + } + + addFactoriesToResolver(actions, resolver) { + resolver.add('component:special-button', Component.extend({ actions: { doStuff() { + let rootElement = getOwner(this).application.rootElement; actions.push(rootElement); } } })); - registry.register('template:application', compile('{{outlet}}', { moduleName: 'application' })); - registry.register('template:index', compile('

Node 1

{{special-button}}', { moduleName: 'index' })); - registry.register('template:components/special-button', compile('', { moduleName: 'components/special-button' })); - }); - - return application; -} -function handleURL(application, path) { - let router = application.__container__.lookup('router:main'); - return run(router, 'handleURL', path); -} - -QUnit.module('View Integration', { - setup() { - actions = []; - jQuery('#qunit-fixture').html('
'); - App1 = startApp('#app-1'); - App2 = startApp('#app-2'); - }, - - teardown() { - run(App1, 'destroy'); - run(App2, 'destroy'); - App1 = App2 = null; + resolver.add( + 'template:index', + this.compile(` +

Node 1

{{special-button}} + `, { + moduleName: 'index' + }) + ); + resolver.add( + 'template:components/special-button', + this.compile(` + + `, { + moduleName: 'components/special-button' + }) + ); } -}); -QUnit.test('booting multiple applications can properly handle events', function(assert) { - run(App1, 'advanceReadiness'); - run(App2, 'advanceReadiness'); + [`@test booting multiple applications can properly handle events`](assert) { + let actions = []; + this.addFactoriesToResolver(actions, this.resolver); + this.addFactoriesToResolver(actions, this.secondResolver); - handleURL(App1, '/'); - handleURL(App2, '/'); + this.runTask(() => { + this.secondApp.visit('/'); + }); + this.runTask(() => { + this.application.visit('/'); + }); - jQuery('#app-2 .do-stuff').click(); - jQuery('#app-1 .do-stuff').click(); + jQuery('#two .do-stuff').click(); + jQuery('#one .do-stuff').click(); + + assert.deepEqual(actions, ['#two', '#one']); + } - assert.deepEqual(actions, ['#app-2', '#app-1']); }); From 6a74d26cb2188a17eac1e3e20b5bb2d9fc48af22 Mon Sep 17 00:00:00 2001 From: patsy-issa Date: Sat, 10 Jun 2017 23:17:37 +0200 Subject: [PATCH 033/224] [PERF] Updated babel block-scoping config Fixes #15233 --- broccoli/to-es5.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/broccoli/to-es5.js b/broccoli/to-es5.js index d921da76abe..be04f6e7e3e 100644 --- a/broccoli/to-es5.js +++ b/broccoli/to-es5.js @@ -43,7 +43,7 @@ module.exports = function toES5(tree, _options) { ['transform-es2015-parameters'], ['transform-es2015-computed-properties', {loose: true}], ['transform-es2015-shorthand-properties'], - ['transform-es2015-block-scoping'], + ['transform-es2015-block-scoping', { 'throwIfClosureRequired': true }], ['check-es2015-constants'], ['transform-es2015-classes', { loose: true }], ['transform-proto-to-assign'], From 490028d6de81adca0a523e82d3e5184be9609f70 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 11 Jun 2017 18:04:11 -0400 Subject: [PATCH 034/224] Remove unused `has` import. --- packages/ember-metal/lib/meta.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 0e7167c8a37..209f8677b74 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -15,7 +15,6 @@ import { import { removeChainWatcher } from './chains'; -import { has } from 'require'; let counters; if (DEBUG) { From 594336397429e37ae04059305d23aa21f45921dd Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 11 Jun 2017 18:04:20 -0400 Subject: [PATCH 035/224] Remove `readInheritedValue` and `writeValue`. These methods are added when `MANDATORY_SETTER` is enabled, which means they are stripped from production builds (after this change). --- packages/ember-metal/lib/meta.js | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 209f8677b74..82486b6f1ed 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -283,36 +283,6 @@ export class Meta { } } - readInheritedValue(key, subkey) { - let internalKey = `_${key}`; - - let pointer = this; - - while (pointer !== undefined) { - let map = pointer[internalKey]; - if (map !== undefined) { - let value = map[subkey]; - if (value !== undefined || subkey in map) { - return value; - } - } - pointer = pointer.parent; - } - - return UNDEFINED; - } - - writeValue(obj, key, value) { - let descriptor = lookupDescriptor(obj, key); - let isMandatorySetter = descriptor !== undefined && descriptor.set && descriptor.set.isMandatorySetter; - - if (isMandatorySetter) { - this.writeValues(key, value); - } else { - obj[key] = value; - } - } - set factory(factory) { this._factory = factory; } From e5f9748cc9598854395f967858af5ef379b0cc8b Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 11 Jun 2017 18:22:22 -0400 Subject: [PATCH 036/224] Remove unused Meta methods. These methods have existed since we started with the current meta system, but they were added via meta-programming (which meant that all of the similar types of things ended up with all of the methods). Now that the meta-programming is unrolled, these methods are not used any longer. --- packages/ember-metal/lib/meta.js | 83 ------------------- .../tests/accessors/mandatory_setters_test.js | 2 +- packages/ember-metal/tests/meta_test.js | 12 --- 3 files changed, 1 insertion(+), 96 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 82486b6f1ed..709beec78d5 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -353,38 +353,6 @@ export class Meta { return this._findInherited('_watching', subkey); } - forEachWatching(fn) { - let pointer = this; - let seen; - while (pointer !== undefined) { - let map = pointer._watching; - if (map !== undefined) { - for (let key in map) { - seen = seen || Object.create(null); - if (seen[key] === undefined) { - seen[key] = true; - fn(key, map[key]); - } - } - } - pointer = pointer.parent; - } - } - - clearWatching() { - assert(`Cannot clear watchers on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); - - this._watching = undefined; - } - - deleteFromWatching(subkey) { - delete this._getOrCreateOwnMap('_watching')[subkey]; - } - - hasInWatching(subkey) { - return this._findInherited('_watching', subkey) !== undefined; - } - writeMixins(subkey, value) { assert(`Cannot add mixins for \`${subkey}\` on \`${toString(this.source)}\` call writeMixins after it has been destroyed.`, !this.isMetaDestroyed()); let map = this._getOrCreateOwnMap('_mixins'); @@ -413,20 +381,6 @@ export class Meta { } } - clearMixins() { - assert(`Cannot clear mixins on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); - - this._mixins = undefined; - } - - deleteFromMixins(subkey) { - delete this._getOrCreateOwnMap('_mixins')[subkey]; - } - - hasInMixins(subkey) { - return this._findInherited('_mixins', subkey) !== undefined; - } - writeBindings(subkey, value) { assert(`Cannot add a binding for \`${subkey}\` on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); @@ -461,14 +415,6 @@ export class Meta { this._bindings = undefined; } - deleteFromBindings(subkey) { - delete this._getOrCreateOwnMap('_bindings')[subkey]; - } - - hasInBindings(subkey) { - return this._findInherited('_bindings', subkey) !== undefined; - } - writeValues(subkey, value) { assert(`Cannot set the value of \`${subkey}\` on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); @@ -480,38 +426,9 @@ export class Meta { return this._findInherited('_values', subkey); } - forEachValues(fn) { - let pointer = this; - let seen; - while (pointer !== undefined) { - let map = pointer._values; - if (map !== undefined) { - for (let key in map) { - seen = seen || Object.create(null); - if (seen[key] === undefined) { - seen[key] = true; - fn(key, map[key]); - } - } - } - pointer = pointer.parent; - } - } - - clearValues() { - assert(`Cannot call clearValues after the object is destroyed.`, !this.isMetaDestroyed()); - - this._values = undefined; - } - deleteFromValues(subkey) { delete this._getOrCreateOwnMap('_values')[subkey]; } - - hasInValues(subkey) { - return this._findInherited('_values', subkey) !== undefined; - } - } if (EMBER_GLIMMER_DETECT_BACKTRACKING_RERENDER || EMBER_GLIMMER_ALLOW_BACKTRACKING_RERENDER) { diff --git a/packages/ember-metal/tests/accessors/mandatory_setters_test.js b/packages/ember-metal/tests/accessors/mandatory_setters_test.js index 5f717cb66b6..2cd22e8360e 100644 --- a/packages/ember-metal/tests/accessors/mandatory_setters_test.js +++ b/packages/ember-metal/tests/accessors/mandatory_setters_test.js @@ -18,7 +18,7 @@ function hasMandatorySetter(object, property) { } function hasMetaValue(object, property) { - return metaFor(object).hasInValues(property); + return metaFor(object).peekValues(property) !== undefined; } if (MANDATORY_SETTER) { diff --git a/packages/ember-metal/tests/meta_test.js b/packages/ember-metal/tests/meta_test.js index c31c7fd5ebf..dc7c6b4c010 100644 --- a/packages/ember-metal/tests/meta_test.js +++ b/packages/ember-metal/tests/meta_test.js @@ -89,18 +89,6 @@ QUnit.test('meta.writeWatching issues useful error after destroy', function(asse }, 'Cannot update watchers for `hello` on `` after it has been destroyed.'); }); -QUnit.test('meta.clearWatching issues useful error after destroy', function(assert) { - let target = { - toString() { return ''; } - }; - let targetMeta = meta(target); - - targetMeta.destroy(); - - expectAssertion(() => { - targetMeta.clearWatching(); - }, 'Cannot clear watchers on `` after it has been destroyed.'); -}); QUnit.test('meta.writableTag issues useful error after destroy', function(assert) { let target = { toString() { return ''; } From 7ad22bf78ce371d7ed0c36cfb30f1241c0fae2ee Mon Sep 17 00:00:00 2001 From: Kelly Selden Date: Mon, 12 Jun 2017 09:50:38 -0700 Subject: [PATCH 037/224] remove template blueprint newlines --- .../__templatepath__/__templatename__.hbs | 2 +- .../__templatepath__/__templatename__.hbs | 2 +- node-tests/blueprints/component-test.js | 56 +++++++++---------- node-tests/blueprints/route-test.js | 26 ++++----- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/blueprints/component/files/__root__/__templatepath__/__templatename__.hbs b/blueprints/component/files/__root__/__templatepath__/__templatename__.hbs index 889d9eeadc1..fb5c4b157d1 100644 --- a/blueprints/component/files/__root__/__templatepath__/__templatename__.hbs +++ b/blueprints/component/files/__root__/__templatepath__/__templatename__.hbs @@ -1 +1 @@ -{{yield}} +{{yield}} \ No newline at end of file diff --git a/blueprints/route/files/__root__/__templatepath__/__templatename__.hbs b/blueprints/route/files/__root__/__templatepath__/__templatename__.hbs index c24cd68950a..e2147cab02d 100644 --- a/blueprints/route/files/__root__/__templatepath__/__templatename__.hbs +++ b/blueprints/route/files/__root__/__templatepath__/__templatename__.hbs @@ -1 +1 @@ -{{outlet}} +{{outlet}} \ No newline at end of file diff --git a/node-tests/blueprints/component-test.js b/node-tests/blueprints/component-test.js index 3ec33a4556e..7838bf5e8c7 100644 --- a/node-tests/blueprints/component-test.js +++ b/node-tests/blueprints/component-test.js @@ -27,7 +27,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/templates/components/x-foo.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/components/x-foo-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -50,7 +50,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/templates/components/foo/x-foo.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/components/foo/x-foo-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -73,7 +73,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/templates/components/x-foo.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/components/x-foo-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -98,7 +98,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('addon/templates/components/x-foo.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('app/components/x-foo.js')) .to.contain("export { default } from 'my-addon/components/x-foo';"); @@ -126,7 +126,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('addon/templates/components/nested/x-foo.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('app/components/nested/x-foo.js')) .to.contain("export { default } from 'my-addon/components/nested/x-foo';"); @@ -152,7 +152,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('tests/dummy/app/templates/components/x-foo.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('app/components/x-foo.js')) .to.not.exist; @@ -173,7 +173,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('tests/dummy/app/templates/components/nested/x-foo.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('app/components/nested/x-foo.js')) .to.not.exist; @@ -196,7 +196,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('lib/my-addon/addon/templates/components/x-foo.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('lib/my-addon/app/components/x-foo.js')) .to.contain("export { default } from 'my-addon/components/x-foo';"); @@ -251,7 +251,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('lib/my-addon/addon/templates/components/nested/x-foo.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('lib/my-addon/app/components/nested/x-foo.js')) .to.contain("export { default } from 'my-addon/components/nested/x-foo';"); @@ -278,7 +278,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/components/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/components/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -300,7 +300,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/pods/components/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/pods/components/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -323,7 +323,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/components/foo/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/components/foo/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -347,7 +347,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/pods/components/foo/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/pods/components/foo/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -370,7 +370,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/bar/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/bar/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -394,7 +394,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/pods/bar/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/pods/bar/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -417,7 +417,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/bar/foo/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/bar/foo/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -441,7 +441,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/pods/bar/foo/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/pods/bar/foo/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -463,7 +463,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/bar/baz/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/bar/baz/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -487,7 +487,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/pods/bar/baz/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/pods/bar/baz/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -510,7 +510,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/bar/baz/foo/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/bar/baz/foo/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -534,7 +534,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/pods/bar/baz/foo/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/pods/bar/baz/foo/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -557,7 +557,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -581,7 +581,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/pods/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/pods/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -604,7 +604,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/foo/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/foo/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -628,7 +628,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('app/pods/foo/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('tests/integration/pods/foo/x-foo/component-test.js')) .to.contain("import { moduleForComponent, test } from 'ember-qunit';") @@ -653,7 +653,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('addon/components/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('app/components/x-foo/component.js')) .to.contain("export { default } from 'my-addon/components/x-foo/component';"); @@ -678,7 +678,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('lib/my-addon/addon/components/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('lib/my-addon/app/components/x-foo/component.js')) .to.contain("export { default } from 'my-addon/components/x-foo/component';"); @@ -703,7 +703,7 @@ describe('Acceptance: ember generate component', function() { .to.contain("});"); expect(_file('lib/my-addon/addon/components/nested/x-foo/template.hbs')) - .to.contain("{{yield}}"); + .to.equal("{{yield}}"); expect(_file('lib/my-addon/app/components/nested/x-foo/component.js')) .to.contain("export { default } from 'my-addon/components/nested/x-foo/component';"); diff --git a/node-tests/blueprints/route-test.js b/node-tests/blueprints/route-test.js index 81b5e462ede..d4cf086e784 100644 --- a/node-tests/blueprints/route-test.js +++ b/node-tests/blueprints/route-test.js @@ -33,7 +33,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('app/templates/foo.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('tests/unit/routes/foo-test.js')) .to.contain('import { moduleFor, test } from \'ember-qunit\';') @@ -69,7 +69,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('app/templates/foo.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('tests/unit/routes/foo-test.js')) .to.contain('import { moduleFor, test } from \'ember-qunit\';') @@ -95,7 +95,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('app/templates/child.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('tests/unit/routes/child-test.js')) .to.contain('import { moduleFor, test } from \'ember-qunit\';') @@ -119,7 +119,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('app/child/template.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('tests/unit/child/route-test.js')) .to.contain('import { moduleFor, test } from \'ember-qunit\';') @@ -176,7 +176,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('addon/templates/foo.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('app/routes/foo.js')) .to.contain('export { default } from \'my-addon/routes/foo\';'); @@ -205,7 +205,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('addon/templates/foo/bar.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('app/routes/foo/bar.js')) .to.contain('export { default } from \'my-addon/routes/foo/bar\';'); @@ -234,7 +234,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('tests/dummy/app/templates/foo.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('app/routes/foo.js')).to.not.exist; expect(_file('app/templates/foo.hbs')).to.not.exist; @@ -257,7 +257,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('tests/dummy/app/templates/foo/bar.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('app/routes/foo/bar.js')).to.not.exist; expect(_file('app/templates/foo/bar.hbs')).to.not.exist; @@ -281,7 +281,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('lib/my-addon/addon/templates/foo.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('lib/my-addon/app/routes/foo.js')) .to.contain('export { default } from \'my-addon/routes/foo\';'); @@ -305,7 +305,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('lib/my-addon/addon/templates/foo/bar.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('lib/my-addon/app/routes/foo/bar.js')) .to.contain('export { default } from \'my-addon/routes/foo/bar\';'); @@ -329,7 +329,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('app/foo/template.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('tests/unit/foo/route-test.js')) .to.contain('import { moduleFor, test } from \'ember-qunit\';') @@ -369,7 +369,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('app/pods/foo/template.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('tests/unit/pods/foo/route-test.js')) .to.contain('import { moduleFor, test } from \'ember-qunit\';') @@ -423,7 +423,7 @@ describe('Acceptance: ember generate and destroy route', function() { .to.contain('export default Ember.Route.extend({\n});'); expect(_file('addon/foo/template.hbs')) - .to.contain('{{outlet}}'); + .to.equal('{{outlet}}'); expect(_file('app/foo/route.js')) .to.contain('export { default } from \'my-addon/foo/route\';'); From 6899ef4799b921c30ca1c6ff8a1011a4ba821cd9 Mon Sep 17 00:00:00 2001 From: Kelly Selden Date: Mon, 12 Jun 2017 13:02:41 -0700 Subject: [PATCH 038/224] sync .editorconfig with default new app --- .editorconfig | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9099689136d..b63ef4c3130 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,9 +3,15 @@ root = true [*] +end_of_line = lf charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true indent_style = space indent_size = 2 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true + +[*.hbs] +insert_final_newline = false + +[*.{diff,md}] +trim_trailing_whitespace = false From b89abc15ca085577bba4433c59ed00553d8a6bde Mon Sep 17 00:00:00 2001 From: Patrick Robertson Date: Tue, 13 Jun 2017 10:32:57 -0400 Subject: [PATCH 039/224] [DOC release] replace lingering NPM commands. Part of the contributing guide tells you to use yarn, part NPM. I suspect we want to use yarn all the way down. --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50d22f0e1be..a1068e4afda 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -116,7 +116,7 @@ Pull requests should pass the Ember.js unit tests. Do the following to run these 1. Follow the setup steps listed above under [Building Ember.js](#building-emberjs). -2. To start the development server, run `npm start`. +2. To start the development server, run `yarn start`. 3. To run all tests, visit . @@ -137,7 +137,7 @@ versions of jQuery. 1. Install phantomjs from http://phantomjs.org. -2. Run `npm test` to run a basic test suite or run `TEST_SUITE=all npm test` to +2. Run `yarn test` to run a basic test suite or run `TEST_SUITE=all yarn test` to run a more comprehensive suite. ## From ember-cli From 12c18e209c088fed758493a232866f152db45f24 Mon Sep 17 00:00:00 2001 From: Patrick Robertson Date: Tue, 13 Jun 2017 14:30:42 -0400 Subject: [PATCH 040/224] Decouple component context tests from global resolver. This extracts the Application Lifecycle - Component Context tests from the component registration tests and then rewrites them to use the TestModuleResolver. side note: I have no idea what I'm doing here. --- .../ember/tests/component_context_test.js | 190 ++++++++++++++++++ .../tests/component_registration_test.js | 160 +-------------- 2 files changed, 191 insertions(+), 159 deletions(-) create mode 100644 packages/ember/tests/component_context_test.js diff --git a/packages/ember/tests/component_context_test.js b/packages/ember/tests/component_context_test.js new file mode 100644 index 00000000000..6f1e3174d2b --- /dev/null +++ b/packages/ember/tests/component_context_test.js @@ -0,0 +1,190 @@ +import { Controller } from 'ember-runtime'; +import { Component } from 'ember-glimmer'; +import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; + +moduleFor('Application Lifecycle - Component Context', class extends ApplicationTestCase { + ['@test Components with a block should have the proper content when a template is provided'](assert) { + this.addTemplate('application', ` +
+ {{#my-component}}{{text}}{{/my-component}} +
+ `); + + this.add('controller:application', Controller.extend({ + 'text': 'outer' + })); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + text: 'inner' + }), + template: `{{text}}-{{yield}}` + }); + + this.visit('/').then(() => { + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'inner-outer', 'The component is composed correctly'); + }); + } + + ['@test Components with a block should yield the proper content without a template provided'](assert) { + this.addTemplate('application', ` +
+ {{#my-component}}{{text}}{{/my-component}} +
+ `); + + this.add('controller:application', Controller.extend({ + 'text': 'outer' + })); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + text: 'inner' + }) + }); + + this.visit('/').then(() => { + let text = this.$('#wrapper').text().trim() + assert.equal(text, 'outer', 'The component is composed correctly'); + }); + } + ['@test Components without a block should have the proper content when a template is provided'](assert) { + this.addTemplate('application', ` +
{{my-component}}
+ `); + + this.add('controller:application', Controller.extend({ + 'text': 'outer' + })); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + text: 'inner' + }), + template: '{{text}}' + }); + + this.visit('/').then(() => { + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'inner', 'The component is composed correctly'); + }); + } + + ['@test Components without a block should have the proper content'](assert) { + this.addTemplate('application', ` +
{{my-component}}
+ `); + + this.add('controller:application', Controller.extend({ + 'text': 'outer' + })); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + didInsertElement() { + this.$().html('Some text inserted by jQuery'); + } + }) + }); + + this.visit('/').then(() => { + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'Some text inserted by jQuery', 'The component is composed correctly'); + }); + } + + ['@test properties of a component without a template should not collide with internal structures [DEPRECATED]'](assert) { + this.addTemplate('application', ` +
{{my-component data=foo}}
` + ); + + this.add('controller:application', Controller.extend({ + 'text': 'outer', + 'foo': 'Some text inserted by jQuery' + })); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + didInsertElement() { + this.$().html(this.get('data')); + } + }) + }); + + this.visit('/').then(() => { + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'Some text inserted by jQuery', 'The component is composed correctly'); + }); + } + + ['@test attrs property of a component without a template should not collide with internal structures'](assert) { + this.addTemplate('application', ` +
{{my-component attrs=foo}}
+ `); + + this.add('controller:application', Controller.extend({ + 'text': 'outer', + 'foo': 'Some text inserted by jQuery' + })); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + didInsertElement() { + // FIXME: I'm unsure if this is even the right way to access attrs + this.$().html(this.get('attrs.attrs.value')); + } + }) + }); + + this.visit('/').then(() => { + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'Some text inserted by jQuery', 'The component is composed correctly'); + }); + } + + ['@test Components trigger actions in the parents context when called from within a block'](assert) { + this.addTemplate('application', ` +
+ {{#my-component}} + Fizzbuzz + {{/my-component}} +
+ `); + + this.add('controller:application', Controller.extend({ + actions: { + fizzbuzz() { + ok(true, 'action triggered on parent'); + } + } + })); + this.addComponent('my-component', { ComponentClass: Component.extend({}) }); + + this.visit('/').then(() => { + this.$('#fizzbuzz', '#wrapper').click(); + }); + } + + ['@test Components trigger actions in the components context when called from within its template'](assert) { + this.addTemplate('application', ` +
{{#my-component}}{{text}}{{/my-component}}
+ `); + + this.add('controller:application', Controller.extend({ + actions: { + fizzbuzz() { + ok(false, 'action on the wrong context'); + } + } + })); + this.addComponent('my-component', { + ComponentClass: Component.extend({ + actions: { + fizzbuzz() { + ok(true, 'action triggered on component'); + } + } + }), + template: `Fizzbuzz` + }); + + this.visit('/').then(() => { + this.$('#fizzbuzz', '#wrapper').click(); + }); + } +}); diff --git a/packages/ember/tests/component_registration_test.js b/packages/ember/tests/component_registration_test.js index d411446fef6..a315d57ac39 100644 --- a/packages/ember/tests/component_registration_test.js +++ b/packages/ember/tests/component_registration_test.js @@ -197,162 +197,4 @@ QUnit.test('Using name of component that does not exist', function () { setTemplate('application', compile('
{{#no-good}} {{/no-good}}
')); expectAssertion(() => boot(), /.* named "no-good" .*/); -}); - -QUnit.module('Application Lifecycle - Component Context', { - setup: prepare, - teardown: cleanup -}); - -QUnit.test('Components with a block should have the proper content when a template is provided', function() { - setTemplate('application', compile('
{{#my-component}}{{text}}{{/my-component}}
')); - setTemplate('components/my-component', compile('{{text}}-{{yield}}')); - - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer' - })); - - appInstance.register('component:my-component', Component.extend({ - text: 'inner' - })); - }); - - equal(jQuery('#wrapper').text(), 'inner-outer', 'The component is composed correctly'); -}); - -QUnit.test('Components with a block should yield the proper content without a template provided', function() { - setTemplate('application', compile('
{{#my-component}}{{text}}{{/my-component}}
')); - - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer' - })); - - appInstance.register('component:my-component', Component.extend({ - text: 'inner' - })); - }); - - equal(jQuery('#wrapper').text(), 'outer', 'The component is composed correctly'); -}); - -QUnit.test('Components without a block should have the proper content when a template is provided', function() { - setTemplate('application', compile('
{{my-component}}
')); - setTemplate('components/my-component', compile('{{text}}')); - - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer' - })); - - appInstance.register('component:my-component', Component.extend({ - text: 'inner' - })); - }); - - equal(jQuery('#wrapper').text(), 'inner', 'The component is composed correctly'); -}); - -QUnit.test('Components without a block should have the proper content', function() { - setTemplate('application', compile('
{{my-component}}
')); - - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer' - })); - - appInstance.register('component:my-component', Component.extend({ - didInsertElement() { - this.$().html('Some text inserted by jQuery'); - } - })); - }); - - equal(jQuery('#wrapper').text(), 'Some text inserted by jQuery', 'The component is composed correctly'); -}); - -// The test following this one is the non-deprecated version -QUnit.test('properties of a component without a template should not collide with internal structures [DEPRECATED]', function() { - setTemplate('application', compile('
{{my-component data=foo}}
')); - - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer', - 'foo': 'Some text inserted by jQuery' - })); - - appInstance.register('component:my-component', Component.extend({ - didInsertElement() { - this.$().html(this.get('data')); - } - })); - }); - - equal(jQuery('#wrapper').text(), 'Some text inserted by jQuery', 'The component is composed correctly'); -}); - -QUnit.test('attrs property of a component without a template should not collide with internal structures', function() { - setTemplate('application', compile('
{{my-component attrs=foo}}
')); - - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer', - 'foo': 'Some text inserted by jQuery' - })); - - appInstance.register('component:my-component', Component.extend({ - didInsertElement() { - // FIXME: I'm unsure if this is even the right way to access attrs - this.$().html(this.get('attrs.attrs.value')); - } - })); - }); - - equal(jQuery('#wrapper').text(), 'Some text inserted by jQuery', 'The component is composed correctly'); -}); - -QUnit.test('Components trigger actions in the parents context when called from within a block', function() { - setTemplate('application', compile('
{{#my-component}}Fizzbuzz{{/my-component}}
')); - - boot(() => { - appInstance.register('controller:application', Controller.extend({ - actions: { - fizzbuzz() { - ok(true, 'action triggered on parent'); - } - } - })); - - appInstance.register('component:my-component', Component.extend()); - }); - - run(() => { - jQuery('#fizzbuzz', '#wrapper').click(); - }); -}); - -QUnit.test('Components trigger actions in the components context when called from within its template', function() { - setTemplate('application', compile('
{{#my-component}}{{text}}{{/my-component}}
')); - setTemplate('components/my-component', compile('Fizzbuzz')); - - boot(() => { - appInstance.register('controller:application', Controller.extend({ - actions: { - fizzbuzz() { - ok(false, 'action triggered on the wrong context'); - } - } - })); - - appInstance.register('component:my-component', Component.extend({ - actions: { - fizzbuzz() { - ok(true, 'action triggered on component'); - } - } - })); - }); - - jQuery('#fizzbuzz', '#wrapper').click(); -}); +}); \ No newline at end of file From e152bcb7006e88d7c0cd82f6a1c096cdeaa6c6c6 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Wed, 14 Jun 2017 10:10:36 -0700 Subject: [PATCH 041/224] [CLEANUP] Don't pass unused arguments to hooks Also remove the `dispatchLifecycleHook` indirection since it doesn't do anything useful anymore. --- packages/ember-glimmer/lib/component-managers/curly.js | 9 +++------ packages/ember-views/lib/index.js | 2 +- packages/ember-views/lib/mixins/view_support.js | 9 +++------ 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/packages/ember-glimmer/lib/component-managers/curly.js b/packages/ember-glimmer/lib/component-managers/curly.js index 49571c37fcd..4294fdc35b6 100644 --- a/packages/ember-glimmer/lib/component-managers/curly.js +++ b/packages/ember-glimmer/lib/component-managers/curly.js @@ -25,10 +25,7 @@ import { _instrumentStart } from 'ember-metal'; import { processComponentArgs } from '../utils/process-args'; -import { - dispatchLifeCycleHook, - setViewElement -} from 'ember-views'; +import { setViewElement } from 'ember-views'; import { privatize as P } from 'container'; import AbstractManager from './abstract'; import ComponentStateBucket from '../utils/curly-component-state-bucket'; @@ -324,8 +321,8 @@ export default class CurlyComponentManager extends AbstractManager { component.setProperties(props); component[IS_DISPATCHING_ATTRS] = false; - dispatchLifeCycleHook(component, 'didUpdateAttrs'); - dispatchLifeCycleHook(component, 'didReceiveAttrs'); + component.trigger('didUpdateAttrs'); + component.trigger('didReceiveAttrs'); } if (environment.isInteractive) { diff --git a/packages/ember-views/lib/index.js b/packages/ember-views/lib/index.js index 5862ff5625e..95423aac8af 100644 --- a/packages/ember-views/lib/index.js +++ b/packages/ember-views/lib/index.js @@ -23,7 +23,7 @@ export { default as CoreView } from './views/core_view'; export { default as ClassNamesSupport } from './mixins/class_names_support'; export { default as ChildViewsSupport } from './mixins/child_views_support'; export { default as ViewStateSupport } from './mixins/view_state_support'; -export { default as ViewMixin, dispatchLifeCycleHook } from './mixins/view_support'; +export { default as ViewMixin } from './mixins/view_support'; export { default as ActionSupport } from './mixins/action_support'; export { MUTABLE_CELL diff --git a/packages/ember-views/lib/mixins/view_support.js b/packages/ember-views/lib/mixins/view_support.js index 7617bbeca1f..a4595c56a49 100644 --- a/packages/ember-views/lib/mixins/view_support.js +++ b/packages/ember-views/lib/mixins/view_support.js @@ -9,10 +9,6 @@ import { DEBUG } from 'ember-env-flags'; function K() { return this; } -export function dispatchLifeCycleHook(component, hook) { - component.trigger(hook); -} - /** @class ViewMixin @namespace Ember @@ -66,9 +62,10 @@ export default Mixin.create({ @public */ concatenatedProperties: ['attributeBindings'], + [POST_INIT]() { - dispatchLifeCycleHook(this, 'didInitAttrs', undefined, this.attrs); - dispatchLifeCycleHook(this, 'didReceiveAttrs', undefined, this.attrs); + this.trigger('didInitAttrs'); + this.trigger('didReceiveAttrs'); }, // .......................................................... From 49787ed3e5b66fd298ac1f9575b7913127cd5f4e Mon Sep 17 00:00:00 2001 From: Doug Yun Date: Mon, 11 Apr 2016 21:55:14 -0400 Subject: [PATCH 042/224] [BUGFIX beta] Allow numeric keys for the `get` helper. Fixes #13296 --- packages/ember-glimmer/lib/helpers/get.js | 2 +- .../tests/integration/helpers/get-test.js | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/ember-glimmer/lib/helpers/get.js b/packages/ember-glimmer/lib/helpers/get.js index 1e6f52e3d08..07bd73b3398 100644 --- a/packages/ember-glimmer/lib/helpers/get.js +++ b/packages/ember-glimmer/lib/helpers/get.js @@ -96,7 +96,7 @@ class GetHelperReference extends CachedReference { if (pathType === 'string') { innerReference = this.innerReference = referenceFromParts(this.sourceReference, path.split('.')); } else if (pathType === 'number') { - innerReference = this.innerReference = this.sourceReference.get(path); + innerReference = this.innerReference = this.sourceReference.get('' + path); } innerTag.update(innerReference.tag); diff --git a/packages/ember-glimmer/tests/integration/helpers/get-test.js b/packages/ember-glimmer/tests/integration/helpers/get-test.js index bf2c6c30369..d9643264bae 100644 --- a/packages/ember-glimmer/tests/integration/helpers/get-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/get-test.js @@ -50,6 +50,31 @@ moduleFor('Helpers test: {{get}}', class extends RenderingTest { this.assertText('[red and yellow] [red and yellow]'); } + ['@test should be able to get an object value with numeric keys']() { + this.render(`{{#each indexes as |index|}}[{{get items index}}]{{/each}}`, { + indexes: [1, 2, 3], + items: { + 1: 'First', + 2: 'Second', + 3: 'Third' + } + }); + + this.assertText('[First][Second][Third]'); + + this.runTask(() => this.rerender()); + + this.assertText('[First][Second][Third]'); + + this.runTask(() => set(this.context, 'items.1', 'Qux')); + + this.assertText('[Qux][Second][Third]'); + + this.runTask(() => set(this.context, 'items', { 1: 'First', 2: 'Second', 3: 'Third' })); + + this.assertText('[First][Second][Third]'); + } + ['@test should be able to get an object value with a bound/dynamic key']() { this.render(`[{{get colors key}}] [{{if true (get colors key)}}]`, { colors: { apple: 'red', banana: 'yellow' }, From 213121ef72697e4a4f0a248990725aec8143960f Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Sun, 18 Jun 2017 19:10:20 +0200 Subject: [PATCH 043/224] Add more requested changes --- .../ember-application/lib/system/application-instance.js | 2 +- packages/ember-routing/lib/system/route.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-application/lib/system/application-instance.js b/packages/ember-application/lib/system/application-instance.js index 989ae769f3b..78826439c5a 100644 --- a/packages/ember-application/lib/system/application-instance.js +++ b/packages/ember-application/lib/system/application-instance.js @@ -235,7 +235,7 @@ const ApplicationInstance = EngineInstance.extend({ @public @param url {String} the destination URL - @return {Promise} + @return {Promise} */ visit(url) { this.setupRouter(); diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index d007524e21b..79c11d6c65e 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -1371,7 +1371,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @method beforeModel @param {Transition} transition - @return {Promise} if the value returned from this hook is + @return {any | Promise} if the value returned from this hook is a promise, the transition will pause until the transition resolves. Otherwise, non-promise return values are not utilized in any way. @@ -1408,7 +1408,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @param {Object} resolvedModel the value returned from `model`, or its resolved value if it was a promise @param {Transition} transition - @return {Promise} if the value returned from this hook is + @return {any | Promise} if the value returned from this hook is a promise, the transition will pause until the transition resolves. Otherwise, non-promise return values are not utilized in any way. @@ -1527,7 +1527,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @method model @param {Object} params the parameters extracted from the URL @param {Transition} transition - @return {Object|Promise} the model for this route. If + @return {any | Promise} the model for this route. If a promise is returned, the transition will pause until the promise resolves, and the resolved value of the promise will be used as the model for this route. @@ -1568,7 +1568,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @method deserialize @param {Object} params the parameters extracted from the URL @param {Transition} transition - @return {Object|Promise} the model for this route. + @return {any | Promise} the model for this route. Router.js hook. */ From f31d43f033b37d6a096d4fd4125342505d8e78af Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Sun, 18 Jun 2017 09:51:21 -0700 Subject: [PATCH 044/224] Refactor base app test helper classes --- .../tests/system/application_test.js | 98 +++++++------------ .../tests/system/bootstrap-test.js | 23 ++--- .../custom_resolver_test.js | 40 ++++---- packages/internal-test-helpers/lib/index.js | 1 + .../lib/test-cases/abstract-application.js | 76 ++------------ .../lib/test-cases/application.js | 58 ++++++++++- .../lib/test-cases/autoboot-application.js | 43 +++----- .../default-resolver-application.js | 61 ++++++++++++ .../lib/test-cases/router.js | 1 - .../test-cases/test-resolver-application.js | 35 +++++++ 10 files changed, 234 insertions(+), 202 deletions(-) create mode 100644 packages/internal-test-helpers/lib/test-cases/default-resolver-application.js create mode 100644 packages/internal-test-helpers/lib/test-cases/test-resolver-application.js diff --git a/packages/ember-application/tests/system/application_test.js b/packages/ember-application/tests/system/application_test.js index b4f63a4eb4f..df086d16cf6 100644 --- a/packages/ember-application/tests/system/application_test.js +++ b/packages/ember-application/tests/system/application_test.js @@ -1,16 +1,12 @@ /*globals EmberDev */ import { VERSION } from 'ember'; import { ENV, context } from 'ember-environment'; -import { - run, - libraries -} from 'ember-metal'; +import { libraries } from 'ember-metal'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; import Application from '../../system/application'; -import DefaultResolver from '../../system/resolver'; import { Router, NoneLocation, @@ -35,10 +31,10 @@ import { moduleFor, ApplicationTestCase, AbstractTestCase, - AutobootApplicationTestCase + AutobootApplicationTestCase, + DefaultResolverApplicationTestCase } from 'internal-test-helpers'; -let { trim } = jQuery; let secondApp; moduleFor('Ember.Application, autobooting multiple apps', class extends ApplicationTestCase { @@ -69,30 +65,30 @@ moduleFor('Ember.Application, autobooting multiple apps', class extends Applicat super.teardown(); if (this.secondApp) { - run(this.secondApp, 'destroy'); + this.runTask(() => this.secondApp.destroy()); } } [`@test you can make a new application in a non-overlapping element`](assert) { - let app = run(() => this.createSecondApplication({ + let app = this.runTask(() => this.createSecondApplication({ rootElement: '#two' })); - run(app, 'destroy'); + this.runTask(() => app.destroy()); assert.ok(true, 'should not raise'); } [`@test you cannot make a new application that is a parent of an existing application`]() { expectAssertion(() => { - run(() => this.createSecondApplication({ - rootElement: '#qunit-fixture' + this.runTask(() => this.createSecondApplication({ + rootElement: this.applicationOptions.rootElement })); }); } [`@test you cannot make a new application that is a descendant of an existing application`]() { expectAssertion(() => { - run(() => this.createSecondApplication({ + this.runTask(() => this.createSecondApplication({ rootElement: '#one-child' })); }); @@ -100,7 +96,7 @@ moduleFor('Ember.Application, autobooting multiple apps', class extends Applicat [`@test you cannot make a new application that is a duplicate of an existing application`]() { expectAssertion(() => { - run(() => this.createSecondApplication({ + this.runTask(() => this.createSecondApplication({ rootElement: '#one' })); }); @@ -108,7 +104,7 @@ moduleFor('Ember.Application, autobooting multiple apps', class extends Applicat [`@test you cannot make two default applications without a rootElement error`]() { expectAssertion(() => { - run(() => this.createSecondApplication()); + this.runTask(() => this.createSecondApplication()); }); } }); @@ -190,7 +186,7 @@ moduleFor('Ember.Application', class extends ApplicationTestCase { }); -moduleFor('Ember.Application, default resolver with autoboot', class extends AutobootApplicationTestCase { +moduleFor('Ember.Application, default resolver with autoboot', class extends DefaultResolverApplicationTestCase { constructor() { super(); @@ -203,19 +199,16 @@ moduleFor('Ember.Application, default resolver with autoboot', class extends Aut setTemplates({}); } - createApplication(options) { - let myOptions = assign({ - Resolver: DefaultResolver - }, options); - return super.createApplication(myOptions); + get applicationOptions() { + return assign(super.applicationOptions, { + autoboot: true + }); } [`@test acts like a namespace`](assert) { let lookup = context.lookup = {}; - run(() => { - lookup.TestApp = this.createApplication(); - }); + lookup.TestApp = this.runTask(() => this.createApplication()); setNamespaceSearchDisabled(false); let Foo = this.application.Foo = EmberObject.extend(); @@ -224,10 +217,11 @@ moduleFor('Ember.Application, default resolver with autoboot', class extends Aut [`@test can specify custom router`](assert) { let MyRouter = Router.extend(); - run(() => { - let app = this.createApplication(); - app.Router = MyRouter; + this.runTask(() => { + this.createApplication() + this.application.Router = MyRouter; }); + assert.ok( this.application.__deprecatedInstance__.lookup('router:main') instanceof MyRouter, 'application resolved the correct router' @@ -235,12 +229,10 @@ moduleFor('Ember.Application, default resolver with autoboot', class extends Aut } [`@test Minimal Application initialized with just an application template`](assert) { - jQuery('#qunit-fixture').html(''); - run(() => { - this.createApplication(); - }); + this.$().html(''); + this.runTask(() => this.createApplication()); - equal(trim(jQuery('#qunit-fixture').text()), 'Hello World'); + assert.equal(this.$().text().trim(), 'Hello World'); } }); @@ -261,28 +253,20 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes super.teardown(); } - createApplication(options, MyApplication) { - let application = super.createApplication(options, MyApplication); - this.add('router:main', Router.extend({ - location: 'none' - })); - return application; - } - [`@test initialized application goes to initial route`](assert) { - run(() => { + this.runTask(() => { this.createApplication(); this.addTemplate('application', '{{outlet}}'); this.addTemplate('index', '

Hi from index

'); }); - assert.equal(jQuery('#qunit-fixture h1').text(), 'Hi from index'); + assert.equal(this.$('h1').text(), 'Hi from index'); } [`@test ready hook is called before routing begins`](assert) { assert.expect(2); - run(() => { + this.runTask(() => { function registerRoute(application, name, callback) { let route = EmberRoute.extend({ activate: callback @@ -306,18 +290,16 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes } [`@test initialize application via initialize call`](assert) { - run(() => { - this.createApplication(); - }); + this.runTask(() => this.createApplication()); // This is not a public way to access the container; we just // need to make some assertions about the created router - let router = this.application.__deprecatedInstance__.lookup('router:main'); + let router = this.applicationInstance.lookup('router:main'); assert.equal(router instanceof Router, true, 'Router was set from initialize call'); assert.equal(router.location instanceof NoneLocation, true, 'Location was set from location implementation name'); } [`@test initialize application with stateManager via initialize call from Router class`](assert) { - run(() => { + this.runTask(() => { this.createApplication(); this.addTemplate('application', '

Hello!

'); }); @@ -325,18 +307,18 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes // need to make some assertions about the created router let router = this.application.__deprecatedInstance__.lookup('router:main'); assert.equal(router instanceof Router, true, 'Router was set from initialize call'); - assert.equal(jQuery('#qunit-fixture h1').text(), 'Hello!'); + assert.equal(this.$('h1').text(), 'Hello!'); } [`@test Application Controller backs the appplication template`](assert) { - run(() => { + this.runTask(() => { this.createApplication(); this.addTemplate('application', '

{{greeting}}

'); this.add('controller:application', Controller.extend({ greeting: 'Hello!' })); }); - assert.equal(jQuery('#qunit-fixture h1').text(), 'Hello!'); + assert.equal(this.$('h1').text(), 'Hello!'); } [`@test enable log of libraries with an ENV var`](assert) { @@ -353,9 +335,7 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes libraries.register('my-lib', '2.0.0a'); - run(() => { - this.createApplication(); - }); + this.runTask(() => this.createApplication()); assert.equal(messages[1], 'Ember : ' + VERSION); assert.equal(messages[2], 'jQuery : ' + jQuery().jquery); @@ -371,9 +351,7 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes setDebugFunction('debug', () => logged = true); - run(() => { - this.createApplication(); - }); + this.runTask(() => this.createApplication()); assert.ok(!logged, 'library version logging skipped'); } @@ -381,7 +359,7 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes [`@test can resolve custom router`](assert) { let CustomRouter = Router.extend(); - run(() => { + this.runTask(() => { this.createApplication(); this.add('router:main', CustomRouter); }); @@ -394,9 +372,9 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes [`@test does not leak itself in onLoad._loaded`](assert) { assert.equal(_loaded.application, undefined); - run(() => this.createApplication()); + this.runTask(() => this.createApplication()); assert.equal(_loaded.application, this.application); - run(this.application, 'destroy'); + this.runTask(() => this.application.destroy()); assert.equal(_loaded.application, undefined); } diff --git a/packages/ember-application/tests/system/bootstrap-test.js b/packages/ember-application/tests/system/bootstrap-test.js index c34b8a6f929..3cd58e6418a 100644 --- a/packages/ember-application/tests/system/bootstrap-test.js +++ b/packages/ember-application/tests/system/bootstrap-test.js @@ -1,11 +1,11 @@ -import { Router } from 'ember-routing'; import { assign } from 'ember-utils'; import { jQuery } from 'ember-views'; -import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -import { setTemplates } from 'ember-glimmer'; -import DefaultResolver from '../../system/resolver'; +import { + moduleFor, + DefaultResolverApplicationTestCase +} from 'internal-test-helpers'; -moduleFor('Ember.Application with default resolver and autoboot', class extends ApplicationTestCase { +moduleFor('Ember.Application with default resolver and autoboot', class extends DefaultResolverApplicationTestCase { constructor() { jQuery('#qunit-fixture').html(`
@@ -16,22 +16,15 @@ moduleFor('Ember.Application with default resolver and autoboot', class extends super(); } - teardown() { - setTemplates({}); - } - get applicationOptions() { return assign(super.applicationOptions, { autoboot: true, - rootElement: '#app', - Resolver: DefaultResolver, - Router: Router.extend({ - location: 'none' - }) + rootElement: '#app' }); } ['@test templates in script tags are extracted at application creation'](assert) { - assert.equal(jQuery('#app').text(), 'Hello World!'); + this.runTask(() => this.createApplication()); + assert.equal(this.$('#app').text(), 'Hello World!'); } }); diff --git a/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js b/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js index 2aa96158d63..fa5a4733aad 100644 --- a/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js +++ b/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js @@ -1,40 +1,34 @@ -import { jQuery } from 'ember-views'; -import { run } from 'ember-metal'; -import Application from '../../../system/application'; import DefaultResolver from '../../../system/resolver'; -import { compile } from 'ember-template-compiler'; +import { assign } from 'ember-utils'; +import { + moduleFor, + DefaultResolverApplicationTestCase +} from 'internal-test-helpers'; -let application; +moduleFor('Ember.Application with extended default resolver and autoboot', class extends DefaultResolverApplicationTestCase { -QUnit.module('Ember.Application Dependency Injection – customResolver', { - setup() { - let fallbackTemplate = compile('

Fallback

'); + get applicationOptions() { + let applicationTemplate = this.compile(`

Fallback

`); let Resolver = DefaultResolver.extend({ resolveTemplate(resolvable) { - let resolvedTemplate = this._super(resolvable); - if (resolvedTemplate) { return resolvedTemplate; } if (resolvable.fullNameWithoutType === 'application') { - return fallbackTemplate; + return applicationTemplate; } else { - return; + return this._super(resolvable); } } }); - application = run(() => { - return Application.create({ - Resolver: Resolver, - rootElement: '#qunit-fixture' - }); + return assign(super.applicationOptions, { + Resolver, + autoboot: true }); - }, + } - teardown() { - run(application, 'destroy'); + [`@test a resolver can be supplied to application`](assert) { + this.runTask(() => this.createApplication()); + assert.equal(this.$('h1').text(), 'Fallback'); } -}); -QUnit.test('a resolver can be supplied to application', function() { - equal(jQuery('h1', application.rootElement).text(), 'Fallback'); }); diff --git a/packages/internal-test-helpers/lib/index.js b/packages/internal-test-helpers/lib/index.js index 3fd55f5b68d..e69ef57a937 100644 --- a/packages/internal-test-helpers/lib/index.js +++ b/packages/internal-test-helpers/lib/index.js @@ -29,6 +29,7 @@ export { default as AbstractRenderingTestCase } from './test-cases/abstract-rend export { default as RenderingTestCase } from './test-cases/rendering'; export { default as RouterTestCase } from './test-cases/router'; export { default as AutobootApplicationTestCase } from './test-cases/autoboot-application'; +export { default as DefaultResolverApplicationTestCase } from './test-cases/default-resolver-application'; export { default as TestResolver, diff --git a/packages/internal-test-helpers/lib/test-cases/abstract-application.js b/packages/internal-test-helpers/lib/test-cases/abstract-application.js index 5e2b519bf97..ced04a3715b 100644 --- a/packages/internal-test-helpers/lib/test-cases/abstract-application.js +++ b/packages/internal-test-helpers/lib/test-cases/abstract-application.js @@ -1,36 +1,23 @@ -import { run } from 'ember-metal'; -import { jQuery } from 'ember-views'; -import { Application } from 'ember-application'; -import { Router } from 'ember-routing'; import { compile } from 'ember-template-compiler'; - import AbstractTestCase from './abstract'; -import { ModuleBasedResolver } from '../test-resolver'; +import { jQuery } from 'ember-views'; import { runDestroy } from '../run'; export default class AbstractApplicationTestCase extends AbstractTestCase { + constructor() { super(); - this.element = jQuery('#qunit-fixture')[0]; + } - let { applicationOptions } = this; - this.application = this.runTask(() => Application.create(applicationOptions)); - - this.resolver = applicationOptions.Resolver.lastInstance; - - if (this.resolver) { - this.resolver.add('router:main', Router.extend(this.routerOptions)); - } - - this.applicationInstance = null; + teardown() { + runDestroy(this.application); + super.teardown(); } get applicationOptions() { return { - rootElement: '#qunit-fixture', - autoboot: false, - Resolver: ModuleBasedResolver + rootElement: '#qunit-fixture' }; } @@ -44,57 +31,8 @@ export default class AbstractApplicationTestCase extends AbstractTestCase { return this.application.resolveRegistration('router:main'); } - get appRouter() { - return this.applicationInstance.lookup('router:main'); - } - - teardown() { - runDestroy(this.applicationInstance); - runDestroy(this.application); - } - - visit(url, options) { - let { applicationInstance } = this; - - if (applicationInstance) { - return this.runTask(() => applicationInstance.visit(url, options)); - } else { - return this.runTask(() => { - return this.application.visit(url, options).then(instance => { - this.applicationInstance = instance; - }); - }); - } - } - - transitionTo() { - return run(this.appRouter, 'transitionTo', ...arguments); - } - compile(string, options) { return compile(...arguments); } - add(specifier, factory) { - this.resolver.add(specifier, factory); - } - - addTemplate(templateName, templateString) { - this.resolver.add(`template:${templateName}`, this.compile(templateString, { - moduleName: templateName - })); - } - - addComponent(name, { ComponentClass = null, template = null }) { - if (ComponentClass) { - this.resolver.add(`component:${name}`, ComponentClass); - } - - if (typeof template === 'string') { - this.resolver.add(`template:components/${name}`, this.compile(template, { - moduleName: `components/${name}` - })); - } - } - } diff --git a/packages/internal-test-helpers/lib/test-cases/application.js b/packages/internal-test-helpers/lib/test-cases/application.js index 4e0e173f615..6f128ba7534 100644 --- a/packages/internal-test-helpers/lib/test-cases/application.js +++ b/packages/internal-test-helpers/lib/test-cases/application.js @@ -1,4 +1,58 @@ -import AbstractApplicationTestCase from './abstract-application'; +import TestResolverApplicationTestCase from './test-resolver-application'; +import { Application } from 'ember-application'; +import { Router } from 'ember-routing'; +import { assign } from 'ember-utils'; +import { runDestroy } from '../run'; + +export default class ApplicationTestCase extends TestResolverApplicationTestCase { + constructor() { + super(); + + let { applicationOptions } = this; + this.application = this.runTask(() => { + return Application.create(applicationOptions) + }); + + this.resolver = applicationOptions.Resolver.lastInstance; + + if (this.resolver) { + this.resolver.add('router:main', Router.extend(this.routerOptions)); + } + } + + get applicationOptions() { + return assign(super.applicationOptions, { + autoboot: false + }); + } + + teardown() { + runDestroy(this.applicationInstance); + super.teardown(); + } + + visit(url, options) { + let { applicationInstance } = this; + + if (applicationInstance) { + return this.runTask(() => applicationInstance.visit(url, options)); + } else { + return this.runTask(() => { + return this.application.visit(url, options).then(instance => { + this.applicationInstance = instance; + }); + }); + } + } + + get appRouter() { + return this.applicationInstance.lookup('router:main'); + } + + transitionTo() { + return this.runTask(() =>{ + return this.appRouter.transitionTo(...arguments); + }); + } -export default class ApplicationTestCase extends AbstractApplicationTestCase { } diff --git a/packages/internal-test-helpers/lib/test-cases/autoboot-application.js b/packages/internal-test-helpers/lib/test-cases/autoboot-application.js index cee242b8191..e63896f2849 100644 --- a/packages/internal-test-helpers/lib/test-cases/autoboot-application.js +++ b/packages/internal-test-helpers/lib/test-cases/autoboot-application.js @@ -1,52 +1,31 @@ -import AbstractTestCase from './abstract'; +import TestResolverApplicationTestCase from './test-resolver-application'; import TestResolver from '../test-resolver'; import { Application } from 'ember-application'; import { assign } from 'ember-utils'; -import { runDestroy } from '../run'; -import { run } from 'ember-metal'; -import { compile } from 'ember-template-compiler'; +import { Router } from 'ember-routing'; -export default class AutobootApplicationTestCase extends AbstractTestCase { - - teardown() { - runDestroy(this.application); - super.teardown(); - } +export default class AutobootApplicationTestCase extends TestResolverApplicationTestCase { createApplication(options, MyApplication=Application) { - let myOptions = assign({ - rootElement: '#qunit-fixture', - Resolver: TestResolver - }, options); + let myOptions = assign(this.applicationOptions, options); let application = this.application = MyApplication.create(myOptions); this.resolver = myOptions.Resolver.lastInstance; - return application; - } - add(specifier, factory) { - this.resolver.add(specifier, factory); - } + if (this.resolver) { + this.resolver.add('router:main', Router.extend(this.routerOptions)); + } - get router() { - return this.application.resolveRegistration('router:main'); + return application; } visit(url, options) { - return run(this.applicationInstance, 'visit', url, options); + return this.runTask(() => { + return this.applicationInstance.visit(url, options); + }); } get applicationInstance() { return this.application.__deprecatedInstance__; } - compile(string, options) { - return compile(...arguments); - } - - addTemplate(templateName, templateString) { - this.resolver.add(`template:${templateName}`, this.compile(templateString, { - moduleName: templateName - })); - } - } diff --git a/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js b/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js new file mode 100644 index 00000000000..bd7a93334cf --- /dev/null +++ b/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js @@ -0,0 +1,61 @@ +import AbstractApplicationTestCase from './abstract-application'; +import { Resolver as DefaultResolver } from 'ember-application'; +import { Application } from 'ember-application'; +import { + setTemplates, + setTemplate +} from 'ember-glimmer'; +import { assign } from 'ember-utils'; +import { runDestroy } from '../run'; + +export default class ApplicationTestCase extends AbstractApplicationTestCase { + + createApplication() { + return this.application = Application.create(this.applicationOptions); + } + + get applicationOptions() { + return assign(super.applicationOptions, { + autoboot: false, + Resolver: DefaultResolver + }); + } + + teardown() { + runDestroy(this.applicationInstance); + super.teardown(); + setTemplates({}); + } + + visit(url, options) { + let { applicationInstance } = this; + + if (applicationInstance) { + return this.runTask(() => applicationInstance.visit(url, options)); + } else { + return this.runTask(() => { + return this.application.visit(url, options).then(instance => { + this.applicationInstance = instance; + }); + }); + } + } + + get appRouter() { + return this.applicationInstance.lookup('router:main'); + } + + transitionTo() { + return this.runTask(() =>{ + return this.appRouter.transitionTo(...arguments); + }); + } + + addTemplate(name, templateString) { + let compiled = this.compile(templateString); + setTemplate(name, compiled); + return compiled; + } + + +} diff --git a/packages/internal-test-helpers/lib/test-cases/router.js b/packages/internal-test-helpers/lib/test-cases/router.js index ab0636e2205..1beaa0519c3 100644 --- a/packages/internal-test-helpers/lib/test-cases/router.js +++ b/packages/internal-test-helpers/lib/test-cases/router.js @@ -1,4 +1,3 @@ - import ApplicationTestCase from './application'; export default class RouterTestCase extends ApplicationTestCase { diff --git a/packages/internal-test-helpers/lib/test-cases/test-resolver-application.js b/packages/internal-test-helpers/lib/test-cases/test-resolver-application.js new file mode 100644 index 00000000000..06e05403daa --- /dev/null +++ b/packages/internal-test-helpers/lib/test-cases/test-resolver-application.js @@ -0,0 +1,35 @@ +import AbstractApplicationTestCase from './abstract-application'; +import { ModuleBasedResolver } from '../test-resolver'; +import { assign } from 'ember-utils'; + +export default class TestResolverApplicationTestCase extends AbstractApplicationTestCase { + + get applicationOptions() { + return assign(super.applicationOptions, { + Resolver: ModuleBasedResolver + }); + } + + add(specifier, factory) { + this.resolver.add(specifier, factory); + } + + addTemplate(templateName, templateString) { + this.resolver.add(`template:${templateName}`, this.compile(templateString, { + moduleName: templateName + })); + } + + addComponent(name, { ComponentClass = null, template = null }) { + if (ComponentClass) { + this.resolver.add(`component:${name}`, ComponentClass); + } + + if (typeof template === 'string') { + this.resolver.add(`template:components/${name}`, this.compile(template, { + moduleName: `components/${name}` + })); + } + } + +} From 93c38104cd73f7cf4a33d08b8384f7d994e887c5 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Fri, 19 May 2017 00:33:40 +0100 Subject: [PATCH 045/224] [DOC release] Improve documentation of `if` template helper * Merge the two separate code blocks Due to the fact that we had two comment blocks for the same helper, only the last one was being rendered by YUIDoc. I tried merging them, giving block and inline forms headers, and do some rejiggering of the text. * Add note about `if` helper branches being eagerly evaluated Fixes https://github.com/emberjs/guides/issues/1737. --- .../ember-glimmer/lib/helpers/if-unless.js | 124 +++++++++--------- 1 file changed, 64 insertions(+), 60 deletions(-) diff --git a/packages/ember-glimmer/lib/helpers/if-unless.js b/packages/ember-glimmer/lib/helpers/if-unless.js index 252c8930fd0..f51c085fcf7 100644 --- a/packages/ember-glimmer/lib/helpers/if-unless.js +++ b/packages/ember-glimmer/lib/helpers/if-unless.js @@ -16,11 +16,55 @@ import { isConst } from '@glimmer/reference'; +class ConditionalHelperReference extends CachedReference { + static create(_condRef, _truthyRef, _falsyRef) { + let condRef = ConditionalReference.create(_condRef); + let truthyRef = _truthyRef || UNDEFINED_REFERENCE; + let falsyRef = _falsyRef || UNDEFINED_REFERENCE; + + if (isConst(condRef)) { + return condRef.value() ? truthyRef : falsyRef; + } else { + return new ConditionalHelperReference(condRef, truthyRef, falsyRef); + } + } + + constructor(cond, truthy, falsy) { + super(); + + this.branchTag = new UpdatableTag(CONSTANT_TAG); + this.tag = combine([cond.tag, this.branchTag]); + + this.cond = cond; + this.truthy = truthy; + this.falsy = falsy; + } + + compute() { + let { cond, truthy, falsy } = this; + + let branch = cond.value() ? truthy : falsy; + + this.branchTag.update(branch.tag); + + return branch.value(); + } +} /** - Use the `if` block helper to conditionally render a block depending on a - property. If the property is "falsey", for example: `false`, `undefined`, - `null`, `""`, `0`, `NaN` or an empty array, the block will not be rendered. + The `if` helper allows you to conditionally render one of two branches, + depending on the "truthiness" of a property. + For example the following values are all falsey: `false`, `undefined`, `null`, `""`, `0`, `NaN` or an empty array. + + This helper has two forms, block and inline. + + ## Block form + + You can use the block form of `if` to conditionally render a section of the template. + + To use it, pass the conditional value to the `if` helper, + using the block form to wrap the section of template you want to conditionally render. + Like so: ```handlebars {{! will not render if foo is falsey}} @@ -54,77 +98,37 @@ import { {{/if}} ``` - You can use `if` inline to conditionally render a single property or string. - This helper acts like a ternary operator. If the first property is truthy, - the second argument will be displayed, if not, the third argument will be - displayed + ## Inline form - ```handlebars - {{if useLongGreeting "Hello" "Hi"}} Dave - ``` + The inline `if` helper conditionally renders a single property or string. - Finally, you can use the `if` helper inside another helper as a subexpression. + In this form, the `if` helper receives three arguments, the conditional value, + the value to render when truthy, and the value to render when falsey. + + For example, if `useLongGreeting` is truthy, the following: ```handlebars - {{some-component height=(if isBig "100" "10")}} + {{if useLongGreeting "Hello" "Hi"}} Alex ``` - @method if - @for Ember.Templates.helpers - @public -*/ - -class ConditionalHelperReference extends CachedReference { - static create(_condRef, _truthyRef, _falsyRef) { - let condRef = ConditionalReference.create(_condRef); - let truthyRef = _truthyRef || UNDEFINED_REFERENCE; - let falsyRef = _falsyRef || UNDEFINED_REFERENCE; - - if (isConst(condRef)) { - return condRef.value() ? truthyRef : falsyRef; - } else { - return new ConditionalHelperReference(condRef, truthyRef, falsyRef); - } - } - - constructor(cond, truthy, falsy) { - super(); - - this.branchTag = new UpdatableTag(CONSTANT_TAG); - this.tag = combine([cond.tag, this.branchTag]); - - this.cond = cond; - this.truthy = truthy; - this.falsy = falsy; - } - - compute() { - let { cond, truthy, falsy } = this; + Will render: - let branch = cond.value() ? truthy : falsy; - - this.branchTag.update(branch.tag); - - return branch.value(); - } -} - -/** - The inline `if` helper conditionally renders a single property or string. - This helper acts like a ternary operator. If the first property is truthy, - the second argument will be displayed, otherwise, the third argument will be - displayed - - ```handlebars - {{if useLongGreeting "Hello" "Hi"}} Alex + ```html + Hello Alex ``` - You can use the `if` helper inside another helper as a subexpression. + ### Nested `if` + + You can use the `if` helper inside another helper as a nested helper: ```handlebars {{some-component height=(if isBig "100" "10")}} ``` + One detail to keep in mind is that both branches of the `if` helper will be evaluated, + so if you have `{{if condition "foo" (expensive-operation "bar")`, + `expensive-operation` will always calculate. + @method if @for Ember.Templates.helpers @public From 5b528a019313dbe8d42a0b4a298b32ebc762a304 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Mon, 19 Jun 2017 14:30:28 +0100 Subject: [PATCH 046/224] [DOC release] Update Array.any documentation --- packages/ember-runtime/lib/mixins/enumerable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/enumerable.js b/packages/ember-runtime/lib/mixins/enumerable.js index beb15d6507b..b1b409d9dc0 100644 --- a/packages/ember-runtime/lib/mixins/enumerable.js +++ b/packages/ember-runtime/lib/mixins/enumerable.js @@ -603,7 +603,7 @@ const Enumerable = Mixin.create({ /** Returns `true` if the passed function returns true for any item in the - enumeration. This corresponds with the `some()` method in JavaScript 1.6. + enumeration. The callback method you provide should have the following signature (all parameters are optional): @@ -616,7 +616,7 @@ const Enumerable = Mixin.create({ - `index` is the current index in the iteration. - `enumerable` is the enumerable object itself. - It should return the `true` to include the item in the results, `false` + It should return `true` to include the item in the results, `false` otherwise. Note that in addition to a callback, you can also pass an optional target From 645e59ee6865d1d53f6204ef56f74cf27e3ccfda Mon Sep 17 00:00:00 2001 From: karthiick Date: Wed, 14 Jun 2017 23:46:32 +0530 Subject: [PATCH 047/224] Decouple test from the default resolver for instance_initializers_test Fix Fixes Fixes Fixes This is easy Fixes --- .../system/instance_initializers_test.js | 639 +++++++++--------- 1 file changed, 302 insertions(+), 337 deletions(-) diff --git a/packages/ember-application/tests/system/instance_initializers_test.js b/packages/ember-application/tests/system/instance_initializers_test.js index ba74689b969..b9f0eff8187 100644 --- a/packages/ember-application/tests/system/instance_initializers_test.js +++ b/packages/ember-application/tests/system/instance_initializers_test.js @@ -1,410 +1,375 @@ -import { run } from 'ember-metal'; -import Application from '../../system/application'; -import ApplicationInstance from '../../system/application-instance'; +import { assign } from 'ember-utils'; +import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; +import { Application, ApplicationInstance } from 'ember-application'; import { jQuery } from 'ember-views'; -let app; +moduleFor('Ember.Application instance initializers', class extends AutobootApplicationTestCase { + constructor() { + jQuery('#qunit-fixture').html(` +
ONE
+
TWO
+ `); + super(); + } + + get applicationOptions() { + return assign(super.applicationOptions, { + rootElement: '#one' + }); + } + + createSecondApplication(options, MyApplication=Application) { + let myOptions = assign(this.applicationOptions, { + rootElement: '#two' + }, options); + let secondApp = this.secondApp = MyApplication.create(myOptions); + return secondApp; + } -QUnit.module('Ember.Application instance initializers', { teardown() { - if (app) { - run(() => app.destroy()); + super.teardown(); + + if (this.secondApp) { + this.runTask(() => this.secondApp.destroy()); } } -}); -QUnit.test('initializers require proper \'name\' and \'initialize\' properties', function() { - let MyApplication = Application.extend(); + [`@test initializers require proper 'name' and 'initialize' properties`]() { + let MyApplication = Application.extend(); - expectAssertion(() => { - run(() => { + expectAssertion(() => { MyApplication.instanceInitializer({ name: 'initializer' }); }); - }); - expectAssertion(() => { - run(() => { + expectAssertion(() => { MyApplication.instanceInitializer({ initialize() {} }); }); - }); -}); -QUnit.test('initializers are passed an app instance', function() { - let MyApplication = Application.extend(); + this.runTask(() => this.createApplication({}, MyApplication)); + } - MyApplication.instanceInitializer({ - name: 'initializer', - initialize(instance) { - ok(instance instanceof ApplicationInstance, 'initialize is passed an application instance'); - } - }); + [`@test initializers are passed an app instance`](assert) { + let MyApplication = Application.extend(); - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.instanceInitializer({ + name: 'initializer', + initialize(instance) { + assert.ok(instance instanceof ApplicationInstance, 'initialize is passed an application instance'); + } }); - }); -}); -QUnit.test('initializers can be registered in a specified order', function() { - let order = []; - let MyApplication = Application.extend(); - MyApplication.instanceInitializer({ - name: 'fourth', - after: 'third', - initialize(registry) { - order.push('fourth'); - } - }); - - MyApplication.instanceInitializer({ - name: 'second', - after: 'first', - before: 'third', - initialize(registry) { - order.push('second'); - } - }); - - MyApplication.instanceInitializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize(registry) { - order.push('fifth'); - } - }); + this.runTask(() => this.createApplication({}, MyApplication)); + } - MyApplication.instanceInitializer({ - name: 'first', - before: 'second', - initialize(registry) { - order.push('first'); - } - }); + [`@test initializers can be registered in a specified order`](assert) { + let order = []; + let MyApplication = Application.extend(); - MyApplication.instanceInitializer({ - name: 'third', - initialize(registry) { - order.push('third'); - } - }); + MyApplication.instanceInitializer({ + name: 'fourth', + after: 'third', + initialize(registry) { + order.push('fourth'); + } + }); - MyApplication.instanceInitializer({ - name: 'sixth', - initialize(registry) { - order.push('sixth'); - } - }); + MyApplication.instanceInitializer({ + name: 'second', + after: 'first', + before: 'third', + initialize(registry) { + order.push('second'); + } + }); - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.instanceInitializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize(registry) { + order.push('fifth'); + } }); - }); - deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); -}); + MyApplication.instanceInitializer({ + name: 'first', + before: 'second', + initialize(registry) { + order.push('first'); + } + }); -QUnit.test('initializers can be registered in a specified order as an array', function() { - let order = []; - let MyApplication = Application.extend(); + MyApplication.instanceInitializer({ + name: 'third', + initialize(registry) { + order.push('third'); + } + }); - MyApplication.instanceInitializer({ - name: 'third', - initialize(registry) { - order.push('third'); - } - }); - - MyApplication.instanceInitializer({ - name: 'second', - after: 'first', - before: ['third', 'fourth'], - initialize(registry) { - order.push('second'); - } - }); + MyApplication.instanceInitializer({ + name: 'sixth', + initialize(registry) { + order.push('sixth'); + } + }); - MyApplication.instanceInitializer({ - name: 'fourth', - after: ['second', 'third'], - initialize(registry) { - order.push('fourth'); - } - }); - - MyApplication.instanceInitializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize(registry) { - order.push('fifth'); - } - }); + this.runTask(() => this.createApplication({}, MyApplication)); - MyApplication.instanceInitializer({ - name: 'first', - before: ['second'], - initialize(registry) { - order.push('first'); - } - }); + assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); + } - MyApplication.instanceInitializer({ - name: 'sixth', - initialize(registry) { - order.push('sixth'); - } - }); + [`@test initializers can be registered in a specified order as an array`](assert) { + let order = []; + let MyApplication = Application.extend(); - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.instanceInitializer({ + name: 'third', + initialize(registry) { + order.push('third'); + } }); - }); - deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); -}); + MyApplication.instanceInitializer({ + name: 'second', + after: 'first', + before: ['third', 'fourth'], + initialize(registry) { + order.push('second'); + } + }); -QUnit.test('initializers can have multiple dependencies', function () { - let order = []; - let a = { - name: 'a', - before: 'b', - initialize(registry) { - order.push('a'); - } - }; - let b = { - name: 'b', - initialize(registry) { - order.push('b'); - } - }; - let c = { - name: 'c', - after: 'b', - initialize(registry) { - order.push('c'); - } - }; - let afterB = { - name: 'after b', - after: 'b', - initialize(registry) { - order.push('after b'); - } - }; - let afterC = { - name: 'after c', - after: 'c', - initialize(registry) { - order.push('after c'); - } - }; - - Application.instanceInitializer(b); - Application.instanceInitializer(a); - Application.instanceInitializer(afterC); - Application.instanceInitializer(afterB); - Application.instanceInitializer(c); - - run(() => { - app = Application.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.instanceInitializer({ + name: 'fourth', + after: ['second', 'third'], + initialize(registry) { + order.push('fourth'); + } }); - }); - ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); - ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); - ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB'); - ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC'); -}); + MyApplication.instanceInitializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize(registry) { + order.push('fifth'); + } + }); + + MyApplication.instanceInitializer({ + name: 'first', + before: ['second'], + initialize(registry) { + order.push('first'); + } + }); -QUnit.test('initializers set on Application subclasses should not be shared between apps', function() { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstApp = Application.extend(); - let firstApp, secondApp; + MyApplication.instanceInitializer({ + name: 'sixth', + initialize(registry) { + order.push('sixth'); + } + }); - FirstApp.instanceInitializer({ - name: 'first', - initialize(registry) { - firstInitializerRunCount++; - } - }); - let SecondApp = Application.extend(); - SecondApp.instanceInitializer({ - name: 'second', - initialize(registry) { - secondInitializerRunCount++; - } - }); - jQuery('#qunit-fixture').html('
'); - run(() => { - firstApp = FirstApp.create({ - router: false, - rootElement: '#qunit-fixture #first' + this.runTask(() => this.createApplication({}, MyApplication)); + + assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); + } + + [`@test initializers can have multiple dependencies`](assert) { + let order = []; + let MyApplication = Application.extend(); + let a = { + name: 'a', + before: 'b', + initialize(registry) { + order.push('a'); + } + }; + let b = { + name: 'b', + initialize(registry) { + order.push('b'); + } + }; + let c = { + name: 'c', + after: 'b', + initialize(registry) { + order.push('c'); + } + }; + let afterB = { + name: 'after b', + after: 'b', + initialize(registry) { + order.push('after b'); + } + }; + let afterC = { + name: 'after c', + after: 'c', + initialize(registry) { + order.push('after c'); + } + }; + + MyApplication.instanceInitializer(b); + MyApplication.instanceInitializer(a); + MyApplication.instanceInitializer(afterC); + MyApplication.instanceInitializer(afterB); + MyApplication.instanceInitializer(c); + + this.runTask(() => this.createApplication({}, MyApplication)); + + assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); + assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); + assert.ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB'); + assert.ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC'); + } + + [`@test initializers set on Application subclasses should not be shared between apps`](assert) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstApp = Application.extend(); + + FirstApp.instanceInitializer({ + name: 'first', + initialize(registry) { + firstInitializerRunCount++; + } }); - }); - equal(firstInitializerRunCount, 1, 'first initializer only was run'); - equal(secondInitializerRunCount, 0, 'first initializer only was run'); - run(() => { - secondApp = SecondApp.create({ - router: false, - rootElement: '#qunit-fixture #second' + + let SecondApp = Application.extend(); + SecondApp.instanceInitializer({ + name: 'second', + initialize(registry) { + secondInitializerRunCount++; + } }); - }); - equal(firstInitializerRunCount, 1, 'second initializer only was run'); - equal(secondInitializerRunCount, 1, 'second initializer only was run'); - run(() => { - firstApp.destroy(); - secondApp.destroy(); - }); -}); -QUnit.test('initializers are concatenated', function() { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstApp = Application.extend(); - let firstApp, secondApp; + this.runTask(() => this.createApplication({}, FirstApp)); - FirstApp.instanceInitializer({ - name: 'first', - initialize(registry) { - firstInitializerRunCount++; - } - }); + assert.equal(firstInitializerRunCount, 1, 'first initializer only was run'); + assert.equal(secondInitializerRunCount, 0, 'first initializer only was run'); - let SecondApp = FirstApp.extend(); - SecondApp.instanceInitializer({ - name: 'second', - initialize(registry) { - secondInitializerRunCount++; - } - }); + this.runTask(() => this.createSecondApplication({}, SecondApp)); + + assert.equal(firstInitializerRunCount, 1, 'second initializer only was run'); + assert.equal(secondInitializerRunCount, 1, 'second initializer only was run'); + } + + [`@test initializers are concatenated`](assert) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstApp = Application.extend(); - jQuery('#qunit-fixture').html('
'); - run(function() { - firstApp = FirstApp.create({ - router: false, - rootElement: '#qunit-fixture #first' + FirstApp.instanceInitializer({ + name: 'first', + initialize(registry) { + firstInitializerRunCount++; + } }); - }); - equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created'); - equal(secondInitializerRunCount, 0, 'first initializer only was run when base class created'); - firstInitializerRunCount = 0; - run(function() { - secondApp = SecondApp.create({ - router: false, - rootElement: '#qunit-fixture #second' + + let SecondApp = FirstApp.extend(); + SecondApp.instanceInitializer({ + name: 'second', + initialize(registry) { + secondInitializerRunCount++; + } }); - }); - equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created'); - equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created'); - run(function() { - firstApp.destroy(); - secondApp.destroy(); - }); -}); -QUnit.test('initializers are per-app', function() { - expect(2); + this.runTask(() => this.createApplication({}, FirstApp)); - let FirstApp = Application.extend(); + equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created'); + equal(secondInitializerRunCount, 0, 'first initializer only was run when base class created'); - FirstApp.instanceInitializer({ - name: 'abc', - initialize(app) {} - }); + firstInitializerRunCount = 0; + this.runTask(() => this.createSecondApplication({}, SecondApp)); - expectAssertion(function() { + equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created'); + equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created'); + } + + [`@test initializers are per-app`](assert) { + assert.expect(2); + + let FirstApp = Application.extend(); FirstApp.instanceInitializer({ name: 'abc', initialize(app) {} }); - }); - let SecondApp = Application.extend(); - SecondApp.instanceInitializer({ - name: 'abc', - initialize(app) {} - }); + expectAssertion(function() { + FirstApp.instanceInitializer({ + name: 'abc', + initialize(app) {} + }); + }); - ok(true, 'Two apps can have initializers named the same.'); -}); + this.runTask(() => this.createApplication({}, FirstApp)); -QUnit.test('initializers are run before ready hook', function() { - expect(2); + let SecondApp = Application.extend(); + SecondApp.instanceInitializer({ + name: 'abc', + initialize(app) {} + }); - let readyWasCalled = false; + this.runTask(() => this.createSecondApplication({}, SecondApp)); - let MyApplication = Application.extend({ - ready() { - ok(true, 'ready is called'); - readyWasCalled = true; - } - }); + assert.ok(true, 'Two apps can have initializers named the same.'); + } - MyApplication.instanceInitializer({ - name: 'initializer', - initialize() { - ok(!readyWasCalled, 'ready is not yet called'); - } - }); + [`@test initializers are run before ready hook`](assert) { + assert.expect(2); - run(function() { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + let MyApplication = Application.extend({ + ready() { + assert.ok(true, 'ready is called'); + readyWasCalled = false; + } }); - }); -}); + let readyWasCalled = false; -QUnit.test('initializers are executed in their own context', function() { - expect(1); + MyApplication.instanceInitializer({ + name: 'initializer', + initialize() { + assert.ok(!readyWasCalled, 'ready is not yet called'); + } + }); - let MyApplication = Application.extend(); + this.runTask(() => this.createApplication({}, MyApplication)); + } - MyApplication.instanceInitializer({ - name: 'coolInitializer', - myProperty: 'cool', - initialize(registry, application) { - equal(this.myProperty, 'cool', 'should have access to its own context'); - } - }); + [`@test initializers are executed in their own context`](assert) { + assert.expect(1); + + let MyApplication = Application.extend(); - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.instanceInitializer({ + name: 'coolInitializer', + myProperty: 'cool', + initialize(registry, application) { + assert.equal(this.myProperty, 'cool', 'should have access to its own context'); + } }); - }); -}); -QUnit.test('initializers get an instance on app reset', function() { - expect(2); + this.runTask(() => this.createApplication({}, MyApplication)); + } - let MyApplication = Application.extend(); + [`@test initializers get an instance on app reset`](assert) { + assert.expect(2); - MyApplication.instanceInitializer({ - name: 'giveMeAnInstance', - initialize(instance) { - ok(!!instance, 'Initializer got an instance'); - } - }); + let MyApplication = Application.extend(); - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.instanceInitializer({ + name: 'giveMeAnInstance', + initialize(instance) { + assert.ok(!!instance, 'Initializer got an instance'); + } }); - }); - run(app, 'reset'); + this.runTask(() => this.createApplication({}, MyApplication)); + + this.runTask(() => this.application.reset()); + } }); From 9da11e7f55034523e6b02f2b448f6db1a1271fe3 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 20 May 2017 14:18:07 +0500 Subject: [PATCH 048/224] clean-up assertion in link-to --- packages/ember-glimmer/lib/components/link-to.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/ember-glimmer/lib/components/link-to.js b/packages/ember-glimmer/lib/components/link-to.js index be4e37e6bc9..2cb83ac33be 100644 --- a/packages/ember-glimmer/lib/components/link-to.js +++ b/packages/ember-glimmer/lib/components/link-to.js @@ -796,13 +796,7 @@ const LinkComponent = EmberComponent.extend({ params = params.slice(); } - assert('You must provide one or more parameters to the link-to component.', (() => { - if (!params) { - return false; - } - - return params.length; - })()); + assert('You must provide one or more parameters to the link-to component.', params && params.length); let disabledWhen = get(this, 'disabledWhen'); if (disabledWhen !== undefined) { From 723752ab630b10dd16fdc9594b13d0693e62b470 Mon Sep 17 00:00:00 2001 From: karthiick Date: Sat, 17 Jun 2017 01:18:40 +0530 Subject: [PATCH 049/224] Decouple test from the default resolver for initializers_test fix Fixes fix --- .../tests/system/initializers_test.js | 653 ++++++++---------- 1 file changed, 306 insertions(+), 347 deletions(-) diff --git a/packages/ember-application/tests/system/initializers_test.js b/packages/ember-application/tests/system/initializers_test.js index e324e2f4bfe..9054da40cda 100644 --- a/packages/ember-application/tests/system/initializers_test.js +++ b/packages/ember-application/tests/system/initializers_test.js @@ -1,422 +1,381 @@ -import { run } from 'ember-metal'; -import Application from '../../system/application'; +import { assign } from 'ember-utils'; +import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; +import { Application } from 'ember-application'; import { jQuery } from 'ember-views'; -let app; +moduleFor('Ember.Application initializers', class extends AutobootApplicationTestCase { + constructor() { + jQuery('#qunit-fixture').html(` +
ONE
+
TWO
+ `); + super(); + } + + get applicationOptions() { + return assign(super.applicationOptions, { + rootElement: '#one' + }); + } + + createSecondApplication(options, MyApplication=Application) { + let myOptions = assign(this.applicationOptions, { + rootElement: '#two' + }, options); + let secondApp = this.secondApp = MyApplication.create(myOptions); + return secondApp; + } -QUnit.module('Ember.Application initializers', { teardown() { - if (app) { - run(() => app.destroy()); + super.teardown(); + + if (this.secondApp) { + this.runTask(() => this.secondApp.destroy()); } } -}); -QUnit.test('initializers require proper \'name\' and \'initialize\' properties', function() { - let MyApplication = Application.extend(); + [`@test initializers require proper 'name' and 'initialize' properties`]() { + let MyApplication = Application.extend(); - expectAssertion(() => { - run(() => { + expectAssertion(() => { MyApplication.initializer({ name: 'initializer' }); }); - }); - expectAssertion(() => { - run(() => { + expectAssertion(() => { MyApplication.initializer({ initialize() {} }); }); - }); -}); - -QUnit.test('initializers that throw errors cause the boot promise to reject with the error', function() { - QUnit.expect(2); - QUnit.stop(); - - let MyApplication = Application.extend(); - - MyApplication.initializer({ - name: 'initializer', - initialize() { throw new Error('boot failure'); } - }); - - app = MyApplication.create({ - autoboot: false - }); - - try { - app.boot().then( - (app) => { - QUnit.start(); - ok(false, 'The boot promise should not resolve when there is a boot error'); - }, - (err) => { - QUnit.start(); - ok(err instanceof Error, 'The boot promise should reject with an error'); - equal(err.message, 'boot failure'); - } - ); - } catch (e) { - QUnit.start(); - ok(false, 'The boot method should not throw'); - throw e; } -}); -QUnit.test('initializers are passed an App', function() { - let MyApplication = Application.extend(); + [`@test initializers that throw errors cause the boot promise to reject with the error`](assert) { + assert.expect(2); - MyApplication.initializer({ - name: 'initializer', - initialize(App) { - ok(App instanceof Application, 'initialize is passed an Application'); - } - }); + let MyApplication = Application.extend(); - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.initializer({ + name: 'initializer', + initialize() { throw new Error('boot failure'); } }); - }); -}); -QUnit.test('initializers can be registered in a specified order', function() { - let order = []; - let MyApplication = Application.extend(); - MyApplication.initializer({ - name: 'fourth', - after: 'third', - initialize(registry) { - order.push('fourth'); - } - }); - - MyApplication.initializer({ - name: 'second', - after: 'first', - before: 'third', - initialize(registry) { - order.push('second'); - } - }); - - MyApplication.initializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize(registry) { - order.push('fifth'); - } - }); + this.runTask(() => { + this.createApplication({ + autoboot: false + }, MyApplication); + }); - MyApplication.initializer({ - name: 'first', - before: 'second', - initialize(registry) { - order.push('first'); - } - }); + let app = this.application; - MyApplication.initializer({ - name: 'third', - initialize(registry) { - order.push('third'); + try { + this.runTask(() => { + app.boot().then(app => { + assert.ok(false, 'The boot promise should not resolve when there is a boot error'); + }, error => { + assert.ok(error instanceof Error, 'The boot promise should reject with an error'); + assert.equal(error.message, 'boot failure'); + }); + }); + } catch (error) { + assert.ok(false, 'The boot method should not throw'); + throw error; } - }); + } - MyApplication.initializer({ - name: 'sixth', - initialize(registry) { - order.push('sixth'); - } - }); + [`@test initializers are passed an App`](assert) { + let MyApplication = Application.extend(); - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.initializer({ + name: 'initializer', + initialize(App) { + assert.ok(App instanceof Application, 'initialize is passed an Application'); + } }); - }); - deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); -}); + this.runTask(() => this.createApplication({}, MyApplication)); + } -QUnit.test('initializers can be registered in a specified order as an array', function() { - let order = []; - let MyApplication = Application.extend(); + [`@test initializers can be registered in a specified order`](assert) { + let order = []; + let MyApplication = Application.extend(); - MyApplication.initializer({ - name: 'third', - initialize(registry) { - order.push('third'); - } - }); - - MyApplication.initializer({ - name: 'second', - after: 'first', - before: ['third', 'fourth'], - initialize(registry) { - order.push('second'); - } - }); + MyApplication.initializer({ + name: 'fourth', + after: 'third', + initialize(registry) { + order.push('fourth'); + } + }); - MyApplication.initializer({ - name: 'fourth', - after: ['second', 'third'], - initialize(registry) { - order.push('fourth'); - } - }); - - MyApplication.initializer({ - name: 'fifth', - after: 'fourth', - before: 'sixth', - initialize(registry) { - order.push('fifth'); - } - }); + MyApplication.initializer({ + name: 'second', + after: 'first', + before: 'third', + initialize(registry) { + order.push('second'); + } + }); - MyApplication.initializer({ - name: 'first', - before: ['second'], - initialize(registry) { - order.push('first'); - } - }); + MyApplication.initializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize(registry) { + order.push('fifth'); + } + }); - MyApplication.initializer({ - name: 'sixth', - initialize(registry) { - order.push('sixth'); - } - }); + MyApplication.initializer({ + name: 'first', + before: 'second', + initialize(registry) { + order.push('first'); + } + }); - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.initializer({ + name: 'third', + initialize(registry) { + order.push('third'); + } }); - }); - deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); -}); + MyApplication.initializer({ + name: 'sixth', + initialize(registry) { + order.push('sixth'); + } + }); -QUnit.test('initializers can have multiple dependencies', function () { - let order = []; - let a = { - name: 'a', - before: 'b', - initialize(registry) { - order.push('a'); - } - }; - let b = { - name: 'b', - initialize(registry) { - order.push('b'); - } - }; - let c = { - name: 'c', - after: 'b', - initialize(registry) { - order.push('c'); - } - }; - let afterB = { - name: 'after b', - after: 'b', - initialize(registry) { - order.push('after b'); - } - }; - let afterC = { - name: 'after c', - after: 'c', - initialize(registry) { - order.push('after c'); - } - }; - - Application.initializer(b); - Application.initializer(a); - Application.initializer(afterC); - Application.initializer(afterB); - Application.initializer(c); - - run(() => { - app = Application.create({ - router: false, - rootElement: '#qunit-fixture' + this.runTask(() => this.createApplication({}, MyApplication)); + + assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); + } + + [`@test initializers can be registered in a specified order as an array`](assert) { + let order = []; + let MyApplication = Application.extend(); + + MyApplication.initializer({ + name: 'third', + initialize(registry) { + order.push('third'); + } }); - }); - ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); - ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); - ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB'); - ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC'); -}); + MyApplication.initializer({ + name: 'second', + after: 'first', + before: ['third', 'fourth'], + initialize(registry) { + order.push('second'); + } + }); -QUnit.test('initializers set on Application subclasses are not shared between apps', function() { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstApp = Application.extend(); + MyApplication.initializer({ + name: 'fourth', + after: ['second', 'third'], + initialize(registry) { + order.push('fourth'); + } + }); - FirstApp.initializer({ - name: 'first', - initialize(registry) { - firstInitializerRunCount++; - } - }); + MyApplication.initializer({ + name: 'fifth', + after: 'fourth', + before: 'sixth', + initialize(registry) { + order.push('fifth'); + } + }); + + MyApplication.initializer({ + name: 'first', + before: ['second'], + initialize(registry) { + order.push('first'); + } + }); - let SecondApp = Application.extend(); + MyApplication.initializer({ + name: 'sixth', + initialize(registry) { + order.push('sixth'); + } + }); - SecondApp.initializer({ - name: 'second', - initialize(registry) { - secondInitializerRunCount++; - } - }); + this.runTask(() => this.createApplication({}, MyApplication)); + + assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); + } + + [`@test initializers can have multiple dependencies`](assert) { + let order = []; + let MyApplication = Application.extend(); + let a = { + name: 'a', + before: 'b', + initialize(registry) { + order.push('a'); + } + }; + let b = { + name: 'b', + initialize(registry) { + order.push('b'); + } + }; + let c = { + name: 'c', + after: 'b', + initialize(registry) { + order.push('c'); + } + }; + let afterB = { + name: 'after b', + after: 'b', + initialize(registry) { + order.push('after b'); + } + }; + let afterC = { + name: 'after c', + after: 'c', + initialize(registry) { + order.push('after c'); + } + }; + + MyApplication.initializer(b); + MyApplication.initializer(a); + MyApplication.initializer(afterC); + MyApplication.initializer(afterB); + MyApplication.initializer(c); + + this.runTask(() => this.createApplication({}, MyApplication)); - jQuery('#qunit-fixture').html('
'); + assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b'); + assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c'); + assert.ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB'); + assert.ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC'); + } + + [`@test initializers set on Application subclasses are not shared between apps`](assert) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstApp = Application.extend(); - let firstApp = run(() => { - return FirstApp.create({ - router: false, - rootElement: '#qunit-fixture #first' + FirstApp.initializer({ + name: 'first', + initialize(registry) { + firstInitializerRunCount++; + } }); - }); - equal(firstInitializerRunCount, 1, 'first initializer only was run'); - equal(secondInitializerRunCount, 0, 'first initializer only was run'); + let SecondApp = Application.extend(); - let secondApp = run(() => { - return SecondApp.create({ - router: false, - rootElement: '#qunit-fixture #second' + SecondApp.initializer({ + name: 'second', + initialize(registry) { + secondInitializerRunCount++; + } }); - }); - equal(firstInitializerRunCount, 1, 'second initializer only was run'); - equal(secondInitializerRunCount, 1, 'second initializer only was run'); + this.runTask(() => this.createApplication({}, FirstApp)); - run(() => { - firstApp.destroy(); - secondApp.destroy(); - }); -}); + assert.equal(firstInitializerRunCount, 1, 'first initializer only was run'); + assert.equal(secondInitializerRunCount, 0, 'first initializer only was run'); -QUnit.test('initializers are concatenated', function() { - let firstInitializerRunCount = 0; - let secondInitializerRunCount = 0; - let FirstApp = Application.extend(); + this.runTask(() => this.createSecondApplication({}, SecondApp)); - FirstApp.initializer({ - name: 'first', - initialize(registry) { - firstInitializerRunCount++; - } - }); + assert.equal(firstInitializerRunCount, 1, 'second initializer only was run'); + assert.equal(secondInitializerRunCount, 1, 'second initializer only was run'); + } - let SecondApp = FirstApp.extend(); - SecondApp.initializer({ - name: 'second', - initialize(registry) { - secondInitializerRunCount++; - } - }); + [`@test initializers are concatenated`](assert) { + let firstInitializerRunCount = 0; + let secondInitializerRunCount = 0; + let FirstApp = Application.extend(); - jQuery('#qunit-fixture').html('
'); - let firstApp = run(() => { - return FirstApp.create({ - router: false, - rootElement: '#qunit-fixture #first' + FirstApp.initializer({ + name: 'first', + initialize(registry) { + firstInitializerRunCount++; + } }); - }); - equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created'); - equal(secondInitializerRunCount, 0, 'first initializer only was run when base class created'); - firstInitializerRunCount = 0; - - let secondApp = run(() => { - return SecondApp.create({ - router: false, - rootElement: '#qunit-fixture #second' + + let SecondApp = FirstApp.extend(); + SecondApp.initializer({ + name: 'second', + initialize(registry) { + secondInitializerRunCount++; + } }); - }); - - equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created'); - equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created'); - run(() => { - firstApp.destroy(); - secondApp.destroy(); - }); -}); -QUnit.test('initializers are per-app', function() { - expect(2); + this.runTask(() => this.createApplication({}, FirstApp)); - let FirstApp = Application.extend(); + assert.equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created'); + assert.equal(secondInitializerRunCount, 0, 'first initializer only was run when base class created'); - FirstApp.initializer({ - name: 'abc', - initialize(app) {} - }); + firstInitializerRunCount = 0; + this.runTask(() => this.createSecondApplication({}, SecondApp)); + + assert.equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created'); + assert.equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created'); + } + + [`@test initializers are per-app`](assert) { + assert.expect(2); + + let FirstApp = Application.extend(); - expectAssertion(() => { FirstApp.initializer({ name: 'abc', initialize(app) {} }); - }); - let SecondApp = Application.extend(); - SecondApp.instanceInitializer({ - name: 'abc', - initialize(app) {} - }); + expectAssertion(() => { + FirstApp.initializer({ + name: 'abc', + initialize(app) {} + }); + }); - ok(true, 'Two apps can have initializers named the same.'); -}); + let SecondApp = Application.extend(); + SecondApp.instanceInitializer({ + name: 'abc', + initialize(app) {} + }); -QUnit.test('initializers are executed in their own context', function() { - expect(1); - let MyApplication = Application.extend(); + assert.ok(true, 'Two apps can have initializers named the same.'); + } - MyApplication.initializer({ - name: 'coolInitializer', - myProperty: 'cool', - initialize(application) { - equal(this.myProperty, 'cool', 'should have access to its own context'); - } - }); + [`@test initializers are executed in their own context`](assert) { + assert.expect(1); + let MyApplication = Application.extend(); - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' + MyApplication.initializer({ + name: 'coolInitializer', + myProperty: 'cool', + initialize(application) { + assert.equal(this.myProperty, 'cool', 'should have access to its own context'); + } }); - }); -}); -QUnit.test('initializers throw a deprecation warning when receiving a second argument', function() { - expect(1); + this.runTask(() => this.createApplication({}, MyApplication)); + } - let MyApplication = Application.extend(); + [`@test initializers throw a deprecation warning when receiving a second argument`](assert) { + assert.expect(1); - MyApplication.initializer({ - name: 'deprecated', - initialize(registry, application) { - } - }); + let MyApplication = Application.extend(); - expectDeprecation(() => { - run(() => { - app = MyApplication.create({ - router: false, - rootElement: '#qunit-fixture' - }); + MyApplication.initializer({ + name: 'deprecated', + initialize(registry, application) { + } }); - }, /The `initialize` method for Application initializer 'deprecated' should take only one argument - `App`, an instance of an `Application`./); + + expectDeprecation(() => { + this.runTask(() => this.createApplication({}, MyApplication)); + }, /The `initialize` method for Application initializer 'deprecated' should take only one argument - `App`, an instance of an `Application`./); + } }); From 74cfead22b2dfbd63586e1b0fab5e57a4f4cd521 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Fri, 16 Jun 2017 18:57:28 -0700 Subject: [PATCH 050/224] Decouple integration_test from globals resolver --- .../ember-testing/tests/integration_test.js | 165 ++++++++---------- 1 file changed, 68 insertions(+), 97 deletions(-) diff --git a/packages/ember-testing/tests/integration_test.js b/packages/ember-testing/tests/integration_test.js index 27146cc7c3d..c7a83c36e54 100644 --- a/packages/ember-testing/tests/integration_test.js +++ b/packages/ember-testing/tests/integration_test.js @@ -1,120 +1,91 @@ -import { run } from 'ember-metal'; import { - Object as EmberObject, + moduleFor, + AutobootApplicationTestCase +} from 'internal-test-helpers'; +import Test from '../test'; + +import { Controller, A as emberA } from 'ember-runtime'; -import { jQuery } from 'ember-views'; -import Test from '../test'; -import { Route as EmberRoute } from 'ember-routing'; -import { Application as EmberApplication } from 'ember-application'; -import { compile } from 'ember-template-compiler'; -import { setTemplates, setTemplate } from 'ember-glimmer'; - -var App, find, visit; -var originalAdapter = Test.adapter; - -QUnit.module('ember-testing Integration', { - setup() { - jQuery('
').appendTo('body'); - run(function() { - setTemplate('people', compile('
{{#each model as |person|}}
{{person.firstName}}
{{/each}}
')); - setTemplate('application', compile('{{outlet}}')); - - App = EmberApplication.create({ - rootElement: '#ember-testing' - }); +import { Route } from 'ember-routing'; - App.Router.map(function() { - this.route('people', { path: '/' }); - }); +moduleFor('ember-testing Integration tests of acceptance', class extends AutobootApplicationTestCase { - App.PeopleRoute = EmberRoute.extend({ - model() { - return App.Person.find(); - } - }); + constructor() { + super(); - App.PeopleController = Controller.extend({}); + this.modelContent = []; + this._originalAdapter = Test.adapter; - App.Person = EmberObject.extend({ - firstName: '' - }); + this.runTask(() => { + this.createApplication(); + + this.addTemplate('people', ` +
+ {{#each model as |person|}} +
{{person.firstName}}
+ {{/each}} +
+ `); - App.Person.reopenClass({ - find() { - return emberA(); - } + this.router.map(function() { + this.route('people', { path: '/' }); }); - App.setupForTesting(); - }); + this.add('route:people', Route.extend({ + model: () => this.modelContent + })); - run(function() { - App.reset(); + this.application.setupForTesting(); }); - App.injectTestHelpers(); + this.runTask(() => { + this.application.reset(); + }); - find = window.find; - visit = window.visit; - }, + this.application.injectTestHelpers(); + } teardown() { - App.removeTestHelpers(); - setTemplates({}); - jQuery('#ember-testing-container, #ember-testing').remove(); - run(App, App.destroy); - App = null; - Test.adapter = originalAdapter; + super.teardown(); + Test.adapter = this._originalAdapter; } -}); - -QUnit.test('template is bound to empty array of people', function() { - App.Person.find = function() { - return emberA(); - }; - run(App, 'advanceReadiness'); - visit('/').then(function() { - var rows = find('.name').length; - equal(rows, 0, 'successfully stubbed an empty array of people'); - }); -}); -QUnit.test('template is bound to array of 2 people', function() { - App.Person.find = function() { - var people = emberA(); - var first = App.Person.create({ firstName: 'x' }); - var last = App.Person.create({ firstName: 'y' }); - run(people, people.pushObject, first); - run(people, people.pushObject, last); - return people; - }; - run(App, 'advanceReadiness'); - visit('/').then(function() { - var rows = find('.name').length; - equal(rows, 2, 'successfully stubbed a non empty array of people'); - }); -}); + [`@test template is bound to empty array of people`](assert) { + this.runTask(() => this.application.advanceReadiness()); + window.visit('/').then(() => { + let rows = window.find('.name').length; + assert.equal( + rows, 0, + 'successfully stubbed an empty array of people' + ); + }); + } -QUnit.test('template is again bound to empty array of people', function() { - App.Person.find = function() { - return emberA(); - }; - run(App, 'advanceReadiness'); - visit('/').then(function() { - var rows = find('.name').length; - equal(rows, 0, 'successfully stubbed another empty array of people'); - }); -}); + [`@test template is bound to array of 2 people`](assert) { + this.modelContent = emberA([]); + this.modelContent.pushObject({ firstName: 'x' }); + this.modelContent.pushObject({ firstName: 'y' }); + + this.runTask(() => this.application.advanceReadiness()); + window.visit('/').then(() => { + let rows = window.find('.name').length; + assert.equal( + rows, 2, + 'successfully stubbed a non empty array of people' + ); + }); + } -QUnit.test('`visit` can be called without advancedReadiness.', function() { - App.Person.find = function() { - return emberA(); - }; + [`@test 'visit' can be called without advanceReadiness.`](assert) { + window.visit('/').then(() => { + let rows = window.find('.name').length; + assert.equal( + rows, 0, + 'stubbed an empty array of people without calling advanceReadiness.' + ); + }); + } - visit('/').then(function() { - var rows = find('.name').length; - equal(rows, 0, 'stubbed an empty array of people without calling advancedReadiness.'); - }); }); From 71a4dd30059469f07a1a8fc713a98ff2133186eb Mon Sep 17 00:00:00 2001 From: Kelly Selden Date: Tue, 20 Jun 2017 13:59:07 -0700 Subject: [PATCH 051/224] Docs: resetController - add a use for transition I was debating with some folks if the transition belongs in resetController, and for the docs to have a use of it would seem beneficial in understanding. --- packages/ember-routing/lib/system/route.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index 79c11d6c65e..4eccfdd1b5b 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -453,7 +453,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { export default Ember.Route.extend({ resetController(controller, isExiting, transition) { - if (isExiting) { + if (isExiting && transition.targetName !== 'error') { controller.set('page', 1); } } From 14b4fd5d2966df33d5418f28adaa0c47349b1a86 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 20 Jun 2017 23:20:36 -0400 Subject: [PATCH 052/224] Update glimmer-vm packages to 0.25.1. --- package.json | 10 ++--- yarn.lock | 102 +++++++++++++++++++++++++-------------------------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/package.json b/package.json index 2b8c230b569..d59779f59e4 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,11 @@ "link:glimmer": "node bin/yarn-link-glimmer.js" }, "dependencies": { - "@glimmer/compiler": "^0.24.0-beta.4", - "@glimmer/node": "^0.24.0-beta.4", - "@glimmer/reference": "^0.24.0-beta.4", - "@glimmer/runtime": "^0.24.0-beta.4", - "@glimmer/util": "^0.24.0-beta.4", + "@glimmer/compiler": "^0.25.1", + "@glimmer/node": "^0.25.1", + "@glimmer/reference": "^0.25.1", + "@glimmer/runtime": "^0.25.1", + "@glimmer/util": "^0.25.1", "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^2.0.0", "ember-cli-get-component-path-option": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 382be88424a..857fb39ebd3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,78 +2,78 @@ # yarn lockfile v1 -"@glimmer/compiler@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/compiler/-/compiler-0.24.0-beta.4.tgz#d90a16b745eddb14c66787ed64816c3a7e220796" - dependencies: - "@glimmer/interfaces" "^0.24.0-beta.4" - "@glimmer/syntax" "^0.24.0-beta.4" - "@glimmer/util" "^0.24.0-beta.4" - "@glimmer/wire-format" "^0.24.0-beta.4" +"@glimmer/compiler@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/compiler/-/compiler-0.25.1.tgz#81fb9f51349f819525da737ae953a5f8461fdef1" + dependencies: + "@glimmer/interfaces" "^0.25.1" + "@glimmer/syntax" "^0.25.1" + "@glimmer/util" "^0.25.1" + "@glimmer/wire-format" "^0.25.1" simple-html-tokenizer "^0.3.0" -"@glimmer/interfaces@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/interfaces/-/interfaces-0.24.0-beta.4.tgz#c4ee238d22f9d6805328e986326fcaa042843878" +"@glimmer/interfaces@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/interfaces/-/interfaces-0.25.1.tgz#234abbbf7021a73ec576943443768d0e2801ad13" dependencies: - "@glimmer/wire-format" "^0.24.0-beta.4" + "@glimmer/wire-format" "^0.25.1" -"@glimmer/node@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/node/-/node-0.24.0-beta.4.tgz#80947df5f73ad678228bcfb25b76f73aac11526c" +"@glimmer/node@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/node/-/node-0.25.1.tgz#0f5301d7a100cbb37e8252f8e5f28ce4afa470db" dependencies: - "@glimmer/runtime" "^0.24.0-beta.4" + "@glimmer/runtime" "^0.25.1" simple-dom "^0.3.0" -"@glimmer/object-reference@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/object-reference/-/object-reference-0.24.0-beta.4.tgz#0f10ef9f9540f782a9b3d6014b1da4d159557014" +"@glimmer/object-reference@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/object-reference/-/object-reference-0.25.1.tgz#6393deb8d24c6ead90437998eb988207d674142e" dependencies: - "@glimmer/reference" "^0.24.0-beta.4" - "@glimmer/util" "^0.24.0-beta.4" + "@glimmer/reference" "^0.25.1" + "@glimmer/util" "^0.25.1" -"@glimmer/object@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/object/-/object-0.24.0-beta.4.tgz#df272461fcd2abd1736b8eae9e2f10a918d9e4b9" +"@glimmer/object@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/object/-/object-0.25.1.tgz#2611f9deb88d4d33c24d1e8dc57d4ae5c224fc24" dependencies: - "@glimmer/object-reference" "^0.24.0-beta.4" - "@glimmer/util" "^0.24.0-beta.4" + "@glimmer/object-reference" "^0.25.1" + "@glimmer/util" "^0.25.1" -"@glimmer/reference@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/reference/-/reference-0.24.0-beta.4.tgz#17f32cf1a4df3ebf57ca62647fc578b608b9f62d" +"@glimmer/reference@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/reference/-/reference-0.25.1.tgz#5c5a148a7e1f33c3ed425999b8b45d0f7a88aeac" dependencies: - "@glimmer/util" "^0.24.0-beta.4" + "@glimmer/util" "^0.25.1" -"@glimmer/runtime@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/runtime/-/runtime-0.24.0-beta.4.tgz#dd1f525b7545f4ed9ef5d9a2bbe586e3db1d7a55" +"@glimmer/runtime@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/runtime/-/runtime-0.25.1.tgz#ead91cc51a44ff9777fee0a786d32aeb8b8e993a" dependencies: - "@glimmer/interfaces" "^0.24.0-beta.4" - "@glimmer/object" "^0.24.0-beta.4" - "@glimmer/object-reference" "^0.24.0-beta.4" - "@glimmer/reference" "^0.24.0-beta.4" - "@glimmer/util" "^0.24.0-beta.4" - "@glimmer/wire-format" "^0.24.0-beta.4" + "@glimmer/interfaces" "^0.25.1" + "@glimmer/object" "^0.25.1" + "@glimmer/object-reference" "^0.25.1" + "@glimmer/reference" "^0.25.1" + "@glimmer/util" "^0.25.1" + "@glimmer/wire-format" "^0.25.1" -"@glimmer/syntax@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/syntax/-/syntax-0.24.0-beta.4.tgz#4e61c912f0f45c43175a178390630da637138e35" +"@glimmer/syntax@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/syntax/-/syntax-0.25.1.tgz#05bbc219af98adc447195d4d74bba6fb9f5fd3d5" dependencies: - "@glimmer/interfaces" "^0.24.0-beta.4" - "@glimmer/util" "^0.24.0-beta.4" + "@glimmer/interfaces" "^0.25.1" + "@glimmer/util" "^0.25.1" handlebars "^4.0.6" simple-html-tokenizer "^0.3.0" -"@glimmer/util@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.24.0-beta.4.tgz#d49063e432e2fd2af7bdc1422d3b0d849e6ce328" +"@glimmer/util@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.25.1.tgz#bdc669de4cae562eb797fb29714da4d290ec58c1" -"@glimmer/wire-format@^0.24.0-beta.4": - version "0.24.0-beta.4" - resolved "https://registry.yarnpkg.com/@glimmer/wire-format/-/wire-format-0.24.0-beta.4.tgz#793acc653e2b718b5052f59943604c0317995b75" +"@glimmer/wire-format@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@glimmer/wire-format/-/wire-format-0.25.1.tgz#cd69f3595a08954fa68a3f1df4feafffa1c3f3de" dependencies: - "@glimmer/util" "^0.24.0-beta.4" + "@glimmer/util" "^0.25.1" abbrev@1, abbrev@~1.0.9: version "1.0.9" From 04e560a5bfac17cabc97389775b31b27cd91b44a Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 21 Jun 2017 00:11:00 -0400 Subject: [PATCH 053/224] Update AST transform plugins to new syntax. --- .../assert-reserved-named-arguments.js | 25 ++-- .../lib/plugins/deprecate-render-model.js | 56 +++---- .../lib/plugins/deprecate-render.js | 53 +++---- .../lib/plugins/extract-pragma-tag.js | 22 +-- .../lib/plugins/index.js | 2 - .../lib/plugins/transform-action-syntax.js | 56 ++++--- .../transform-angle-bracket-components.js | 34 ++--- .../lib/plugins/transform-attrs-into-args.js | 66 ++++---- .../transform-dot-component-invocation.js | 66 ++++---- .../plugins/transform-each-in-into-each.js | 37 ++--- .../lib/plugins/transform-has-block-syntax.js | 54 +++---- .../lib/plugins/transform-inline-link-to.js | 75 +++++----- .../plugins/transform-input-on-to-onEvent.js | 141 ++++++++---------- .../plugins/transform-input-type-syntax.js | 30 ++-- .../lib/plugins/transform-item-class.js | 36 ----- .../plugins/transform-old-binding-syntax.js | 68 ++++----- .../transform-old-class-binding-syntax.js | 102 ++++++------- ...form-quoted-bindings-into-just-bindings.js | 35 ++--- .../plugins/transform-top-level-components.js | 30 ++-- 19 files changed, 415 insertions(+), 573 deletions(-) delete mode 100644 packages/ember-template-compiler/lib/plugins/transform-item-class.js diff --git a/packages/ember-template-compiler/lib/plugins/assert-reserved-named-arguments.js b/packages/ember-template-compiler/lib/plugins/assert-reserved-named-arguments.js index 6f839df26b3..4a8f0d807eb 100644 --- a/packages/ember-template-compiler/lib/plugins/assert-reserved-named-arguments.js +++ b/packages/ember-template-compiler/lib/plugins/assert-reserved-named-arguments.js @@ -1,24 +1,21 @@ import { assert } from 'ember-debug'; import calculateLocationDisplay from '../system/calculate-location-display'; -export default function AssertReservedNamedArguments(options) { - this.syntax = null; - this.options = options; -} +export default function assertReservedNamedArguments(env) { + let { moduleName } = env.meta; -AssertReservedNamedArguments.prototype.transform = function AssertReservedNamedArguments_transform(ast) { - let moduleName = this.options.meta.moduleName; + return { + name: 'assert-reserved-named-arguments', - this.syntax.traverse(ast, { - PathExpression(node) { - if (node.original[0] === '@') { - assert(assertMessage(moduleName, node)); + visitors: { + PathExpression(node) { + if (node.original[0] === '@') { + assert(assertMessage(moduleName, node)); + } } } - }); - - return ast; -}; + } +} function assertMessage(moduleName, node) { let path = node.original; diff --git a/packages/ember-template-compiler/lib/plugins/deprecate-render-model.js b/packages/ember-template-compiler/lib/plugins/deprecate-render-model.js index 8a305deeb20..d8b53fb4ec3 100644 --- a/packages/ember-template-compiler/lib/plugins/deprecate-render-model.js +++ b/packages/ember-template-compiler/lib/plugins/deprecate-render-model.js @@ -2,41 +2,27 @@ import { deprecate } from 'ember-debug'; import calculateLocationDisplay from '../system/calculate-location-display'; -export default function DeprecateRenderModel(options) { - this.syntax = null; - this.options = options; -} - -DeprecateRenderModel.prototype.transform = function DeprecateRenderModel_transform(ast) { - let moduleName = this.options.meta.moduleName; - let walker = new this.syntax.Walker(); - - walker.visit(ast, node => { - if (!validate(node)) { return; } - - each(node.params, (param) => { - if (param.type !== 'PathExpression') { return; } - - deprecate(deprecationMessage(moduleName, node, param), false, { - id: 'ember-template-compiler.deprecate-render-model', - until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x#toc_model-param-in-code-render-code-helper' - }); - }); - }); - - return ast; -}; - -function validate(node) { - return (node.type === 'MustacheStatement') && - (node.path.original === 'render') && - (node.params.length > 1); -} - -function each(list, callback) { - for (let i = 0, l = list.length; i < l; i++) { - callback(list[i]); +export default function deprecateRenderModel(env) { + let { moduleName } = env.meta; + + return { + name: 'deprecate-render-model', + + visitors: { + MustacheStatement(node) { + if (node.path.original === 'render' && node.params.length > 1) { + node.params.forEach(param => { + if (param.type !== 'PathExpression') { return; } + + deprecate(deprecationMessage(moduleName, node, param), false, { + id: 'ember-template-compiler.deprecate-render-model', + until: '3.0.0', + url: 'https://emberjs.com/deprecations/v2.x#toc_model-param-in-code-render-code-helper' + }); + }); + } + } + } } } diff --git a/packages/ember-template-compiler/lib/plugins/deprecate-render.js b/packages/ember-template-compiler/lib/plugins/deprecate-render.js index 8d11f5c8c6b..69cc74e0a24 100644 --- a/packages/ember-template-compiler/lib/plugins/deprecate-render.js +++ b/packages/ember-template-compiler/lib/plugins/deprecate-render.js @@ -1,36 +1,29 @@ import { deprecate } from 'ember-debug'; import calculateLocationDisplay from '../system/calculate-location-display'; -export default function DeprecateRender(options) { - this.syntax = null; - this.options = options; -} - -DeprecateRender.prototype.transform = function DeprecateRender_transform(ast) { - let moduleName = this.options.meta.moduleName; - let walker = new this.syntax.Walker(); - - walker.visit(ast, node => { - if (!validate(node)) { return; } - - each(node.params, (param) => { - if (param.type !== 'StringLiteral') { return; } - - deprecate(deprecationMessage(moduleName, node), false, { - id: 'ember-template-compiler.deprecate-render', - until: '3.0.0', - url: 'https://emberjs.com/deprecations/v2.x#toc_code-render-code-helper' - }); - }); - }); - - return ast; -}; - -function validate(node) { - return (node.type === 'MustacheStatement') && - (node.path.original === 'render') && - (node.params.length === 1); +export default function deprecateRender(env) { + let { moduleName } = env.meta; + + return { + name: 'deprecate-render', + + visitors: { + MustacheStatement(node) { + if (node.path.original !== 'render') { return; } + if (node.params.length !== 1) { return; } + + each(node.params, (param) => { + if (param.type !== 'StringLiteral') { return; } + + deprecate(deprecationMessage(moduleName, node), false, { + id: 'ember-template-compiler.deprecate-render', + until: '3.0.0', + url: 'https://emberjs.com/deprecations/v2.x#toc_code-render-code-helper' + }); + }); + } + } + }; } function each(list, callback) { diff --git a/packages/ember-template-compiler/lib/plugins/extract-pragma-tag.js b/packages/ember-template-compiler/lib/plugins/extract-pragma-tag.js index 479a20ad5f8..f0cd7183712 100644 --- a/packages/ember-template-compiler/lib/plugins/extract-pragma-tag.js +++ b/packages/ember-template-compiler/lib/plugins/extract-pragma-tag.js @@ -1,26 +1,20 @@ const PRAGMA_TAG = 'use-component-manager'; -// Custom Glimmer AST transform to extract custom component -// manager id from the template -export default class ExtractPragmaPlugin { - constructor(options) { - this.options = options; - } +export default function extractPragmaTag(env) { + let { meta } = env; - transform(ast) { - let options = this.options; + return { + name: 'exract-pragma-tag', - this.syntax.traverse(ast, { + visitors: { MustacheStatement: { enter(node) { if (node.path.type === 'PathExpression' && node.path.original === PRAGMA_TAG) { - options.meta.managerId = node.params[0].value; + meta.managerId = node.params[0].value; return null; } } } - }); - - return ast; - } + } + }; } diff --git a/packages/ember-template-compiler/lib/plugins/index.js b/packages/ember-template-compiler/lib/plugins/index.js index ebac057e0be..eda3b4dc3ab 100644 --- a/packages/ember-template-compiler/lib/plugins/index.js +++ b/packages/ember-template-compiler/lib/plugins/index.js @@ -1,5 +1,4 @@ import TransformOldBindingSyntax from './transform-old-binding-syntax'; -import TransformItemClass from './transform-item-class'; import TransformAngleBracketComponents from './transform-angle-bracket-components'; import TransformInputOnToOnEvent from './transform-input-on-to-onEvent'; import TransformTopLevelComponents from './transform-top-level-components'; @@ -23,7 +22,6 @@ import { const transforms = [ TransformDotComponentInvocation, TransformOldBindingSyntax, - TransformItemClass, TransformAngleBracketComponents, TransformInputOnToOnEvent, TransformTopLevelComponents, diff --git a/packages/ember-template-compiler/lib/plugins/transform-action-syntax.js b/packages/ember-template-compiler/lib/plugins/transform-action-syntax.js index 2a26a0c14d4..987071af96b 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-action-syntax.js +++ b/packages/ember-template-compiler/lib/plugins/transform-action-syntax.js @@ -24,39 +24,33 @@ @class TransformActionSyntax */ -export default function TransformActionSyntax() { - // set later within Glimmer2 to the syntax package - this.syntax = null; -} - -/** - @private - @method transform - @param {AST} ast The AST to be transformed. -*/ -TransformActionSyntax.prototype.transform = function TransformActionSyntax_transform(ast) { - let { traverse, builders: b } = this.syntax; - - traverse(ast, { - ElementModifierStatement(node) { - if (isAction(node)) { - insertThisAsFirstParam(node, b); - } - }, - MustacheStatement(node) { - if (isAction(node)) { - insertThisAsFirstParam(node, b); - } - }, - SubExpression(node) { - if (isAction(node)) { - insertThisAsFirstParam(node, b); +export default function transformActionSyntax({ syntax }) { + let { builders: b } = syntax; + + return { + name: 'transform-action-syntax', + + visitors: { + ElementModifierStatement(node) { + if (isAction(node)) { + insertThisAsFirstParam(node, b); + } + }, + + MustacheStatement(node) { + if (isAction(node)) { + insertThisAsFirstParam(node, b); + } + }, + + SubExpression(node) { + if (isAction(node)) { + insertThisAsFirstParam(node, b); + } } } - }); - - return ast; -}; + }; +} function isAction(node) { return node.path.original === 'action'; diff --git a/packages/ember-template-compiler/lib/plugins/transform-angle-bracket-components.js b/packages/ember-template-compiler/lib/plugins/transform-angle-bracket-components.js index aad24be3653..46ea0d3662b 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-angle-bracket-components.js +++ b/packages/ember-template-compiler/lib/plugins/transform-angle-bracket-components.js @@ -1,25 +1,11 @@ -export default function TransformAngleBracketComponents() { - // set later within HTMLBars to the syntax package - this.syntax = null; -} - -/** - @private - @method transform - @param {AST} ast The AST to be transformed. -*/ -TransformAngleBracketComponents.prototype.transform = function TransformAngleBracketComponents_transform(ast) { - let walker = new this.syntax.Walker(); - - walker.visit(ast, node => { - if (!validate(node)) { return; } - - node.tag = `<${node.tag}>`; - }); - - return ast; -}; - -function validate(node) { - return node.type === 'ComponentNode'; +export default function transformAngleBracketComponents(env) { + return { + name: 'transform-angle-bracket-components', + + visitors: { + ComponentNode(node) { + node.tag = `<${node.tag}>`; + } + } + }; } diff --git a/packages/ember-template-compiler/lib/plugins/transform-attrs-into-args.js b/packages/ember-template-compiler/lib/plugins/transform-attrs-into-args.js index 94d4be94f51..0271af8d09c 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-attrs-into-args.js +++ b/packages/ember-template-compiler/lib/plugins/transform-attrs-into-args.js @@ -23,9 +23,35 @@ @class TransformAttrsToProps */ -export default function TransformAttrsToProps() { - // set later within Glimmer2 to the syntax package - this.syntax = null; +export default function transformAttrsIntoArgs(env) { + let { builders: b } = env.syntax; + + let stack = [[]]; + + return { + name: 'transform-attrs-into-args', + + visitors: { + Program: { + enter(node) { + let parent = stack[stack.length - 1]; + stack.push(parent.concat(node.blockParams)); + }, + exit(node) { + stack.pop(); + } + }, + + PathExpression(node) { + if (isAttrs(node, stack[stack.length - 1])) { + let path = b.path(node.original.substr(6)); + path.original = `@${path.original}`; + path.data = true; + return path; + } + } + } + }; } function isAttrs(node, symbols) { @@ -46,37 +72,3 @@ function isAttrs(node, symbols) { return false; } - -/** - @private - @method transform - @param {AST} ast The AST to be transformed. -*/ -TransformAttrsToProps.prototype.transform = function TransformAttrsToProps_transform(ast) { - let { traverse, builders: b } = this.syntax; - - let stack = [[]]; - - traverse(ast, { - Program: { - enter(node) { - let parent = stack[stack.length - 1]; - stack.push(parent.concat(node.blockParams)); - }, - exit(node) { - stack.pop(); - } - }, - - PathExpression(node) { - if (isAttrs(node, stack[stack.length - 1])) { - let path = b.path(node.original.substr(6)); - path.original = `@${path.original}`; - path.data = true; - return path; - } - } - }); - - return ast; -}; diff --git a/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js b/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js index a63a9b97a4a..1f6f3c31e46 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js +++ b/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js @@ -52,50 +52,44 @@ @private @class TransFormDotComponentInvocation */ -export default function TransFormDotComponentInvocation() { - // set later within Glimmer2 to the syntax package - this.syntax = null; -} - -TransFormDotComponentInvocation.prototype = { - _isMulipartPath(path) { - return path.parts.length > 1; - }, - - _isInlineInvocation(path, params, hash) { - if (this._isMulipartPath(path)) { - if (params.length > 0 || hash.pairs.length > 0) { - return true; - } - } - - return false; - }, +export default function transformDotComponentInvocation(env) { + let { builders: b } = env.syntax; - _wrapInComponent(node, builder) { - let component = node.path; - let componentHelper = builder.path('component'); - node.path = componentHelper; - node.params.unshift(component); - }, + return { + name: 'transform-dot-component-invocation', - transform(ast) { - let { traverse, builders: b } = this.syntax; - - traverse(ast, { + visitors: { MustacheStatement: (node) => { - if (this._isInlineInvocation(node.path, node.params, node.hash)) { - this._wrapInComponent(node, b); + if (isInlineInvocation(node.path, node.params, node.hash)) { + wrapInComponent(node, b); } }, BlockStatement: (node) => { - if (this._isMulipartPath(node.path)) { - this._wrapInComponent(node, b) + if (isMulipartPath(node.path)) { + wrapInComponent(node, b) } } - }); + } + } +} + +function isMulipartPath(path) { + return path.parts.length > 1; +} - return ast; +function isInlineInvocation(path, params, hash) { + if (isMulipartPath(path)) { + if (params.length > 0 || hash.pairs.length > 0) { + return true; + } } -}; + return false; +} + +function wrapInComponent(node, builder) { + let component = node.path; + let componentHelper = builder.path('component'); + node.path = componentHelper; + node.params.unshift(component); +} diff --git a/packages/ember-template-compiler/lib/plugins/transform-each-in-into-each.js b/packages/ember-template-compiler/lib/plugins/transform-each-in-into-each.js index e9051ea442f..b2b89628c2c 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-each-in-into-each.js +++ b/packages/ember-template-compiler/lib/plugins/transform-each-in-into-each.js @@ -19,28 +19,19 @@ @private @class TransformHasBlockSyntax */ - -export default function TransformEachInIntoEach() { - // set later within Glimmer2 to the syntax package - this.syntax = null; -} - -/** - @private - @method transform - @param {AST} ast The AST to be transformed. -*/ -TransformEachInIntoEach.prototype.transform = function TransformEachInIntoEach_transform(ast) { - let { traverse, builders: b } = this.syntax; - - traverse(ast, { - BlockStatement(node) { - if (node.path.original === 'each-in') { - node.params[0] = b.sexpr(b.path('-each-in'), [node.params[0]]); - return b.block(b.path('each'), node.params, node.hash, node.program, node.inverse, node.loc); +export default function transformEachInIntoEach(env) { + let { builders: b } = env.syntax; + + return { + name: 'transform-each-in-into-each', + + visitors: { + BlockStatement(node) { + if (node.path.original === 'each-in') { + node.params[0] = b.sexpr(b.path('-each-in'), [node.params[0]]); + return b.block(b.path('each'), node.params, node.hash, node.program, node.inverse, node.loc); + } } } - }); - - return ast; -}; + }; +} diff --git a/packages/ember-template-compiler/lib/plugins/transform-has-block-syntax.js b/packages/ember-template-compiler/lib/plugins/transform-has-block-syntax.js index 6482b4e29aa..a3d0f8facd1 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-has-block-syntax.js +++ b/packages/ember-template-compiler/lib/plugins/transform-has-block-syntax.js @@ -20,41 +20,33 @@ @class TransformHasBlockSyntax */ -export default function TransformHasBlockSyntax() { - // set later within Glimmer2 to the syntax package - this.syntax = null; -} - const TRANSFORMATIONS = { hasBlock: 'has-block', hasBlockParams: 'has-block-params' }; -/** - @private - @method transform - @param {AST} ast The AST to be transformed. -*/ -TransformHasBlockSyntax.prototype.transform = function TransformHasBlockSyntax_transform(ast) { - let { traverse, builders: b } = this.syntax; - - traverse(ast, { - PathExpression(node) { - if (TRANSFORMATIONS[node.original]) { - return b.sexpr(b.path(TRANSFORMATIONS[node.original])); - } - }, - MustacheStatement(node) { - if (TRANSFORMATIONS[node.path.original]) { - return b.mustache(b.path(TRANSFORMATIONS[node.path.original]), node.params, node.hash, null, node.loc); - } - }, - SubExpression(node) { - if (TRANSFORMATIONS[node.path.original]) { - return b.sexpr(b.path(TRANSFORMATIONS[node.path.original]), node.params, node.hash); +export default function transformHasBlockSyntax(env) { + let { builders: b } = env.syntax; + + return { + name: 'transform-has-block-syntax', + + visitors: { + PathExpression(node) { + if (TRANSFORMATIONS[node.original]) { + return b.sexpr(b.path(TRANSFORMATIONS[node.original])); + } + }, + MustacheStatement(node) { + if (TRANSFORMATIONS[node.path.original]) { + return b.mustache(b.path(TRANSFORMATIONS[node.path.original]), node.params, node.hash, null, node.loc); + } + }, + SubExpression(node) { + if (TRANSFORMATIONS[node.path.original]) { + return b.sexpr(b.path(TRANSFORMATIONS[node.path.original]), node.params, node.hash); + } } } - }); - - return ast; -}; + } +} diff --git a/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js b/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js index 122f59e8f76..15c6829687a 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js +++ b/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js @@ -1,48 +1,45 @@ -export default function TransformInlineLinkTo(options) { - this.options = options; - this.syntax = null; +function buildProgram(b, content, loc) { + return b.program([buildStatement(b, content, loc)], null, loc); } -TransformInlineLinkTo.prototype.transform = function TransformInlineLinkTo_transform(ast) { - let { traverse, builders: b } = this.syntax; +function buildStatement(b, content, loc) { + switch (content.type) { + case 'PathExpression': + return b.mustache(content, null, null, null, loc); - function buildProgram(content, loc) { - return b.program([buildStatement(content, loc)], null, loc); - } - - function buildStatement(content, loc) { - switch (content.type) { - case 'PathExpression': - return b.mustache(content, null, null, null, loc); - - case 'SubExpression': - return b.mustache(content.path, content.params, content.hash, null, loc); + case 'SubExpression': + return b.mustache(content.path, content.params, content.hash, null, loc); - // The default case handles literals. - default: - return b.text(`${content.value}`, loc); - } + // The default case handles literals. + default: + return b.text(`${content.value}`, loc); } +} - function unsafeHtml(expr) { - return b.sexpr('-html-safe', [expr]); - } +function unsafeHtml(b, expr) { + return b.sexpr('-html-safe', [expr]); +} - traverse(ast, { - MustacheStatement(node) { - if (node.path.original === 'link-to') { - let content = node.escaped ? node.params[0] : unsafeHtml(node.params[0]); - return b.block( - 'link-to', - node.params.slice(1), - node.hash, - buildProgram(content, node.loc), - null, - node.loc - ); +export default function transformInlineLinkTo(env) { + let { builders: b } = env.syntax; + + return { + name: 'transform-inline-link-to', + + visitors: { + MustacheStatement(node) { + if (node.path.original === 'link-to') { + let content = node.escaped ? node.params[0] : unsafeHtml(b, node.params[0]); + return b.block( + 'link-to', + node.params.slice(1), + node.hash, + buildProgram(b, content, node.loc), + null, + node.loc + ); + } } } - }); - - return ast; -}; + }; +} diff --git a/packages/ember-template-compiler/lib/plugins/transform-input-on-to-onEvent.js b/packages/ember-template-compiler/lib/plugins/transform-input-on-to-onEvent.js index f92e23f21f5..2a125593c5c 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-input-on-to-onEvent.js +++ b/packages/ember-template-compiler/lib/plugins/transform-input-on-to-onEvent.js @@ -24,93 +24,82 @@ import calculateLocationDisplay from '../system/calculate-location-display'; @private @class TransformInputOnToOnEvent */ -export default function TransformInputOnToOnEvent(options = {}) { - // set later within HTMLBars to the syntax package - this.syntax = null; - this.options = options; -} +export default function transformInputOnToOnEvent(env) { + let b = env.syntax.builders; + let { moduleName } = env.meta; -/** - @private - @method transform - @param {AST} ast The AST to be transformed. -*/ -TransformInputOnToOnEvent.prototype.transform = function TransformInputOnToOnEvent_transform(ast) { - let pluginContext = this; - let b = pluginContext.syntax.builders; - let walker = new pluginContext.syntax.Walker(); - let moduleName = pluginContext.options.meta.moduleName; - - walker.visit(ast, function(node) { - if (pluginContext.validate(node)) { - let action = hashPairForKey(node.hash, 'action'); - let on = hashPairForKey(node.hash, 'on'); - let onEvent = hashPairForKey(node.hash, 'onEvent'); - let normalizedOn = on || onEvent; - let moduleInfo = calculateLocationDisplay(moduleName, node.loc); - - if (normalizedOn && normalizedOn.value.type !== 'StringLiteral') { - deprecate( - `Using a dynamic value for '#{normalizedOn.key}=' with the '{{input}}' helper ${moduleInfo}is deprecated.`, - false, - { id: 'ember-template-compiler.transform-input-on-to-onEvent.dynamic-value', until: '3.0.0' } - ); + return { + name: 'transform-input-on-to-onEvent', - normalizedOn.key = 'onEvent'; - return; // exit early, as we cannot transform further - } + visitors: { + MustacheStatement(node) { + if (node.path.original !== 'input') { + return; + } - removeFromHash(node.hash, normalizedOn); - removeFromHash(node.hash, action); + let action = hashPairForKey(node.hash, 'action'); + let on = hashPairForKey(node.hash, 'on'); + let onEvent = hashPairForKey(node.hash, 'onEvent'); - if (!action) { - deprecate( - `Using '{{input ${normalizedOn.key}="${normalizedOn.value.value}" ...}}' without specifying an action ${moduleInfo}will do nothing.`, - false, - { id: 'ember-template-compiler.transform-input-on-to-onEvent.no-action', until: '3.0.0' } - ); + if (!action && !on && !onEvent) { + return; + } - return; // exit early, if no action was available there is nothing to do - } + let normalizedOn = on || onEvent; + let moduleInfo = calculateLocationDisplay(moduleName, node.loc); - let specifiedOn = normalizedOn ? `${normalizedOn.key}="${normalizedOn.value.value}" ` : ''; - if (normalizedOn && normalizedOn.value.value === 'keyPress') { - // using `keyPress` in the root of the component will - // clobber the keyPress event handler - normalizedOn.value.value = 'key-press'; - } + if (normalizedOn && normalizedOn.value.type !== 'StringLiteral') { + deprecate( + `Using a dynamic value for '#{normalizedOn.key}=' with the '{{input}}' helper ${moduleInfo}is deprecated.`, + false, + { id: 'ember-template-compiler.transform-input-on-to-onEvent.dynamic-value', until: '3.0.0' } + ); - let expected = `${normalizedOn ? normalizedOn.value.value : 'enter'}="${action.value.original}"`; + normalizedOn.key = 'onEvent'; + return; // exit early, as we cannot transform further + } - deprecate( - `Using '{{input ${specifiedOn}action="${action.value.original}"}}' ${moduleInfo}is deprecated. Please use '{{input ${expected}}}' instead.`, - false, - { id: 'ember-template-compiler.transform-input-on-to-onEvent.normalized-on', until: '3.0.0' } - ); - if (!normalizedOn) { - normalizedOn = b.pair('onEvent', b.string('enter')); - } + removeFromHash(node.hash, normalizedOn); + removeFromHash(node.hash, action); + + if (!action) { + deprecate( + `Using '{{input ${normalizedOn.key}="${normalizedOn.value.value}" ...}}' without specifying an action ${moduleInfo}will do nothing.`, + false, + { id: 'ember-template-compiler.transform-input-on-to-onEvent.no-action', until: '3.0.0' } + ); + + return; // exit early, if no action was available there is nothing to do + } + + + let specifiedOn = normalizedOn ? `${normalizedOn.key}="${normalizedOn.value.value}" ` : ''; + if (normalizedOn && normalizedOn.value.value === 'keyPress') { + // using `keyPress` in the root of the component will + // clobber the keyPress event handler + normalizedOn.value.value = 'key-press'; + } - node.hash.pairs.push(b.pair( - normalizedOn.value.value, - action.value - )); + let expected = `${normalizedOn ? normalizedOn.value.value : 'enter'}="${action.value.original}"`; + + deprecate( + `Using '{{input ${specifiedOn}action="${action.value.original}"}}' ${moduleInfo}is deprecated. Please use '{{input ${expected}}}' instead.`, + false, + { id: 'ember-template-compiler.transform-input-on-to-onEvent.normalized-on', until: '3.0.0' } + ); + if (!normalizedOn) { + normalizedOn = b.pair('onEvent', b.string('enter')); + } + + node.hash.pairs.push(b.pair( + normalizedOn.value.value, + action.value + )); + } } - }); - - return ast; -}; - -TransformInputOnToOnEvent.prototype.validate = function TransformWithAsToHash_validate(node) { - return node.type === 'MustacheStatement' && - node.path.original === 'input' && - ( - hashPairForKey(node.hash, 'action') || - hashPairForKey(node.hash, 'on') || - hashPairForKey(node.hash, 'onEvent') - ); -}; + }; +} function hashPairForKey(hash, key) { for (let i = 0; i < hash.pairs.length; i++) { diff --git a/packages/ember-template-compiler/lib/plugins/transform-input-type-syntax.js b/packages/ember-template-compiler/lib/plugins/transform-input-type-syntax.js index 8085dea48a5..00e8f3d3958 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-input-type-syntax.js +++ b/packages/ember-template-compiler/lib/plugins/transform-input-type-syntax.js @@ -24,29 +24,21 @@ @class TransformInputTypeSyntax */ -export default function TransformInputTypeSyntax() { - // set later within Glimmer2 to the syntax package - this.syntax = null; -} +export default function transformInputTypeSyntax(env) { + let b = env.syntax.builders; -/** - @private - @method transform - @param {AST} ast The AST to be transformed. -*/ -TransformInputTypeSyntax.prototype.transform = function TransformInputTypeSyntax_transform(ast) { - let { traverse, builders: b } = this.syntax; + return { + name: 'transform-input-type-syntax', - traverse(ast, { - MustacheStatement(node) { - if (isInput(node)) { - insertTypeHelperParameter(node, b); + visitors: { + MustacheStatement(node) { + if (isInput(node)) { + insertTypeHelperParameter(node, b); + } } } - }); - - return ast; -}; + }; +} function isInput(node) { return node.path.original === 'input'; diff --git a/packages/ember-template-compiler/lib/plugins/transform-item-class.js b/packages/ember-template-compiler/lib/plugins/transform-item-class.js deleted file mode 100644 index 2df50e01656..00000000000 --- a/packages/ember-template-compiler/lib/plugins/transform-item-class.js +++ /dev/null @@ -1,36 +0,0 @@ -export default function TransformItemClass() { - this.syntax = null; -} - -TransformItemClass.prototype.transform = function TransformItemClass_transform(ast) { - let b = this.syntax.builders; - let walker = new this.syntax.Walker(); - - walker.visit(ast, node => { - if (!validate(node)) { return; } - - for (let i = 0; i < node.hash.pairs.length; i++) { - let pair = node.hash.pairs[i]; - let { key, value } = pair; - - if (key !== 'itemClass') { return; } - if (value.type === 'StringLiteral') { return; } - - let propName = value.original; - let params = [value]; - let sexprParams = [b.string(propName), b.path(propName)]; - - params.push(b.sexpr(b.string('-normalize-class'), sexprParams)); - let sexpr = b.sexpr(b.string('if'), params); - - pair.value = sexpr; - } - }); - - return ast; -}; - -function validate(node) { - return (node.type === 'BlockStatement' || node.type === 'MustacheStatement') && - node.path.original === 'collection'; -} diff --git a/packages/ember-template-compiler/lib/plugins/transform-old-binding-syntax.js b/packages/ember-template-compiler/lib/plugins/transform-old-binding-syntax.js index f26fad63133..72dc067b41f 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-old-binding-syntax.js +++ b/packages/ember-template-compiler/lib/plugins/transform-old-binding-syntax.js @@ -1,51 +1,51 @@ import { assert, deprecate } from 'ember-debug'; import calculateLocationDisplay from '../system/calculate-location-display'; -export default function TransformOldBindingSyntax(options) { - this.syntax = null; - this.options = options; -} +export default function transformOldBindingSyntax(env) { + let { moduleName } = env.meta; + let b = env.syntax.builders; + + return { + name: 'transform-old-binding-syntax', -TransformOldBindingSyntax.prototype.transform = function TransformOldBindingSyntax_transform(ast) { - let moduleName = this.options.meta.moduleName; - let b = this.syntax.builders; - let walker = new this.syntax.Walker(); + visitors: { + BlockStatement(node) { + processHash(b, node, moduleName); + }, - walker.visit(ast, node => { - if (!validate(node)) { return; } + MustacheStatement(node) { + processHash(b, node, moduleName); + } + } + }; +} - for (let i = 0; i < node.hash.pairs.length; i++) { - let pair = node.hash.pairs[i]; - let { key, value } = pair; +function processHash(b, node, moduleName) { + for (let i = 0; i < node.hash.pairs.length; i++) { + let pair = node.hash.pairs[i]; + let { key, value } = pair; - let sourceInformation = calculateLocationDisplay(moduleName, pair.loc); + let sourceInformation = calculateLocationDisplay(moduleName, pair.loc); - if (key === 'classBinding') { return; } + if (key === 'classBinding') { return; } - assert(`Setting 'attributeBindings' via template helpers is not allowed ${sourceInformation}`, key !== 'attributeBindings'); + assert(`Setting 'attributeBindings' via template helpers is not allowed ${sourceInformation}`, key !== 'attributeBindings'); - if (key.substr(-7) === 'Binding') { - let newKey = key.slice(0, -7); + if (key.substr(-7) === 'Binding') { + let newKey = key.slice(0, -7); - deprecate( - `You're using legacy binding syntax: ${key}=${exprToString(value)} ${sourceInformation}. Please replace with ${newKey}=${value.original}`, - false, - { id: 'ember-template-compiler.transform-old-binding-syntax', until: '3.0.0' } - ); + deprecate( + `You're using legacy binding syntax: ${key}=${exprToString(value)} ${sourceInformation}. Please replace with ${newKey}=${value.original}`, + false, + { id: 'ember-template-compiler.transform-old-binding-syntax', until: '3.0.0' } + ); - pair.key = newKey; - if (value.type === 'StringLiteral') { - pair.value = b.path(value.original); - } + pair.key = newKey; + if (value.type === 'StringLiteral') { + pair.value = b.path(value.original); } } - }); - - return ast; -}; - -function validate(node) { - return (node.type === 'BlockStatement' || node.type === 'MustacheStatement'); + } } function exprToString(expr) { diff --git a/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.js b/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.js index 8a7a87660a4..a1bff353aee 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.js +++ b/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.js @@ -1,66 +1,70 @@ -export default function TransformOldClassBindingSyntax(options) { - this.syntax = null; - this.options = options; -} - -TransformOldClassBindingSyntax.prototype.transform = function TransformOldClassBindingSyntax_transform(ast) { - let b = this.syntax.builders; - let walker = new this.syntax.Walker(); +export default function transformOldClassBindingSyntax(env) { + let b = env.syntax.builders; - walker.visit(ast, node => { - if (!validate(node)) { return; } + return { + name: 'transform-old-class-binding-syntax', - let allOfTheMicrosyntaxes = []; - let allOfTheMicrosyntaxIndexes = []; - let classPair; + visitors: { + MustacheStatement(node) { + process(b, node); + }, - each(node.hash.pairs, (pair, index) => { - let { key } = pair; - - if (key === 'classBinding' || key === 'classNameBindings') { - allOfTheMicrosyntaxIndexes.push(index); - allOfTheMicrosyntaxes.push(pair); - } else if (key === 'class') { - classPair = pair; + BlockStatement(node) { + process(b, node); } - }); + } + }; +} - if (allOfTheMicrosyntaxes.length === 0) { return; } +function process(b, node) { + let allOfTheMicrosyntaxes = []; + let allOfTheMicrosyntaxIndexes = []; + let classPair; - let classValue = []; + each(node.hash.pairs, (pair, index) => { + let { key } = pair; - if (classPair) { - classValue.push(classPair.value); - classValue.push(b.string(' ')); - } else { - classPair = b.pair('class', null); - node.hash.pairs.push(classPair); + if (key === 'classBinding' || key === 'classNameBindings') { + allOfTheMicrosyntaxIndexes.push(index); + allOfTheMicrosyntaxes.push(pair); + } else if (key === 'class') { + classPair = pair; } + }); + + if (allOfTheMicrosyntaxes.length === 0) { return; } - each(allOfTheMicrosyntaxIndexes, index => { - node.hash.pairs.splice(index, 1); - }); + let classValue = []; - each(allOfTheMicrosyntaxes, ({ value, loc }) => { - let sexprs = []; - // TODO: add helpful deprecation when both `classNames` and `classNameBindings` can - // be removed. + if (classPair) { + classValue.push(classPair.value); + classValue.push(b.string(' ')); + } else { + classPair = b.pair('class', null); + node.hash.pairs.push(classPair); + } + + each(allOfTheMicrosyntaxIndexes, index => { + node.hash.pairs.splice(index, 1); + }); - if (value.type === 'StringLiteral') { - let microsyntax = parseMicrosyntax(value.original); + each(allOfTheMicrosyntaxes, ({ value, loc }) => { + let sexprs = []; + // TODO: add helpful deprecation when both `classNames` and `classNameBindings` can + // be removed. - buildSexprs(microsyntax, sexprs, b); + if (value.type === 'StringLiteral') { + let microsyntax = parseMicrosyntax(value.original); - classValue.push(...sexprs); - } - }); + buildSexprs(microsyntax, sexprs, b); - let hash = b.hash(); - classPair.value = b.sexpr(b.path('concat'), classValue, hash); + classValue.push(...sexprs); + } }); - return ast; -}; + let hash = b.hash(); + classPair.value = b.sexpr(b.path('concat'), classValue, hash); +} function buildSexprs(microsyntax, sexprs, b) { for (let i = 0; i < microsyntax.length; i++) { @@ -102,10 +106,6 @@ function buildSexprs(microsyntax, sexprs, b) { } } -function validate(node) { - return (node.type === 'BlockStatement' || node.type === 'MustacheStatement'); -} - function each(list, callback) { for (let i = 0; i < list.length; i++) { callback(list[i], i); diff --git a/packages/ember-template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js b/packages/ember-template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js index 2d258895b40..54d3f2487b3 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js +++ b/packages/ember-template-compiler/lib/plugins/transform-quoted-bindings-into-just-bindings.js @@ -1,31 +1,18 @@ -export default function TransformQuotedBindingsIntoJustBindings() { - // set later within HTMLBars to the syntax package - this.syntax = null; -} - -/** - @private - @method transform - @param {AST} ast The AST to be transformed. -*/ -TransformQuotedBindingsIntoJustBindings.prototype.transform = function TransformQuotedBindingsIntoJustBindings_transform(ast) { - let walker = new this.syntax.Walker(); - - walker.visit(ast, node => { - if (!validate(node)) { return; } +export default function transformQuotedBindingsIntoJustBindings(env) { - let styleAttr = getStyleAttr(node); + return { + name: 'transform-quoted-bindings-into-just-bindings', - if (!validStyleAttr(styleAttr)) { return; } + visitors: { + ElementNode(node) { + let styleAttr = getStyleAttr(node); - styleAttr.value = styleAttr.value.parts[0]; - }); + if (!validStyleAttr(styleAttr)) { return; } - return ast; -}; - -function validate(node) { - return node.type === 'ElementNode'; + styleAttr.value = styleAttr.value.parts[0]; + } + } + } } function validStyleAttr(attr) { diff --git a/packages/ember-template-compiler/lib/plugins/transform-top-level-components.js b/packages/ember-template-compiler/lib/plugins/transform-top-level-components.js index 01b64d7a768..6a010efab88 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-top-level-components.js +++ b/packages/ember-template-compiler/lib/plugins/transform-top-level-components.js @@ -1,22 +1,18 @@ -export default function TransformTopLevelComponents() { - // set later within HTMLBars to the syntax package - this.syntax = null; +export default function transformTopLevelComponent(env) { + return { + name: 'transform-top-level-component', + + visitors: { + Program(node) { + hasSingleComponentNode(node, component => { + component.tag = `@${component.tag}`; + component.isStatic = true; + }); + } + } + } } -/** - @private - @method transform - @param {AST} The AST to be transformed. -*/ -TransformTopLevelComponents.prototype.transform = function TransformTopLevelComponents_transform(ast) { - hasSingleComponentNode(ast, component => { - component.tag = `@${component.tag}`; - component.isStatic = true; - }); - - return ast; -}; - function hasSingleComponentNode(program, componentCallback) { let { loc, body } = program; if (!loc || loc.start.line !== 1 || loc.start.column !== 0) { return; } From f21c8f0c53d710a550cb8e96c05734de4b51317f Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 21 Jun 2017 02:02:46 -0400 Subject: [PATCH 054/224] Ensure user plugins can be of the "old" type. --- .../lib/system/compile-options.js | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/ember-template-compiler/lib/system/compile-options.js b/packages/ember-template-compiler/lib/system/compile-options.js index 1a1ff53b34c..ae990f35c60 100644 --- a/packages/ember-template-compiler/lib/system/compile-options.js +++ b/packages/ember-template-compiler/lib/system/compile-options.js @@ -25,14 +25,36 @@ export default function compileOptions(_options) { return options; } -export function registerPlugin(type, PluginClass) { +function ensurePlugin(FunctionOrPlugin) { +} + +export function registerPlugin(type, _plugin) { if (type !== 'ast') { - throw new Error(`Attempting to register ${PluginClass} as "${type}" which is not a valid Glimmer plugin type.`); + throw new Error(`Attempting to register ${_plugin} as "${type}" which is not a valid Glimmer plugin type.`); } - if (USER_PLUGINS.indexOf(PluginClass) === -1) { - USER_PLUGINS = [PluginClass, ...USER_PLUGINS]; + let plugin; + if (_plugin.prototype && _plugin.prototype.transform) { + plugin = (env) => { + return { + name: _plugin.constructor && _plugin.constructor.name, + + visitors: { + Program(node) { + let plugin = new _plugin(env); + + plugin.syntax = env.syntax; + + return plugin.transform(node); + } + } + }; + }; + } else { + plugin = _plugin; } + + USER_PLUGINS = [plugin, ...USER_PLUGINS]; } export function removePlugin(type, PluginClass) { From c018a1536b333660dbd8aa9ed5e4efd9c21ba08c Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 21 Jun 2017 18:44:40 +0500 Subject: [PATCH 055/224] call `peekMeta` when it is necessary --- packages/ember-metal/lib/property_set.js | 5 ++--- packages/ember-runtime/lib/mixins/promise_proxy.js | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index a09aeaa8c90..2ab309d509c 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -47,10 +47,8 @@ export function set(obj, keyName, value, tolerant) { return setPath(obj, keyName, value, tolerant); } - let meta = peekMeta(obj); - let possibleDesc = obj[keyName]; - let desc, currentValue; + let possibleDesc = obj[keyName]; if (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) { desc = possibleDesc; } else { @@ -65,6 +63,7 @@ export function set(obj, keyName, value, tolerant) { } else if (currentValue === value) { /* no change */ return value; } else { + let meta = peekMeta(obj); propertyWillChange(obj, keyName, meta); if (MANDATORY_SETTER) { diff --git a/packages/ember-runtime/lib/mixins/promise_proxy.js b/packages/ember-runtime/lib/mixins/promise_proxy.js index 67a399a8a3c..0a963c2cbfc 100644 --- a/packages/ember-runtime/lib/mixins/promise_proxy.js +++ b/packages/ember-runtime/lib/mixins/promise_proxy.js @@ -104,7 +104,7 @@ export default Mixin.create({ @default null @public */ - reason: null, + reason: null, /** Once the proxied promise has settled this will become `false`. @@ -113,7 +113,7 @@ export default Mixin.create({ @default true @public */ - isPending: not('isSettled').readOnly(), + isPending: not('isSettled').readOnly(), /** Once the proxied promise has settled this will become `true`. @@ -122,7 +122,7 @@ export default Mixin.create({ @default false @public */ - isSettled: or('isRejected', 'isFulfilled').readOnly(), + isSettled: or('isRejected', 'isFulfilled').readOnly(), /** Will become `true` if the proxied promise is rejected. @@ -131,7 +131,7 @@ export default Mixin.create({ @default false @public */ - isRejected: false, + isRejected: false, /** Will become `true` if the proxied promise is fulfilled. From 24e2a175f58a2b39da0ca5e329c9e1cbcb2a675a Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 21 Jun 2017 20:10:57 +0500 Subject: [PATCH 056/224] cleanup `core-object --- packages/ember-runtime/lib/system/core_object.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/ember-runtime/lib/system/core_object.js b/packages/ember-runtime/lib/system/core_object.js index 24df8c919cd..def42b1042a 100644 --- a/packages/ember-runtime/lib/system/core_object.js +++ b/packages/ember-runtime/lib/system/core_object.js @@ -132,11 +132,7 @@ function makeCtor() { let baseValue = this[keyName]; if (baseValue) { - if ('function' === typeof baseValue.concat) { - value = baseValue.concat(value); - } else { - value = makeArray(baseValue).concat(value); - } + value = makeArray(baseValue).concat(value); } else { value = makeArray(value); } @@ -866,13 +862,13 @@ let ClassMixinProps = { metaForProperty(key) { let proto = this.proto(); let possibleDesc = proto[key]; - let desc = (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) ? possibleDesc : undefined; + let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; assert( `metaForProperty() could not find a computed property with key '${key}'.`, - !!desc && desc instanceof ComputedProperty + isDescriptor && possibleDesc instanceof ComputedProperty ); - return desc._meta || {}; + return possibleDesc._meta || {}; }, _computedProperties: computed(function() { @@ -884,7 +880,7 @@ let ClassMixinProps = { for (let name in proto) { property = proto[name]; - if (property && property.isDescriptor) { + if (property !== null && typeof property === 'object' && property.isDescriptor) { properties.push({ name, meta: property._meta From a80f300ec49d0e10631542e4677230216b292a9c Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 22 Jun 2017 00:31:44 +0500 Subject: [PATCH 057/224] cleanup `property_set` --- packages/ember-metal/lib/property_get.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/ember-metal/lib/property_get.js b/packages/ember-metal/lib/property_get.js index 0ff2bdbb62a..9c4679de820 100644 --- a/packages/ember-metal/lib/property_get.js +++ b/packages/ember-metal/lib/property_get.js @@ -55,24 +55,21 @@ export function get(obj, keyName) { assert('Cannot call `Ember.get` with an empty string', keyName !== ''); let value = obj[keyName]; - let desc = (value !== null && typeof value === 'object' && value.isDescriptor) ? value : undefined; - let ret; + let isDescriptor = value !== null && typeof value === 'object' && value.isDescriptor; - if (desc === undefined && isPath(keyName)) { + if (!isDescriptor && isPath(keyName)) { return _getPath(obj, keyName); } - if (desc) { - return desc.get(obj, keyName); + if (isDescriptor) { + return value.get(obj, keyName); } else { - ret = value; - - if (ret === undefined && + if (value === undefined && 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { return obj.unknownProperty(keyName); } - return ret; + return value; } } @@ -96,7 +93,7 @@ export function _getPath(root, path) { } function isGettable(obj) { - if (obj == null) { + if (obj === undefined || obj === null) { return false; } From 9537d0683f05983039547ab6244e35ce7e9ad1ba Mon Sep 17 00:00:00 2001 From: Patrick Robertson Date: Tue, 13 Jun 2017 17:30:03 -0400 Subject: [PATCH 058/224] Decouple link-to + query param tests from global resolver. Also refactor the tests into a more readable format. --- .../link_to_with_query_params_test.js | 972 ++++++++++-------- 1 file changed, 522 insertions(+), 450 deletions(-) diff --git a/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js b/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js index ab92c3a4bca..8f0528185f1 100644 --- a/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js +++ b/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js @@ -1,506 +1,578 @@ -import { set, run } from 'ember-metal'; import { Controller, RSVP } from 'ember-runtime'; -import { Route, NoneLocation } from 'ember-routing'; -import { compile } from 'ember-template-compiler'; -import { Application } from 'ember-application'; -import { jQuery } from 'ember-views'; -import { setTemplates, setTemplate } from 'ember-glimmer'; - -let Router, App, router, registry, container; - -function bootApplication() { - router = container.lookup('router:main'); - run(App, 'advanceReadiness'); -} - - -function shouldNotBeActive(selector) { - checkActive(selector, false); -} - -function shouldBeActive(selector) { - checkActive(selector, true); -} - -function checkActive(selector, active) { - let classList = jQuery(selector, '#qunit-fixture')[0].className; - equal(classList.indexOf('active') > -1, active, selector + ' active should be ' + active.toString()); -} - -let updateCount, replaceCount; - -function sharedSetup() { - App = Application.create({ - name: 'App', - rootElement: '#qunit-fixture' - }); - - App.deferReadiness(); - - updateCount = replaceCount = 0; - App.Router.reopen({ - location: NoneLocation.create({ - setURL(path) { - updateCount++; - set(this, 'path', path); - }, - - replaceURL(path) { - replaceCount++; - set(this, 'path', path); - } - }) - }); - - Router = App.Router; - registry = App.__registry__; - container = App.__container__; -} - -function sharedTeardown() { - run(() => App.destroy()); - setTemplates({}); -} - -QUnit.module('The {{link-to}} helper: invoking with query params', { - setup() { - run(() => { - sharedSetup(); - - App.IndexController = Controller.extend({ - queryParams: ['foo', 'bar', 'abool'], - foo: '123', - bar: 'abc', - boundThing: 'OMG', - abool: true - }); - - App.AboutController = Controller.extend({ +import { Route, Router } from 'ember-routing'; +import { moduleFor, ApplicationTestCase, AutobootApplicationTestCase } from 'internal-test-helpers'; + +moduleFor('The {{link-to}} helper: invoking with query params', class extends ApplicationTestCase { + constructor() { + super(); + let indexProperties = { + foo: '123', + bar: 'abc' + } + this.add('controller:index', Controller.extend({ + queryParams: ['foo', 'bar', 'abool'], + foo: indexProperties.foo, + bar: indexProperties.bar, + boundThing: 'OMG', + abool: true + })); + this.add('controller:about', Controller.extend({ queryParams: ['baz', 'bat'], baz: 'alex', bat: 'borf' - }); - - registry.unregister('router:main'); - registry.register('router:main', Router); + })); + this.indexProperties = indexProperties; + } + + shouldNotBeActive(assert, selector) { + this.checkActive(assert, selector, false); + } + + shouldBeActive(assert, selector) { + this.checkActive(assert, selector, true); + } + + getController(name) { + return this.applicationInstance.lookup(`controller:${name}`); + } + + checkActive(assert, selector, active) { + let classList = this.$(selector)[0].className; + assert.equal(classList.indexOf('active') > -1, active, selector + ' active should be ' + active.toString()); + } + + [`@test doesn't update controller QP properties on current route when invoked`](assert) { + this.addTemplate('index', ` + {{#link-to 'index' id='the-link'}}Index{{/link-to}} + `); + + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); + + assert.deepEqual(indexController.getProperties('foo', 'bar'), + this.indexProperties, + 'controller QP properties do not update' + ); }); - }, + } - teardown: sharedTeardown -}); + [`@test doesn't update controller QP properties on current route when invoked (empty query-params obj)`](assert) { + this.addTemplate('index', ` + {{#link-to 'index' (query-params) id='the-link'}}Index{{/link-to}} + `); -QUnit.test('doesn\'t update controller QP properties on current route when invoked', function() { - setTemplate('index', compile(`{{#link-to 'index' id='the-link'}}Index{{/link-to}}`)); - bootApplication(); + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); - run(jQuery('#the-link'), 'click'); - let indexController = container.lookup('controller:index'); - deepEqual(indexController.getProperties('foo', 'bar'), { foo: '123', bar: 'abc' }, 'controller QP properties not'); -}); - -QUnit.test('doesn\'t update controller QP properties on current route when invoked (empty query-params obj)', function() { - setTemplate('index', compile(`{{#link-to 'index' (query-params) id='the-link'}}Index{{/link-to}}`)); - bootApplication(); + assert.deepEqual(indexController.getProperties('foo', 'bar'), + this.indexProperties, + 'controller QP properties do not update' + ); + }); + } - run(jQuery('#the-link'), 'click'); - let indexController = container.lookup('controller:index'); - deepEqual(indexController.getProperties('foo', 'bar'), { foo: '123', bar: 'abc' }, 'controller QP properties not'); -}); + [`@test doesn't update controller QP properties on current route when invoked (empty query-params obj, inferred route)`](assert) { + this.addTemplate('index', ` + {{#link-to (query-params) id='the-link'}}Index{{/link-to}} + `); -QUnit.test('link-to with no params throws', function() { - setTemplate('index', compile(`{{#link-to id='the-link'}}Index{{/link-to}}`)); - expectAssertion(() => bootApplication(), /one or more/); -}); + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); -QUnit.test('doesn\'t update controller QP properties on current route when invoked (empty query-params obj, inferred route)', function() { - setTemplate('index', compile(`{{#link-to (query-params) id='the-link'}}Index{{/link-to}}`)); - bootApplication(); - - run(jQuery('#the-link'), 'click'); - let indexController = container.lookup('controller:index'); - deepEqual(indexController.getProperties('foo', 'bar'), { foo: '123', bar: 'abc' }, 'controller QP properties not'); -}); + assert.deepEqual(indexController.getProperties('foo', 'bar'), + this.indexProperties, + 'controller QP properties do not update' + ); + }); + } + + ['@test updates controller QP properties on current route when invoked'](assert) { + this.addTemplate('index', ` + {{#link-to 'index' (query-params foo='456') id="the-link"}} + Index + {{/link-to}} + `); + + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); + + assert.deepEqual(indexController.getProperties('foo', 'bar'), + { foo: '456', bar: 'abc' }, + 'controller QP properties updated' + ); + }); + } + + ['@test updates controller QP properties on current route when invoked (inferred route)'](assert) { + this.addTemplate('index', ` + {{#link-to (query-params foo='456') id="the-link"}} + Index + {{/link-to}} + `); + + return this.visit('/').then(() => { + this.click('#the-link'); + let indexController = this.getController('index'); + + assert.deepEqual(indexController.getProperties('foo', 'bar'), + { foo: '456', bar: 'abc' }, + 'controller QP properties updated' + ); + }); + } -QUnit.test('updates controller QP properties on current route when invoked', function() { - setTemplate('index', compile(`{{#link-to 'index' (query-params foo='456') id='the-link'}}Index{{/link-to}}`)); - bootApplication(); + ['@test updates controller QP properties on other route after transitioning to that route'](assert) { + this.router.map(function() { + this.route('about'); + }); - run(jQuery('#the-link'), 'click'); - let indexController = container.lookup('controller:index'); - deepEqual(indexController.getProperties('foo', 'bar'), { foo: '456', bar: 'abc' }, 'controller QP properties updated'); -}); + this.addTemplate('index',` + {{#link-to 'about' (query-params baz='lol') id='the-link'}} + About + {{/link-to}} + `); -QUnit.test('updates controller QP properties on current route when invoked (inferred route)', function() { - setTemplate('index', compile(`{{#link-to (query-params foo='456') id='the-link'}}Index{{/link-to}}`)); - bootApplication(); + return this.visit('/').then(() => { + let theLink = this.$('#the-link'); + assert.equal(theLink.attr('href'), '/about?baz=lol'); - run(jQuery('#the-link'), 'click'); - let indexController = container.lookup('controller:index'); - deepEqual(indexController.getProperties('foo', 'bar'), { foo: '456', bar: 'abc' }, 'controller QP properties updated'); -}); + this.click('#the-link'); + let aboutController = this.getController('about'); -QUnit.test('updates controller QP properties on other route after transitioning to that route', function() { - Router.map(function() { - this.route('about'); - }); + assert.deepEqual(aboutController.getProperties('baz', 'bat'), + { baz: 'lol', bat: 'borf' }, + 'about controller QP properties updated' + ); + }); + } - setTemplate('index', compile(`{{#link-to 'about' (query-params baz='lol') id='the-link'}}About{{/link-to}}`)); - bootApplication(); + ['@test supplied QP properties can be bound'](assert) { + this.addTemplate('index', ` + {{#link-to (query-params foo=boundThing) id='the-link'}}Index{{/link-to}} + `); - equal(jQuery('#the-link').attr('href'), '/about?baz=lol'); - run(jQuery('#the-link'), 'click'); - let aboutController = container.lookup('controller:about'); - deepEqual(aboutController.getProperties('baz', 'bat'), { baz: 'lol', bat: 'borf' }, 'about controller QP properties updated'); + return this.visit('/').then(() => { + let indexController = this.getController('index'); + let theLink = this.$('#the-link') - equal(container.lookup('controller:application').get('currentPath'), 'about'); -}); + assert.equal(theLink.attr('href'), '/?foo=OMG'); -QUnit.test('supplied QP properties can be bound', function() { - let indexController = container.lookup('controller:index'); - setTemplate('index', compile(`{{#link-to (query-params foo=boundThing) id='the-link'}}Index{{/link-to}}`)); + this.runTask(() => indexController.set('boundThing', 'ASL')); - bootApplication(); + assert.equal(theLink.attr('href'), '/?foo=ASL'); + }); + } - equal(jQuery('#the-link').attr('href'), '/?foo=OMG'); - run(indexController, 'set', 'boundThing', 'ASL'); - equal(jQuery('#the-link').attr('href'), '/?foo=ASL'); -}); + ['@test supplied QP properties can be bound (booleans)'](assert) { + this.addTemplate('index',` + {{#link-to (query-params abool=boundThing) id='the-link'}} + Index + {{/link-to}} + `); -QUnit.test('supplied QP properties can be bound (booleans)', function() { - let indexController = container.lookup('controller:index'); - setTemplate('index', compile(`{{#link-to (query-params abool=boundThing) id='the-link'}}Index{{/link-to}}`)); + return this.visit('/').then(() => { + let indexController = this.getController('index'); + let theLink = this.$('#the-link'); - bootApplication(); + assert.equal(theLink.attr('href'), '/?abool=OMG'); - equal(jQuery('#the-link').attr('href'), '/?abool=OMG'); - run(indexController, 'set', 'boundThing', false); - equal(jQuery('#the-link').attr('href'), '/?abool=false'); + this.runTask(() => indexController.set('boundThing', false)); - run(jQuery('#the-link'), 'click'); + assert.equal(theLink.attr('href'), '/?abool=false'); - deepEqual(indexController.getProperties('foo', 'bar', 'abool'), { foo: '123', bar: 'abc', abool: false }); -}); + this.click('#the-link'); -QUnit.test('href updates when unsupplied controller QP props change', function() { - setTemplate('index', compile(`{{#link-to (query-params foo='lol') id='the-link'}}Index{{/link-to}}`)); + assert.deepEqual(indexController.getProperties('foo', 'bar', 'abool'), + { foo: '123', bar: 'abc', abool: false }, + 'bound bool QP properties update' + ); + }); + } + ['@test href updates when unsupplied controller QP props change'](assert) { + this.addTemplate('index', ` + {{#link-to (query-params foo='lol') id='the-link'}}Index{{/link-to}} + `); - bootApplication(); - let indexController = container.lookup('controller:index'); + return this.visit('/').then(() => { + let indexController = this.getController('index'); + let theLink = this.$('#the-link'); - equal(jQuery('#the-link').attr('href'), '/?foo=lol'); - run(indexController, 'set', 'bar', 'BORF'); - equal(jQuery('#the-link').attr('href'), '/?bar=BORF&foo=lol'); - run(indexController, 'set', 'foo', 'YEAH'); - equal(jQuery('#the-link').attr('href'), '/?bar=BORF&foo=lol'); -}); + assert.equal(theLink.attr('href'), '/?foo=lol'); -QUnit.test('The {{link-to}} with only query params always transitions to the current route with the query params applied', function() { - // Test harness for bug #12033 + this.runTask(() => indexController.set('bar', 'BORF')); - setTemplate('cars', compile(` - {{#link-to 'cars.create' id='create-link'}}Create new car{{/link-to}} - {{#link-to (query-params page='2') id='page2-link'}}Page 2{{/link-to}} - {{outlet}} - `)); + assert.equal(theLink.attr('href'), '/?bar=BORF&foo=lol'); - setTemplate('cars/create', compile( - `{{#link-to 'cars' id='close-link'}}Close create form{{/link-to}}` - )); + this.runTask(() => indexController.set('foo', 'YEAH')); - Router.map(function() { - this.route('cars', function() { - this.route('create'); + assert.equal(theLink.attr('href'), '/?bar=BORF&foo=lol'); + }); + } + + ['@test The {{link-to}} with only query params always transitions to the current route with the query params applied'](assert) { + // Test harness for bug #12033 + this.addTemplate('cars',` + {{#link-to 'cars.create' id='create-link'}}Create new car{{/link-to}} + {{#link-to (query-params page='2') id='page2-link'}}Page 2{{/link-to}} + {{outlet}} + `); + this.addTemplate('cars.create', + `{{#link-to 'cars' id='close-link'}}Close create form{{/link-to}}` + ); + + this.router.map(function() { + this.route('cars', function() { + this.route('create'); + }) }); - }); - App.CarsController = Controller.extend({ - queryParams: ['page'], - page: 1 - }); + this.add('controller:cars', Controller.extend({ + queryParams: ['page'], + page: 1 + })); - bootApplication(); + return this.visit('/cars/create').then(() => { + let router = this.appRouter; + let carsController = this.getController('cars'); - let carsController = container.lookup('controller:cars'); + assert.equal(router.currentRouteName, 'cars.create'); - run(() => router.handleURL('/cars/create')); + this.click('#close-link'); - run(() => { - equal(router.currentRouteName, 'cars.create'); - jQuery('#close-link').click(); - }); + assert.equal(router.currentRouteName, 'cars.index'); + assert.equal(router.get('url'), '/cars'); + assert.equal(carsController.get('page'), 1, 'The page query-param is 1'); - run(() => { - equal(router.currentRouteName, 'cars.index'); - equal(router.get('url'), '/cars'); - equal(carsController.get('page'), 1, 'The page query-param is 1'); - jQuery('#page2-link').click(); - }); + this.click('#page2-link'); - run(() => { - equal(router.currentRouteName, 'cars.index', 'The active route is still cars'); - equal(router.get('url'), '/cars?page=2', 'The url has been updated'); - equal(carsController.get('page'), 2, 'The query params have been updated'); - }); -}); - -QUnit.test('The {{link-to}} applies activeClass when query params are not changed', function() { - setTemplate('index', compile(` - {{#link-to (query-params foo='cat') id='cat-link'}}Index{{/link-to}} - {{#link-to (query-params foo='dog') id='dog-link'}}Index{{/link-to}} - {{#link-to 'index' id='change-nothing'}}Index{{/link-to}} - `)); - - setTemplate('search', compile(` - {{#link-to (query-params search='same') id='same-search'}}Index{{/link-to}} - {{#link-to (query-params search='change') id='change-search'}}Index{{/link-to}} - {{#link-to (query-params search='same' archive=true) id='same-search-add-archive'}}Index{{/link-to}} - {{#link-to (query-params archive=true) id='only-add-archive'}}Index{{/link-to}} - {{#link-to (query-params search='same' archive=true) id='both-same'}}Index{{/link-to}} - {{#link-to (query-params search='different' archive=true) id='change-one'}}Index{{/link-to}} - {{#link-to (query-params search='different' archive=false) id='remove-one'}}Index{{/link-to}} - {{outlet}} - `)); - - setTemplate('search/results', compile(` - {{#link-to (query-params sort='title') id='same-sort-child-only'}}Index{{/link-to}} - {{#link-to (query-params search='same') id='same-search-parent-only'}}Index{{/link-to}} - {{#link-to (query-params search='change') id='change-search-parent-only'}}Index{{/link-to}} - {{#link-to (query-params search='same' sort='title') id='same-search-same-sort-child-and-parent'}}Index{{/link-to}} - {{#link-to (query-params search='same' sort='author') id='same-search-different-sort-child-and-parent'}}Index{{/link-to}} - {{#link-to (query-params search='change' sort='title') id='change-search-same-sort-child-and-parent'}}Index{{/link-to}} - {{#link-to (query-params foo='dog') id='dog-link'}}Index{{/link-to}} - `)); - - Router.map(function() { - this.route('search', function() { - this.route('results'); + assert.equal(router.currentRouteName, 'cars.index', 'The active route is still cars'); + assert.equal(router.get('url'), '/cars?page=2', 'The url has been updated'); + assert.equal(carsController.get('page'), 2, 'The query params have been updated'); }); - }); - - App.SearchController = Controller.extend({ - queryParams: ['search', 'archive'], - search: '', - archive: false - }); - - App.SearchResultsController = Controller.extend({ - queryParams: ['sort', 'showDetails'], - sort: 'title', - showDetails: true - }); - - bootApplication(); - - //Basic tests - shouldNotBeActive('#cat-link'); - shouldNotBeActive('#dog-link'); - run(router, 'handleURL', '/?foo=cat'); - shouldBeActive('#cat-link'); - shouldNotBeActive('#dog-link'); - run(router, 'handleURL', '/?foo=dog'); - shouldBeActive('#dog-link'); - shouldNotBeActive('#cat-link'); - shouldBeActive('#change-nothing'); - - //Multiple params - run(() => router.handleURL('/search?search=same')); - shouldBeActive('#same-search'); - shouldNotBeActive('#change-search'); - shouldNotBeActive('#same-search-add-archive'); - shouldNotBeActive('#only-add-archive'); - shouldNotBeActive('#remove-one'); - - run(() => router.handleURL('/search?search=same&archive=true')); - - shouldBeActive('#both-same'); - shouldNotBeActive('#change-one'); - - //Nested Controllers - run(() => { - // Note: this is kind of a strange case; sort's default value is 'title', - // so this URL shouldn't have been generated in the first place, but - // we should also be able to gracefully handle these cases. - router.handleURL('/search/results?search=same&sort=title&showDetails=true'); - }); - //shouldBeActive('#same-sort-child-only'); - shouldBeActive('#same-search-parent-only'); - shouldNotBeActive('#change-search-parent-only'); - shouldBeActive('#same-search-same-sort-child-and-parent'); - shouldNotBeActive('#same-search-different-sort-child-and-parent'); - shouldNotBeActive('#change-search-same-sort-child-and-parent'); -}); - -QUnit.test('The {{link-to}} applies active class when query-param is number', function() { - setTemplate('index', compile(` - {{#link-to (query-params page=pageNumber) id='page-link'}}Index{{/link-to}} - `)); - - App.IndexController = Controller.extend({ - queryParams: ['page'], - page: 1, - pageNumber: 5 - }); - - bootApplication(); - - shouldNotBeActive('#page-link'); - run(router, 'handleURL', '/?page=5'); - shouldBeActive('#page-link'); -}); - -QUnit.test('The {{link-to}} applies active class when query-param is array', function() { - setTemplate('index', compile(` - {{#link-to (query-params pages=pagesArray) id='array-link'}}Index{{/link-to}} - {{#link-to (query-params pages=biggerArray) id='bigger-link'}}Index{{/link-to}} - {{#link-to (query-params pages=emptyArray) id='empty-link'}}Index{{/link-to}} - `)); - - App.IndexController = Controller.extend({ - queryParams: ['pages'], - pages: [], - pagesArray: [1, 2], - biggerArray: [1, 2, 3], - emptyArray: [] - }); - - bootApplication(); - - shouldNotBeActive('#array-link'); - run(router, 'handleURL', '/?pages=%5B1%2C2%5D'); - shouldBeActive('#array-link'); - shouldNotBeActive('#bigger-link'); - shouldNotBeActive('#empty-link'); - run(router, 'handleURL', '/?pages=%5B2%2C1%5D'); - shouldNotBeActive('#array-link'); - shouldNotBeActive('#bigger-link'); - shouldNotBeActive('#empty-link'); - run(router, 'handleURL', '/?pages=%5B1%2C2%2C3%5D'); - shouldBeActive('#bigger-link'); - shouldNotBeActive('#array-link'); - shouldNotBeActive('#empty-link'); -}); - -QUnit.test('The {{link-to}} helper applies active class to parent route', function() { - App.Router.map(function() { - this.route('parent', function() { - this.route('child'); + } + + ['@test the {{link-to}} applies activeClass when query params are not changed'](assert) { + this.addTemplate('index', ` + {{#link-to (query-params foo='cat') id='cat-link'}}Index{{/link-to}} + {{#link-to (query-params foo='dog') id='dog-link'}}Index{{/link-to}} + {{#link-to 'index' id='change-nothing'}}Index{{/link-to}} + `); + this.addTemplate('search', ` + {{#link-to (query-params search='same') id='same-search'}}Index{{/link-to}} + {{#link-to (query-params search='change') id='change-search'}}Index{{/link-to}} + {{#link-to (query-params search='same' archive=true) id='same-search-add-archive'}}Index{{/link-to}} + {{#link-to (query-params archive=true) id='only-add-archive'}}Index{{/link-to}} + {{#link-to (query-params search='same' archive=true) id='both-same'}}Index{{/link-to}} + {{#link-to (query-params search='different' archive=true) id='change-one'}}Index{{/link-to}} + {{#link-to (query-params search='different' archive=false) id='remove-one'}}Index{{/link-to}} + {{outlet}} + `); + this.addTemplate('search.results', ` + {{#link-to (query-params sort='title') id='same-sort-child-only'}}Index{{/link-to}} + {{#link-to (query-params search='same') id='same-search-parent-only'}}Index{{/link-to}} + {{#link-to (query-params search='change') id='change-search-parent-only'}}Index{{/link-to}} + {{#link-to (query-params search='same' sort='title') id='same-search-same-sort-child-and-parent'}}Index{{/link-to}} + {{#link-to (query-params search='same' sort='author') id='same-search-different-sort-child-and-parent'}}Index{{/link-to}} + {{#link-to (query-params search='change' sort='title') id='change-search-same-sort-child-and-parent'}}Index{{/link-to}} + {{#link-to (query-params foo='dog') id='dog-link'}}Index{{/link-to}} + `); + + this.router.map(function() { + this.route('search', function() { + this.route('results'); + }) }); - }); - - setTemplate('application', compile(` - {{#link-to 'parent' id='parent-link'}}Parent{{/link-to}} - {{#link-to 'parent.child' id='parent-child-link'}}Child{{/link-to}} - {{#link-to 'parent' (query-params foo=cat) id='parent-link-qp'}}Parent{{/link-to}} - {{outlet}} - `)); - - App.ParentChildController = Controller.extend({ - queryParams: ['foo'], - foo: 'bar' - }); - - bootApplication(); - shouldNotBeActive('#parent-link'); - shouldNotBeActive('#parent-child-link'); - shouldNotBeActive('#parent-link-qp'); - run(router, 'handleURL', '/parent/child?foo=dog'); - shouldBeActive('#parent-link'); - shouldNotBeActive('#parent-link-qp'); -}); -QUnit.test('The {{link-to}} helper disregards query-params in activeness computation when current-when specified', function() { - App.Router.map(function() { - this.route('parent'); - }); - - setTemplate('application', compile(` - {{#link-to 'parent' (query-params page=1) current-when='parent' id='app-link'}}Parent{{/link-to}} {{outlet}} - `)); - setTemplate('parent', compile(` - {{#link-to 'parent' (query-params page=1) current-when='parent' id='parent-link'}}Parent{{/link-to}} {{outlet}} - `)); - - App.ParentController = Controller.extend({ - queryParams: ['page'], - page: 1 - }); - - bootApplication(); - equal(jQuery('#app-link').attr('href'), '/parent'); - shouldNotBeActive('#app-link'); - - run(router, 'handleURL', '/parent?page=2'); - equal(jQuery('#app-link').attr('href'), '/parent'); - shouldBeActive('#app-link'); - equal(jQuery('#parent-link').attr('href'), '/parent'); - shouldBeActive('#parent-link'); - - let parentController = container.lookup('controller:parent'); - equal(parentController.get('page'), 2); - run(parentController, 'set', 'page', 3); - equal(router.get('location.path'), '/parent?page=3'); - shouldBeActive('#app-link'); - shouldBeActive('#parent-link'); - - jQuery('#app-link').click(); - equal(router.get('location.path'), '/parent'); -}); + this.add('controller:search', Controller.extend({ + queryParams: ['search', 'archive'], + search: '', + archive: false + })); + + this.add('controller:search.results', Controller.extend({ + queryParams: ['sort', 'showDetails'], + sort: 'title', + showDetails: true + })); + + return this.visit('/').then(() => { + this.shouldNotBeActive(assert, '#cat-link'); + this.shouldNotBeActive(assert, '#dog-link'); + + return this.visit('/?foo=cat'); + }).then(() => { + this.shouldBeActive(assert, '#cat-link'); + this.shouldNotBeActive(assert, '#dog-link'); + + return this.visit('/?foo=dog'); + }).then(() => { + this.shouldBeActive(assert, '#dog-link'); + this.shouldNotBeActive(assert, '#cat-link'); + this.shouldBeActive(assert, '#change-nothing'); + + return this.visit('/search?search=same'); + }).then(() => { + this.shouldBeActive(assert, '#same-search'); + this.shouldNotBeActive(assert, '#change-search'); + this.shouldNotBeActive(assert, '#same-search-add-archive'); + this.shouldNotBeActive(assert, '#only-add-archive'); + this.shouldNotBeActive(assert, '#remove-one'); + + return this.visit('/search?search=same&archive=true') + }).then(() => { + this.shouldBeActive(assert, '#both-same'); + this.shouldNotBeActive(assert, '#change-one'); + + return this.visit('/search/results?search=same&sort=title&showDetails=true'); + }).then(() => { + this.shouldBeActive(assert, '#same-sort-child-only'); + this.shouldBeActive(assert, '#same-search-parent-only'); + this.shouldNotBeActive(assert, '#change-search-parent-only'); + this.shouldBeActive(assert, '#same-search-same-sort-child-and-parent'); + this.shouldNotBeActive(assert, '#same-search-different-sort-child-and-parent'); + this.shouldNotBeActive(assert, '#change-search-same-sort-child-and-parent'); + }); + } + + ['@test the {{link-to}} applies active class when query-param is a number'](assert) { + this.addTemplate('index', ` + {{#link-to (query-params page=pageNumber) id='page-link'}} + Index + {{/link-to}} + `); + this.add('controller:index', Controller.extend({ + queryParams: ['page'], + page: 1, + pageNumber: 5 + })); + + return this.visit('/').then(() => { + this.shouldNotBeActive(assert, '#page-link'); + return this.visit('/?page=5'); + }).then(() => { + this.shouldBeActive(assert, '#page-link'); + }); + } + + ['@test the {{link-to}} applies active class when query-param is an array'](assert) { + this.addTemplate('index', ` + {{#link-to (query-params pages=pagesArray) id='array-link'}}Index{{/link-to}} + {{#link-to (query-params pages=biggerArray) id='bigger-link'}}Index{{/link-to}} + {{#link-to (query-params pages=emptyArray) id='empty-link'}}Index{{/link-to}} + `); + + this.add('controller:index', Controller.extend({ + queryParams: ['pages'], + pages: [], + pagesArray: [1, 2], + biggerArray: [1, 2, 3], + emptyArray: [] + })); + + return this.visit('/').then(() => { + this.shouldNotBeActive(assert, '#array-link'); + + return this.visit('/?pages=%5B1%2C2%5D'); + }).then(() => { + this.shouldBeActive(assert, '#array-link'); + this.shouldNotBeActive(assert, '#bigger-link'); + this.shouldNotBeActive(assert, '#empty-link'); + + return this.visit('/?pages=%5B2%2C1%5D') + }).then(() => { + this.shouldNotBeActive(assert, '#array-link'); + this.shouldNotBeActive(assert, '#bigger-link'); + this.shouldNotBeActive(assert, '#empty-link'); + + return this.visit('/?pages=%5B1%2C2%2C3%5D'); + }).then(() => { + this.shouldBeActive(assert, '#bigger-link'); + this.shouldNotBeActive(assert, '#array-link'); + this.shouldNotBeActive(assert, '#empty-link'); + }); + } + ['@test the {{link-to}} helper applies active class to the parent route'](assert) { + this.router.map(function() { + this.route('parent', function() { + this.route('child'); + }); + }); -QUnit.test('link-to default query params while in active transition regression test', function() { - App.Router.map(function() { - this.route('foos'); - this.route('bars'); - }); - let foos = RSVP.defer(); - let bars = RSVP.defer(); - - setTemplate('application', compile(` - {{link-to 'Foos' 'foos' id='foos-link'}} - {{link-to 'Baz Foos' 'foos' (query-params baz=true) id='baz-foos-link'}} - {{link-to 'Quux Bars' 'bars' (query-params quux=true) id='bars-link'}} - `)); - - App.FoosController = Controller.extend({ - queryParams: ['status'], - baz: false - }); - - App.FoosRoute = Route.extend({ - model() { - return foos.promise; - } - }); + this.addTemplate('application', ` + {{#link-to 'parent' id='parent-link'}}Parent{{/link-to}} + {{#link-to 'parent.child' id='parent-child-link'}}Child{{/link-to}} + {{#link-to 'parent' (query-params foo=cat) id='parent-link-qp'}}Parent{{/link-to}} + {{outlet}} + `); + + this.add('controller:parent.child', Controller.extend({ + queryParams: ['foo'], + foo: 'bar' + })); + + return this.visit('/').then(() => { + this.shouldNotBeActive(assert, '#parent-link'); + this.shouldNotBeActive(assert, '#parent-child-link'); + this.shouldNotBeActive(assert, '#parent-link-qp'); + return this.visit('/parent/child?foo=dog'); + }).then(() => { + this.shouldBeActive(assert, '#parent-link'); + this.shouldNotBeActive(assert, '#parent-link-qp'); + }); + } - App.BarsController = Controller.extend({ - queryParams: ['status'], - quux: false - }); + ['@test The {{link-to}} helper disregards query-params in activeness computation when current-when is specified'](assert) { + let appLink; - App.BarsRoute = Route.extend({ - model() { - return bars.promise; - } - }); + this.router.map(function() { + this.route('parent'); + }); + this.addTemplate('application', ` + {{#link-to 'parent' (query-params page=1) current-when='parent' id='app-link'}} + Parent + {{/link-to}} + {{outlet}} + `); + this.addTemplate('parent', ` + {{#link-to 'parent' (query-params page=1) current-when='parent' id='parent-link'}} + Parent + {{/link-to}} + {{outlet}} + `); + this.add('controller:parent', Controller.extend({ + queryParams: ['page'], + page: 1 + })); + + return this.visit('/').then(() => { + appLink = this.$('#app-link'); + + assert.equal(appLink.attr('href'), '/parent'); + this.shouldNotBeActive(assert, '#app-link'); + + return this.visit('/parent?page=2'); + }).then(() => { + appLink = this.$('#app-link'); + let router = this.appRouter; + + assert.equal(appLink.attr('href'), '/parent'); + this.shouldBeActive(assert, '#app-link'); + assert.equal(this.$('#parent-link').attr('href'), '/parent'); + this.shouldBeActive(assert, '#parent-link'); + + let parentController = this.getController('parent'); + + assert.equal(parentController.get('page'), 2); + + this.runTask(() => parentController.set('page', 3)); + + assert.equal(router.get('location.path'), '/parent?page=3'); + this.shouldBeActive(assert, '#app-link'); + this.shouldBeActive(assert, '#parent-link'); + + this.click('#app-link'); + + assert.equal(router.get('location.path'), '/parent'); + }); + } - bootApplication(); - equal(jQuery('#foos-link').attr('href'), '/foos'); - equal(jQuery('#baz-foos-link').attr('href'), '/foos?baz=true'); - equal(jQuery('#bars-link').attr('href'), '/bars?quux=true'); + ['@test link-to default query params while in active transition regression test'](assert) { + this.router.map(function() { + this.route('foos'); + this.route('bars'); + }); + let foos = RSVP.defer(); + let bars = RSVP.defer(); + + this.addTemplate('application', ` + {{link-to 'Foos' 'foos' id='foos-link'}} + {{link-to 'Baz Foos' 'foos' (query-params baz=true) id='baz-foos-link'}} + {{link-to 'Quux Bars' 'bars' (query-params quux=true) id='bars-link'}} + `); + this.add('controller:foos', Controller.extend({ + queryParams: ['status'], + baz: false + })); + this.add('route:foos', Route.extend({ + model() { + return foos.promise; + } + })); + this.add('controller:bars', Controller.extend({ + queryParams: ['status'], + quux: false + })); + this.add('route:bars', Route.extend({ + model() { + return bars.promise; + } + })); - equal(router.get('location.path'), ''); + return this.visit('/').then(() => { + let router = this.appRouter; + let foosLink = this.$('#foos-link'); + let barsLink = this.$('#bars-link'); + let bazLink = this.$('#baz-foos-link'); - shouldNotBeActive('#foos-link'); - shouldNotBeActive('#baz-foos-link'); - shouldNotBeActive('#bars-link'); + assert.equal(foosLink.attr('href'), '/foos'); + assert.equal(bazLink.attr('href'), '/foos?baz=true'); + assert.equal(barsLink.attr('href'), '/bars?quux=true'); + assert.equal(router.get('location.path'), '/'); + this.shouldNotBeActive(assert, '#foos-link'); + this.shouldNotBeActive(assert, '#baz-foos-link'); + this.shouldNotBeActive(assert, '#bars-link'); - run(jQuery('#bars-link'), 'click'); - shouldNotBeActive('#bars-link'); + this.runTask(() => barsLink.click()); + this.shouldNotBeActive(assert, '#bars-link'); - run(jQuery('#foos-link'), 'click'); - shouldNotBeActive('#foos-link'); + this.runTask(() => foosLink.click()); + this.shouldNotBeActive(assert, '#foos-link'); - run(foos, 'resolve'); + this.runTask(() => foos.resolve()); - equal(router.get('location.path'), '/foos'); - shouldBeActive('#foos-link'); + assert.equal(router.get('location.path'), '/foos'); + this.shouldBeActive(assert, '#foos-link'); + }); + } }); + +moduleFor('The {{link-to}} helper + query params - globals mode app', class extends AutobootApplicationTestCase { + /* + * When an exception is thrown during the initial rendering phase, the + * `visit` promise is not resolved or rejected. This means the `applicationInstance` + * is never torn down and tests running after this one will fail. + * + * It is ugly, but since this test intentionally causes an initial render + * error, it requires globals mode to access the `applicationInstance` + * for teardown after test completion. + * + * Application "globals mode" is trigged by `autoboot: true`. It doesn't + * have anything to do with the resolver. + * + * We should be able to fix this by having the application eagerly stash a + * copy of each application instance it creates. When the application is + * destroyed, it can also destroy the instances (this is how the globals + * mode avoid the problem). + * + * See: https://github.com/emberjs/ember.js/issues/15327 + */ + [`@test the {{link-to}} helper throws a useful error if you invoke it wrong`](assert) { + assert.expect(1); + + assert.throws(() => { + this.runTask(() => { + this.createApplication(); + + this.add('router:main', Router.extend({ + location: 'none' + })); + + this.addTemplate('application', `{{#link-to id='the-link'}}Index{{/link-to}}`); + }); + }, /(You must provide one or more parameters to the link-to component.|undefined is not an object)/); + } +}); \ No newline at end of file From 9208dd1ae96fc23b52e55f656981cc6d99b59e0d Mon Sep 17 00:00:00 2001 From: Patrick Robertson Date: Wed, 21 Jun 2017 17:29:21 -0400 Subject: [PATCH 059/224] Remove runloop from abstract click helper. In #15358, we discovered that not returning visit functions was causing us to use unecessary run loops. A click event shouldn't need to be scheduled in the run loop, and when that is something else is going wrong. --- packages/internal-test-helpers/lib/test-cases/abstract.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/internal-test-helpers/lib/test-cases/abstract.js b/packages/internal-test-helpers/lib/test-cases/abstract.js index 3e56714741e..3b34b63f952 100644 --- a/packages/internal-test-helpers/lib/test-cases/abstract.js +++ b/packages/internal-test-helpers/lib/test-cases/abstract.js @@ -88,7 +88,7 @@ export default class AbstractTestCase { } click(selector) { - this.runTask(() => this.$(selector).click()); + return this.$(selector).click(); } textValue() { From b2f3f6ee6f5a0f055c2a84af2a263934f66899b5 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Thu, 22 Jun 2017 09:29:54 -0700 Subject: [PATCH 060/224] Update enumerable.js More doc tweaks re: https://github.com/emberjs/ember.js/pull/15373#issuecomment-310418518 --- packages/ember-runtime/lib/mixins/enumerable.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/enumerable.js b/packages/ember-runtime/lib/mixins/enumerable.js index b1b409d9dc0..45477348392 100644 --- a/packages/ember-runtime/lib/mixins/enumerable.js +++ b/packages/ember-runtime/lib/mixins/enumerable.js @@ -616,8 +616,9 @@ const Enumerable = Mixin.create({ - `index` is the current index in the iteration. - `enumerable` is the enumerable object itself. - It should return `true` to include the item in the results, `false` - otherwise. + It must return a truthy value (i.e. `true`) to include an item in the + results. Any non-truthy return value will discard the item from the + results. Note that in addition to a callback, you can also pass an optional target object that will be set as `this` on the context. This is a good way From d3d3627554e437603f6311f94f75a024d3218caf Mon Sep 17 00:00:00 2001 From: Patrick Robertson Date: Thu, 22 Jun 2017 16:26:36 -0400 Subject: [PATCH 061/224] Deouple View Instrumentation tests from the global resolver. Also fix test failures in the link_to + query params test related to async operations. --- .../link_to_with_query_params_test.js | 9 +- .../ember/tests/view_instrumentation_test.js | 99 ++++++++----------- 2 files changed, 47 insertions(+), 61 deletions(-) diff --git a/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js b/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js index 8f0528185f1..513467bb26d 100644 --- a/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js +++ b/packages/ember/tests/helpers/link_to_test/link_to_with_query_params_test.js @@ -140,7 +140,8 @@ moduleFor('The {{link-to}} helper: invoking with query params', class extends Ap let theLink = this.$('#the-link'); assert.equal(theLink.attr('href'), '/about?baz=lol'); - this.click('#the-link'); + this.runTask(() => this.click('#the-link')); + let aboutController = this.getController('about'); assert.deepEqual(aboutController.getProperties('baz', 'bat'), @@ -241,13 +242,13 @@ moduleFor('The {{link-to}} helper: invoking with query params', class extends Ap assert.equal(router.currentRouteName, 'cars.create'); - this.click('#close-link'); + this.runTask(() => this.click('#close-link')); assert.equal(router.currentRouteName, 'cars.index'); assert.equal(router.get('url'), '/cars'); assert.equal(carsController.get('page'), 1, 'The page query-param is 1'); - this.click('#page2-link'); + this.runTask(() => this.click('#page2-link')); assert.equal(router.currentRouteName, 'cars.index', 'The active route is still cars'); assert.equal(router.get('url'), '/cars?page=2', 'The url has been updated'); @@ -474,7 +475,7 @@ moduleFor('The {{link-to}} helper: invoking with query params', class extends Ap this.shouldBeActive(assert, '#app-link'); this.shouldBeActive(assert, '#parent-link'); - this.click('#app-link'); + this.runTask(() => this.click('#app-link')); assert.equal(router.get('location.path'), '/parent'); }); diff --git a/packages/ember/tests/view_instrumentation_test.js b/packages/ember/tests/view_instrumentation_test.js index ba3cd866c5a..53c7263b223 100644 --- a/packages/ember/tests/view_instrumentation_test.js +++ b/packages/ember/tests/view_instrumentation_test.js @@ -3,67 +3,52 @@ import { instrumentationSubscribe as subscribe, instrumentationReset as reset } from 'ember-metal'; -import { jQuery as $ } from 'ember-views'; -import { Application } from 'ember-application'; -import { compile } from 'ember-template-compiler'; -import { setTemplates, setTemplate } from 'ember-glimmer'; +import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -let App, $fixture; +moduleFor('View Instrumentation', class extends ApplicationTestCase { + constructor() { + super(); + this.addTemplate('application', `{{outlet}}`); + this.addTemplate('index', `

Index

`); + this.addTemplate('posts', `

Posts

`); -function setupExample() { - // setup templates - setTemplate('application', compile('{{outlet}}')); - setTemplate('index', compile('

Index

')); - setTemplate('posts', compile('

Posts

')); - - App.Router.map(function() { - this.route('posts'); - }); -} - -function handleURL(path) { - let router = App.__container__.lookup('router:main'); - return run(router, 'handleURL', path); -} - -QUnit.module('View Instrumentation', { - setup() { - run(() => { - App = Application.create({ - rootElement: '#qunit-fixture' - }); - App.deferReadiness(); - - App.Router.reopen({ - location: 'none' - }); + this.router.map(function() { + this.route('posts'); }); - - $fixture = $('#qunit-fixture'); - setupExample(); - }, - + } teardown() { reset(); - run(App, 'destroy'); - App = null; - setTemplates({}); + super.teardown(); } -}); -QUnit.test('Nodes without view instances are instrumented', function(assert) { - let called = false; - subscribe('render', { - before() { - called = true; - }, - after() {} - }); - run(App, 'advanceReadiness'); - assert.equal($fixture.text(), 'Index', 'It rendered the right template'); - assert.ok(called, 'Instrumentation called on first render'); - called = false; - handleURL('/posts'); - assert.equal($fixture.text(), 'Posts', 'It rendered the right template'); - assert.ok(called, 'instrumentation called on transition to non-view backed route'); -}); + ['@test Nodes without view instances are instrumented'](assert) { + let called = false; + + subscribe('render', { + before() { + called = true; + }, + after() {} + }); + + return this.visit('/').then(() => { + assert.equal(this.textValue(), + 'Index', + 'It rendered the correct template' + ); + + assert.ok(called, 'Instrumentation called on first render'); + called = false; + + return this.visit('/posts'); + }).then(() => { + assert.equal(this.textValue(), + 'Posts', + 'It rendered the correct template' + ); + assert.ok(called, + 'Instrumentation called on transition to non-view backed route' + ); + }); + } +}); \ No newline at end of file From d1ead30d508f557ca9c17ba72fe6d3e9be7d05a2 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 22 Jun 2017 18:32:21 +0500 Subject: [PATCH 062/224] removed `hasThisCache` since `hasThisCache` only used `DEBUG` mode --- packages/ember-metal/lib/path_cache.js | 7 ------- packages/ember-metal/lib/property_get.js | 4 ++-- packages/ember-metal/lib/property_set.js | 5 ++--- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/ember-metal/lib/path_cache.js b/packages/ember-metal/lib/path_cache.js index 65a65dca013..e853057e80a 100644 --- a/packages/ember-metal/lib/path_cache.js +++ b/packages/ember-metal/lib/path_cache.js @@ -2,11 +2,9 @@ import Cache from './cache'; const IS_GLOBAL = /^[A-Z$]/; const IS_GLOBAL_PATH = /^[A-Z$].*[\.]/; -const HAS_THIS = 'this.'; const isGlobalCache = new Cache(1000, key => IS_GLOBAL.test(key)); const isGlobalPathCache = new Cache(1000, key => IS_GLOBAL_PATH.test(key)); -const hasThisCache = new Cache(1000, key => key.lastIndexOf(HAS_THIS, 0) === 0); const firstDotIndexCache = new Cache(1000, key => key.indexOf('.')); const firstKeyCache = new Cache(1000, (path) => { @@ -28,7 +26,6 @@ const tailPathCache = new Cache(1000, (path) => { export const caches = { isGlobalCache, isGlobalPathCache, - hasThisCache, firstDotIndexCache, firstKeyCache, tailPathCache @@ -42,10 +39,6 @@ export function isGlobalPath(path) { return isGlobalPathCache.get(path); } -export function hasThis(path) { - return hasThisCache.get(path); -} - export function isPath(path) { return firstDotIndexCache.get(path) !== -1; } diff --git a/packages/ember-metal/lib/property_get.js b/packages/ember-metal/lib/property_get.js index 9c4679de820..c4a54ec5455 100644 --- a/packages/ember-metal/lib/property_get.js +++ b/packages/ember-metal/lib/property_get.js @@ -3,7 +3,7 @@ */ import { assert } from 'ember-debug'; -import { isPath, hasThis } from './path_cache'; +import { isPath } from './path_cache'; const ALLOWABLE_TYPES = { object: true, @@ -51,7 +51,7 @@ export function get(obj, keyName) { assert(`Get must be called with two arguments; an object and a property key`, arguments.length === 2); assert(`Cannot call get with '${keyName}' on an undefined object.`, obj !== undefined && obj !== null); assert(`The key provided to get must be a string, you passed ${keyName}`, typeof keyName === 'string'); - assert(`'this' in paths is not supported`, !hasThis(keyName)); + assert(`'this' in paths is not supported`, keyName.lastIndexOf('this.', 0) !== 0); assert('Cannot call `Ember.get` with an empty string', keyName !== ''); let value = obj[keyName]; diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index 2ab309d509c..dc4778acfe2 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -7,8 +7,7 @@ import { } from './property_events'; import { - isPath, - hasThis as pathHasThis + isPath } from './path_cache'; import { peekMeta @@ -40,7 +39,7 @@ export function set(obj, keyName, value, tolerant) { ); assert(`Cannot call set with '${keyName}' on an undefined object.`, obj && typeof obj === 'object' || typeof obj === 'function'); assert(`The key provided to set must be a string, you passed ${keyName}`, typeof keyName === 'string'); - assert(`'this' in paths is not supported`, !pathHasThis(keyName)); + assert(`'this' in paths is not supported`, keyName.lastIndexOf('this.', 0) !== 0); assert(`calling set on destroyed object: ${toString(obj)}.${keyName} = ${toString(value)}`, !obj.isDestroyed); if (isPath(keyName)) { From 6d9a9735eeb04182589ff9bd98569288667cb8d8 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 22 Jun 2017 15:11:43 +0500 Subject: [PATCH 063/224] use flat array in `dsl` --- packages/ember-routing/lib/system/dsl.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/ember-routing/lib/system/dsl.js b/packages/ember-routing/lib/system/dsl.js index 485f24a1303..094d3bb08e7 100644 --- a/packages/ember-routing/lib/system/dsl.js +++ b/packages/ember-routing/lib/system/dsl.js @@ -68,7 +68,7 @@ class DSL { if (url === '' || url === '/' || parts[parts.length - 1] === 'index') { this.explicitIndex = true; } - this.matches.push([url, name, callback]); + this.matches.push(url, name, callback); } resource(name, options = {}, callback) { @@ -90,9 +90,8 @@ class DSL { } return match => { - for (let i = 0; i < dslMatches.length; i++) { - let dslMatch = dslMatches[i]; - match(dslMatch[0]).to(dslMatch[1], dslMatch[2]); + for (let i = 0; i < dslMatches.length; i += 3) { + match(dslMatches[i]).to(dslMatches[i + 1], dslMatches[i + 2]); } }; } @@ -136,7 +135,6 @@ class DSL { createRoute(childDSL, 'loading'); createRoute(childDSL, 'error', { path: dummyErrorRoute }); - engineRouteMap.class.call(childDSL); callback = childDSL.generate(); @@ -174,7 +172,7 @@ class DSL { export default DSL; function canNest(dsl) { - return dsl.parent && dsl.parent !== 'application'; + return dsl.parent !== 'application'; } function getFullName(dsl, name, resetNamespace) { From 5f386095aa9ba6ee3b193e0d7ddc74d7ff27a5f9 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 22 Jun 2017 10:35:29 +0500 Subject: [PATCH 064/224] remove dead code --- packages/ember-metal/lib/meta.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 709beec78d5..d9ae04f007b 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -506,14 +506,6 @@ if (HAS_NATIVE_WEAKMAP) { metaStore.set(obj, meta); }; - peekMeta = function WeakMap_peekMeta(obj) { - if (DEBUG) { - counters.peekCalls++ - } - - return metaStore.get(obj); - }; - peekMeta = function WeakMap_peekParentMeta(obj) { let pointer = obj; let meta; From 18aeb4fdfb1e254131044ebc7ad2ffc1dc410df4 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 22 Jun 2017 10:08:27 +0500 Subject: [PATCH 065/224] cleanup `if statements` in `property_get` --- packages/ember-metal/lib/property_get.js | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/ember-metal/lib/property_get.js b/packages/ember-metal/lib/property_get.js index 9c4679de820..7d150be8978 100644 --- a/packages/ember-metal/lib/property_get.js +++ b/packages/ember-metal/lib/property_get.js @@ -57,18 +57,14 @@ export function get(obj, keyName) { let value = obj[keyName]; let isDescriptor = value !== null && typeof value === 'object' && value.isDescriptor; - if (!isDescriptor && isPath(keyName)) { - return _getPath(obj, keyName); - } - if (isDescriptor) { return value.get(obj, keyName); + } else if (isPath(keyName)) { + return _getPath(obj, keyName); + } else if (value === undefined && + 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { + return obj.unknownProperty(keyName); } else { - if (value === undefined && - 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { - return obj.unknownProperty(keyName); - } - return value; } } @@ -93,11 +89,7 @@ export function _getPath(root, path) { } function isGettable(obj) { - if (obj === undefined || obj === null) { - return false; - } - - return ALLOWABLE_TYPES[typeof obj]; + return obj !== undefined && obj !== null && ALLOWABLE_TYPES[typeof obj]; } /** From 934024254b0257953475d38f26fe72aef5ed184e Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 21 Jun 2017 23:52:52 +0500 Subject: [PATCH 066/224] cleanup `property_set` --- packages/ember-metal/lib/property_set.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index 2ab309d509c..d7834ea3655 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -47,16 +47,11 @@ export function set(obj, keyName, value, tolerant) { return setPath(obj, keyName, value, tolerant); } - let desc, currentValue; - let possibleDesc = obj[keyName]; - if (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) { - desc = possibleDesc; - } else { - currentValue = possibleDesc; - } + let currentValue = obj[keyName]; + let isDescriptor = currentValue !== null && typeof currentValue === 'object' && currentValue.isDescriptor; - if (desc) { /* computed property */ - desc.set(obj, keyName, value); + if (isDescriptor) { /* computed property */ + currentValue.set(obj, keyName, value); } else if (obj.setUnknownProperty && currentValue === undefined && !(keyName in obj)) { /* unknown property */ assert('setUnknownProperty must be a function', typeof obj.setUnknownProperty === 'function'); obj.setUnknownProperty(keyName, value); From 974155e35d23785a6ddcd0a4a2f131a41c7cffd5 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 22 Jun 2017 01:03:28 +0500 Subject: [PATCH 067/224] avoid bool conversion --- packages/ember-metal/lib/property_events.js | 18 +++++++++--------- packages/ember-metal/lib/watch_key.js | 16 +++++++--------- .../ember-runtime/lib/system/core_object.js | 10 +++++----- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/packages/ember-metal/lib/property_events.js b/packages/ember-metal/lib/property_events.js index 423ec068576..de4d8ce9267 100644 --- a/packages/ember-metal/lib/property_events.js +++ b/packages/ember-metal/lib/property_events.js @@ -51,10 +51,10 @@ function propertyWillChange(obj, keyName, _meta) { let watching = meta && meta.peekWatching(keyName) > 0; let possibleDesc = obj[keyName]; - let desc = (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) ? possibleDesc : undefined; + let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; - if (desc && desc.willChange) { - desc.willChange(obj, keyName); + if (isDescriptor && possibleDesc.willChange) { + possibleDesc.willChange(obj, keyName); } if (watching) { @@ -90,11 +90,11 @@ function propertyDidChange(obj, keyName, _meta) { } let possibleDesc = obj[keyName]; - let desc = (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) ? possibleDesc : undefined; + let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; // shouldn't this mean that we're watching this key? - if (desc && desc.didChange) { - desc.didChange(obj, keyName); + if (isDescriptor && possibleDesc.didChange) { + possibleDesc.didChange(obj, keyName); } if (hasMeta && meta.peekWatching(keyName) > 0) { @@ -157,7 +157,7 @@ function dependentKeysDidChange(obj, depKey, meta) { } function iterDeps(method, obj, depKey, seen, meta) { - let possibleDesc, desc; + let possibleDesc, isDescriptor; let guid = guidFor(obj); let current = seen[guid]; @@ -175,9 +175,9 @@ function iterDeps(method, obj, depKey, seen, meta) { if (!value) { return; } possibleDesc = obj[key]; - desc = (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) ? possibleDesc : undefined; + isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; - if (desc && desc._suspended === obj) { + if (isDescriptor && possibleDesc._suspended === obj) { return; } diff --git a/packages/ember-metal/lib/watch_key.js b/packages/ember-metal/lib/watch_key.js index 2ce7f5c1f1b..3b8db9a6575 100644 --- a/packages/ember-metal/lib/watch_key.js +++ b/packages/ember-metal/lib/watch_key.js @@ -22,10 +22,9 @@ export function watchKey(obj, keyName, meta) { m.writeWatching(keyName, 1); let possibleDesc = obj[keyName]; - let desc = (possibleDesc !== null && - typeof possibleDesc === 'object' && - possibleDesc.isDescriptor) ? possibleDesc : undefined; - if (desc && desc.willWatch) { desc.willWatch(obj, keyName); } + let isDescriptor = possibleDesc !== null && + typeof possibleDesc === 'object' && possibleDesc.isDescriptor; + if (isDescriptor && possibleDesc.willWatch) { possibleDesc.willWatch(obj, keyName); } if ('function' === typeof obj.willWatchProperty) { obj.willWatchProperty(keyName); @@ -98,11 +97,10 @@ export function unwatchKey(obj, keyName, _meta) { meta.writeWatching(keyName, 0); let possibleDesc = obj[keyName]; - let desc = (possibleDesc !== null && - typeof possibleDesc === 'object' && - possibleDesc.isDescriptor) ? possibleDesc : undefined; + let isDescriptor = possibleDesc !== null && + typeof possibleDesc === 'object' && possibleDesc.isDescriptor; - if (desc && desc.didUnwatch) { desc.didUnwatch(obj, keyName); } + if (isDescriptor && possibleDesc.didUnwatch) { possibleDesc.didUnwatch(obj, keyName); } if ('function' === typeof obj.didUnwatchProperty) { obj.didUnwatchProperty(keyName); @@ -117,7 +115,7 @@ export function unwatchKey(obj, keyName, _meta) { // for mutation, will bypass observation. This code exists to assert when // that occurs, and attempt to provide more helpful feedback. The alternative // is tricky to debug partially observable properties. - if (!desc && keyName in obj) { + if (!isDescriptor && keyName in obj) { let maybeMandatoryDescriptor = lookupDescriptor(obj, keyName); if (maybeMandatoryDescriptor.set && maybeMandatoryDescriptor.set.isMandatorySetter) { diff --git a/packages/ember-runtime/lib/system/core_object.js b/packages/ember-runtime/lib/system/core_object.js index def42b1042a..afe37b0272d 100644 --- a/packages/ember-runtime/lib/system/core_object.js +++ b/packages/ember-runtime/lib/system/core_object.js @@ -107,9 +107,6 @@ function makeCtor() { m.writeBindings(keyName, value); } - let possibleDesc = this[keyName]; - let desc = (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) ? possibleDesc : undefined; - assert( 'Ember.Object.create no longer supports defining computed ' + 'properties. Define computed properties using extend() or reopen() ' + @@ -146,8 +143,11 @@ function makeCtor() { value = assign({}, originalValue, value); } - if (desc) { - desc.set(this, keyName, value); + let possibleDesc = this[keyName]; + let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; + + if (isDescriptor) { + possibleDesc.set(this, keyName, value); } else { if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { this.setUnknownProperty(keyName, value); From 5d7ae49a64600d1e107dbbbac37b4ca901cd7ef9 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 23 Jun 2017 15:31:30 +0200 Subject: [PATCH 068/224] helpers/current_route_name: Fix example rendering --- packages/ember-testing/lib/helpers/current_route_name.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/ember-testing/lib/helpers/current_route_name.js b/packages/ember-testing/lib/helpers/current_route_name.js index a2ef24df0ca..a1bf19d7806 100644 --- a/packages/ember-testing/lib/helpers/current_route_name.js +++ b/packages/ember-testing/lib/helpers/current_route_name.js @@ -5,13 +5,16 @@ import { get } from 'ember-metal'; /** Returns the currently active route name. + Example: + ```javascript function validateRouteName() { equal(currentRouteName(), 'some.path', "correct route was transitioned into."); } visit('/some/path').then(validateRouteName) ``` + @method currentRouteName @return {Object} The name of the currently active route. @since 1.5.0 From 0475101c6c2e99f00b015c59be4b4f65566f5721 Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 23 Jun 2017 19:32:32 +0500 Subject: [PATCH 069/224] cleanup assertion --- packages/ember-metal/lib/computed.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/ember-metal/lib/computed.js b/packages/ember-metal/lib/computed.js index 97fde136d00..fc506d66644 100644 --- a/packages/ember-metal/lib/computed.js +++ b/packages/ember-metal/lib/computed.js @@ -133,15 +133,7 @@ function ComputedProperty(config, opts) { this._getter = config; } else { assert('Ember.computed expects a function or an object as last argument.', typeof config === 'object' && !Array.isArray(config)); - assert('Config object passed to an Ember.computed can only contain `get` or `set` keys.', ((() => { - let keys = Object.keys(config); - for (let i = 0; i < keys.length; i++) { - if (keys[i] !== 'get' && keys[i] !== 'set') { - return false; - } - } - return true; - }))()); + assert('Config object passed to an Ember.computed can only contain `get` or `set` keys.', Object.keys(config).every((key)=> key === 'get' || key === 'set')); this._getter = config.get; this._setter = config.set; } From 1edd196b21b368be36260a8909cf913746352860 Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 23 Jun 2017 19:41:08 +0500 Subject: [PATCH 070/224] cleanup `defineProperty` * avoiding bool conversion * corrected `if statement` nesting --- packages/ember-metal/lib/properties.js | 58 +++++++++++++------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/packages/ember-metal/lib/properties.js b/packages/ember-metal/lib/properties.js index 3a194fd1b6f..cad54b4131b 100644 --- a/packages/ember-metal/lib/properties.js +++ b/packages/ember-metal/lib/properties.js @@ -130,14 +130,14 @@ export function defineProperty(obj, keyName, desc, data, meta) { if (!meta) { meta = metaFor(obj); } - let watchEntry = meta.peekWatching(keyName); - let possibleDesc = obj[keyName]; - let existingDesc = (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) ? possibleDesc : undefined; + let watchEntry = meta.peekWatching(keyName); let watching = watchEntry !== undefined && watchEntry > 0; + let possibleDesc = obj[keyName]; + let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; - if (existingDesc) { - existingDesc.teardown(obj, keyName); + if (isDescriptor) { + possibleDesc.teardown(obj, keyName); } let value; @@ -161,38 +161,36 @@ export function defineProperty(obj, keyName, desc, data, meta) { didDefineComputedProperty(obj.constructor); if (typeof desc.setup === 'function') { desc.setup(obj, keyName); } - } else { - if (desc == null) { - value = data; - - if (MANDATORY_SETTER) { - if (watching) { - meta.writeValues(keyName, data); - - let defaultDescriptor = { - configurable: true, - enumerable: true, - set: MANDATORY_SETTER_FUNCTION(keyName), - get: DEFAULT_GETTER_FUNCTION(keyName) - }; - - if (REDEFINE_SUPPORTED) { - Object.defineProperty(obj, keyName, defaultDescriptor); - } else { - handleBrokenPhantomDefineProperty(obj, keyName, defaultDescriptor); - } + } else if (desc === undefined || desc === null) { + value = data; + + if (MANDATORY_SETTER) { + if (watching) { + meta.writeValues(keyName, data); + + let defaultDescriptor = { + configurable: true, + enumerable: true, + set: MANDATORY_SETTER_FUNCTION(keyName), + get: DEFAULT_GETTER_FUNCTION(keyName) + }; + + if (REDEFINE_SUPPORTED) { + Object.defineProperty(obj, keyName, defaultDescriptor); } else { - obj[keyName] = data; + handleBrokenPhantomDefineProperty(obj, keyName, defaultDescriptor); } } else { obj[keyName] = data; } } else { - value = desc; - - // fallback to ES5 - Object.defineProperty(obj, keyName, desc); + obj[keyName] = data; } + } else { + value = desc; + + // fallback to ES5 + Object.defineProperty(obj, keyName, desc); } // if key is being watched, override chains that From eea8c112213138a47a53547fc15fb37300e747b9 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 24 Jun 2017 13:40:29 +0500 Subject: [PATCH 071/224] avoid toboolean coercion in `meta_listeners` --- packages/ember-metal/lib/is_proxy.js | 2 +- packages/ember-metal/lib/meta_listeners.js | 18 +++++++++--------- packages/ember-metal/lib/tags.js | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/ember-metal/lib/is_proxy.js b/packages/ember-metal/lib/is_proxy.js index 26fb6c594bf..c1ac7dd2a0b 100644 --- a/packages/ember-metal/lib/is_proxy.js +++ b/packages/ember-metal/lib/is_proxy.js @@ -1,7 +1,7 @@ import { peekMeta } from './meta'; export function isProxy(value) { - if (typeof value === 'object' && value) { + if (typeof value === 'object' && value !== null) { let meta = peekMeta(value); return meta && meta.isProxy(); } diff --git a/packages/ember-metal/lib/meta_listeners.js b/packages/ember-metal/lib/meta_listeners.js index b25dc25fa08..3902b04df42 100644 --- a/packages/ember-metal/lib/meta_listeners.js +++ b/packages/ember-metal/lib/meta_listeners.js @@ -17,7 +17,7 @@ export const SUSPENDED = 2; export const protoMethods = { addToListeners(eventName, target, method, flags) { - if (!this._listeners) { + if (this._listeners === undefined) { this._listeners = []; } this._listeners.push(eventName, target, method, flags); @@ -25,11 +25,11 @@ export const protoMethods = { _finalizeListeners() { if (this._listenersFinalized) { return; } - if (!this._listeners) { this._listeners = []; } + if (this._listeners === undefined) { this._listeners = []; } let pointer = this.parent; - while (pointer) { + while (pointer !== undefined) { let listeners = pointer._listeners; - if (listeners) { + if (listeners !== undefined) { this._listeners = this._listeners.concat(listeners); } if (pointer._listenersFinalized) { break; } @@ -40,9 +40,9 @@ export const protoMethods = { removeFromListeners(eventName, target, method, didRemove) { let pointer = this; - while (pointer) { + while (pointer !== undefined) { let listeners = pointer._listeners; - if (listeners) { + if (listeners !== undefined) { for (let index = listeners.length - 4; index >= 0; index -= 4) { if (listeners[index] === eventName && (!method || (listeners[index + 1] === target && listeners[index + 2] === method))) { if (pointer === this) { @@ -123,9 +123,9 @@ export const protoMethods = { watchedEvents() { let pointer = this; let names = {}; - while (pointer) { + while (pointer !== undefined) { let listeners = pointer._listeners; - if (listeners) { + if (listeners !== undefined) { for (let index = 0; index < listeners.length - 3; index += 4) { names[listeners[index]] = true; } @@ -141,7 +141,7 @@ function pushUniqueListener(destination, source, index) { let target = source[index + 1]; let method = source[index + 2]; for (let destinationIndex = 0; destinationIndex < destination.length - 2; destinationIndex += 3) { - if (destination[destinationIndex] === target && destination[destinationIndex + 1] === method) { + if (destination[destinationIndex] === target && destination[destinationIndex + 1] === method) { return; } } diff --git a/packages/ember-metal/lib/tags.js b/packages/ember-metal/lib/tags.js index 8f80abbc4db..2f01c3b2537 100644 --- a/packages/ember-metal/lib/tags.js +++ b/packages/ember-metal/lib/tags.js @@ -28,7 +28,7 @@ export function tagForProperty(object, propertyKey, _meta) { } export function tagFor(object, _meta) { - if (typeof object === 'object' && object) { + if (typeof object === 'object' && object !== null) { let meta = _meta || metaFor(object); return meta.writableTag(makeTag); } else { From e8dab55d185bc4da5a640fa944d23aa6cdb23d90 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 24 Jun 2017 22:59:34 +0500 Subject: [PATCH 072/224] cleanup `core-object` constructor --- .../ember-runtime/lib/system/core_object.js | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/packages/ember-runtime/lib/system/core_object.js b/packages/ember-runtime/lib/system/core_object.js index afe37b0272d..baf97efb039 100644 --- a/packages/ember-runtime/lib/system/core_object.js +++ b/packages/ember-runtime/lib/system/core_object.js @@ -80,6 +80,8 @@ function makeCtor() { let concatenatedProperties = this.concatenatedProperties; let mergedProperties = this.mergedProperties; + let hasConcatenatedProps = concatenatedProperties && concatenatedProperties.length > 0; + let hasMergedProps = mergedProperties && mergedProperties.length > 0; for (let i = 0; i < props.length; i++) { let properties = props[i]; @@ -123,11 +125,10 @@ function makeCtor() { !((keyName === 'actions') && ActionHandler.detect(this)) ); - if (concatenatedProperties && - concatenatedProperties.length > 0 && - concatenatedProperties.indexOf(keyName) > -1) { - let baseValue = this[keyName]; + let baseValue = this[keyName]; + let isDescriptor = baseValue !== null && typeof baseValue === 'object' && baseValue.isDescriptor; + if (hasConcatenatedProps && concatenatedProperties.indexOf(keyName) > -1) { if (baseValue) { value = makeArray(baseValue).concat(value); } else { @@ -135,28 +136,19 @@ function makeCtor() { } } - if (mergedProperties && - mergedProperties.length > 0 && - mergedProperties.indexOf(keyName) > -1) { - let originalValue = this[keyName]; - - value = assign({}, originalValue, value); + if (hasMergedProps && mergedProperties.indexOf(keyName) > -1) { + value = assign({}, baseValue, value); } - let possibleDesc = this[keyName]; - let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; - if (isDescriptor) { - possibleDesc.set(this, keyName, value); + baseValue.set(this, keyName, value); + } else if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { + this.setUnknownProperty(keyName, value); } else { - if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { - this.setUnknownProperty(keyName, value); + if (MANDATORY_SETTER) { + defineProperty(this, keyName, null, value); // setup mandatory setter } else { - if (MANDATORY_SETTER) { - defineProperty(this, keyName, null, value); // setup mandatory setter - } else { - this[keyName] = value; - } + this[keyName] = value; } } } From 69de17126747516c9bc64e6232dc08875d6e2940 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 24 Jun 2017 21:55:36 +0500 Subject: [PATCH 073/224] correct checks in `chains` --- packages/ember-metal/lib/chains.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/ember-metal/lib/chains.js b/packages/ember-metal/lib/chains.js index 9046bb93db7..65273bcb789 100644 --- a/packages/ember-metal/lib/chains.js +++ b/packages/ember-metal/lib/chains.js @@ -36,7 +36,7 @@ class ChainWatchers { remove(key, node) { let nodes = this.chains[key]; - if (nodes) { + if (nodes !== undefined) { for (let i = 0; i < nodes.length; i++) { if (nodes[i] === node) { nodes.splice(i, 1); @@ -48,7 +48,7 @@ class ChainWatchers { has(key, node) { let nodes = this.chains[key]; - if (nodes) { + if (nodes !== undefined) { for (let i = 0; i < nodes.length; i++) { if (nodes[i] === node) { return true; @@ -153,10 +153,10 @@ class ChainNode { this._value = value; this._paths = undefined; - if (isWatching === true) { + if (isWatching) { let obj = parent.value(); - if (!isObject(obj) === true) { + if (!isObject(obj)) { return; } @@ -167,7 +167,7 @@ class ChainNode { } value() { - if (this._value === undefined && this._watching === true) { + if (this._value === undefined && this._watching) { let obj = this._parent.value(); this._value = lazyGet(obj, this._key); } @@ -175,7 +175,7 @@ class ChainNode { } destroy() { - if (this._watching === true) { + if (this._watching) { removeChainWatcher(this._object, this._key, this); this._watching = false; // so future calls do nothing } @@ -268,7 +268,7 @@ class ChainNode { } notify(revalidate, affected) { - if (revalidate && this._watching === true) { + if (revalidate && this._watching) { let parentValue = this._parent.value(); if (parentValue !== this._object) { @@ -329,7 +329,7 @@ function lazyGet(obj, key) { } // Use `get` if the return value is an EachProxy or an uncacheable value. - if (isVolatile(obj[key]) === true) { + if (isVolatile(obj[key])) { return get(obj, key); // Otherwise attempt to get the cached value of the computed property } else { From 662e76dfe834dafa1a8c519896438bfcd5e723ab Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 25 Jun 2017 13:49:10 +0500 Subject: [PATCH 074/224] use inheritance for iterators in `iterable` --- packages/ember-glimmer/lib/utils/iterable.js | 67 +++++++------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/packages/ember-glimmer/lib/utils/iterable.js b/packages/ember-glimmer/lib/utils/iterable.js index e026da6055b..6f5deadff6a 100644 --- a/packages/ember-glimmer/lib/utils/iterable.js +++ b/packages/ember-glimmer/lib/utils/iterable.js @@ -68,7 +68,7 @@ function identity(item) { function ensureUniqueKey(seen, key) { let seenCount = seen[key]; - if (seenCount) { + if (seenCount > 0) { seen[key]++; return `${key}${ITERATOR_KEY_GUID}${seenCount}`; } else { @@ -91,13 +91,21 @@ class ArrayIterator { return false; } + getMemo(position) { + return position; + } + + getValue(position) { + return this.array[position]; + } + next() { - let { array, length, keyFor, position, seen } = this; + let { length, keyFor, position, seen } = this; if (position >= length) { return null; } - let value = array[position]; - let memo = position; + let value = this.getValue(position); + let memo = this.getMemo(position); let key = ensureUniqueKey(seen, keyFor(value, memo)); this.position++; @@ -106,59 +114,30 @@ class ArrayIterator { } } -class EmberArrayIterator { +class EmberArrayIterator extends ArrayIterator { constructor(array, keyFor) { - this.array = array; + super(array, keyFor); this.length = get(array, 'length'); - this.keyFor = keyFor; - this.position = 0; - this.seen = Object.create(null); } - isEmpty() { - return this.length === 0; - } - - next() { - let { array, length, keyFor, position, seen } = this; - - if (position >= length) { return null; } - - let value = objectAt(array, position); - let memo = position; - let key = ensureUniqueKey(seen, keyFor(value, memo)); - - this.position++; - - return { key, value, memo }; + getValue(position) { + return objectAt(this.array, position); } } -class ObjectKeysIterator { +class ObjectKeysIterator extends ArrayIterator { constructor(keys, values, keyFor) { + super(values, keyFor); this.keys = keys; - this.values = values; - this.keyFor = keyFor; - this.position = 0; - this.seen = Object.create(null); + this.length = keys.length; } - isEmpty() { - return this.keys.length === 0; + getMemo(position) { + return this.keys[position]; } - next() { - let { keys, values, keyFor, position, seen } = this; - - if (position >= keys.length) { return null; } - - let value = values[position]; - let memo = keys[position]; - let key = ensureUniqueKey(seen, keyFor(value, memo)); - - this.position++; - - return { key, value, memo }; + getValue(position) { + return this.array[position]; } } From 71de1162c7e20f04eb61339a1aee1fa7b3b02dc0 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 25 Jun 2017 23:11:26 +0500 Subject: [PATCH 075/224] remove unused vars --- packages/ember-metal/lib/mixin.js | 23 +++++++++---------- .../ember-runtime/lib/system/core_object.js | 3 +-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/ember-metal/lib/mixin.js b/packages/ember-metal/lib/mixin.js index fa3c7ab5853..51ffc12abac 100644 --- a/packages/ember-metal/lib/mixin.js +++ b/packages/ember-metal/lib/mixin.js @@ -37,19 +37,18 @@ import { removeListener } from './events'; -const a_slice = Array.prototype.slice; const a_concat = Array.prototype.concat; const { isArray } = Array; function isMethod(obj) { return 'function' === typeof obj && - obj.isMethod !== false && - obj !== Boolean && - obj !== Object && - obj !== Number && - obj !== Array && - obj !== Date && - obj !== String; + obj.isMethod !== false && + obj !== Boolean && + obj !== Object && + obj !== Number && + obj !== Array && + obj !== Date && + obj !== String; } const CONTINUE = {}; @@ -213,8 +212,8 @@ function addNormalizedProperty(base, key, value, meta, descs, values, concats, m values[key] = undefined; } else { if ((concats && concats.indexOf(key) >= 0) || - key === 'concatenatedProperties' || - key === 'mergedProperties') { + key === 'concatenatedProperties' || + key === 'mergedProperties') { value = applyConcatenatedProperties(base, key, value, values); } else if ((mergings && mergings.indexOf(key) >= 0)) { value = applyMergedProperties(base, key, value, values); @@ -736,7 +735,7 @@ export function aliasMethod(methodName) { @public */ export function observer(...args) { - let func = args.slice(-1)[0]; + let func = args[args.length - 1]; let paths; let addWatchedProperty = path => { @@ -822,7 +821,7 @@ export function _immediateObserver() { @private */ export function _beforeObserver(...args) { - let func = args.slice(-1)[0]; + let func = args[args.length - 1]; let paths; let addWatchedProperty = path => { paths.push(path); }; diff --git a/packages/ember-runtime/lib/system/core_object.js b/packages/ember-runtime/lib/system/core_object.js index baf97efb039..23720f90fc3 100644 --- a/packages/ember-runtime/lib/system/core_object.js +++ b/packages/ember-runtime/lib/system/core_object.js @@ -854,11 +854,10 @@ let ClassMixinProps = { metaForProperty(key) { let proto = this.proto(); let possibleDesc = proto[key]; - let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; assert( `metaForProperty() could not find a computed property with key '${key}'.`, - isDescriptor && possibleDesc instanceof ComputedProperty + possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ); return possibleDesc._meta || {}; }, From a1619fb854bdb775a13a8f8717dab2dfd07ca34a Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 25 Jun 2017 23:33:54 +0500 Subject: [PATCH 076/224] remove deprecated `Ember.Backburner` --- packages/ember-metal/tests/main_test.js | 6 ------ packages/ember/lib/index.js | 26 ------------------------- 2 files changed, 32 deletions(-) diff --git a/packages/ember-metal/tests/main_test.js b/packages/ember-metal/tests/main_test.js index 438a50d8d71..fafa7ff7de7 100644 --- a/packages/ember-metal/tests/main_test.js +++ b/packages/ember-metal/tests/main_test.js @@ -32,12 +32,6 @@ QUnit.test('SEMVER_REGEX properly validates and invalidates version numbers', fu validateVersionString('1.11', false); }); -QUnit.test('Ember.Backburner is deprecated', function() { - expectDeprecation(function() { - new Ember.Backburner(['foo']); - }, 'Usage of Ember.Backburner is deprecated.'); -}); - QUnit.test('Ember.K is deprecated', function(assert) { expectDeprecation(function() { let obj = { diff --git a/packages/ember/lib/index.js b/packages/ember/lib/index.js index 3900d0f05ec..9a7488e973f 100644 --- a/packages/ember/lib/index.js +++ b/packages/ember/lib/index.js @@ -259,34 +259,8 @@ Object.defineProperty(Ember, 'testing', { import Backburner from 'backburner'; -/** - @class Backburner - @for Ember - @private - */ -Ember.Backburner = function() { - deprecate( - 'Usage of Ember.Backburner is deprecated.', - false, - { - id: 'ember-metal.ember-backburner', - until: '2.8.0', - url: 'https://emberjs.com/deprecations/v2.x/#toc_ember-backburner' - } - ); - - function BackburnerAlias(args) { - return Backburner.apply(this, args); - } - - BackburnerAlias.prototype = Backburner.prototype; - - return new BackburnerAlias(arguments); -}; - Ember._Backburner = Backburner; - import Logger from 'ember-console'; Ember.Logger = Logger; From 97bd72266ffd208649820218398a74c0a7f99a6a Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 25 Jun 2017 00:42:30 +0500 Subject: [PATCH 077/224] turned throw error into `assertion` in `reduce_computed_macros` --- packages/ember-glimmer/lib/renderer.js | 4 +--- .../lib/computed/reduce_computed_macros.js | 11 +++++------ .../tests/computed/reduce_computed_macros_test.js | 10 +++++----- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/ember-glimmer/lib/renderer.js b/packages/ember-glimmer/lib/renderer.js index 2c17e8a3b0c..e598f0d96e8 100644 --- a/packages/ember-glimmer/lib/renderer.js +++ b/packages/ember-glimmer/lib/renderer.js @@ -70,9 +70,7 @@ class RootState { let result = this.result = iteratorResult.value; // override .render function after initial render - this.render = () => { - result.rerender(options); - }; + this.render = () => result.rerender(options); }; } diff --git a/packages/ember-runtime/lib/computed/reduce_computed_macros.js b/packages/ember-runtime/lib/computed/reduce_computed_macros.js index 5745c10ff7d..13b81512664 100644 --- a/packages/ember-runtime/lib/computed/reduce_computed_macros.js +++ b/packages/ember-runtime/lib/computed/reduce_computed_macros.js @@ -4,14 +4,13 @@ */ import { guidFor } from 'ember-utils'; -import { assert, Error as EmberError } from 'ember-debug'; +import { assert } from 'ember-debug'; import { get, ComputedProperty, computed, addObserver, removeObserver, - isNone, getProperties, WeakMap } from 'ember-metal'; @@ -573,9 +572,9 @@ export function intersect(...args) { @public */ export function setDiff(setAProperty, setBProperty) { - if (arguments.length !== 2) { - throw new EmberError('setDiff requires exactly two dependent arrays.'); - } + assert('Ember.computed.setDiff requires exactly two dependent arrays.', + arguments.length === 2 + ); return computed(`${setAProperty}.[]`, `${setBProperty}.[]`, function() { let setA = this.get(setAProperty); @@ -620,7 +619,7 @@ export function collect(...dependentKeys) { let res = emberA(); for (let key in properties) { if (properties.hasOwnProperty(key)) { - if (isNone(properties[key])) { + if (properties[key] === undefined) { res.push(null); } else { res.push(properties[key]); diff --git a/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js b/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js index bdf336810f6..7c13a55d879 100644 --- a/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js +++ b/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js @@ -639,17 +639,17 @@ QUnit.test('setDiff is readOnly', function() { }, /Cannot set read-only property "diff" on object:/); }); -QUnit.test('it throws an error if given fewer or more than two dependent properties', function() { - throws(function () { +QUnit.test('it asserts if given fewer or more than two dependent properties', function() { + expectAssertion(function () { EmberObject.extend({ diff: setDiff('array') }).create({ array: emberA([1, 2, 3, 4, 5, 6, 7]), array2: emberA([3, 4, 5]) }); - }, /requires exactly two dependent arrays/, 'setDiff requires two dependent arrays'); + }, /Ember\.computed\.setDiff requires exactly two dependent arrays/, 'setDiff requires two dependent arrays'); - throws(function () { + expectAssertion(function () { EmberObject.extend({ diff: setDiff('array', 'array2', 'array3') }).create({ @@ -657,7 +657,7 @@ QUnit.test('it throws an error if given fewer or more than two dependent propert array2: emberA([3, 4, 5]), array3: emberA([7]) }); - }, /requires exactly two dependent arrays/, 'setDiff requires two dependent arrays'); + }, /Ember\.computed\.setDiff requires exactly two dependent arrays/, 'setDiff requires two dependent arrays'); }); From cb7dd5053209c8511d9ec618244814d3a3768ff4 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 25 Jun 2017 09:42:10 +0500 Subject: [PATCH 078/224] cleanup `computed.teardown` --- packages/ember-metal/lib/computed.js | 5 ++--- packages/ember-metal/lib/properties.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/ember-metal/lib/computed.js b/packages/ember-metal/lib/computed.js index fc506d66644..24e6052d90a 100644 --- a/packages/ember-metal/lib/computed.js +++ b/packages/ember-metal/lib/computed.js @@ -426,13 +426,12 @@ ComputedPropertyPrototype._set = function computedPropertySet(obj, keyName, valu }; /* called before property is overridden */ -ComputedPropertyPrototype.teardown = function(obj, keyName) { +ComputedPropertyPrototype.teardown = function(obj, keyName, meta) { if (this._volatile) { return; } - let meta = metaFor(obj); let cache = meta.readableCache(); - if (cache && cache[keyName] !== undefined) { + if (cache !== undefined && cache[keyName] !== undefined) { removeDependentKeys(this, obj, keyName, meta); cache[keyName] = undefined; } diff --git a/packages/ember-metal/lib/properties.js b/packages/ember-metal/lib/properties.js index cad54b4131b..dd506cdd468 100644 --- a/packages/ember-metal/lib/properties.js +++ b/packages/ember-metal/lib/properties.js @@ -137,7 +137,7 @@ export function defineProperty(obj, keyName, desc, data, meta) { let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; if (isDescriptor) { - possibleDesc.teardown(obj, keyName); + possibleDesc.teardown(obj, keyName, meta); } let value; From 5314c87a16bc5065b28a06294bcc56b3a1d9c8d6 Mon Sep 17 00:00:00 2001 From: scalvert Date: Mon, 13 Mar 2017 10:42:33 -0700 Subject: [PATCH 079/224] Adding isActive --- packages/ember-routing/lib/services/router.js | 64 +++++ .../ember-routing/lib/system/router_state.js | 1 + .../router_service_test/isActive_test.js | 243 ++++++++++++++++++ .../router_service_test/urlFor_test.js | 27 +- .../lib/test-cases/router.js | 6 + 5 files changed, 324 insertions(+), 17 deletions(-) create mode 100644 packages/ember/tests/routing/router_service_test/isActive_test.js diff --git a/packages/ember-routing/lib/services/router.js b/packages/ember-routing/lib/services/router.js index e4c385e157f..e9894c99631 100644 --- a/packages/ember-routing/lib/services/router.js +++ b/packages/ember-routing/lib/services/router.js @@ -7,6 +7,24 @@ import { Service, readOnly } from 'ember-runtime'; +import { + get, + isEmpty +} from 'ember-metal'; +import { assign } from 'ember-utils'; +import RouterDSL from '../system/dsl'; + + +function shallowEqual(a, b) { + let k; + for (k in a) { + if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + for (k in b) { + if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + return true; +} /** The Router service is the public API that provides component/view layer @@ -19,6 +37,7 @@ import { const RouterService = Service.extend({ currentRouteName: readOnly('router.currentRouteName'), currentURL: readOnly('router.currentURL'), + currentState: readOnly('router.currentState'), location: readOnly('router.location'), rootURL: readOnly('router.rootURL'), router: null, @@ -79,6 +98,51 @@ const RouterService = Service.extend({ */ urlFor(/* routeName, ...models, options */) { return this.router.generate(...arguments); + }, + + /** + Determines whether a route is active. + + @method urlFor + @param {String} routeName the name of the route + @param {...Object} models the model(s) or identifier(s) to be used while + transitioning to the route. + @param {Object} [options] optional hash with a queryParams property + containing a mapping of query parameters + @return {String} the string representing the generated URL + @public + */ + isActive(/* routeName, ...models, options */) { + if (!this.router.isActive(...arguments)) { return false; } +debugger; + let { routeName, models, queryParams } = this._extractArguments(...arguments); + let emptyQueryParams = Object.keys(queryParams).length; + + if (!emptyQueryParams) { + let visibleQueryParams = {}; + assign(visibleQueryParams, queryParams); + + this.router._prepareQueryParams(routeName, models, visibleQueryParams); + return shallowEqual(visibleQueryParams, queryParams); + } + + return true; + }, + + _extractArguments(...args) { + let routeName; + let models; + let possibleQueryParams = args[args.length - 1]; + let queryParams = {}; + + if (possibleQueryParams && possibleQueryParams.hasOwnProperty('queryParams')) { + queryParams = args.pop().queryParams; + } + + routeName = args.shift(); + models = args; + + return { routeName, models, queryParams }; } }); diff --git a/packages/ember-routing/lib/system/router_state.js b/packages/ember-routing/lib/system/router_state.js index 446136de6b2..09a572348d2 100644 --- a/packages/ember-routing/lib/system/router_state.js +++ b/packages/ember-routing/lib/system/router_state.js @@ -8,6 +8,7 @@ export default EmberObject.extend({ routerJsState: null, isActiveIntent(routeName, models, queryParams, queryParamsMustMatch) { + debugger; let state = this.routerJsState; if (!this.routerJs.isActiveIntent(routeName, models, null, state)) { return false; } diff --git a/packages/ember/tests/routing/router_service_test/isActive_test.js b/packages/ember/tests/routing/router_service_test/isActive_test.js new file mode 100644 index 00000000000..aaa91f9cf0a --- /dev/null +++ b/packages/ember/tests/routing/router_service_test/isActive_test.js @@ -0,0 +1,243 @@ +import { + Controller, + inject, + String +} from 'ember-runtime'; +import { Component } from 'ember-glimmer'; +import { Route, NoneLocation } from 'ember-routing'; +import { + get, + set +} from 'ember-metal'; +import { + RouterTestCase, + moduleFor +} from 'internal-test-helpers'; + +import { EMBER_ROUTING_ROUTER_SERVICE } from 'ember/features'; + +if (EMBER_ROUTING_ROUTER_SERVICE) { + moduleFor('Router Service - isActive', class extends RouterTestCase { + ['@test RouterService#isActive returns true for simple route'](assert) { + assert.expect(1); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child'); + }) + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + assert.ok(this.routerService.isActive('parent.sister')); + }); + } + + ['@test RouterService#isActive returns true for simple route with dynamic segments'](assert) { + assert.expect(1); + + let dynamicModel = { id: 1 }; + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('dynamic', dynamicModel); + }) + .then(() => { + assert.ok(this.routerService.isActive('dynamic', dynamicModel)); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with basic query params'](assert) { + assert.expect(2); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + this.registerController('parent.child', Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + }) + ); + debugger; + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.ok(this.routerService.isActive('parent.child', queryParams)); + assert.notOk(this.routerService.isActive('parent.child', this.buildQueryParams({ sort: 'DESC' }))); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with array as query params'](assert) { + assert.expect(1); + + let queryParams = this.buildQueryParams({ sort: ['ascending'] }); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.ok(this.routerService.isActive('parent.child', this.buildQueryParams({ sort: 'descending' }))); + }); + } + + // ['@test RouterService#urlFor returns URL for simple route with null query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: null }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('parent.child', queryParams); + + // assert.equal('/child', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with undefined query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: undefined }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('parent.child', queryParams); + + // assert.equal('/child', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and basic query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: 'bar' }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + // assert.equal('/dynamic/1?foo=bar', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and array as query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + // assert.equal('/dynamic/1?selectedItems[]=a&selectedItems[]=b&selectedItems[]=c', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and null query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: null }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + // assert.equal('/dynamic/1', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and undefined query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: undefined }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + // assert.equal('/dynamic/1', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor correctly transitions to route via generated path'](assert) { + // assert.expect(1); + + // let expectedURL; + + // return this.visit('/') + // .then(() => { + // expectedURL = this.routerService.urlFor('parent.child'); + + // return this.routerService.transitionTo(expectedURL); + // }) + // .then(() => { + // assert.equal(expectedURL, this.routerService.get('currentURL')); + // }); + // } + + // ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments'](assert) { + // assert.expect(1); + + // let expectedURL; + // let dynamicModel = { id: 1 }; + + // this.registerRoute('dynamic', Route.extend({ + // model() { + // return dynamicModel; + // } + // })); + + // return this.visit('/') + // .then(() => { + // expectedURL = this.routerService.urlFor('dynamic', dynamicModel); + + // return this.routerService.transitionTo(expectedURL); + // }) + // .then(() => { + // assert.equal(expectedURL, this.routerService.get('currentURL')); + // }); + // } + + // ['@test RouterService#urlFor correctly transitions to route via generated path with query params'](assert) { + // assert.expect(1); + + // let expectedURL; + // let actualURL; + // let queryParams = buildQueryParams({ foo: 'bar' }); + + // return this.visit('/') + // .then(() => { + // expectedURL = this.routerService.urlFor('parent.child', queryParams); + + // return this.routerService.transitionTo(expectedURL); + // }) + // .then(() => { + // actualURL = `${this.routerService.get('currentURL')}?foo=bar`; + + // assert.equal(expectedURL, actualURL); + // }); + // } + + // ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments and query params'](assert) { + // assert.expect(1); + + // let expectedURL; + // let actualURL; + // let queryParams = buildQueryParams({ foo: 'bar' }); + // let dynamicModel = { id: 1 }; + + // this.registerRoute('dynamic', Route.extend({ + // model() { + // return dynamicModel; + // } + // })); + + // return this.visit('/') + // .then(() => { + // expectedURL = this.routerService.urlFor('dynamic', dynamicModel, queryParams); + + // return this.routerService.transitionTo(expectedURL); + // }) + // .then(() => { + // actualURL = `${this.routerService.get('currentURL')}?foo=bar`; + + // assert.equal(expectedURL, actualURL); + // }); + // } + }); +} diff --git a/packages/ember/tests/routing/router_service_test/urlFor_test.js b/packages/ember/tests/routing/router_service_test/urlFor_test.js index c17fcffa8e4..a0d8e74fd0b 100644 --- a/packages/ember/tests/routing/router_service_test/urlFor_test.js +++ b/packages/ember/tests/routing/router_service_test/urlFor_test.js @@ -3,7 +3,6 @@ import { inject, String } from 'ember-runtime'; -import { Component } from 'ember-glimmer'; import { Route, NoneLocation } from 'ember-routing'; import { get, @@ -26,12 +25,6 @@ function setupController(app, name) { }); } -function buildQueryParams(queryParams) { - return { - queryParams - }; -} - if (EMBER_ROUTING_ROUTER_SERVICE) { moduleFor('Router Service - urlFor', class extends RouterTestCase { ['@test RouterService#urlFor returns URL for simple route'](assert) { @@ -61,7 +54,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with basic query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: 'bar' }); + let queryParams = this.buildQueryParams({ foo: 'bar' }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('parent.child', queryParams); @@ -73,7 +66,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with array as query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); + let queryParams = this.buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('parent.child', queryParams); @@ -85,7 +78,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with null query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: null }); + let queryParams = this.buildQueryParams({ foo: null }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('parent.child', queryParams); @@ -97,7 +90,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with undefined query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: undefined }); + let queryParams = this.buildQueryParams({ foo: undefined }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('parent.child', queryParams); @@ -109,7 +102,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with dynamic segments and basic query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: 'bar' }); + let queryParams = this.buildQueryParams({ foo: 'bar' }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); @@ -121,7 +114,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with dynamic segments and array as query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); + let queryParams = this.buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); @@ -133,7 +126,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with dynamic segments and null query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: null }); + let queryParams = this.buildQueryParams({ foo: null }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); @@ -145,7 +138,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with dynamic segments and undefined query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: undefined }); + let queryParams = this.buildQueryParams({ foo: undefined }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); @@ -198,7 +191,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { let expectedURL; let actualURL; - let queryParams = buildQueryParams({ foo: 'bar' }); + let queryParams = this.buildQueryParams({ foo: 'bar' }); return this.visit('/') .then(() => { @@ -218,7 +211,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { let expectedURL; let actualURL; - let queryParams = buildQueryParams({ foo: 'bar' }); + let queryParams = this.buildQueryParams({ foo: 'bar' }); let dynamicModel = { id: 1 }; this.add('route:dynamic', Route.extend({ diff --git a/packages/internal-test-helpers/lib/test-cases/router.js b/packages/internal-test-helpers/lib/test-cases/router.js index 1beaa0519c3..4fc8488e4aa 100644 --- a/packages/internal-test-helpers/lib/test-cases/router.js +++ b/packages/internal-test-helpers/lib/test-cases/router.js @@ -17,4 +17,10 @@ export default class RouterTestCase extends ApplicationTestCase { get routerService() { return this.applicationInstance.lookup('service:router'); } + + buildQueryParams(queryParams) { + return { + queryParams + }; + } } From 3b9489cf6acb61c5ee22f8016f7486ef1e7133d4 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 25 Jun 2017 20:32:37 -0700 Subject: [PATCH 080/224] [FEATURE ember-routing-router-service] Cleanup and confirm expected behaviors. * Ensure that `routerService.transitionTo` and `routerService.replaceWith` does not elide query params (even the are the default values). * Update implementation of `routerService.isActive` to handle query params. * Ensure that the `router:main` injection property into the routerService is at `_router`. * Remove `routerService.currentState` * Add tests around various query param edge cases with `transitionTo` / `replaceWith` --- .../lib/system/application.js | 2 +- packages/ember-routing/lib/services/router.js | 77 ++++--- packages/ember-routing/lib/system/route.js | 2 +- packages/ember-routing/lib/system/router.js | 35 ++- .../ember-routing/lib/system/router_state.js | 1 - .../router_service_test/isActive_test.js | 200 +++--------------- .../router_service_test/replaceWith_test.js | 26 +++ .../router_service_test/transitionTo_test.js | 58 +++++ .../router_service_test/urlFor_test.js | 38 ++++ 9 files changed, 229 insertions(+), 210 deletions(-) diff --git a/packages/ember-application/lib/system/application.js b/packages/ember-application/lib/system/application.js index a9cfa3d870d..8c9e8876806 100644 --- a/packages/ember-application/lib/system/application.js +++ b/packages/ember-application/lib/system/application.js @@ -1045,7 +1045,7 @@ function commonSetupRegistry(registry) { if (EMBER_ROUTING_ROUTER_SERVICE) { registry.register('service:router', RouterService); - registry.injection('service:router', 'router', 'router:main'); + registry.injection('service:router', '_router', 'router:main'); } } diff --git a/packages/ember-routing/lib/services/router.js b/packages/ember-routing/lib/services/router.js index e9894c99631..eccdfaf0308 100644 --- a/packages/ember-routing/lib/services/router.js +++ b/packages/ember-routing/lib/services/router.js @@ -7,10 +7,6 @@ import { Service, readOnly } from 'ember-runtime'; -import { - get, - isEmpty -} from 'ember-metal'; import { assign } from 'ember-utils'; import RouterDSL from '../system/dsl'; @@ -35,12 +31,11 @@ function shallowEqual(a, b) { @category ember-routing-router-service */ const RouterService = Service.extend({ - currentRouteName: readOnly('router.currentRouteName'), - currentURL: readOnly('router.currentURL'), - currentState: readOnly('router.currentState'), - location: readOnly('router.location'), - rootURL: readOnly('router.rootURL'), - router: null, + currentRouteName: readOnly('_router.currentRouteName'), + currentURL: readOnly('_router.currentURL'), + location: readOnly('_router.location'), + rootURL: readOnly('_router.rootURL'), + _router: null, /** Transition the application into another route. The route may @@ -59,8 +54,25 @@ const RouterService = Service.extend({ attempted transition @public */ - transitionTo(/* routeNameOrUrl, ...models, options */) { - return this.router.transitionTo(...arguments); + transitionTo(...args) { + let queryParams; + let arg = args[0]; + if (resemblesURL(arg)) { + return this._router._doURLTransition('transitionTo', arg); + } + + let possibleQueryParams = args[args.length - 1]; + if (possibleQueryParams && possibleQueryParams.hasOwnProperty('queryParams')) { + queryParams = args.pop().queryParams; + } else { + queryParams = {}; + } + + let targetRouteName = args.shift(); + let transition = this._router._doTransition(targetRouteName, args, queryParams, true); + transition._keepDefaultQueryParamValues = true; + + return transition; }, /** @@ -81,13 +93,14 @@ const RouterService = Service.extend({ @public */ replaceWith(/* routeNameOrUrl, ...models, options */) { - return this.router.replaceWith(...arguments); + return this.transitionTo(...arguments).method('replace'); }, /** Generate a URL based on the supplied route name. @method urlFor + @category ember-routing-router-service @param {String} routeName the name of the route @param {...Object} models the model(s) or identifier(s) to be used while transitioning to the route. @@ -97,53 +110,53 @@ const RouterService = Service.extend({ @public */ urlFor(/* routeName, ...models, options */) { - return this.router.generate(...arguments); + return this._router.generate(...arguments); }, /** Determines whether a route is active. - @method urlFor + @method isActive + @category ember-routing-router-service @param {String} routeName the name of the route @param {...Object} models the model(s) or identifier(s) to be used while transitioning to the route. @param {Object} [options] optional hash with a queryParams property containing a mapping of query parameters - @return {String} the string representing the generated URL + @return {boolean} true if the provided routeName/models/queryParams are active @public */ isActive(/* routeName, ...models, options */) { - if (!this.router.isActive(...arguments)) { return false; } -debugger; let { routeName, models, queryParams } = this._extractArguments(...arguments); - let emptyQueryParams = Object.keys(queryParams).length; + let routerMicrolib = this._router._routerMicrolib; + let state = routerMicrolib.state; - if (!emptyQueryParams) { - let visibleQueryParams = {}; - assign(visibleQueryParams, queryParams); + if (!routerMicrolib.isActiveIntent(routeName, models, null)) { return false; } + let hasQueryParams = Object.keys(queryParams).length > 0; - this.router._prepareQueryParams(routeName, models, visibleQueryParams); - return shallowEqual(visibleQueryParams, queryParams); + if (hasQueryParams) { + this._router._prepareQueryParams(routeName, models, queryParams, true /* fromRouterService */); + return shallowEqual(queryParams, state.queryParams); } return true; }, - _extractArguments(...args) { - let routeName; - let models; - let possibleQueryParams = args[args.length - 1]; + _extractArguments(routeName, ...models) { + let possibleQueryParams = models[models.length - 1]; let queryParams = {}; if (possibleQueryParams && possibleQueryParams.hasOwnProperty('queryParams')) { - queryParams = args.pop().queryParams; + let options = models.pop(); + queryParams = options.queryParams; } - routeName = args.shift(); - models = args; - return { routeName, models, queryParams }; } }); +function resemblesURL(str) { + return typeof str === 'string' && (str === '' || str[0] === '/'); +} + export default RouterService; diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index 79c11d6c65e..07d92211c8e 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -873,7 +873,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { qp.serializedValue = svalue; let thisQueryParamHasDefaultValue = (qp.serializedDefaultValue === svalue); - if (!thisQueryParamHasDefaultValue) { + if (!thisQueryParamHasDefaultValue || transition._keepDefaultQueryParamValues) { finalParams.push({ value: svalue, visible: true, diff --git a/packages/ember-routing/lib/system/router.js b/packages/ember-routing/lib/system/router.js index f8f98f00fe9..6ffa5acefa9 100644 --- a/packages/ember-routing/lib/system/router.js +++ b/packages/ember-routing/lib/system/router.js @@ -767,7 +767,7 @@ const EmberRouter = EmberObject.extend(Evented, { } }, - _doTransition(_targetRouteName, models, _queryParams) { + _doTransition(_targetRouteName, models, _queryParams, _keepDefaultQueryParamValues) { let targetRouteName = _targetRouteName || getActiveTargetName(this._routerMicrolib); assert(`The route ${targetRouteName} was not found`, targetRouteName && this._routerMicrolib.hasRoute(targetRouteName)); @@ -776,7 +776,7 @@ const EmberRouter = EmberObject.extend(Evented, { this._processActiveTransitionQueryParams(targetRouteName, models, queryParams, _queryParams); assign(queryParams, _queryParams); - this._prepareQueryParams(targetRouteName, models, queryParams); + this._prepareQueryParams(targetRouteName, models, queryParams, _keepDefaultQueryParamValues); let transitionArgs = routeArgs(targetRouteName, models, queryParams); let transition = this._routerMicrolib.transitionTo(...transitionArgs); @@ -817,13 +817,17 @@ const EmberRouter = EmberObject.extend(Evented, { @param {String} targetRouteName @param {Array} models @param {Object} queryParams + @param {boolean} keepDefaultQueryParamValues @return {Void} */ - _prepareQueryParams(targetRouteName, models, queryParams) { + _prepareQueryParams(targetRouteName, models, queryParams, _fromRouterService) { let state = calculatePostTransitionState(this, targetRouteName, models); - this._hydrateUnsuppliedQueryParams(state, queryParams); + this._hydrateUnsuppliedQueryParams(state, queryParams, _fromRouterService); this._serializeQueryParams(state.handlerInfos, queryParams); - this._pruneDefaultQueryParamValues(state.handlerInfos, queryParams); + + if (!_fromRouterService) { + this._pruneDefaultQueryParamValues(state.handlerInfos, queryParams); + } }, /** @@ -945,7 +949,7 @@ const EmberRouter = EmberObject.extend(Evented, { @param {Object} queryParams @return {Void} */ - _hydrateUnsuppliedQueryParams(state, queryParams) { + _hydrateUnsuppliedQueryParams(state, queryParams, _fromRouterService) { let handlerInfos = state.handlerInfos; let appCache = this._bucketCache; @@ -955,12 +959,27 @@ const EmberRouter = EmberObject.extend(Evented, { if (!qpMeta) { continue; } for (let j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { - let qp = qpMeta.qps[j]; + var qp = qpMeta.qps[j]; - let presentProp = qp.prop in queryParams && qp.prop || + var presentProp = qp.prop in queryParams && qp.prop || qp.scopedPropertyName in queryParams && qp.scopedPropertyName || qp.urlKey in queryParams && qp.urlKey; + assert( + `You passed the \`${presentProp}\` query parameter during a transition into ${qp.route.routeName}, please update to ${qp.urlKey}`, + (function() { + if (qp.urlKey === presentProp) { + return true; + } + + if (_fromRouterService) { + return false; + } + + return true; + })() + ); + if (presentProp) { if (presentProp !== qp.scopedPropertyName) { queryParams[qp.scopedPropertyName] = queryParams[presentProp]; diff --git a/packages/ember-routing/lib/system/router_state.js b/packages/ember-routing/lib/system/router_state.js index 09a572348d2..446136de6b2 100644 --- a/packages/ember-routing/lib/system/router_state.js +++ b/packages/ember-routing/lib/system/router_state.js @@ -8,7 +8,6 @@ export default EmberObject.extend({ routerJsState: null, isActiveIntent(routeName, models, queryParams, queryParamsMustMatch) { - debugger; let state = this.routerJsState; if (!this.routerJs.isActiveIntent(routeName, models, null, state)) { return false; } diff --git a/packages/ember/tests/routing/router_service_test/isActive_test.js b/packages/ember/tests/routing/router_service_test/isActive_test.js index aaa91f9cf0a..1aad6807dc7 100644 --- a/packages/ember/tests/routing/router_service_test/isActive_test.js +++ b/packages/ember/tests/routing/router_service_test/isActive_test.js @@ -47,17 +47,41 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { }); } - ['@test RouterService#urlFor returns URL for simple route with basic query params'](assert) { - assert.expect(2); + ['@test RouterService#isActive does not eagerly instantiate controller for query params'](assert) { + assert.expect(1); let queryParams = this.buildQueryParams({ sort: 'ASC' }); - this.registerController('parent.child', Controller.extend({ - queryParams: ['sort'], - sort: 'ASC' + this.add('controller:parent.sister', Controller.extend({ + queryParams: ['sort'], + sort: 'ASC', + + init() { + assert.ok(false, 'should never create'); + this._super(...arguments); + } + })); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.brother'); }) - ); - debugger; + .then(() => { + assert.notOk(this.routerService.isActive('parent.sister', queryParams)); + }); + } + + ['@test RouterService#isActive is correct for simple route with basic query params'](assert) { + assert.expect(2); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + this.add('controller:parent.child', Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + }) + ); + return this.visit('/') .then(() => { return this.routerService.transitionTo('parent.child', queryParams); @@ -68,7 +92,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { }); } - ['@test RouterService#urlFor returns URL for simple route with array as query params'](assert) { + ['@test RouterService#isActive for simple route with array as query params'](assert) { assert.expect(1); let queryParams = this.buildQueryParams({ sort: ['ascending'] }); @@ -78,166 +102,8 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { return this.routerService.transitionTo('parent.child', queryParams); }) .then(() => { - assert.ok(this.routerService.isActive('parent.child', this.buildQueryParams({ sort: 'descending' }))); + assert.notOk(this.routerService.isActive('parent.child', this.buildQueryParams({ sort: 'descending' }))); }); } - - // ['@test RouterService#urlFor returns URL for simple route with null query params'](assert) { - // assert.expect(1); - - // let queryParams = buildQueryParams({ foo: null }); - - // return this.visit('/').then(() => { - // let expectedURL = this.routerService.urlFor('parent.child', queryParams); - - // assert.equal('/child', expectedURL); - // }); - // } - - // ['@test RouterService#urlFor returns URL for simple route with undefined query params'](assert) { - // assert.expect(1); - - // let queryParams = buildQueryParams({ foo: undefined }); - - // return this.visit('/').then(() => { - // let expectedURL = this.routerService.urlFor('parent.child', queryParams); - - // assert.equal('/child', expectedURL); - // }); - // } - - // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and basic query params'](assert) { - // assert.expect(1); - - // let queryParams = buildQueryParams({ foo: 'bar' }); - - // return this.visit('/').then(() => { - // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); - - // assert.equal('/dynamic/1?foo=bar', expectedURL); - // }); - // } - - // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and array as query params'](assert) { - // assert.expect(1); - - // let queryParams = buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); - - // return this.visit('/').then(() => { - // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); - - // assert.equal('/dynamic/1?selectedItems[]=a&selectedItems[]=b&selectedItems[]=c', expectedURL); - // }); - // } - - // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and null query params'](assert) { - // assert.expect(1); - - // let queryParams = buildQueryParams({ foo: null }); - - // return this.visit('/').then(() => { - // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); - - // assert.equal('/dynamic/1', expectedURL); - // }); - // } - - // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and undefined query params'](assert) { - // assert.expect(1); - - // let queryParams = buildQueryParams({ foo: undefined }); - - // return this.visit('/').then(() => { - // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); - - // assert.equal('/dynamic/1', expectedURL); - // }); - // } - - // ['@test RouterService#urlFor correctly transitions to route via generated path'](assert) { - // assert.expect(1); - - // let expectedURL; - - // return this.visit('/') - // .then(() => { - // expectedURL = this.routerService.urlFor('parent.child'); - - // return this.routerService.transitionTo(expectedURL); - // }) - // .then(() => { - // assert.equal(expectedURL, this.routerService.get('currentURL')); - // }); - // } - - // ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments'](assert) { - // assert.expect(1); - - // let expectedURL; - // let dynamicModel = { id: 1 }; - - // this.registerRoute('dynamic', Route.extend({ - // model() { - // return dynamicModel; - // } - // })); - - // return this.visit('/') - // .then(() => { - // expectedURL = this.routerService.urlFor('dynamic', dynamicModel); - - // return this.routerService.transitionTo(expectedURL); - // }) - // .then(() => { - // assert.equal(expectedURL, this.routerService.get('currentURL')); - // }); - // } - - // ['@test RouterService#urlFor correctly transitions to route via generated path with query params'](assert) { - // assert.expect(1); - - // let expectedURL; - // let actualURL; - // let queryParams = buildQueryParams({ foo: 'bar' }); - - // return this.visit('/') - // .then(() => { - // expectedURL = this.routerService.urlFor('parent.child', queryParams); - - // return this.routerService.transitionTo(expectedURL); - // }) - // .then(() => { - // actualURL = `${this.routerService.get('currentURL')}?foo=bar`; - - // assert.equal(expectedURL, actualURL); - // }); - // } - - // ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments and query params'](assert) { - // assert.expect(1); - - // let expectedURL; - // let actualURL; - // let queryParams = buildQueryParams({ foo: 'bar' }); - // let dynamicModel = { id: 1 }; - - // this.registerRoute('dynamic', Route.extend({ - // model() { - // return dynamicModel; - // } - // })); - - // return this.visit('/') - // .then(() => { - // expectedURL = this.routerService.urlFor('dynamic', dynamicModel, queryParams); - - // return this.routerService.transitionTo(expectedURL); - // }) - // .then(() => { - // actualURL = `${this.routerService.get('currentURL')}?foo=bar`; - - // assert.equal(expectedURL, actualURL); - // }); - // } }); } diff --git a/packages/ember/tests/routing/router_service_test/replaceWith_test.js b/packages/ember/tests/routing/router_service_test/replaceWith_test.js index eae51024eb0..40770d281ba 100644 --- a/packages/ember/tests/routing/router_service_test/replaceWith_test.js +++ b/packages/ember/tests/routing/router_service_test/replaceWith_test.js @@ -4,6 +4,7 @@ import { moduleFor } from 'internal-test-helpers'; import { Transition } from 'router'; +import { Controller } from 'ember-runtime'; import { EMBER_ROUTING_ROUTER_SERVICE } from 'ember/features'; @@ -105,5 +106,30 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { assert.deepEqual(this.state, ['/', '/child', '/sister', '/sister']); }); } + + ['@test RouterService#replaceWith with basic query params does not remove query param defaults'](assert) { + assert.expect(1); + + this.add('controller:parent.child', Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + })); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.brother'); + }) + .then(() => { + return this.routerService.replaceWith('parent.sister'); + }) + .then(() => { + return this.routerService.replaceWith('parent.child', queryParams); + }) + .then(() => { + assert.deepEqual(this.state, ['/', '/child?sort=ASC']); + }); + } }); } diff --git a/packages/ember/tests/routing/router_service_test/transitionTo_test.js b/packages/ember/tests/routing/router_service_test/transitionTo_test.js index cdd836c6564..ab98ce08570 100644 --- a/packages/ember/tests/routing/router_service_test/transitionTo_test.js +++ b/packages/ember/tests/routing/router_service_test/transitionTo_test.js @@ -1,6 +1,7 @@ import { inject } from 'ember-runtime'; import { Component } from 'ember-glimmer'; import { Route, NoneLocation } from 'ember-routing'; +import { Controller } from 'ember-runtime'; import { run, get, @@ -236,5 +237,62 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { this.assertText('much dynamicism'); }); } + + ['@test RouterService#transitionTo with basic query params does not remove query param defaults'](assert) { + assert.expect(1); + + this.add('controller:parent.child', Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + })); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + return this.visit('/').then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.equal(this.routerService.get('currentURL'), '/child?sort=ASC'); + }); + } + + ['@test RouterService#transitionTo with aliased query params uses the original provided key'](assert) { + assert.expect(1); + + this.add('controller:parent.child', Controller.extend({ + queryParams: { + 'cont_sort': 'url_sort' + }, + cont_sort: 'ASC' + })); + + let queryParams = this.buildQueryParams({ url_sort: 'ASC' }); + + return this.visit('/').then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.equal(this.routerService.get('currentURL'), '/child?url_sort=ASC'); + }); + } + + ['@test RouterService#transitionTo with aliased query params uses the original provided key when controller property name'](assert) { + assert.expect(1); + + this.add('controller:parent.child', Controller.extend({ + queryParams: { + 'cont_sort': 'url_sort' + }, + cont_sort: 'ASC' + })); + + let queryParams = this.buildQueryParams({ cont_sort: 'ASC' }); + + return this.visit('/').then(() => { + expectAssertion(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }, 'You passed the `cont_sort` query parameter during a transition into parent.child, please update to url_sort'); + }); + } }); } diff --git a/packages/ember/tests/routing/router_service_test/urlFor_test.js b/packages/ember/tests/routing/router_service_test/urlFor_test.js index a0d8e74fd0b..92ae2fa3178 100644 --- a/packages/ember/tests/routing/router_service_test/urlFor_test.js +++ b/packages/ember/tests/routing/router_service_test/urlFor_test.js @@ -63,6 +63,44 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { }); } + ['@test RouterService#urlFor returns URL for simple route with basic query params and default value'](assert) { + assert.expect(1); + + this.add('controller:parent.child', Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + })); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + return this.visit('/').then(() => { + let expectedURL = this.routerService.urlFor('parent.child', queryParams); + + assert.equal('/child?sort=ASC', expectedURL); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with basic query params and default value with stickyness'](assert) { + assert.expect(2); + + this.add('controller:parent.child', Controller.extend({ + queryParams: ['sort', 'foo'], + sort: 'ASC' + })); + + let queryParams = this.buildQueryParams({ sort: 'DESC' }); + + return this.visit('/child/?sort=DESC').then(() => { + let controller = this.applicationInstance.lookup('controller:parent.child'); + assert.equal(get(controller, 'sort'), 'DESC', 'sticky is set'); + + let queryParams = this.buildQueryParams({ foo: 'derp' }); + let actual = this.routerService.urlFor('parent.child', queryParams); + + assert.equal(actual, '/child?foo=derp', 'does not use "stickiness"'); + }); + } + ['@test RouterService#urlFor returns URL for simple route with array as query params'](assert) { assert.expect(1); From 724aa5407eab276a318003cb9321994d17529dba Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 25 Jun 2017 22:30:31 -0700 Subject: [PATCH 081/224] [FEATURE ember-routing-router-service] Enable by default. Enables the first phase of the routing service by default. The service implements all proposed API's (with the proposed semantics) that are not returning RouteInfo objects (that will come in a later stage). --- features.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features.json b/features.json index 7622a80e070..4f73e99c77f 100644 --- a/features.json +++ b/features.json @@ -5,7 +5,7 @@ "ember-improved-instrumentation": null, "ember-metal-weakmap": null, "ember-glimmer-allow-backtracking-rerender": null, - "ember-routing-router-service": null, + "ember-routing-router-service": true, "ember-engines-mount-params": true, "glimmer-custom-component-manager": null }, From 4ce419565db027fa7fb8e0821fe74f353c3ea402 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 26 Jun 2017 00:23:36 +0500 Subject: [PATCH 082/224] reuse empty func in `ember-debug` --- packages/ember-debug/lib/index.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/ember-debug/lib/index.js b/packages/ember-debug/lib/index.js index a076b9ded10..50c963e90fe 100644 --- a/packages/ember-debug/lib/index.js +++ b/packages/ember-debug/lib/index.js @@ -6,9 +6,9 @@ import EmberError from './error'; import { default as isFeatureEnabled } from './features'; import * as FLAGS from 'ember/features'; let { DEFAULT_FEATURES, FEATURES } = FLAGS; - import _deprecate from './deprecate'; import _warn from './warn'; + export { registerHandler as registerWarnHandler } from './warn'; export { registerHandler as registerDeprecationHandler } from './deprecate'; export { default as isFeatureEnabled } from './features'; @@ -16,20 +16,21 @@ export { default as Error } from './error'; export { isTesting, setTesting } from './testing'; // These are the default production build versions: -let assert = () => {}; -let info = () => {}; -let warn = () => {}; -let debug = () => {}; -let deprecate = () => {}; -let debugSeal = () => {}; -let debugFreeze = () => {}; -let runInDebug = () => {}; +const noop = () => {}; + +let assert = noop; +let info = noop; +let warn = noop; +let debug = noop; +let deprecate = noop; +let debugSeal = noop; +let debugFreeze = noop; +let runInDebug = noop; +let setDebugFunction = noop; +let getDebugFunction = noop; let deprecateFunc = function() { return arguments[arguments.length - 1]; }; -let setDebugFunction = () => {}; -let getDebugFunction = () => {}; - if (DEBUG) { setDebugFunction = function(type, callback) { switch (type) { From d0f320a8ebac19f3f0afeb94784b8b79abb75464 Mon Sep 17 00:00:00 2001 From: Mikhail Topolskiy Date: Wed, 18 Jan 2017 21:15:55 +0300 Subject: [PATCH 083/224] [BUGFIX beta] Allow boolean values for current-when As the docs say, `A link will be active if current-when is true`. Looks like this might have been broken since 1.13 and https://github.com/emberjs/ember.js/pull/12344 did not seem to actually fix this particular bug. Related issues: - https://github.com/emberjs/ember.js/issues/12512 - https://github.com/emberjs/ember.js/pull/12630 (fix was not merged) - https://github.com/emberjs/ember.js/issues/12296 --- packages/ember-glimmer/lib/components/link-to.js | 6 +++++- packages/ember/tests/helpers/link_to_test.js | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/ember-glimmer/lib/components/link-to.js b/packages/ember-glimmer/lib/components/link-to.js index 2cb83ac33be..73f5c2cde46 100644 --- a/packages/ember-glimmer/lib/components/link-to.js +++ b/packages/ember-glimmer/lib/components/link-to.js @@ -549,8 +549,12 @@ const LinkComponent = EmberComponent.extend({ let routing = get(this, '_routing'); let models = get(this, 'models'); let resolvedQueryParams = get(this, 'resolvedQueryParams'); - let currentWhen = get(this, 'current-when'); + + if (typeof currentWhen === 'boolean') { + return currentWhen ? get(this, 'activeClass') : false; + } + let isCurrentWhenSpecified = !!currentWhen; currentWhen = currentWhen || get(this, 'qualifiedRouteName'); currentWhen = currentWhen.split(' '); diff --git a/packages/ember/tests/helpers/link_to_test.js b/packages/ember/tests/helpers/link_to_test.js index 8b8baa0fae3..d0b645cc526 100644 --- a/packages/ember/tests/helpers/link_to_test.js +++ b/packages/ember/tests/helpers/link_to_test.js @@ -527,6 +527,22 @@ moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class assert.equal(this.$('#link3.active').length, 0, 'The link is not active since current-when does not contain the active route'); } + ['@test The {{link-to}} helper supports boolean values for current-when'](assert) { + this.router.map(function(match) { + this.route('index', { path: '/' }, function() { + this.route('about'); + }); + this.route('item'); + }); + + this.addTemplate('index', `

Home

{{outlet}}`); + this.addTemplate('index.about', `{{#link-to 'item' id='other-link' current-when=true}}ITEM{{/link-to}}`); + + this.visit('/about'); + + assert.equal(this.$('#other-link').length, 1, 'The link is active since current-when is true'); + } + ['@test The {{link-to}} helper defaults to bubbling'](assert) { this.addTemplate('about', `
From b9b3e2c097565ca88c8b9ab18e03250a80f69ebf Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 22 Jun 2017 16:11:49 +0500 Subject: [PATCH 084/224] cleaner logic --- packages/ember-metal/lib/property_set.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index d7834ea3655..b6edf413e66 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -94,22 +94,17 @@ if (MANDATORY_SETTER) { } function setPath(root, path, value, tolerant) { - // get the last part of the path - let keyName = path.slice(path.lastIndexOf('.') + 1); - - // get the first part of the part - path = (path === keyName) ? keyName : path.slice(0, path.length - (keyName.length + 1)); - - // unless the path is this, look up the first part to - // get the root - if (path !== 'this') { - root = getPath(root, path); - } + let parts = path.split('.'); + let keyName = parts.pop(); if (!keyName || keyName.length === 0) { throw new EmberError('Property set failed: You passed an empty path'); } + path = parts.length > 0 ? parts.join('.') : keyName; + + root = getPath(root, path); + if (!root) { if (tolerant) { return; From 790a3dbb2b589476ca723d83411f9568f06a0668 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 26 Jun 2017 18:18:22 +0500 Subject: [PATCH 085/224] correct `undefined` checks --- packages/ember-glimmer/lib/modifiers/action.js | 2 +- packages/ember-runtime/lib/mixins/target_action_support.js | 2 +- packages/ember-testing/lib/helpers/fill_in.js | 2 +- packages/ember-testing/lib/helpers/key_event.js | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-glimmer/lib/modifiers/action.js b/packages/ember-glimmer/lib/modifiers/action.js index 8585e36c0d2..28a4ea05188 100644 --- a/packages/ember-glimmer/lib/modifiers/action.js +++ b/packages/ember-glimmer/lib/modifiers/action.js @@ -11,7 +11,7 @@ const MODIFIERS = ['alt', 'shift', 'meta', 'ctrl']; const POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; function isAllowedEvent(event, allowedKeys) { - if (allowedKeys === null || typeof allowedKeys === 'undefined') { + if (allowedKeys === null || allowedKeys === undefined) { if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { return isSimpleClick(event); } else { diff --git a/packages/ember-runtime/lib/mixins/target_action_support.js b/packages/ember-runtime/lib/mixins/target_action_support.js index e1e899ff2be..0a4f8129952 100644 --- a/packages/ember-runtime/lib/mixins/target_action_support.js +++ b/packages/ember-runtime/lib/mixins/target_action_support.js @@ -109,7 +109,7 @@ export default Mixin.create({ return ret.concat(options); } - if (typeof actionContext === 'undefined') { + if (actionContext === undefined) { actionContext = get(this, 'actionContextObject') || this; } diff --git a/packages/ember-testing/lib/helpers/fill_in.js b/packages/ember-testing/lib/helpers/fill_in.js index 38bffd752b6..5e59add6254 100644 --- a/packages/ember-testing/lib/helpers/fill_in.js +++ b/packages/ember-testing/lib/helpers/fill_in.js @@ -24,7 +24,7 @@ import { focus, fireEvent } from '../events'; */ export default function fillIn(app, selector, contextOrText, text) { let $el, el, context; - if (typeof text === 'undefined') { + if (text === undefined) { text = contextOrText; } else { context = contextOrText; diff --git a/packages/ember-testing/lib/helpers/key_event.js b/packages/ember-testing/lib/helpers/key_event.js index c98d89976bb..c41ca8f0574 100644 --- a/packages/ember-testing/lib/helpers/key_event.js +++ b/packages/ember-testing/lib/helpers/key_event.js @@ -21,7 +21,7 @@ export default function keyEvent(app, selector, contextOrType, typeOrKeyCode, keyCode) { let context, type; - if (typeof keyCode === 'undefined') { + if (keyCode === undefined) { context = null; keyCode = typeOrKeyCode; type = contextOrType; @@ -30,5 +30,5 @@ export default function keyEvent(app, selector, contextOrType, typeOrKeyCode, ke type = typeOrKeyCode; } - return app.testHelpers.triggerEvent(selector, context, type, { keyCode: keyCode, which: keyCode }); + return app.testHelpers.triggerEvent(selector, context, type, { keyCode, which: keyCode }); } From 7c205b974c7d22d9cef74337edf2ed9452a6227f Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 26 Jun 2017 18:28:32 +0500 Subject: [PATCH 086/224] cleanup `target_action_support` --- .../lib/mixins/target_action_support.js | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/target_action_support.js b/packages/ember-runtime/lib/mixins/target_action_support.js index e1e899ff2be..62456e0ea2f 100644 --- a/packages/ember-runtime/lib/mixins/target_action_support.js +++ b/packages/ember-runtime/lib/mixins/target_action_support.js @@ -93,21 +93,9 @@ export default Mixin.create({ @private */ triggerAction(opts = {}) { - let action = opts.action || get(this, 'action'); - let target = opts.target; - - if (!target) { - target = getTarget(this); - } - - let actionContext = opts.actionContext; - - function args(options, actionName) { - let ret = []; - if (actionName) { ret.push(actionName); } - - return ret.concat(options); - } + let { action, target, actionContext } = opts; + action = action || get(this, 'action'); + target = target || getTarget(this); if (typeof actionContext === 'undefined') { actionContext = get(this, 'actionContextObject') || this; @@ -117,20 +105,18 @@ export default Mixin.create({ let ret; if (target.send) { - ret = target.send(...args(actionContext, action)); + ret = target.send(...[action].concat(actionContext)); } else { assert(`The action '${action}' did not exist on ${target}`, typeof target[action] === 'function'); - ret = target[action](...args(actionContext)); + ret = target[action](...[].concat(actionContext)); } if (ret !== false) { - ret = true; + return true; } - - return ret; - } else { - return false; } + + return false; } }); From defd2544faaff798fed16e0019fb88af5313694f Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 25 Jun 2017 12:19:38 +0500 Subject: [PATCH 087/224] use `ensureInstance` to ensure runloop in `tags` --- packages/ember-metal/lib/tags.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/ember-metal/lib/tags.js b/packages/ember-metal/lib/tags.js index 2f01c3b2537..b5dbd55c52e 100644 --- a/packages/ember-metal/lib/tags.js +++ b/packages/ember-metal/lib/tags.js @@ -39,14 +39,14 @@ export function tagFor(object, _meta) { export function markObjectAsDirty(meta, propertyKey) { let objectTag = meta.readableTag(); - if (objectTag) { + if (objectTag !== undefined) { objectTag.dirty(); } let tags = meta.readableTags(); - let propertyTag = tags && tags[propertyKey]; + let propertyTag = tags !== undefined ? tags[propertyKey] : undefined; - if (propertyTag) { + if (propertyTag !== undefined) { propertyTag.dirty(); } @@ -54,21 +54,18 @@ export function markObjectAsDirty(meta, propertyKey) { meta.getTag().contentDidChange(); } - if (objectTag || propertyTag) { + if (objectTag !== undefined || propertyTag !== undefined) { ensureRunloop(); } } let run; - -function K() {} - function ensureRunloop() { - if (!run) { + if (run === undefined) { run = require('ember-metal').run; } - if (hasViews() && !run.backburner.currentInstance) { - run.schedule('actions', K); + if (hasViews()) { + run.backburner.ensureInstance(); } } From b1d93ed2f653d226c316cac81f10a2ad246cb321 Mon Sep 17 00:00:00 2001 From: bekzod Date: Tue, 27 Jun 2017 09:56:20 +0500 Subject: [PATCH 088/224] bumped `backburner.js` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d59779f59e4..8bef442a5b1 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "babel-plugin-transform-es2015-template-literals": "^6.22.0", "babel-plugin-transform-proto-to-assign": "^6.23.0", "babel-template": "^6.24.1", - "backburner.js": "^1.0.0", + "backburner.js": "^1.1.0", "broccoli-babel-transpiler": "next", "broccoli-concat": "^3.2.2", "broccoli-file-creator": "^1.1.1", From e8a9bce9e929e0b2e3c53af50099cd90d8ac26d8 Mon Sep 17 00:00:00 2001 From: Gavin Joyce Date: Tue, 27 Jun 2017 09:23:40 +0100 Subject: [PATCH 089/224] [DEPRECATION] update dispatch to event manager deprecation until version --- packages/ember-views/lib/mixins/view_support.js | 2 +- packages/ember-views/lib/system/event_dispatcher.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-views/lib/mixins/view_support.js b/packages/ember-views/lib/mixins/view_support.js index a4595c56a49..385b6e882c6 100644 --- a/packages/ember-views/lib/mixins/view_support.js +++ b/packages/ember-views/lib/mixins/view_support.js @@ -412,7 +412,7 @@ export default Mixin.create({ false, { id: 'ember-views.event-dispatcher.canDispatchToEventManager', - until: '2.16.0' + until: '2.17.0' } ); diff --git a/packages/ember-views/lib/system/event_dispatcher.js b/packages/ember-views/lib/system/event_dispatcher.js index df297906f47..2a631bcbef4 100644 --- a/packages/ember-views/lib/system/event_dispatcher.js +++ b/packages/ember-views/lib/system/event_dispatcher.js @@ -143,7 +143,7 @@ export default EmberObject.extend({ !('canDispatchToEventManager' in this), { id: 'ember-views.event-dispatcher.canDispatchToEventManager', - until: '2.16.0' + until: '2.17.0' } ); }, From bd6c5d3149fdb0891d92605d358f15b13c76fbe4 Mon Sep 17 00:00:00 2001 From: Patrick Robertson Date: Fri, 16 Jun 2017 10:45:26 -0400 Subject: [PATCH 090/224] Decouple toString tests from the Global resolver. --- .../dependency_injection/to_string_test.js | 94 +++++++++---------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/packages/ember-application/tests/system/dependency_injection/to_string_test.js b/packages/ember-application/tests/system/dependency_injection/to_string_test.js index 64dcd30fd9a..4985eb4bbad 100644 --- a/packages/ember-application/tests/system/dependency_injection/to_string_test.js +++ b/packages/ember-application/tests/system/dependency_injection/to_string_test.js @@ -1,62 +1,58 @@ -import { guidFor } from 'ember-utils'; -import { ENV, context } from 'ember-environment'; // lookup, etc -import { run } from 'ember-metal'; -import Application from '../../../system/application'; +import { guidFor, assign } from 'ember-utils'; import { Object as EmberObject } from 'ember-runtime'; -import DefaultResolver from '../../../system/resolver'; - -let originalLookup, App; - -QUnit.module('Ember.Application Dependency Injection – toString', { - setup() { - originalLookup = context.lookup; - - run(() => { - App = Application.create(); - context.lookup = { - App: App - }; - }); - - App.Post = EmberObject.extend(); - }, - - teardown() { - context.lookup = originalLookup; - run(App, 'destroy'); +import { Resolver as DefaultResolver } from 'ember-application'; +import { moduleFor, ApplicationTestCase, ModuleBasedTestResolver, + DefaultResolverApplicationTestCase } from 'internal-test-helpers'; + +moduleFor('Ember.Application Dependency Injection - DefaultResolver#toString', class extends + DefaultResolverApplicationTestCase { + constructor() { + super(); + this.createApplication(); + this.application.Post = EmberObject.extend(); + this.visit('/'); } -}); -QUnit.test('factories', function() { - let PostFactory; - PostFactory = App.__container__.factoryFor('model:post').class; - equal(PostFactory.toString(), 'App.Post', 'expecting the model to be post'); -}); + ['@test factories'](assert) { + let PostFactory = this.applicationInstance.factoryFor('model:post').class; + assert.equal( + PostFactory.toString(), '.Post', + 'expecting the model to be post' + ); + } -QUnit.test('instances', function() { - let post = App.__container__.lookup('model:post'); - let guid = guidFor(post); + ['@test instances'](assert) { + let post = this.applicationInstance.lookup('model:post'); + let guid = guidFor(post); - equal(post.toString(), '', 'expecting the model to be post'); + assert.equal(post.toString(), '<.Post:' + guid + '>', 'expecting the model to be post'); + } }); -QUnit.test('with a custom resolver', function() { - run(App, 'destroy'); +moduleFor('Ember.Application Dependency Injection - Resolver#toString', class extends ApplicationTestCase { + constructor() { + super(); + this.visit('/'); + } - run(() => { - App = Application.create({ - Resolver: DefaultResolver.extend({ - makeToString(factory, fullName) { + get applicationOptions() { + return assign(super.applicationOptions, { + Resolver: class extends ModuleBasedTestResolver { + makeToString(_, fullName) { return fullName; } - }) + } }); - }); - - App.register('model:peter', EmberObject.extend()); + } - let peter = App.__container__.lookup('model:peter'); - let guid = guidFor(peter); + ['@test toString called on a resolver'](assert) { + this.add('model:peter', EmberObject.extend()); - equal(peter.toString(), '', 'expecting the supermodel to be peter'); -}); + let peter = this.applicationInstance.lookup('model:peter'); + let guid = guidFor(peter); + assert.equal( + peter.toString(), ``, + 'expecting the supermodel to be peter' + ); + } +}); \ No newline at end of file From bd6967b150d433cbd5f9d5a0b6748cbf87876666 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 27 Jun 2017 14:45:37 -0700 Subject: [PATCH 091/224] cleanup unused function --- packages/ember-template-compiler/lib/system/compile-options.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/ember-template-compiler/lib/system/compile-options.js b/packages/ember-template-compiler/lib/system/compile-options.js index ae990f35c60..bb1deaaa862 100644 --- a/packages/ember-template-compiler/lib/system/compile-options.js +++ b/packages/ember-template-compiler/lib/system/compile-options.js @@ -25,9 +25,6 @@ export default function compileOptions(_options) { return options; } -function ensurePlugin(FunctionOrPlugin) { -} - export function registerPlugin(type, _plugin) { if (type !== 'ast') { throw new Error(`Attempting to register ${_plugin} as "${type}" which is not a valid Glimmer plugin type.`); From d28121a7ae311396e04021dbf5e90bc8607504fe Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 28 Jun 2017 12:04:28 +0500 Subject: [PATCH 092/224] use `peekMeta` instead of `metaFor` --- packages/ember-metal/lib/watch_key.js | 7 ++++--- packages/ember-metal/lib/watch_path.js | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/ember-metal/lib/watch_key.js b/packages/ember-metal/lib/watch_key.js index 3b8db9a6575..fe7e5a78943 100644 --- a/packages/ember-metal/lib/watch_key.js +++ b/packages/ember-metal/lib/watch_key.js @@ -1,7 +1,8 @@ import { lookupDescriptor } from 'ember-utils'; import { MANDATORY_SETTER } from 'ember/features'; import { - meta as metaFor + meta as metaFor, + peekMeta } from './meta'; import { MANDATORY_SETTER_FUNCTION, @@ -87,10 +88,10 @@ export function unwatchKey(obj, keyName, _meta) { if (typeof obj !== 'object' || obj === null) { return; } - let meta = _meta || metaFor(obj); + let meta = _meta || peekMeta(obj); // do nothing of this object has already been destroyed - if (meta.isSourceDestroyed()) { return; } + if (!meta || meta.isSourceDestroyed()) { return; } let count = meta.peekWatching(keyName); if (count === 1) { diff --git a/packages/ember-metal/lib/watch_path.js b/packages/ember-metal/lib/watch_path.js index 5301b1614d1..f6c2c1c55ff 100644 --- a/packages/ember-metal/lib/watch_path.js +++ b/packages/ember-metal/lib/watch_path.js @@ -1,5 +1,6 @@ import { - meta as metaFor + meta as metaFor, + peekMeta } from './meta'; import { ChainNode } from './chains'; @@ -32,8 +33,8 @@ export function unwatchPath(obj, keyPath, meta) { if (typeof obj !== 'object' || obj === null) { return; } - let m = meta || metaFor(obj); - let counter = m.peekWatching(keyPath) || 0; + let m = meta || peekMeta(obj); + let counter = m && m.peekWatching(keyPath) || 0; if (counter === 1) { m.writeWatching(keyPath, 0); From cecf68a048942886136d3419f68b73841a9c56ad Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 28 Jun 2017 12:18:05 +0500 Subject: [PATCH 093/224] cleanup `watch_key` and `watch_path` --- packages/ember-metal/lib/watch_key.js | 16 ++++++---------- packages/ember-metal/lib/watch_path.js | 18 +++++++----------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/packages/ember-metal/lib/watch_key.js b/packages/ember-metal/lib/watch_key.js index fe7e5a78943..34578f375a3 100644 --- a/packages/ember-metal/lib/watch_key.js +++ b/packages/ember-metal/lib/watch_key.js @@ -13,15 +13,13 @@ import { let handleMandatorySetter; export function watchKey(obj, keyName, meta) { - if (typeof obj !== 'object' || obj === null) { - return; - } - let m = meta || metaFor(obj); + if (typeof obj !== 'object' || obj === null) { return; } - // activate watching first time - if (!m.peekWatching(keyName)) { - m.writeWatching(keyName, 1); + let m = meta || metaFor(obj); + let count = m.peekWatching(keyName) || 0; + m.writeWatching(keyName, count + 1); + if (count === 0) { // activate watching first time let possibleDesc = obj[keyName]; let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; @@ -35,8 +33,6 @@ export function watchKey(obj, keyName, meta) { // NOTE: this is dropped for prod + minified builds handleMandatorySetter(m, obj, keyName); } - } else { - m.writeWatching(keyName, (m.peekWatching(keyName) || 0) + 1); } } @@ -91,7 +87,7 @@ export function unwatchKey(obj, keyName, _meta) { let meta = _meta || peekMeta(obj); // do nothing of this object has already been destroyed - if (!meta || meta.isSourceDestroyed()) { return; } + if (meta === undefined || meta.isSourceDestroyed()) { return; } let count = meta.peekWatching(keyName); if (count === 1) { diff --git a/packages/ember-metal/lib/watch_path.js b/packages/ember-metal/lib/watch_path.js index f6c2c1c55ff..fb76aaa84f1 100644 --- a/packages/ember-metal/lib/watch_path.js +++ b/packages/ember-metal/lib/watch_path.js @@ -16,25 +16,21 @@ export function makeChainNode(obj) { } export function watchPath(obj, keyPath, meta) { - if (typeof obj !== 'object' || obj === null) { - return; - } + if (typeof obj !== 'object' || obj === null) { return; } let m = meta || metaFor(obj); let counter = m.peekWatching(keyPath) || 0; - if (!counter) { // activate watching first time - m.writeWatching(keyPath, 1); + + m.writeWatching(keyPath, counter + 1); + if (counter === 0) { // activate watching first time chainsFor(obj, m).add(keyPath); - } else { - m.writeWatching(keyPath, counter + 1); } } export function unwatchPath(obj, keyPath, meta) { - if (typeof obj !== 'object' || obj === null) { - return; - } + if (typeof obj !== 'object' || obj === null) { return; } let m = meta || peekMeta(obj); - let counter = m && m.peekWatching(keyPath) || 0; + if (m === undefined) { return; } + let counter = m.peekWatching(keyPath) || 0; if (counter === 1) { m.writeWatching(keyPath, 0); From 144b998e4124d82374bebbbf063f85067271547b Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 25 Jun 2017 08:58:13 +0500 Subject: [PATCH 094/224] cleanup `computed` --- packages/ember-metal/lib/computed.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/ember-metal/lib/computed.js b/packages/ember-metal/lib/computed.js index fc506d66644..87a0d13f028 100644 --- a/packages/ember-metal/lib/computed.js +++ b/packages/ember-metal/lib/computed.js @@ -138,7 +138,6 @@ function ComputedProperty(config, opts) { this._setter = config.set; } assert('Computed properties must receive a getter or a setter, you passed none.', !!this._getter || !!this._setter); - this._dependentKeys = undefined; this._suspended = undefined; this._meta = undefined; this._volatile = false; @@ -408,9 +407,7 @@ ComputedPropertyPrototype._set = function computedPropertySet(obj, keyName, valu if (hadCachedValue) { cache[keyName] = undefined; - } - - if (!hadCachedValue) { + } else { addDependentKeys(this, obj, keyName, meta); } @@ -523,17 +520,12 @@ ComputedPropertyPrototype.teardown = function(obj, keyName) { @return {Ember.ComputedProperty} property descriptor instance @public */ -export default function computed(func) { - let args; - - if (arguments.length > 1) { - args = [].slice.call(arguments); - func = args.pop(); - } +export default function computed(...args) { + let func = args.pop(); let cp = new ComputedProperty(func); - if (args) { + if (args.length > 0) { cp.property(...args); } From cc33c0bf40c9c6e6b3e2db0e6d8870dbba4944d3 Mon Sep 17 00:00:00 2001 From: bekzod Date: Tue, 27 Jun 2017 00:44:06 +0500 Subject: [PATCH 095/224] `Ember.observer` cleanup --- packages/ember-metal/lib/mixin.js | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/ember-metal/lib/mixin.js b/packages/ember-metal/lib/mixin.js index 51ffc12abac..1107411661a 100644 --- a/packages/ember-metal/lib/mixin.js +++ b/packages/ember-metal/lib/mixin.js @@ -735,32 +735,28 @@ export function aliasMethod(methodName) { @public */ export function observer(...args) { - let func = args[args.length - 1]; - let paths; - - let addWatchedProperty = path => { - paths.push(path); - }; - let _paths = args.slice(0, -1); - - if (typeof func !== 'function') { + let _paths, func; + if (typeof args[args.length - 1] !== 'function') { // revert to old, soft-deprecated argument ordering deprecate('Passing the dependentKeys after the callback function in Ember.observer is deprecated. Ensure the callback function is the last argument.', false, { id: 'ember-metal.observer-argument-order', until: '3.0.0' }); - func = args[0]; - _paths = args.slice(1); + func = args.shift(); + _paths = args; + } else { + func = args.pop(); + _paths = args; } - paths = []; + assert('Ember.observer called without a function', typeof func === 'function'); + assert('Ember.observer called without valid path', _paths.length > 0 && _paths.every((p)=> p && p.length)); + + let paths = []; + let addWatchedProperty = path => paths.push(path); for (let i = 0; i < _paths.length; ++i) { expandProperties(_paths[i], addWatchedProperty); } - if (typeof func !== 'function') { - throw new EmberError('Ember.observer called without a function'); - } - func.__ember_observes__ = paths; return func; } From 77b839fcc068e62ff95fc2c6e4d58ea2771887b4 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 29 Jun 2017 19:01:24 +0500 Subject: [PATCH 096/224] added test for `observer` assertions --- packages/ember-metal/lib/mixin.js | 2 +- packages/ember-metal/tests/observer_test.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/ember-metal/lib/mixin.js b/packages/ember-metal/lib/mixin.js index 1107411661a..00630226f29 100644 --- a/packages/ember-metal/lib/mixin.js +++ b/packages/ember-metal/lib/mixin.js @@ -748,7 +748,7 @@ export function observer(...args) { } assert('Ember.observer called without a function', typeof func === 'function'); - assert('Ember.observer called without valid path', _paths.length > 0 && _paths.every((p)=> p && p.length)); + assert('Ember.observer called without valid path', _paths.length > 0 && _paths.every((p)=> typeof p === 'string' && p.length)); let paths = []; let addWatchedProperty = path => paths.push(path); diff --git a/packages/ember-metal/tests/observer_test.js b/packages/ember-metal/tests/observer_test.js index 49c70d714ae..1dcd81bd048 100644 --- a/packages/ember-metal/tests/observer_test.js +++ b/packages/ember-metal/tests/observer_test.js @@ -31,6 +31,18 @@ function K() {} QUnit.module('addObserver'); +testBoth('observer should assert to invalid input', function(get, set) { + expectAssertion(()=> { + observer(()=>{}) + }, 'Ember.observer called without valid path'); + + expectDeprecation('Passing the dependentKeys after the callback function in Ember.observer is deprecated. Ensure the callback function is the last argument.') + + expectAssertion(()=> { + observer(null) + }, 'Ember.observer called without a function'); +}) + testBoth('observer should fire when property is modified', function(get, set) { let obj = {}; let count = 0; From af8a2e5f6f286a9630ef080e40f2527d4ce7b808 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Thu, 22 Jun 2017 22:14:34 -0700 Subject: [PATCH 097/224] Decouple default_resolver_test from defaults The `default_resolver_test.js` was written under the assumption that the Ember `DefaultResolver` globals resolver would be an application default. This decouples away from that. --- .../default_resolver_test.js | 462 ++++++++++-------- .../internal-test-helpers/lib/module-for.js | 4 + .../default-resolver-application.js | 5 +- 3 files changed, 271 insertions(+), 200 deletions(-) diff --git a/packages/ember-application/tests/system/dependency_injection/default_resolver_test.js b/packages/ember-application/tests/system/dependency_injection/default_resolver_test.js index 80cb142c138..8a114b27b1f 100644 --- a/packages/ember-application/tests/system/dependency_injection/default_resolver_test.js +++ b/packages/ember-application/tests/system/dependency_injection/default_resolver_test.js @@ -1,6 +1,10 @@ /* globals EmberDev */ +import { + moduleFor, + DefaultResolverApplicationTestCase +} from 'internal-test-helpers'; + import { context } from 'ember-environment'; -import { run } from 'ember-metal'; import { Controller, Service, @@ -8,280 +12,340 @@ import { Namespace } from 'ember-runtime'; import { Route } from 'ember-routing'; -import Application from '../../../system/application'; import { Component, - setTemplates, - setTemplate, Helper, helper as makeHelper, } from 'ember-glimmer'; -import { compile } from 'ember-template-compiler'; import { getDebugFunction, setDebugFunction } from 'ember-debug'; -let registry, locator, application, originalLookup, originalInfo; - -QUnit.module('Ember.Application Dependency Injection - default resolver', { - setup() { - originalLookup = context.lookup; - application = run(Application, 'create'); - - registry = application.__registry__; - locator = application.__container__; - originalInfo = getDebugFunction('info'); - }, +moduleFor('Ember.Application Dependency Injection - Integration - default resolver', class extends DefaultResolverApplicationTestCase { - teardown() { - setTemplates({}); - context.lookup = originalLookup; - run(application, 'destroy'); - let UserInterfaceNamespace = Namespace.NAMESPACES_BY_ID['UserInterface']; - if (UserInterfaceNamespace) { run(UserInterfaceNamespace, 'destroy'); } + beforeEach() { + this.runTask(() => this.createApplication()); + return this.visit('/'); + } - setDebugFunction('info', originalInfo); + get privateRegistry() { + return this.application.__registry__; } -}); -QUnit.test('the default resolver can look things up in other namespaces', function() { - let UserInterface = context.lookup.UserInterface = Namespace.create(); - UserInterface.NavigationController = Controller.extend(); + /* + * This first batch of tests are integration tests against the public + * applicationInstance API. + */ + + [`@test the default resolver looks up templates in Ember.TEMPLATES`](assert) { + let fooTemplate = this.addTemplate('foo', `foo template`); + let fooBarTemplate = this.addTemplate('fooBar', `fooBar template`); + let fooBarBazTemplate = this.addTemplate('fooBar/baz', `fooBar/baz template`); + + assert.equal( + this.applicationInstance.factoryFor('template:foo').class, fooTemplate, + 'resolves template:foo' + ); + assert.equal( + this.applicationInstance.factoryFor('template:fooBar').class, fooBarTemplate, + 'resolves template:foo_bar' + ); + assert.equal( + this.applicationInstance.factoryFor('template:fooBar.baz').class, fooBarBazTemplate, + 'resolves template:foo_bar.baz' + ); + } - let nav = locator.lookup('controller:userInterface/navigation'); + [`@test the default resolver looks up basic name as no prefix`](assert) { + let instance = this.applicationInstance.lookup('controller:basic'); + assert.ok( + Controller.detect(instance), + 'locator looks up correct controller' + ); + } - ok(nav instanceof UserInterface.NavigationController, 'the result should be an instance of the specified class'); -}); + [`@test the default resolver looks up arbitrary types on the namespace`](assert) { + let Class = this.application.FooManager = EmberObject.extend(); + let resolvedClass = this.application.resolveRegistration('manager:foo'); + assert.equal( + Class, resolvedClass, + 'looks up FooManager on application' + ); + } -QUnit.test('the default resolver looks up templates in Ember.TEMPLATES', function() { - let fooTemplate = compile('foo template'); - let fooBarTemplate = compile('fooBar template'); - let fooBarBazTemplate = compile('fooBar/baz template'); + [`@test the default resolver resolves models on the namespace`](assert) { + let Class = this.application.Post = EmberObject.extend(); + let factoryClass = this.applicationInstance.factoryFor('model:post').class; + assert.equal( + Class, factoryClass, + 'looks up Post model on application' + ); + } - setTemplate('foo', fooTemplate); - setTemplate('fooBar', fooBarTemplate); - setTemplate('fooBar/baz', fooBarBazTemplate); + [`@test the default resolver resolves *:main on the namespace`](assert) { + let Class = this.application.FooBar = EmberObject.extend(); + let factoryClass = this.applicationInstance.factoryFor('foo-bar:main').class; + assert.equal( + Class, factoryClass, + 'looks up FooBar type without name on application' + ); + } - equal(locator.factoryFor('template:foo').class, fooTemplate, 'resolves template:foo'); - equal(locator.factoryFor('template:fooBar').class, fooBarTemplate, 'resolves template:foo_bar'); - equal(locator.factoryFor('template:fooBar.baz').class, fooBarBazTemplate, 'resolves template:foo_bar.baz'); -}); + [`@test the default resolver resolves container-registered helpers`](assert) { + let shorthandHelper = makeHelper(() => {}); + let helper = Helper.extend(); -QUnit.test('the default resolver looks up basic name as no prefix', function() { - ok(Controller.detect(locator.lookup('controller:basic')), 'locator looks up correct controller'); -}); + this.application.register('helper:shorthand', shorthandHelper); + this.application.register('helper:complete', helper); -function detectEqual(first, second, message) { - ok(first.detect(second), message); -} + let lookedUpShorthandHelper = this.applicationInstance.factoryFor('helper:shorthand').class; -QUnit.test('the default resolver looks up arbitrary types on the namespace', function() { - application.FooManager = EmberObject.extend({}); + assert.ok(lookedUpShorthandHelper.isHelperInstance, 'shorthand helper isHelper'); - detectEqual(application.FooManager, registry.resolve('manager:foo'), 'looks up FooManager on application'); -}); + let lookedUpHelper = this.applicationInstance.factoryFor('helper:complete').class; -QUnit.test('the default resolver resolves models on the namespace', function() { - application.Post = EmberObject.extend({}); + assert.ok(lookedUpHelper.isHelperFactory, 'complete helper is factory'); + assert.ok(helper.detect(lookedUpHelper), 'looked up complete helper'); + } - detectEqual(application.Post, locator.factoryFor('model:post').class, 'looks up Post model on application'); -}); + [`@test the default resolver resolves container-registered helpers via lookupFor`](assert) { + let shorthandHelper = makeHelper(() => {}); + let helper = Helper.extend(); -QUnit.test('the default resolver resolves *:main on the namespace', function() { - application.FooBar = EmberObject.extend({}); + this.application.register('helper:shorthand', shorthandHelper); + this.application.register('helper:complete', helper); - detectEqual(application.FooBar, locator.factoryFor('foo-bar:main').class, 'looks up FooBar type without name on application'); -}); + let lookedUpShorthandHelper = this.applicationInstance.factoryFor('helper:shorthand').class; -QUnit.test('the default resolver resolves container-registered helpers', function() { - let shorthandHelper = makeHelper(() => {}); - let helper = Helper.extend(); + assert.ok(lookedUpShorthandHelper.isHelperInstance, 'shorthand helper isHelper'); - application.register('helper:shorthand', shorthandHelper); - application.register('helper:complete', helper); + let lookedUpHelper = this.applicationInstance.factoryFor('helper:complete').class; - let lookedUpShorthandHelper = locator.factoryFor('helper:shorthand').class; + assert.ok(lookedUpHelper.isHelperFactory, 'complete helper is factory'); + assert.ok(helper.detect(lookedUpHelper), 'looked up complete helper'); + } - ok(lookedUpShorthandHelper.isHelperInstance, 'shorthand helper isHelper'); + [`@test the default resolver resolves helpers on the namespace`](assert) { + let ShorthandHelper = makeHelper(() => {}); + let CompleteHelper = Helper.extend(); - let lookedUpHelper = locator.factoryFor('helper:complete').class; + this.application.ShorthandHelper = ShorthandHelper; + this.application.CompleteHelper = CompleteHelper; - ok(lookedUpHelper.isHelperFactory, 'complete helper is factory'); - ok(helper.detect(lookedUpHelper), 'looked up complete helper'); -}); + let resolvedShorthand = this.application.resolveRegistration('helper:shorthand'); + let resolvedComplete = this.application.resolveRegistration('helper:complete'); + assert.equal(resolvedShorthand, ShorthandHelper, 'resolve fetches the shorthand helper factory'); + assert.equal(resolvedComplete, CompleteHelper, 'resolve fetches the complete helper factory'); + } -QUnit.test('the default resolver resolves container-registered helpers via lookupFor', function() { - let shorthandHelper = makeHelper(() => {}); - let helper = Helper.extend(); + [`@test the default resolver resolves to the same instance, no matter the notation `](assert) { + this.application.NestedPostController = Controller.extend({}); - application.register('helper:shorthand', shorthandHelper); - application.register('helper:complete', helper); + assert.equal( + this.applicationInstance.lookup('controller:nested-post'), + this.applicationInstance.lookup('controller:nested_post'), + 'looks up NestedPost controller on application' + ); + } - let lookedUpShorthandHelper = locator.factoryFor('helper:shorthand').class; + [`@test the default resolver throws an error if the fullName to resolve is invalid`](assert) { + assert.throws(() => { this.applicationInstance.resolveRegistration(undefined);}, TypeError, /Invalid fullName/); + assert.throws(() => { this.applicationInstance.resolveRegistration(null); }, TypeError, /Invalid fullName/); + assert.throws(() => { this.applicationInstance.resolveRegistration(''); }, TypeError, /Invalid fullName/); + assert.throws(() => { this.applicationInstance.resolveRegistration(''); }, TypeError, /Invalid fullName/); + assert.throws(() => { this.applicationInstance.resolveRegistration(':'); }, TypeError, /Invalid fullName/); + assert.throws(() => { this.applicationInstance.resolveRegistration('model'); }, TypeError, /Invalid fullName/); + assert.throws(() => { this.applicationInstance.resolveRegistration('model:'); }, TypeError, /Invalid fullName/); + assert.throws(() => { this.applicationInstance.resolveRegistration(':type'); }, TypeError, /Invalid fullName/); + } - ok(lookedUpShorthandHelper.isHelperInstance, 'shorthand helper isHelper'); + /* + * The following are integration tests against the private registry API. + */ + + [`@test lookup description`](assert) { + this.application.toString = () => 'App'; + + assert.equal( + this.privateRegistry.describe('controller:foo'), 'App.FooController', + 'Type gets appended at the end' + ); + assert.equal( + this.privateRegistry.describe('controller:foo.bar'), 'App.FooBarController', + 'dots are removed' + ); + assert.equal( + this.privateRegistry.describe('model:foo'), 'App.Foo', + 'models don\'t get appended at the end' + ); + } - let lookedUpHelper = locator.factoryFor('helper:complete').class; + [`@test assertion for routes without isRouteFactory property`](assert) { + this.application.FooRoute = Component.extend(); - ok(lookedUpHelper.isHelperFactory, 'complete helper is factory'); - ok(helper.detect(lookedUpHelper), 'looked up complete helper'); -}); + expectAssertion(() => { + this.privateRegistry.resolve(`route:foo`) + }, /to resolve to an Ember.Route/, 'Should assert'); + } -QUnit.test('the default resolver resolves helpers on the namespace', function() { - let ShorthandHelper = makeHelper(() => {}); - let CompleteHelper = Helper.extend(); - let LegacyHTMLBarsBoundHelper; + [`@test no assertion for routes that extend from Ember.Route`](assert) { + assert.expect(0); + this.application.FooRoute = Route.extend(); + this.privateRegistry.resolve(`route:foo`); + } - application.ShorthandHelper = ShorthandHelper; - application.CompleteHelper = CompleteHelper; + [`@test deprecation warning for service factories without isServiceFactory property`](assert) { + expectAssertion(() =>{ + this.application.FooService = EmberObject.extend(); + this.privateRegistry.resolve('service:foo'); + }, /Expected service:foo to resolve to an Ember.Service but instead it was \.FooService\./); + } - let resolvedShorthand = registry.resolve('helper:shorthand'); - let resolvedComplete = registry.resolve('helper:complete'); + [`@test no deprecation warning for service factories that extend from Ember.Service`](assert) { + assert.expect(0); + this.application.FooService = Service.extend(); + this.privateRegistry.resolve('service:foo'); + } - equal(resolvedShorthand, ShorthandHelper, 'resolve fetches the shorthand helper factory'); - equal(resolvedComplete, CompleteHelper, 'resolve fetches the complete helper factory'); -}); + [`@test deprecation warning for component factories without isComponentFactory property`](assert) { + expectAssertion(() => { + this.application.FooComponent = EmberObject.extend(); + this.privateRegistry.resolve('component:foo'); + }, /Expected component:foo to resolve to an Ember\.Component but instead it was \.FooComponent\./); + } -QUnit.test('the default resolver resolves to the same instance, no matter the notation ', function() { - application.NestedPostController = Controller.extend({}); + [`@test no deprecation warning for component factories that extend from Ember.Component`](assert) { + expectNoDeprecation(); + this.application.FooView = Component.extend(); + this.privateRegistry.resolve('component:foo'); + } - equal(locator.lookup('controller:nested-post'), locator.lookup('controller:nested_post'), 'looks up NestedPost controller on application'); -}); + [`@test knownForType returns each item for a given type found`](assert) { + this.application.FooBarHelper = 'foo'; + this.application.BazQuxHelper = 'bar'; -QUnit.test('the default resolver throws an error if the fullName to resolve is invalid', function() { - throws(() => { registry.resolve(undefined);}, TypeError, /Invalid fullName/); - throws(() => { registry.resolve(null); }, TypeError, /Invalid fullName/); - throws(() => { registry.resolve(''); }, TypeError, /Invalid fullName/); - throws(() => { registry.resolve(''); }, TypeError, /Invalid fullName/); - throws(() => { registry.resolve(':'); }, TypeError, /Invalid fullName/); - throws(() => { registry.resolve('model'); }, TypeError, /Invalid fullName/); - throws(() => { registry.resolve('model:'); }, TypeError, /Invalid fullName/); - throws(() => { registry.resolve(':type'); }, TypeError, /Invalid fullName/); -}); + let found = this.privateRegistry.resolver.knownForType('helper'); -QUnit.test('the default resolver logs hits if `LOG_RESOLVER` is set', function() { - if (EmberDev && EmberDev.runningProdBuild) { - ok(true, 'Logging does not occur in production builds'); - return; + assert.deepEqual(found, { + 'helper:foo-bar': true, + 'helper:baz-qux': true + }); } - expect(3); + [`@test knownForType is not required to be present on the resolver`](assert) { + delete this.privateRegistry.resolver.knownForType; - application.LOG_RESOLVER = true; - application.ScoobyDoo = EmberObject.extend(); - application.toString = () => 'App'; + this.privateRegistry.resolver.knownForType('helper', () => { }); - setDebugFunction('info', function(symbol, name, padding, lookupDescription) { - equal(symbol, '[✓]', 'proper symbol is printed when a module is found'); - equal(name, 'doo:scooby', 'proper lookup value is logged'); - equal(lookupDescription, 'App.ScoobyDoo'); - }); + assert.ok(true, 'does not error'); + } - registry.resolve('doo:scooby'); }); -QUnit.test('the default resolver logs misses if `LOG_RESOLVER` is set', function() { - if (EmberDev && EmberDev.runningProdBuild) { - ok(true, 'Logging does not occur in production builds'); - return; - } +moduleFor('Ember.Application Dependency Injection - Integration - default resolver w/ other namespace', class extends DefaultResolverApplicationTestCase { - expect(3); + beforeEach() { + this.UserInterface = context.lookup.UserInterface = Namespace.create(); + this.runTask(() => this.createApplication()); + return this.visit('/'); + } - application.LOG_RESOLVER = true; - application.toString = () => 'App'; + teardown() { + let UserInterfaceNamespace = Namespace.NAMESPACES_BY_ID['UserInterface']; + if (UserInterfaceNamespace) { + this.runTask(() => { + UserInterfaceNamespace.destroy(); + }); + } + super.teardown(); + } - setDebugFunction('info', function(symbol, name, padding, lookupDescription) { - equal(symbol, '[ ]', 'proper symbol is printed when a module is not found'); - equal(name, 'doo:scooby', 'proper lookup value is logged'); - equal(lookupDescription, 'App.ScoobyDoo'); - }); + [`@test the default resolver can look things up in other namespaces`](assert) { + this.UserInterface.NavigationController = Controller.extend(); - registry.resolve('doo:scooby'); -}); + let nav = this.applicationInstance.lookup('controller:userInterface/navigation'); -QUnit.test('doesn\'t log without LOG_RESOLVER', function() { - if (EmberDev && EmberDev.runningProdBuild) { - ok(true, 'Logging does not occur in production builds'); - return; + assert.ok( + nav instanceof this.UserInterface.NavigationController, + 'the result should be an instance of the specified class' + ); } +}); - let infoCount = 0; +moduleFor('Ember.Application Dependency Injection - Integration - default resolver', class extends DefaultResolverApplicationTestCase { - application.ScoobyDoo = EmberObject.extend(); + constructor() { + super(); + this._originalLookup = context.lookup; + this._originalInfo = getDebugFunction('info'); + } - setDebugFunction('info', (symbol, name) => infoCount = infoCount + 1); + beforeEach() { + this.runTask(() => this.createApplication()); + return this.visit('/'); + } - registry.resolve('doo:scooby'); - registry.resolve('doo:scrappy'); - equal(infoCount, 0, 'Logger.info should not be called if LOG_RESOLVER is not set'); -}); + teardown() { + setDebugFunction('info', this._originalInfo); + context.lookup = this._originalLookup; + super.teardown(); + } -QUnit.test('lookup description', function() { - application.toString = () => 'App'; + [`@test the default resolver logs hits if 'LOG_RESOLVER' is set`](assert) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; + } - equal(registry.describe('controller:foo'), 'App.FooController', 'Type gets appended at the end'); - equal(registry.describe('controller:foo.bar'), 'App.FooBarController', 'dots are removed'); - equal(registry.describe('model:foo'), 'App.Foo', 'models don\'t get appended at the end'); -}); + assert.expect(3); -QUnit.test('assertion for routes without isRouteFactory property', function() { - application.FooRoute = Component.extend(); + this.application.LOG_RESOLVER = true; + this.application.ScoobyDoo = EmberObject.extend(); + this.application.toString = () => 'App'; - expectAssertion(() => registry.resolve(`route:foo`), /to resolve to an Ember.Route/, 'Should assert'); -}); + setDebugFunction('info', function(symbol, name, padding, lookupDescription) { + assert.equal(symbol, '[✓]', 'proper symbol is printed when a module is found'); + assert.equal(name, 'doo:scooby', 'proper lookup value is logged'); + assert.equal(lookupDescription, 'App.ScoobyDoo'); + }); -QUnit.test('no assertion for routes that extend from Ember.Route', function() { - expect(0); - application.FooRoute = Route.extend(); - registry.resolve(`route:foo`); -}); + this.applicationInstance.resolveRegistration('doo:scooby'); + } -QUnit.test('deprecation warning for service factories without isServiceFactory property', function() { - expectAssertion(() =>{ - application.FooService = EmberObject.extend(); - registry.resolve('service:foo'); - }, /Expected service:foo to resolve to an Ember.Service but instead it was \.FooService\./); -}); + [`@test the default resolver logs misses if 'LOG_RESOLVER' is set`](assert) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; + } -QUnit.test('no deprecation warning for service factories that extend from Ember.Service', function() { - expect(0); - application.FooService = Service.extend(); - registry.resolve('service:foo'); -}); + assert.expect(3); -QUnit.test('deprecation warning for component factories without isComponentFactory property', function() { - expectAssertion(() => { - application.FooComponent = EmberObject.extend(); - registry.resolve('component:foo'); - }, /Expected component:foo to resolve to an Ember\.Component but instead it was \.FooComponent\./); -}); + this.application.LOG_RESOLVER = true; + this.application.toString = () => 'App'; -QUnit.test('no deprecation warning for component factories that extend from Ember.Component', function() { - expectNoDeprecation(); - application.FooView = Component.extend(); - registry.resolve('component:foo'); -}); + setDebugFunction('info', function(symbol, name, padding, lookupDescription) { + assert.equal(symbol, '[ ]', 'proper symbol is printed when a module is not found'); + assert.equal(name, 'doo:scooby', 'proper lookup value is logged'); + assert.equal(lookupDescription, 'App.ScoobyDoo'); + }); -QUnit.test('knownForType returns each item for a given type found', function() { - application.FooBarHelper = 'foo'; - application.BazQuxHelper = 'bar'; + this.applicationInstance.resolveRegistration('doo:scooby'); + } - let found = registry.resolver.knownForType('helper'); + [`@test doesn't log without LOG_RESOLVER`](assert) { + if (EmberDev && EmberDev.runningProdBuild) { + assert.ok(true, 'Logging does not occur in production builds'); + return; + } - // using `Object.keys` and manually confirming values over using `deepEqual` - // due to an issue in QUnit (through at least 1.20.0) that are unable to properly compare - // objects with an `undefined` constructor (like ember-metal/empty_object) - let foundKeys = Object.keys(found); + let infoCount = 0; - deepEqual(foundKeys, ['helper:foo-bar', 'helper:baz-qux']); - ok(found['helper:foo-bar']); - ok(found['helper:baz-qux']); -}); + this.application.ScoobyDoo = EmberObject.extend(); -QUnit.test('knownForType is not required to be present on the resolver', function() { - delete registry.resolver.knownForType; + setDebugFunction('info', (symbol, name) => infoCount = infoCount + 1); - registry.resolver.knownForType('helper', () => { }); + this.applicationInstance.resolveRegistration('doo:scooby'); + this.applicationInstance.resolveRegistration('doo:scrappy'); + assert.equal(infoCount, 0, 'Logger.info should not be called if LOG_RESOLVER is not set'); + } - ok(true, 'does not error'); }); diff --git a/packages/internal-test-helpers/lib/module-for.js b/packages/internal-test-helpers/lib/module-for.js index 278be7649a8..f99c358d1a0 100644 --- a/packages/internal-test-helpers/lib/module-for.js +++ b/packages/internal-test-helpers/lib/module-for.js @@ -1,3 +1,4 @@ +import { RSVP } from 'ember-runtime'; import applyMixins from './apply-mixins'; export default function moduleFor(description, TestClass, ...mixins) { @@ -6,6 +7,9 @@ export default function moduleFor(description, TestClass, ...mixins) { QUnit.module(description, { setup() { context = new TestClass(); + if (context.beforeEach) { + return context.beforeEach(); + } }, teardown() { diff --git a/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js b/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js index bd7a93334cf..594150e5e19 100644 --- a/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js +++ b/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js @@ -7,11 +7,14 @@ import { } from 'ember-glimmer'; import { assign } from 'ember-utils'; import { runDestroy } from '../run'; +import { Router } from 'ember-routing'; export default class ApplicationTestCase extends AbstractApplicationTestCase { createApplication() { - return this.application = Application.create(this.applicationOptions); + let application = this.application = Application.create(this.applicationOptions); + application.Router = Router.extend({ location: 'none' }); + return application; } get applicationOptions() { From e6d1dbe704ebceadc42ac9e9786095a97ad143cb Mon Sep 17 00:00:00 2001 From: Brian Runnells Date: Tue, 27 Jun 2017 16:09:35 -0500 Subject: [PATCH 098/224] use updated address for model_factory_injections deprecation --- packages/ember/lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember/lib/index.js b/packages/ember/lib/index.js index 9a7488e973f..cf9ba435e6d 100644 --- a/packages/ember/lib/index.js +++ b/packages/ember/lib/index.js @@ -185,7 +185,7 @@ if (DEBUG) { { id: 'ember-metal.model_factory_injections', until: '2.17.0', - url: 'https://emberjs.com/deprecations/v2.x/#toc_ember-model-em-factory-em-injections-removed' + url: 'https://emberjs.com/deprecations/v2.x/#toc_id-ember-metal-model_factory_injections' } ); }, From 7939b1d82447e475500992593e31d607970c72bf Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 29 Jun 2017 16:51:19 +0500 Subject: [PATCH 099/224] use `peekMeta` in `watchedEvents` --- packages/ember-metal/lib/events.js | 9 ++++----- packages/ember-metal/lib/watch_key.js | 7 +++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/ember-metal/lib/events.js b/packages/ember-metal/lib/events.js index 673cfe40fb9..173f6253a59 100644 --- a/packages/ember-metal/lib/events.js +++ b/packages/ember-metal/lib/events.js @@ -3,12 +3,10 @@ @submodule ember-metal */ import { applyStr } from 'ember-utils'; -import { meta as metaFor, peekMeta } from './meta'; import { deprecate, assert } from 'ember-debug'; - +import { meta as metaFor, peekMeta } from './meta'; import { ONCE, SUSPENDED } from './meta_listeners'; - /* The event system uses a series of nested hashes to store listeners on an object. When a listener is registered, or when an event arrives, these @@ -185,7 +183,8 @@ export function suspendListeners(obj, eventNames, target, method, callback) { @param obj */ export function watchedEvents(obj) { - return metaFor(obj).watchedEvents(); + let meta = peekMeta(obj); + return meta && meta.watchedEvents() || []; } /** @@ -212,7 +211,7 @@ export function sendEvent(obj, eventName, params, actions, _meta) { meta.matchingListeners(eventName); } - if (actions === undefined || actions.length === 0) { return; } + if (actions === undefined || actions.length === 0) { return false; } for (let i = actions.length - 3; i >= 0; i -= 3) { // looping in reverse for once listeners let target = actions[i]; diff --git a/packages/ember-metal/lib/watch_key.js b/packages/ember-metal/lib/watch_key.js index 34578f375a3..ee3087230d8 100644 --- a/packages/ember-metal/lib/watch_key.js +++ b/packages/ember-metal/lib/watch_key.js @@ -2,7 +2,8 @@ import { lookupDescriptor } from 'ember-utils'; import { MANDATORY_SETTER } from 'ember/features'; import { meta as metaFor, - peekMeta + peekMeta, + UNDEFINED } from './meta'; import { MANDATORY_SETTER_FUNCTION, @@ -78,8 +79,6 @@ if (MANDATORY_SETTER) { }; } -import { UNDEFINED } from './meta'; - export function unwatchKey(obj, keyName, _meta) { if (typeof obj !== 'object' || obj === null) { return; @@ -87,7 +86,7 @@ export function unwatchKey(obj, keyName, _meta) { let meta = _meta || peekMeta(obj); // do nothing of this object has already been destroyed - if (meta === undefined || meta.isSourceDestroyed()) { return; } + if (!meta || meta.isSourceDestroyed()) { return; } let count = meta.peekWatching(keyName); if (count === 1) { From c422e0d3ff72fe876fbe551bc8821f5938affc29 Mon Sep 17 00:00:00 2001 From: Longfei Wu Date: Wed, 28 Jun 2017 10:57:42 +0800 Subject: [PATCH 100/224] fix typo --- packages/ember-routing/lib/system/route.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index 07d92211c8e..1f0b0f66295 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -1980,7 +1980,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { renderTemplate(controller, model){ this.render('posts', { // the template to render, referenced by name into: 'application', // the template to render into, referenced by name - outlet: 'anOutletName', // the outlet inside `options.template` to render into. + outlet: 'anOutletName', // the outlet inside `options.into` to render into. controller: 'someControllerName', // the controller to use for this template, referenced by name model: model // the model to set on `options.controller`. }) @@ -2042,7 +2042,7 @@ let Route = EmberObject.extend(ActionHandler, Evented, { @param {Object} [options] the options @param {String} [options.into] the template to render into, referenced by name. Defaults to the parent template - @param {String} [options.outlet] the outlet inside `options.template` to render into. + @param {String} [options.outlet] the outlet inside `options.into` to render into. Defaults to 'main' @param {String|Object} [options.controller] the controller to use for this template, referenced by name or as a controller instance. Defaults to the Route's paired controller From d8880eed573a56c8a9172ef9d2bebcfe8fd25582 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 25 Jun 2017 09:15:45 +0500 Subject: [PATCH 101/224] avoid extra checks for `lookupDescriptor` return value --- packages/ember-metal/lib/meta.js | 4 +--- packages/ember-metal/lib/property_set.js | 1 - packages/ember-metal/lib/watch_key.js | 9 +++++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index d9ae04f007b..61c00252310 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -480,9 +480,7 @@ if (MANDATORY_SETTER) { Meta.prototype.writeValue = function(obj, key, value) { let descriptor = lookupDescriptor(obj, key); - let isMandatorySetter = descriptor !== undefined && - descriptor !== null && - descriptor.set && descriptor.set.isMandatorySetter; + let isMandatorySetter = descriptor !== null && descriptor.set && descriptor.set.isMandatorySetter; if (isMandatorySetter) { this.writeValues(key, value); diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index d7834ea3655..bb316c643b8 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -56,7 +56,6 @@ export function set(obj, keyName, value, tolerant) { assert('setUnknownProperty must be a function', typeof obj.setUnknownProperty === 'function'); obj.setUnknownProperty(keyName, value); } else if (currentValue === value) { /* no change */ - return value; } else { let meta = peekMeta(obj); propertyWillChange(obj, keyName, meta); diff --git a/packages/ember-metal/lib/watch_key.js b/packages/ember-metal/lib/watch_key.js index ee3087230d8..36304f07cd8 100644 --- a/packages/ember-metal/lib/watch_key.js +++ b/packages/ember-metal/lib/watch_key.js @@ -48,10 +48,11 @@ if (MANDATORY_SETTER) { // ember strip this entire block out handleMandatorySetter = function handleMandatorySetter(m, obj, keyName) { let descriptor = lookupDescriptor(obj, keyName); - let configurable = descriptor ? descriptor.configurable : true; - let isWritable = descriptor ? descriptor.writable : true; - let hasValue = descriptor ? 'value' in descriptor : true; - let possibleDesc = descriptor && descriptor.value; + let hasDescriptor = descriptor !== null; + let configurable = hasDescriptor ? descriptor.configurable : true; + let isWritable = hasDescriptor ? descriptor.writable : true; + let hasValue = hasDescriptor ? 'value' in descriptor : true; + let possibleDesc = hasDescriptor && descriptor.value; let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; From a654f5b640246c89a1b28b90df7597bab5ce30ac Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 28 Jun 2017 09:11:18 +0500 Subject: [PATCH 102/224] cleanup `removeFromListeners` --- packages/ember-metal/lib/events.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/ember-metal/lib/events.js b/packages/ember-metal/lib/events.js index 173f6253a59..810b5731572 100644 --- a/packages/ember-metal/lib/events.js +++ b/packages/ember-metal/lib/events.js @@ -124,11 +124,9 @@ export function removeListener(obj, eventName, target, method) { target = null; } - metaFor(obj).removeFromListeners(eventName, target, method, (...args) => { - if ('function' === typeof obj.didRemoveListener) { - obj.didRemoveListener(...args); - } - }); + let func = ('function' === typeof obj.didRemoveListener) ? + obj.didRemoveListener.bind(obj) : ()=> {}; + metaFor(obj).removeFromListeners(eventName, target, method, func); } /** From beea6c869a3adb3745bff0a08ed40db7d778f182 Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 28 Jun 2017 14:47:33 +0500 Subject: [PATCH 103/224] cleanup `meta_listenerss` --- packages/ember-metal/lib/meta.js | 2 +- packages/ember-metal/lib/meta_listeners.js | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 61c00252310..6ec6cb9915e 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -89,7 +89,7 @@ export class Meta { } this._listeners = undefined; - this._listenersFinalized = undefined; + this._listenersFinalized = false; this._suspendedListeners = undefined; } diff --git a/packages/ember-metal/lib/meta_listeners.js b/packages/ember-metal/lib/meta_listeners.js index 3902b04df42..678910c7c30 100644 --- a/packages/ember-metal/lib/meta_listeners.js +++ b/packages/ember-metal/lib/meta_listeners.js @@ -17,9 +17,7 @@ export const SUSPENDED = 2; export const protoMethods = { addToListeners(eventName, target, method, flags) { - if (this._listeners === undefined) { - this._listeners = []; - } + if (this._listeners === undefined) { this._listeners = []; } this._listeners.push(eventName, target, method, flags); }, @@ -72,21 +70,21 @@ export const protoMethods = { while (pointer !== undefined) { let listeners = pointer._listeners; if (listeners !== undefined) { - for (let index = 0; index < listeners.length - 3; index += 4) { + for (let index = 0; index < listeners.length; index += 4) { if (listeners[index] === eventName) { result = result || []; pushUniqueListener(result, listeners, index); } } } - if (pointer._listenersFinalized === true) { break; } + if (pointer._listenersFinalized) { break; } pointer = pointer.parent; } let sus = this._suspendedListeners; if (sus !== undefined && result !== undefined) { - for (let susIndex = 0; susIndex < sus.length - 2; susIndex += 3) { + for (let susIndex = 0; susIndex < sus.length; susIndex += 3) { if (eventName === sus[susIndex]) { - for (let resultIndex = 0; resultIndex < result.length - 2; resultIndex += 3) { + for (let resultIndex = 0; resultIndex < result.length; resultIndex += 3) { if (result[resultIndex] === sus[susIndex + 1] && result[resultIndex + 1] === sus[susIndex + 2]) { result[resultIndex + 2] |= SUSPENDED; } @@ -99,7 +97,7 @@ export const protoMethods = { suspendListeners(eventNames, target, method, callback) { let sus = this._suspendedListeners; - if (!sus) { + if (sus === undefined) { sus = this._suspendedListeners = []; } for (let i = 0; i < eventNames.length; i++) { @@ -126,7 +124,7 @@ export const protoMethods = { while (pointer !== undefined) { let listeners = pointer._listeners; if (listeners !== undefined) { - for (let index = 0; index < listeners.length - 3; index += 4) { + for (let index = 0; index < listeners.length; index += 4) { names[listeners[index]] = true; } } @@ -140,7 +138,7 @@ export const protoMethods = { function pushUniqueListener(destination, source, index) { let target = source[index + 1]; let method = source[index + 2]; - for (let destinationIndex = 0; destinationIndex < destination.length - 2; destinationIndex += 3) { + for (let destinationIndex = 0; destinationIndex < destination.length; destinationIndex += 3) { if (destination[destinationIndex] === target && destination[destinationIndex + 1] === method) { return; } From cc6ded7d9a28df3099f4e5f53e46c1bf3e5ec320 Mon Sep 17 00:00:00 2001 From: Patrick Robertson Date: Fri, 23 Jun 2017 18:08:03 -0400 Subject: [PATCH 104/224] Decouple transitioning CSS classes tests from global resolver. I did a fair amount of other refactorings here: * split the class assertions in a 1:1 per selector. I wasn't particurarly fond of the assertion function that relied on argument length and found having explicit assertions per selector to be helpful. * split the two cases into two modules because the test case setup was different enough to merit it (imo). --- .../link_to_transitioning_classes_test.js | 342 ++++++++++-------- 1 file changed, 193 insertions(+), 149 deletions(-) diff --git a/packages/ember/tests/helpers/link_to_test/link_to_transitioning_classes_test.js b/packages/ember/tests/helpers/link_to_test/link_to_transitioning_classes_test.js index b1d0c9b2e87..9846a2ff1a7 100644 --- a/packages/ember/tests/helpers/link_to_test/link_to_transitioning_classes_test.js +++ b/packages/ember/tests/helpers/link_to_test/link_to_transitioning_classes_test.js @@ -1,200 +1,244 @@ import { RSVP } from 'ember-runtime'; -import { Route, NoneLocation } from 'ember-routing'; -import { run, set } from 'ember-metal'; -import { compile } from 'ember-template-compiler'; -import { Application } from 'ember-application'; -import { jQuery } from 'ember-views'; -import { setTemplates, setTemplate } from 'ember-glimmer'; +import { Route } from 'ember-routing'; +import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; -let Router, App, registry, container; +function assertHasClass(assert, selector, label) { + let testLabel = `${selector.attr('id')} should have class ${label}`; -let aboutDefer, otherDefer; - -function bootApplication() { - container.lookup('router:main'); - run(App, 'advanceReadiness'); + assert.equal(selector.hasClass(label), true, testLabel); } -function assertHasClass(className) { - let i = 1; - while (i < arguments.length) { - let $a = arguments[i]; - let shouldHaveClass = arguments[i + 1]; - equal($a.hasClass(className), shouldHaveClass, $a.attr('id') + ' should ' + (shouldHaveClass ? '' : 'not ') + 'have class ' + className); - i += 2; - } +function assertHasNoClass(assert, selector, label) { + let testLabel = `${selector.attr('id')} should not have class ${label}`; + + assert.equal(selector.hasClass(label), false, testLabel); } -let updateCount, replaceCount; +moduleFor('The {{link-to}} helper: .transitioning-in .transitioning-out CSS classes', class extends ApplicationTestCase { + constructor() { + super(); -function sharedSetup() { - App = Application.create({ - name: 'App', - rootElement: '#qunit-fixture' - }); + this.aboutDefer = RSVP.defer(); + this.otherDefer = RSVP.defer(); + let _this = this; - App.deferReadiness(); + this.router.map(function() { + this.route('about'); + this.route('other'); + }); - updateCount = replaceCount = 0; - App.Router.reopen({ - location: NoneLocation.create({ - setURL(path) { - updateCount++; - set(this, 'path', path); - }, + this.add('route:about', Route.extend({ + model() { + return _this.aboutDefer.promise; + } + })); - replaceURL(path) { - replaceCount++; - set(this, 'path', path); + this.add('route:other', Route.extend({ + model() { + return _this.otherDefer.promise; } - }) - }); + })); - Router = App.Router; - registry = App.__registry__; - container = App.__container__; -} + this.addTemplate('application',` + {{outlet}} + {{link-to 'Index' 'index' id='index-link'}} + {{link-to 'About' 'about' id='about-link'}} + {{link-to 'Other' 'other' id='other-link'}} + `); -function sharedTeardown() { - run(() => App.destroy()); - setTemplates({}); -} + this.visit('/'); + } + teardown() { + super.teardown(); + this.aboutDefer = null; + this.otherDefer = null; + } + + ['@test while a transition is underway'](assert) { + let $index = this.$('#index-link'); + let $about = this.$('#about-link'); + let $other = this.$('#other-link'); + + $about.click(); + + assertHasClass(assert, $index, 'active'); + assertHasNoClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); + + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); -QUnit.module('The {{link-to}} helper: .transitioning-in .transitioning-out CSS classes', { - setup() { - run(() => { - sharedSetup(); + assertHasClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - registry.unregister('router:main'); - registry.register('router:main', Router); + this.runTask(() => this.aboutDefer.resolve()); + + assertHasNoClass(assert, $index, 'active'); + assertHasClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); + + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); + + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); + } +}); - Router.map(function() { +moduleFor(`The {{link-to}} helper: .transitioning-in .transitioning-out CSS classes - nested link-to's`, class extends ApplicationTestCase { + constructor() { + super(); + this.aboutDefer = RSVP.defer(); + this.otherDefer = RSVP.defer(); + let _this = this; + + this.router.map(function() { + this.route('parent-route', function() { this.route('about'); this.route('other'); }); + }); + this.add('route:parent-route.about', Route.extend({ + model() { + return _this.aboutDefer.promise; + } + })); - App.AboutRoute = Route.extend({ - model() { - aboutDefer = RSVP.defer(); - return aboutDefer.promise; - } - }); + this.add('route:parent-route.other', Route.extend({ + model() { + return _this.otherDefer.promise; + } + })); + + this.addTemplate('application', ` + {{outlet}} + {{#link-to 'index' tagName='li'}} + {{link-to 'Index' 'index' id='index-link'}} + {{/link-to}} + {{#link-to 'parent-route.about' tagName='li'}} + {{link-to 'About' 'parent-route.about' id='about-link'}} + {{/link-to}} + {{#link-to 'parent-route.other' tagName='li'}} + {{link-to 'Other' 'parent-route.other' id='other-link'}} + {{/link-to}} + `); + + this.visit('/'); + } - App.OtherRoute = Route.extend({ - model() { - otherDefer = RSVP.defer(); - return otherDefer.promise; - } - }); + resolveAbout() { + return this.runTask(() => { + this.aboutDefer.resolve(); + this.aboutDefer = RSVP.defer(); + }); + } - setTemplate('application', compile('{{outlet}}{{link-to \'Index\' \'index\' id=\'index-link\'}}{{link-to \'About\' \'about\' id=\'about-link\'}}{{link-to \'Other\' \'other\' id=\'other-link\'}}')); + resolveOther() { + return this.runTask(() => { + this.otherDefer.resolve(); + this.otherDefer = RSVP.defer(); }); - }, + } teardown() { - sharedTeardown(); - aboutDefer = null; + super.teardown(); + this.aboutDefer = null; + this.otherDefer = null; } -}); -QUnit.test('while a transition is underway', function() { - expect(18); - bootApplication(); + [`@test while a transition is underway with nested link-to's`](assert) { + let $index = this.$('#index-link'); + let $about = this.$('#about-link'); + let $other = this.$('#other-link'); - let $index = jQuery('#index-link'); - let $about = jQuery('#about-link'); - let $other = jQuery('#other-link'); + $about.click(); - run($about, 'click'); + assertHasClass(assert, $index, 'active'); + assertHasNoClass(assert, $about, 'active'); + assertHasNoClass(assert, $about, 'active'); - assertHasClass('active', $index, true, $about, false, $other, false); - assertHasClass('ember-transitioning-in', $index, false, $about, true, $other, false); - assertHasClass('ember-transitioning-out', $index, true, $about, false, $other, false); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - run(aboutDefer, 'resolve'); + assertHasClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - assertHasClass('active', $index, false, $about, true, $other, false); - assertHasClass('ember-transitioning-in', $index, false, $about, false, $other, false); - assertHasClass('ember-transitioning-out', $index, false, $about, false, $other, false); -}); + this.resolveAbout(); -QUnit.test('while a transition is underway with nested link-to\'s', function() { - expect(54); + assertHasNoClass(assert, $index, 'active'); + assertHasClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); - Router.map(function() { - this.route('parent-route', function() { - this.route('about'); - this.route('other'); - }); - }); - - App.ParentRouteAboutRoute = Route.extend({ - model() { - aboutDefer = RSVP.defer(); - return aboutDefer.promise; - } - }); - - App.ParentRouteOtherRoute = Route.extend({ - model() { - otherDefer = RSVP.defer(); - return otherDefer.promise; - } - }); - - setTemplate('application', compile(` - {{outlet}} - {{#link-to 'index' tagName='li'}} - {{link-to 'Index' 'index' id='index-link'}} - {{/link-to}} - {{#link-to 'parent-route.about' tagName='li'}} - {{link-to 'About' 'parent-route.about' id='about-link'}} - {{/link-to}} - {{#link-to 'parent-route.other' tagName='li'}} - {{link-to 'Other' 'parent-route.other' id='other-link'}} - {{/link-to}} - `)); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - bootApplication(); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - let $index = jQuery('#index-link'); - let $about = jQuery('#about-link'); - let $other = jQuery('#other-link'); + $other.click(); - run($about, 'click'); + assertHasNoClass(assert, $index, 'active'); + assertHasClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); - assertHasClass('active', $index, true, $about, false, $other, false); - assertHasClass('ember-transitioning-in', $index, false, $about, true, $other, false); - assertHasClass('ember-transitioning-out', $index, true, $about, false, $other, false); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasClass(assert, $other, 'ember-transitioning-in'); - run(aboutDefer, 'resolve'); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - assertHasClass('active', $index, false, $about, true, $other, false); - assertHasClass('ember-transitioning-in', $index, false, $about, false, $other, false); - assertHasClass('ember-transitioning-out', $index, false, $about, false, $other, false); + this.resolveOther(); - run($other, 'click'); + assertHasNoClass(assert, $index, 'active'); + assertHasNoClass(assert, $about, 'active'); + assertHasClass(assert, $other, 'active'); - assertHasClass('active', $index, false, $about, true, $other, false); - assertHasClass('ember-transitioning-in', $index, false, $about, false, $other, true); - assertHasClass('ember-transitioning-out', $index, false, $about, true, $other, false); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - run(otherDefer, 'resolve'); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); - assertHasClass('active', $index, false, $about, false, $other, true); - assertHasClass('ember-transitioning-in', $index, false, $about, false, $other, false); - assertHasClass('ember-transitioning-out', $index, false, $about, false, $other, false); + $about.click(); - run($about, 'click'); - assertHasClass('active', $index, false, $about, false, $other, true); - assertHasClass('ember-transitioning-in', $index, false, $about, true, $other, false); - assertHasClass('ember-transitioning-out', $index, false, $about, false, $other, true); + assertHasNoClass(assert, $index, 'active'); + assertHasNoClass(assert, $about, 'active'); + assertHasClass(assert, $other, 'active'); - run(aboutDefer, 'resolve'); + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); - assertHasClass('active', $index, false, $about, true, $other, false); - assertHasClass('ember-transitioning-in', $index, false, $about, false, $other, false); - assertHasClass('ember-transitioning-out', $index, false, $about, false, $other, false); + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasClass(assert, $other, 'ember-transitioning-out'); + + this.resolveAbout(); + + assertHasNoClass(assert, $index, 'active'); + assertHasClass(assert, $about, 'active'); + assertHasNoClass(assert, $other, 'active'); + + assertHasNoClass(assert, $index, 'ember-transitioning-in'); + assertHasNoClass(assert, $about, 'ember-transitioning-in'); + assertHasNoClass(assert, $other, 'ember-transitioning-in'); + + assertHasNoClass(assert, $index, 'ember-transitioning-out'); + assertHasNoClass(assert, $about, 'ember-transitioning-out'); + assertHasNoClass(assert, $other, 'ember-transitioning-out'); + } }); From 98cc07f7efeeabed7524511966a510e0470b1000 Mon Sep 17 00:00:00 2001 From: karthiick Date: Wed, 21 Jun 2017 00:01:56 +0530 Subject: [PATCH 105/224] Decouple test from the default resolver for component_registration_test updated test cases Remove extra visit calls --- .../tests/component_registration_test.js | 314 +++++++++--------- 1 file changed, 156 insertions(+), 158 deletions(-) diff --git a/packages/ember/tests/component_registration_test.js b/packages/ember/tests/component_registration_test.js index a315d57ac39..a06c7243663 100644 --- a/packages/ember/tests/component_registration_test.js +++ b/packages/ember/tests/component_registration_test.js @@ -1,200 +1,198 @@ import { Controller } from 'ember-runtime'; -import { run } from 'ember-metal'; - -import { Application } from 'ember-application'; -import { Router } from 'ember-routing'; -import { compile } from 'ember-template-compiler'; -import { - Component, - setTemplates, - setTemplate -} from 'ember-glimmer'; -import { jQuery } from 'ember-views'; - -let App, appInstance; - -function prepare() { - setTemplate('components/expand-it', compile('

hello {{yield}}

')); - setTemplate('application', compile('Hello world {{#expand-it}}world{{/expand-it}}')); -} - -function cleanup() { - run(() => { - try { - if (App) { - App.destroy(); - } - App = appInstance = null; - } finally { - setTemplates({}); - } - }); -} - -QUnit.module('Application Lifecycle - Component Registration', { - setup: prepare, - teardown: cleanup -}); - -function boot(callback, startURL = '/') { - run(() => { - App = Application.create({ - name: 'App', - rootElement: '#qunit-fixture' - }); - - App.deferReadiness(); - - App.Router = Router.extend({ - location: 'none' - }); +import { Component } from 'ember-glimmer'; +import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers'; - appInstance = App.__deprecatedInstance__; +moduleFor('Application Lifecycle - Component Registration', class extends AutobootApplicationTestCase { - if (callback) { callback(); } - }); + ['@test The helper becomes the body of the component'](assert) { + this.runTask(() => { + this.createApplication(); - let router = appInstance.lookup('router:main'); + this.addTemplate('components/expand-it', '

hello {{yield}}

'); + this.addTemplate('application', 'Hello world {{#expand-it}}world{{/expand-it}}'); + }); - run(App, 'advanceReadiness'); - run(() => router.handleURL(startURL)); -} + let text = this.$('div.ember-view > div.ember-view').text().trim(); + assert.equal(text, 'hello world', 'The component is composed correctly'); + } -QUnit.test('The helper becomes the body of the component', function() { - boot(); - equal(jQuery('div.ember-view > div.ember-view', '#qunit-fixture').text(), 'hello world', 'The component is composed correctly'); -}); + ['@test If a component is registered, it is used'](assert) { + this.runTask(() => { + this.createApplication(); -QUnit.test('If a component is registered, it is used', function() { - boot(() => { - appInstance.register('component:expand-it', Component.extend({ - classNames: 'testing123' - })); - }); + this.addTemplate('components/expand-it', '

hello {{yield}}

'); + this.addTemplate('application', `Hello world {{#expand-it}}world{{/expand-it}}`); - equal(jQuery('div.testing123', '#qunit-fixture').text(), 'hello world', 'The component is composed correctly'); -}); + this.applicationInstance.register('component:expand-it', Component.extend({ + classNames: 'testing123' + })); + }); -QUnit.test('Late-registered components can be rendered with custom `layout` property', function() { - setTemplate('application', compile('
there goes {{my-hero}}
')); + let text = this.$('div.testing123').text().trim(); + assert.equal(text, 'hello world', 'The component is composed correctly'); + } - boot(() => { - appInstance.register('component:my-hero', Component.extend({ - classNames: 'testing123', - layout: compile('watch him as he GOES') - })); - }); + ['@test Late-registered components can be rendered with custom `layout` property'](assert) { + this.runTask(() => { + this.createApplication(); - equal(jQuery('#wrapper').text(), 'there goes watch him as he GOES', 'The component is composed correctly'); -}); + this.addTemplate('application', `
there goes {{my-hero}}
`); -QUnit.test('Late-registered components can be rendered with template registered on the container', function() { - setTemplate('application', compile('
hello world {{sally-rutherford}}-{{#sally-rutherford}}!!!{{/sally-rutherford}}
')); + this.applicationInstance.register('component:my-hero', Component.extend({ + classNames: 'testing123', + layout: this.compile('watch him as he GOES') + })); + }); - boot(() => { - appInstance.register('template:components/sally-rutherford', compile('funkytowny{{yield}}')); - appInstance.register('component:sally-rutherford', Component); - }); + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'there goes watch him as he GOES', 'The component is composed correctly'); + } - equal(jQuery('#wrapper').text(), 'hello world funkytowny-funkytowny!!!', 'The component is composed correctly'); -}); + ['@test Late-registered components can be rendered with template registered on the container'](assert) { + this.runTask(() => { + this.createApplication(); -QUnit.test('Late-registered components can be rendered with ONLY the template registered on the container', function() { - setTemplate('application', compile('
hello world {{borf-snorlax}}-{{#borf-snorlax}}!!!{{/borf-snorlax}}
')); + this.addTemplate('application', `
hello world {{sally-rutherford}}-{{#sally-rutherford}}!!!{{/sally-rutherford}}
`); - boot(() => { - appInstance.register('template:components/borf-snorlax', compile('goodfreakingTIMES{{yield}}')); - }); + this.applicationInstance.register('template:components/sally-rutherford', this.compile('funkytowny{{yield}}')); + this.applicationInstance.register('component:sally-rutherford', Component); + }); - equal(jQuery('#wrapper').text(), 'hello world goodfreakingTIMES-goodfreakingTIMES!!!', 'The component is composed correctly'); -}); + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'hello world funkytowny-funkytowny!!!', 'The component is composed correctly'); + } -QUnit.test('Assigning layoutName to a component should setup the template as a layout', function() { - expect(1); + ['@test Late-registered components can be rendered with ONLY the template registered on the container'](assert) { + this.runTask(() => { + this.createApplication(); - setTemplate('application', compile('
{{#my-component}}{{text}}{{/my-component}}
')); - setTemplate('foo-bar-baz', compile('{{text}}-{{yield}}')); + this.addTemplate('application', `
hello world {{borf-snorlax}}-{{#borf-snorlax}}!!!{{/borf-snorlax}}
`); - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer' - })); + this.applicationInstance.register('template:components/borf-snorlax', this.compile('goodfreakingTIMES{{yield}}')); + }); - appInstance.register('component:my-component', Component.extend({ - text: 'inner', - layoutName: 'foo-bar-baz' - })); - }); + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'hello world goodfreakingTIMES-goodfreakingTIMES!!!', 'The component is composed correctly'); + } - equal(jQuery('#wrapper').text(), 'inner-outer', 'The component is composed correctly'); -}); + ['@test Assigning layoutName to a component should setup the template as a layout'](assert) { + assert.expect(1); -QUnit.test('Assigning layoutName and layout to a component should use the `layout` value', function() { - expect(1); + this.runTask(() => { + this.createApplication(); - setTemplate('application', compile('
{{#my-component}}{{text}}{{/my-component}}
')); - setTemplate('foo-bar-baz', compile('No way!')); + this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`); + this.addTemplate('foo-bar-baz', '{{text}}-{{yield}}'); - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer' - })); + this.applicationInstance.register('controller:application', Controller.extend({ + text: 'outer' + })); + this.applicationInstance.register('component:my-component', Component.extend({ + text: 'inner', + layoutName: 'foo-bar-baz' + })); + }); - appInstance.register('component:my-component', Component.extend({ - text: 'inner', - layoutName: 'foo-bar-baz', - layout: compile('{{text}}-{{yield}}') - })); - }); + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'inner-outer', 'The component is composed correctly'); + } - equal(jQuery('#wrapper').text(), 'inner-outer', 'The component is composed correctly'); -}); + ['@test Assigning layoutName and layout to a component should use the `layout` value'](assert) { + assert.expect(1); -QUnit.test('Assigning defaultLayout to a component should set it up as a layout if no layout was found [DEPRECATED]', function() { - expect(2); + this.runTask(() => { + this.createApplication(); - setTemplate('application', compile('
{{#my-component}}{{text}}{{/my-component}}
')); + this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`); + this.addTemplate('foo-bar-baz', 'No way!'); - expectDeprecation(() => { - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer' + this.applicationInstance.register('controller:application', Controller.extend({ + text: 'outer' })); - - appInstance.register('component:my-component', Component.extend({ + this.applicationInstance.register('component:my-component', Component.extend({ text: 'inner', - defaultLayout: compile('{{text}}-{{yield}}') + layoutName: 'foo-bar-baz', + layout: this.compile('{{text}}-{{yield}}') })); }); - }, /Specifying `defaultLayout` to .+ is deprecated\./); - equal(jQuery('#wrapper').text(), 'inner-outer', 'The component is composed correctly'); -}); + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'inner-outer', 'The component is composed correctly'); + } -QUnit.test('Assigning defaultLayout to a component should set it up as a layout if layout was found [DEPRECATED]', function() { - expect(2); + ['@test Assigning defaultLayout to a component should set it up as a layout if no layout was found [DEPRECATED]'](assert) { + assert.expect(2); - setTemplate('application', compile('
{{#my-component}}{{text}}{{/my-component}}
')); - setTemplate('components/my-component', compile('{{text}}-{{yield}}')); + expectDeprecation(() => { + this.runTask(() => { + this.createApplication(); - expectDeprecation(() => { - boot(() => { - appInstance.register('controller:application', Controller.extend({ - 'text': 'outer' - })); + this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`); - appInstance.register('component:my-component', Component.extend({ - text: 'inner', - defaultLayout: compile('should not see this!') - })); + this.applicationInstance.register('controller:application', Controller.extend({ + text: 'outer' + })); + this.applicationInstance.register('component:my-component', Component.extend({ + text: 'inner', + defaultLayout: this.compile('{{text}}-{{yield}}') + })); + }); }); - }, /Specifying `defaultLayout` to .+ is deprecated\./); - - equal(jQuery('#wrapper').text(), 'inner-outer', 'The component is composed correctly'); -}); - -QUnit.test('Using name of component that does not exist', function () { - setTemplate('application', compile('
{{#no-good}} {{/no-good}}
')); - expectAssertion(() => boot(), /.* named "no-good" .*/); + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'inner-outer', 'The component is composed correctly'); + } + + ['@test Assigning defaultLayout to a component should set it up as a layout if layout was found [DEPRECATED]'](assert) { + assert.expect(2); + + expectDeprecation(() => { + this.runTask(() => { + this.createApplication(); + + this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`); + this.addTemplate('components/my-component', '{{text}}-{{yield}}'); + + this.applicationInstance.register('controller:application', Controller.extend({ + text: 'outer' + })); + this.applicationInstance.register('component:my-component', Component.extend({ + text: 'inner', + defaultLayout: this.compile('should not see this!') + })); + }); + }, /Specifying `defaultLayout` to .+ is deprecated\./); + + let text = this.$('#wrapper').text().trim(); + assert.equal(text, 'inner-outer', 'The component is composed correctly'); + } + + /* + * When an exception is thrown during the initial rendering phase, the + * `visit` promise is not resolved or rejected. This means the `applicationInstance` + * is never torn down and tests running after this one will fail. + * + * It is ugly, but since this test intentionally causes an initial render + * error, it requires globals mode to access the `applicationInstance` + * for teardown after test completion. + * + * Application "globals mode" is trigged by `autoboot: true`. It doesn't + * have anything to do with the resolver. + * + * We should be able to fix this by having the application eagerly stash a + * copy of each application instance it creates. When the application is + * destroyed, it can also destroy the instances (this is how the globals + * mode avoid the problem). + * + * See: https://github.com/emberjs/ember.js/issues/15327 + */ + ['@test Using name of component that does not exist']() { + expectAssertion(() => { + this.runTask(() => { + this.createApplication(); + + this.addTemplate('application', `
{{#no-good}} {{/no-good}}
`); + }); + }, /.* named "no-good" .*/); + } }); \ No newline at end of file From 0960519155795e9bd7cf2ea0cf6bbc298cb9503f Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Fri, 30 Jun 2017 08:59:42 +0100 Subject: [PATCH 106/224] [DOC beta] Fix wording on private Routing service --- packages/ember-routing/lib/services/routing.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ember-routing/lib/services/routing.js b/packages/ember-routing/lib/services/routing.js index abb1e47c8b9..6b9b8cac79d 100644 --- a/packages/ember-routing/lib/services/routing.js +++ b/packages/ember-routing/lib/services/routing.js @@ -16,9 +16,8 @@ import { routeArgs } from '../utils'; The Routing service is used by LinkComponent, and provides facilities for the component/view layer to interact with the router. - While still private, this service can eventually be opened up, and provides - the set of API needed for components to control routing without interacting - with router internals. + This is a private service for internal usage only. For public usage, + refer to the `Router` service. @private @class RoutingService From 842a1b18ff779d464b94ba5813fff8f143dae554 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Fri, 30 Jun 2017 16:54:57 -0700 Subject: [PATCH 107/224] Drop unimplemented application.option API --- packages/ember-runtime/lib/mixins/registry_proxy.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/registry_proxy.js b/packages/ember-runtime/lib/mixins/registry_proxy.js index 33cc371ee14..32cb5da59b6 100644 --- a/packages/ember-runtime/lib/mixins/registry_proxy.js +++ b/packages/ember-runtime/lib/mixins/registry_proxy.js @@ -119,17 +119,6 @@ export default Mixin.create({ */ hasRegistration: registryAlias('has'), - /** - Register an option for a particular factory. - - @public - @method registerOption - @param {String} fullName - @param {String} optionName - @param {Object} options - */ - registerOption: registryAlias('option'), - /** Return a specific registered option for a particular factory. From 16a9ede4d40a039f101dec8dae618bc286812d50 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Wed, 28 Jun 2017 22:11:17 -0700 Subject: [PATCH 108/224] Decouple visit_test from default resolver --- .../dependency_injection/to_string_test.js | 26 +- .../tests/system/visit_test.js | 701 +++++++++--------- .../lib/test-cases/application.js | 9 +- .../default-resolver-application.js | 2 +- 4 files changed, 355 insertions(+), 383 deletions(-) diff --git a/packages/ember-application/tests/system/dependency_injection/to_string_test.js b/packages/ember-application/tests/system/dependency_injection/to_string_test.js index 4985eb4bbad..79f8154f800 100644 --- a/packages/ember-application/tests/system/dependency_injection/to_string_test.js +++ b/packages/ember-application/tests/system/dependency_injection/to_string_test.js @@ -1,16 +1,22 @@ import { guidFor, assign } from 'ember-utils'; import { Object as EmberObject } from 'ember-runtime'; import { Resolver as DefaultResolver } from 'ember-application'; -import { moduleFor, ApplicationTestCase, ModuleBasedTestResolver, - DefaultResolverApplicationTestCase } from 'internal-test-helpers'; +import { + moduleFor, + ApplicationTestCase, + ModuleBasedTestResolver, + DefaultResolverApplicationTestCase +} from 'internal-test-helpers'; -moduleFor('Ember.Application Dependency Injection - DefaultResolver#toString', class extends - DefaultResolverApplicationTestCase { +moduleFor('Ember.Application Dependency Injection - DefaultResolver#toString', class extends DefaultResolverApplicationTestCase { constructor() { super(); - this.createApplication(); + this.runTask(() => this.createApplication()); this.application.Post = EmberObject.extend(); - this.visit('/'); + } + + beforeEach() { + return this.visit('/'); } ['@test factories'](assert) { @@ -30,9 +36,9 @@ moduleFor('Ember.Application Dependency Injection - DefaultResolver#toString', c }); moduleFor('Ember.Application Dependency Injection - Resolver#toString', class extends ApplicationTestCase { - constructor() { - super(); - this.visit('/'); + + beforeEach() { + return this.visit('/'); } get applicationOptions() { @@ -55,4 +61,4 @@ moduleFor('Ember.Application Dependency Injection - Resolver#toString', class ex 'expecting the supermodel to be peter' ); } -}); \ No newline at end of file +}); diff --git a/packages/ember-application/tests/system/visit_test.js b/packages/ember-application/tests/system/visit_test.js index 33d613ba22c..cd66de11d6f 100644 --- a/packages/ember-application/tests/system/visit_test.js +++ b/packages/ember-application/tests/system/visit_test.js @@ -1,3 +1,4 @@ +import { moduleFor, ApplicationTestCase } from 'internal-test-helpers'; import { Object as EmberObject, inject, @@ -13,403 +14,367 @@ import { Component, helper } from 'ember-glimmer'; import { compile } from 'ember-template-compiler'; import { jQuery } from 'ember-views'; -let App = null; -let instance = null; -let instances = []; - -function createApplication(integration) { - App = Application.extend().create({ - autoboot: false, - rootElement: '#qunit-fixture', - LOG_TRANSITIONS: true, - LOG_TRANSITIONS_INTERNAL: true, - LOG_ACTIVE_GENERATION: true - }); - - App.Router = Router.extend({ - location: 'none' - }); - - if (integration) { - App.instanceInitializer({ - name: 'auto-cleanup', - initialize(_instance) { - instances.push(_instance); - } - }); - } else { - App.instanceInitializer({ - name: 'auto-cleanup', - initialize(_instance) { - if (instance) { - run(instance, 'destroy'); - } - - instance = _instance; - } - }); - } - - return App; -} - function expectAsyncError() { RSVP.off('error'); } -QUnit.module('Ember.Application - visit()', { +moduleFor('Ember.Application - visit()', class extends ApplicationTestCase { + teardown() { RSVP.on('error', onerrorDefault); - - if (instance) { - run(instance, 'destroy'); - instance = null; - } - - if (App) { - run(App, 'destroy'); - App = null; - } + super.teardown(); } -}); -// This tests whether the application is "autobooted" by registering an -// instance initializer and asserting it never gets run. Since this is -// inherently testing that async behavior *doesn't* happen, we set a -// 500ms timeout to verify that when autoboot is set to false, the -// instance initializer that would normally get called on DOM ready -// does not fire. -QUnit.test('Applications with autoboot set to false do not autoboot', function(assert) { - function delay(time) { - return new RSVP.Promise(resolve => run.later(resolve, time)); + createApplication(options) { + return super.createApplication(options, Application.extend()); } - let appBooted = 0; - let instanceBooted = 0; + // This tests whether the application is "autobooted" by registering an + // instance initializer and asserting it never gets run. Since this is + // inherently testing that async behavior *doesn't* happen, we set a + // 500ms timeout to verify that when autoboot is set to false, the + // instance initializer that would normally get called on DOM ready + // does not fire. + [`@test Applications with autoboot set to false do not autoboot`](assert) { + function delay(time) { + return new RSVP.Promise(resolve => run.later(resolve, time)); + } - run(() => { - createApplication(); + let appBooted = 0; + let instanceBooted = 0; - App.initializer({ + this.application.initializer({ name: 'assert-no-autoboot', initialize() { appBooted++; } }); - App.instanceInitializer({ + this.application.instanceInitializer({ name: 'assert-no-autoboot', initialize() { instanceBooted++; } }); - }); - // Continue after 500ms - return delay(500).then(() => { - assert.ok(appBooted === 0, '500ms elapsed without app being booted'); - assert.ok(instanceBooted === 0, '500ms elapsed without instances being booted'); + assert.ok(!this.applicationInstance, 'precond - no instance'); + assert.ok(appBooted === 0, 'precond - not booted'); + assert.ok(instanceBooted === 0, 'precond - not booted'); - return run(App, 'boot'); - }).then(() => { - assert.ok(appBooted === 1, 'app should boot when manually calling `app.boot()`'); - assert.ok(instanceBooted === 0, 'no instances should be booted automatically when manually calling `app.boot()'); - }); -}); + // Continue after 500ms + return delay(500).then(() => { + assert.ok(appBooted === 0, '500ms elapsed without app being booted'); + assert.ok(instanceBooted === 0, '500ms elapsed without instances being booted'); -QUnit.test('calling visit() on an app without first calling boot() should boot the app', function(assert) { - let appBooted = 0; - let instanceBooted = 0; + return this.runTask(() => this.application.boot()); + }).then(() => { + assert.ok(appBooted === 1, 'app should boot when manually calling `app.boot()`'); + assert.ok(instanceBooted === 0, 'no instances should be booted automatically when manually calling `app.boot()'); + }); + } - run(() => { - createApplication(); + [`@test calling visit() on an app without first calling boot() should boot the app`](assert) { + let appBooted = 0; + let instanceBooted = 0; - App.initializer({ + this.application.initializer({ name: 'assert-no-autoboot', initialize() { appBooted++; } }); - App.instanceInitializer({ + this.application.instanceInitializer({ name: 'assert-no-autoboot', initialize() { instanceBooted++; } }); - }); - - return run(App, 'visit', '/').then(() => { - assert.ok(appBooted === 1, 'the app should be booted`'); - assert.ok(instanceBooted === 1, 'an instances should be booted'); - }); -}); -QUnit.test('calling visit() on an already booted app should not boot it again', function(assert) { - let appBooted = 0; - let instanceBooted = 0; + return this.visit('/').then(() => { + assert.ok(appBooted === 1, 'the app should be booted`'); + assert.ok(instanceBooted === 1, 'an instances should be booted'); + }); + } - run(() => { - createApplication(); + [`@test calling visit() on an already booted app should not boot it again`](assert) { + let appBooted = 0; + let instanceBooted = 0; - App.initializer({ + this.application.initializer({ name: 'assert-no-autoboot', initialize() { appBooted++; } }); - App.instanceInitializer({ + this.application.instanceInitializer({ name: 'assert-no-autoboot', initialize() { instanceBooted++; } }); - }); - - return run(App, 'boot').then(() => { - assert.ok(appBooted === 1, 'the app should be booted'); - assert.ok(instanceBooted === 0, 'no instances should be booted'); - - return run(App, 'visit', '/'); - }).then(() => { - assert.ok(appBooted === 1, 'the app should not be booted again'); - assert.ok(instanceBooted === 1, 'an instance should be booted'); - - return run(App, 'visit', '/'); - }).then(() => { - assert.ok(appBooted === 1, 'the app should not be booted again'); - assert.ok(instanceBooted === 2, 'another instance should be booted'); - }); -}); -QUnit.test('visit() rejects on application boot failure', function(assert) { - run(() => { - createApplication(); + return this.runTask(() => this.application.boot()).then(() => { + assert.ok(appBooted === 1, 'the app should be booted'); + assert.ok(instanceBooted === 0, 'no instances should be booted'); + + return this.visit('/'); + }).then(() => { + assert.ok(appBooted === 1, 'the app should not be booted again'); + assert.ok(instanceBooted === 1, 'an instance should be booted'); + + /* + * Destroy the instance. + */ + return this.runTask(() => { + this.applicationInstance.destroy() + this.applicationInstance = null; + }); + }).then(() => { + /* + * Visit on the application a second time. The application should remain + * booted, but a new instance will be created. + */ + return this.visit('/'); + }).then(() => { + assert.ok(appBooted === 1, 'the app should not be booted again'); + assert.ok(instanceBooted === 2, 'another instance should be booted'); + }); + } - App.initializer({ + [`@test visit() rejects on application boot failure`](assert) { + this.application.initializer({ name: 'error', initialize() { throw new Error('boot failure'); } }); - }); - expectAsyncError(); - - return run(App, 'visit', '/').then(() => { - assert.ok(false, 'It should not resolve the promise'); - }, error => { - assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); - assert.equal(error.message, 'boot failure'); - }); -}); + expectAsyncError(); -QUnit.test('visit() rejects on instance boot failure', function(assert) { - run(() => { - createApplication(); + return this.visit('/').then(() => { + assert.ok(false, 'It should not resolve the promise'); + }, error => { + assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); + assert.equal(error.message, 'boot failure'); + }); + } - App.instanceInitializer({ + [`@test visit() rejects on instance boot failure`](assert) { + this.application.instanceInitializer({ name: 'error', initialize() { throw new Error('boot failure'); } }); - }); - - expectAsyncError(); - return run(App, 'visit', '/').then(() => { - assert.ok(false, 'It should not resolve the promise'); - }, error => { - assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); - assert.equal(error.message, 'boot failure'); - }); -}); + expectAsyncError(); -QUnit.test('visit() follows redirects', function(assert) { - run(() => { - createApplication(); + return this.visit('/').then(() => { + assert.ok(false, 'It should not resolve the promise'); + }, error => { + assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); + assert.equal(error.message, 'boot failure'); + }); + } - App.Router.map(function() { + [`@test visit() follows redirects`](assert) { + this.router.map(function() { this.route('a'); this.route('b', { path: '/b/:b' }); this.route('c', { path: '/c/:c' }); }); - App.register('route:a', Route.extend({ + this.add('route:a', Route.extend({ afterModel() { this.replaceWith('b', 'zomg'); } })); - App.register('route:b', Route.extend({ + this.add('route:b', Route.extend({ afterModel(params) { this.transitionTo('c', params.b); } })); - }); - return run(App, 'visit', '/a').then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/c/zomg', 'It should follow all redirects'); - }); -}); - -QUnit.test('visit() rejects if an error occurred during a transition', function(assert) { - run(() => { - createApplication(); + /* + * First call to `visit` is `this.application.visit` and returns the + * applicationInstance. + */ + return this.visit('/a').then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/c/zomg', 'It should follow all redirects'); + }); + } - App.Router.map(function() { + [`@test visit() rejects if an error occurred during a transition`](assert) { + this.router.map(function() { this.route('a'); this.route('b', { path: '/b/:b' }); this.route('c', { path: '/c/:c' }); }); - App.register('route:a', Route.extend({ + this.add('route:a', Route.extend({ afterModel() { this.replaceWith('b', 'zomg'); } })); - App.register('route:b', Route.extend({ + this.add('route:b', Route.extend({ afterModel(params) { this.transitionTo('c', params.b); } })); - App.register('route:c', Route.extend({ + this.add('route:c', Route.extend({ afterModel(params) { throw new Error('transition failure'); } })); - }); - expectAsyncError(); + expectAsyncError(); - return run(App, 'visit', '/a').then(() => { - assert.ok(false, 'It should not resolve the promise'); - }, error => { - assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); - assert.equal(error.message, 'transition failure'); - }); -}); - -QUnit.test('visit() chain', function(assert) { - run(() => { - createApplication(); + return this.visit('/a').then(() => { + assert.ok(false, 'It should not resolve the promise'); + }, error => { + assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); + assert.equal(error.message, 'transition failure'); + }); + } - App.Router.map(function() { + [`@test visit() chain`](assert) { + this.router.map(function() { this.route('a'); this.route('b'); this.route('c'); }); - }); - - return run(App, 'visit', '/').then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/'); - - return instance.visit('/a'); - }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/a'); - - return instance.visit('/b'); - }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/b'); - - return instance.visit('/c'); - }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/c'); - }); -}); - -QUnit.test('visit() returns a promise that resolves when the view has rendered', function(assert) { - run(() => { - createApplication(); - - App.register('template:application', compile('

Hello world

')); - }); - - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); - - return run(App, 'visit', '/').then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(jQuery('#qunit-fixture > .ember-view h1').text(), 'Hello world', 'the application was rendered once the promise resolves'); - }); -}); -QUnit.test('visit() returns a promise that resolves without rendering when shouldRender is set to false', function(assert) { - assert.expect(3); + return this.visit('/').then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/'); - run(() => { - createApplication(); + return instance.visit('/a'); + }).then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/a'); - App.register('template:application', compile('

Hello world

')); - }); + return instance.visit('/b'); + }).then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/b'); - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); - - return run(App, 'visit', '/', { shouldRender: false }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are still no elements in the fixture element after visit'); - }); -}); - -QUnit.test('visit() renders a template when shouldRender is set to true', function(assert) { - assert.expect(3); - - run(() => { - createApplication(); + return instance.visit('/c'); + }).then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/c'); + }); + } - App.register('template:application', compile('

Hello world

')); - }); + [`@test visit() returns a promise that resolves when the view has rendered`](assert) { + this.addTemplate('application', `

Hello world

`); + + assert.strictEqual( + this.$().children().length, 0, + 'there are no elements in the fixture element' + ); + + return this.visit('/').then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.equal( + this.$('.ember-view h1').text(), 'Hello world', + 'the application was rendered once the promise resolves' + ); + }); + } - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); + [`@test visit() returns a promise that resolves without rendering when shouldRender is set to false`](assert) { + assert.expect(3); + + this.addTemplate('application', '

Hello world

'); + + assert.strictEqual( + this.$().children().length, 0, + 'there are no elements in the fixture element' + ); + + return this.visit('/', { shouldRender: false }).then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.strictEqual( + this.$().children().length, 0, + 'there are still no elements in the fixture element after visit' + ); + }); + } - return run(App, 'visit', '/', { shouldRender: true }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.strictEqual(jQuery('#qunit-fixture').children().length, 1, 'there is 1 element in the fixture element after visit'); - }); -}); + [`@test visit() renders a template when shouldRender is set to true`](assert) { + assert.expect(3); + + this.addTemplate('application', '

Hello world

'); + + assert.strictEqual( + this.$('#qunit-fixture').children().length, 0, + 'there are no elements in the fixture element' + ); + + return this.visit('/', { shouldRender: true }).then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.strictEqual( + this.$().children().length, 1, + 'there is 1 element in the fixture element after visit' + ); + }); + } -QUnit.test('visit() returns a promise that resolves without rendering when shouldRender is set to false with Engines', function(assert) { - assert.expect(3); + [`@test visit() returns a promise that resolves without rendering when shouldRender is set to false with Engines`](assert) { + assert.expect(3); - run(() => { - createApplication(); + this.router.map(function() { + this.mount('blog'); + }); - App.register('template:application', compile('

Hello world

')); + this.addTemplate('application', '

Hello world

'); // Register engine let BlogEngine = Engine.extend(); - App.register('engine:blog', BlogEngine); + this.add('engine:blog', BlogEngine); // Register engine route map let BlogMap = function() {}; - App.register('route-map:blog', BlogMap); - - App.Router.map(function() { - this.mount('blog'); + this.add('route-map:blog', BlogMap); + + assert.strictEqual( + this.$('#qunit-fixture').children().length, 0, + 'there are no elements in the fixture element' + ); + + return this.visit('/blog', { shouldRender: false }).then(instance => { + assert.ok( + instance instanceof ApplicationInstance, + 'promise is resolved with an ApplicationInstance' + ); + assert.strictEqual( + this.$().children().length, 0, + 'there are still no elements in the fixture element after visit' + ); }); - }); - - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); - - return run(App, 'visit', '/blog', { shouldRender: false }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are still no elements in the fixture element after visit'); - }); -}); + } -QUnit.test('visit() on engine resolves engine component', function(assert) { - assert.expect(2); + [`@test visit() on engine resolves engine component`](assert) { + assert.expect(2); - run(() => { - createApplication(); + this.router.map(function() { + this.mount('blog'); + }); // Register engine let BlogEngine = Engine.extend({ @@ -422,29 +387,31 @@ QUnit.test('visit() on engine resolves engine component', function(assert) { this.register('component:cache-money', Component.extend({})); } }); - App.register('engine:blog', BlogEngine); + this.add('engine:blog', BlogEngine); // Register engine route map let BlogMap = function() {}; - App.register('route-map:blog', BlogMap); - - App.Router.map(function() { - this.mount('blog'); + this.add('route-map:blog', BlogMap); + + assert.strictEqual( + this.$().children().length, 0, + 'there are no elements in the fixture element' + ); + + return this.visit('/blog', { shouldRender: true }).then(instance => { + assert.strictEqual( + this.$().find('p').text(), 'Dis cache money', + 'Engine component is resolved' + ); }); - }); - - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); - - return run(App, 'visit', '/blog', { shouldRender: true }).then(instance => { - assert.strictEqual(jQuery('#qunit-fixture').find('p').text(), 'Dis cache money', 'Engine component is resolved'); - }); -}); + } -QUnit.test('visit() on engine resolves engine helper', function(assert) { - assert.expect(2); + [`@test visit() on engine resolves engine helper`](assert) { + assert.expect(2); - run(() => { - createApplication(); + this.router.map(function() { + this.mount('blog'); + }); // Register engine let BlogEngine = Engine.extend({ @@ -456,53 +423,37 @@ QUnit.test('visit() on engine resolves engine helper', function(assert) { })); } }); - App.register('engine:blog', BlogEngine); + this.add('engine:blog', BlogEngine); // Register engine route map let BlogMap = function() {}; - App.register('route-map:blog', BlogMap); - - App.Router.map(function() { - this.mount('blog'); + this.add('route-map:blog', BlogMap); + + assert.strictEqual( + this.$().children().length, 0, + 'there are no elements in the fixture element' + ); + + return this.visit('/blog', { shouldRender: true }).then(() => { + assert.strictEqual( + this.$().text(), 'turnt up', + 'Engine component is resolved' + ); }); - }); - - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); - - return run(App, 'visit', '/blog', { shouldRender: true }).then(instance => { - assert.strictEqual(jQuery('#qunit-fixture').text(), 'turnt up', 'Engine component is resolved'); - }); -}); - -QUnit.module('Ember.Application - visit() Integration Tests', { - teardown() { - if (instances) { - run(instances, 'forEach', (i) => i.destroy()); - instances = []; - } - - if (App) { - run(App, 'destroy'); - App = null; - } } -}); -QUnit.test('Ember Islands-style setup', function(assert) { - let xFooInitCalled = false; - let xFooDidInsertElementCalled = false; + [`@test Ember Islands-style setup`](assert) { + let xFooInitCalled = false; + let xFooDidInsertElementCalled = false; - let xBarInitCalled = false; - let xBarDidInsertElementCalled = false; + let xBarInitCalled = false; + let xBarDidInsertElementCalled = false; - run(() => { - createApplication(true); - - App.Router.map(function() { + this.router.map(function() { this.route('show', { path: '/:component_name' }); }); - App.register('route:show', Route.extend({ + this.add('route:show', Route.extend({ queryParams: { data: { refreshModel: true } }, @@ -523,17 +474,18 @@ QUnit.test('Ember Islands-style setup', function(assert) { } }); - App.register('service:isolated-counter', Counter); - App.register('service:shared-counter', Counter.create(), { instantiate: false }); + this.add('service:isolatedCounter', Counter); + this.add('service:sharedCounter', Counter.create()); + this.application.registerOptions('service:sharedCounter', {instantiate: false}); - App.register('template:show', compile('{{component model.componentName model=model.componentData}}')); + this.addTemplate('show', '{{component model.componentName model=model.componentData}}'); - App.register('template:components/x-foo', compile(` + this.addTemplate('components/x-foo', `

X-Foo

Hello {{model.name}}, I have been clicked {{isolatedCounter.value}} times ({{sharedCounter.value}} times combined)!

- `)); + `); - App.register('component:x-foo', Component.extend({ + this.add('component:x-foo', Component.extend({ tagName: 'x-foo', isolatedCounter: inject.service(), @@ -554,13 +506,13 @@ QUnit.test('Ember Islands-style setup', function(assert) { } })); - App.register('template:components/x-bar', compile(` + this.addTemplate('components/x-bar', `

X-Bar

- `)); + `); - App.register('component:x-bar', Component.extend({ - counter: inject.service('shared-counter'), + this.add('component:x-bar', Component.extend({ + counter: inject.service('sharedCounter'), actions: { incrementCounter() { @@ -577,48 +529,59 @@ QUnit.test('Ember Islands-style setup', function(assert) { xBarDidInsertElementCalled = true; } })); - }); - - let $foo = jQuery('
').appendTo('#qunit-fixture'); - let $bar = jQuery('
').appendTo('#qunit-fixture'); - - let data = encodeURIComponent(JSON.stringify({ name: 'Godfrey' })); - - return RSVP.all([ - run(App, 'visit', `/x-foo?data=${data}`, { rootElement: $foo[0] }), - run(App, 'visit', '/x-bar', { rootElement: $bar[0] }) - ]).then(() => { - assert.ok(xFooInitCalled); - assert.ok(xFooDidInsertElementCalled); - - assert.ok(xBarInitCalled); - assert.ok(xBarDidInsertElementCalled); - - assert.equal($foo.find('h1').text(), 'X-Foo'); - assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 0 times (0 times combined)!'); - assert.ok($foo.text().indexOf('X-Bar') === -1); - - assert.equal($bar.find('h1').text(), 'X-Bar'); - assert.equal($bar.find('button').text(), 'Join 0 others in clicking me!'); - assert.ok($bar.text().indexOf('X-Foo') === -1); - run(() => $foo.find('x-foo').click()); - - assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (1 times combined)!'); - assert.equal($bar.find('button').text(), 'Join 1 others in clicking me!'); - - run(() => { - $bar.find('button').click(); - $bar.find('button').click(); + let $foo = jQuery('
').appendTo(this.$()); + let $bar = jQuery('
').appendTo(this.$()); + + let data = encodeURIComponent(JSON.stringify({ name: 'Godfrey' })); + let instances = []; + + return RSVP.all([ + this.runTask(() => { + return this.application.visit(`/x-foo?data=${data}`, { rootElement: $foo[0] }); + }), + this.runTask(() => { + return this.application.visit('/x-bar', { rootElement: $bar[0] }); + }) + ]).then(_instances => { + instances = _instances; + + assert.ok(xFooInitCalled); + assert.ok(xFooDidInsertElementCalled); + + assert.ok(xBarInitCalled); + assert.ok(xBarDidInsertElementCalled); + + assert.equal($foo.find('h1').text(), 'X-Foo'); + assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 0 times (0 times combined)!'); + assert.ok($foo.text().indexOf('X-Bar') === -1); + + assert.equal($bar.find('h1').text(), 'X-Bar'); + assert.equal($bar.find('button').text(), 'Join 0 others in clicking me!'); + assert.ok($bar.text().indexOf('X-Foo') === -1); + + this.runTask(() => { + $foo.find('x-foo').click(); + }); + + assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (1 times combined)!'); + assert.equal($bar.find('button').text(), 'Join 1 others in clicking me!'); + + this.runTask(() => { + $bar.find('button').click(); + $bar.find('button').click(); + }); + + assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (3 times combined)!'); + assert.equal($bar.find('button').text(), 'Join 3 others in clicking me!'); + + }).finally(() => { + this.runTask(() => { + instances.forEach(instance => { + instance.destroy(); + }); + }); }); + } - assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (3 times combined)!'); - assert.equal($bar.find('button').text(), 'Join 3 others in clicking me!'); - }); -}); - -QUnit.skip('Test setup', function(assert) { -}); - -QUnit.skip('iframe setup', function(assert) { }); diff --git a/packages/internal-test-helpers/lib/test-cases/application.js b/packages/internal-test-helpers/lib/test-cases/application.js index 6f128ba7534..d778179b0ca 100644 --- a/packages/internal-test-helpers/lib/test-cases/application.js +++ b/packages/internal-test-helpers/lib/test-cases/application.js @@ -9,9 +9,7 @@ export default class ApplicationTestCase extends TestResolverApplicationTestCase super(); let { applicationOptions } = this; - this.application = this.runTask(() => { - return Application.create(applicationOptions) - }); + this.application = this.runTask(() => this.createApplication(applicationOptions)); this.resolver = applicationOptions.Resolver.lastInstance; @@ -20,6 +18,10 @@ export default class ApplicationTestCase extends TestResolverApplicationTestCase } } + createApplication(myOptions={}, MyApplication=Application) { + return MyApplication.create(myOptions); + } + get applicationOptions() { return assign(super.applicationOptions, { autoboot: false @@ -40,6 +42,7 @@ export default class ApplicationTestCase extends TestResolverApplicationTestCase return this.runTask(() => { return this.application.visit(url, options).then(instance => { this.applicationInstance = instance; + return instance; }); }); } diff --git a/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js b/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js index 594150e5e19..7587a790fdf 100644 --- a/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js +++ b/packages/internal-test-helpers/lib/test-cases/default-resolver-application.js @@ -13,7 +13,7 @@ export default class ApplicationTestCase extends AbstractApplicationTestCase { createApplication() { let application = this.application = Application.create(this.applicationOptions); - application.Router = Router.extend({ location: 'none' }); + application.Router = Router.extend(this.routerOptions); return application; } From f34c4e88f9ac980dd1dd493ec4f2a6343bf422a5 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 1 Jul 2017 21:19:24 +0500 Subject: [PATCH 109/224] cleanup `alias.teardown` --- packages/ember-metal/lib/alias.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ember-metal/lib/alias.js b/packages/ember-metal/lib/alias.js index 89b28bf9446..c861cca558e 100644 --- a/packages/ember-metal/lib/alias.js +++ b/packages/ember-metal/lib/alias.js @@ -35,9 +35,8 @@ export class AliasedProperty extends Descriptor { } } - teardown(obj, keyName) { - let meta = metaFor(obj); - if (meta.peekWatching(keyName)) { + teardown(obj, keyName, meta) { + if (meta && meta.peekWatching(keyName)) { removeDependentKeys(this, obj, keyName, meta); } } From d807315f99cd09fbd2a4ab2bca4ab4e9657c4534 Mon Sep 17 00:00:00 2001 From: Isaac Ezer Date: Fri, 16 Jun 2017 13:45:57 -0400 Subject: [PATCH 110/224] [FEATURE ember-module-unification] Initial work * Pass `source` to the resolver's `resolve` method as a second argument * Update the logic for component pairs to ensure local/private resolution of a component/template are only matched with another local/private resolution. --- FEATURES.md | 16 ++ features.json | 1 + packages/container/lib/container.js | 53 +++++-- packages/container/lib/registry.js | 35 ++++- packages/container/tests/container_test.js | 45 ++++++ packages/container/tests/registry_test.js | 29 ++++ packages/ember-glimmer/lib/environment.js | 9 +- .../components/local-lookup-test.js | 144 ++++++++++++++---- .../ember-views/lib/utils/lookup-component.js | 33 ++++ yarn.lock | 6 +- 10 files changed, 317 insertions(+), 54 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 3456d4ec2a3..4233f6c3a20 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -26,3 +26,19 @@ for a detailed explanation. Adds an ability to for developers to integrate their own custom component managers into Ember Applications per [RFC](https://github.com/emberjs/rfcs/blob/custom-components/text/0000-custom-components.md). + +* `ember-module-unification` + + Introduces support for Module Unification + ([RFC](https://github.com/dgeb/rfcs/blob/module-unification/text/0000-module-unification.md)) + to Ember. This includes: + + - Passing the `source` of a `lookup`/`factoryFor` call as the second argument + to an Ember resolver's `resolve` method (as a positional arg we will call + `referrer`). + - Making `lookupComponentPair` friendly to local/private resolutions. The + new code ensures a local resolution is not paired with a global resolution. + + This feature is paired with the + [`EMBER_RESOLVER_MODULE_UNIFICATION`](https://github.com/ember-cli/ember-resolver#ember_resolver_module_unification) + flag on the ember-resolver package. diff --git a/features.json b/features.json index 4f73e99c77f..5c4ee8a2222 100644 --- a/features.json +++ b/features.json @@ -7,6 +7,7 @@ "ember-glimmer-allow-backtracking-rerender": null, "ember-routing-router-service": true, "ember-engines-mount-params": true, + "ember-module-unification": null, "glimmer-custom-component-manager": null }, "deprecations": { diff --git a/packages/container/lib/container.js b/packages/container/lib/container.js index fd1c54a8c41..818ebd96e38 100644 --- a/packages/container/lib/container.js +++ b/packages/container/lib/container.js @@ -1,5 +1,6 @@ /* globals Proxy */ import { assert } from 'ember-debug'; +import { EMBER_MODULE_UNIFICATION } from 'ember/features'; import { DEBUG } from 'ember-env-flags'; import { dictionary, @@ -135,6 +136,10 @@ Container.prototype = { return { [OWNER]: this.owner }; }, + _resolverCacheKey(name, options) { + return this.registry.resolverCacheKey(name, options); + }, + /** Given a fullName, return the corresponding factory. The consumer of the factory is responsible for the destruction of any factory instances, as there is no @@ -153,18 +158,28 @@ Container.prototype = { assert('fullName must be a proper full name', this.registry.validateFullName(normalizedName)); if (options.source) { - normalizedName = this.registry.expandLocalLookup(fullName, options); + let expandedFullName = this.registry.expandLocalLookup(fullName, options); // if expandLocalLookup returns falsey, we do not support local lookup - if (!normalizedName) { - return; + if (!EMBER_MODULE_UNIFICATION) { + if (!expandedFullName) { + return; + } + + normalizedName = expandedFullName; + } else if (expandedFullName) { + // with ember-module-unification, if expandLocalLookup returns something, + // pass it to the resolve without the source + normalizedName = expandedFullName; + options = {}; } } - let cached = this.factoryManagerCache[normalizedName]; + let cacheKey = this._resolverCacheKey(normalizedName, options); + let cached = this.factoryManagerCache[cacheKey]; if (cached !== undefined) { return cached; } - let factory = this.registry.resolve(normalizedName); + let factory = EMBER_MODULE_UNIFICATION ? this.registry.resolve(normalizedName, options) : this.registry.resolve(normalizedName); if (factory === undefined) { return; @@ -180,7 +195,7 @@ Container.prototype = { manager = wrapManagerInDeprecationProxy(manager); } - this.factoryManagerCache[normalizedName] = manager; + this.factoryManagerCache[cacheKey] = manager; return manager; } }; @@ -224,15 +239,25 @@ function isInstantiatable(container, fullName) { function lookup(container, fullName, options = {}) { if (options.source) { - fullName = container.registry.expandLocalLookup(fullName, options); + let expandedFullName = container.registry.expandLocalLookup(fullName, options); - // if expandLocalLookup returns falsey, we do not support local lookup - if (!fullName) { - return; + if (!EMBER_MODULE_UNIFICATION) { + // if expandLocalLookup returns falsey, we do not support local lookup + if (!expandedFullName) { + return; + } + + fullName = expandedFullName; + } else if (expandedFullName) { + // with ember-module-unification, if expandLocalLookup returns something, + // pass it to the resolve without the source + fullName = expandedFullName; + options = {}; } } - let cached = container.cache[fullName]; + let cacheKey = container._resolverCacheKey(fullName, options); + let cached = container.cache[cacheKey]; if (cached !== undefined && options.singleton !== false) { return cached; } @@ -257,16 +282,18 @@ function isFactoryInstance(container, fullName, { instantiate, singleton }) { } function instantiateFactory(container, fullName, options) { - let factoryManager = container.factoryFor(fullName); + let factoryManager = EMBER_MODULE_UNIFICATION && options && options.source ? container.factoryFor(fullName, options) : container.factoryFor(fullName); if (factoryManager === undefined) { return; } + let cacheKey = container._resolverCacheKey(fullName, options); + // SomeClass { singleton: true, instantiate: true } | { singleton: true } | { instantiate: true } | {} // By default majority of objects fall into this case if (isSingletonInstance(container, fullName, options)) { - return container.cache[fullName] = factoryManager.create(); + return container.cache[cacheKey] = factoryManager.create(); } // SomeClass { singleton: false, instantiate: true } diff --git a/packages/container/lib/registry.js b/packages/container/lib/registry.js index 6128cc6463f..6de09fdee55 100644 --- a/packages/container/lib/registry.js +++ b/packages/container/lib/registry.js @@ -1,5 +1,6 @@ import { dictionary, assign, intern } from 'ember-utils'; import { assert, deprecate } from 'ember-debug'; +import { EMBER_MODULE_UNIFICATION } from 'ember/features'; import Container from './container'; import { DEBUG } from 'ember-env-flags'; @@ -604,6 +605,14 @@ Registry.prototype = { injections = injections.concat(this.fallback.getTypeInjections(type)); } return injections; + }, + + resolverCacheKey(name, options) { + if (!EMBER_MODULE_UNIFICATION) { + return name; + } + + return (options && options.source) ? `${options.source}:${name}` : name; } }; @@ -686,20 +695,32 @@ function resolve(registry, normalizedName, options) { if (options && options.source) { // when `source` is provided expand normalizedName // and source into the full normalizedName - normalizedName = registry.expandLocalLookup(normalizedName, options); + let expandedNormalizedName = registry.expandLocalLookup(normalizedName, options); // if expandLocalLookup returns falsey, we do not support local lookup - if (!normalizedName) { return; } + if (!EMBER_MODULE_UNIFICATION) { + if (!expandedNormalizedName) { + return; + } + + normalizedName = expandedNormalizedName; + } else if (expandedNormalizedName) { + // with ember-module-unification, if expandLocalLookup returns something, + // pass it to the resolve without the source + normalizedName = expandedNormalizedName; + options = {}; + } } - let cached = registry._resolveCache[normalizedName]; + let cacheKey = registry.resolverCacheKey(normalizedName, options); + let cached = registry._resolveCache[cacheKey]; if (cached !== undefined) { return cached; } - if (registry._failCache[normalizedName]) { return; } + if (registry._failCache[cacheKey]) { return; } let resolved; if (registry.resolver) { - resolved = registry.resolver.resolve(normalizedName); + resolved = registry.resolver.resolve(normalizedName, options && options.source); } if (resolved === undefined) { @@ -707,9 +728,9 @@ function resolve(registry, normalizedName, options) { } if (resolved === undefined) { - registry._failCache[normalizedName] = true; + registry._failCache[cacheKey] = true; } else { - registry._resolveCache[normalizedName] = resolved; + registry._resolveCache[cacheKey] = resolved; } return resolved; diff --git a/packages/container/tests/container_test.js b/packages/container/tests/container_test.js index 71f69d3f1c9..2d6f931ff11 100644 --- a/packages/container/tests/container_test.js +++ b/packages/container/tests/container_test.js @@ -1,6 +1,7 @@ import { getOwner, OWNER, assign } from 'ember-utils'; import { ENV } from 'ember-environment'; import { get } from 'ember-metal'; +import { EMBER_MODULE_UNIFICATION } from 'ember/features'; import { Registry } from '..'; import { factory } from 'internal-test-helpers'; @@ -615,3 +616,47 @@ QUnit.skip('#factoryFor does not add properties to the object being instantiated // not via registry/container shenanigans assert.deepEqual(Object.keys(instance), []); }); + +if (EMBER_MODULE_UNIFICATION) { + QUnit.module('Container module unification'); + + QUnit.test('The container can pass a source to factoryFor', function(assert) { + let PrivateComponent = factory(); + let lookup = 'component:my-input'; + let expectedSource = 'template:routes/application'; + let registry = new Registry(); + let resolveCount = 0; + registry.resolve = function(fullName, { source }) { + resolveCount++; + if (fullName === lookup && source === expectedSource) { + return PrivateComponent; + } + }; + + let container = registry.container(); + + assert.strictEqual(container.factoryFor(lookup, { source: expectedSource }).class, PrivateComponent, 'The correct factory was provided'); + assert.strictEqual(container.factoryFor(lookup, { source: expectedSource }).class, PrivateComponent, 'The correct factory was provided again'); + assert.equal(resolveCount, 1, 'resolve called only once and a cached factory was returned the second time'); + }); + + QUnit.test('The container can pass a source to lookup', function(assert) { + let PrivateComponent = factory(); + let lookup = 'component:my-input'; + let expectedSource = 'template:routes/application'; + let registry = new Registry(); + registry.resolve = function(fullName, { source }) { + if (fullName === lookup && source === expectedSource) { + return PrivateComponent; + } + }; + + let container = registry.container(); + + let result = container.lookup(lookup, { source: expectedSource }); + assert.ok(result instanceof PrivateComponent, 'The correct factory was provided'); + + assert.ok(container.cache[`template:routes/application:component:my-input`] instanceof PrivateComponent, + 'The correct factory was stored in the cache with the correct key which includes the source.'); + }); +} diff --git a/packages/container/tests/registry_test.js b/packages/container/tests/registry_test.js index 286b3b5294f..804624a7021 100644 --- a/packages/container/tests/registry_test.js +++ b/packages/container/tests/registry_test.js @@ -1,5 +1,6 @@ import { Registry, privatize } from '..'; import { factory } from 'internal-test-helpers'; +import { EMBER_MODULE_UNIFICATION } from 'ember/features'; QUnit.module('Registry'); @@ -691,6 +692,7 @@ QUnit.test('has uses expandLocalLookup', function(assert) { let resolver = { resolve(name) { + if (EMBER_MODULE_UNIFICATION && name === 'foo:baz') { return; } resolvedFullNames.push(name); return 'yippie!'; @@ -737,3 +739,30 @@ QUnit.test('valid format', function(assert) { assert.equal(matched[2], 'factory'); assert.ok(/^\d+$/.test(matched[3])); }); + +if (EMBER_MODULE_UNIFICATION) { + QUnit.module('Registry module unification'); + + QUnit.test('The registry can pass a source to the resolver', function(assert) { + let PrivateComponent = factory(); + let lookup = 'component:my-input'; + let source = 'template:routes/application'; + let resolveCount = 0; + let resolver = { + resolve(fullName, src) { + resolveCount++; + if (fullName === lookup && src === source) { + return PrivateComponent; + } + } + }; + let registry = new Registry({ resolver }); + registry.normalize = function(name) { + return name; + }; + + assert.strictEqual(registry.resolve(lookup, { source }), PrivateComponent, 'The correct factory was provided'); + assert.strictEqual(registry.resolve(lookup, { source }), PrivateComponent, 'The correct factory was provided again'); + assert.equal(resolveCount, 1, 'resolve called only once and a cached factory was returned the second time'); + }); +} diff --git a/packages/ember-glimmer/lib/environment.js b/packages/ember-glimmer/lib/environment.js index 7367d64c1c9..e8087ff92d3 100644 --- a/packages/ember-glimmer/lib/environment.js +++ b/packages/ember-glimmer/lib/environment.js @@ -1,6 +1,7 @@ import { guidFor, OWNER } from 'ember-utils'; import { Cache, _instrumentStart } from 'ember-metal'; import { assert, warn } from 'ember-debug'; +import { EMBER_MODULE_UNIFICATION } from 'ember/features'; import { DEBUG } from 'ember-env-flags'; import { lookupPartial, @@ -91,7 +92,8 @@ export default class Environment extends GlimmerEnvironment { return new CurlyComponentDefinition(name, componentFactory, layout, undefined, customManager); } }, ({ name, source, owner }) => { - let expandedName = source && owner._resolveLocalLookupName(name, source) || name; + let expandedName = source && this._resolveLocalLookupName(name, source, owner) || name; + let ownerGuid = guidFor(owner); return ownerGuid + '|' + expandedName; @@ -147,6 +149,11 @@ export default class Environment extends GlimmerEnvironment { } } + _resolveLocalLookupName(name, source, owner) { + return EMBER_MODULE_UNIFICATION ? `${source}:${name}` + : owner._resolveLocalLookupName(name, source); + } + macros() { let macros = super.macros(); populateMacros(macros.blocks, macros.inlines); diff --git a/packages/ember-glimmer/tests/integration/components/local-lookup-test.js b/packages/ember-glimmer/tests/integration/components/local-lookup-test.js index ab640904df4..514881230b2 100644 --- a/packages/ember-glimmer/tests/integration/components/local-lookup-test.js +++ b/packages/ember-glimmer/tests/integration/components/local-lookup-test.js @@ -1,36 +1,10 @@ import { moduleFor, RenderingTest } from '../../utils/test-case'; +import { ModuleBasedTestResolver } from 'internal-test-helpers'; import { Component } from '../../utils/helpers'; +import { EMBER_MODULE_UNIFICATION } from 'ember/features'; +import { helper, Helper } from 'ember-glimmer'; -function buildResolver() { - let resolver = { - resolve() { }, - expandLocalLookup(fullName, sourceFullName) { - let [sourceType, sourceName ] = sourceFullName.split(':'); - let [type, name ] = fullName.split(':'); - - if (type !== 'template' && sourceType === 'template' && sourceName.slice(0, 11) === 'components/') { - sourceName = sourceName.slice(11); - } - - if (type === 'template' && sourceType === 'template' && name.slice(0, 11) === 'components/') { - name = name.slice(11); - } - - - let result = `${type}:${sourceName}/${name}`; - - return result; - } - }; - - return resolver; -} - -moduleFor('Components test: local lookup', class extends RenderingTest { - getResolver() { - return buildResolver(); - } - +class LocalLookupTest extends RenderingTest { ['@test it can lookup a local template']() { this.registerComponent('x-outer/x-inner', { template: 'Nested template says: {{yield}}' }); this.registerComponent('x-outer', { template: '{{#x-inner}}Hi!{{/x-inner}}' }); @@ -217,4 +191,114 @@ moduleFor('Components test: local lookup', class extends RenderingTest { this.assertText('Nested template says (from global): Hi! Nested template says (from local): Hi! Nested template says (from local): Hi!'); } +} + +// first run these tests with expandLocalLookup + +function buildResolver() { + let resolver = { + resolve() { }, + expandLocalLookup(fullName, sourceFullName) { + let [sourceType, sourceName ] = sourceFullName.split(':'); + let [type, name ] = fullName.split(':'); + + if (type !== 'template' && sourceType === 'template' && sourceName.slice(0, 11) === 'components/') { + sourceName = sourceName.slice(11); + } + + if (type === 'template' && sourceType === 'template' && name.slice(0, 11) === 'components/') { + name = name.slice(11); + } + + + let result = `${type}:${sourceName}/${name}`; + + return result; + } + }; + + return resolver; +} + +moduleFor('Components test: local lookup with expandLocalLookup feature', class extends LocalLookupTest { + getResolver() { + return buildResolver(); + } }); + +if (EMBER_MODULE_UNIFICATION) { + class LocalLookupTestResolver extends ModuleBasedTestResolver { + resolve(specifier, referrer) { + let fullSpecifier = specifier; + + if (referrer) { + let namespace = referrer.split('template:components/')[1]; + if (specifier.indexOf('template:components/') !== -1) { + let name = specifier.split('template:components/')[1]; + fullSpecifier = `template:components/${namespace}/${name}`; + } else if (specifier.indexOf(':') !== -1) { + let [type, name] = specifier.split(':'); + fullSpecifier = `${type}:${namespace}/${name}`; + } + } + + return super.resolve(fullSpecifier); + } + } + + /* + * This sub-classing changes `registerXXX` methods to use the resolver. + * Required for testing the module unification-friendly `resolve` call + * with a `referrer` argument. + * + * In theory all these tests can be ported to use the resolver instead of + * the registry. + */ + moduleFor('Components test: local lookup with resolution referrer', class extends LocalLookupTest { + get resolver() { + return this.owner.__registry__.fallback.resolver; + } + + getResolver() { + return new LocalLookupTestResolver(); + } + + registerComponent(name, { ComponentClass = null, template = null }) { + let { resolver } = this; + + if (ComponentClass) { + resolver.add(`component:${name}`, ComponentClass); + } + + if (typeof template === 'string') { + resolver.add(`template:components/${name}`, this.compile(template, { + moduleName: `components/${name}` + })); + } + } + + registerTemplate(name, template) { + let { resolver } = this; + if (typeof template === 'string') { + resolver.add(`template:${name}`, this.compile(template, { + moduleName: name + })); + } else { + throw new Error(`Registered template "${name}" must be a string`); + } + } + + registerHelper(name, funcOrClassBody) { + let { resolver } = this; + let type = typeof funcOrClassBody; + + if (type === 'function') { + resolver.add(`helper:${name}`, helper(funcOrClassBody)); + } else if (type === 'object' && type !== null) { + resolver.add(`helper:${name}`, Helper.extend(funcOrClassBody)); + } else { + throw new Error(`Cannot register ${funcOrClassBody} as a helper`); + } + } + }); +} diff --git a/packages/ember-views/lib/utils/lookup-component.js b/packages/ember-views/lib/utils/lookup-component.js index 2be90a86886..7457c3f6696 100644 --- a/packages/ember-views/lib/utils/lookup-component.js +++ b/packages/ember-views/lib/utils/lookup-component.js @@ -1,6 +1,39 @@ import { privatize as P } from 'container'; +import { EMBER_MODULE_UNIFICATION } from 'ember/features'; + +function lookupModuleUnificationComponentPair(componentLookup, owner, name, options) { + let localComponent = componentLookup.componentFor(name, owner, options); + let localLayout = componentLookup.layoutFor(name, owner, options); + + let globalComponent = componentLookup.componentFor(name, owner); + let globalLayout = componentLookup.layoutFor(name, owner); + + let localAndUniqueComponent = !!localComponent && (!globalComponent || localComponent.class !== globalComponent.class); + let localAndUniqueLayout = !!localLayout && (!globalLayout || localLayout.meta.moduleName !== globalLayout.meta.moduleName); + + if (localAndUniqueComponent && localAndUniqueLayout) { + return { layout: localLayout, component: localComponent }; + } + + if (localAndUniqueComponent && !localAndUniqueLayout) { + return { layout: null, component: localComponent }; + } + + let defaultComponentFactory = owner.factoryFor(P`component:-default`); + + if (!localAndUniqueComponent && localAndUniqueLayout) { + return { layout: localLayout, component: defaultComponentFactory }; + } + + let component = globalComponent || (globalLayout && defaultComponentFactory); + return { layout: globalLayout, component }; +} function lookupComponentPair(componentLookup, owner, name, options) { + if (EMBER_MODULE_UNIFICATION) { + return lookupModuleUnificationComponentPair(componentLookup, owner, name, options); + } + let component = componentLookup.componentFor(name, owner, options); let layout = componentLookup.layoutFor(name, owner, options); diff --git a/yarn.lock b/yarn.lock index 857fb39ebd3..9a7f1e05cb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -838,9 +838,9 @@ backbone@^1.1.2: dependencies: underscore ">=1.8.3" -backburner.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/backburner.js/-/backburner.js-1.0.0.tgz#fffae139998f20a161ac2140d85639b152dfc226" +backburner.js@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/backburner.js/-/backburner.js-1.1.0.tgz#16ef021891bc330a2d021c63d8d68cb8611eb3e4" backo2@1.0.2: version "1.0.2" From c4796b585d059564b2c2d711a2b1479bfde60459 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Mon, 3 Jul 2017 00:46:02 +0200 Subject: [PATCH 111/224] [BUGFIX beta] Assert {{input}} helper is not used in block form. `input`'s content model is empty. That means it cannot have anything inside. Previously, calling the `{{input}}` helper with a block was allowed, but now it fails. This PR improves the message and fails earlier than during execution. Fixes #15361 --- .../assert-input-helper-without-block.js | 24 +++++++++++++++++++ .../lib/plugins/index.js | 4 +++- .../assert-input-helper-without-block-test.js | 16 +++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 packages/ember-template-compiler/lib/plugins/assert-input-helper-without-block.js create mode 100644 packages/ember-template-compiler/tests/plugins/assert-input-helper-without-block-test.js diff --git a/packages/ember-template-compiler/lib/plugins/assert-input-helper-without-block.js b/packages/ember-template-compiler/lib/plugins/assert-input-helper-without-block.js new file mode 100644 index 00000000000..e607f6cae62 --- /dev/null +++ b/packages/ember-template-compiler/lib/plugins/assert-input-helper-without-block.js @@ -0,0 +1,24 @@ +import { assert } from 'ember-debug'; +import calculateLocationDisplay from '../system/calculate-location-display'; + +export default function errorOnInputWithContent(env) { + let { moduleName } = env.meta; + + return { + name: 'assert-input-helper-without-block', + + visitors: { + BlockStatement(node) { + if (node.path.original !== 'input') { return; } + + assert(assertMessage(moduleName, node)); + } + } + }; +} + +function assertMessage(moduleName, node) { + let sourceInformation = calculateLocationDisplay(moduleName, node.loc); + + return `The {{input}} helper cannot be used in block form. ${sourceInformation}`; +} diff --git a/packages/ember-template-compiler/lib/plugins/index.js b/packages/ember-template-compiler/lib/plugins/index.js index eda3b4dc3ab..9b009b383ee 100644 --- a/packages/ember-template-compiler/lib/plugins/index.js +++ b/packages/ember-template-compiler/lib/plugins/index.js @@ -15,6 +15,7 @@ import TransformEachInIntoEach from './transform-each-in-into-each'; import TransformHasBlockSyntax from './transform-has-block-syntax'; import TransformDotComponentInvocation from './transform-dot-component-invocation'; import ExtractPragmaTag from './extract-pragma-tag'; +import AssertInputHelperWithoutBlock from './assert-input-helper-without-block'; import { GLIMMER_CUSTOM_COMPONENT_MANAGER } from 'ember/features'; @@ -35,7 +36,8 @@ const transforms = [ TransformInputTypeSyntax, TransformAttrsIntoArgs, TransformEachInIntoEach, - TransformHasBlockSyntax + TransformHasBlockSyntax, + AssertInputHelperWithoutBlock ]; if (GLIMMER_CUSTOM_COMPONENT_MANAGER) { diff --git a/packages/ember-template-compiler/tests/plugins/assert-input-helper-without-block-test.js b/packages/ember-template-compiler/tests/plugins/assert-input-helper-without-block-test.js new file mode 100644 index 00000000000..d6e5338ec0d --- /dev/null +++ b/packages/ember-template-compiler/tests/plugins/assert-input-helper-without-block-test.js @@ -0,0 +1,16 @@ +import { compile } from '../../index'; + +QUnit.module('ember-template-compiler: assert-input-helper-without-block'); + +QUnit.test('Using {{#input}}{{/input}} is not valid', function() { + expect(1); + + let expectedMessage = + `The {{input}} helper cannot be used in block form. ('baz/foo-bar' @ L1:C0) `; + + expectAssertion(() => { + compile('{{#input value="123"}}Completely invalid{{/input}}', { + moduleName: 'baz/foo-bar' + }); + }, expectedMessage); +}); From 4cc9b994331c28bbca2fa39a6b069abcdad9de32 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Mon, 3 Jul 2017 00:52:09 +0200 Subject: [PATCH 112/224] [CLEANUP] Fix typo in function name --- .../lib/plugins/transform-dot-component-invocation.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js b/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js index 1f6f3c31e46..5ad62615da1 100644 --- a/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js +++ b/packages/ember-template-compiler/lib/plugins/transform-dot-component-invocation.js @@ -65,7 +65,7 @@ export default function transformDotComponentInvocation(env) { } }, BlockStatement: (node) => { - if (isMulipartPath(node.path)) { + if (isMultipartPath(node.path)) { wrapInComponent(node, b) } } @@ -73,12 +73,12 @@ export default function transformDotComponentInvocation(env) { } } -function isMulipartPath(path) { +function isMultipartPath(path) { return path.parts.length > 1; } function isInlineInvocation(path, params, hash) { - if (isMulipartPath(path)) { + if (isMultipartPath(path)) { if (params.length > 0 || hash.pairs.length > 0) { return true; } From fb2ab987cbc72ed1640a3e310e1489a9f91fd5f9 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 3 Jul 2017 09:32:19 +0500 Subject: [PATCH 113/224] removed `isGlobalCache` since its not being used --- packages/ember-metal/lib/path_cache.js | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/packages/ember-metal/lib/path_cache.js b/packages/ember-metal/lib/path_cache.js index 65a65dca013..241a090cbd1 100644 --- a/packages/ember-metal/lib/path_cache.js +++ b/packages/ember-metal/lib/path_cache.js @@ -1,32 +1,23 @@ import Cache from './cache'; -const IS_GLOBAL = /^[A-Z$]/; const IS_GLOBAL_PATH = /^[A-Z$].*[\.]/; const HAS_THIS = 'this.'; -const isGlobalCache = new Cache(1000, key => IS_GLOBAL.test(key)); const isGlobalPathCache = new Cache(1000, key => IS_GLOBAL_PATH.test(key)); const hasThisCache = new Cache(1000, key => key.lastIndexOf(HAS_THIS, 0) === 0); const firstDotIndexCache = new Cache(1000, key => key.indexOf('.')); const firstKeyCache = new Cache(1000, (path) => { let index = firstDotIndexCache.get(path); - if (index === -1) { - return path; - } else { - return path.slice(0, index); - } + return index === -1 ? path : path.slice(0, index); }); const tailPathCache = new Cache(1000, (path) => { let index = firstDotIndexCache.get(path); - if (index !== -1) { - return path.slice(index + 1); - } + return index === -1 ? undefined : path.slice(index + 1); }); export const caches = { - isGlobalCache, isGlobalPathCache, hasThisCache, firstDotIndexCache, @@ -34,10 +25,6 @@ export const caches = { tailPathCache }; -export function isGlobal(path) { - return isGlobalCache.get(path); -} - export function isGlobalPath(path) { return isGlobalPathCache.get(path); } From bbc845f41824800ce084027f5bb67b6a0f567e06 Mon Sep 17 00:00:00 2001 From: bekzod Date: Tue, 4 Jul 2017 13:35:38 +0500 Subject: [PATCH 114/224] correct assertion in `meta` --- packages/ember-metal/lib/meta.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 6ec6cb9915e..74a2f05faff 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -331,10 +331,11 @@ export class Meta { let ret = this._chains; if (ret === undefined) { if (this.parent) { - ret = this._chains = this.parent.writableChains(create).copy(this.source); + ret = this.parent.writableChains(create).copy(this.source); } else { - ret = this._chains = create(this.source); + ret = create(this.source); } + this._chains = ret; } return ret; } @@ -344,7 +345,7 @@ export class Meta { } writeWatching(subkey, value) { - assert(`Cannot update watchers for \`hello\` on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); + assert(`Cannot update watchers for \`${subkey}\` on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); let map = this._getOrCreateOwnMap('_watching'); map[subkey] = value; } From 0c72faaa4586da57283691ac1d8f4a3f1f88f081 Mon Sep 17 00:00:00 2001 From: bekzod Date: Tue, 4 Jul 2017 15:02:33 +0500 Subject: [PATCH 115/224] remove `chainsFor` --- packages/ember-metal/lib/watch_path.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/ember-metal/lib/watch_path.js b/packages/ember-metal/lib/watch_path.js index fb76aaa84f1..988a716c914 100644 --- a/packages/ember-metal/lib/watch_path.js +++ b/packages/ember-metal/lib/watch_path.js @@ -2,14 +2,8 @@ import { meta as metaFor, peekMeta } from './meta'; -import { ChainNode } from './chains'; -// get the chains for the current object. If the current object has -// chains inherited from the proto they will be cloned and reconfigured for -// the current object. -function chainsFor(obj, meta) { - return (meta || metaFor(obj)).writableChains(makeChainNode); -} +import { ChainNode } from './chains'; export function makeChainNode(obj) { return new ChainNode(null, null, obj); @@ -22,7 +16,7 @@ export function watchPath(obj, keyPath, meta) { m.writeWatching(keyPath, counter + 1); if (counter === 0) { // activate watching first time - chainsFor(obj, m).add(keyPath); + m.writableChains(makeChainNode).add(keyPath); } } @@ -34,7 +28,7 @@ export function unwatchPath(obj, keyPath, meta) { if (counter === 1) { m.writeWatching(keyPath, 0); - chainsFor(obj, m).remove(keyPath); + m.readableChains().remove(keyPath); } else if (counter > 1) { m.writeWatching(keyPath, counter - 1); } From b2ea8fe77a9d7864af7d9325c5f63d09108149df Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 30 Jun 2017 20:08:30 +0500 Subject: [PATCH 116/224] bump rsvp --- package.json | 2 +- yarn.lock | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 8bef442a5b1..14ae2e840c8 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "handlebars": "^4.0.6", "jquery": "^3.2.1", "resolve": "^1.3.3", - "rsvp": "^3.5.0", + "rsvp": "^3.6.1", "simple-dom": "^0.3.0", "simple-html-tokenizer": "^0.4.1" }, diff --git a/yarn.lock b/yarn.lock index 9a7f1e05cb9..f0e7cdae590 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5234,9 +5234,13 @@ rsvp@3.0.14, rsvp@~3.0.6: version "3.0.14" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" -rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" +rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.0.tgz#666dfffa715f7e10eef76f4d1e56fb2566fce5c3" + +rsvp@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.1.tgz#34f4a7ac2859f7bacc8f49789c5604f1e26ae702" rsvp@~3.2.1: version "3.2.1" From 44eb0488467cf4ea7cd84f8f4ba5b6dbf47edd8b Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Wed, 5 Jul 2017 07:49:53 +0100 Subject: [PATCH 117/224] Add deprecated annotation to API docs --- packages/ember/lib/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember/lib/index.js b/packages/ember/lib/index.js index cf9ba435e6d..b12abe68c8d 100644 --- a/packages/ember/lib/index.js +++ b/packages/ember/lib/index.js @@ -232,6 +232,7 @@ Object.defineProperty(Ember, 'onerror', { @method K @return {Object} @public + @deprecated */ function deprecatedEmberK() { return this; } From 80a2113df01a8a9f3c1a37af86dddc8d631e5d04 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Wed, 5 Jul 2017 07:50:54 +0100 Subject: [PATCH 118/224] Update render.js --- packages/ember-glimmer/lib/syntax/render.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember-glimmer/lib/syntax/render.js b/packages/ember-glimmer/lib/syntax/render.js index 59889e5a793..a86e3ba8762 100644 --- a/packages/ember-glimmer/lib/syntax/render.js +++ b/packages/ember-glimmer/lib/syntax/render.js @@ -115,6 +115,7 @@ function makeComponentDefinition(vm, args) { @param {Hash} options @return {String} HTML string @public + @deprecated Use a component instead */ export function renderMacro(name, params, hash, builder) { if (!params) { From a1167cf6654bd5af880e1d50b4c9aa2ccdfbebd6 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Wed, 5 Jul 2017 11:30:13 +0100 Subject: [PATCH 119/224] [DOC release] Delete view.js This class is documentation-only at the moment, and I believe should have been removed after 2.4. --- packages/ember-views/lib/views/view.js | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 packages/ember-views/lib/views/view.js diff --git a/packages/ember-views/lib/views/view.js b/packages/ember-views/lib/views/view.js deleted file mode 100644 index df13b82643e..00000000000 --- a/packages/ember-views/lib/views/view.js +++ /dev/null @@ -1,13 +0,0 @@ -/** -@module ember -@submodule ember-views -*/ - -/** - @class View - @namespace Ember - @extends Ember.CoreView - @deprecated See https://emberjs.com/deprecations/v1.x/#toc_ember-view - @uses Ember.ClassNamesSupport - @private -*/ From bf9ceb640235717e5f1b20b3592bc96f67f3d240 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Wed, 5 Jul 2017 15:03:02 +0100 Subject: [PATCH 120/224] [DOC release] Fix `@for` documentation of registerDeprecationHandler --- packages/ember-debug/lib/deprecate.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember-debug/lib/deprecate.js b/packages/ember-debug/lib/deprecate.js index 65a08904eaa..8ead9561ac6 100644 --- a/packages/ember-debug/lib/deprecate.js +++ b/packages/ember-debug/lib/deprecate.js @@ -45,6 +45,7 @@ import { registerHandler as genericRegisterHandler, invoke } from './handlers'; @public @static @method registerDeprecationHandler + @for Ember.Debug @param handler {Function} A function to handle deprecation calls. @since 2.1.0 */ From b435034ed6c29cafece46633760819616add3506 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Wed, 5 Jul 2017 15:05:56 +0100 Subject: [PATCH 121/224] [DOC release] Fix `@for` documentation of registerWarnHandler --- packages/ember-debug/lib/warn.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember-debug/lib/warn.js b/packages/ember-debug/lib/warn.js index 05dc922804f..e57842b3642 100644 --- a/packages/ember-debug/lib/warn.js +++ b/packages/ember-debug/lib/warn.js @@ -39,6 +39,7 @@ if (DEBUG) { @public @static @method registerWarnHandler + @for Ember.Debug @param handler {Function} A function to handle warnings. @since 2.1.0 */ From e3b93ab5639d2c418f156506a6fe4c476595d931 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 5 Jul 2017 10:36:53 -0400 Subject: [PATCH 122/224] Post release version bump. --- VERSION | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index a9e6e20e8aa..83592be3d8e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.15.0.alpha.1 +2.16.0.alpha.1 diff --git a/package.json b/package.json index 14ae2e840c8..f592be64008 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-source", - "version": "2.15.0-alpha.1", + "version": "2.16.0-alpha.1", "description": "A JavaScript framework for creating ambitious web applications", "keywords": [ "ember-addon" From f20ef314db6e26751014acf21a62e6fe6503490d Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 5 Jul 2017 09:36:23 -0400 Subject: [PATCH 123/224] Update CHANGELOG to 2.14.0. [ci skip] --- CHANGELOG.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c43e0dd1d1d..fd44ef73c15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,20 @@ # Ember Changelog -### 2.14.0-beta.3 (May 30, 2017) +### 2.14.0 (July 5, 2017) +- [#15312](https://github.com/emberjs/ember.js/pull/15312) [BUGFIX] Avoid re-freezing already frozen objects. +- [#15315](https://github.com/emberjs/ember.js/pull/15315) [FEATURE] Add minlength to TextSupport +- [#15321](https://github.com/emberjs/ember.js/pull/15321) [BUGFIX] Improve fastboot debugger/repl experience +- [#15366](https://github.com/emberjs/ember.js/pull/15366) [BUGFIX] Allow numeric keys for the `get` helper. - [#15242](https://github.com/emberjs/ember.js/pull/15242) [BUGFIX] Fix EmberError import in system/router - [#15204](https://github.com/emberjs/ember.js/pull/15204) [DEPRECATION] `Ember.MODEL_FACTORY_INJECTIONS` is now always false, and issues a deprecation if set. - [#15239](https://github.com/emberjs/ember.js/pull/15239) [BUGFIX] Ensure `Ember.deprecate` is exported properly. - [glimmerjs/glimmer-vm#529](https://github.com/glimmerjs/glimmer-vm/pull/529) [BUGFIX] Fix issues identified with custom element support. - [#15277](https://github.com/emberjs/ember.js/pull/15277) [BUGFIX] Fix issues with retrying an initial transition. - -### 2.14.0-beta.2 (May 10, 2017) - - [#15138](https://github.com/emberjs/ember.js/pull/15138) [BUGFIX] Fix mocha blueprint service test filename - [#15193](https://github.com/emberjs/ember.js/pull/15193) [BUGFIX] Ensure `factoryFor` does validation. - [#15207](https://github.com/emberjs/ember.js/pull/15207) [BUGFIX] Ensure that an engines container is only destroyed once. - [#15218](https://github.com/emberjs/ember.js/pull/15218) [BUGFIX] Update route-recognizer to v0.3.3. - -### 2.14.0-beta.1 (April 27, 2017) - - [#15015](https://github.com/emberjs/ember.js/pull/15015) Allow mounting routeless engines with a bound engine name - [#15078](https://github.com/emberjs/ember.js/pull/15078) [DEPRECATION] Deprecate `EventManager#canDispatchToEventManager`. - [#15085](https://github.com/emberjs/ember.js/pull/15085) Add missing instrumentation for compilation/lookup phase From 2e45c053542f92ed363162b5d27f3da070310c62 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 5 Jul 2017 09:16:50 -0400 Subject: [PATCH 124/224] Add 2.13.4 to CHANGELOG.md. [ci skip] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd44ef73c15..c5637b53309 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,10 @@ - [#15178](https://github.com/emberjs/ember.js/pull/15178) Refactor route to lookup controller for QPs. - [#15129](https://github.com/emberjs/ember.js/pull/15129) Fix access to service:-document in ember-engines +### 2.13.4 (July 5, 2017) + +- [#15321](https://github.com/emberjs/ember.js/pull/15321) [BUGFIX] Improve fastboot debugger/repl experience. + ### 2.13.3 (May 31, 2017) - [#15284](https://github.com/emberjs/ember.js/pull/15284) [BUGFIX] remove nested transaction assertion from glimmer. From 6ccb09546ecc300148b737eaed653b0361c16311 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 5 Jul 2017 10:34:13 -0400 Subject: [PATCH 125/224] Add 2.15.0-beta.1 to CHANGELOG.md. [ci skip] --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5637b53309..f03ec5cc8f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Ember Changelog +### 2.15.0-beta.1 (July 5, 2017) + +- [#14338](https://github.com/emberjs/ember.js/pull/14338) [FEATURE] Remove explicit names from initializers. +- [#15325](https://github.com/emberjs/ember.js/pull/15325) / [#15326](https://github.com/emberjs/ember.js/pull/15326) [FEATURE ember-engines-mount-params] Allow `{{mount` to accept a `model` named parameter. +- [#15347](https://github.com/emberjs/ember.js/pull/15347) [BUGFIX] Make better errors for meta updates after object destruction. +- [#15411](https://github.com/emberjs/ember.js/pull/15411) [CLEANUP] Remove deprecated `Ember.Backburner`. +- [#15366](https://github.com/emberjs/ember.js/pull/15366) [BUGFIX] Allow numeric keys for the `get` helper. +- [#14805](https://github.com/emberjs/ember.js/pull/14805) / [#14861](https://github.com/emberjs/ember.js/pull/14861) / [#14979](https://github.com/emberjs/ember.js/pull/14979) / [#15414](https://github.com/emberjs/ember.js/pull/15414) / [#15415](https://github.com/emberjs/ember.js/pull/15415) [FEATURE ember-routing-router-service] Enable by default. +- [#15193](https://github.com/emberjs/ember.js/pull/15193) [CLEANUP] Remove `owner._lookupFactory` support. + ### 2.14.0 (July 5, 2017) - [#15312](https://github.com/emberjs/ember.js/pull/15312) [BUGFIX] Avoid re-freezing already frozen objects. From c6a52be3da2d035c149ef65ebc6ca92baab56fb9 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 6 Jul 2017 14:32:04 +0500 Subject: [PATCH 126/224] correct function extensions --- packages/ember-runtime/lib/ext/function.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/packages/ember-runtime/lib/ext/function.js b/packages/ember-runtime/lib/ext/function.js index 06352c01515..1fac9cb7674 100644 --- a/packages/ember-runtime/lib/ext/function.js +++ b/packages/ember-runtime/lib/ext/function.js @@ -5,12 +5,12 @@ import { ENV } from 'ember-environment'; import { + on, computed, observer } from 'ember-metal'; import { assert, deprecateFunc } from 'ember-debug'; -const a_slice = Array.prototype.slice; const FunctionPrototype = Function.prototype; if (ENV.EXTEND_PROTOTYPES.Function) { @@ -74,10 +74,7 @@ if (ENV.EXTEND_PROTOTYPES.Function) { @public */ FunctionPrototype.property = function () { - let ret = computed(this); - // ComputedProperty.prototype.property expands properties; no need for us to - // do so here. - return ret.property(...arguments); + return computed(...arguments, this); }; /** @@ -105,9 +102,8 @@ if (ENV.EXTEND_PROTOTYPES.Function) { @for Function @public */ - FunctionPrototype.observes = function(...args) { - args.push(this); - return observer.apply(this, args); + FunctionPrototype.observes = function() { + return observer(...arguments, this); }; @@ -184,9 +180,6 @@ if (ENV.EXTEND_PROTOTYPES.Function) { @public */ FunctionPrototype.on = function () { - let events = a_slice.call(arguments); - this.__ember_listens__ = events; - - return this; + return on(...arguments, this); }; } From 2c2eee15a7332abb5d9f6afdac4132d02ade9bcd Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 6 Jul 2017 14:50:32 +0500 Subject: [PATCH 127/224] added assertion to `Ember.on` for invalid arguments --- packages/ember-metal/lib/events.js | 4 ++++ packages/ember-metal/tests/events_test.js | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/ember-metal/lib/events.js b/packages/ember-metal/lib/events.js index 810b5731572..6fb2e0ce730 100644 --- a/packages/ember-metal/lib/events.js +++ b/packages/ember-metal/lib/events.js @@ -301,6 +301,10 @@ export function listenersFor(obj, eventName) { export function on(...args) { let func = args.pop(); let events = args; + + assert('Ember.on expects function as last argument', typeof func === 'function'); + assert('Ember.on called without valid event names', events.length > 0 && events.every((p)=> typeof p === 'string' && p.length)); + func.__ember_listens__ = events; return func; } diff --git a/packages/ember-metal/tests/events_test.js b/packages/ember-metal/tests/events_test.js index 4ce35f05a6b..cbbaf4858a5 100644 --- a/packages/ember-metal/tests/events_test.js +++ b/packages/ember-metal/tests/events_test.js @@ -236,6 +236,20 @@ QUnit.test('a listener can be added as part of a mixin', function() { equal(triggered, 2, 'should invoke listeners'); }); +QUnit.test('Ember.on asserts for invalid arguments', function() { + expectAssertion(()=> { + Mixin.create({ + foo1: on('bar'), + }); + }, 'Ember.on expects function as last argument'); + + expectAssertion(()=> { + Mixin.create({ + foo1: on(function(){}), + }); + }, 'Ember.on called without valid event names'); +}); + QUnit.test('a listener added as part of a mixin may be overridden', function() { let triggered = 0; let FirstMixin = Mixin.create({ From 4b2f8caedfb980cc2cbcd2e289f12b64b0944025 Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 7 Jul 2017 00:50:05 +0500 Subject: [PATCH 128/224] cleanup `mixin` --- packages/ember-metal/lib/mixin.js | 36 ++++++++++++++----------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/packages/ember-metal/lib/mixin.js b/packages/ember-metal/lib/mixin.js index 00630226f29..bb65ed202a0 100644 --- a/packages/ember-metal/lib/mixin.js +++ b/packages/ember-metal/lib/mixin.js @@ -140,16 +140,14 @@ function applyConcatenatedProperties(obj, key, value, values) { if (baseValue === null || baseValue === undefined) { ret = makeArray(value); - } else { - if (isArray(baseValue)) { - if (value === null || value === undefined) { - ret = baseValue; - } else { - ret = a_concat.call(baseValue, value); - } + } else if (isArray(baseValue)) { + if (value === null || value === undefined) { + ret = baseValue; } else { - ret = a_concat.call(makeArray(baseValue), value); + ret = a_concat.call(baseValue, value); } + } else { + ret = a_concat.call(makeArray(baseValue), value); } if (DEBUG) { @@ -215,7 +213,7 @@ function addNormalizedProperty(base, key, value, meta, descs, values, concats, m key === 'concatenatedProperties' || key === 'mergedProperties') { value = applyConcatenatedProperties(base, key, value, values); - } else if ((mergings && mergings.indexOf(key) >= 0)) { + } else if (mergings && mergings.indexOf(key) > -1) { value = applyMergedProperties(base, key, value, values); } else if (isMethod(value)) { value = giveMethodSuper(base, key, value, values, descs); @@ -315,9 +313,7 @@ function followAlias(obj, desc, descs, values) { return { desc, value }; } -function updateObserversAndListeners(obj, key, observerOrListener, pathsKey, updateMethod) { - let paths = observerOrListener[pathsKey]; - +function updateObserversAndListeners(obj, key, paths, updateMethod) { if (paths) { for (let i = 0; i < paths.length; i++) { updateMethod(obj, paths[i], null, key); @@ -328,16 +324,16 @@ function updateObserversAndListeners(obj, key, observerOrListener, pathsKey, upd function replaceObserversAndListeners(obj, key, observerOrListener) { let prev = obj[key]; - if ('function' === typeof prev) { - updateObserversAndListeners(obj, key, prev, '__ember_observesBefore__', _removeBeforeObserver); - updateObserversAndListeners(obj, key, prev, '__ember_observes__', removeObserver); - updateObserversAndListeners(obj, key, prev, '__ember_listens__', removeListener); + if (typeof prev === 'function') { + updateObserversAndListeners(obj, key, prev.__ember_observesBefore__, _removeBeforeObserver); + updateObserversAndListeners(obj, key, prev.__ember_observes__, removeObserver); + updateObserversAndListeners(obj, key, prev.__ember_listens__, removeListener); } - if ('function' === typeof observerOrListener) { - updateObserversAndListeners(obj, key, observerOrListener, '__ember_observesBefore__', _addBeforeObserver); - updateObserversAndListeners(obj, key, observerOrListener, '__ember_observes__', addObserver); - updateObserversAndListeners(obj, key, observerOrListener, '__ember_listens__', addListener); + if (typeof observerOrListener === 'function') { + updateObserversAndListeners(obj, key, observerOrListener.__ember_observesBefore__, _addBeforeObserver); + updateObserversAndListeners(obj, key, observerOrListener.__ember_observes__, addObserver); + updateObserversAndListeners(obj, key, observerOrListener.__ember_listens__, addListener); } } From 40fad187858ca4b865fd0ac683a8845418346340 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 7 Jul 2017 11:34:10 -0400 Subject: [PATCH 129/224] Properly instantiate subclass from Environment.create. --- packages/ember-glimmer/lib/environment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-glimmer/lib/environment.js b/packages/ember-glimmer/lib/environment.js index e8087ff92d3..f6a8ad4fab1 100644 --- a/packages/ember-glimmer/lib/environment.js +++ b/packages/ember-glimmer/lib/environment.js @@ -64,7 +64,7 @@ function instrumentationPayload(name) { export default class Environment extends GlimmerEnvironment { static create(options) { - return new Environment(options); + return new this(options); } constructor({ [OWNER]: owner }) { From 3f78533de784140747d2345282d7e4b136ba04ad Mon Sep 17 00:00:00 2001 From: cibernox Date: Fri, 7 Jul 2017 17:06:36 +0100 Subject: [PATCH 130/224] Cleanup packages/ember-metal/lib/dependent_keys.js --- packages/ember-metal/lib/dependent_keys.js | 9 ++++----- yarn.lock | 6 +----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/ember-metal/lib/dependent_keys.js b/packages/ember-metal/lib/dependent_keys.js index 29996d6a38f..919be3382b4 100644 --- a/packages/ember-metal/lib/dependent_keys.js +++ b/packages/ember-metal/lib/dependent_keys.js @@ -15,14 +15,13 @@ import { export function addDependentKeys(desc, obj, keyName, meta) { // the descriptor has a list of dependent keys, so // add all of its dependent keys. - let idx, depKey; let depKeys = desc._dependentKeys; - if (!depKeys) { + if (depKeys === null || depKeys === undefined) { return; } - for (idx = 0; idx < depKeys.length; idx++) { - depKey = depKeys[idx]; + for (let idx = 0; idx < depKeys.length; idx++) { + let depKey = depKeys[idx]; // Increment the number of times depKey depends on keyName. meta.writeDeps(depKey, keyName, (meta.peekDeps(depKey, keyName) || 0) + 1); // Watch the depKey @@ -34,7 +33,7 @@ export function removeDependentKeys(desc, obj, keyName, meta) { // the descriptor has a list of dependent keys, so // remove all of its dependent keys. let depKeys = desc._dependentKeys; - if (!depKeys) { + if (depKeys === null || depKeys === undefined) { return; } diff --git a/yarn.lock b/yarn.lock index f0e7cdae590..20d866f4a7c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5234,11 +5234,7 @@ rsvp@3.0.14, rsvp@~3.0.6: version "3.0.14" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" -rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3: - version "3.6.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.0.tgz#666dfffa715f7e10eef76f4d1e56fb2566fce5c3" - -rsvp@^3.6.1: +rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.6.1: version "3.6.1" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.1.tgz#34f4a7ac2859f7bacc8f49789c5604f1e26ae702" From 129c379e041cfe0571daf4cc8b20cb973aaa9954 Mon Sep 17 00:00:00 2001 From: cibernox Date: Fri, 7 Jul 2017 18:32:14 +0100 Subject: [PATCH 131/224] Move `accumulateListeners` to the only place where it's used. This avoids a few import/export for no reason. Also we void peeking the meta because it's always available in the context from where this function is called. --- packages/ember-metal/lib/events.js | 36 ------------------ packages/ember-metal/lib/index.js | 3 +- packages/ember-metal/lib/property_events.js | 42 +++++++++++++++++++-- packages/ember/lib/index.js | 1 - packages/ember/tests/reexports_test.js | 1 - 5 files changed, 39 insertions(+), 44 deletions(-) diff --git a/packages/ember-metal/lib/events.js b/packages/ember-metal/lib/events.js index 810b5731572..c09dc314050 100644 --- a/packages/ember-metal/lib/events.js +++ b/packages/ember-metal/lib/events.js @@ -25,42 +25,6 @@ import { ONCE, SUSPENDED } from './meta_listeners'; */ -function indexOf(array, target, method) { - let index = -1; - // hashes are added to the end of the event array - // so it makes sense to start searching at the end - // of the array and search in reverse - for (let i = array.length - 3; i >= 0; i -= 3) { - if (target === array[i] && method === array[i + 1]) { - index = i; - break; - } - } - return index; -} - -export function accumulateListeners(obj, eventName, otherActions) { - let meta = peekMeta(obj); - if (!meta) { return; } - let actions = meta.matchingListeners(eventName); - if (actions === undefined) { return; } - let newActions = []; - - for (let i = actions.length - 3; i >= 0; i -= 3) { - let target = actions[i]; - let method = actions[i + 1]; - let flags = actions[i + 2]; - let actionIndex = indexOf(otherActions, target, method); - - if (actionIndex === -1) { - otherActions.push(target, method, flags); - newActions.push(target, method, flags); - } - } - - return newActions; -} - /** Add an event listener diff --git a/packages/ember-metal/lib/index.js b/packages/ember-metal/lib/index.js index 64cf900ed1f..1a2c2ed94e0 100644 --- a/packages/ember-metal/lib/index.js +++ b/packages/ember-metal/lib/index.js @@ -44,7 +44,6 @@ export { } from './property_set'; export { default as WeakMap } from './weak_map'; export { - accumulateListeners, addListener, hasListeners, listenersFor, @@ -151,4 +150,4 @@ export { export { isProxy } from './is_proxy'; -export { default as descriptor } from './descriptor'; \ No newline at end of file +export { default as descriptor } from './descriptor'; diff --git a/packages/ember-metal/lib/property_events.js b/packages/ember-metal/lib/property_events.js index de4d8ce9267..0168c38e587 100644 --- a/packages/ember-metal/lib/property_events.js +++ b/packages/ember-metal/lib/property_events.js @@ -3,8 +3,7 @@ import { peekMeta } from './meta'; import { - sendEvent, - accumulateListeners + sendEvent } from './events'; import { markObjectAsDirty @@ -252,6 +251,41 @@ function changeProperties(callback, binding) { } } +function indexOf(array, target, method) { + let index = -1; + // hashes are added to the end of the event array + // so it makes sense to start searching at the end + // of the array and search in reverse + for (let i = array.length - 3; i >= 0; i -= 3) { + if (target === array[i] && method === array[i + 1]) { + index = i; + break; + } + } + return index; +} + +function accumulateListeners(obj, eventName, otherActions, meta) { + if (meta === null || meta === undefined) { return; } + let actions = meta.matchingListeners(eventName); + if (actions === undefined) { return; } + let newActions = []; + + for (let i = actions.length - 3; i >= 0; i -= 3) { + let target = actions[i]; + let method = actions[i + 1]; + let flags = actions[i + 2]; + let actionIndex = indexOf(otherActions, target, method); + + if (actionIndex === -1) { + otherActions.push(target, method, flags); + newActions.push(target, method, flags); + } + } + + return newActions; +} + function notifyBeforeObservers(obj, keyName, meta) { if (meta.isSourceDestroying()) { return; } @@ -259,7 +293,7 @@ function notifyBeforeObservers(obj, keyName, meta) { let listeners, added; if (deferred) { listeners = beforeObserverSet.add(obj, keyName, eventName); - added = accumulateListeners(obj, eventName, listeners); + added = accumulateListeners(obj, eventName, listeners, meta); sendEvent(obj, eventName, [obj, keyName], added); } else { sendEvent(obj, eventName, [obj, keyName]); @@ -273,7 +307,7 @@ function notifyObservers(obj, keyName, meta) { let listeners; if (deferred) { listeners = observerSet.add(obj, keyName, eventName); - accumulateListeners(obj, eventName, listeners); + accumulateListeners(obj, eventName, listeners, meta); } else { sendEvent(obj, eventName, [obj, keyName]); } diff --git a/packages/ember/lib/index.js b/packages/ember/lib/index.js index b12abe68c8d..566deb26949 100644 --- a/packages/ember/lib/index.js +++ b/packages/ember/lib/index.js @@ -88,7 +88,6 @@ Ember.sendEvent = metal.sendEvent; Ember.hasListeners = metal.hasListeners; Ember.watchedEvents = metal.watchedEvents; Ember.listenersFor = metal.listenersFor; -Ember.accumulateListeners = metal.accumulateListeners; Ember.isNone = metal.isNone; Ember.isEmpty = metal.isEmpty; Ember.isBlank = metal.isBlank; diff --git a/packages/ember/tests/reexports_test.js b/packages/ember/tests/reexports_test.js index 9c7aac1f3ed..f0769a3f8ea 100644 --- a/packages/ember/tests/reexports_test.js +++ b/packages/ember/tests/reexports_test.js @@ -71,7 +71,6 @@ QUnit.module('ember reexports'); ['hasListeners', 'ember-metal'], ['watchedEvents', 'ember-metal'], ['listenersFor', 'ember-metal'], - ['accumulateListeners', 'ember-metal'], ['isNone', 'ember-metal'], ['isEmpty', 'ember-metal'], ['isBlank', 'ember-metal'], From 50807348ceab7a50fa5a77df8ec8c38eb97f3b9d Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 8 Jul 2017 11:57:22 +0500 Subject: [PATCH 132/224] remove `getTag/setTag` and use `readableTag/writableTag` instead --- packages/ember-metal/lib/meta.js | 8 -------- packages/ember-metal/lib/tags.js | 10 +++++----- packages/ember-runtime/lib/mixins/-proxy.js | 2 +- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 6ec6cb9915e..7bf2b701834 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -97,14 +97,6 @@ export class Meta { return this.proto !== obj; } - setTag(tag) { - this._tag = tag; - } - - getTag(tag) { - return this._tag; - } - destroy() { if (this.isMetaDestroyed()) { return; } diff --git a/packages/ember-metal/lib/tags.js b/packages/ember-metal/lib/tags.js index b5dbd55c52e..5e265cd9ad4 100644 --- a/packages/ember-metal/lib/tags.js +++ b/packages/ember-metal/lib/tags.js @@ -51,7 +51,7 @@ export function markObjectAsDirty(meta, propertyKey) { } if (propertyKey === 'content' && meta.isProxy()) { - meta.getTag().contentDidChange(); + objectTag.contentDidChange(); } if (objectTag !== undefined || propertyTag !== undefined) { @@ -59,13 +59,13 @@ export function markObjectAsDirty(meta, propertyKey) { } } -let run; +let backburner; function ensureRunloop() { - if (run === undefined) { - run = require('ember-metal').run; + if (backburner === undefined) { + backburner = require('ember-metal').run.backburner; } if (hasViews()) { - run.backburner.ensureInstance(); + backburner.ensureInstance(); } } diff --git a/packages/ember-runtime/lib/mixins/-proxy.js b/packages/ember-runtime/lib/mixins/-proxy.js index a9cae5863ee..9bd147a4a7c 100644 --- a/packages/ember-runtime/lib/mixins/-proxy.js +++ b/packages/ember-runtime/lib/mixins/-proxy.js @@ -86,7 +86,7 @@ export default Mixin.create({ this._super(...arguments); let m = meta(this); m.setProxy(); - m.setTag(new ProxyTag(this)); + m.writableTag((source)=> new ProxyTag(source)); }, isTruthy: bool('content'), From aeff86a8314795197e5daa3168d41cd2aeaee2df Mon Sep 17 00:00:00 2001 From: cibernox Date: Sat, 8 Jul 2017 15:32:21 +0100 Subject: [PATCH 133/224] Remove meta check --- packages/ember-metal/lib/property_events.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ember-metal/lib/property_events.js b/packages/ember-metal/lib/property_events.js index 0168c38e587..20126fd1eb5 100644 --- a/packages/ember-metal/lib/property_events.js +++ b/packages/ember-metal/lib/property_events.js @@ -266,7 +266,6 @@ function indexOf(array, target, method) { } function accumulateListeners(obj, eventName, otherActions, meta) { - if (meta === null || meta === undefined) { return; } let actions = meta.matchingListeners(eventName); if (actions === undefined) { return; } let newActions = []; From 94f188ad47f1c58fe8444b837594c777d2b0d0cb Mon Sep 17 00:00:00 2001 From: Michael Donaldson Date: Fri, 7 Jul 2017 10:33:12 +0100 Subject: [PATCH 134/224] [BUGFIX lts] Ensure event dispatcher is a singleton --- .../lib/system/engine-instance.js | 4 +- .../tests/system/application_instance_test.js | 4 +- .../tests/integration/mount-test.js | 42 +++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/ember-application/lib/system/engine-instance.js b/packages/ember-application/lib/system/engine-instance.js index 1498d49e5f5..c480644aeb3 100644 --- a/packages/ember-application/lib/system/engine-instance.js +++ b/packages/ember-application/lib/system/engine-instance.js @@ -166,7 +166,6 @@ const EngineInstance = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixi let registrations = [ 'route:basic', - 'event_dispatcher:main', 'service:-routing', 'service:-glimmer-environment' ]; @@ -181,7 +180,8 @@ const EngineInstance = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixi P`-bucket-cache:main`, '-view-registry:main', `renderer:-${env.isInteractive ? 'dom' : 'inert'}`, - 'service:-document' + 'service:-document', + 'event_dispatcher:main' ]; singletons.forEach(key => this.register(key, parent.lookup(key), { instantiate: false })); diff --git a/packages/ember-application/tests/system/application_instance_test.js b/packages/ember-application/tests/system/application_instance_test.js index 824aeffefec..6995296b1f7 100644 --- a/packages/ember-application/tests/system/application_instance_test.js +++ b/packages/ember-application/tests/system/application_instance_test.js @@ -156,7 +156,6 @@ QUnit.test('can build and boot a registered engine', function(assert) { let registrations = [ 'route:basic', - 'event_dispatcher:main', 'service:-routing', 'service:-glimmer-environment' ]; @@ -173,7 +172,8 @@ QUnit.test('can build and boot a registered engine', function(assert) { P`-bucket-cache:main`, '-view-registry:main', '-environment:main', - 'service:-document' + 'service:-document', + 'event_dispatcher:main' ]; let env = appInstance.lookup('-environment:main'); diff --git a/packages/ember-glimmer/tests/integration/mount-test.js b/packages/ember-glimmer/tests/integration/mount-test.js index dcb9fa92d0b..85fb44eeb0a 100644 --- a/packages/ember-glimmer/tests/integration/mount-test.js +++ b/packages/ember-glimmer/tests/integration/mount-test.js @@ -188,6 +188,48 @@ moduleFor('{{mount}} test', class extends ApplicationTest { }); } + ['@test it declares the event dispatcher as a singleton']() { + this.router.map(function() { + this.route('engine-event-dispatcher-singleton'); + }); + + let controller; + let component; + + this.add('controller:engine-event-dispatcher-singleton', Controller.extend({ + init() { + this._super(...arguments); + controller = this; + } + })); + this.addTemplate('engine-event-dispatcher-singleton', '{{mount "foo"}}'); + + this.add('engine:foo', Engine.extend({ + router: null, + init() { + this._super(...arguments); + this.register('template:application', compile('

Foo Engine: {{tagless-component}}

', { moduleName: 'application' })); + this.register('component:tagless-component', Component.extend({ + tagName: "", + init() { + this._super(...arguments); + component = this; + } + })); + this.register('template:components/tagless-component', compile('Tagless Component', { moduleName: 'components/tagless-component' })); + } + })); + + return this.visit('/engine-event-dispatcher-singleton').then(() => { + this.assertComponentElement(this.firstChild, { content: '

Foo Engine: Tagless Component

' }); + + let controllerOwnerEventDispatcher = getOwner(controller).lookup('event_dispatcher:main'); + let taglessComponentOwnerEventDispatcher = getOwner(component).lookup('event_dispatcher:main'); + + this.assert.strictEqual(controllerOwnerEventDispatcher, taglessComponentOwnerEventDispatcher); + }); + } + }); if (EMBER_ENGINES_MOUNT_PARAMS) { From 1f2564de371db234b2ec6576b875ad7be4e05016 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 10 Jul 2017 01:00:10 +0500 Subject: [PATCH 135/224] update `ember-cli-sauce` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f592be64008..d098c34cfde 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "ember-cli": "2.10.0", "ember-cli-blueprint-test-helpers": "^0.12.0", "ember-cli-dependency-checker": "^1.4.0", - "ember-cli-sauce": "^2.0.0", + "ember-cli-sauce": "^2.1.0", "ember-cli-yuidoc": "^0.8.8", "ember-dev": "github:emberjs/ember-dev#eace534", "ember-publisher": "0.0.7", From 2696395bd8e895d5a91f7041ca18a1e660293a3c Mon Sep 17 00:00:00 2001 From: cibernox Date: Fri, 7 Jul 2017 19:11:19 +0100 Subject: [PATCH 136/224] Cleanup packages/ember-metal/lib/properties.js --- packages/ember-metal/lib/properties.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/ember-metal/lib/properties.js b/packages/ember-metal/lib/properties.js index dd506cdd468..f54a3fdb6e7 100644 --- a/packages/ember-metal/lib/properties.js +++ b/packages/ember-metal/lib/properties.js @@ -58,7 +58,9 @@ export function MANDATORY_SETTER_FUNCTION(name) { export function DEFAULT_GETTER_FUNCTION(name) { return function GETTER_FUNCTION() { let meta = peekMeta(this); - return meta && meta.peekValues(name); + if (meta !== undefined) { + return meta.peekValues(name); + } }; } @@ -67,7 +69,10 @@ import { UNDEFINED } from './meta'; export function INHERITING_GETTER_FUNCTION(name) { function IGETTER_FUNCTION() { let meta = peekMeta(this); - let val = meta && meta.readInheritedValue('values', name); + let val; + if (meta !== undefined) { + val = meta.readInheritedValue('values', name); + } if (val === UNDEFINED) { let proto = Object.getPrototypeOf(this); @@ -127,7 +132,7 @@ export function INHERITING_GETTER_FUNCTION(name) { become the explicit value of this property. */ export function defineProperty(obj, keyName, desc, data, meta) { - if (!meta) { + if (meta === null || meta === undefined) { meta = metaFor(obj); } From 904b739f2cdc35ae728ffea657583a91c5204598 Mon Sep 17 00:00:00 2001 From: cibernox Date: Fri, 7 Jul 2017 23:56:09 +0100 Subject: [PATCH 137/224] `meta` can be null --- packages/ember-metal/lib/properties.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-metal/lib/properties.js b/packages/ember-metal/lib/properties.js index f54a3fdb6e7..b89ff62b487 100644 --- a/packages/ember-metal/lib/properties.js +++ b/packages/ember-metal/lib/properties.js @@ -58,7 +58,7 @@ export function MANDATORY_SETTER_FUNCTION(name) { export function DEFAULT_GETTER_FUNCTION(name) { return function GETTER_FUNCTION() { let meta = peekMeta(this); - if (meta !== undefined) { + if (meta !== null && meta !== undefined) { return meta.peekValues(name); } }; @@ -70,7 +70,7 @@ export function INHERITING_GETTER_FUNCTION(name) { function IGETTER_FUNCTION() { let meta = peekMeta(this); let val; - if (meta !== undefined) { + if (meta !== null && meta !== undefined) { val = meta.readInheritedValue('values', name); } From 1f8c4f6dc98957ec461189b9ee6b45ab947e13a6 Mon Sep 17 00:00:00 2001 From: bekzod Date: Tue, 11 Jul 2017 23:14:57 +0500 Subject: [PATCH 138/224] remove logic that already handled by `PrimitiveReference.create` --- packages/ember-glimmer/lib/utils/references.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/packages/ember-glimmer/lib/utils/references.js b/packages/ember-glimmer/lib/utils/references.js index 75ac4b368e0..b1d2c8cc85b 100644 --- a/packages/ember-glimmer/lib/utils/references.js +++ b/packages/ember-glimmer/lib/utils/references.js @@ -22,7 +22,6 @@ import { import { ConditionalReference as GlimmerConditionalReference, PrimitiveReference, - NULL_REFERENCE, UNDEFINED_REFERENCE } from '@glimmer/runtime'; import emberToBool from './to-bool'; @@ -97,7 +96,7 @@ export class RootReference extends ConstReference { get(propertyKey) { let ref = this.children[propertyKey]; - if (!ref) { + if (ref === undefined) { ref = this.children[propertyKey] = new RootPropertyReference(this.inner, propertyKey); } @@ -318,11 +317,7 @@ export class SimpleHelperReference extends CachedReference { let result = helper(positionalValue, namedValue); - if (result === null) { - return NULL_REFERENCE; - } else if (result === undefined) { - return UNDEFINED_REFERENCE; - } else if (typeof result === 'object') { + if (typeof result === 'object' && result !== null) { return new RootReference(result); } else { return PrimitiveReference.create(result); @@ -403,11 +398,7 @@ export class InternalHelperReference extends CachedReference { // @implements PathReference export class UnboundReference extends ConstReference { static create(value) { - if (value === null) { - return NULL_REFERENCE; - } else if (value === undefined) { - return UNDEFINED_REFERENCE; - } else if (typeof value === 'object') { + if (typeof value === 'object' && value !== null) { return new UnboundReference(value); } else { return PrimitiveReference.create(value); From e4755452492bed282a974ff6510629ffa9851246 Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 12 Jul 2017 01:04:20 +0500 Subject: [PATCH 139/224] avoid using `expandProperties` twice --- packages/ember-runtime/lib/computed/computed_macros.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/ember-runtime/lib/computed/computed_macros.js b/packages/ember-runtime/lib/computed/computed_macros.js index c95b2659982..7fa5fcd9621 100644 --- a/packages/ember-runtime/lib/computed/computed_macros.js +++ b/packages/ember-runtime/lib/computed/computed_macros.js @@ -2,6 +2,7 @@ import { get, set, computed, + ComputedProperty, isEmpty, isNone, alias, @@ -38,7 +39,7 @@ function generateComputedWithPredicate(name, predicate) { return (...properties) => { let expandedProperties = expandPropertiesToArray(name, properties); - let computedFunc = computed(function() { + let computedFunc = new ComputedProperty(function() { let lastIdx = expandedProperties.length - 1; for (let i = 0; i < lastIdx; i++) { @@ -49,9 +50,9 @@ function generateComputedWithPredicate(name, predicate) { } return get(this, expandedProperties[lastIdx]); - }); + }, { dependentKeys: expandedProperties }); - return computedFunc.property(...expandedProperties); + return computedFunc; }; } From 220f07adb72a57a26e2973713042a673ced68043 Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 12 Jul 2017 13:15:53 +0500 Subject: [PATCH 140/224] avoid creating extra function --- .../ember-runtime/lib/computed/reduce_computed_macros.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/ember-runtime/lib/computed/reduce_computed_macros.js b/packages/ember-runtime/lib/computed/reduce_computed_macros.js index 13b81512664..657d8c1b63f 100644 --- a/packages/ember-runtime/lib/computed/reduce_computed_macros.js +++ b/packages/ember-runtime/lib/computed/reduce_computed_macros.js @@ -25,9 +25,7 @@ function reduceMacro(dependentKey, callback, initialValue) { if (arr === null || typeof arr !== 'object') { return initialValue; } - return arr.reduce((previousValue, currentValue, index, array) => { - return callback.call(this, previousValue, currentValue, index, array); - }, initialValue); + return arr.reduce(callback, initialValue, this); }).readOnly(); } @@ -512,7 +510,6 @@ export function intersect(...args) { return multiArrayMacro(args, function(dependentKeys) { let arrays = dependentKeys.map(dependentKey => { let array = get(this, dependentKey); - return isArray(array) ? array : []; }); From 33155b50c2725695a452ed29f01032b264a22107 Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 12 Jul 2017 14:12:44 +0500 Subject: [PATCH 141/224] reuse `shallowEqual` --- packages/ember-routing/lib/services/router.js | 13 +----------- .../ember-routing/lib/system/router_state.js | 20 +++---------------- packages/ember-routing/lib/utils.js | 20 +++++++++++++++++++ 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/packages/ember-routing/lib/services/router.js b/packages/ember-routing/lib/services/router.js index eccdfaf0308..c1a3b9797ac 100644 --- a/packages/ember-routing/lib/services/router.js +++ b/packages/ember-routing/lib/services/router.js @@ -8,20 +8,9 @@ import { readOnly } from 'ember-runtime'; import { assign } from 'ember-utils'; +import { shallowEqual } from '../utils'; import RouterDSL from '../system/dsl'; - -function shallowEqual(a, b) { - let k; - for (k in a) { - if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } - } - for (k in b) { - if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } - } - return true; -} - /** The Router service is the public API that provides component/view layer access to the router. diff --git a/packages/ember-routing/lib/system/router_state.js b/packages/ember-routing/lib/system/router_state.js index 446136de6b2..7e0785cd378 100644 --- a/packages/ember-routing/lib/system/router_state.js +++ b/packages/ember-routing/lib/system/router_state.js @@ -1,5 +1,5 @@ import { assign } from 'ember-utils'; -import { isEmpty } from 'ember-metal'; +import { shallowEqual } from '../utils'; import { Object as EmberObject } from 'ember-runtime'; export default EmberObject.extend({ @@ -11,11 +11,8 @@ export default EmberObject.extend({ let state = this.routerJsState; if (!this.routerJs.isActiveIntent(routeName, models, null, state)) { return false; } - let emptyQueryParams = isEmpty(Object.keys(queryParams)); - - if (queryParamsMustMatch && !emptyQueryParams) { - let visibleQueryParams = {}; - assign(visibleQueryParams, queryParams); + if (queryParamsMustMatch && Object.keys(queryParams).length > 0) { + let visibleQueryParams = assign({}, queryParams); this.emberRouter._prepareQueryParams(routeName, models, visibleQueryParams); return shallowEqual(visibleQueryParams, state.queryParams); @@ -24,14 +21,3 @@ export default EmberObject.extend({ return true; } }); - -function shallowEqual(a, b) { - let k; - for (k in a) { - if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } - } - for (k in b) { - if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } - } - return true; -} diff --git a/packages/ember-routing/lib/utils.js b/packages/ember-routing/lib/utils.js index de29d594ef2..ee2b7f706e1 100644 --- a/packages/ember-routing/lib/utils.js +++ b/packages/ember-routing/lib/utils.js @@ -193,3 +193,23 @@ export function prefixRouteNameArg(route, args) { return args; } + +export function shallowEqual(a, b) { + let k; + let aCount = 0; + let bCount = 0; + for (k in a) { + if (a.hasOwnProperty(k)) { + if (a[k] !== b[k]) { return false; } + aCount++; + } + } + + for (k in b) { + if (b.hasOwnProperty(k)) { + bCount++; + } + } + + return aCount === bCount; +} From 1182922b9d3247c5dbc69ce70c2bf8e7cb372daa Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 13 Jul 2017 11:20:13 +0500 Subject: [PATCH 142/224] fixed typo --- packages/ember-metal/lib/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 6ec6cb9915e..7846056597b 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -522,7 +522,7 @@ if (HAS_NATIVE_WEAKMAP) { pointer = getPrototypeOf(pointer); if (DEBUG) { - counters.peakPrototypeWalks++; + counters.peekPrototypeWalks++; } } }; From 8e353e7442fb4f256240acf1862f09b3105e52e3 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 10 Jul 2017 10:48:58 +0500 Subject: [PATCH 143/224] cleanup `if-unless` positional arguments list already returns `UNDEFINED_REFERENCE` for missing positional argument so need to replace it with null then replace it with `UNDEFINED_REFERENCE` --- packages/ember-glimmer/lib/helpers/action.js | 1 - .../ember-glimmer/lib/helpers/if-unless.js | 40 +++++++------------ packages/ember-metal/lib/property_events.js | 2 +- 3 files changed, 15 insertions(+), 28 deletions(-) diff --git a/packages/ember-glimmer/lib/helpers/action.js b/packages/ember-glimmer/lib/helpers/action.js index b9cbf0c31e0..1c8c483a63f 100644 --- a/packages/ember-glimmer/lib/helpers/action.js +++ b/packages/ember-glimmer/lib/helpers/action.js @@ -272,7 +272,6 @@ export default function(vm, args) { let { named, positional } = args; let capturedArgs = positional.capture(); - let { references } = capturedArgs; // The first two argument slots are reserved. // pos[0] is the context (or `this`) diff --git a/packages/ember-glimmer/lib/helpers/if-unless.js b/packages/ember-glimmer/lib/helpers/if-unless.js index f51c085fcf7..f53fcab8535 100644 --- a/packages/ember-glimmer/lib/helpers/if-unless.js +++ b/packages/ember-glimmer/lib/helpers/if-unless.js @@ -5,7 +5,6 @@ import { assert } from 'ember-debug'; import { - UNDEFINED_REFERENCE, CachedReference, ConditionalReference } from '../utils/references'; @@ -17,11 +16,8 @@ import { } from '@glimmer/reference'; class ConditionalHelperReference extends CachedReference { - static create(_condRef, _truthyRef, _falsyRef) { + static create(_condRef, truthyRef, falsyRef) { let condRef = ConditionalReference.create(_condRef); - let truthyRef = _truthyRef || UNDEFINED_REFERENCE; - let falsyRef = _falsyRef || UNDEFINED_REFERENCE; - if (isConst(condRef)) { return condRef.value() ? truthyRef : falsyRef; } else { @@ -41,9 +37,7 @@ class ConditionalHelperReference extends CachedReference { } compute() { - let { cond, truthy, falsy } = this; - - let branch = cond.value() ? truthy : falsy; + let branch = this.cond.value() ? this.truthy : this.falsy; this.branchTag.update(branch.tag); @@ -134,15 +128,12 @@ class ConditionalHelperReference extends CachedReference { @public */ export function inlineIf(vm, { positional }) { - switch (positional.length) { - case 2: return ConditionalHelperReference.create(positional.at(0), positional.at(1), null); - case 3: return ConditionalHelperReference.create(positional.at(0), positional.at(1), positional.at(2)); - default: - assert( - 'The inline form of the `if` helper expects two or three arguments, e.g. ' + - '`{{if trialExpired "Expired" expiryDate}}`.' - ); - } + assert( + 'The inline form of the `if` helper expects two or three arguments, e.g. ' + + '`{{if trialExpired "Expired" expiryDate}}`.', + positional.length === 3 || positional.length === 2 + ); + return ConditionalHelperReference.create(positional.at(0), positional.at(1), positional.at(2)); } /** @@ -166,13 +157,10 @@ export function inlineIf(vm, { positional }) { @public */ export function inlineUnless(vm, { positional }) { - switch (positional.length) { - case 2: return ConditionalHelperReference.create(positional.at(0), null, positional.at(1)); - case 3: return ConditionalHelperReference.create(positional.at(0), positional.at(2), positional.at(1)); - default: - assert( - 'The inline form of the `unless` helper expects two or three arguments, e.g. ' + - '`{{unless isFirstLogin "Welcome back!"}}`.' - ); - } + assert( + 'The inline form of the `unless` helper expects two or three arguments, e.g. ' + + '`{{unless isFirstLogin "Welcome back!"}}`.', + positional.length === 3 || positional.length === 2 + ); + return ConditionalHelperReference.create(positional.at(0), positional.at(2), positional.at(1)); } diff --git a/packages/ember-metal/lib/property_events.js b/packages/ember-metal/lib/property_events.js index 20126fd1eb5..a339d0ba587 100644 --- a/packages/ember-metal/lib/property_events.js +++ b/packages/ember-metal/lib/property_events.js @@ -101,7 +101,7 @@ function propertyDidChange(obj, keyName, _meta) { dependentKeysDidChange(obj, keyName, meta); } - chainsDidChange(obj, keyName, meta, false); + chainsDidChange(obj, keyName, meta); notifyObservers(obj, keyName, meta); } From 20bea46c43afab31f1dba20363811693c6e4e4ab Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 8 Jul 2017 18:47:53 +0500 Subject: [PATCH 144/224] remove `NULL_REFERENCE`, `UNDEFINED_REFERENCE` rexporting --- packages/ember-glimmer/lib/utils/references.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ember-glimmer/lib/utils/references.js b/packages/ember-glimmer/lib/utils/references.js index b1d2c8cc85b..fda919586ab 100644 --- a/packages/ember-glimmer/lib/utils/references.js +++ b/packages/ember-glimmer/lib/utils/references.js @@ -35,8 +35,6 @@ import { export const UPDATE = symbol('UPDATE'); -export { NULL_REFERENCE, UNDEFINED_REFERENCE } from '@glimmer/runtime'; - let maybeFreeze; if (DEBUG) { // gaurding this in a DEBUG gaurd (as well as all invocations) From 0d73a2ce0a9f0f04d63e49b68b1a0e94fdfbc4c3 Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 30 Jun 2017 11:08:48 +0500 Subject: [PATCH 145/224] cleanup `import/export` in `watching` and `properties` --- packages/ember-metal/lib/properties.js | 4 +--- packages/ember-metal/lib/property_events.js | 19 +++++++------------ packages/ember-metal/lib/watching.js | 20 ++++++++------------ 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/packages/ember-metal/lib/properties.js b/packages/ember-metal/lib/properties.js index dd506cdd468..318b5d89bd6 100644 --- a/packages/ember-metal/lib/properties.js +++ b/packages/ember-metal/lib/properties.js @@ -3,7 +3,7 @@ */ import { assert } from 'ember-debug'; -import { meta as metaFor, peekMeta } from './meta'; +import { meta as metaFor, peekMeta, UNDEFINED } from './meta'; import { overrideChains } from './property_events'; import { MANDATORY_SETTER } from 'ember/features'; // .......................................................... @@ -62,8 +62,6 @@ export function DEFAULT_GETTER_FUNCTION(name) { }; } -import { UNDEFINED } from './meta'; - export function INHERITING_GETTER_FUNCTION(name) { function IGETTER_FUNCTION() { let meta = peekMeta(this); diff --git a/packages/ember-metal/lib/property_events.js b/packages/ember-metal/lib/property_events.js index a339d0ba587..d54d3fad22a 100644 --- a/packages/ember-metal/lib/property_events.js +++ b/packages/ember-metal/lib/property_events.js @@ -43,10 +43,7 @@ let deferred = 0; */ function propertyWillChange(obj, keyName, _meta) { let meta = _meta || peekMeta(obj); - - if (meta && !meta.isInitialized(obj)) { - return; - } + if (meta && !meta.isInitialized(obj)) { return; } let watching = meta && meta.peekWatching(keyName) > 0; let possibleDesc = obj[keyName]; @@ -84,9 +81,7 @@ function propertyDidChange(obj, keyName, _meta) { let meta = _meta || peekMeta(obj); let hasMeta = !!meta; - if (hasMeta && !meta.isInitialized(obj)) { - return; - } + if (hasMeta && !meta.isInitialized(obj)) { return; } let possibleDesc = obj[keyName]; let isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; @@ -186,21 +181,21 @@ function iterDeps(method, obj, depKey, seen, meta) { function chainsWillChange(obj, keyName, meta) { let chainWatchers = meta.readableChainWatchers(); - if (chainWatchers) { + if (chainWatchers !== undefined) { chainWatchers.notify(keyName, false, propertyWillChange); } } function chainsDidChange(obj, keyName, meta) { let chainWatchers = meta.readableChainWatchers(); - if (chainWatchers) { + if (chainWatchers !== undefined) { chainWatchers.notify(keyName, true, propertyDidChange); } } function overrideChains(obj, keyName, meta) { let chainWatchers = meta.readableChainWatchers(); - if (chainWatchers) { + if (chainWatchers !== undefined) { chainWatchers.revalidate(keyName); } } @@ -290,7 +285,7 @@ function notifyBeforeObservers(obj, keyName, meta) { let eventName = `${keyName}:before`; let listeners, added; - if (deferred) { + if (deferred > 0) { listeners = beforeObserverSet.add(obj, keyName, eventName); added = accumulateListeners(obj, eventName, listeners, meta); sendEvent(obj, eventName, [obj, keyName], added); @@ -304,7 +299,7 @@ function notifyObservers(obj, keyName, meta) { let eventName = `${keyName}:change`; let listeners; - if (deferred) { + if (deferred > 0) { listeners = observerSet.add(obj, keyName, eventName); accumulateListeners(obj, eventName, listeners, meta); } else { diff --git a/packages/ember-metal/lib/watching.js b/packages/ember-metal/lib/watching.js index d05bdbb9713..2ea610b6f24 100644 --- a/packages/ember-metal/lib/watching.js +++ b/packages/ember-metal/lib/watching.js @@ -31,16 +31,14 @@ import { @param obj @param {String} _keyPath */ -function watch(obj, _keyPath, m) { - if (!isPath(_keyPath)) { - watchKey(obj, _keyPath, m); - } else { +export function watch(obj, _keyPath, m) { + if (isPath(_keyPath)) { watchPath(obj, _keyPath, m); + } else { + watchKey(obj, _keyPath, m); } } -export { watch }; - export function isWatching(obj, key) { if (typeof obj !== 'object' || obj === null) { return false; @@ -55,10 +53,10 @@ export function watcherCount(obj, key) { } export function unwatch(obj, _keyPath, m) { - if (!isPath(_keyPath)) { - unwatchKey(obj, _keyPath, m); - } else { + if (isPath(_keyPath)) { unwatchPath(obj, _keyPath, m); + } else { + unwatchKey(obj, _keyPath, m); } } @@ -72,6 +70,4 @@ export function unwatch(obj, _keyPath, m) { @return {void} @private */ -export function destroy(obj) { - deleteMeta(obj); -} +export { deleteMeta as destroy }; From 6721c736edb2395497d61f3c53eab69868706f42 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 8 Jul 2017 10:00:21 +0500 Subject: [PATCH 146/224] remove unnecessary binding --- packages/ember-metal/lib/observer_set.js | 10 +++--- packages/ember-metal/lib/property_events.js | 34 +++++++++------------ 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/packages/ember-metal/lib/observer_set.js b/packages/ember-metal/lib/observer_set.js index b5f823e20b2..e0ec60579ef 100644 --- a/packages/ember-metal/lib/observer_set.js +++ b/packages/ember-metal/lib/observer_set.js @@ -29,12 +29,12 @@ export default class ObserverSet { let observers = this.observers; let senderGuid = guidFor(sender); let keySet = observerSet[senderGuid]; - let index; - if (!keySet) { + if (keySet === undefined) { observerSet[senderGuid] = keySet = {}; } - index = keySet[keyName]; + + let index = keySet[keyName]; if (index === undefined) { index = observers.push({ sender, @@ -49,9 +49,9 @@ export default class ObserverSet { flush() { let observers = this.observers; - let i, observer, sender; + let observer, sender; this.clear(); - for (i = 0; i < observers.length; ++i) { + for (let i = 0; i < observers.length; ++i) { observer = observers[i]; sender = observer.sender; if (sender.isDestroying || sender.isDestroyed) { continue; } diff --git a/packages/ember-metal/lib/property_events.js b/packages/ember-metal/lib/property_events.js index a339d0ba587..1407896f727 100644 --- a/packages/ember-metal/lib/property_events.js +++ b/packages/ember-metal/lib/property_events.js @@ -15,7 +15,7 @@ import { } from 'ember/features'; import { assertNotRendered } from './transaction'; -export let PROPERTY_DID_CHANGE = symbol('PROPERTY_DID_CHANGE'); +export const PROPERTY_DID_CHANGE = symbol('PROPERTY_DID_CHANGE'); const beforeObserverSet = new ObserverSet(); const observerSet = new ObserverSet(); @@ -97,10 +97,7 @@ function propertyDidChange(obj, keyName, _meta) { } if (hasMeta && meta.peekWatching(keyName) > 0) { - if (meta.hasDeps(keyName) && !meta.isSourceDestroying()) { - dependentKeysDidChange(obj, keyName, meta); - } - + dependentKeysDidChange(obj, keyName, meta); chainsDidChange(obj, keyName, meta); notifyObservers(obj, keyName, meta); } @@ -122,25 +119,24 @@ function propertyDidChange(obj, keyName, _meta) { let WILL_SEEN, DID_SEEN; // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...) function dependentKeysWillChange(obj, depKey, meta) { - if (meta.isSourceDestroying()) { return; } - if (meta.hasDeps(depKey)) { - let seen = WILL_SEEN; - let top = !seen; + if (meta.isSourceDestroying() || !meta.hasDeps(depKey)) { return; } + let seen = WILL_SEEN; + let top = !seen; - if (top) { - seen = WILL_SEEN = {}; - } + if (top) { + seen = WILL_SEEN = {}; + } - iterDeps(propertyWillChange, obj, depKey, seen, meta); + iterDeps(propertyWillChange, obj, depKey, seen, meta); - if (top) { - WILL_SEEN = null; - } + if (top) { + WILL_SEEN = null; } } // called whenever a property has just changed to update dependent keys function dependentKeysDidChange(obj, depKey, meta) { + if (meta.isSourceDestroying() || !meta.hasDeps(depKey)) { return; } let seen = DID_SEEN; let top = !seen; @@ -247,7 +243,7 @@ function changeProperties(callback, binding) { try { callback.call(binding); } finally { - endPropertyChanges.call(binding); + endPropertyChanges(); } } @@ -293,10 +289,8 @@ function notifyBeforeObservers(obj, keyName, meta) { if (deferred) { listeners = beforeObserverSet.add(obj, keyName, eventName); added = accumulateListeners(obj, eventName, listeners, meta); - sendEvent(obj, eventName, [obj, keyName], added); - } else { - sendEvent(obj, eventName, [obj, keyName]); } + sendEvent(obj, eventName, [obj, keyName], added); } function notifyObservers(obj, keyName, meta) { From b18873a34966ca700f5968626f45bdc46f80544a Mon Sep 17 00:00:00 2001 From: Spencer Price Date: Wed, 26 Apr 2017 15:13:09 -0700 Subject: [PATCH 147/224] [BUGFIX] controller replaceRoute in engine --- packages/ember-routing/lib/ext/controller.js | 2 +- .../tests/ext/controller_test.js | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/ember-routing/lib/ext/controller.js b/packages/ember-routing/lib/ext/controller.js index 28187b4d4e0..9f6333bba4d 100644 --- a/packages/ember-routing/lib/ext/controller.js +++ b/packages/ember-routing/lib/ext/controller.js @@ -211,7 +211,7 @@ ControllerMixin.reopen({ // target may be either another controller or a router let target = get(this, 'target'); let method = target.replaceRoute || target.replaceWith; - return method.apply(target, prefixRouteNameArg(target, args)); + return method.apply(target, prefixRouteNameArg(this, args)); } }); diff --git a/packages/ember-routing/tests/ext/controller_test.js b/packages/ember-routing/tests/ext/controller_test.js index 5e47c51cee1..ecde59cea44 100644 --- a/packages/ember-routing/tests/ext/controller_test.js +++ b/packages/ember-routing/tests/ext/controller_test.js @@ -30,3 +30,30 @@ QUnit.test('transitionToRoute considers an engine\'s mountPoint', function() { let queryParams = {}; strictEqual(controller.transitionToRoute(queryParams), queryParams, 'passes query param only transitions through'); }); + +QUnit.test('replaceRoute considers an engine\'s mountPoint', function() { + expect(4); + + let router = { + replaceWith(route) { + return route; + } + }; + + let engineInstance = buildOwner({ + ownerOptions: { + routable: true, + mountPoint: 'foo.bar' + } + }); + + let controller = Controller.create({ target: router }); + setOwner(controller, engineInstance); + + strictEqual(controller.replaceRoute('application'), 'foo.bar.application', 'properly prefixes application route'); + strictEqual(controller.replaceRoute('posts'), 'foo.bar.posts', 'properly prefixes child routes'); + throws(() => controller.replaceRoute('/posts'), 'throws when trying to use a url'); + + let queryParams = {}; + strictEqual(controller.replaceRoute(queryParams), queryParams, 'passes query param only transitions through'); +}); From 4361f995dabbf8e35dad738f418a977275dea6ae Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Thu, 13 Jul 2017 19:29:02 +0200 Subject: [PATCH 148/224] [DOC release] Document the result of `hash` is an empty object. Fixes #14489 --- packages/ember-glimmer/lib/helpers/hash.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/ember-glimmer/lib/helpers/hash.js b/packages/ember-glimmer/lib/helpers/hash.js index aa990084ac9..f2330361d0d 100644 --- a/packages/ember-glimmer/lib/helpers/hash.js +++ b/packages/ember-glimmer/lib/helpers/hash.js @@ -23,6 +23,17 @@ Where the `title` is bound to updates of the `office` property. + Note that the hash is an empty object with no prototype chain, therefore + common methods like `toString` are not available in the resulting hash. + If you need to use such a method, you can use the `call` or `apply` + approach: + + ```js + function toString(obj) { + return Object.prototype.toString.apply(obj); + } + ``` + @method hash @for Ember.Templates.helpers @param {Object} options From 82bfd03c12e466f0aeb5eb8bf5b017f250c9762d Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 13 Jul 2017 18:12:52 -0700 Subject: [PATCH 149/224] [BUGFIX release] [Fixes #15492] WorkAround WebKit/JSC JIT WorkARound MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Affected version: 10.1.1 (12603.2.4) Unaffected version: Safari 11.0, WebKit 12604.1.29 Which suggests the issue has been addressed upstream. --- The following commit https://github.com/emberjs/ember.js/commit/986710f9c57a9ff4520034b600e7fea93b56b955#diff-7e13eecefe753df1d82ce67b32bc4366R566 remove an implicit toBoolean conversion in WeakMap_peekParentMeta which apparently trips up Webkit… Simply reversing the expression addressed the issue. failed: `if (meta === null || meta !== undefined) { … }` passed: `if (meta !== undefined || meta === null) { … }` We also, confirmed that reverting the one line in question to `meta === null || !meta) {` fixed Safari. This PR removes the need for the an unused feature which avoids the expression entirely. @krisselden / @stefanpenner --- packages/ember-metal/lib/meta.js | 19 ++++++------------- packages/ember-runtime/lib/mixins/array.js | 7 ++++--- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index d9ae04f007b..d386c43ec7f 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -515,10 +515,7 @@ if (HAS_NATIVE_WEAKMAP) { if (DEBUG) { counters.peekCalls++; } - // stop if we find a `null` value, since - // that means the meta was deleted - // any other truthy value is a "real" meta - if (meta === null || meta !== undefined) { + if (meta !== undefined) { return meta; } @@ -530,14 +527,10 @@ if (HAS_NATIVE_WEAKMAP) { }; } else { setMeta = function Fallback_setMeta(obj, meta) { - // if `null` already, just set it to the new value - // otherwise define property first - if (obj[META_FIELD] !== null) { - if (obj.__defineNonEnumerable) { - obj.__defineNonEnumerable(EMBER_META_PROPERTY); - } else { - Object.defineProperty(obj, META_FIELD, META_DESC); - } + if (obj.__defineNonEnumerable) { + obj.__defineNonEnumerable(EMBER_META_PROPERTY); + } else { + Object.defineProperty(obj, META_FIELD, META_DESC); } obj[META_FIELD] = meta; @@ -586,7 +579,7 @@ export function meta(obj) { let parent; // remove this code, in-favor of explicit parent - if (maybeMeta !== undefined && maybeMeta !== null) { + if (maybeMeta !== undefined) { if (maybeMeta.source === obj) { return maybeMeta; } diff --git a/packages/ember-runtime/lib/mixins/array.js b/packages/ember-runtime/lib/mixins/array.js index 55f9690041f..1fe9f3ae821 100644 --- a/packages/ember-runtime/lib/mixins/array.js +++ b/packages/ember-runtime/lib/mixins/array.js @@ -8,7 +8,6 @@ // import { symbol } from 'ember-utils'; -import { peekMeta } from 'ember-metal'; import Ember, { // ES6TODO: Ember.A get, computed, @@ -24,7 +23,9 @@ import Ember, { // ES6TODO: Ember.A _addBeforeObserver, _removeBeforeObserver, addObserver, - removeObserver + removeObserver, + meta, + peekMeta } from 'ember-metal'; import { deprecate, assert } from 'ember-debug'; import Enumerable from './enumerable'; @@ -638,7 +639,7 @@ const ArrayMixin = Mixin.create(Enumerable, { function EachProxy(content) { this._content = content; this._keys = undefined; - this.__ember_meta__ = null; + meta(this); } EachProxy.prototype = { From 4a86f6706a73eda4a0378637dfaac7eeda8c74e7 Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 14 Jul 2017 08:13:43 +0500 Subject: [PATCH 150/224] cleanup resolver --- .../ember-application/lib/system/resolver.js | 39 +++++-------------- 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/packages/ember-application/lib/system/resolver.js b/packages/ember-application/lib/system/resolver.js index 9297b580989..c2a985e7b78 100644 --- a/packages/ember-application/lib/system/resolver.js +++ b/packages/ember-application/lib/system/resolver.js @@ -117,11 +117,9 @@ export default EmberObject.extend({ init() { this._parseNameCache = dictionary(null); }, + normalize(fullName) { - let [ - type, - name - ] = fullName.split(':', 2); + let [ type, name ] = fullName.split(':'); assert( 'Tried to normalize a container name without a colon (:) in it. ' + @@ -131,19 +129,8 @@ export default EmberObject.extend({ ); if (type !== 'template') { - let result = name; - - if (result.indexOf('.') > -1) { - result = result.replace(/\.(.)/g, m => m.charAt(1).toUpperCase()); - } - - if (name.indexOf('_') > -1) { - result = result.replace(/_(.)/g, m => m.charAt(1).toUpperCase()); - } - - if (name.indexOf('-') > -1) { - result = result.replace(/-(.)/g, m => m.charAt(1).toUpperCase()); - } + let result = name + .replace(/(\.|_|-)./g, m => m.charAt(1).toUpperCase()); return `${type}:${result}`; } else { @@ -151,7 +138,6 @@ export default EmberObject.extend({ } }, - /** This method is called via the container's resolver method. It parses the provided `fullName` and then looks up and @@ -203,10 +189,7 @@ export default EmberObject.extend({ }, _parseName(fullName) { - let [ - type, - fullNameWithoutType - ] = fullName.split(':'); + let [ type, fullNameWithoutType ] = fullName.split(':'); let name = fullNameWithoutType; let namespace = get(this, 'namespace'); @@ -284,9 +267,10 @@ export default EmberObject.extend({ @protected */ useRouterNaming(parsedName) { - parsedName.name = parsedName.name.replace(/\./g, '_'); if (parsedName.name === 'basic') { parsedName.name = ''; + } else { + parsedName.name = parsedName.name.replace(/\./g, '_'); } }, /** @@ -394,14 +378,9 @@ export default EmberObject.extend({ @private */ _logLookup(found, parsedName) { - let symbol, padding; - - if (found) { - symbol = '[✓]'; - } else { - symbol = '[ ]'; - } + let symbol = found ? '[✓]' : '[ ]'; + let padding; if (parsedName.fullName.length > 60) { padding = '.'; } else { From 7e87ba180638ce6f7f6190c3bf43432314a0987f Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 14 Jul 2017 08:32:33 +0500 Subject: [PATCH 151/224] converted throw error to assertion --- packages/ember-metal/lib/property_set.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index b6edf413e66..d3ad3268053 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -97,23 +97,21 @@ function setPath(root, path, value, tolerant) { let parts = path.split('.'); let keyName = parts.pop(); - if (!keyName || keyName.length === 0) { - throw new EmberError('Property set failed: You passed an empty path'); - } + assert('Property set failed: You passed an empty path', keyName && keyName.length > 0) - path = parts.length > 0 ? parts.join('.') : keyName; + let newPath = parts.length > 0 ? parts.join('.') : keyName; - root = getPath(root, path); + let newRoot = getPath(root, newPath); - if (!root) { + if (!newRoot) { if (tolerant) { return; } else { - throw new EmberError(`Property set failed: object in path "${path}" could not be found or was destroyed.`); + throw new EmberError(`Property set failed: object in path "${newPath}" could not be found or was destroyed.`); } } - return set(root, keyName, value); + return set(newRoot, keyName, value); } /** From b7762ad080e0cf01904116b0b2cec18a503db831 Mon Sep 17 00:00:00 2001 From: bekzod Date: Tue, 4 Jul 2017 19:15:58 +0500 Subject: [PATCH 152/224] cleanup `chains` --- packages/ember-metal/lib/chains.js | 20 +++++++------------- packages/ember-metal/lib/meta.js | 12 ++++++------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/packages/ember-metal/lib/chains.js b/packages/ember-metal/lib/chains.js index 65273bcb789..af030854b47 100644 --- a/packages/ember-metal/lib/chains.js +++ b/packages/ember-metal/lib/chains.js @@ -185,16 +185,12 @@ class ChainNode { copy(obj) { let ret = new ChainNode(null, null, obj); let paths = this._paths; - let path; if (paths !== undefined) { + let path; for (path in paths) { - // this check will also catch non-number vals. - if (paths[path] <= 0) { - continue; - } - ret.add(path); + if (paths[path] > 0) { ret.add(path); } } - } + } return ret; } @@ -281,13 +277,13 @@ class ChainNode { this._object = undefined; } } - this._value = undefined; + this._value = undefined; } // then notify chains... let chains = this._chains; - let node; if (chains !== undefined) { + let node; for (let key in chains) { node = chains[key]; if (node !== undefined) { @@ -308,10 +304,8 @@ class ChainNode { if (this._parent) { this._parent.populateAffected(path, depth + 1, affected); - } else { - if (depth > 1) { - affected.push(this.value(), path); - } + } else if (depth > 1) { + affected.push(this.value(), path); } } } diff --git a/packages/ember-metal/lib/meta.js b/packages/ember-metal/lib/meta.js index 6c4d50fbbff..2e9e8833f8f 100644 --- a/packages/ember-metal/lib/meta.js +++ b/packages/ember-metal/lib/meta.js @@ -103,14 +103,14 @@ export class Meta { // remove chainWatchers to remove circular references that would prevent GC let nodes, key, nodeObject; let node = this.readableChains(); - if (node) { + if (node !== undefined) { NODE_STACK.push(node); // process tree while (NODE_STACK.length > 0) { node = NODE_STACK.pop(); // push children nodes = node._chains; - if (nodes) { + if (nodes !== undefined) { for (key in nodes) { if (nodes[key] !== undefined) { NODE_STACK.push(nodes[key]); @@ -121,7 +121,7 @@ export class Meta { // remove chainWatcher in node object if (node._watching) { nodeObject = node._object; - if (nodeObject) { + if (nodeObject !== undefined) { let foreignMeta = peekMeta(nodeObject); // avoid cleaning up chain watchers when both current and // foreign objects are being destroyed @@ -322,10 +322,10 @@ export class Meta { assert(`Cannot create a new chains for \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed()); let ret = this._chains; if (ret === undefined) { - if (this.parent) { - ret = this.parent.writableChains(create).copy(this.source); - } else { + if (this.parent === undefined) { ret = create(this.source); + } else { + ret = this.parent.writableChains(create).copy(this.source); } this._chains = ret; } From 4771b609bdceb47e6add5d2a6a7174a16f025272 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 16 Jul 2017 15:59:50 +0500 Subject: [PATCH 153/224] [BUGFIX beta] rsvp classCallCheck issue fix --- ember-cli-build.js | 2 +- yarn.lock | 1574 ++++++++++++++++++++++++-------------------- 2 files changed, 865 insertions(+), 711 deletions(-) diff --git a/ember-cli-build.js b/ember-cli-build.js index deb13c71997..5267b0df4e3 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -229,6 +229,7 @@ module.exports = function(options) { glimmerUtil, glimmerWireFormat, backburner, + rsvp ].map(stripForProd); let emberProdTestES5 = emberTests.map((tree) => { @@ -251,7 +252,6 @@ module.exports = function(options) { ...emberProdES5, ...depsProd, emberMetalProd, - rsvp, productionFeatures, babelProdHelpersES5, version, diff --git a/yarn.lock b/yarn.lock index 20d866f4a7c..d8153ba485b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -66,8 +66,8 @@ simple-html-tokenizer "^0.3.0" "@glimmer/util@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.25.1.tgz#bdc669de4cae562eb797fb29714da4d290ec58c1" + version "0.25.2" + resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.25.2.tgz#a79e7100f7c38181be026dddf2d3b4ce8a8c8421" "@glimmer/wire-format@^0.25.1": version "0.25.1" @@ -75,7 +75,11 @@ dependencies: "@glimmer/util" "^0.25.1" -abbrev@1, abbrev@~1.0.9: +abbrev@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + +abbrev@~1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" @@ -92,14 +96,18 @@ acorn-jsx@^3.0.0: dependencies: acorn "^3.0.4" -acorn@4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" - -acorn@^3.0.4, acorn@^3.1.0: +acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" +acorn@^4.0.3: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + +acorn@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.1.tgz#53fe161111f912ab999ee887a90a0bc52822fd75" + adm-zip@~0.4.3: version "0.4.7" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" @@ -109,8 +117,8 @@ after@0.8.1: resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" agent-base@2: - version "2.0.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.0.1.tgz#bd8f9e86a8eb221fffa07bd14befd55df142815e" + version "2.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" dependencies: extend "~3.0.0" semver "~5.0.1" @@ -119,9 +127,9 @@ ajv-keywords@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" -ajv@^4.7.0: - version "4.11.5" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd" +ajv@^4.7.0, ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" @@ -154,6 +162,10 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" +ansi-regex@*, ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" @@ -162,9 +174,9 @@ ansi-regex@^1.0.0, ansi-regex@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-1.1.1.tgz#41c847194646375e6a1a5d10c3ca054ef9fc980d" -ansi-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" ansi-styles@^1.1.0: version "1.1.0" @@ -193,6 +205,12 @@ anymatch@^1.3.0: arrify "^1.0.0" micromatch "^2.1.5" +aot-test-generators@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/aot-test-generators/-/aot-test-generators-0.1.0.tgz#43f0f615f97cb298d7919c1b0b4e6b7310b03cd0" + dependencies: + jsesc "^2.5.0" + aproba@^1.0.3, aproba@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" @@ -208,9 +226,9 @@ archiver-utils@^1.3.0: normalize-path "^2.0.0" readable-stream "^2.0.0" -archiver@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/archiver/-/archiver-1.1.0.tgz#e1e8c4d356cf155308f351d60cc18cb6fb2344ee" +archiver@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-1.3.0.tgz#4f2194d6d8f99df3f531e6881f14f15d55faaf22" dependencies: archiver-utils "^1.3.0" async "^2.0.0" @@ -219,6 +237,7 @@ archiver@1.1.0: lodash "^4.8.0" readable-stream "^2.0.0" tar-stream "^1.5.0" + walkdir "^0.0.11" zip-stream "^1.1.0" archy@~1.0.0: @@ -226,11 +245,11 @@ archy@~1.0.0: resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" are-we-there-yet@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" dependencies: delegates "^1.0.0" - readable-stream "^2.0.0 || ^1.1.13" + readable-stream "^2.0.6" argparse@^1.0.7, argparse@~1.0.2: version "1.0.9" @@ -245,8 +264,8 @@ arr-diff@^2.0.0: arr-flatten "^1.0.1" arr-flatten@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" array-equal@^1.0.0: version "1.0.0" @@ -296,8 +315,8 @@ arrify@^1.0.0: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" asap@^2.0.0, asap@~2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" asn1@0.1.11: version "0.1.11" @@ -307,6 +326,10 @@ asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + assert-plus@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" @@ -315,10 +338,6 @@ assert-plus@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" -assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - assertion-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" @@ -331,19 +350,35 @@ ast-types@0.8.12: version "0.8.12" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" -ast-types@0.9.2: - version "0.9.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.2.tgz#2cc19979d15c655108bf565323b8e7ee38751f6b" +ast-types@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" -async-disk-cache@^1.0.0: - version "1.0.9" - resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.0.9.tgz#23bafb823184f463407e474e8d5f87899f72ca63" +ast-types@0.9.11: + version "0.9.11" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.11.tgz#371177bb59232ff5ceaa1d09ee5cad705b1a5aa9" + +ast-types@0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + +async-disk-cache@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.3.2.tgz#ac53d6152843df202c9406e28d774362608d74dd" dependencies: debug "^2.1.3" + heimdalljs "^0.2.3" istextorbinary "2.1.0" mkdirp "^0.5.0" rimraf "^2.5.3" rsvp "^3.0.18" + username-sync "1.0.1" + +async-promise-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.3.tgz#70c9c37635620f894978814b6c65e6e14e2573ee" + dependencies: + async "^2.4.1" async@2.0.1: version "2.0.1" @@ -355,9 +390,9 @@ async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.0.0, async@^2.0.1, async@^2.1.2: - version "2.1.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.4.tgz#2d2160c7788032e4dd6cbe2502f1f9a2c8f6cde4" +async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.4.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" dependencies: lodash "^4.14.0" @@ -374,11 +409,12 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" aws-sdk@^2.0.9, aws-sdk@^2.46.0: - version "2.46.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.46.0.tgz#6856d5669d8b00a4cd42091beebf12be7d8ef48e" + version "2.85.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.85.0.tgz#e3860761c9a2f8a9017461ab7f3bd075f69dfa8f" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" + events "^1.1.1" jmespath "0.15.0" querystring "0.2.0" sax "1.2.1" @@ -396,8 +432,8 @@ aws-sign2@~0.6.0: resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" aws4@^1.2.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: version "6.22.0" @@ -458,20 +494,20 @@ babel-core@^5.0.0: trim-right "^1.0.0" try-resolve "^1.0.0" -babel-core@^6.14.0, babel-core@^6.24.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02" +babel-core@^6.14.0, babel-core@^6.24.1: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.25.0.tgz#7dd42b0463c742e9d5296deb3ec67a9322dad729" dependencies: babel-code-frame "^6.22.0" - babel-generator "^6.24.0" - babel-helpers "^6.23.0" + babel-generator "^6.25.0" + babel-helpers "^6.24.1" babel-messages "^6.23.0" - babel-register "^6.24.0" + babel-register "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.1" - babel-types "^6.23.0" - babylon "^6.11.0" + babel-template "^6.25.0" + babel-traverse "^6.25.0" + babel-types "^6.25.0" + babylon "^6.17.2" convert-source-map "^1.1.0" debug "^2.1.1" json5 "^0.5.0" @@ -482,13 +518,13 @@ babel-core@^6.14.0, babel-core@^6.24.0: slash "^1.0.0" source-map "^0.5.0" -babel-generator@^6.24.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56" +babel-generator@^6.25.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.25.0.tgz#33a1af70d5f2890aeb465a4a7793c1df6a9ea9fc" dependencies: babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-types "^6.23.0" + babel-types "^6.25.0" detect-indent "^4.0.0" jsesc "^1.3.0" lodash "^4.2.0" @@ -537,9 +573,9 @@ babel-helper-hoist-variables@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-helper-mark-eval-scopes@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.0.3.tgz#902f75aeb537336edc35eb9f52b6f09db7785328" +babel-helper-mark-eval-scopes@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.1.1.tgz#4554345edf9f2549427bd2098e530253f8af2992" babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" @@ -548,9 +584,9 @@ babel-helper-optimise-call-expression@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-helper-remove-or-void@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.0.1.tgz#f602790e465acf2dfbe84fb3dd210c43a2dd7262" +babel-helper-remove-or-void@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.1.1.tgz#9d7e1856dc6fafcb41b283a416730dc1844f66d7" babel-helper-replace-supers@^6.24.1: version "6.24.1" @@ -563,12 +599,12 @@ babel-helper-replace-supers@^6.24.1: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-helpers@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992" +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" dependencies: babel-runtime "^6.22.0" - babel-template "^6.23.0" + babel-template "^6.24.1" babel-messages@^6.23.0: version "6.23.0" @@ -591,8 +627,8 @@ babel-plugin-dead-code-elimination@^1.0.2: resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" babel-plugin-debug-macros@^0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.10.tgz#dd077ad6e1cc0a8f9bbc6405c561392ebfc9a01c" + version "0.1.11" + resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" dependencies: semver "^5.3.0" @@ -621,11 +657,11 @@ babel-plugin-member-expression-literals@^1.0.1: resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" babel-plugin-minify-dead-code-elimination@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.1.4.tgz#18b6ecfab77c29caca061d8210fa3495001e4fa1" + version "0.1.7" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.1.7.tgz#774f536f347b98393a27baa717872968813c342c" dependencies: - babel-helper-mark-eval-scopes "^0.0.3" - babel-helper-remove-or-void "^0.0.1" + babel-helper-mark-eval-scopes "^0.1.1" + babel-helper-remove-or-void "^0.1.1" lodash.some "^4.6.0" babel-plugin-property-literals@^1.0.1: @@ -772,11 +808,11 @@ babel-plugin-undefined-to-void@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" -babel-register@^6.24.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd" +babel-register@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f" dependencies: - babel-core "^6.24.0" + babel-core "^6.24.1" babel-runtime "^6.22.0" core-js "^2.4.0" home-or-tmp "^2.0.0" @@ -791,33 +827,33 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-template@^6.23.0, babel-template@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" +babel-template@^6.24.1, babel-template@^6.25.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.25.0.tgz#665241166b7c2aa4c619d71e192969552b10c071" dependencies: babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babylon "^6.11.0" + babel-traverse "^6.25.0" + babel-types "^6.25.0" + babylon "^6.17.2" lodash "^4.2.0" -babel-traverse@^6.23.1, babel-traverse@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" +babel-traverse@^6.24.1, babel-traverse@^6.25.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.25.0.tgz#2257497e2fcd19b89edc13c4c91381f9512496f1" dependencies: babel-code-frame "^6.22.0" babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-types "^6.24.1" - babylon "^6.15.0" + babel-types "^6.25.0" + babylon "^6.17.2" debug "^2.2.0" globals "^9.0.0" invariant "^2.2.0" lodash "^4.2.0" -babel-types@^6.23.0, babel-types@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" +babel-types@^6.24.1, babel-types@^6.25.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.25.0.tgz#70afb248d5660e5d18f811d91c8303b54134a18e" dependencies: babel-runtime "^6.22.0" esutils "^2.0.2" @@ -828,9 +864,9 @@ babylon@^5.8.38: version "5.8.38" resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" -babylon@^6.11.0, babylon@^6.15.0: - version "6.16.1" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3" +babylon@^6.17.2: + version "6.17.4" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.4.tgz#3e8b7402b88d22c3423e137a1577883b15ff869a" backbone@^1.1.2: version "1.3.3" @@ -846,29 +882,29 @@ backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" -balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" base64-arraybuffer@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + version "1.2.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" base64id@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" -basic-auth@~1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.0.4.tgz#030935b01de7c9b94a824b29f3fccb750d3a5290" +basic-auth@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" bcrypt-pbkdf@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" dependencies: tweetnacl "^0.14.3" @@ -907,8 +943,8 @@ bluebird@^2.9.33: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" bluebird@^3.1.1, bluebird@^3.4.6: - version "3.4.7" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + version "3.5.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" body@^5.1.0: version "5.1.0" @@ -949,11 +985,11 @@ bower@^1.3.12: version "1.8.0" resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" -brace-expansion@^1.0.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" +brace-expansion@^1.0.0, brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" dependencies: - balanced-match "^0.4.1" + balanced-match "^1.0.0" concat-map "0.0.1" braces@^1.8.2: @@ -968,29 +1004,35 @@ breakable@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" -broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.6.0: - version "5.6.1" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.1.tgz#97184dcb140b40aa57f3ff38330afccc675d0a3c" +broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.6.2: + version "5.7.1" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.1.tgz#e10d831faed1c57e37272e4223748ba71a7926d1" dependencies: babel-core "^5.0.0" broccoli-funnel "^1.0.0" broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.0.1" + broccoli-persistent-filter "^1.4.2" clone "^0.2.0" hash-for-dep "^1.0.2" + heimdalljs-logger "^0.1.7" json-stable-stringify "^1.0.0" + rsvp "^3.5.0" + workerpool "^2.2.1" broccoli-babel-transpiler@next: - version "6.0.0" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0.tgz#a52c5404bf36236849da503b011fd41fe64a00a2" + version "6.1.1" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.1.1.tgz#938f470e1ddb47047a77ef5e38f34c21de0e85a8" dependencies: babel-core "^6.14.0" broccoli-funnel "^1.0.0" broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.0.1" + broccoli-persistent-filter "^1.4.0" clone "^2.0.0" hash-for-dep "^1.0.2" + heimdalljs-logger "^0.1.7" json-stable-stringify "^1.0.0" + rsvp "^3.5.0" + workerpool "^2.2.1" broccoli-brocfile-loader@^0.18.0: version "0.18.0" @@ -999,8 +1041,8 @@ broccoli-brocfile-loader@^0.18.0: findup-sync "^0.4.2" broccoli-builder@^0.18.0: - version "0.18.3" - resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.3.tgz#9d2c90558e7f4d1118ae6e938c63b35da00dd38f" + version "0.18.8" + resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.8.tgz#fe54694d544c3cdfdb01028e802eeca65749a879" dependencies: heimdalljs "^0.2.0" promise-map-series "^0.2.1" @@ -1009,7 +1051,18 @@ broccoli-builder@^0.18.0: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.4: +broccoli-caching-writer@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.2.1" + debug "^2.1.1" + rimraf "^2.2.8" + rsvp "^3.0.17" + walk-sync "^0.3.0" + +broccoli-caching-writer@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: @@ -1049,10 +1102,10 @@ broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: walk-sync "^0.3.1" broccoli-config-loader@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" + version "1.0.1" + resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" dependencies: - broccoli-caching-writer "^2.0.4" + broccoli-caching-writer "^3.0.3" broccoli-config-replace@^1.1.2: version "1.1.2" @@ -1063,6 +1116,18 @@ broccoli-config-replace@^1.1.2: debug "^2.2.0" fs-extra "^0.24.0" +broccoli-debug@^0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.2.tgz#4c6e89459fc3de7d5d4fc7b77e57f46019f44db1" + dependencies: + broccoli-plugin "^1.2.1" + fs-tree-diff "^0.5.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + minimatch "^3.0.3" + symlink-or-copy "^1.1.8" + tree-sync "^1.2.2" + broccoli-file-creator@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" @@ -1125,19 +1190,20 @@ broccoli-kitchen-sink-helpers@^0.3.1: mkdirp "^0.5.1" broccoli-lint-eslint@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-3.2.1.tgz#6c88cd36f2999eab98b07538a382ef2c10d2b77f" + version "3.3.1" + resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-3.3.1.tgz#35c675546a5a7ad8f3319edd732e3aad8ca241de" dependencies: + aot-test-generators "^0.1.0" + broccoli-concat "^3.2.2" broccoli-persistent-filter "^1.2.0" - escape-string-regexp "^1.0.5" eslint "^3.0.0" - js-string-escape "^1.0.1" json-stable-stringify "^1.0.1" + lodash.defaultsdeep "^4.6.0" md5-hex "^2.0.0" broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1, broccoli-merge-trees@^1.1.3: - version "1.2.1" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.1.tgz#16a7494ed56dbe61611f6c2d4817cfbaad2a3055" + version "1.2.4" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -1162,20 +1228,21 @@ broccoli-middleware@^0.18.1: handlebars "^4.0.4" mime "^1.2.11" -broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0: - version "1.2.11" - resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.11.tgz#95cc6b0b0eb0dcce5f8e6ae18f6a3cc45a06bf40" +broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.2.tgz#17af1278a25ff2556f9d7d23e115accfad3a7ce7" dependencies: - async-disk-cache "^1.0.0" - blank-object "^1.0.1" + async-disk-cache "^1.2.1" + async-promise-queue "^1.0.3" broccoli-plugin "^1.0.0" + crypto "0.0.3" fs-tree-diff "^0.5.2" hash-for-dep "^1.0.2" heimdalljs "^0.2.1" heimdalljs-logger "^0.1.7" - md5-hex "^1.0.2" mkdirp "^0.5.1" promise-map-series "^0.2.1" + rimraf "^2.6.1" rsvp "^3.0.18" symlink-or-copy "^1.0.1" walk-sync "^0.3.1" @@ -1199,8 +1266,8 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli symlink-or-copy "^1.1.8" broccoli-rollup@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/broccoli-rollup/-/broccoli-rollup-1.2.0.tgz#627636c05837d894a85724ef9b7ca04d12b66751" + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-rollup/-/broccoli-rollup-1.3.0.tgz#43a0a7798555bab54217009eb470a4ff5a056df0" dependencies: broccoli-plugin "^1.2.1" es6-map "^0.1.4" @@ -1225,19 +1292,22 @@ broccoli-source@^1.1.0: resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.4.0.tgz#1bdb0a1804d62a419d190abc26acb3c91878154d" + version "1.5.0" + resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c" dependencies: + broccoli-debug "^0.6.1" broccoli-funnel "^1.0.1" broccoli-merge-trees "^1.0.0" broccoli-persistent-filter "^1.1.6" + broccoli-plugin "^1.3.0" chalk "^1.1.3" - debug "^2.1.0" + debug "^2.4.0" ensure-posix-path "^1.0.1" - fs-extra "^0.30.0" + fs-extra "^2.0.0" minimatch "^3.0.2" resolve "^1.1.6" rsvp "^3.0.16" + symlink-or-copy "^1.1.8" walk-sync "^0.3.0" broccoli-string-replace@^0.1.2: @@ -1275,9 +1345,9 @@ broccoli-writer@^0.1.1, broccoli-writer@~0.1.1: quick-temp "^0.1.0" rsvp "^3.0.6" -bser@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" +bser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" dependencies: node-int64 "^0.4.0" @@ -1305,13 +1375,17 @@ builtins@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + bytes@1: version "1.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" -bytes@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" +bytes@2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.5.0.tgz#4c9423ea2d252c270c41b2bdefeff9bb6b62c06a" caller-path@^0.1.0: version "0.1.0" @@ -1338,8 +1412,8 @@ can-symlink@^1.0.0: tmp "0.0.28" capture-exit@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.1.0.tgz#d931b32b11c2bd20ae57f34af0c1eb2c18781626" + version "1.2.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: rsvp "^3.3.3" @@ -1354,6 +1428,10 @@ caseless@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" @@ -1446,8 +1524,8 @@ clean-css-promise@^0.1.0: pinkie-promise "^2.0.0" clean-css@^3.4.5: - version "3.4.23" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.23.tgz#604fbbca24c12feb59b02f00b84f1fb7ded6d001" + version "3.4.28" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" dependencies: commander "2.8.x" source-map "0.4.x" @@ -1498,8 +1576,8 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" clone@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.0.tgz#9c715bfbd39aa197c8ee0f8e65c3912ba34f8cd6" + version "2.1.1" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" cmd-shim@~2.0.2: version "2.0.2" @@ -1568,10 +1646,8 @@ commander@2.8.x: graceful-readlink ">= 1.0.0" commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" commander@~2.1.0: version "2.1.0" @@ -1613,31 +1689,32 @@ component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" -compress-commons@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.1.0.tgz#9f4460bb1288564c7473916e0298aa3c320dcadb" +compress-commons@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.0.tgz#58587092ef20d37cb58baf000112c9278ff73b9f" dependencies: buffer-crc32 "^0.2.1" - crc32-stream "^1.0.0" + crc32-stream "^2.0.0" normalize-path "^2.0.0" readable-stream "^2.0.0" -compressible@~2.0.8: - version "2.0.9" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" +compressible@~2.0.10: + version "2.0.10" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd" dependencies: - mime-db ">= 1.24.0 < 2" + mime-db ">= 1.27.0 < 2" compression@^1.4.4: - version "1.6.2" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + version "1.7.0" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.0.tgz#030c9f198f1643a057d776a738e922da4373012d" dependencies: accepts "~1.3.3" - bytes "2.3.0" - compressible "~2.0.8" - debug "~2.2.0" + bytes "2.5.0" + compressible "~2.0.10" + debug "2.6.8" on-headers "~1.0.1" - vary "~1.1.0" + safe-buffer "5.1.1" + vary "~1.1.1" concat-map@0.0.1: version "0.0.1" @@ -1695,8 +1772,8 @@ continuable-cache@^0.3.1: resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" convert-source-map@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + version "1.5.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" cookie-signature@1.0.6: version "1.0.6" @@ -1710,7 +1787,7 @@ core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" -core-js@^2.4.0: +core-js@^2.4.0, core-js@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" @@ -1719,8 +1796,8 @@ core-object@^1.1.0: resolved "https://registry.yarnpkg.com/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" core-object@^2.0.2: - version "2.0.6" - resolved "https://registry.yarnpkg.com/core-object/-/core-object-2.0.6.tgz#60134b9c40ff69b27bc15e82db945e4df782961b" + version "2.1.1" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-2.1.1.tgz#4b7a5f1edefcb1e6d0dcb58eab1b9f90bfc666a8" dependencies: chalk "^1.1.3" @@ -1728,13 +1805,17 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -crc32-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-1.0.0.tgz#ea155e5e1d738ed3778438ffe92ffe2a141aeb3f" +crc32-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4" dependencies: - buffer-crc32 "^0.2.1" + crc "^3.4.4" readable-stream "^2.0.0" +crc@^3.4.4: + version "3.4.4" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b" + cross-spawn@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -1759,6 +1840,10 @@ crypto-browserify@1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" +crypto@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/crypto/-/crypto-0.0.3.tgz#470a81b86be4c5ee17acc8207a1f5315ae20dbb0" + ctype@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" @@ -1769,12 +1854,6 @@ d@1: dependencies: es5-ext "^0.10.9" -d@^0.1.1, d@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" - dependencies: - es5-ext "~0.10.2" - dag-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" @@ -1785,13 +1864,13 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@2, debug@2.6.4, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3: - version "2.6.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" +debug@2, debug@2.6.8, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0, debug@~2.6.7: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: - ms "0.7.3" + ms "2.0.0" -debug@2.2.0, debug@~2.2.0: +debug@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: @@ -1803,19 +1882,13 @@ debug@2.3.3: dependencies: ms "0.7.2" -debug@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" - dependencies: - ms "0.7.2" - -debug@^2.2.0: - version "2.5.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.5.2.tgz#50c295a53dbf1657146e0c1b21307275e90d49cb" +debug@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e" dependencies: - ms "0.7.2" + ms "2.0.0" -debuglog@^1.0.1: +debuglog@*, debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -1911,10 +1984,10 @@ detect-indent@^4.0.0: repeating "^2.0.0" detective@^4.3.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.3.2.tgz#77697e2e7947ac3fe7c8e26a6d6f115235afa91c" + version "4.5.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" dependencies: - acorn "^3.1.0" + acorn "^4.0.3" defined "^1.0.0" dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@~1.0.3: @@ -1963,11 +2036,11 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.3: - version "5.2.1" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.1.tgz#14a1a7b3ae9e9f1284f7bcdb142eb53bd0b1b5bd" +ember-cli-babel@^5.0.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" dependencies: - broccoli-babel-transpiler "^5.6.0" + broccoli-babel-transpiler "^5.6.2" broccoli-funnel "^1.0.0" clone "^2.0.0" ember-cli-version-checker "^1.0.2" @@ -2039,8 +2112,8 @@ ember-cli-is-package-missing@^1.0.0: resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" ember-cli-legacy-blueprints@^0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" + version "0.1.5" + resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.5.tgz#93c15ca242ec5107d62a8af7ec30f6ac538f3ad9" dependencies: chalk "^1.1.1" ember-cli-get-component-path-option "^1.0.0" @@ -2061,8 +2134,8 @@ ember-cli-legacy-blueprints@^0.1.2: silent-error "^1.0.0" ember-cli-lodash-subset@^1.0.11, ember-cli-lodash-subset@^1.0.7: - version "1.0.11" - resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.11.tgz#0149eef9c0c3505ba44ed202f8d034ddbbfb2826" + version "1.0.12" + resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" @@ -2075,25 +2148,25 @@ ember-cli-path-utils@^1.0.0: resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" ember-cli-preprocess-registry@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.0.0.tgz#5a7e6a4048a895856c8a54ed145cf92153b2ab96" + version "3.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" dependencies: broccoli-clean-css "^1.1.0" broccoli-funnel "^1.0.0" broccoli-merge-trees "^1.0.0" debug "^2.2.0" + ember-cli-lodash-subset "^1.0.7" exists-sync "0.0.3" - lodash "^4.5.0" process-relative-require "^1.0.0" silent-error "^1.0.0" -ember-cli-sauce@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-sauce/-/ember-cli-sauce-2.0.0.tgz#35efa76597732dd8e273815d1fe78a45c3d4cd3c" +ember-cli-sauce@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-sauce/-/ember-cli-sauce-2.1.0.tgz#ecafc2bc7c2cd63fd7b98fb2296fa96809907b79" dependencies: - recast "^0.11.17" - rsvp "^3.1.0" - saucie "^3.0.0" + recast "^0.12.0" + rsvp "^3.6.1" + saucie "^3.2.0" ember-cli-string-utils@^1.0.0, ember-cli-string-utils@^1.1.0: version "1.1.0" @@ -2225,8 +2298,8 @@ ember-publisher@0.0.7: aws-sdk "^2.0.9" ember-router-generator@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.2.tgz#62dac1f63e873553e6d4c7e32da6589e577bcf63" + version "1.2.3" + resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: recast "^0.11.3" @@ -2240,14 +2313,13 @@ ember-try-config@^2.0.1: semver "^5.1.0" ember-try@^0.2.6: - version "0.2.8" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.8.tgz#5f135d23d83561dc8dfb4a4d998420b69b740acd" + version "0.2.15" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.15.tgz#559c756058717595babe70068e541625bd5e210a" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" core-object "^1.1.0" debug "^2.2.0" - ember-cli-babel "^5.1.3" ember-cli-version-checker "^1.1.6" ember-try-config "^2.0.1" extend "^3.0.0" @@ -2257,7 +2329,6 @@ ember-try@^0.2.6: rimraf "^2.3.2" rsvp "^3.0.17" semver "^5.1.0" - sync-exec "^0.6.2" encodeurl@~1.0.1: version "1.0.1" @@ -2270,10 +2341,10 @@ encoding@^0.1.11: iconv-lite "~0.4.13" end-of-stream@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.1.0.tgz#e9353258baa9108965efc41cb0ef8ade2f3cfb07" + version "1.4.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" dependencies: - once "~1.3.0" + once "^1.4.0" engine.io-client@1.8.0: version "1.8.0" @@ -2330,28 +2401,13 @@ error@^7.0.0: xtend "~4.0.0" es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.14" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.14.tgz#625bc9ab9cac0f6fb9dc271525823d1800b3d360" - dependencies: - es6-iterator "2" - es6-symbol "~3.1" - -es5-ext@^0.10.7, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: - version "0.10.12" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + version "0.10.24" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.24.tgz#a55877c9924bc0c8d9bd3c2cbe17495ac1709b14" dependencies: es6-iterator "2" es6-symbol "~3.1" -es6-iterator@2: - version "2.0.0" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" - dependencies: - d "^0.1.1" - es5-ext "^0.10.7" - es6-symbol "3" - -es6-iterator@^2.0.1: +es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" dependencies: @@ -2360,34 +2416,27 @@ es6-iterator@^2.0.1: es6-symbol "^3.1" es6-map@^0.1.3, es6-map@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" - dependencies: - d "~0.1.1" - es5-ext "~0.10.11" - es6-iterator "2" - es6-set "~0.1.3" - es6-symbol "~3.1.0" - event-emitter "~0.3.4" - -es6-set@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" dependencies: - d "~0.1.1" - es5-ext "~0.10.11" - es6-iterator "2" - es6-symbol "3" - event-emitter "~0.3.4" + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" -es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" +es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" dependencies: - d "~0.1.1" - es5-ext "~0.10.11" + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" -es6-symbol@^3.0.2, es6-symbol@^3.1, es6-symbol@^3.1.1: +es6-symbol@3.1.1, es6-symbol@^3.0.2, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: @@ -2432,8 +2481,8 @@ eslint-plugin-ember-internal@^1.1.0: requireindex "~1.1.0" eslint@^3.0.0: - version "3.18.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.18.0.tgz#647e985c4ae71502d20ac62c109f66d5104c8a4b" + version "3.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" dependencies: babel-code-frame "^6.16.0" chalk "^1.1.3" @@ -2472,10 +2521,10 @@ eslint@^3.0.0: user-home "^2.0.0" espree@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" + version "3.4.3" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" dependencies: - acorn "4.0.4" + acorn "^5.0.1" acorn-jsx "^3.0.0" esprima-fb@~12001.1.0-dev-harmony-fb: @@ -2490,6 +2539,10 @@ esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" +esprima@^4.0.0, esprima@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + esprima@~3.1.0: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" @@ -2501,20 +2554,16 @@ esquery@^1.0.0: estraverse "^4.0.0" esrecurse@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + version "4.2.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" dependencies: - estraverse "~4.1.0" + estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.0.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" -estraverse@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" - esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -2523,20 +2572,24 @@ etag@~1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" -event-emitter@~0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" +event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" dependencies: - d "~0.1.1" - es5-ext "~0.10.7" + d "1" + es5-ext "~0.10.14" eventemitter3@1.x.x: version "1.2.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" events-to-array@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" + version "1.1.2" + resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" + +events@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" exec-sh@^0.2.0: version "0.2.0" @@ -2579,8 +2632,8 @@ expand-tilde@^1.2.2: os-homedir "^1.0.1" express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.15.2: - version "4.15.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" + version "4.15.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662" dependencies: accepts "~1.3.3" array-flatten "1.1.1" @@ -2588,32 +2641,32 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.15.2: content-type "~1.0.2" cookie "0.3.1" cookie-signature "1.0.6" - debug "2.6.1" + debug "2.6.7" depd "~1.1.0" encodeurl "~1.0.1" escape-html "~1.0.3" etag "~1.8.0" - finalhandler "~1.0.0" + finalhandler "~1.0.3" fresh "0.5.0" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.1" path-to-regexp "0.1.7" - proxy-addr "~1.1.3" + proxy-addr "~1.1.4" qs "6.4.0" range-parser "~1.2.0" - send "0.15.1" - serve-static "1.12.1" + send "0.15.3" + serve-static "1.12.3" setprototypeof "1.0.3" statuses "~1.3.1" - type-is "~1.6.14" + type-is "~1.6.15" utils-merge "1.0.0" - vary "~1.1.0" + vary "~1.1.1" extend@3, extend@^3.0.0, extend@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" external-editor@^1.1.0: version "1.1.1" @@ -2662,11 +2715,11 @@ faye-websocket@~0.10.0: dependencies: websocket-driver ">=0.5.1" -fb-watchman@^1.8.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.0.tgz#6f268f1f347a6b3c875d1e89da7e1ed79adfc0ec" +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" dependencies: - bser "^1.0.2" + bser "^2.0.0" figures@^1.3.5: version "1.7.0" @@ -2683,12 +2736,12 @@ file-entry-cache@^2.0.0: object-assign "^4.0.1" filename-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" filesize@^3.1.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.3.0.tgz#53149ea3460e3b2e024962a51648aa572cf98122" + version "3.5.10" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f" fill-range@^2.1.0: version "2.2.3" @@ -2700,11 +2753,11 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@^1.0.2, finalhandler@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a" +finalhandler@^1.0.2, finalhandler@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89" dependencies: - debug "2.6.4" + debug "2.6.7" encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" @@ -2758,15 +2811,15 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" -for-in@^0.1.5: - version "0.1.6" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" for-own@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" dependencies: - for-in "^0.1.5" + for-in "^1.0.1" forever-agent@~0.5.0: version "0.5.2" @@ -2792,13 +2845,13 @@ form-data@~1.0.0-rc4: combined-stream "^1.0.5" mime-types "^2.1.11" -form-data@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" dependencies: asynckit "^0.4.0" combined-stream "^1.0.5" - mime-types "^2.1.11" + mime-types "^2.1.12" forwarded@~0.1.0: version "0.1.0" @@ -2849,19 +2902,26 @@ fs-extra@^1.0.0: jsonfile "^2.1.0" klaw "^1.0.0" +fs-extra@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + fs-readdir-recursive@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" -fs-sync@^0.2.4: - version "0.2.6" - resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-0.2.6.tgz#657116c12b95ac9a36c51a850066c9ee6441fe06" +fs-sync@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" dependencies: - glob "~4.0.4" - iconv-lite "~0.2.10" - lodash "~1.2.1" - mkdirp "~0.3.5" - rimraf "~2.1.4" + glob "^7.1.0" + iconv-lite "^0.4.13" + lodash "^4.16.1" + mkdirp "^0.5.1" + rimraf "^2.1.4" fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: version "0.5.6" @@ -2873,16 +2933,16 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 symlink-or-copy "^1.1.8" fs-vacuum@~1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.9.tgz#4f90193ab8ea02890995bcd4e804659a5d366b2d" + version "1.2.10" + resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" dependencies: graceful-fs "^4.1.2" path-is-inside "^1.0.1" rimraf "^2.5.2" fs-write-stream-atomic@~1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.8.tgz#e49aaddf288f87d46ff9e882f216a13abc40778b" + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" dependencies: graceful-fs "^4.1.2" iferr "^0.1.5" @@ -2902,15 +2962,15 @@ fstream-ignore@^1.0.0: minimatch "^3.0.0" fstream-npm@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fstream-npm/-/fstream-npm-1.2.0.tgz#d2c3c89101346982d64e57091c38487bda916fce" + version "1.2.1" + resolved "https://registry.yarnpkg.com/fstream-npm/-/fstream-npm-1.2.1.tgz#08c4a452f789dcbac4c89a4563c902b2c862fd5b" dependencies: fstream-ignore "^1.0.0" inherits "2" fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -2931,9 +2991,9 @@ gauge@~2.6.0: strip-ansi "^3.0.1" wide-align "^1.1.0" -gauge@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" +gauge@~2.7.1, gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -2942,7 +3002,6 @@ gauge@~2.7.1: signal-exit "^3.0.0" string-width "^1.0.1" strip-ansi "^3.0.1" - supports-color "^0.2.0" wide-align "^1.1.0" generate-function@^2.0.0: @@ -2964,8 +3023,8 @@ get-stdin@^4.0.1: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" getpass@^0.1.1: - version "0.1.6" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" dependencies: assert-plus "^1.0.0" @@ -3022,7 +3081,7 @@ glob@3.2.8: inherits "2" minimatch "~0.2.11" -glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5: +glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: @@ -3043,25 +3102,6 @@ glob@^5.0.10, glob@^5.0.13, glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^6.0.0: - version "6.0.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@~4.0.4: - version "4.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.0.6.tgz#695c50bdd4e2fb5c5d370b091f388d3707e291a7" - dependencies: - graceful-fs "^3.0.2" - inherits "2" - minimatch "^1.0.0" - once "^1.3.0" - glob@~7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" @@ -3094,8 +3134,8 @@ globals@^6.4.0: resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" globals@^9.0.0, globals@^9.14.0: - version "9.14.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" globby@^5.0.0: version "5.0.0" @@ -3108,20 +3148,10 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^3.0.2: - version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" - dependencies: - natives "^1.1.0" - -graceful-fs@^4.1.0, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.6: +graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -graceful-fs@~1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" - "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" @@ -3135,8 +3165,8 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4, handlebars@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + version "4.0.10" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -3144,6 +3174,10 @@ handlebars@^4.0.4, handlebars@^4.0.6: optionalDependencies: uglify-js "^2.6" +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + har-validator@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" @@ -3153,6 +3187,13 @@ har-validator@~2.0.6: is-my-json-valid "^2.12.4" pinkie-promise "^2.0.0" +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + has-ansi@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" @@ -3230,15 +3271,15 @@ heimdalljs-fs-monitor@^0.0.3: heimdalljs "^0.2.0" heimdalljs-logger@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.7.tgz#10e340af5c22a811e34522d9b9397675ad589ca4" + version "0.1.9" + resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" dependencies: debug "^2.2.0" heimdalljs "^0.2.0" heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.3.tgz#35b82a6a4d73541fc4fb88d2fe2b23608fb4f779" + version "0.2.5" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" dependencies: rsvp "~3.2.1" @@ -3270,7 +3311,11 @@ homedir-polyfill@^1.0.0: dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@~2.1.5: +hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + +hosted-git-info@~2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" @@ -3326,13 +3371,9 @@ https-proxy-agent@~1.0.0: debug "2" extend "3" -iconv-lite@^0.4.5, iconv-lite@~0.4.13: - version "0.4.15" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" - -iconv-lite@~0.2.10: - version "0.2.11" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" +iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: + version "0.4.18" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2" ieee754@^1.1.4: version "1.1.8" @@ -3343,10 +3384,10 @@ iferr@^0.1.5, iferr@~0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" ignore@^3.2.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.6.tgz#26e8da0644be0bb4cb39516f6c79f0e0f4ffe48c" + version "3.3.3" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" -imurmurhash@^0.1.4: +imurmurhash@*, imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -3355,8 +3396,8 @@ indexof@0.0.1: resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflection@^1.7.0, inflection@^1.7.1: - version "1.10.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.10.0.tgz#5bffcb1197ad3e81050f8e17e21668087ee9eb2f" + version "1.12.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflight@^1.0.4, inflight@~1.0.5: version "1.0.6" @@ -3374,17 +3415,17 @@ ini@^1.3.4, ini@~1.3.4: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" init-package-json@~1.9.4: - version "1.9.4" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.9.4.tgz#b4053d0b40f0cf842a41966937cb3dc0f534e856" + version "1.9.6" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.9.6.tgz#789fc2b74466a4952b9ea77c0575bc78ebd60a61" dependencies: - glob "^6.0.0" - npm-package-arg "^4.0.0" + glob "^7.1.1" + npm-package-arg "^4.0.0 || ^5.0.0" promzard "^0.3.0" read "~1.0.1" read-package-json "1 || 2" semver "2.x || 3.x || 4 || 5" validate-npm-package-license "^3.0.1" - validate-npm-package-name "^2.0.1" + validate-npm-package-name "^3.0.0" inline-source-map-comment@^1.0.5: version "1.0.5" @@ -3434,8 +3475,8 @@ inquirer@^1.2.1: through "^2.3.6" interpret@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" + version "1.0.3" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" invariant@^2.2.0: version "2.2.2" @@ -3451,9 +3492,9 @@ ipaddr.js@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" -is-buffer@^1.0.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" +is-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" is-builtin-module@^1.0.0: version "1.0.0" @@ -3462,8 +3503,8 @@ is-builtin-module@^1.0.0: builtin-modules "^1.0.0" is-dotfile@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" is-equal-shallow@^0.1.3: version "0.1.3" @@ -3496,8 +3537,8 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" is-git-url@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.0.tgz#b9ce0fb044821c88880213d602db03bdb255da1b" + version "0.2.3" + resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" @@ -3506,26 +3547,32 @@ is-glob@^2.0.0, is-glob@^2.0.1: is-extglob "^1.0.0" is-integer@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c" dependencies: is-finite "^1.0.0" is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: - version "2.15.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + version "2.16.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" jsonpointer "^4.0.0" xtend "^4.0.0" -is-number@^2.0.2, is-number@^2.1.0: +is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" dependencies: kind-of "^3.0.2" +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" @@ -3595,12 +3642,12 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" isbinaryfile@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.1.tgz#6e99573675372e841a0520c036b41513d783e79e" + version "3.0.2" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" -isexe@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" isobject@^2.0.0: version "2.1.0" @@ -3635,43 +3682,37 @@ jmespath@0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" -jodid25519@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" - dependencies: - jsbn "~0.1.0" - jquery@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" -js-string-escape@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" - js-tokens@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" js-tokens@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: - version "3.7.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + version "3.9.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.0.tgz#4ffbbf25c2ac963b8299dc74da7e3740de1c18ce" dependencies: argparse "^1.0.7" - esprima "^2.6.0" + esprima "^4.0.0" jsbn@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" +jsesc@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -3723,18 +3764,25 @@ jsonpointer@^4.0.0: resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" jsprim@^1.2.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + version "1.4.0" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" dependencies: + assert-plus "1.0.0" extsprintf "1.0.2" json-schema "0.2.3" verror "1.3.6" kind-of@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" dependencies: - is-buffer "^1.0.2" + is-buffer "^1.1.5" klaw@^1.0.0: version "1.3.1" @@ -3785,8 +3833,8 @@ line-column@^1.0.2: isobject "^2.0.0" linkify-it@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.2.tgz#994629a4adfa5a7d34e08c075611575ab9b6fcfc" + version "2.0.3" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" dependencies: uc.micro "^1.0.1" @@ -3838,6 +3886,10 @@ lodash._basefor@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" +lodash._baseindexof@*: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -3845,10 +3897,14 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@^3.0.0: +lodash._bindcallback@*, lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" +lodash._cacheindexof@*: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -3857,11 +3913,17 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" +lodash._createcache@*: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + dependencies: + lodash._getnative "^3.0.0" + lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" -lodash._getnative@^3.0.0: +lodash._getnative@*, lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" @@ -3899,6 +3961,10 @@ lodash.debounce@^3.1.1: dependencies: lodash._getnative "^3.0.0" +lodash.defaultsdeep@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81" + lodash.find@^4.5.1: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" @@ -3969,7 +4035,7 @@ lodash.omit@^4.1.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" -lodash.restparam@^3.0.0: +lodash.restparam@*, lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -4021,13 +4087,9 @@ lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.6, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@^4.8.0: - version "4.17.3" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.3.tgz#557ed7d2a9438cac5fd5a43043ca60cb455e01f7" - -lodash@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.2.1.tgz#ed47b16e46f06b2b40309b68e9163c17e93ea304" +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.1, lodash@^4.16.6, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1, lodash@^4.8.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" longest@^1.0.1: version "1.0.1" @@ -4044,11 +4106,11 @@ lru-cache@2: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" lru-cache@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + version "4.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" dependencies: - pseudomap "^1.0.1" - yallist "^2.0.0" + pseudomap "^1.0.2" + yallist "^2.1.2" makeerror@1.0.x: version "1.0.11" @@ -4092,7 +4154,7 @@ matcher-collection@^1.0.0: dependencies: minimatch "^3.0.2" -md5-hex@^1.0.2, md5-hex@^1.3.0: +md5-hex@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" dependencies: @@ -4121,8 +4183,8 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" memory-streams@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.0.tgz#bec658a71e3f28b0f0c2f1b14501c2db547d5f7a" + version "0.1.2" + resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" dependencies: readable-stream "~1.0.2" @@ -4167,24 +4229,32 @@ micromatch@^2.1.5, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -"mime-db@>= 1.24.0 < 2", mime-db@~1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" +"mime-db@>= 1.27.0 < 2": + version "1.29.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.29.0.tgz#48d26d235589651704ac5916ca06001914266878" + +mime-db@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" -mime-types@^2.1.11, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: - version "2.1.13" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" +mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: + version "2.1.15" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" dependencies: - mime-db "~1.25.0" + mime-db "~1.27.0" mime-types@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" -mime@1.3.4, mime@^1.2.11: +mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" +mime@^1.2.11: + version "1.3.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" + mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" @@ -4197,17 +4267,10 @@ minimatch@0.3: sigmund "~1.0.0" "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" - dependencies: - brace-expansion "^1.0.0" - -minimatch@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: - lru-cache "2" - sigmund "~1.0.0" + brace-expansion "^1.1.7" minimatch@^2.0.3: version "2.0.10" @@ -4240,7 +4303,7 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi dependencies: minimist "0.0.8" -mkdirp@^0.3.5, mkdirp@~0.3.5: +mkdirp@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" @@ -4264,11 +4327,11 @@ mocha@^2.4.5: to-iso-string "0.0.2" morgan@^1.5.2: - version "1.7.0" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.7.0.tgz#eb10ca8e50d1abe0f8d3dad5c0201d052d981c62" + version "1.8.2" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.8.2.tgz#784ac7734e4a453a9c6e6e8680a9329275c8b687" dependencies: - basic-auth "~1.0.3" - debug "~2.2.0" + basic-auth "~1.1.0" + debug "2.6.8" depd "~1.1.0" on-finished "~2.3.0" on-headers "~1.0.1" @@ -4285,13 +4348,9 @@ ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" -ms@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" - -ms@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-1.0.0.tgz#59adcd22edc543f7b5381862d31387b1f4bc9473" +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" mustache@^2.2.1: version "2.3.0" @@ -4305,10 +4364,6 @@ mute-stream@0.0.6, mute-stream@~0.0.4: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" -natives@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -4318,8 +4373,8 @@ negotiator@0.6.1: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" node-fetch@^1.3.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + version "1.7.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5" dependencies: encoding "^0.1.11" is-stream "^1.0.1" @@ -4365,8 +4420,8 @@ node-uuid@1.4.0: resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.0.tgz#07f9b2337572ff6275c775e1d48513f3a45d7a65" node-uuid@^1.4.3, node-uuid@~1.4.0, node-uuid@~1.4.7: - version "1.4.7" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" + version "1.4.8" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" "nopt@2 || 3", nopt@^3.0.1, nopt@~3.0.6: version "3.0.6" @@ -4379,8 +4434,8 @@ normalize-git-url@~3.0.2: resolved "https://registry.yarnpkg.com/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" normalize-package-data@^2.0.0, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + version "2.3.8" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -4388,8 +4443,10 @@ normalize-package-data@^2.0.0, "normalize-package-data@~1.0.1 || ^2.0.0", normal validate-npm-package-license "^3.0.1" normalize-path@^2.0.0, normalize-path@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" npm-cache-filename@~1.0.2: version "1.0.2" @@ -4401,9 +4458,9 @@ npm-install-checks@~3.0.0: dependencies: semver "^2.3.0 || 3.x || 4 || 5" -"npm-package-arg@^3.0.0 || ^4.0.0", npm-package-arg@^4.0.0, npm-package-arg@^4.1.1, npm-package-arg@~4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.0.tgz#809bc61cabf54bd5ff94f6165c89ba8ee88c115c" +"npm-package-arg@^3.0.0 || ^4.0.0", "npm-package-arg@^4.0.0 || ^5.0.0", npm-package-arg@^4.1.1, npm-package-arg@~4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" dependencies: hosted-git-info "^2.1.5" semver "^5.1.0" @@ -4513,7 +4570,16 @@ npm@3.10.8: gauge "~2.6.0" set-blocking "~2.0.0" -npmlog@^4.0.0, npmlog@~4.0.0: +npmlog@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +npmlog@~4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" dependencies: @@ -4534,10 +4600,14 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@4.1.0, object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" +object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" @@ -4559,25 +4629,19 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0, once@^1.3.3, once@~1.4.0: +once@^1.3.0, once@^1.3.3, once@^1.4.0, once@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" -once@~1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" - dependencies: - wrappy "1" - onetime@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" opener@~1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.2.tgz#b32582080042af8680c389a499175b4c54fff523" + version "1.4.3" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" optimist@^0.6.1: version "0.6.1" @@ -4718,6 +4782,10 @@ path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -4737,8 +4805,8 @@ pluralize@^1.2.1: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" portfinder@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.10.tgz#7a4de9d98553c315da6f1e1ed05138eeb2d16bb8" + version "1.0.13" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" dependencies: async "^1.5.2" debug "^2.2.0" @@ -4757,8 +4825,8 @@ printf@^0.2.3: resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" private@^0.1.6, private@~0.1.5: - version "0.1.6" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + version "0.1.7" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" process-nextick-args@~1.0.6: version "1.0.7" @@ -4790,14 +4858,14 @@ proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" -proxy-addr@~1.1.3: +proxy-addr@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" dependencies: forwarded "~0.1.0" ipaddr.js "1.3.0" -pseudomap@^1.0.1: +pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -4817,7 +4885,7 @@ q@~0.9.6: version "0.9.7" resolved "https://registry.yarnpkg.com/q/-/q-0.9.7.tgz#4de2e6cb3b29088c9e4cbc03bf9d42fb96ce2f75" -qs@6.4.0, qs@^6.2.0: +qs@6.4.0, qs@^6.4.0, qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -4826,8 +4894,12 @@ qs@~1.0.0: resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" qs@~6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + version "6.2.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" + +qs@~6.3.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" querystring@0.2.0: version "0.2.0" @@ -4846,19 +4918,25 @@ qunit-extras@^1.5.0: resolved "https://registry.yarnpkg.com/qunit-extras/-/qunit-extras-1.5.0.tgz#a64d1c5088ab20c01c0e1b04c72132c397b3964c" qunit-phantomjs-runner@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/qunit-phantomjs-runner/-/qunit-phantomjs-runner-2.2.0.tgz#557a0f55d7d83c315312d1b7048ed972ffea4549" + version "2.3.0" + resolved "https://registry.yarnpkg.com/qunit-phantomjs-runner/-/qunit-phantomjs-runner-2.3.0.tgz#270acb197c0f2fcaaf06676ab0a48fd5aca66a99" + dependencies: + qunit-reporter-junit "^1.0.2" + +qunit-reporter-junit@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/qunit-reporter-junit/-/qunit-reporter-junit-1.1.1.tgz#eeb6226457896993e795a11940f18af6afa579b4" qunitjs@^1.22.0: version "1.23.1" resolved "https://registry.yarnpkg.com/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" randomatic@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" dependencies: - is-number "^2.0.2" - kind-of "^3.0.2" + is-number "^3.0.0" + kind-of "^4.0.0" range-parser@~1.2.0: version "1.2.0" @@ -4891,18 +4969,18 @@ read-installed@~4.0.3: graceful-fs "^4.1.2" "read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@~2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.4.tgz#61ed1b2256ea438d8008895090be84b8e799c853" + version "2.0.10" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.10.tgz#dc0229f6dde6b4b705b39e25b2d970ebe95685ae" dependencies: - glob "^6.0.0" + glob "^7.1.1" json-parse-helpfulerror "^1.0.2" normalize-package-data "^2.0.0" optionalDependencies: graceful-fs "^4.1.2" read-package-tree@~5.1.5: - version "5.1.5" - resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.1.5.tgz#ace7e6381c7684f970aaa98fc7c5d2b666addab6" + version "5.1.6" + resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.1.6.tgz#4f03e83d0486856fb60d97c94882841c2a7b1b7a" dependencies: debuglog "^1.0.1" dezalgo "^1.0.0" @@ -4916,16 +4994,16 @@ read@1, read@~1.0.1, read@~1.0.7: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: - buffer-shims "^1.0.0" core-util-is "~1.0.0" - inherits "~2.0.1" + inherits "~2.0.3" isarray "~1.0.0" process-nextick-args "~1.0.6" - string_decoder "~0.10.x" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" util-deprecate "~1.0.1" readable-stream@^2, readable-stream@~2.1.5: @@ -4960,7 +5038,7 @@ readable-stream@~2.0.5: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: @@ -4984,7 +5062,7 @@ realize-package-specifier@~3.0.3: dezalgo "^1.0.1" npm-package-arg "^4.1.1" -recast@0.10.33, recast@^0.10.10: +recast@0.10.33: version "0.10.33" resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" dependencies: @@ -4993,15 +5071,34 @@ recast@0.10.33, recast@^0.10.10: private "~0.1.5" source-map "~0.5.0" +recast@^0.10.10: + version "0.10.43" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" + dependencies: + ast-types "0.8.15" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + source-map "~0.5.0" + recast@^0.11.17, recast@^0.11.3: - version "0.11.18" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.18.tgz#07af6257ca769868815209401d4d60eef1b5b947" + version "0.11.23" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" dependencies: - ast-types "0.9.2" + ast-types "0.9.6" esprima "~3.1.0" private "~0.1.5" source-map "~0.5.0" +recast@^0.12.0: + version "0.12.6" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.6.tgz#4b0fb82feb1d10b3bd62d34943426d9b3ed30d4c" + dependencies: + ast-types "0.9.11" + core-js "^2.4.1" + esprima "~4.0.0" + private "~0.1.5" + source-map "~0.5.0" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -5019,8 +5116,8 @@ regenerate@^1.2.1: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" regenerator-runtime@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" regenerator@0.8.40: version "0.8.40" @@ -5060,6 +5157,10 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +remove-trailing-separator@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz#69b062d978727ad14dc6b56ba4ab772fd8d70511" + repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" @@ -5080,44 +5181,44 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2, request@^2.51.0, request@^2.74.0, request@~2.74.0: - version "2.74.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" +request@2, request@^2.74.0, request@^2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" dependencies: aws-sign2 "~0.6.0" aws4 "^1.2.1" - bl "~1.1.2" - caseless "~0.11.0" + caseless "~0.12.0" combined-stream "~1.0.5" extend "~3.0.0" forever-agent "~0.6.1" - form-data "~1.0.0-rc4" - har-validator "~2.0.6" + form-data "~2.1.1" + har-validator "~4.2.1" hawk "~3.1.3" http-signature "~1.1.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" mime-types "~2.1.7" - node-uuid "~1.4.7" oauth-sign "~0.8.1" - qs "~6.2.0" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" stringstream "~0.0.4" tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" + tunnel-agent "^0.6.0" + uuid "^3.0.0" -request@2.75.0: - version "2.75.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.75.0.tgz#d2b8268a286da13eaa5d01adf5d18cc90f657d93" +request@2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" dependencies: aws-sign2 "~0.6.0" aws4 "^1.2.1" - bl "~1.1.2" caseless "~0.11.0" combined-stream "~1.0.5" extend "~3.0.0" forever-agent "~0.6.1" - form-data "~2.0.0" + form-data "~2.1.1" har-validator "~2.0.6" hawk "~3.1.3" http-signature "~1.1.0" @@ -5125,12 +5226,12 @@ request@2.75.0: isstream "~0.1.2" json-stringify-safe "~5.0.1" mime-types "~2.1.7" - node-uuid "~1.4.7" oauth-sign "~0.8.1" - qs "~6.2.0" + qs "~6.3.0" stringstream "~0.0.4" tough-cookie "~2.3.0" tunnel-agent "~0.4.1" + uuid "^3.0.0" request@~2.40.0: version "2.40.0" @@ -5151,6 +5252,32 @@ request@~2.40.0: tough-cookie ">=0.12.0" tunnel-agent "~0.4.0" +request@~2.74.0: + version "2.74.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + bl "~1.1.2" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~1.0.0-rc4" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + node-uuid "~1.4.7" + oauth-sign "~0.8.1" + qs "~6.2.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + require-uncached@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -5200,44 +5327,48 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@~2.5.4: - version "2.5.4" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" +rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: glob "^7.0.5" -rimraf@~2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2" - optionalDependencies: - graceful-fs "~1" - rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" +rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + rollup@^0.41.4: - version "0.41.5" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.41.5.tgz#cdfaade5cd1c2c7314351566a50ef74df6e66e3d" + version "0.41.6" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.41.6.tgz#e0d05497877a398c104d816d2733a718a7a94e2a" dependencies: source-map-support "^0.4.0" route-recognizer@^0.3.3: version "0.3.3" - resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" + resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" router_js@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/router_js/-/router_js-1.2.8.tgz#d2ea5d00726e1fd6494d20ae3ebeb99ce86cf0b3" -rsvp@3.0.14, rsvp@~3.0.6: +rsvp@3.0.14: version "3.0.14" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" -rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.6.1: +rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.5.0, rsvp@^3.6.1: version "3.6.1" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.1.tgz#34f4a7ac2859f7bacc8f49789c5604f1e26ae702" +rsvp@~3.0.6: + version "3.0.21" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" + rsvp@~3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" @@ -5262,25 +5393,29 @@ rx@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" +safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + safe-json-parse@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" sane@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3" + version "1.7.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" dependencies: anymatch "^1.3.0" exec-sh "^0.2.0" - fb-watchman "^1.8.0" + fb-watchman "^2.0.0" minimatch "^3.0.2" minimist "^1.1.1" walker "~1.0.5" watch "~0.10.0" -sauce-connect-launcher@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.2.0.tgz#6dc26611ef23428abe8b8f49e0044d7c752b8a6c" +sauce-connect-launcher@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.2.2.tgz#7346cc8fbdc443191323439b0733451f5f3521f2" dependencies: adm-zip "~0.4.3" async "^2.1.2" @@ -5288,15 +5423,15 @@ sauce-connect-launcher@^1.2.0: lodash "^4.16.6" rimraf "^2.5.4" -saucie@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/saucie/-/saucie-3.1.0.tgz#757ea4a740a0e1071877dc5723d03a79ae40c3f4" +saucie@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/saucie/-/saucie-3.2.0.tgz#f3cb07acc253daeda65f12f56cdf88063359670e" dependencies: bluebird "^3.1.1" commander "^2.9.0" - request "^2.51.0" - sauce-connect-launcher "^1.2.0" - wd "^1.0.0" + request "^2.81.0" + sauce-connect-launcher "^1.2.2" + wd "^1.2.0" sax@1.2.1, sax@>=0.6.0: version "1.2.1" @@ -5314,29 +5449,11 @@ semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" -send@0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" - dependencies: - debug "2.6.1" - depd "~1.1.0" - destroy "~1.0.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.8.0" - fresh "0.5.0" - http-errors "~1.6.1" - mime "1.3.4" - ms "0.7.2" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.3.1" - -send@0.15.2: - version "0.15.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.15.2.tgz#f91fab4403bcf87e716f70ceb5db2f578bdc17d6" +send@0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309" dependencies: - debug "2.6.4" + debug "2.6.7" depd "~1.1.0" destroy "~1.0.4" encodeurl "~1.0.1" @@ -5345,28 +5462,19 @@ send@0.15.2: fresh "0.5.0" http-errors "~1.6.1" mime "1.3.4" - ms "1.0.0" + ms "2.0.0" on-finished "~2.3.0" range-parser "~1.2.0" statuses "~1.3.1" -serve-static@1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" - dependencies: - encodeurl "~1.0.1" - escape-html "~1.0.3" - parseurl "~1.3.1" - send "0.15.1" - -serve-static@^1.12.2: - version "1.12.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.2.tgz#e546e2726081b81b4bcec8e90808ebcdd323afba" +serve-static@1.12.3, serve-static@^1.12.2: + version "1.12.3" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.3.tgz#9f4ba19e2f3030c547f8af99107838ec38d5b1e2" dependencies: encodeurl "~1.0.1" escape-html "~1.0.3" parseurl "~1.3.1" - send "0.15.2" + send "0.15.3" set-blocking@~2.0.0: version "2.0.0" @@ -5394,8 +5502,8 @@ shebang-regex@^1.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" shelljs@^0.7.5: - version "0.7.7" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1" + version "0.7.8" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" dependencies: glob "^7.0.0" interpret "^1.0.0" @@ -5414,8 +5522,8 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" silent-error@^1.0.0, silent-error@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" + version "1.1.0" + resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" dependencies: debug "^2.2.0" @@ -5512,8 +5620,8 @@ sort-object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.4.0.tgz#1a80e1770f32f8b23769699f2400cf053f27ef63" + version "1.7.0" + resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.7.0.tgz#13b362ff6400c5b4eaa9ba220f9ea7c3d6644b5f" dependencies: sort-object-keys "^1.1.1" @@ -5528,10 +5636,10 @@ source-map-support@^0.2.10: source-map "0.1.32" source-map-support@^0.4.0, source-map-support@^0.4.2: - version "0.4.8" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.8.tgz#4871918d8a3af07289182e974e32844327b2e98b" + version "0.4.15" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" dependencies: - source-map "^0.5.3" + source-map "^0.5.6" source-map-url@^0.3.0: version "0.3.0" @@ -5549,7 +5657,7 @@ source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.3, source-map@~0.5.0, source-map@~0.5.1: +source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" @@ -5583,8 +5691,8 @@ sprintf-js@^1.0.3, sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sshpk@^1.7.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0" + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -5593,13 +5701,12 @@ sshpk@^1.7.0: optionalDependencies: bcrypt-pbkdf "^1.0.0" ecc-jsbn "~0.1.1" - jodid25519 "^1.0.0" jsbn "~0.1.0" tweetnacl "~0.14.0" stable@~0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.5.tgz#08232f60c732e9890784b5bed0734f8b32a887b9" + version "0.1.6" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" "statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" @@ -5609,7 +5716,7 @@ string-template@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" -string-width@^1.0.1: +string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -5618,16 +5725,22 @@ string-width@^1.0.1: strip-ansi "^3.0.0" string-width@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + version "2.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.0.tgz#030664561fc146c9423ec7d978fe2457437fe6d0" dependencies: is-fullwidth-code-point "^2.0.0" - strip-ansi "^3.0.0" + strip-ansi "^4.0.0" string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + stringmap@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" @@ -5658,6 +5771,12 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1, strip-ansi@~3.0.1: dependencies: ansi-regex "^2.0.0" +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -5696,10 +5815,6 @@ symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" -sync-exec@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" - table@^3.7.8: version "3.8.3" resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" @@ -5712,8 +5827,8 @@ table@^3.7.8: string-width "^2.0.0" tap-parser@^5.1.0: - version "5.3.3" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-5.3.3.tgz#53ec8a90f275d6fff43f169e56a679502a741185" + version "5.4.0" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-5.4.0.tgz#6907e89725d7b7fa6ae41ee2c464c3db43188aec" dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -5721,8 +5836,8 @@ tap-parser@^5.1.0: readable-stream "^2" tar-stream@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.2.tgz#fbc6c6e83c1a19d4cb48c7d96171fc248effc7bf" + version "1.5.4" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.4.tgz#36549cf04ed1aee9b2a30c0143252238daf94016" dependencies: bl "^1.0.0" end-of-stream "^1.0.0" @@ -5779,29 +5894,29 @@ text-table@~0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": - version "2.0.1" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" + version "2.1.0" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.1.0.tgz#1be0dc2a0dc244d44be8a09af6a85afb93c4dbc3" through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" tiny-lr@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" + version "1.0.5" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.5.tgz#21f40bf84ebd1f853056680375eef1670c334112" dependencies: body "^5.1.0" - debug "~2.2.0" + debug "~2.6.7" faye-websocket "~0.10.0" livereload-js "^2.2.2" object-assign "^4.1.0" - qs "^6.2.0" + qs "^6.4.0" tmp-sync@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.0.tgz#2b38ec94b094ed2515ec02a9aee1f51dd2c9023f" + version "1.1.2" + resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" dependencies: - fs-sync "^0.2.4" + fs-sync "^1.0.4" osenv "^0.1.0" tmp@0.0.28: @@ -5825,8 +5940,8 @@ to-array@0.1.4: resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" to-fast-properties@^1.0.0, to-fast-properties@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" to-iso-string@0.0.2: version "0.0.2" @@ -5838,12 +5953,12 @@ tough-cookie@>=0.12.0, tough-cookie@~2.3.0: dependencies: punycode "^1.4.1" -tree-sync@^1.1.4: - version "1.2.1" - resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.1.tgz#35619b7c310f5dfb4091601c013e8a72da67937a" +tree-sync@^1.1.4, tree-sync@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: debug "^2.2.0" - fs-tree-diff "^0.5.2" + fs-tree-diff "^0.5.6" mkdirp "^0.5.1" quick-temp "^0.1.5" walk-sync "^0.2.7" @@ -5864,6 +5979,12 @@ tryor@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: version "0.4.3" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" @@ -5886,12 +6007,12 @@ type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" -type-is@~1.6.14: - version "1.6.14" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" +type-is@~1.6.15: + version "1.6.15" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" dependencies: media-typer "0.3.0" - mime-types "~2.1.13" + mime-types "~2.1.15" typedarray@^0.0.6: version "0.0.6" @@ -5902,13 +6023,13 @@ uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" uglify-js@^2.6, uglify-js@^2.7.0: - version "2.7.5" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: - async "~0.2.6" source-map "~0.5.1" - uglify-to-browserify "~1.0.0" yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" uglify-js@~2.6.2: version "2.6.4" @@ -5989,6 +6110,10 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" +username-sync@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" + util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -6001,7 +6126,7 @@ utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@3.0.1: +uuid@3.0.1, uuid@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" @@ -6009,14 +6134,20 @@ uuid@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" -validate-npm-package-license@^3.0.1: +validate-npm-package-license@*, validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" dependencies: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" -validate-npm-package-name@^2.0.1, validate-npm-package-name@~2.2.2: +validate-npm-package-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + dependencies: + builtins "^1.0.3" + +validate-npm-package-name@~2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" dependencies: @@ -6026,9 +6157,9 @@ vargs@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff" -vary@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" +vary@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" verror@1.3.6: version "1.3.6" @@ -6064,12 +6195,16 @@ walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: matcher-collection "^1.0.0" walk-sync@^0.3.0, walk-sync@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" + version "0.3.2" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" +walkdir@^0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.11.tgz#a16d025eb931bd03b52f308caed0f40fcebe9532" + walker@~1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" @@ -6086,15 +6221,16 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" -wd@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/wd/-/wd-1.1.1.tgz#f2c6c41700f69e3009dcfc3574f42e9ae70fb5c1" +wd@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/wd/-/wd-1.4.0.tgz#85958787abc32f048d4b3927b2ab3c5fc8c9c9fa" dependencies: - archiver "1.1.0" + archiver "1.3.0" async "2.0.1" lodash "4.16.2" + mkdirp "^0.5.1" q "1.4.1" - request "2.75.0" + request "2.79.0" underscore.string "3.3.4" vargs "0.1.0" @@ -6109,16 +6245,16 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" which@1, which@^1.2.12, which@^1.2.9, which@~1.2.11: - version "1.2.12" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" dependencies: - isexe "^1.1.1" + isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" dependencies: - string-width "^1.0.1" + string-width "^1.0.2" window-size@0.1.0: version "0.1.0" @@ -6128,19 +6264,37 @@ window-size@^0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" -wordwrap@0.0.2, wordwrap@~0.0.2: +wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" +workerpool@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.2.2.tgz#1cf53bacafd98ca5d808ff54cc72f3fecb5e1d56" + dependencies: + object-assign "4.1.1" + wrappy@1, wrappy@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -write-file-atomic@^1.1.2, write-file-atomic@~1.2.0: +write-file-atomic@^1.1.2: + version "1.3.4" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write-file-atomic@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" dependencies: @@ -6200,9 +6354,9 @@ y18n@^3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" -yallist@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" yam@0.0.22: version "0.0.22" @@ -6254,10 +6408,10 @@ yuidocjs@^0.10.0: yui "^3.18.1" zip-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.1.0.tgz#2ad479fffc168e05a888e8c348ff6813b3f13733" + version "1.2.0" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04" dependencies: archiver-utils "^1.3.0" - compress-commons "^1.1.0" + compress-commons "^1.2.0" lodash "^4.8.0" readable-stream "^2.0.0" From ed2ffb76014aadd126f158ddfda1ada5285146b0 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 16 Jul 2017 14:27:33 +0500 Subject: [PATCH 154/224] [BUGFIX beta] possible fix for #15490 --- packages/ember-testing/lib/test/promise.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/ember-testing/lib/test/promise.js b/packages/ember-testing/lib/test/promise.js index a5e2624017e..81a78a95846 100644 --- a/packages/ember-testing/lib/test/promise.js +++ b/packages/ember-testing/lib/test/promise.js @@ -9,8 +9,10 @@ export default class TestPromise extends RSVP.Promise { lastPromise = this; } - then(onFulfillment, ...args) { - return super.then(result => isolate(onFulfillment, result), ...args); + then(_onFulfillment, ...args) { + let onFulfillment = typeof _onFulfillment === 'function' ? + result => isolate(_onFulfillment, result) : undefined; + return super.then(onFulfillment, ...args); } } From 099d112bac2c4f551e240d309cbc8e23e04c92c6 Mon Sep 17 00:00:00 2001 From: Mitch Lloyd Date: Sun, 16 Jul 2017 15:38:35 -0700 Subject: [PATCH 155/224] Run skipped Glimmer assertions --- .../tests/integration/components/append-test.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/ember-glimmer/tests/integration/components/append-test.js b/packages/ember-glimmer/tests/integration/components/append-test.js index d973f495480..9d574e31ddc 100644 --- a/packages/ember-glimmer/tests/integration/components/append-test.js +++ b/packages/ember-glimmer/tests/integration/components/append-test.js @@ -317,11 +317,7 @@ class AbstractAppendTest extends RenderingTest { this.runTask(() => this.component.destroy()); - if (this.isHTMLBars) { - // Bug in Glimmer – component should not have .element at this point - assert.ok(!this.component.element, 'It should not have an element'); - } - + assert.ok(!this.component.element, 'It should not have an element'); assert.ok(!componentElement.parentElement, 'The component element should be detached'); this.assert.equal(willDestroyCalled, 1); @@ -411,11 +407,8 @@ class AbstractAppendTest extends RenderingTest { second.destroy(); }); - if (this.isHTMLBars) { - // Bug in Glimmer – component should not have .element at this point - assert.ok(!first.element, 'The first component should not have an element'); - assert.ok(!second.element, 'The second component should not have an element'); - } + assert.ok(!first.element, 'The first component should not have an element'); + assert.ok(!second.element, 'The second component should not have an element'); assert.ok(!componentElement1.parentElement, 'The first component element should be detached'); assert.ok(!componentElement2.parentElement, 'The second component element should be detached'); From bd60d853d76252e379dc4876b24475cb3c5d3a10 Mon Sep 17 00:00:00 2001 From: Mitch Lloyd Date: Sun, 16 Jul 2017 15:39:42 -0700 Subject: [PATCH 156/224] Release reference to root components after destroy --- packages/ember-glimmer/lib/renderer.js | 1 + .../tests/integration/components/append-test.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/ember-glimmer/lib/renderer.js b/packages/ember-glimmer/lib/renderer.js index e598f0d96e8..29cf5c9b7cf 100644 --- a/packages/ember-glimmer/lib/renderer.js +++ b/packages/ember-glimmer/lib/renderer.js @@ -241,6 +241,7 @@ class Renderer { let root = roots[i]; if (root.isFor(view)) { root.destroy(); + roots.splice(i, 1); } } } diff --git a/packages/ember-glimmer/tests/integration/components/append-test.js b/packages/ember-glimmer/tests/integration/components/append-test.js index 9d574e31ddc..75eb9691867 100644 --- a/packages/ember-glimmer/tests/integration/components/append-test.js +++ b/packages/ember-glimmer/tests/integration/components/append-test.js @@ -323,6 +323,23 @@ class AbstractAppendTest extends RenderingTest { this.assert.equal(willDestroyCalled, 1); } + ['@test releasing a root component after it has been destroy'](assert) { + let renderer = this.owner.lookup('renderer:-dom'); + + this.registerComponent('x-component', { + ComponentClass: Component.extend() + }); + + this.component = this.owner.factoryFor('component:x-component').create(); + this.append(this.component); + + assert.equal(renderer._roots.length, 1, 'added a root component'); + + this.runTask(() => this.component.destroy()); + + assert.equal(renderer._roots.length, 0, 'released the root component'); + } + ['@test appending, updating and destroying multiple components'](assert) { let willDestroyCalled = 0; From 14243438756b908b4557f9f3e296d3af89bcda81 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 17 Jul 2017 11:50:04 +0500 Subject: [PATCH 157/224] remove unnecessary check --- packages/ember-metal/lib/property_set.js | 4 ++-- packages/ember-metal/lib/weak_map.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index 515809c0714..09b07ca959d 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -95,9 +95,9 @@ function setPath(root, path, value, tolerant) { let parts = path.split('.'); let keyName = parts.pop(); - assert('Property set failed: You passed an empty path', keyName && keyName.length > 0) + assert('Property set failed: You passed an empty path', keyName.trim().length > 0) - let newPath = parts.length > 0 ? parts.join('.') : keyName; + let newPath = parts.join('.'); let newRoot = getPath(root, newPath); diff --git a/packages/ember-metal/lib/weak_map.js b/packages/ember-metal/lib/weak_map.js index 5854695f44d..416d1e723e5 100644 --- a/packages/ember-metal/lib/weak_map.js +++ b/packages/ember-metal/lib/weak_map.js @@ -115,7 +115,7 @@ WeakMap.prototype.has = function(obj) { */ WeakMap.prototype.delete = function(obj) { if (this.has(obj)) { - delete metaFor(obj).writableWeak()[this._id]; + delete peekMeta(obj).writableWeak()[this._id]; return true; } else { return false; From db380f3b36b332861b2f5bfdbfdb89e95e171ed7 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 17 Jul 2017 13:00:23 +0500 Subject: [PATCH 158/224] cleanup `setPath` --- packages/ember-metal/lib/property_set.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index 09b07ca959d..40982dc2b98 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -101,15 +101,11 @@ function setPath(root, path, value, tolerant) { let newRoot = getPath(root, newPath); - if (!newRoot) { - if (tolerant) { - return; - } else { - throw new EmberError(`Property set failed: object in path "${newPath}" could not be found or was destroyed.`); - } + if (newRoot) { + return set(newRoot, keyName, value); + } else if (!tolerant) { + throw new EmberError(`Property set failed: object in path "${newPath}" could not be found or was destroyed.`); } - - return set(newRoot, keyName, value); } /** From 505bdc5d0623ad6c8d1561983559e28f9651f6f9 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 17 Jul 2017 13:20:22 +0500 Subject: [PATCH 159/224] make consistent how `unknownProperty` `setUnknownProperty` checked --- packages/ember-metal/lib/property_get.js | 4 ++-- packages/ember-metal/lib/property_set.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-metal/lib/property_get.js b/packages/ember-metal/lib/property_get.js index 5a5563d43ad..caa2a9c7672 100644 --- a/packages/ember-metal/lib/property_get.js +++ b/packages/ember-metal/lib/property_get.js @@ -61,8 +61,8 @@ export function get(obj, keyName) { return value.get(obj, keyName); } else if (isPath(keyName)) { return _getPath(obj, keyName); - } else if (value === undefined && - 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { + } else if (value === undefined && 'object' === typeof obj && !(keyName in obj) && + typeof obj.unknownProperty === 'function') { return obj.unknownProperty(keyName); } else { return value; diff --git a/packages/ember-metal/lib/property_set.js b/packages/ember-metal/lib/property_set.js index 515809c0714..c89282cdcac 100644 --- a/packages/ember-metal/lib/property_set.js +++ b/packages/ember-metal/lib/property_set.js @@ -51,8 +51,8 @@ export function set(obj, keyName, value, tolerant) { if (isDescriptor) { /* computed property */ currentValue.set(obj, keyName, value); - } else if (obj.setUnknownProperty && currentValue === undefined && !(keyName in obj)) { /* unknown property */ - assert('setUnknownProperty must be a function', typeof obj.setUnknownProperty === 'function'); + } else if (currentValue === undefined && 'object' === typeof obj && !(keyName in obj) && + typeof obj.setUnknownProperty === 'function') { /* unknown property */ obj.setUnknownProperty(keyName, value); } else if (currentValue === value) { /* no change */ } else { From 567b17802a739d359867e86fcfe5c318a56ef3bb Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 17 Jul 2017 17:33:02 +0500 Subject: [PATCH 160/224] added test for `TestPromise` --- packages/ember-testing/tests/ext/rsvp_test.js | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/ember-testing/tests/ext/rsvp_test.js b/packages/ember-testing/tests/ext/rsvp_test.js index 24eeae51c41..4d4f817650c 100644 --- a/packages/ember-testing/tests/ext/rsvp_test.js +++ b/packages/ember-testing/tests/ext/rsvp_test.js @@ -1,5 +1,6 @@ import RSVP from '../../ext/rsvp'; import { getAdapter, setAdapter } from '../../test/adapter'; +import TestPromise, { getLastPromise } from '../../test/promise'; import { run } from 'ember-metal'; import { isTesting, setTesting } from 'ember-debug'; @@ -84,3 +85,35 @@ QUnit.test('given `Ember.testing = true`, correctly informs the test suite about equal(asyncEnded, 2); }); }); + + +QUnit.module('TestPromise'); + +QUnit.test('does not throw error when falsy value passed to then', function() { + expect(1); + return new TestPromise(function(resolve) { + resolve() + }) + .then(null) + .then(function() { + ok(true); + }); +}); + +QUnit.test('able to get last Promise', function() { + expect(2); + + var p1 = new TestPromise(function(resolve) { + resolve() + }) + .then(function() { + ok(true); + }); + + var p2 = new TestPromise(function(resolve) { + resolve() + }); + + deepEqual(getLastPromise(), p2); + return p1; +}); From ce2a191c74628290a14369c0fdd98bf78f9384ed Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 30 Jun 2017 16:10:17 +0500 Subject: [PATCH 161/224] correct checking `args` and cleanup in `mixins/array` --- packages/ember-runtime/lib/mixins/array.js | 19 +++++-------------- .../ember-runtime/lib/mixins/enumerable.js | 2 +- packages/ember-utils/lib/invoke.js | 2 +- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/array.js b/packages/ember-runtime/lib/mixins/array.js index 1fe9f3ae821..9d092b418e1 100644 --- a/packages/ember-runtime/lib/mixins/array.js +++ b/packages/ember-runtime/lib/mixins/array.js @@ -7,7 +7,6 @@ // HELPERS // import { symbol } from 'ember-utils'; - import Ember, { // ES6TODO: Ember.A get, computed, @@ -58,11 +57,7 @@ export function removeArrayObserver(array, target, opts) { } export function objectAt(content, idx) { - if (content.objectAt) { - return content.objectAt(idx); - } - - return content[idx]; + return typeof content.objectAt === 'function' ? content.objectAt(idx) : content[idx]; } export function arrayContentWillChange(array, startIdx, removeAmt, addAmt) { @@ -160,7 +155,7 @@ export function arrayContentDidChange(array, startIdx, removeAmt, addAmt) { const EMBER_ARRAY = symbol('EMBER_ARRAY'); export function isEmberArray(obj) { - return obj && !!obj[EMBER_ARRAY]; + return obj && obj[EMBER_ARRAY]; } // .......................................................... @@ -340,17 +335,13 @@ const ArrayMixin = Mixin.create(Enumerable, { if (isNone(beginIndex)) { beginIndex = 0; + } else if (beginIndex < 0) { + beginIndex = length + beginIndex; } if (isNone(endIndex) || (endIndex > length)) { endIndex = length; - } - - if (beginIndex < 0) { - beginIndex = length + beginIndex; - } - - if (endIndex < 0) { + } else if (endIndex < 0) { endIndex = length + endIndex; } diff --git a/packages/ember-runtime/lib/mixins/enumerable.js b/packages/ember-runtime/lib/mixins/enumerable.js index 45477348392..3a56f7a2730 100644 --- a/packages/ember-runtime/lib/mixins/enumerable.js +++ b/packages/ember-runtime/lib/mixins/enumerable.js @@ -742,7 +742,7 @@ const Enumerable = Mixin.create({ let method = x && x[methodName]; if ('function' === typeof method) { - ret[idx] = args ? method.apply(x, args) : x[methodName](); + ret[idx] = args.length ? method.apply(x, args) : x[methodName](); } }, this); diff --git a/packages/ember-utils/lib/invoke.js b/packages/ember-utils/lib/invoke.js index 31841694bfc..e708b81d854 100644 --- a/packages/ember-utils/lib/invoke.js +++ b/packages/ember-utils/lib/invoke.js @@ -44,6 +44,6 @@ export function canInvoke(obj, methodName) { */ export function tryInvoke(obj, methodName, args) { if (canInvoke(obj, methodName)) { - return args ? applyStr(obj, methodName, args) : applyStr(obj, methodName); + return applyStr(obj, methodName, args); } } From 03f4bbb015392d083386fe06bdf8795c390f36e0 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 17 Jul 2017 11:46:36 -0700 Subject: [PATCH 162/224] [BUGFIX beta] remove Error.captureStackTrace We only do this for stack cosmetic reasons, it really just removes 1 or so frames, but apparently more recently at a hefty cost: context: https://github.com/emberjs/ember.js/issues/15516 --- packages/ember-debug/lib/error.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/ember-debug/lib/error.js b/packages/ember-debug/lib/error.js index 3d7490cc413..c7205b95522 100644 --- a/packages/ember-debug/lib/error.js +++ b/packages/ember-debug/lib/error.js @@ -27,13 +27,7 @@ export default class EmberError extends ExtendBuiltin(Error) { } let error = Error.call(this, message); - - if (Error.captureStackTrace) { - Error.captureStackTrace(this, EmberError); - } else { - this.stack = error.stack; - } - + this.stack = error.stack; this.description = error.description; this.fileName = error.fileName; this.lineNumber = error.lineNumber; From 5752d95af1556a18774602091b108f43a1c4b322 Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 14 Jul 2017 20:15:26 +0500 Subject: [PATCH 163/224] [BUGFIX beta] fix for lastObject/firstObject update issue --- packages/ember-runtime/lib/mixins/array.js | 34 ++++++++++++------- .../tests/suites/mutable_array/insertAt.js | 10 ++++++ .../tests/suites/mutable_array/pushObject.js | 22 ++++++++++++ .../tests/suites/mutable_array/replace.js | 21 ++++++++++++ .../suites/mutable_array/unshiftObject.js | 4 +-- 5 files changed, 77 insertions(+), 14 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/array.js b/packages/ember-runtime/lib/mixins/array.js index 1fe9f3ae821..9d931333bd0 100644 --- a/packages/ember-runtime/lib/mixins/array.js +++ b/packages/ember-runtime/lib/mixins/array.js @@ -141,19 +141,29 @@ export function arrayContentDidChange(array, startIdx, removeAmt, addAmt) { let meta = peekMeta(array); let cache = meta && meta.readableCache(); - - if (cache) { - if (cache.firstObject !== undefined && - objectAt(array, 0) !== cacheFor.get(cache, 'firstObject')) { - propertyWillChange(array, 'firstObject', meta); - propertyDidChange(array, 'firstObject', meta); - } - if (cache.lastObject !== undefined && - objectAt(array, get(array, 'length') - 1) !== cacheFor.get(cache, 'lastObject')) { - propertyWillChange(array, 'lastObject', meta); - propertyDidChange(array, 'lastObject', meta); - } + if (cache !== undefined) { + let length = get(array, 'length'); + let addedAmount = (addAmt === -1 ? 0 : addAmt); + let removedAmount = (removeAmt === -1 ? 0 : removeAmt); + let delta = addedAmount - removedAmount; + let previousLength = length - delta; + + let normalStartIdx = startIdx < 0 ? previousLength + startIdx : startIdx; + if (cache.firstObject !== undefined && normalStartIdx === 0) { + propertyWillChange(array, 'firstObject'); + propertyDidChange(array, 'firstObject'); + } + + if (cache.lastObject !== undefined) { + let previousLastIndex = previousLength - 1; + let lastAffectedIndex = normalStartIdx + removedAmount; + if (previousLastIndex < lastAffectedIndex) { + propertyWillChange(array, 'lastObject'); + propertyDidChange(array, 'lastObject'); + } + } } + return array; } diff --git a/packages/ember-runtime/tests/suites/mutable_array/insertAt.js b/packages/ember-runtime/tests/suites/mutable_array/insertAt.js index be4e4de840b..eb230c160b6 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/insertAt.js +++ b/packages/ember-runtime/tests/suites/mutable_array/insertAt.js @@ -135,10 +135,20 @@ suite.test('[A,B,C].insertAt(1,X) => [A,X,B,C] + notify', function() { let after = [before[0], item, before[1], before[2]]; let obj = this.newObject(before); let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + let objectAtCalls = []; + + let objectAt = obj.objectAt; + obj.objectAt = (ix) => { + objectAtCalls.push(ix); + return objectAt.call(obj, ix); + } obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ + objectAtCalls.splice(0, objectAtCalls.length); + obj.insertAt(1, item); + deepEqual(objectAtCalls, [], 'objectAt is not called when only inserting items'); deepEqual(this.toArray(obj), after, 'post item results'); equal(get(obj, 'length'), after.length, 'length'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/pushObject.js b/packages/ember-runtime/tests/suites/mutable_array/pushObject.js index fce14652d35..45ab22bc066 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/pushObject.js +++ b/packages/ember-runtime/tests/suites/mutable_array/pushObject.js @@ -54,4 +54,26 @@ suite.test('[A,B,C].pushObject(X) => [A,B,C,X] + notify', function() { equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); }); +suite.test('[A,B,C,C].pushObject(A) => [A,B,C,C] + notify', function() { + let before = this.newFixture(3); + let item = before[2]; // note same object as current tail. should end up twice + let after = [before[0], before[1], before[2], item]; + let obj = this.newObject(before); + let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + + obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ + + obj.pushObject(item); + + deepEqual(this.toArray(obj), after, 'post item results'); + equal(get(obj, 'length'), after.length, 'length'); + + equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); + equal(observer.timesCalled('length'), 1, 'should have notified length once'); + + equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); + equal(observer.validate('lastObject'), true, 'should have notified lastObject'); +}); + export default suite; diff --git a/packages/ember-runtime/tests/suites/mutable_array/replace.js b/packages/ember-runtime/tests/suites/mutable_array/replace.js index b9f17b08484..a1ac5b636ec 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/replace.js +++ b/packages/ember-runtime/tests/suites/mutable_array/replace.js @@ -126,6 +126,27 @@ suite.test('[A,B,C,D].replace(2,2) => [A,B] + notify', function() { equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); }); +suite.test('[A,B,C,D].replace(-1,1) => [A,B,C] + notify', function() { + let before = this.newFixture(4); + let after = [before[0], before[1], before[2]]; + + let obj = this.newObject(before); + let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); + + obj.getProperties('firstObject', 'lastObject'); /* Prime the cache */ + + obj.replace(-1, 1); + + deepEqual(this.toArray(obj), after, 'post item results'); + + equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); + equal(observer.timesCalled('length'), 1, 'should have notified length once'); + equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); + + equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); +}); + suite.test('Adding object should notify enumerable observer', function() { let fixtures = this.newFixture(4); let obj = this.newObject(fixtures); diff --git a/packages/ember-runtime/tests/suites/mutable_array/unshiftObject.js b/packages/ember-runtime/tests/suites/mutable_array/unshiftObject.js index e563dd7ac3c..1db55b51feb 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/unshiftObject.js +++ b/packages/ember-runtime/tests/suites/mutable_array/unshiftObject.js @@ -58,7 +58,7 @@ suite.test('[A,B,C].unshiftObject(X) => [X,A,B,C] + notify', function() { suite.test('[A,B,C].unshiftObject(A) => [A,A,B,C] + notify', function() { let before = this.newFixture(3); let item = before[0]; // note same object as current head. should end up twice - let after = [item, before[0], before[1], before[2]]; + let after = [item, before[0], before[1], before[2]]; let obj = this.newObject(before); let observer = this.newObserver(obj, '[]', '@each', 'length', 'firstObject', 'lastObject'); @@ -73,7 +73,7 @@ suite.test('[A,B,C].unshiftObject(A) => [A,A,B,C] + notify', function() { equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); - equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); + equal(observer.validate('firstObject'), true, 'should have notified firstObject'); equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject'); }); From 3666ea2e3bb47bd9dc610a4f3a9c4058afe65eb2 Mon Sep 17 00:00:00 2001 From: Sarah Clatterbuck Date: Mon, 20 Feb 2017 16:19:26 -0800 Subject: [PATCH 164/224] [DOC release] Fixing documentation of Location API and various implementations https://github.com/emberjs/ember.js/issues/14909 Also, doing a minor spiff of Component to accurately reflect current state of the Layout API, which was previously marked as public --- packages/ember-glimmer/lib/component.js | 37 ++++-- packages/ember-routing/lib/location/api.js | 108 +++--------------- .../lib/location/auto_location.js | 32 +++++- .../lib/location/hash_location.js | 21 +++- .../lib/location/history_location.js | 24 +++- .../lib/location/none_location.js | 6 +- 6 files changed, 125 insertions(+), 103 deletions(-) diff --git a/packages/ember-glimmer/lib/component.js b/packages/ember-glimmer/lib/component.js index f9cb15e41e0..e6f6387de81 100644 --- a/packages/ember-glimmer/lib/component.js +++ b/packages/ember-glimmer/lib/component.js @@ -432,6 +432,34 @@ export const BOUNDS = symbol('BOUNDS'); See [Ember.Templates.helpers.yield](/api/classes/Ember.Templates.helpers.html#method_yield) for more information. + Layout can be used to wrap content in a component. In addition + to wrapping content in a Component's template, you can also use + the public layout API in your Component JavaScript. + + ```app/templates/components/person-profile.hbs +

Person's Title

+
{{yield}}
+ ``` + + ```app/components/person-profile.js + import Ember from 'ember'; + import layout from '../templates/components/person-profile'; + + export default Ember.Component.extend({ + layout + }); + ``` + + The above will result in the following HTML output: + + ```html +

Person's Title

+
+

Chief Basket Weaver

+

Fisherman Industries

+
+ ``` + ## Responding to Browser Events @@ -809,14 +837,7 @@ const Component = CoreView.extend( */ /** - A component may contain a layout. A layout is a regular template but - supersedes the `template` property during rendering. It is the - responsibility of the layout template to retrieve the `template` - property from the component (or alternatively, call `Handlebars.helpers.yield`, - `{{yield}}`) to render it in the correct location. - This is useful for a component that has a shared wrapper, but which delegates - the rendering of the contents of the wrapper to the `template` property - on a subclass. + Layout can be used to wrap content in a component. @property layout @type Function @public diff --git a/packages/ember-routing/lib/location/api.js b/packages/ember-routing/lib/location/api.js index 45009b955b3..c87aa7852a2 100644 --- a/packages/ember-routing/lib/location/api.js +++ b/packages/ember-routing/lib/location/api.js @@ -13,94 +13,14 @@ import { getHash } from './util'; ## Implementations - You can pass an implementation name (`hash`, `history`, `none`) to force a + You can pass an implementation name (`hash`, `history`, `none`, `auto`) to force a particular implementation to be used in your application. - ### HashLocation + See [Ember.Location.HashLocation](/api/classes/Ember.Location.HashLocation). + See [Ember.Location.HistoryLocation](/api/classes/Ember.Location.HistoryLocation). + See [Ember.Location.NoneLocation](/api/classes/Ember.Location.NoneLocation). + See [Ember.Location.AutoLocation](/api/classes/Ember.Location.AutoLocation). - Using `HashLocation` results in URLs with a `#` (hash sign) separating the - server side URL portion of the URL from the portion that is used by Ember. - This relies upon the `hashchange` event existing in the browser. - - Example: - - ```javascript - App.Router.map(function() { - this.route('posts', function() { - this.route('new'); - }); - }); - - App.Router.reopen({ - location: 'hash' - }); - ``` - - This will result in a posts.new url of `/#/posts/new`. - - ### HistoryLocation - - Using `HistoryLocation` results in URLs that are indistinguishable from a - standard URL. This relies upon the browser's `history` API. - - Example: - - ```javascript - App.Router.map(function() { - this.route('posts', function() { - this.route('new'); - }); - }); - - App.Router.reopen({ - location: 'history' - }); - ``` - - This will result in a posts.new url of `/posts/new`. - - Keep in mind that your server must serve the Ember app at all the routes you - define. - - ### AutoLocation - - Using `AutoLocation`, the router will use the best Location class supported by - the browser it is running in. - - Browsers that support the `history` API will use `HistoryLocation`, those that - do not, but still support the `hashchange` event will use `HashLocation`, and - in the rare case neither is supported will use `NoneLocation`. - - Example: - - ```javascript - App.Router.map(function() { - this.route('posts', function() { - this.route('new'); - }); - }); - - App.Router.reopen({ - location: 'auto' - }); - ``` - - This will result in a posts.new url of `/posts/new` for modern browsers that - support the `history` api or `/#/posts/new` for older ones, like Internet - Explorer 9 and below. - - When a user visits a link to your application, they will be automatically - upgraded or downgraded to the appropriate `Location` class, with the URL - transformed accordingly, if needed. - - Keep in mind that since some of your users will use `HistoryLocation`, your - server must serve the Ember app at all the routes you define. - - ### NoneLocation - - Using `NoneLocation` causes Ember to not store the applications URL state - in the actual URL. This is generally used for testing purposes, and is one - of the changes made when calling `App.setupForTesting()`. ## Location API @@ -128,14 +48,20 @@ import { getHash } from './util'; ```javascript import Ember from 'ember'; - export default Ember.HistoryLocation.extend({ - implementation: 'history-url-logging', + const { HistoryLocation } = Ember; - pushState: function (path) { - console.log(path); - this._super.apply(this, arguments); + export default class MyHistory { + implementation: 'my-custom-history', + constructor() { + this._history = HistoryLocation.create(...arguments); } - }); + create() { + return new this(...arguments); + } + pushState(path) { + this._history.pushState(path); + } + } ``` @class Location diff --git a/packages/ember-routing/lib/location/auto_location.js b/packages/ember-routing/lib/location/auto_location.js index de71db7f737..7313c4298b4 100644 --- a/packages/ember-routing/lib/location/auto_location.js +++ b/packages/ember-routing/lib/location/auto_location.js @@ -19,6 +19,7 @@ import { @submodule ember-routing */ + /** Ember.AutoLocation will select the best location option based off browser support with the priority order: history, hash, none. @@ -29,10 +30,39 @@ import { Keep in mind that since some of your users will use `HistoryLocation`, your server must serve the Ember app at all the routes you define. + Browsers that support the `history` API will use `HistoryLocation`, those that + do not, but still support the `hashchange` event will use `HashLocation`, and + in the rare case neither is supported will use `NoneLocation`. + + Example: + + ```javascript + App.Router.map(function() { + this.route('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'auto' + }); + ``` + + This will result in a posts.new url of `/posts/new` for modern browsers that + support the `history` api or `/#/posts/new` for older ones, like Internet + Explorer 9 and below. + + When a user visits a link to your application, they will be automatically + upgraded or downgraded to the appropriate `Location` class, with the URL + transformed accordingly, if needed. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + @class AutoLocation @namespace Ember @static - @private + @protected */ export default EmberObject.extend({ /** diff --git a/packages/ember-routing/lib/location/hash_location.js b/packages/ember-routing/lib/location/hash_location.js index 698ae0e35db..9d90f9a59e6 100644 --- a/packages/ember-routing/lib/location/hash_location.js +++ b/packages/ember-routing/lib/location/hash_location.js @@ -17,10 +17,29 @@ import EmberLocation from './api'; hash. At present, it relies on a `hashchange` event existing in the browser. + Using `HashLocation` results in URLs with a `#` (hash sign) separating the + server side URL portion of the URL from the portion that is used by Ember. + + Example: + + ```javascript + App.Router.map(function() { + this.route('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'hash' + }); + ``` + + This will result in a posts.new url of `/#/posts/new`. + @class HashLocation @namespace Ember @extends Ember.Object - @private + @protected */ export default EmberObject.extend({ implementation: 'hash', diff --git a/packages/ember-routing/lib/location/history_location.js b/packages/ember-routing/lib/location/history_location.js index 1834aad836a..714bdc2f10f 100644 --- a/packages/ember-routing/lib/location/history_location.js +++ b/packages/ember-routing/lib/location/history_location.js @@ -27,10 +27,32 @@ function _uuid() { Ember.HistoryLocation implements the location API using the browser's history.pushState API. + Using `HistoryLocation` results in URLs that are indistinguishable from a + standard URL. This relies upon the browser's `history` API. + + Example: + + ```javascript + App.Router.map(function() { + this.route('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'history' + }); + ``` + + This will result in a posts.new url of `/posts/new`. + + Keep in mind that your server must serve the Ember app at all the routes you + define. + @class HistoryLocation @namespace Ember @extends Ember.Object - @private + @protected */ export default EmberObject.extend({ implementation: 'history', diff --git a/packages/ember-routing/lib/location/none_location.js b/packages/ember-routing/lib/location/none_location.js index b16ebf74b68..a32178ad16d 100644 --- a/packages/ember-routing/lib/location/none_location.js +++ b/packages/ember-routing/lib/location/none_location.js @@ -16,10 +16,14 @@ import { Object as EmberObject } from 'ember-runtime'; don't want it to muck with the URL (for example when you embed your application in a larger page). + Using `NoneLocation` causes Ember to not store the applications URL state + in the actual URL. This is generally used for testing purposes, and is one + of the changes made when calling `App.setupForTesting()`. + @class NoneLocation @namespace Ember @extends Ember.Object - @private + @protected */ export default EmberObject.extend({ implementation: 'none', From f576b4ad30a8184bc00dc24510cd9112b0005999 Mon Sep 17 00:00:00 2001 From: Kelly Selden Date: Fri, 14 Jul 2017 10:31:35 -0700 Subject: [PATCH 165/224] [BUGFIX lts] add ember-cli-is-package-missing to dependencies --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index d098c34cfde..c15f6f40e13 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^2.0.0", "ember-cli-get-component-path-option": "^1.0.0", + "ember-cli-is-package-missing": "^1.0.0", "ember-cli-normalize-entity-name": "^1.0.0", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.1.0", From 773cd8d9dd6494fa023ed9e0be0717248c6dda0a Mon Sep 17 00:00:00 2001 From: Kelly Selden Date: Fri, 14 Jul 2017 10:37:34 -0700 Subject: [PATCH 166/224] [BUGFIX lts] add ember-router-generator to dependencies --- package.json | 1 + yarn.lock | 38 ++++++++++++-------------------------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index d098c34cfde..5637b66b31c 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "ember-cli-test-info": "^1.0.0", "ember-cli-valid-component-name": "^1.0.0", "ember-cli-version-checker": "^1.3.1", + "ember-router-generator": "^1.2.3", "handlebars": "^4.0.6", "jquery": "^3.2.1", "resolve": "^1.3.3", diff --git a/yarn.lock b/yarn.lock index d8153ba485b..f024e75f685 100644 --- a/yarn.lock +++ b/yarn.lock @@ -162,10 +162,6 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" -ansi-regex@*, ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" @@ -174,6 +170,10 @@ ansi-regex@^1.0.0, ansi-regex@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-1.1.1.tgz#41c847194646375e6a1a5d10c3ca054ef9fc980d" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" @@ -1888,7 +1888,7 @@ debug@2.6.7: dependencies: ms "2.0.0" -debuglog@*, debuglog@^1.0.1: +debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -2297,7 +2297,7 @@ ember-publisher@0.0.7: dependencies: aws-sdk "^2.0.9" -ember-router-generator@^1.0.0: +ember-router-generator@^1.0.0, ember-router-generator@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: @@ -3387,7 +3387,7 @@ ignore@^3.2.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -3886,10 +3886,6 @@ lodash._basefor@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" -lodash._baseindexof@*: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -3897,14 +3893,10 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@*, lodash._bindcallback@^3.0.0: +lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" -lodash._cacheindexof@*: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -3913,17 +3905,11 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" -lodash._createcache@*: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - dependencies: - lodash._getnative "^3.0.0" - lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" -lodash._getnative@*, lodash._getnative@^3.0.0: +lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" @@ -4035,7 +4021,7 @@ lodash.omit@^4.1.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" -lodash.restparam@*, lodash.restparam@^3.0.0: +lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -5038,7 +5024,7 @@ readable-stream@~2.0.5: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: @@ -6134,7 +6120,7 @@ uuid@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" -validate-npm-package-license@*, validate-npm-package-license@^3.0.1: +validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" dependencies: From ea1d3011023b341b767ae640ca34251f1b012a0b Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 9 Jul 2017 19:50:18 +0500 Subject: [PATCH 167/224] [BUGFIX release] enable templates read a property from a function --- packages/ember-glimmer/lib/utils/references.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/ember-glimmer/lib/utils/references.js b/packages/ember-glimmer/lib/utils/references.js index fda919586ab..e360b08385a 100644 --- a/packages/ember-glimmer/lib/utils/references.js +++ b/packages/ember-glimmer/lib/utils/references.js @@ -213,11 +213,13 @@ export class NestedPropertyReference extends PropertyReference { _parentObjectTag.update(tagForProperty(parentValue, _propertyKey)); - if (typeof parentValue === 'string' && _propertyKey === 'length') { + let parentValueType = typeof parentValue; + + if (parentValueType === 'string' && _propertyKey === 'length') { return parentValue.length; } - if (typeof parentValue === 'object' && parentValue) { + if (parentValueType === 'object' && parentValue !== null || parentValueType === 'function') { if (MANDATORY_SETTER) { watchKey(parentValue, _propertyKey); } @@ -315,7 +317,7 @@ export class SimpleHelperReference extends CachedReference { let result = helper(positionalValue, namedValue); - if (typeof result === 'object' && result !== null) { + if (typeof result === 'object' && result !== null || typeof result === 'function') { return new RootReference(result); } else { return PrimitiveReference.create(result); @@ -396,7 +398,7 @@ export class InternalHelperReference extends CachedReference { // @implements PathReference export class UnboundReference extends ConstReference { static create(value) { - if (typeof value === 'object' && value !== null) { + if (typeof value === 'object' && value !== null || typeof result === 'function') { return new UnboundReference(value); } else { return PrimitiveReference.create(value); From 6492271acc324e8d341184ea07898d3c8ecf823e Mon Sep 17 00:00:00 2001 From: Kyle Turney Date: Fri, 16 Dec 2016 17:24:06 -0600 Subject: [PATCH 168/224] [BUGFIX release] failing test for reading a property off of a function --- .../tests/integration/content-test.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/ember-glimmer/tests/integration/content-test.js b/packages/ember-glimmer/tests/integration/content-test.js index 542a05e12a2..cfd60ffa548 100644 --- a/packages/ember-glimmer/tests/integration/content-test.js +++ b/packages/ember-glimmer/tests/integration/content-test.js @@ -484,6 +484,29 @@ class DynamicContentTest extends RenderingTest { this.assertContent('hello'); this.assertInvariants(); } + + ['@test it can render a property on a function']() { + let func = () => {}; + func.aProp = 'this is a property on a function'; + + this.renderPath('func.aProp', { func }); + + this.assertContent('this is a property on a function'); + + this.assertStableRerender(); + + // this.runTask(() => set(func, 'aProp', 'still a property on a function')); + // this.assertContent('still a property on a function'); + // this.assertInvariants(); + + // func = () => {}; + // func.aProp = 'a prop on a new function'; + + // this.runTask(() => set(this.context, 'func', func)); + + // this.assertContent('a prop on a new function'); + // this.assertInvariants(); + } } const EMPTY = {}; From d006a79056b129ffca8c80e7dfee1b7ad46dd8a7 Mon Sep 17 00:00:00 2001 From: NetForce1 Date: Fri, 21 Jul 2017 08:37:53 +0200 Subject: [PATCH 169/224] [DOC release] Replace RSVP.cast with RSVP.resolve cast is dead (see: https://github.com/emberjs/ember.js/issues/13984), and should be replaced with resolve --- packages/ember-runtime/lib/mixins/promise_proxy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/promise_proxy.js b/packages/ember-runtime/lib/mixins/promise_proxy.js index 0a963c2cbfc..6a368eacb57 100644 --- a/packages/ember-runtime/lib/mixins/promise_proxy.js +++ b/packages/ember-runtime/lib/mixins/promise_proxy.js @@ -44,7 +44,7 @@ function tap(proxy, promise) { let ObjectPromiseProxy = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); let proxy = ObjectPromiseProxy.create({ - promise: Ember.RSVP.cast($.getJSON('/some/remote/data.json')) + promise: Ember.RSVP.resolve($.getJSON('/some/remote/data.json')) }); proxy.then(function(json){ @@ -67,7 +67,7 @@ function tap(proxy, promise) { When the $.getJSON completes, and the promise is fulfilled with json, the life cycle attributes will update accordingly. Note that $.getJSON doesn't return an ECMA specified promise, - it is useful to wrap this with an `RSVP.cast` so that it behaves + it is useful to wrap this with an `RSVP.resolve` so that it behaves as a spec compliant promise. ```javascript From cd150fa456a160e534a474683c844524b1d3dfb6 Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 21 Jul 2017 15:07:58 +0500 Subject: [PATCH 170/224] remove extra type check --- packages/ember-metal/lib/watching.js | 7 +------ packages/ember-runtime/lib/computed/computed_macros.js | 3 +-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/ember-metal/lib/watching.js b/packages/ember-metal/lib/watching.js index 2ea610b6f24..c939e07b28a 100644 --- a/packages/ember-metal/lib/watching.js +++ b/packages/ember-metal/lib/watching.js @@ -1,7 +1,6 @@ /** @module ember-metal */ - import { watchKey, unwatchKey @@ -40,11 +39,7 @@ export function watch(obj, _keyPath, m) { } export function isWatching(obj, key) { - if (typeof obj !== 'object' || obj === null) { - return false; - } - let meta = peekMeta(obj); - return (meta && meta.peekWatching(key)) > 0; + return watcherCount(obj, key) > 0; } export function watcherCount(obj, key) { diff --git a/packages/ember-runtime/lib/computed/computed_macros.js b/packages/ember-runtime/lib/computed/computed_macros.js index 7fa5fcd9621..0c4af53eac8 100644 --- a/packages/ember-runtime/lib/computed/computed_macros.js +++ b/packages/ember-runtime/lib/computed/computed_macros.js @@ -251,8 +251,7 @@ export function bool(dependentKey) { export function match(dependentKey, regexp) { return computed(dependentKey, function() { let value = get(this, dependentKey); - - return typeof value === 'string' ? regexp.test(value) : false; + return regexp.test(value); }); } From c39297c94044975cc8589a17d425661dfe3bcd7f Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 23 Jul 2017 13:08:25 +0500 Subject: [PATCH 171/224] convert weakmap polyfill to es6 and use native weakmap when available --- packages/ember-metal/lib/index.js | 2 +- packages/ember-metal/lib/weak_map.js | 167 ++++++++++---------- packages/ember-metal/tests/weak_map_test.js | 11 +- yarn.lock | 21 +-- 4 files changed, 86 insertions(+), 115 deletions(-) diff --git a/packages/ember-metal/lib/index.js b/packages/ember-metal/lib/index.js index 1a2c2ed94e0..d78c0e2629e 100644 --- a/packages/ember-metal/lib/index.js +++ b/packages/ember-metal/lib/index.js @@ -42,7 +42,7 @@ export { set, trySet } from './property_set'; -export { default as WeakMap } from './weak_map'; +export { default as WeakMap, WeakMapPolyfill } from './weak_map'; export { addListener, hasListeners, diff --git a/packages/ember-metal/lib/weak_map.js b/packages/ember-metal/lib/weak_map.js index 416d1e723e5..62348782134 100644 --- a/packages/ember-metal/lib/weak_map.js +++ b/packages/ember-metal/lib/weak_map.js @@ -1,4 +1,4 @@ -import { GUID_KEY } from 'ember-utils'; +import { GUID_KEY, HAS_NATIVE_WEAKMAP } from 'ember-utils'; import { peekMeta, meta as metaFor, @@ -25,107 +25,104 @@ function isObject(value) { * practice, most use cases satisfy this limitation which is why it is included * in ember-metal. */ -export default function WeakMap(iterable) { - if (!(this instanceof WeakMap)) { - throw new TypeError(`Constructor WeakMap requires 'new'`); - } - - this._id = GUID_KEY + (id++); - - if (iterable === null || iterable === undefined) { - return; - } else if (Array.isArray(iterable)) { - for (let i = 0; i < iterable.length; i++) { - let [key, value] = iterable[i]; - this.set(key, value); +export class WeakMapPolyfill { + constructor(iterable) { + this._id = GUID_KEY + (id++); + + if (iterable === null || iterable === undefined) { + return; + } else if (Array.isArray(iterable)) { + for (let i = 0; i < iterable.length; i++) { + let [key, value] = iterable[i]; + this.set(key, value); + } + } else { + throw new TypeError('The weak map constructor polyfill only supports an array argument'); } - } else { - throw new TypeError('The weak map constructor polyfill only supports an array argument'); } -} -/* - * @method get - * @param key {Object | Function} - * @return {Any} stored value - */ -WeakMap.prototype.get = function(obj) { - if (!isObject(obj)) { - return undefined; + /* + * @method get + * @param key {Object | Function} + * @return {Any} stored value + */ + get(obj) { + if (!isObject(obj)) { return undefined; } + + let meta = peekMeta(obj); + if (meta) { + let map = meta.readableWeak(); + if (map) { + if (map[this._id] === UNDEFINED) { + return undefined; + } + + return map[this._id]; + } + } } - let meta = peekMeta(obj); - if (meta) { - let map = meta.readableWeak(); - if (map) { - if (map[this._id] === UNDEFINED) { - return undefined; - } + /* + * @method set + * @param key {Object | Function} + * @param value {Any} + * @return {WeakMap} the weak map + */ + set(obj, value) { + if (!isObject(obj)) { + throw new TypeError('Invalid value used as weak map key'); + } - return map[this._id]; + if (value === undefined) { + value = UNDEFINED; } - } -}; -/* - * @method set - * @param key {Object | Function} - * @param value {Any} - * @return {WeakMap} the weak map - */ -WeakMap.prototype.set = function(obj, value) { - if (!isObject(obj)) { - throw new TypeError('Invalid value used as weak map key'); - } + metaFor(obj).writableWeak()[this._id] = value; - if (value === undefined) { - value = UNDEFINED; + return this; } - metaFor(obj).writableWeak()[this._id] = value; - - return this; -}; + /* + * @method has + * @param key {Object | Function} + * @return {boolean} if the key exists + */ + has(obj) { + if (!isObject(obj)) { return false; } + + let meta = peekMeta(obj); + if (meta) { + let map = meta.readableWeak(); + if (map) { + return map[this._id] !== undefined; + } + } -/* - * @method has - * @param key {Object | Function} - * @return {boolean} if the key exists - */ -WeakMap.prototype.has = function(obj) { - if (!isObject(obj)) { return false; } - let meta = peekMeta(obj); - if (meta) { - let map = meta.readableWeak(); - if (map) { - return map[this._id] !== undefined; + /* + * @method delete + * @param key {Object | Function} + * @return {boolean} if the key was deleted + */ + delete(obj) { + if (this.has(obj)) { + delete peekMeta(obj).writableWeak()[this._id]; + return true; + } else { + return false; } } - return false; -}; - -/* - * @method delete - * @param key {Object | Function} - * @return {boolean} if the key was deleted - */ -WeakMap.prototype.delete = function(obj) { - if (this.has(obj)) { - delete peekMeta(obj).writableWeak()[this._id]; - return true; - } else { - return false; + /* + * @method toString + * @return {String} + */ + toString() { + return '[object WeakMap]'; } -}; -/* - * @method toString - * @return {String} - */ -WeakMap.prototype.toString = function() { - return '[object WeakMap]'; -}; +} + +export default HAS_NATIVE_WEAKMAP ? WeakMap : WeakMapPolyfill; diff --git a/packages/ember-metal/tests/weak_map_test.js b/packages/ember-metal/tests/weak_map_test.js index c84fd365a1f..4810083c691 100644 --- a/packages/ember-metal/tests/weak_map_test.js +++ b/packages/ember-metal/tests/weak_map_test.js @@ -1,4 +1,4 @@ -import { WeakMap } from '..'; +import { WeakMapPolyfill as WeakMap } from '..'; QUnit.module('Ember.WeakMap'); @@ -47,15 +47,6 @@ QUnit.test('has weakMap like qualities', function(assert) { assert.strictEqual(map.get(b), undefined); }); -QUnit.test('WeakMap constructor requres new', function(assert) { - let expectedError = new TypeError(`Constructor WeakMap requires 'new'`); - - assert.throws(() => { - // jshint newcap: false - WeakMap(); - }, expectedError); -}); - QUnit.test('constructing a WeakMap with an invalid iterator throws an error', function(assert) { let expectedError = new TypeError('The weak map constructor polyfill only supports an array argument'); diff --git a/yarn.lock b/yarn.lock index f024e75f685..09949840c8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -350,10 +350,6 @@ ast-types@0.8.12: version "0.8.12" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" -ast-types@0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" - ast-types@0.9.11: version "0.9.11" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.11.tgz#371177bb59232ff5ceaa1d09ee5cad705b1a5aa9" @@ -3311,11 +3307,7 @@ homedir-polyfill@^1.0.0: dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" - -hosted-git-info@~2.1.5: +hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@~2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" @@ -5048,7 +5040,7 @@ realize-package-specifier@~3.0.3: dezalgo "^1.0.1" npm-package-arg "^4.1.1" -recast@0.10.33: +recast@0.10.33, recast@^0.10.10: version "0.10.33" resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" dependencies: @@ -5057,15 +5049,6 @@ recast@0.10.33: private "~0.1.5" source-map "~0.5.0" -recast@^0.10.10: - version "0.10.43" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" - dependencies: - ast-types "0.8.15" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - recast@^0.11.17, recast@^0.11.3: version "0.11.23" resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" From d368449c8c2009d6f14704c66963a0cdaa176fb6 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 24 Jul 2017 18:37:16 +0500 Subject: [PATCH 172/224] replace `throw` with assertion in `enumerable` --- .../ember-runtime/lib/mixins/enumerable.js | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/enumerable.js b/packages/ember-runtime/lib/mixins/enumerable.js index 45477348392..7eecd17edc8 100644 --- a/packages/ember-runtime/lib/mixins/enumerable.js +++ b/packages/ember-runtime/lib/mixins/enumerable.js @@ -28,7 +28,10 @@ import require from 'require'; let _emberA; function emberA() { - return (_emberA || (_emberA = require('ember-runtime/system/native_array').A))(); + if (_emberA === undefined) { + _emberA = require('ember-runtime/system/native_array').A; + } + return _emberA(); } const contexts = []; @@ -265,9 +268,7 @@ const Enumerable = Mixin.create({ @public */ forEach(callback, target) { - if (typeof callback !== 'function') { - throw new TypeError(); - } + assert('Enumerable#forEach expects a function as first argument.', typeof callback === 'function'); let context = popCtx(); let len = get(this, 'length'); @@ -343,6 +344,8 @@ const Enumerable = Mixin.create({ @public */ map(callback, target) { + assert('Enumerable#map expects a function as first argument.', typeof callback === 'function'); + let ret = emberA(); this.forEach((x, idx, i) => ret[idx] = callback.call(target, x, idx, i)); @@ -393,6 +396,8 @@ const Enumerable = Mixin.create({ @public */ filter(callback, target) { + assert('Enumerable#filter expects a function as first argument.', typeof callback === 'function'); + let ret = emberA(); this.forEach((x, idx, i) => { @@ -432,6 +437,8 @@ const Enumerable = Mixin.create({ @public */ reject(callback, target) { + assert('Enumerable#reject expects a function as first argument.', typeof callback === 'function'); + return this.filter(function() { return !(callback.apply(target, arguments)); }); @@ -501,6 +508,8 @@ const Enumerable = Mixin.create({ @public */ find(callback, target) { + assert('Enumerable#find expects a function as first argument.', typeof callback === 'function'); + let len = get(this, 'length'); if (target === undefined) { @@ -582,6 +591,8 @@ const Enumerable = Mixin.create({ @public */ every(callback, target) { + assert('Enumerable#every expects a function as first argument.', typeof callback === 'function'); + return !this.find((x, idx, i) => !callback.call(target, x, idx, i)); }, @@ -639,6 +650,8 @@ const Enumerable = Mixin.create({ @public */ any(callback, target) { + assert('Enumerable#any expects a function as first argument.', typeof callback === 'function'); + let len = get(this, 'length'); let context = popCtx(); let found = false; @@ -711,9 +724,7 @@ const Enumerable = Mixin.create({ @public */ reduce(callback, initialValue, reducerProperty) { - if (typeof callback !== 'function') { - throw new TypeError(); - } + assert('Enumerable#reduce expects a function as first argument.', typeof callback === 'function'); let ret = initialValue; From 9b0f7591f4373445f98a15c80fbbb0fb8aa57cfc Mon Sep 17 00:00:00 2001 From: kumkanillam Date: Mon, 24 Jul 2017 17:22:46 +0530 Subject: [PATCH 173/224] [DOC release]missed code block added --- packages/ember-routing/lib/system/route.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index 66793dfbaa3..d4ab02a3fd1 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -2119,7 +2119,8 @@ let Route = EmberObject.extend(ActionHandler, Evented, { } } }); - + ``` + @method disconnectOutlet @param {Object|String} options the options hash or outlet name @since 1.0.0 From 388fac59bef8d00c1e7ff207cc1e96901c5d6068 Mon Sep 17 00:00:00 2001 From: anon4562 <5o20od+9em5xhwulvet4@sharklasers.com> Date: Thu, 22 Dec 2016 10:26:41 -0800 Subject: [PATCH 174/224] [BUGFIX beta] Reusing element causes problems in Safari When testing allowed input types, in some versions of Safari the type cannot be change to `file` if previously set to a different one. Fixes #14727 --- packages/ember-glimmer/lib/components/text_field.js | 5 +---- .../ember-glimmer/tests/integration/helpers/input-test.js | 7 +++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/ember-glimmer/lib/components/text_field.js b/packages/ember-glimmer/lib/components/text_field.js index 84e0306c49d..161fac6455a 100644 --- a/packages/ember-glimmer/lib/components/text_field.js +++ b/packages/ember-glimmer/lib/components/text_field.js @@ -8,7 +8,6 @@ import Component from '../component'; import layout from '../templates/empty'; import { TextSupport } from 'ember-views'; -let inputTypeTestElement; const inputTypes = Object.create(null); function canSetTypeOfInput(type) { if (type in inputTypes) { @@ -23,9 +22,7 @@ function canSetTypeOfInput(type) { return type; } - if (!inputTypeTestElement) { - inputTypeTestElement = document.createElement('input'); - } + let inputTypeTestElement = document.createElement('input'); try { inputTypeTestElement.type = type; diff --git a/packages/ember-glimmer/tests/integration/helpers/input-test.js b/packages/ember-glimmer/tests/integration/helpers/input-test.js index 36150bb024a..aed3252c66e 100644 --- a/packages/ember-glimmer/tests/integration/helpers/input-test.js +++ b/packages/ember-glimmer/tests/integration/helpers/input-test.js @@ -425,6 +425,13 @@ moduleFor('Helpers test: {{input}}', class extends InputRenderingTest { keyCode: 65 }); } + + ['@test GH#14727 can render a file input after having had render an input of other type']() { + this.render(`{{input type="text"}}{{input type="file"}}`); + + this.assert.equal(this.$input()[0].type, 'text'); + this.assert.equal(this.$input()[1].type, 'file'); + } }); moduleFor('Helpers test: {{input}} with dynamic type', class extends InputRenderingTest { From e76e6dda6a7866b72fada57053181d88477d1d4a Mon Sep 17 00:00:00 2001 From: "J. Lopez" Date: Tue, 25 Jul 2017 13:56:20 -0400 Subject: [PATCH 175/224] [DOC release] Update wait.js - Add missing backticks to code snippet. --- packages/ember-testing/lib/helpers/wait.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember-testing/lib/helpers/wait.js b/packages/ember-testing/lib/helpers/wait.js index 70e52639476..9da91cbe61f 100644 --- a/packages/ember-testing/lib/helpers/wait.js +++ b/packages/ember-testing/lib/helpers/wait.js @@ -27,6 +27,7 @@ import { pendingRequests } from '../test/pending_requests'; .fillIn('#password', password) .click('.submit'); }); + ``` @method wait @param {Object} value The value to be returned. From ea1c8db2a31afedd2ea76215835f384cdbb0c088 Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 26 Jul 2017 12:59:54 +0500 Subject: [PATCH 176/224] avoid expanding already expanded property key in computed.sort --- .../lib/computed/reduce_computed_macros.js | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/packages/ember-runtime/lib/computed/reduce_computed_macros.js b/packages/ember-runtime/lib/computed/reduce_computed_macros.js index 657d8c1b63f..aa27ce3c96a 100644 --- a/packages/ember-runtime/lib/computed/reduce_computed_macros.js +++ b/packages/ember-runtime/lib/computed/reduce_computed_macros.js @@ -716,7 +716,6 @@ function customSort(itemsKey, comparator) { // depending on the sortProperties function propertySort(itemsKey, sortPropertiesKey) { let cp = new ComputedProperty(function(key) { - let itemsKeyIsAtThis = (itemsKey === '@this'); let sortProperties = get(this, sortPropertiesKey); assert( @@ -724,42 +723,37 @@ function propertySort(itemsKey, sortPropertiesKey) { isArray(sortProperties) && sortProperties.every(s => typeof s === 'string') ); - let normalizedSortProperties = normalizeSortProperties(sortProperties); - // Add/remove property observers as required. let activeObserversMap = cp._activeObserverMap || (cp._activeObserverMap = new WeakMap()); let activeObservers = activeObserversMap.get(this); - if (activeObservers) { + if (activeObservers !== undefined) { activeObservers.forEach(args => removeObserver(...args)); } + let itemsKeyIsAtThis = (itemsKey === '@this'); + let items = itemsKeyIsAtThis ? this : get(this, itemsKey); + if (!isArray(items)) { return emberA(); } + function sortPropertyDidChange() { this.notifyPropertyChange(key); } + let normalizedSortProperties = normalizeSortProperties(sortProperties); activeObservers = normalizedSortProperties.map(([prop]) => { let path = itemsKeyIsAtThis ? `@each.${prop}` : `${itemsKey}.@each.${prop}`; - let args = [this, path, sortPropertyDidChange]; - addObserver(...args); - return args; + addObserver(this, path, sortPropertyDidChange); + return [this, path, sortPropertyDidChange]; }); activeObserversMap.set(this, activeObservers); - // Sort and return the array. - let items = itemsKeyIsAtThis ? this : get(this, itemsKey); - - if (isArray(items)) { - return sortByNormalizedSortProperties(items, normalizedSortProperties); - } else { - return emberA(); - } - }); + return sortByNormalizedSortProperties(items, normalizedSortProperties); + }, { dependentKeys: [`${sortPropertiesKey}.[]`] }); cp._activeObserverMap = undefined; - return cp.property(`${sortPropertiesKey}.[]`).readOnly(); + return cp.readOnly(); } function normalizeSortProperties(sortProperties) { From 0b751758b364d78eff04646f5e4a67077376740e Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 26 Jul 2017 13:26:07 +0500 Subject: [PATCH 177/224] avoid expanding already expanded property key in reduceMacro/arrayMacro/multiArrayMacro --- .../lib/computed/computed_macros.js | 10 +++---- .../lib/computed/reduce_computed_macros.js | 26 ++++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/ember-runtime/lib/computed/computed_macros.js b/packages/ember-runtime/lib/computed/computed_macros.js index 0c4af53eac8..0461f121219 100644 --- a/packages/ember-runtime/lib/computed/computed_macros.js +++ b/packages/ember-runtime/lib/computed/computed_macros.js @@ -37,20 +37,20 @@ function expandPropertiesToArray(predicateName, properties) { function generateComputedWithPredicate(name, predicate) { return (...properties) => { - let expandedProperties = expandPropertiesToArray(name, properties); + let dependentKeys = expandPropertiesToArray(name, properties); let computedFunc = new ComputedProperty(function() { - let lastIdx = expandedProperties.length - 1; + let lastIdx = dependentKeys.length - 1; for (let i = 0; i < lastIdx; i++) { - let value = get(this, expandedProperties[i]); + let value = get(this, dependentKeys[i]); if (!predicate(value)) { return value; } } - return get(this, expandedProperties[lastIdx]); - }, { dependentKeys: expandedProperties }); + return get(this, dependentKeys[lastIdx]); + }, { dependentKeys }); return computedFunc; }; diff --git a/packages/ember-runtime/lib/computed/reduce_computed_macros.js b/packages/ember-runtime/lib/computed/reduce_computed_macros.js index aa27ce3c96a..11ef3aa589c 100644 --- a/packages/ember-runtime/lib/computed/reduce_computed_macros.js +++ b/packages/ember-runtime/lib/computed/reduce_computed_macros.js @@ -20,13 +20,13 @@ import { A as emberA } from '../system/native_array'; function reduceMacro(dependentKey, callback, initialValue) { - return computed(`${dependentKey}.[]`, function() { + let cp = new ComputedProperty(function() { let arr = get(this, dependentKey); - if (arr === null || typeof arr !== 'object') { return initialValue; } - return arr.reduce(callback, initialValue, this); - }).readOnly(); + }, { dependentKeys: [`${dependentKey}.[]`] }) + + return cp.readOnly(); } function arrayMacro(dependentKey, callback) { @@ -39,24 +39,26 @@ function arrayMacro(dependentKey, callback) { dependentKey += '.[]'; } - return computed(dependentKey, function() { + let cp = new ComputedProperty(function() { let value = get(this, propertyName); if (isArray(value)) { return emberA(callback.call(this, value)); } else { return emberA(); } - }).readOnly(); + }, { dependentKeys: [ dependentKey ] }); + + return cp.readOnly(); } -function multiArrayMacro(dependentKeys, callback) { - let args = dependentKeys.map(key => `${key}.[]`); +function multiArrayMacro(_dependentKeys, callback) { + let dependentKeys = _dependentKeys.map(key => `${key}.[]`); - args.push(function() { - return emberA(callback.call(this, dependentKeys)); - }); + let cp = new ComputedProperty(function() { + return emberA(callback.call(this, _dependentKeys)); + }, { dependentKeys }); - return computed.apply(this, args).readOnly(); + return cp.readOnly(); } /** From ba3d6f467cf8c7e3752b613fcdd850412e275ece Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 26 Jul 2017 13:34:34 +0500 Subject: [PATCH 178/224] avoid boolean coarsion --- packages/ember-metal/lib/weak_map.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-metal/lib/weak_map.js b/packages/ember-metal/lib/weak_map.js index 62348782134..3b9aa6156c2 100644 --- a/packages/ember-metal/lib/weak_map.js +++ b/packages/ember-metal/lib/weak_map.js @@ -52,12 +52,12 @@ export class WeakMapPolyfill { let meta = peekMeta(obj); if (meta) { let map = meta.readableWeak(); - if (map) { - if (map[this._id] === UNDEFINED) { + if (map !== undefined) { + let val = map[this._id]; + if (val === UNDEFINED) { return undefined; } - - return map[this._id]; + return val; } } } @@ -93,7 +93,7 @@ export class WeakMapPolyfill { let meta = peekMeta(obj); if (meta) { let map = meta.readableWeak(); - if (map) { + if (map !== undefined) { return map[this._id] !== undefined; } } From 3b12df863750c5d52662b812227fdda72244f029 Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 26 Jul 2017 11:18:16 +0500 Subject: [PATCH 179/224] use safe `toString` for array content in `mixins/array` --- packages/ember-runtime/lib/mixins/array.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/array.js b/packages/ember-runtime/lib/mixins/array.js index 9d931333bd0..25fe6d33f76 100644 --- a/packages/ember-runtime/lib/mixins/array.js +++ b/packages/ember-runtime/lib/mixins/array.js @@ -6,8 +6,7 @@ // .......................................................... // HELPERS // -import { symbol } from 'ember-utils'; - +import { symbol, toString } from 'ember-utils'; import Ember, { // ES6TODO: Ember.A get, computed, @@ -743,7 +742,7 @@ function addObserverForContentKey(content, keyName, proxy, idx, loc) { while (--loc >= idx) { let item = objectAt(content, loc); if (item) { - assert(`When using @each to observe the array ${content}, the array must return an object`, typeof item === 'object'); + assert(`When using @each to observe the array \`${toString(content)}\`, the array must return an object`, typeof item === 'object'); _addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); addObserver(item, keyName, proxy, 'contentKeyDidChange'); } From 49f01699a9c209c3134ac85895cba4456a58b935 Mon Sep 17 00:00:00 2001 From: bekzod Date: Wed, 26 Jul 2017 23:19:55 +0500 Subject: [PATCH 180/224] reuse meta `arrayContentDidChange` --- packages/ember-runtime/lib/mixins/array.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/array.js b/packages/ember-runtime/lib/mixins/array.js index 25fe6d33f76..0f3b103c1d8 100644 --- a/packages/ember-runtime/lib/mixins/array.js +++ b/packages/ember-runtime/lib/mixins/array.js @@ -149,16 +149,16 @@ export function arrayContentDidChange(array, startIdx, removeAmt, addAmt) { let normalStartIdx = startIdx < 0 ? previousLength + startIdx : startIdx; if (cache.firstObject !== undefined && normalStartIdx === 0) { - propertyWillChange(array, 'firstObject'); - propertyDidChange(array, 'firstObject'); + propertyWillChange(array, 'firstObject', meta); + propertyDidChange(array, 'firstObject', meta); } if (cache.lastObject !== undefined) { let previousLastIndex = previousLength - 1; let lastAffectedIndex = normalStartIdx + removedAmount; if (previousLastIndex < lastAffectedIndex) { - propertyWillChange(array, 'lastObject'); - propertyDidChange(array, 'lastObject'); + propertyWillChange(array, 'lastObject', meta); + propertyDidChange(array, 'lastObject', meta); } } } From 2b0918303ce33256b5ae8505193b6e490c161251 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 27 Jul 2017 13:49:46 +0500 Subject: [PATCH 181/224] avoid boolean coarsion in weak_map --- packages/ember-metal/lib/weak_map.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-metal/lib/weak_map.js b/packages/ember-metal/lib/weak_map.js index 416d1e723e5..224f976e09b 100644 --- a/packages/ember-metal/lib/weak_map.js +++ b/packages/ember-metal/lib/weak_map.js @@ -57,12 +57,12 @@ WeakMap.prototype.get = function(obj) { let meta = peekMeta(obj); if (meta) { let map = meta.readableWeak(); - if (map) { - if (map[this._id] === UNDEFINED) { + if (map !== undefined) { + let val = map[this._id]; + if (val === UNDEFINED) { return undefined; } - - return map[this._id]; + return val; } } }; @@ -100,7 +100,7 @@ WeakMap.prototype.has = function(obj) { let meta = peekMeta(obj); if (meta) { let map = meta.readableWeak(); - if (map) { + if (map !== undefined) { return map[this._id] !== undefined; } } From e2f4d058a4e766b49c5917c3f32f951e842c3557 Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 27 Jul 2017 13:50:14 +0500 Subject: [PATCH 182/224] avoid boolean coarsion in `computed` --- packages/ember-metal/lib/computed.js | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/packages/ember-metal/lib/computed.js b/packages/ember-metal/lib/computed.js index 6276ff701a4..df39b900569 100644 --- a/packages/ember-metal/lib/computed.js +++ b/packages/ember-metal/lib/computed.js @@ -142,7 +142,7 @@ function ComputedProperty(config, opts) { this._meta = undefined; this._volatile = false; this._dependentKeys = opts && opts.dependentKeys; - this._readOnly = false; + this._readOnly = false; } ComputedProperty.prototype = new Descriptor(); @@ -304,7 +304,7 @@ ComputedPropertyPrototype.didChange = function(obj, keyName) { } let cache = meta.readableCache(); - if (cache && cache[keyName] !== undefined) { + if (cache !== undefined && cache[keyName] !== undefined) { cache[keyName] = undefined; removeDependentKeys(this, obj, keyName, meta); } @@ -326,14 +326,10 @@ ComputedPropertyPrototype.get = function(obj, keyName) { } let ret = this._getter.call(obj, keyName); - if (ret === undefined) { - cache[keyName] = UNDEFINED; - } else { - cache[keyName] = ret; - } + cache[keyName] = ret === undefined ? UNDEFINED : ret; let chainWatchers = meta.readableChainWatchers(); - if (chainWatchers) { + if (chainWatchers !== undefined) { chainWatchers.revalidate(keyName); } addDependentKeys(this, obj, keyName, meta); @@ -383,15 +379,14 @@ ComputedPropertyPrototype.setWithSuspend = function computedPropertySetWithSuspe }; ComputedPropertyPrototype._set = function computedPropertySet(obj, keyName, value) { - // cache requires own meta - let meta = metaFor(obj); - // either there is a writable cache or we need one to update - let cache = meta.writableCache(); + let meta = metaFor(obj); + let cache = meta.writableCache(); let hadCachedValue = false; let cachedValue; - if (cache[keyName] !== undefined) { - if (cache[keyName] !== UNDEFINED) { - cachedValue = cache[keyName]; + let val = cache[keyName]; + if (val !== undefined) { + if (val !== UNDEFINED) { + cachedValue = val; } hadCachedValue = true; } From 64209e0f4ed1db2d2fb72f9a92e400fb6711e0e5 Mon Sep 17 00:00:00 2001 From: _nkgm Date: Mon, 31 Jul 2017 12:27:31 +0300 Subject: [PATCH 183/224] [DOC] Improve Ember.isEmpty --- packages/ember-metal/lib/is_empty.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-metal/lib/is_empty.js b/packages/ember-metal/lib/is_empty.js index 5e1b208ad93..9576d07ac3d 100644 --- a/packages/ember-metal/lib/is_empty.js +++ b/packages/ember-metal/lib/is_empty.js @@ -2,11 +2,11 @@ import { get } from './property_get'; import isNone from './is_none'; /** - Verifies that a value is `null` or an empty string, empty array, - or empty function. + Verifies that a value is `null` or `undefined`, an empty string, or an empty + array. - Constrains the rules on `Ember.isNone` by returning true for empty - string and empty arrays. + Constrains the rules on `Ember.isNone` by returning true for empty strings and + empty arrays. ```javascript Ember.isEmpty(); // true From dc60f97e9dab2479ff78d696ca6a0b4acf486d01 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 31 Jul 2017 15:52:23 +0500 Subject: [PATCH 184/224] remove unused imports --- packages/ember-routing/lib/services/router.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ember-routing/lib/services/router.js b/packages/ember-routing/lib/services/router.js index c1a3b9797ac..3b415b3dc20 100644 --- a/packages/ember-routing/lib/services/router.js +++ b/packages/ember-routing/lib/services/router.js @@ -7,9 +7,7 @@ import { Service, readOnly } from 'ember-runtime'; -import { assign } from 'ember-utils'; import { shallowEqual } from '../utils'; -import RouterDSL from '../system/dsl'; /** The Router service is the public API that provides component/view layer From 205827276b4cedf191e29ec30120523790d0d6da Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Wed, 19 Jul 2017 17:41:41 +0100 Subject: [PATCH 185/224] Remove ControllerContentModelAliasDeprecation for deprecatingAlias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So, this is kind of a fun one. From what I can tell, `ControllerContentModelAliasDeprecation` was introduced, due to Controllers having a `content` property, which `model` was aliased to. This was done because `ObjectController` and `ArrayController` were proxying controllers. But, in Ember, routes set up the `model` property of its respective controller. What this meant is that if someone declared a `content` property in their controller, `model` would—seemingly unrelated—break, hence the `ControllerContentModelAliasDeprecation` mixin. Nowadays it is fine to override `content` because the source of truth was reverse, and `model` is now the primary property, being `content` the alias. It is, then, time to remove the old deprecation and instead deprecate the alias itself, so that in the future users can define a `content` property in their controllers if they so desire. Another API bites the dust. Here's to removing yet more code in the future, and make Ember sparkle-clean. --- features.json | 2 +- .../ember-runtime/lib/mixins/controller.js | 13 +++-- ...troller_content_model_alias_deprecation.js | 49 ------------------- .../tests/controllers/controller_test.js | 29 ++++++----- 4 files changed, 25 insertions(+), 68 deletions(-) delete mode 100644 packages/ember-runtime/lib/mixins/controller_content_model_alias_deprecation.js diff --git a/features.json b/features.json index 5c4ee8a2222..d9caf942b7a 100644 --- a/features.json +++ b/features.json @@ -35,10 +35,10 @@ "ember-views.render-double-modify": "2.0.0", "ember-routing.router-resource": "2.0.0", "ember-routing.top-level-render-helper": "2.11.0", + "ember-runtime.controller-content": "2.16.0", "ember-runtime.controller-proxy": "2.0.0", "ember-runtime.action-handler-_actions": "2.0.0", "ember-runtime.enumerable-contains": "2.7.0", - "ember-runtime.will-merge-mixin": "2.0.0", "ember-runtime.frozen-copy": "2.0.0", "ember-runtime.freezable-init": "2.0.0", "ember-string-utils.fmt": "2.0.0", diff --git a/packages/ember-runtime/lib/mixins/controller.js b/packages/ember-runtime/lib/mixins/controller.js index c5363b6d4ff..5ada9d2be34 100644 --- a/packages/ember-runtime/lib/mixins/controller.js +++ b/packages/ember-runtime/lib/mixins/controller.js @@ -1,6 +1,6 @@ import { Mixin, alias } from 'ember-metal'; +import { deprecatingAlias } from '../computed/computed_macros'; import ActionHandler from './action_handler'; -import ControllerContentModelAliasDeprecation from './controller_content_model_alias_deprecation'; /** @class ControllerMixin @@ -8,7 +8,7 @@ import ControllerContentModelAliasDeprecation from './controller_content_model_a @uses Ember.ActionHandler @private */ -export default Mixin.create(ActionHandler, ControllerContentModelAliasDeprecation, { +export default Mixin.create(ActionHandler, { /* ducktype as a controller */ isController: true, @@ -38,12 +38,15 @@ export default Mixin.create(ActionHandler, ControllerContentModelAliasDeprecatio @property model @public - */ + */ model: null, /** @private */ - content: alias('model') - + content: deprecatingAlias('model', { + id: 'ember-runtime.controller.content-alias', + until: '2.17.0', + url: 'https://emberjs.com/deprecations/v2.x/#toc_controller-content-alias' + }) }); diff --git a/packages/ember-runtime/lib/mixins/controller_content_model_alias_deprecation.js b/packages/ember-runtime/lib/mixins/controller_content_model_alias_deprecation.js deleted file mode 100644 index 4f59c8fa383..00000000000 --- a/packages/ember-runtime/lib/mixins/controller_content_model_alias_deprecation.js +++ /dev/null @@ -1,49 +0,0 @@ -import { Mixin } from 'ember-metal'; -import { deprecate } from 'ember-debug'; - -/* - The ControllerContentModelAliasDeprecation mixin is used to provide a useful - deprecation warning when specifying `content` directly on a `Ember.Controller` - (without also specifying `model`). - - Ember versions prior to 1.7 used `model` as an alias of `content`, but due to - much confusion this alias was reversed (so `content` is now an alias of `model). - - This change reduces many caveats with model/content, and also sets a - simple ground rule: Never set a controllers content, rather always set - its model and ember will do the right thing. - - Used internally by Ember in `Ember.Controller`. -*/ -export default Mixin.create({ - /** - @private - - Moves `content` to `model` at extend time if a `model` is not also specified. - - Note that this currently modifies the mixin themselves, which is technically - dubious but is practically of little consequence. This may change in the - future. - - @method willMergeMixin - @since 1.4.0 - */ - willMergeMixin(props) { - // Calling super is only OK here since we KNOW that - // there is another Mixin loaded first. - this._super(...arguments); - - let modelSpecified = !!props.model; - - if (props.content && !modelSpecified) { - props.model = props.content; - delete props['content']; - - deprecate( - 'Do not specify `content` on a Controller, use `model` instead.', - false, - { id: 'ember-runtime.will-merge-mixin', until: '3.0.0' } - ); - } - } -}); diff --git a/packages/ember-runtime/tests/controllers/controller_test.js b/packages/ember-runtime/tests/controllers/controller_test.js index 8ea64577180..75a26ef6d74 100644 --- a/packages/ember-runtime/tests/controllers/controller_test.js +++ b/packages/ember-runtime/tests/controllers/controller_test.js @@ -102,16 +102,18 @@ QUnit.module('Controller deprecations'); QUnit.module('Controller Content -> Model Alias'); -QUnit.test('`model` is aliased as `content`', function() { - expect(1); +QUnit.test('`content` is a deprecated alias of `model`', function() { + expect(2); let controller = Controller.extend({ model: 'foo-bar' }).create(); - equal(controller.get('content'), 'foo-bar', 'content is an alias of model'); + expectDeprecation(function () { + equal(controller.get('content'), 'foo-bar', 'content is an alias of model'); + }); }); -QUnit.test('`content` is moved to `model` when `model` is unset', function() { +QUnit.test('`content` is not moved to `model` when `model` is unset', function() { expect(2); let controller; @@ -121,18 +123,19 @@ QUnit.test('`content` is moved to `model` when `model` is unset', function() { }).create(); }); - equal(controller.get('model'), 'foo-bar', 'model is set properly'); - equal(controller.get('content'), 'foo-bar', 'content is set properly'); + notEqual(controller.get('model'), 'foo-bar', 'model is set properly'); + equal(controller.get('content'), 'foo-bar', 'content is not set properly'); }); -QUnit.test('specifying `content` (without `model` specified) results in deprecation', function() { - expect(1); +QUnit.test('specifying `content` (without `model` specified) does not result in deprecation', function() { + expect(2); + expectNoDeprecation(); - expectDeprecation(function() { - Controller.extend({ - content: 'foo-bar' - }).create(); - }, 'Do not specify `content` on a Controller, use `model` instead.'); + let controller = Controller.extend({ + content: 'foo-bar' + }).create(); + + equal(get(controller, 'content'), 'foo-bar'); }); QUnit.test('specifying `content` (with `model` specified) does not result in deprecation', function() { From 201c656f1bb2cdd2b945ba2e80e472a68c4ecdfc Mon Sep 17 00:00:00 2001 From: bekzod Date: Tue, 1 Aug 2017 16:27:59 +0500 Subject: [PATCH 186/224] micro optimization in `enumerable` --- packages/ember-routing/lib/location/none_location.js | 6 ++++-- packages/ember-runtime/lib/mixins/enumerable.js | 11 ++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/ember-routing/lib/location/none_location.js b/packages/ember-routing/lib/location/none_location.js index a32178ad16d..9ec96cda9f8 100644 --- a/packages/ember-routing/lib/location/none_location.js +++ b/packages/ember-routing/lib/location/none_location.js @@ -32,8 +32,10 @@ export default EmberObject.extend({ detect() { let rootURL = this.rootURL; - assert('rootURL must end with a trailing forward slash e.g. "/app/"', - rootURL.charAt(rootURL.length - 1) === '/'); + assert( + 'rootURL must end with a trailing forward slash e.g. "/app/"', + rootURL.charAt(rootURL.length - 1) === '/' + ); }, /** diff --git a/packages/ember-runtime/lib/mixins/enumerable.js b/packages/ember-runtime/lib/mixins/enumerable.js index 7eecd17edc8..eabd19893dd 100644 --- a/packages/ember-runtime/lib/mixins/enumerable.js +++ b/packages/ember-runtime/lib/mixins/enumerable.js @@ -48,12 +48,9 @@ function pushCtx(ctx) { function iter(key, value) { let valueProvided = arguments.length === 2; - function i(item) { - let cur = get(item, key); - return valueProvided ? value === cur : !!cur; - } - - return i; + return valueProvided ? + (item)=> value === get(item, key) : + (item)=> !!get(item, key); } /** @@ -753,7 +750,7 @@ const Enumerable = Mixin.create({ let method = x && x[methodName]; if ('function' === typeof method) { - ret[idx] = args ? method.apply(x, args) : x[methodName](); + ret[idx] = args.length ? method.apply(x, args) : x[methodName](); } }, this); From 16f8ca8ed82c4b40666f4cee9faa472c059f71ed Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Tue, 1 Aug 2017 10:23:12 -0400 Subject: [PATCH 187/224] [DOCS] Use shorthand for inject.service example --- packages/ember-runtime/lib/system/service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-runtime/lib/system/service.js b/packages/ember-runtime/lib/system/service.js index bfc5e674aaf..0560825f9d6 100644 --- a/packages/ember-runtime/lib/system/service.js +++ b/packages/ember-runtime/lib/system/service.js @@ -12,7 +12,7 @@ import { createInjectionHelper } from '../inject'; App.ApplicationRoute = Ember.Route.extend({ authManager: Ember.inject.service('auth'), - model: function() { + model() { return this.get('authManager').findCurrentUser(); } }); From e32d1cd7849b17efcc03065ea1583f889c2b9ac2 Mon Sep 17 00:00:00 2001 From: David Yan Date: Wed, 2 Aug 2017 08:42:40 -0700 Subject: [PATCH 188/224] Super minor docs improvement --- packages/ember-glimmer/lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-glimmer/lib/index.js b/packages/ember-glimmer/lib/index.js index 794f008b66e..f59ef149f0a 100644 --- a/packages/ember-glimmer/lib/index.js +++ b/packages/ember-glimmer/lib/index.js @@ -81,7 +81,7 @@ for semantic clarity as it allows you to retain default scope or to reference a property from another `{{with}}` block. - If the aliased property is "falsey", for example: `false`, `undefined` `null`, `""`, `0`, NaN or + If the aliased property is "falsey", for example: `false`, `undefined` `null`, `""`, `0`, `NaN` or an empty array, the block will not be rendered. ```handlebars From c74f76ca663db7a47fac8abae0271bd48656cd7a Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 27 Jul 2017 14:15:48 +0500 Subject: [PATCH 189/224] check `meta` for being `undefined` only --- packages/ember-metal/lib/chains.js | 8 +++----- packages/ember-metal/lib/computed.js | 2 +- packages/ember-metal/lib/events.js | 2 +- packages/ember-metal/lib/is_proxy.js | 2 +- packages/ember-metal/lib/mixin.js | 4 ++-- packages/ember-metal/lib/properties.js | 8 +++----- packages/ember-metal/lib/watch_key.js | 2 +- packages/ember-runtime/lib/mixins/array.js | 2 +- 8 files changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/ember-metal/lib/chains.js b/packages/ember-metal/lib/chains.js index 65273bcb789..4213570db2b 100644 --- a/packages/ember-metal/lib/chains.js +++ b/packages/ember-metal/lib/chains.js @@ -113,13 +113,11 @@ function addChainWatcher(obj, keyName, node) { } function removeChainWatcher(obj, keyName, node, _meta) { - if (!isObject(obj)) { - return; - } + if (!isObject(obj)) { return; } - let meta = _meta || peekMeta(obj); + let meta = _meta === undefined ? peekMeta(obj) : _meta; - if (!meta || !meta.readableChainWatchers()) { + if (meta === undefined || meta.readableChainWatchers() === undefined) { return; } diff --git a/packages/ember-metal/lib/computed.js b/packages/ember-metal/lib/computed.js index df39b900569..2671fa04427 100644 --- a/packages/ember-metal/lib/computed.js +++ b/packages/ember-metal/lib/computed.js @@ -299,7 +299,7 @@ ComputedPropertyPrototype.didChange = function(obj, keyName) { // don't create objects just to invalidate let meta = peekMeta(obj); - if (!meta || meta.source !== obj) { + if (meta === undefined || meta.source !== obj) { return; } diff --git a/packages/ember-metal/lib/events.js b/packages/ember-metal/lib/events.js index c09dc314050..ceb8ee940f8 100644 --- a/packages/ember-metal/lib/events.js +++ b/packages/ember-metal/lib/events.js @@ -210,7 +210,7 @@ export function sendEvent(obj, eventName, params, actions, _meta) { */ export function hasListeners(obj, eventName) { let meta = peekMeta(obj); - if (!meta) { return false; } + if (meta === undefined) { return false; } let matched = meta.matchingListeners(eventName); return matched !== undefined && matched.length > 0; } diff --git a/packages/ember-metal/lib/is_proxy.js b/packages/ember-metal/lib/is_proxy.js index c1ac7dd2a0b..0ddd6b680d9 100644 --- a/packages/ember-metal/lib/is_proxy.js +++ b/packages/ember-metal/lib/is_proxy.js @@ -3,7 +3,7 @@ import { peekMeta } from './meta'; export function isProxy(value) { if (typeof value === 'object' && value !== null) { let meta = peekMeta(value); - return meta && meta.isProxy(); + return meta === undefined ? false : meta.isProxy(); } return false; diff --git a/packages/ember-metal/lib/mixin.js b/packages/ember-metal/lib/mixin.js index 00630226f29..9be38d79129 100644 --- a/packages/ember-metal/lib/mixin.js +++ b/packages/ember-metal/lib/mixin.js @@ -516,7 +516,7 @@ export default class Mixin { static mixins(obj) { let meta = peekMeta(obj); let ret = []; - if (!meta) { return ret; } + if (meta === undefined) { return ret; } meta.forEachMixins((key, currentMixin) => { // skip primitive mixins since these are always anonymous @@ -621,7 +621,7 @@ MixinPrototype.detect = function(obj) { if (typeof obj !== 'object' || obj === null) { return false; } if (obj instanceof Mixin) { return _detect(obj, this, {}); } let meta = peekMeta(obj); - if (!meta) { return false; } + if (meta === undefined) { return false; } return !!meta.peekMixins(guidFor(this)); }; diff --git a/packages/ember-metal/lib/properties.js b/packages/ember-metal/lib/properties.js index b981a02709e..f6df5b3f05d 100644 --- a/packages/ember-metal/lib/properties.js +++ b/packages/ember-metal/lib/properties.js @@ -58,7 +58,7 @@ export function MANDATORY_SETTER_FUNCTION(name) { export function DEFAULT_GETTER_FUNCTION(name) { return function GETTER_FUNCTION() { let meta = peekMeta(this); - if (meta !== null && meta !== undefined) { + if (meta !== undefined) { return meta.peekValues(name); } }; @@ -68,7 +68,7 @@ export function INHERITING_GETTER_FUNCTION(name) { function IGETTER_FUNCTION() { let meta = peekMeta(this); let val; - if (meta !== null && meta !== undefined) { + if (meta !== undefined) { val = meta.readInheritedValue('values', name); } @@ -130,9 +130,7 @@ export function INHERITING_GETTER_FUNCTION(name) { become the explicit value of this property. */ export function defineProperty(obj, keyName, desc, data, meta) { - if (meta === null || meta === undefined) { - meta = metaFor(obj); - } + if (meta === undefined) { meta = metaFor(obj); } let watchEntry = meta.peekWatching(keyName); let watching = watchEntry !== undefined && watchEntry > 0; diff --git a/packages/ember-metal/lib/watch_key.js b/packages/ember-metal/lib/watch_key.js index 36304f07cd8..da941d53852 100644 --- a/packages/ember-metal/lib/watch_key.js +++ b/packages/ember-metal/lib/watch_key.js @@ -87,7 +87,7 @@ export function unwatchKey(obj, keyName, _meta) { let meta = _meta || peekMeta(obj); // do nothing of this object has already been destroyed - if (!meta || meta.isSourceDestroyed()) { return; } + if (meta === undefined || meta.isSourceDestroyed()) { return; } let count = meta.peekWatching(keyName); if (count === 1) { diff --git a/packages/ember-runtime/lib/mixins/array.js b/packages/ember-runtime/lib/mixins/array.js index 25fe6d33f76..f364798217b 100644 --- a/packages/ember-runtime/lib/mixins/array.js +++ b/packages/ember-runtime/lib/mixins/array.js @@ -139,7 +139,7 @@ export function arrayContentDidChange(array, startIdx, removeAmt, addAmt) { sendEvent(array, '@array:change', [array, startIdx, removeAmt, addAmt]); let meta = peekMeta(array); - let cache = meta && meta.readableCache(); + let cache = meta !== undefined ? meta.readableCache() : undefined; if (cache !== undefined) { let length = get(array, 'length'); let addedAmount = (addAmt === -1 ? 0 : addAmt); From 60d708f9e24e87c063653dd6de59fa5b64d8b74f Mon Sep 17 00:00:00 2001 From: bekzod Date: Thu, 27 Jul 2017 10:26:15 +0500 Subject: [PATCH 190/224] allow readOnly to passed as option in `ComputedProperty` --- packages/ember-metal/lib/computed.js | 6 ++-- .../lib/computed/computed_macros.js | 4 +-- .../lib/computed/reduce_computed_macros.js | 32 +++++++++++-------- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/packages/ember-metal/lib/computed.js b/packages/ember-metal/lib/computed.js index 6276ff701a4..abfb399c7f9 100644 --- a/packages/ember-metal/lib/computed.js +++ b/packages/ember-metal/lib/computed.js @@ -129,7 +129,8 @@ const DEEP_EACH_REGEX = /\.@each\.[^.]+\./; */ function ComputedProperty(config, opts) { this.isDescriptor = true; - if (typeof config === 'function') { + let hasGetterOnly = typeof config === 'function'; + if (hasGetterOnly) { this._getter = config; } else { assert('Ember.computed expects a function or an object as last argument.', typeof config === 'object' && !Array.isArray(config)); @@ -141,8 +142,9 @@ function ComputedProperty(config, opts) { this._suspended = undefined; this._meta = undefined; this._volatile = false; + this._dependentKeys = opts && opts.dependentKeys; - this._readOnly = false; + this._readOnly = opts && hasGetterOnly && opts.readOnly === true; } ComputedProperty.prototype = new Descriptor(); diff --git a/packages/ember-runtime/lib/computed/computed_macros.js b/packages/ember-runtime/lib/computed/computed_macros.js index 0461f121219..6d68a356c87 100644 --- a/packages/ember-runtime/lib/computed/computed_macros.js +++ b/packages/ember-runtime/lib/computed/computed_macros.js @@ -462,7 +462,7 @@ export function lte(dependentKey, value) { a logical `and` on the values of all the original values for properties. @public */ -export let and = generateComputedWithPredicate('and', value => value); +export const and = generateComputedWithPredicate('and', value => value); /** A computed property which performs a logical `or` on the @@ -499,7 +499,7 @@ export let and = generateComputedWithPredicate('and', value => value); a logical `or` on the values of all the original values for properties. @public */ -export let or = generateComputedWithPredicate('or', value => !value); +export const or = generateComputedWithPredicate('or', value => !value); /** Creates a new property that is an alias for another property diff --git a/packages/ember-runtime/lib/computed/reduce_computed_macros.js b/packages/ember-runtime/lib/computed/reduce_computed_macros.js index 11ef3aa589c..8802584d24c 100644 --- a/packages/ember-runtime/lib/computed/reduce_computed_macros.js +++ b/packages/ember-runtime/lib/computed/reduce_computed_macros.js @@ -24,9 +24,9 @@ function reduceMacro(dependentKey, callback, initialValue) { let arr = get(this, dependentKey); if (arr === null || typeof arr !== 'object') { return initialValue; } return arr.reduce(callback, initialValue, this); - }, { dependentKeys: [`${dependentKey}.[]`] }) + }, { dependentKeys: [`${dependentKey}.[]`], readOnly: true }) - return cp.readOnly(); + return cp; } function arrayMacro(dependentKey, callback) { @@ -46,9 +46,9 @@ function arrayMacro(dependentKey, callback) { } else { return emberA(); } - }, { dependentKeys: [ dependentKey ] }); + }, { dependentKeys: [ dependentKey ], readOnly: true }); - return cp.readOnly(); + return cp; } function multiArrayMacro(_dependentKeys, callback) { @@ -56,9 +56,9 @@ function multiArrayMacro(_dependentKeys, callback) { let cp = new ComputedProperty(function() { return emberA(callback.call(this, _dependentKeys)); - }, { dependentKeys }); + }, { dependentKeys, readOnly: true }); - return cp.readOnly(); + return cp; } /** @@ -429,7 +429,7 @@ export function uniq(...args) { @public */ export function uniqBy(dependentKey, propertyKey) { - return computed(`${dependentKey}.[]`, function() { + let cp = new ComputedProperty(function() { let uniq = emberA(); let seen = Object.create(null); let list = get(this, dependentKey); @@ -443,7 +443,9 @@ export function uniqBy(dependentKey, propertyKey) { }); } return uniq; - }).readOnly(); + }, { dependentKeys: [`${dependentKey}.[]`], readOnly: true }); + + return cp; } /** @@ -575,7 +577,7 @@ export function setDiff(setAProperty, setBProperty) { arguments.length === 2 ); - return computed(`${setAProperty}.[]`, `${setBProperty}.[]`, function() { + let cp = new ComputedProperty(function() { let setA = this.get(setAProperty); let setB = this.get(setBProperty); @@ -583,7 +585,12 @@ export function setDiff(setAProperty, setBProperty) { if (!isArray(setB)) { return emberA(setA); } return setA.filter(x => setB.indexOf(x) === -1); - }).readOnly(); + }, { + dependentKeys: [ `${setAProperty}.[]`, `${setBProperty}.[]` ], + readOnly: true + }); + + return cp; } /** @@ -751,11 +758,11 @@ function propertySort(itemsKey, sortPropertiesKey) { activeObserversMap.set(this, activeObservers); return sortByNormalizedSortProperties(items, normalizedSortProperties); - }, { dependentKeys: [`${sortPropertiesKey}.[]`] }); + }, { dependentKeys: [`${sortPropertiesKey}.[]`], readOnly: true }); cp._activeObserverMap = undefined; - return cp.readOnly(); + return cp; } function normalizeSortProperties(sortProperties) { @@ -776,7 +783,6 @@ function sortByNormalizedSortProperties(items, normalizedSortProperties) { return (direction === 'desc') ? (-1 * result) : result; } } - return 0; })); } From 56dcb2f360709fe9fdd52aac6e1de29b72079468 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 7 Aug 2017 16:44:24 -0400 Subject: [PATCH 191/224] Update @glimmer packages to 0.25.3. --- package.json | 10 ++--- yarn.lock | 102 +++++++++++++++++++++++++-------------------------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/package.json b/package.json index 3f8cfa3f368..b3c6fe475b6 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,11 @@ "link:glimmer": "node bin/yarn-link-glimmer.js" }, "dependencies": { - "@glimmer/compiler": "^0.25.1", - "@glimmer/node": "^0.25.1", - "@glimmer/reference": "^0.25.1", - "@glimmer/runtime": "^0.25.1", - "@glimmer/util": "^0.25.1", + "@glimmer/compiler": "^0.25.3", + "@glimmer/node": "^0.25.3", + "@glimmer/reference": "^0.25.3", + "@glimmer/runtime": "^0.25.3", + "@glimmer/util": "^0.25.3", "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^2.0.0", "ember-cli-get-component-path-option": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 09949840c8f..c21c9c9c87b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,78 +2,78 @@ # yarn lockfile v1 -"@glimmer/compiler@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/compiler/-/compiler-0.25.1.tgz#81fb9f51349f819525da737ae953a5f8461fdef1" - dependencies: - "@glimmer/interfaces" "^0.25.1" - "@glimmer/syntax" "^0.25.1" - "@glimmer/util" "^0.25.1" - "@glimmer/wire-format" "^0.25.1" +"@glimmer/compiler@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/compiler/-/compiler-0.25.3.tgz#25eb06394f3ba1c1fae5af25c9cf7deb2c11ef4e" + dependencies: + "@glimmer/interfaces" "^0.25.3" + "@glimmer/syntax" "^0.25.3" + "@glimmer/util" "^0.25.3" + "@glimmer/wire-format" "^0.25.3" simple-html-tokenizer "^0.3.0" -"@glimmer/interfaces@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/interfaces/-/interfaces-0.25.1.tgz#234abbbf7021a73ec576943443768d0e2801ad13" +"@glimmer/interfaces@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/interfaces/-/interfaces-0.25.3.tgz#8c460b28ad5a17eaa1712e6aa7b8ebb49738c38f" dependencies: - "@glimmer/wire-format" "^0.25.1" + "@glimmer/wire-format" "^0.25.3" -"@glimmer/node@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/node/-/node-0.25.1.tgz#0f5301d7a100cbb37e8252f8e5f28ce4afa470db" +"@glimmer/node@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/node/-/node-0.25.3.tgz#301828e8455be141d5384b01980ed9be02984059" dependencies: - "@glimmer/runtime" "^0.25.1" + "@glimmer/runtime" "^0.25.3" simple-dom "^0.3.0" -"@glimmer/object-reference@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/object-reference/-/object-reference-0.25.1.tgz#6393deb8d24c6ead90437998eb988207d674142e" +"@glimmer/object-reference@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/object-reference/-/object-reference-0.25.3.tgz#e0d1fa874f912e7d1232d487fcd2096e6b31b620" dependencies: - "@glimmer/reference" "^0.25.1" - "@glimmer/util" "^0.25.1" + "@glimmer/reference" "^0.25.3" + "@glimmer/util" "^0.25.3" -"@glimmer/object@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/object/-/object-0.25.1.tgz#2611f9deb88d4d33c24d1e8dc57d4ae5c224fc24" +"@glimmer/object@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/object/-/object-0.25.3.tgz#451eb208dadba1ede9c0c038a90dfe32637493fe" dependencies: - "@glimmer/object-reference" "^0.25.1" - "@glimmer/util" "^0.25.1" + "@glimmer/object-reference" "^0.25.3" + "@glimmer/util" "^0.25.3" -"@glimmer/reference@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/reference/-/reference-0.25.1.tgz#5c5a148a7e1f33c3ed425999b8b45d0f7a88aeac" +"@glimmer/reference@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/reference/-/reference-0.25.3.tgz#a09ddc397bee0223de73ea5044a304a30935104f" dependencies: - "@glimmer/util" "^0.25.1" + "@glimmer/util" "^0.25.3" -"@glimmer/runtime@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/runtime/-/runtime-0.25.1.tgz#ead91cc51a44ff9777fee0a786d32aeb8b8e993a" +"@glimmer/runtime@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/runtime/-/runtime-0.25.3.tgz#ae2101a1e4de3330d08f20806c18327dbfa86d78" dependencies: - "@glimmer/interfaces" "^0.25.1" - "@glimmer/object" "^0.25.1" - "@glimmer/object-reference" "^0.25.1" - "@glimmer/reference" "^0.25.1" - "@glimmer/util" "^0.25.1" - "@glimmer/wire-format" "^0.25.1" + "@glimmer/interfaces" "^0.25.3" + "@glimmer/object" "^0.25.3" + "@glimmer/object-reference" "^0.25.3" + "@glimmer/reference" "^0.25.3" + "@glimmer/util" "^0.25.3" + "@glimmer/wire-format" "^0.25.3" -"@glimmer/syntax@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/syntax/-/syntax-0.25.1.tgz#05bbc219af98adc447195d4d74bba6fb9f5fd3d5" +"@glimmer/syntax@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/syntax/-/syntax-0.25.3.tgz#b3f8a59bee616fd600301d778de3b649bf77036e" dependencies: - "@glimmer/interfaces" "^0.25.1" - "@glimmer/util" "^0.25.1" + "@glimmer/interfaces" "^0.25.3" + "@glimmer/util" "^0.25.3" handlebars "^4.0.6" simple-html-tokenizer "^0.3.0" -"@glimmer/util@^0.25.1": - version "0.25.2" - resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.25.2.tgz#a79e7100f7c38181be026dddf2d3b4ce8a8c8421" +"@glimmer/util@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.25.3.tgz#7cedf72947137b519658c8be34d0d5965cebe3a1" -"@glimmer/wire-format@^0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@glimmer/wire-format/-/wire-format-0.25.1.tgz#cd69f3595a08954fa68a3f1df4feafffa1c3f3de" +"@glimmer/wire-format@^0.25.3": + version "0.25.3" + resolved "https://registry.yarnpkg.com/@glimmer/wire-format/-/wire-format-0.25.3.tgz#046692b3a26a30a498712266cd0bdb47d7710f37" dependencies: - "@glimmer/util" "^0.25.1" + "@glimmer/util" "^0.25.3" abbrev@1: version "1.1.0" From 18ae10eef196e0806f08c68e47238d415b8e3596 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Tue, 8 Aug 2017 00:13:36 +0200 Subject: [PATCH 192/224] [DOC release] Fix links in {{action}} helper documentation Documentation in the `{{action}}` helper still referred to Ember.View documentation. Fixes #15571 --- packages/ember-glimmer/lib/helpers/action.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ember-glimmer/lib/helpers/action.js b/packages/ember-glimmer/lib/helpers/action.js index 1c8c483a63f..c4f501558ca 100644 --- a/packages/ember-glimmer/lib/helpers/action.js +++ b/packages/ember-glimmer/lib/helpers/action.js @@ -205,8 +205,8 @@ export const ACTION = symbol('ACTION'); If you need the default handler to trigger you should either register your own event handler, or use event methods on your view class. See - ["Responding to Browser Events"](/api/classes/Ember.View.html#toc_responding-to-browser-events) - in the documentation for Ember.View for more information. + ["Responding to Browser Events"](/api/classes/Ember.Component#responding-to-browser-events) + in the documentation for Ember.Component for more information. ### Specifying DOM event type @@ -220,7 +220,7 @@ export const ACTION = symbol('ACTION');
``` - See ["Event Names"](/api/classes/Ember.View.html#toc_event-names) for a list of + See ["Event Names"](/api/classes/Ember.Component#event-names) for a list of acceptable DOM event names. ### Specifying whitelisted modifier keys From 5a7356fe741455e171093369838fa18745fc5fd2 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Fri, 11 Aug 2017 00:26:04 +0530 Subject: [PATCH 193/224] remove unused deps --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index b3c6fe475b6..4719cfb9f8e 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "@glimmer/node": "^0.25.3", "@glimmer/reference": "^0.25.3", "@glimmer/runtime": "^0.25.3", - "@glimmer/util": "^0.25.3", "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^2.0.0", "ember-cli-get-component-path-option": "^1.0.0", @@ -55,7 +54,6 @@ "ember-cli-valid-component-name": "^1.0.0", "ember-cli-version-checker": "^1.3.1", "ember-router-generator": "^1.2.3", - "handlebars": "^4.0.6", "jquery": "^3.2.1", "resolve": "^1.3.3", "rsvp": "^3.6.1", From 458880b5ad4d7f5c22e52ca60abbf57b0f208cd2 Mon Sep 17 00:00:00 2001 From: simonihmig Date: Thu, 10 Aug 2017 23:02:37 +0200 Subject: [PATCH 194/224] [BUGFIX beta] Include missing sourcemaps in vendorTree Fixes #15464 --- index.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 1775fb35a4a..d86151eb8d0 100644 --- a/index.js +++ b/index.js @@ -58,11 +58,18 @@ module.exports = { 'ember.debug.js', 'ember.min.js', 'ember.prod.js' - ].filter(function(file) { - var fullPath = path.join(__dirname, 'dist', file); + ] + .map(function(file) { + return [file, file.replace('.js', '.map')]; + }) + .reduce(function(flat, jsAndMap) { + return flat.concat(jsAndMap); + }, []) + .filter(function(file) { + var fullPath = path.join(__dirname, 'dist', file); - return fs.existsSync(fullPath); - }); + return fs.existsSync(fullPath); + }); var ember = new Funnel(__dirname + '/dist', { destDir: 'ember', From 282185535b7bde56437d6d3a78d89a201dac0e53 Mon Sep 17 00:00:00 2001 From: David Yan Date: Sat, 12 Aug 2017 15:05:38 -0700 Subject: [PATCH 195/224] Fix casing of JavaScript in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 41186ea6622..340b3bc7bff 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,10 @@ Sauce Test Status

-Ember.js is a Javascript framework that greatly reduces the time, effort and resources needed +Ember.js is a JavaScript framework that greatly reduces the time, effort and resources needed to build any web application. It is focused on making you, the developer, as productive as possible by doing all the common, repetitive, yet essential, tasks involved in most web development projects. -Ember.js also provides access to the most advanced features of Javascript, HTML and the Browser giving you everything you need to create your next killer web app. +Ember.js also provides access to the most advanced features of JavaScript, HTML and the Browser giving you everything you need to create your next killer web app. - [Website](https://emberjs.com) - [Guides](https://guides.emberjs.com) From 48d5d4620bc5e0fa705397344619cdc133bf6a16 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Tue, 15 Aug 2017 14:10:15 +0100 Subject: [PATCH 196/224] Update core_object.js --- packages/ember-runtime/lib/system/core_object.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-runtime/lib/system/core_object.js b/packages/ember-runtime/lib/system/core_object.js index 23720f90fc3..3c1d0f58fb2 100644 --- a/packages/ember-runtime/lib/system/core_object.js +++ b/packages/ember-runtime/lib/system/core_object.js @@ -510,7 +510,7 @@ CoreObject.PrototypeMixin = Mixin.create({ If the object's class is not defined on an Ember namespace, it will indicate it is a subclass of the registered superclass: - ```javascript + ```javascript const Student = Person.extend() let student = Student.create() student.toString() //=> "<(subclass of Person):ember1025>" From dac942a86eedc8f71727ae1bed7abfaac9aee935 Mon Sep 17 00:00:00 2001 From: Richard Livsey Date: Wed, 16 Aug 2017 09:19:29 +0100 Subject: [PATCH 197/224] Remove outdated {{with}} documentation `{{with}}` no longer changes the scope of `this` so this note no longer applies --- packages/ember-glimmer/lib/index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/ember-glimmer/lib/index.js b/packages/ember-glimmer/lib/index.js index f59ef149f0a..2b20ffc0ae1 100644 --- a/packages/ember-glimmer/lib/index.js +++ b/packages/ember-glimmer/lib/index.js @@ -95,9 +95,7 @@ {{/each}} {{/with}} ``` - - Without the `as` operator, it would be impossible to reference `user.name` in the example above. - + NOTE: The alias should not reuse a name from the bound property path. For example: `{{#with foo.bar as |foo|}}` is not supported because it attempts to alias using From f5a63208f8d998425e15c7af1167f6d8fdb16f1e Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Thu, 27 Jul 2017 07:10:52 +0100 Subject: [PATCH 198/224] Updates code blocks to adhere to RFC 176. --- .../tests/acceptance/__name__-test.js | 4 +- .../files/__root__/__path__/__name__.js | 4 +- .../files/__root__/__path__/__name__.js | 4 +- .../helper/files/__root__/helpers/__name__.js | 4 +- .../tests/unit/initializers/__name__-test.js | 7 +- .../tests/unit/initializers/__name__-test.js | 8 +- .../instance-initializers/__name__-test.js | 9 +- .../instance-initializers/__name__-test.js | 9 +- .../tests/unit/mixins/__name__-test.js | 4 +- .../tests/unit/mixins/__name__-test.js | 4 +- .../mixin/files/__root__/mixins/__name__.js | 4 +- .../route/files/__root__/__path__/__name__.js | 4 +- .../files/__root__/__path__/__name__.js | 4 +- .../files/tests/helpers/__name__.js | 4 +- broccoli/minify.js | 2 +- node-tests/blueprints/component-test.js | 112 ++++++------- node-tests/blueprints/controller-test.js | 48 +++--- node-tests/blueprints/helper-test.js | 44 ++--- node-tests/blueprints/initializer-test.js | 6 +- .../blueprints/instance-initializer-test.js | 6 +- node-tests/blueprints/mixin-test.js | 44 ++--- node-tests/blueprints/route-test.js | 52 +++--- node-tests/blueprints/service-test.js | 32 ++-- node-tests/blueprints/test-helper-test.js | 4 +- packages/container/lib/container.js | 2 +- .../lib/system/application.js | 4 +- .../ember-application/lib/system/engine.js | 151 +++++++++++------- .../ember-application/lib/system/resolver.js | 49 +++--- packages/ember-glimmer/lib/component.js | 74 ++++----- .../ember-glimmer/lib/components/link-to.js | 20 +-- .../ember-glimmer/lib/components/text_area.js | 26 +-- packages/ember-glimmer/lib/helper.js | 26 +-- packages/ember-glimmer/lib/helpers/action.js | 31 ++-- .../ember-glimmer/lib/helpers/component.js | 10 +- .../ember-glimmer/lib/helpers/readonly.js | 8 +- packages/ember-glimmer/lib/index.js | 20 +-- packages/ember-glimmer/lib/syntax/outlet.js | 7 +- packages/ember-glimmer/lib/syntax/render.js | 6 +- packages/ember-metal/lib/computed.js | 9 +- packages/ember-metal/lib/mixin.js | 16 +- packages/ember-metal/lib/run_loop.js | 24 ++- packages/ember-routing/lib/ext/controller.js | 12 +- .../lib/location/auto_location.js | 6 +- .../lib/location/hash_location.js | 6 +- .../lib/location/history_location.js | 6 +- packages/ember-routing/lib/system/route.js | 129 ++++++++------- packages/ember-routing/lib/system/router.js | 4 +- .../lib/controllers/controller.js | 19 ++- packages/ember-runtime/lib/ext/function.js | 28 +++- .../lib/mixins/action_handler.js | 60 +++++-- packages/ember-runtime/lib/mixins/evented.js | 51 +++--- .../ember-runtime/lib/mixins/observable.js | 6 +- .../ember-runtime/lib/system/native_array.js | 6 +- packages/ember-runtime/lib/system/service.js | 9 +- .../tests/system/object/create_test.js | 9 -- .../tests/adapters/adapter_test.js | 9 -- packages/ember-utils/lib/owner.js | 13 +- .../ember-views/lib/mixins/action_support.js | 28 ++-- .../ember-views/lib/mixins/view_support.js | 38 +++-- packages/ember/lib/index.js | 76 ++++----- 60 files changed, 792 insertions(+), 629 deletions(-) diff --git a/blueprints/acceptance-test/mocha-files/tests/acceptance/__name__-test.js b/blueprints/acceptance-test/mocha-files/tests/acceptance/__name__-test.js index f301c4e37b8..2700039e658 100644 --- a/blueprints/acceptance-test/mocha-files/tests/acceptance/__name__-test.js +++ b/blueprints/acceptance-test/mocha-files/tests/acceptance/__name__-test.js @@ -1,7 +1,7 @@ import { describe, it, beforeEach, afterEach } from 'mocha'; import { expect } from 'chai'; import startApp from '<%= dasherizedPackageName %>/tests/helpers/start-app'; -<% if (destroyAppExists) { %>import destroyApp from '<%= dasherizedPackageName %>/tests/helpers/destroy-app';<% } else { %>import Ember from 'ember';<% } %> +<% if (destroyAppExists) { %>import destroyApp from '<%= dasherizedPackageName %>/tests/helpers/destroy-app';<% } else { %>import { run } from '@ember/runloop';<% } %> describe('<%= friendlyTestName %>', function() { let application; @@ -11,7 +11,7 @@ describe('<%= friendlyTestName %>', function() { }); afterEach(function() { - <% if (destroyAppExists) { %>destroyApp(application);<% } else { %>Ember.run(application, 'destroy');<% } %> + <% if (destroyAppExists) { %>destroyApp(application);<% } else { %>run(application, 'destroy');<% } %> }); it('can visit /<%= dasherizedModuleName %>', function() { diff --git a/blueprints/component/files/__root__/__path__/__name__.js b/blueprints/component/files/__root__/__path__/__name__.js index fb1798c77cb..10ff1811a5a 100644 --- a/blueprints/component/files/__root__/__path__/__name__.js +++ b/blueprints/component/files/__root__/__path__/__name__.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import Component from '@ember/component'; <%= importTemplate %> -export default Ember.Component.extend({<%= contents %> +export default Component.extend({<%= contents %> }); diff --git a/blueprints/controller/files/__root__/__path__/__name__.js b/blueprints/controller/files/__root__/__path__/__name__.js index 55ff9aa587a..d630f313455 100644 --- a/blueprints/controller/files/__root__/__path__/__name__.js +++ b/blueprints/controller/files/__root__/__path__/__name__.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import Controller from '@ember/controller'; -export default Ember.Controller.extend({ +export default Controller.extend({ }); diff --git a/blueprints/helper/files/__root__/helpers/__name__.js b/blueprints/helper/files/__root__/helpers/__name__.js index eb31fd5447d..61f52c98be7 100644 --- a/blueprints/helper/files/__root__/helpers/__name__.js +++ b/blueprints/helper/files/__root__/helpers/__name__.js @@ -1,7 +1,7 @@ -import Ember from 'ember'; +import { helper } from '@ember/component/helper'; export function <%= camelizedModuleName %>(params/*, hash*/) { return params; } -export default Ember.Helper.helper(<%= camelizedModuleName %>); +export default helper(<%= camelizedModuleName %>); diff --git a/blueprints/initializer-test/mocha-files/tests/unit/initializers/__name__-test.js b/blueprints/initializer-test/mocha-files/tests/unit/initializers/__name__-test.js index 7d84890f929..5cad7fb4658 100644 --- a/blueprints/initializer-test/mocha-files/tests/unit/initializers/__name__-test.js +++ b/blueprints/initializer-test/mocha-files/tests/unit/initializers/__name__-test.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { describe, it, beforeEach, afterEach } from 'mocha'; -import Ember from 'ember'; +import { run } from '@ember/runloop'; +import Application from '@ember/application'; import { initialize } from '<%= dasherizedModulePrefix %>/initializers/<%= dasherizedModuleName %>'; import destroyApp from '../../helpers/destroy-app'; @@ -8,8 +9,8 @@ describe('<%= friendlyTestName %>', function() { let application; beforeEach(function() { - Ember.run(function() { - application = Ember.Application.create(); + run(function() { + application = Application.create(); application.deferReadiness(); }); }); diff --git a/blueprints/initializer-test/qunit-files/tests/unit/initializers/__name__-test.js b/blueprints/initializer-test/qunit-files/tests/unit/initializers/__name__-test.js index 9f78d0495e9..c54768cb0df 100644 --- a/blueprints/initializer-test/qunit-files/tests/unit/initializers/__name__-test.js +++ b/blueprints/initializer-test/qunit-files/tests/unit/initializers/__name__-test.js @@ -1,12 +1,14 @@ -import Ember from 'ember'; +import Application from '@ember/application'; +import { run } from '@ember/runloop'; + import { initialize } from '<%= dasherizedModulePrefix %>/initializers/<%= dasherizedModuleName %>'; import { module, test } from 'qunit'; import destroyApp from '../../helpers/destroy-app'; module('<%= friendlyTestName %>', { beforeEach() { - Ember.run(() => { - this.application = Ember.Application.create(); + run(() => { + this.application = Application.create(); this.application.deferReadiness(); }); }, diff --git a/blueprints/instance-initializer-test/mocha-files/tests/unit/instance-initializers/__name__-test.js b/blueprints/instance-initializer-test/mocha-files/tests/unit/instance-initializers/__name__-test.js index ecb40956350..4c33d9ca485 100644 --- a/blueprints/instance-initializer-test/mocha-files/tests/unit/instance-initializers/__name__-test.js +++ b/blueprints/instance-initializer-test/mocha-files/tests/unit/instance-initializers/__name__-test.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { describe, it, beforeEach } from 'mocha'; -import Ember from 'ember'; +import Application from '@ember/application'; +import { run } from '@ember/runloop'; import { initialize } from '<%= dasherizedModulePrefix %>/instance-initializers/<%= dasherizedModuleName %>'; import destroyApp from '../../helpers/destroy-app'; @@ -8,14 +9,14 @@ describe('<%= friendlyTestName %>', function() { let application, appInstance; beforeEach(function() { - Ember.run(function() { - application = Ember.Application.create(); + run(function() { + application = Application.create(); appInstance = application.buildInstance(); }); }); afterEach(function() { - Ember.run(appInstance, 'destroy'); + run(appInstance, 'destroy'); destroyApp(application); }); diff --git a/blueprints/instance-initializer-test/qunit-files/tests/unit/instance-initializers/__name__-test.js b/blueprints/instance-initializer-test/qunit-files/tests/unit/instance-initializers/__name__-test.js index be83200ba1c..57b271fe050 100644 --- a/blueprints/instance-initializer-test/qunit-files/tests/unit/instance-initializers/__name__-test.js +++ b/blueprints/instance-initializer-test/qunit-files/tests/unit/instance-initializers/__name__-test.js @@ -1,17 +1,18 @@ -import Ember from 'ember'; +import Application from '@ember/application'; +import { run } from '@ember/runloop'; import { initialize } from '<%= dasherizedModulePrefix %>/instance-initializers/<%= dasherizedModuleName %>'; import { module, test } from 'qunit'; import destroyApp from '../../helpers/destroy-app'; module('<%= friendlyTestName %>', { beforeEach() { - Ember.run(() => { - this.application = Ember.Application.create(); + run(() => { + this.application = Application.create(); this.appInstance = this.application.buildInstance(); }); }, afterEach() { - Ember.run(this.appInstance, 'destroy'); + run(this.appInstance, 'destroy'); destroyApp(this.application); } }); diff --git a/blueprints/mixin-test/mocha-files/tests/unit/mixins/__name__-test.js b/blueprints/mixin-test/mocha-files/tests/unit/mixins/__name__-test.js index 6242fc5a1ee..07938b78ea3 100644 --- a/blueprints/mixin-test/mocha-files/tests/unit/mixins/__name__-test.js +++ b/blueprints/mixin-test/mocha-files/tests/unit/mixins/__name__-test.js @@ -1,12 +1,12 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import Ember from 'ember'; +import EmberObject from '@ember/object'; import <%= classifiedModuleName %>Mixin from '<%= dasherizedPackageName %>/mixins/<%= dasherizedModuleName %>'; describe('<%= friendlyTestName %>', function() { // Replace this with your real tests. it('works', function() { - let <%= classifiedModuleName %>Object = Ember.Object.extend(<%= classifiedModuleName %>Mixin); + let <%= classifiedModuleName %>Object = EmberObject.extend(<%= classifiedModuleName %>Mixin); let subject = <%= classifiedModuleName %>Object.create(); expect(subject).to.be.ok; }); diff --git a/blueprints/mixin-test/qunit-files/tests/unit/mixins/__name__-test.js b/blueprints/mixin-test/qunit-files/tests/unit/mixins/__name__-test.js index 72d60b1a9b3..e5de1f13257 100644 --- a/blueprints/mixin-test/qunit-files/tests/unit/mixins/__name__-test.js +++ b/blueprints/mixin-test/qunit-files/tests/unit/mixins/__name__-test.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import EmberObject from '@ember/object'; import <%= classifiedModuleName %>Mixin from '<%= projectName %>/mixins/<%= dasherizedModuleName %>'; import { module, test } from 'qunit'; @@ -6,7 +6,7 @@ module('<%= friendlyTestName %>'); // Replace this with your real tests. test('it works', function(assert) { - let <%= classifiedModuleName %>Object = Ember.Object.extend(<%= classifiedModuleName %>Mixin); + let <%= classifiedModuleName %>Object = EmberObject.extend(<%= classifiedModuleName %>Mixin); let subject = <%= classifiedModuleName %>Object.create(); assert.ok(subject); }); diff --git a/blueprints/mixin/files/__root__/mixins/__name__.js b/blueprints/mixin/files/__root__/mixins/__name__.js index abf754d7160..4f1bab5d000 100644 --- a/blueprints/mixin/files/__root__/mixins/__name__.js +++ b/blueprints/mixin/files/__root__/mixins/__name__.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import Mixin from '@ember/object/mixin'; -export default Ember.Mixin.create({ +export default Mixin.create({ }); diff --git a/blueprints/route/files/__root__/__path__/__name__.js b/blueprints/route/files/__root__/__path__/__name__.js index 26d9f3124ec..6c74252aa1b 100644 --- a/blueprints/route/files/__root__/__path__/__name__.js +++ b/blueprints/route/files/__root__/__path__/__name__.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import Route from '@ember/routing/route'; -export default Ember.Route.extend({ +export default Route.extend({ }); diff --git a/blueprints/service/files/__root__/__path__/__name__.js b/blueprints/service/files/__root__/__path__/__name__.js index b9261c61d86..2c0547143aa 100644 --- a/blueprints/service/files/__root__/__path__/__name__.js +++ b/blueprints/service/files/__root__/__path__/__name__.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import Service from '@ember/service'; -export default Ember.Service.extend({ +export default Service.extend({ }); diff --git a/blueprints/test-helper/files/tests/helpers/__name__.js b/blueprints/test-helper/files/tests/helpers/__name__.js index b5387d2d3f1..74a6dc7f40a 100644 --- a/blueprints/test-helper/files/tests/helpers/__name__.js +++ b/blueprints/test-helper/files/tests/helpers/__name__.js @@ -1,5 +1,5 @@ -import Ember from 'ember'; +import { registerAsyncHelper } from '@ember/test'; -export default Ember.Test.registerAsyncHelper('<%= camelizedModuleName %>', function(app) { +export default registerAsyncHelper('<%= camelizedModuleName %>', function(app) { }); diff --git a/broccoli/minify.js b/broccoli/minify.js index 16c55afd58b..493f3baf9e5 100644 --- a/broccoli/minify.js +++ b/broccoli/minify.js @@ -12,7 +12,7 @@ module.exports = function _minify(tree, name) { }, mangle: true, compress: { - // this is adversely affects heuristics for IIFE eval + // this adversely affects heuristics for IIFE eval negate_iife: false, // limit sequences because of memory issues during parsing sequences: 30 diff --git a/node-tests/blueprints/component-test.js b/node-tests/blueprints/component-test.js index 7838bf5e8c7..fedc46bc311 100644 --- a/node-tests/blueprints/component-test.js +++ b/node-tests/blueprints/component-test.js @@ -22,8 +22,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { - expect(_file('app/components/x-foo.js')).to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + expect(_file('app/components/x-foo.js')).to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/templates/components/x-foo.hbs')) @@ -45,8 +45,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/components/foo/x-foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/templates/components/foo/x-foo.hbs')) @@ -68,8 +68,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/components/x-foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/templates/components/x-foo.hbs')) @@ -91,9 +91,9 @@ describe('Acceptance: ember generate component', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/components/x-foo.js')) - .to.contain("import Ember from 'ember';") + .to.contain("import Component from '@ember/component';") .to.contain("import layout from '../templates/components/x-foo';") - .to.contain("export default Ember.Component.extend({") + .to.contain("export default Component.extend({") .to.contain("layout") .to.contain("});"); @@ -119,9 +119,9 @@ describe('Acceptance: ember generate component', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/components/nested/x-foo.js')) - .to.contain("import Ember from 'ember';") + .to.contain("import Component from '@ember/component';") .to.contain("import layout from '../../templates/components/nested/x-foo';") - .to.contain("export default Ember.Component.extend({") + .to.contain("export default Component.extend({") .to.contain("layout") .to.contain("});"); @@ -147,8 +147,8 @@ describe('Acceptance: ember generate component', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/dummy/app/components/x-foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('tests/dummy/app/templates/components/x-foo.hbs')) @@ -168,8 +168,8 @@ describe('Acceptance: ember generate component', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/dummy/app/components/nested/x-foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('tests/dummy/app/templates/components/nested/x-foo.hbs')) @@ -189,9 +189,9 @@ describe('Acceptance: ember generate component', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/components/x-foo.js')) - .to.contain("import Ember from 'ember';") + .to.contain("import Component from '@ember/component';") .to.contain("import layout from '../templates/components/x-foo';") - .to.contain("export default Ember.Component.extend({") + .to.contain("export default Component.extend({") .to.contain("layout") .to.contain("});"); @@ -244,9 +244,9 @@ describe('Acceptance: ember generate component', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/components/nested/x-foo.js')) - .to.contain("import Ember from 'ember';") + .to.contain("import Component from '@ember/component';") .to.contain("import layout from '../../templates/components/nested/x-foo';") - .to.contain("export default Ember.Component.extend({") + .to.contain("export default Component.extend({") .to.contain("layout") .to.contain("});"); @@ -273,8 +273,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/components/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/components/x-foo/template.hbs')) @@ -295,8 +295,8 @@ describe('Acceptance: ember generate component', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/components/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/pods/components/x-foo/template.hbs')) @@ -318,8 +318,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/components/foo/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/components/foo/x-foo/template.hbs')) @@ -342,8 +342,8 @@ describe('Acceptance: ember generate component', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/components/foo/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/pods/components/foo/x-foo/template.hbs')) @@ -365,8 +365,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/bar/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/bar/x-foo/template.hbs')) @@ -389,8 +389,8 @@ describe('Acceptance: ember generate component', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/bar/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/pods/bar/x-foo/template.hbs')) @@ -412,8 +412,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/bar/foo/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/bar/foo/x-foo/template.hbs')) @@ -436,8 +436,8 @@ describe('Acceptance: ember generate component', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/bar/foo/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/pods/bar/foo/x-foo/template.hbs')) @@ -458,8 +458,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/bar/baz/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/bar/baz/x-foo/template.hbs')) @@ -482,8 +482,8 @@ describe('Acceptance: ember generate component', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/bar/baz/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/pods/bar/baz/x-foo/template.hbs')) @@ -505,8 +505,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/bar/baz/foo/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/bar/baz/foo/x-foo/template.hbs')) @@ -529,8 +529,8 @@ describe('Acceptance: ember generate component', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/bar/baz/foo/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/pods/bar/baz/foo/x-foo/template.hbs')) @@ -552,8 +552,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/x-foo/template.hbs')) @@ -576,8 +576,8 @@ describe('Acceptance: ember generate component', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/pods/x-foo/template.hbs')) @@ -599,8 +599,8 @@ describe('Acceptance: ember generate component', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/foo/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/foo/x-foo/template.hbs')) @@ -623,8 +623,8 @@ describe('Acceptance: ember generate component', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/foo/x-foo/component.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Component.extend({") + .to.contain("import Component from '@ember/component';") + .to.contain("export default Component.extend({") .to.contain("});"); expect(_file('app/pods/foo/x-foo/template.hbs')) @@ -646,9 +646,9 @@ describe('Acceptance: ember generate component', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/components/x-foo/component.js')) - .to.contain("import Ember from 'ember';") + .to.contain("import Component from '@ember/component';") .to.contain("import layout from './template';") - .to.contain("export default Ember.Component.extend({") + .to.contain("export default Component.extend({") .to.contain("layout") .to.contain("});"); @@ -671,9 +671,9 @@ describe('Acceptance: ember generate component', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/components/x-foo/component.js')) - .to.contain("import Ember from 'ember';") + .to.contain("import Component from '@ember/component';") .to.contain("import layout from './template';") - .to.contain("export default Ember.Component.extend({") + .to.contain("export default Component.extend({") .to.contain("layout") .to.contain("});"); @@ -696,9 +696,9 @@ describe('Acceptance: ember generate component', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/components/nested/x-foo/component.js')) - .to.contain("import Ember from 'ember';") + .to.contain("import Component from '@ember/component';") .to.contain("import layout from './template';") - .to.contain("export default Ember.Component.extend({") + .to.contain("export default Component.extend({") .to.contain("layout") .to.contain("});"); diff --git a/node-tests/blueprints/controller-test.js b/node-tests/blueprints/controller-test.js index f8c31d48119..ecf5a041883 100644 --- a/node-tests/blueprints/controller-test.js +++ b/node-tests/blueprints/controller-test.js @@ -21,8 +21,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/controllers/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('tests/unit/controllers/foo-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -36,8 +36,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/controllers/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('tests/unit/controllers/foo/bar-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -51,8 +51,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/controllers/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('app/controllers/foo.js')) .to.contain("export { default } from 'my-addon/controllers/foo';"); @@ -69,8 +69,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/controllers/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('app/controllers/foo/bar.js')) .to.contain("export { default } from 'my-addon/controllers/foo/bar';"); @@ -87,8 +87,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/dummy/app/controllers/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('app/controllers/foo-test.js')) .to.not.exist; @@ -104,8 +104,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/dummy/app/controllers/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('app/controllers/foo/bar.js')) .to.not.exist; @@ -121,8 +121,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/controllers/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('lib/my-addon/app/controllers/foo.js')) .to.contain("export { default } from 'my-addon/controllers/foo';"); @@ -139,8 +139,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/controllers/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('lib/my-addon/app/controllers/foo/bar.js')) .to.contain("export { default } from 'my-addon/controllers/foo/bar';"); @@ -157,8 +157,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/foo/controller.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('tests/unit/foo/controller-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -173,8 +173,8 @@ describe('Acceptance: ember generate and destroy controller', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/foo/controller.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('tests/unit/pods/foo/controller-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -188,8 +188,8 @@ describe('Acceptance: ember generate and destroy controller', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/foo/bar/controller.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('tests/unit/foo/bar/controller-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -204,8 +204,8 @@ describe('Acceptance: ember generate and destroy controller', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/foo/bar/controller.js')) - .to.contain("import Ember from 'ember';") - .to.contain("export default Ember.Controller.extend({\n});"); + .to.contain("import Controller from '@ember/controller';") + .to.contain("export default Controller.extend({\n});"); expect(_file('tests/unit/pods/foo/bar/controller-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") diff --git a/node-tests/blueprints/helper-test.js b/node-tests/blueprints/helper-test.js index 69054e3b5b7..e6da696222a 100644 --- a/node-tests/blueprints/helper-test.js +++ b/node-tests/blueprints/helper-test.js @@ -21,11 +21,11 @@ describe('Acceptance: ember generate and destroy helper', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/helpers/foo/bar-baz.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBarBaz(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBarBaz);"); + "export default helper(fooBarBaz);"); expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) .to.contain("moduleForComponent('foo/bar-baz', 'helper:foo/bar-baz', {"); @@ -38,11 +38,11 @@ describe('Acceptance: ember generate and destroy helper', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/helpers/foo-bar.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBar(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBar);"); + "export default helper(fooBar);"); expect(_file('app/helpers/foo-bar.js')) .to.contain("export { default, fooBar } from 'my-addon/helpers/foo-bar';"); @@ -57,11 +57,11 @@ describe('Acceptance: ember generate and destroy helper', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/helpers/foo/bar-baz.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBarBaz(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBarBaz);"); + "export default helper(fooBarBaz);"); expect(_file('app/helpers/foo/bar-baz.js')) .to.contain("export { default, fooBarBaz } from 'my-addon/helpers/foo/bar-baz';"); @@ -76,11 +76,11 @@ describe('Acceptance: ember generate and destroy helper', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/dummy/app/helpers/foo-bar.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBar(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBar);"); + "export default helper(fooBar);"); expect(_file('app/helpers/foo-bar.js')) .to.not.exist; @@ -95,11 +95,11 @@ describe('Acceptance: ember generate and destroy helper', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/dummy/app/helpers/foo/bar-baz.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBarBaz(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBarBaz);"); + "export default helper(fooBarBaz);"); expect(_file('app/helpers/foo/bar-baz.js')) .to.not.exist; @@ -114,11 +114,11 @@ describe('Acceptance: ember generate and destroy helper', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/helpers/foo-bar.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBar(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBar);"); + "export default helper(fooBar);"); expect(_file('lib/my-addon/app/helpers/foo-bar.js')) .to.contain("export { default, fooBar } from 'my-addon/helpers/foo-bar';"); @@ -133,11 +133,11 @@ describe('Acceptance: ember generate and destroy helper', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/helpers/foo/bar-baz.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBarBaz(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBarBaz);"); + "export default helper(fooBarBaz);"); expect(_file('lib/my-addon/app/helpers/foo/bar-baz.js')) .to.contain("export { default, fooBarBaz } from 'my-addon/helpers/foo/bar-baz';"); @@ -152,11 +152,11 @@ describe('Acceptance: ember generate and destroy helper', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/helpers/foo-bar.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBar(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBar);"); + "export default helper(fooBar);"); expect(_file('tests/integration/helpers/foo-bar-test.js')) .to.contain("moduleForComponent('foo-bar', 'helper:foo-bar', {"); @@ -170,11 +170,11 @@ describe('Acceptance: ember generate and destroy helper', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/helpers/foo-bar.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBar(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBar);"); + "export default helper(fooBar);"); expect(_file('tests/integration/helpers/foo-bar-test.js')) .to.contain("moduleForComponent('foo-bar', 'helper:foo-bar', {"); @@ -187,11 +187,11 @@ describe('Acceptance: ember generate and destroy helper', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/helpers/foo/bar-baz.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBarBaz(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBarBaz);"); + "export default helper(fooBarBaz);"); expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) .to.contain("moduleForComponent('foo/bar-baz', 'helper:foo/bar-baz', {"); @@ -205,11 +205,11 @@ describe('Acceptance: ember generate and destroy helper', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/helpers/foo/bar-baz.js')) - .to.contain("import Ember from 'ember';\n\n" + + .to.contain("import { helper } from '@ember/component/helper';\n\n" + "export function fooBarBaz(params/*, hash*/) {\n" + " return params;\n" + "}\n\n" + - "export default Ember.Helper.helper(fooBarBaz);"); + "export default helper(fooBarBaz);"); expect(_file('tests/integration/helpers/foo/bar-baz-test.js')) .to.contain("moduleForComponent('foo/bar-baz', 'helper:foo/bar-baz', {"); diff --git a/node-tests/blueprints/initializer-test.js b/node-tests/blueprints/initializer-test.js index 439ad6a8602..822b7001d2f 100644 --- a/node-tests/blueprints/initializer-test.js +++ b/node-tests/blueprints/initializer-test.js @@ -261,7 +261,7 @@ describe('Acceptance: ember generate and destroy initializer', function() { expect(_file('tests/unit/initializers/foo-test.js')) .to.contain("import { initialize } from 'my-app/initializers/foo';") .to.contain("module('Unit | Initializer | foo'") - .to.contain("application = Ember.Application.create();") + .to.contain("application = Application.create();") .to.contain("initialize(this.application);"); })); }); @@ -274,7 +274,7 @@ describe('Acceptance: ember generate and destroy initializer', function() { expect(_file('tests/unit/initializers/foo-test.js')) .to.contain("import { initialize } from 'dummy/initializers/foo';") .to.contain("module('Unit | Initializer | foo'") - .to.contain("application = Ember.Application.create();") + .to.contain("application = Application.create();") .to.contain("initialize(this.application);"); })); }); @@ -291,7 +291,7 @@ describe('Acceptance: ember generate and destroy initializer', function() { expect(_file('tests/unit/initializers/foo-test.js')) .to.contain("import { initialize } from 'my-app/initializers/foo';") .to.contain("describe('Unit | Initializer | foo', function() {") - .to.contain("application = Ember.Application.create();") + .to.contain("application = Application.create();") .to.contain("initialize(application);"); })); }); diff --git a/node-tests/blueprints/instance-initializer-test.js b/node-tests/blueprints/instance-initializer-test.js index f71009044a8..736a2c2990e 100644 --- a/node-tests/blueprints/instance-initializer-test.js +++ b/node-tests/blueprints/instance-initializer-test.js @@ -259,7 +259,7 @@ describe('Acceptance: ember generate and destroy instance-initializer', function expect(_file('tests/unit/instance-initializers/foo-test.js')) .to.contain("import { initialize } from 'my-app/instance-initializers/foo';") .to.contain("module('Unit | Instance Initializer | foo'") - .to.contain("application = Ember.Application.create();") + .to.contain("application = Application.create();") .to.contain("this.appInstance = this.application.buildInstance();") .to.contain("initialize(this.appInstance);"); })); @@ -273,7 +273,7 @@ describe('Acceptance: ember generate and destroy instance-initializer', function expect(_file('tests/unit/instance-initializers/foo-test.js')) .to.contain("import { initialize } from 'dummy/instance-initializers/foo';") .to.contain("module('Unit | Instance Initializer | foo'") - .to.contain("application = Ember.Application.create();") + .to.contain("application = Application.create();") .to.contain("this.appInstance = this.application.buildInstance();") .to.contain("initialize(this.appInstance);"); })); @@ -291,7 +291,7 @@ describe('Acceptance: ember generate and destroy instance-initializer', function expect(_file('tests/unit/instance-initializers/foo-test.js')) .to.contain("import { initialize } from 'my-app/instance-initializers/foo';") .to.contain("describe('Unit | Instance Initializer | foo', function() {") - .to.contain("application = Ember.Application.create();") + .to.contain("application = Application.create();") .to.contain("appInstance = application.buildInstance();") .to.contain("initialize(appInstance);"); })); diff --git a/node-tests/blueprints/mixin-test.js b/node-tests/blueprints/mixin-test.js index 4fe7141c540..936b08c85ef 100644 --- a/node-tests/blueprints/mixin-test.js +++ b/node-tests/blueprints/mixin-test.js @@ -19,8 +19,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/mixins/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo-test.js')) .to.contain("import FooMixin from 'my-app/mixins/foo';"); @@ -33,8 +33,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/mixins/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo/bar-test.js')) .to.contain("import FooBarMixin from 'my-app/mixins/foo/bar';"); @@ -57,8 +57,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/mixins/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo-test.js')) .to.contain("import FooMixin from 'my-addon/mixins/foo';"); @@ -74,8 +74,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/mixins/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo/bar-test.js')) .to.contain("import FooBarMixin from 'my-addon/mixins/foo/bar';"); @@ -91,8 +91,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/mixins/foo/bar/baz.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo/bar/baz-test.js')) .to.contain("import FooBarBazMixin from 'my-addon/mixins/foo/bar/baz';"); @@ -108,8 +108,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/mixins/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo-test.js')) .to.contain("import FooMixin from 'my-addon/mixins/foo';"); @@ -122,8 +122,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('lib/my-addon/addon/mixins/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo/bar-test.js')) .to.contain("import FooBarMixin from 'my-addon/mixins/foo/bar';"); @@ -148,8 +148,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/mixins/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo-test.js')) .to.contain("import FooMixin from 'my-app/mixins/foo';"); @@ -163,8 +163,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/mixins/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo-test.js')) .to.contain("import FooMixin from 'my-app/mixins/foo';"); @@ -177,8 +177,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/mixins/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo/bar-test.js')) .to.contain("import FooBarMixin from 'my-app/mixins/foo/bar';"); @@ -192,8 +192,8 @@ describe('Acceptance: ember generate and destroy mixin', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/mixins/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Mixin.create({\n});'); + .to.contain('import Mixin from \'@ember/object/mixin\';') + .to.contain('export default Mixin.create({\n});'); expect(_file('tests/unit/mixins/foo/bar-test.js')) .to.contain("import FooBarMixin from 'my-app/mixins/foo/bar';"); diff --git a/node-tests/blueprints/route-test.js b/node-tests/blueprints/route-test.js index d4cf086e784..b42ae3d76fc 100644 --- a/node-tests/blueprints/route-test.js +++ b/node-tests/blueprints/route-test.js @@ -29,8 +29,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew() .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('app/routes/foo.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('app/templates/foo.hbs')) .to.equal('{{outlet}}'); @@ -65,8 +65,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew() .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('app/routes/foo.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('app/templates/foo.hbs')) .to.equal('{{outlet}}'); @@ -91,8 +91,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew() .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('app/routes/child.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('app/templates/child.hbs')) .to.equal('{{outlet}}'); @@ -115,8 +115,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew() .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('app/child/route.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('app/child/template.hbs')) .to.equal('{{outlet}}'); @@ -172,8 +172,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('addon/routes/foo.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('addon/templates/foo.hbs')) .to.equal('{{outlet}}'); @@ -201,8 +201,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('addon/routes/foo/bar.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('addon/templates/foo/bar.hbs')) .to.equal('{{outlet}}'); @@ -230,8 +230,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('tests/dummy/app/routes/foo.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('tests/dummy/app/templates/foo.hbs')) .to.equal('{{outlet}}'); @@ -253,8 +253,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('tests/dummy/app/routes/foo/bar.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('tests/dummy/app/templates/foo/bar.hbs')) .to.equal('{{outlet}}'); @@ -277,8 +277,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('lib/my-addon/addon/routes/foo.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('lib/my-addon/addon/templates/foo.hbs')) .to.equal('{{outlet}}'); @@ -301,8 +301,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew({ target: 'in-repo-addon' }) .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('lib/my-addon/addon/routes/foo/bar.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('lib/my-addon/addon/templates/foo/bar.hbs')) .to.equal('{{outlet}}'); @@ -325,8 +325,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew() .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('app/foo/route.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('app/foo/template.hbs')) .to.equal('{{outlet}}'); @@ -365,8 +365,8 @@ describe('Acceptance: ember generate and destroy route', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('app/pods/foo/route.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('app/pods/foo/template.hbs')) .to.equal('{{outlet}}'); @@ -419,8 +419,8 @@ describe('Acceptance: ember generate and destroy route', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, (_file) => { expect(_file('addon/foo/route.js')) - .to.contain('import Ember from \'ember\';') - .to.contain('export default Ember.Route.extend({\n});'); + .to.contain('import Route from \'@ember/routing/route\';') + .to.contain('export default Route.extend({\n});'); expect(_file('addon/foo/template.hbs')) .to.equal('{{outlet}}'); diff --git a/node-tests/blueprints/service-test.js b/node-tests/blueprints/service-test.js index 2fea770fb51..9d7226e292c 100644 --- a/node-tests/blueprints/service-test.js +++ b/node-tests/blueprints/service-test.js @@ -21,8 +21,8 @@ describe('Acceptance: ember generate and destroy service', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/services/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Service.extend({\n});'); + .to.contain("import Service from '@ember/service';") + .to.contain('export default Service.extend({\n});'); expect(_file('tests/unit/services/foo-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -36,8 +36,8 @@ describe('Acceptance: ember generate and destroy service', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/services/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Service.extend({\n});'); + .to.contain("import Service from '@ember/service';") + .to.contain('export default Service.extend({\n});'); expect(_file('tests/unit/services/foo/bar-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -50,8 +50,8 @@ describe('Acceptance: ember generate and destroy service', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/services/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Service.extend({\n});'); + .to.contain("import Service from '@ember/service';") + .to.contain('export default Service.extend({\n});'); expect(_file('app/services/foo.js')) .to.contain("export { default } from 'my-addon/services/foo';"); @@ -68,8 +68,8 @@ describe('Acceptance: ember generate and destroy service', function() { return emberNew({ target: 'addon' }) .then(() => emberGenerateDestroy(args, _file => { expect(_file('addon/services/foo/bar.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Service.extend({\n});'); + .to.contain("import Service from '@ember/service';") + .to.contain('export default Service.extend({\n});'); expect(_file('app/services/foo/bar.js')) .to.contain("export { default } from 'my-addon/services/foo/bar';"); @@ -86,8 +86,8 @@ describe('Acceptance: ember generate and destroy service', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/foo/service.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Service.extend({\n});'); + .to.contain("import Service from '@ember/service';") + .to.contain('export default Service.extend({\n});'); expect(_file('tests/unit/foo/service-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -101,8 +101,8 @@ describe('Acceptance: ember generate and destroy service', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/foo/bar/service.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Service.extend({\n});'); + .to.contain("import Service from '@ember/service';") + .to.contain('export default Service.extend({\n});'); expect(_file('tests/unit/foo/bar/service-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -117,8 +117,8 @@ describe('Acceptance: ember generate and destroy service', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/foo/service.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Service.extend({\n});'); + .to.contain("import Service from '@ember/service';") + .to.contain('export default Service.extend({\n});'); expect(_file('tests/unit/pods/foo/service-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") @@ -133,8 +133,8 @@ describe('Acceptance: ember generate and destroy service', function() { .then(() => setupPodConfig({ podModulePrefix: true })) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/pods/foo/bar/service.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Service.extend({\n});'); + .to.contain("import Service from '@ember/service';") + .to.contain('export default Service.extend({\n});'); expect(_file('tests/unit/pods/foo/bar/service-test.js')) .to.contain("import { moduleFor, test } from 'ember-qunit';") diff --git a/node-tests/blueprints/test-helper-test.js b/node-tests/blueprints/test-helper-test.js index fc51c74de65..a34fc8de2a0 100644 --- a/node-tests/blueprints/test-helper-test.js +++ b/node-tests/blueprints/test-helper-test.js @@ -17,8 +17,8 @@ describe('Acceptance: ember generate and destroy test-helper', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/helpers/foo.js')) - .to.contain("import Ember from 'ember';") - .to.contain('export default Ember.Test.registerAsyncHelper(\'foo\', function(app) {\n\n}'); + .to.contain("import { registerAsyncHelper } from '@ember/test';") + .to.contain('export default registerAsyncHelper(\'foo\', function(app) {\n\n}'); })); }); }); diff --git a/packages/container/lib/container.js b/packages/container/lib/container.js index 818ebd96e38..7e808bd5a2b 100644 --- a/packages/container/lib/container.js +++ b/packages/container/lib/container.js @@ -449,7 +449,7 @@ class FactoryManager { if (typeof this.class._initFactory === 'function') { this.class._initFactory(this); } else { - // in the non-Ember.Object case we need to still setOwner + // in the non-EmberObject case we need to still setOwner // this is required for supporting glimmer environment and // template instantiation which rely heavily on // `options[OWNER]` being passed into `create` diff --git a/packages/ember-application/lib/system/application.js b/packages/ember-application/lib/system/application.js index 8c9e8876806..ce9e3338d4c 100644 --- a/packages/ember-application/lib/system/application.js +++ b/packages/ember-application/lib/system/application.js @@ -932,11 +932,11 @@ const Application = Engine.extend({ ``` ```app/routes/post.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; // An example of how the (hypothetical) service is used in routes. - export default Ember.Route.extend({ + export default Route.extend({ model(params) { return this.network.fetch(`/api/posts/${params.post_id}.json`); }, diff --git a/packages/ember-application/lib/system/engine.js b/packages/ember-application/lib/system/engine.js index 5e18ef02b4f..a2b8d863235 100644 --- a/packages/ember-application/lib/system/engine.js +++ b/packages/ember-application/lib/system/engine.js @@ -188,14 +188,17 @@ Engine.reopenClass({ This must be a unique name, as trying to register two initializers with the same name will result in an error. - ```javascript - Ember.Application.initializer({ - name: 'namedInitializer', + ```app/initializer/named-initializer.js + import { debug } from '@ember/debug'; - initialize: function(application) { - Ember.debug('Running namedInitializer!'); - } - }); + export function initialize() { + debug('Running namedInitializer!'); + } + + export default { + name: 'named-initializer', + initialize + }; ``` * `before` and `after` are used to ensure that this initializer is ran prior @@ -204,31 +207,41 @@ Engine.reopenClass({ An example of ordering initializers, we create an initializer named `first`: - ```javascript - Ember.Application.initializer({ - name: 'first', + ```app/initializer/first.js + import { debug } from '@ember/debug'; - initialize: function(application) { - Ember.debug('First initializer!'); - } - }); + export function initialize() { + debug('First initializer!'); + } + + export default { + name: 'first', + initialize + }; + ``` + ```bash // DEBUG: First initializer! ``` We add another initializer named `second`, specifying that it should run after the initializer named `first`: - ```javascript - Ember.Application.initializer({ + ```app/initializer/second.js + import { debug } from '@ember/debug'; + + export function initialize() { + debug('Second initializer!'); + } + + export default { name: 'second', after: 'first', + initialize + }; + ``` - initialize: function(application) { - Ember.debug('Second initializer!'); - } - }); - + ``` // DEBUG: First initializer! // DEBUG: Second initializer! ``` @@ -236,16 +249,21 @@ Engine.reopenClass({ Afterwards we add a further initializer named `pre`, this time specifying that it should run before the initializer named `first`: - ```javascript - Ember.Application.initializer({ + ```app/initializer/pre.js + import { debug } from '@ember/debug'; + + export function initialize() { + debug('Pre initializer!'); + } + + export default { name: 'pre', before: 'first', + initialize + }; + ``` - initialize: function(application) { - Ember.debug('Pre initializer!'); - } - }); - + ```bash // DEBUG: Pre initializer! // DEBUG: First initializer! // DEBUG: Second initializer! @@ -254,16 +272,21 @@ Engine.reopenClass({ Finally we add an initializer named `post`, specifying it should run after both the `first` and the `second` initializers: - ```javascript - Ember.Application.initializer({ + ```app/initializer/post.js + import { debug } from '@ember/debug'; + + export function initialize() { + debug('Post initializer!'); + } + + export default { name: 'post', after: ['first', 'second'], + initialize + }; + ``` - initialize: function(application) { - Ember.debug('Post initializer!'); - } - }); - + ```bash // DEBUG: Pre initializer! // DEBUG: First initializer! // DEBUG: Second initializer! @@ -275,14 +298,18 @@ Engine.reopenClass({ Example of using `application` to register an adapter: - ```javascript - Ember.Application.initializer({ - name: 'api-adapter', + ```app/initializer/api-adapter.js + import ApiAdapter from '../utils/api-adapter'; - initialize: function(application) { - application.register('api-adapter:main', ApiAdapter); - } - }); + export function initialize(application) { + application.register('api-adapter:main', ApiAdapter); + } + + export default { + name: 'post', + after: ['first', 'second'], + initialize + }; ``` @method initializer @@ -306,14 +333,17 @@ Engine.reopenClass({ registered. This must be a unique name, as trying to register two instanceInitializer with the same name will result in an error. - ```javascript - Ember.Application.instanceInitializer({ - name: 'namedinstanceInitializer', + ```app/initializer/named-instance-initializer.js + import { debug } from '@ember/debug'; - initialize: function(application) { - Ember.debug('Running namedInitializer!'); - } - }); + export function initialize() { + debug('Running named-instance-initializer!'); + } + + export default { + name: 'named-instance-initializer', + initialize + }; ``` * `before` and `after` are used to ensure that this initializer is ran prior @@ -325,11 +355,10 @@ Engine.reopenClass({ Example instanceInitializer to preload data into the store. - ```javascript - Ember.Application.initializer({ - name: 'preload-data', + ```app/initializer/preload-data.js + import $ from 'jquery'; - initialize: function(application) { + export function initialize(application) { var userConfig, userConfigEncoded, store; // We have a HTML escaped JSON representation of the user's basic // configuration generated server side and stored in the DOM of the main @@ -338,17 +367,24 @@ Engine.reopenClass({ // needed for immediate rendering of the page. Keep in mind, this data, // like all local models and data can be manipulated by the user, so it // should not be relied upon for security or authorization. - // + // Grab the encoded data from the meta tag - userConfigEncoded = Ember.$('head meta[name=app-user-config]').attr('content'); + userConfigEncoded = $('head meta[name=app-user-config]').attr('content'); + // Unescape the text, then parse the resulting JSON into a real object userConfig = JSON.parse(unescape(userConfigEncoded)); + // Lookup the store store = application.lookup('service:store'); + // Push the encoded JSON into the store store.pushPayload(userConfig); - } - }); + } + + export default { + name: 'named-instance-initializer', + initialize + }; ``` @method instanceInitializer @@ -400,7 +436,6 @@ Engine.reopenClass({ /** Set this to provide an alternate class to `Ember.DefaultResolver` - @deprecated Use 'Resolver' instead @property resolver @public diff --git a/packages/ember-application/lib/system/resolver.js b/packages/ember-application/lib/system/resolver.js index c2a985e7b78..0dcdd32e7b1 100644 --- a/packages/ember-application/lib/system/resolver.js +++ b/packages/ember-application/lib/system/resolver.js @@ -61,12 +61,16 @@ export const Resolver = EmberObject.extend({ in a subclass. For example, you could enhance how a template is resolved like so: - ```javascript - App = Ember.Application.create({ - Resolver: Ember.DefaultResolver.extend({ - resolveTemplate: function(parsedName) { + ```app/app.js + import Application from '@ember/application'; + import GlobalsResolver from '@ember/application/globals-resolver'; + + App = Application.create({ + Resolver: GlobalsResolver.extend({ + resolveTemplate(parsedName) { let resolvedTemplate = this._super(parsedName); if (resolvedTemplate) { return resolvedTemplate; } + return Ember.TEMPLATES['not_found']; } }) @@ -372,10 +376,10 @@ export default EmberObject.extend({ }, /** - @method _logLookup - @param {Boolean} found - @param {Object} parsedName - @private + @method _logLookup + @param {Boolean} found + @param {Object} parsedName + @private */ _logLookup(found, parsedName) { let symbol = found ? '[✓]' : '[ ]'; @@ -391,12 +395,12 @@ export default EmberObject.extend({ }, /** - Used to iterate all items of a given type. + Used to iterate all items of a given type. - @method knownForType - @param {String} type the type to search for - @private - */ + @method knownForType + @param {String} type the type to search for + @private + */ knownForType(type) { let namespace = get(this, 'namespace'); let suffix = StringUtils.classify(type); @@ -418,19 +422,18 @@ export default EmberObject.extend({ }, /** - Converts provided name from the backing namespace into a container lookup name. + Converts provided name from the backing namespace into a container lookup name. - Examples: + Examples: - App.FooBarHelper -> helper:foo-bar - App.THelper -> helper:t - - @method translateToContainerFullname - @param {String} type - @param {String} name - @private - */ + * App.FooBarHelper -> helper:foo-bar + * App.THelper -> helper:t + @method translateToContainerFullname + @param {String} type + @param {String} name + @private + */ translateToContainerFullname(type, name) { let suffix = StringUtils.classify(type); let namePrefix = name.slice(0, suffix.length * -1); diff --git a/packages/ember-glimmer/lib/component.js b/packages/ember-glimmer/lib/component.js index e6f6387de81..07ef2a66412 100644 --- a/packages/ember-glimmer/lib/component.js +++ b/packages/ember-glimmer/lib/component.js @@ -84,9 +84,9 @@ export const BOUNDS = symbol('BOUNDS'); `hello` for the `person-profile` component: ```app/components/person-profile.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ actions: { hello(name) { console.log("Hello", name); @@ -118,9 +118,9 @@ export const BOUNDS = symbol('BOUNDS'); The following component class: ```app/components/emphasized-paragraph.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ tagName: 'em' }); ``` @@ -138,9 +138,9 @@ export const BOUNDS = symbol('BOUNDS'); `classNames` property that is set to an array of strings: ```app/components/my-widget.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ classNames: ['my-class', 'my-other-class'] }); ``` @@ -157,9 +157,9 @@ export const BOUNDS = symbol('BOUNDS'); attribute. These properties can be computed properties: ```app/components/my-widget.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ classNameBindings: ['propertyA', 'propertyB'], propertyA: 'from-a', propertyB: Ember.computed(function() { @@ -179,9 +179,9 @@ export const BOUNDS = symbol('BOUNDS'); The class name will not be added if the value is `false` or `undefined`. ```app/components/my-widget.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ classNameBindings: ['hovered'], hovered: true }); @@ -198,9 +198,9 @@ export const BOUNDS = symbol('BOUNDS'); preferred value after a ":" character when defining the binding: ```app/components/my-widget.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ classNameBindings: ['awesome:so-very-cool'], awesome: true }); @@ -216,9 +216,9 @@ export const BOUNDS = symbol('BOUNDS'); camelCase-style format will be converted to a dasherized format: ```app/components/my-widget.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ classNameBindings: ['isUrgent'], isUrgent: true }); @@ -234,9 +234,9 @@ export const BOUNDS = symbol('BOUNDS'); traversing a path relative to the component itself: ```app/components/my-widget.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ classNameBindings: ['messages.empty'], messages: Ember.Object.create({ empty: true @@ -255,9 +255,9 @@ export const BOUNDS = symbol('BOUNDS'); like this: ```app/components/my-widget.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ classNameBindings: ['isEnabled:enabled:disabled'], isEnabled: true }); @@ -279,10 +279,10 @@ export const BOUNDS = symbol('BOUNDS'); This syntax offers the convenience to add a class if a property is `false`: ```app/components/my-widget.js - import Ember from 'ember'; + import Component from '@ember/component'; // Applies no class when isEnabled is true and class 'disabled' when isEnabled is false - export default Ember.Component.extend({ + export default Component.extend({ classNameBindings: ['isEnabled::disabled'], isEnabled: true }); @@ -318,9 +318,9 @@ export const BOUNDS = symbol('BOUNDS'); HTML associated attribute: ```app/components/my-anchor.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ tagName: 'a', attributeBindings: ['href'], href: 'http://google.com' @@ -337,9 +337,9 @@ export const BOUNDS = symbol('BOUNDS'); the source property and the destination property: ```app/components/my-anchor.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ tagName: 'a', attributeBindings: ['url:href'], url: 'http://google.com' @@ -356,9 +356,9 @@ export const BOUNDS = symbol('BOUNDS'); mapped, since `:` is not a valid character for properties in Javascript: ```app/components/my-use.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ tagName: 'use', attributeBindings: ['xlinkHref:xlink:href'], xlinkHref: '#triangle' @@ -375,9 +375,9 @@ export const BOUNDS = symbol('BOUNDS'); the attribute will be present or absent depending on the value: ```app/components/my-text-input.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ tagName: 'input', attributeBindings: ['disabled'], disabled: false @@ -393,9 +393,9 @@ export const BOUNDS = symbol('BOUNDS'); `attributeBindings` can refer to computed properties: ```app/components/my-text-input.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ tagName: 'input', attributeBindings: ['disabled'], disabled: Ember.computed(function() { @@ -412,9 +412,9 @@ export const BOUNDS = symbol('BOUNDS'); return value of the `attributeBindings` monitored property: ```app/components/my-text-input.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ tagName: 'form', attributeBindings: ['novalidate'], novalidate: null @@ -442,10 +442,10 @@ export const BOUNDS = symbol('BOUNDS'); ``` ```app/components/person-profile.js - import Ember from 'ember'; + import Component from '@ember/component'; import layout from '../templates/components/person-profile'; - export default Ember.Component.extend({ + export default Component.extend({ layout }); ``` @@ -475,9 +475,9 @@ export const BOUNDS = symbol('BOUNDS'); argument to this method. ```app/components/my-widget.js - import Ember from 'ember'; + import Component from '@ember/component'; - export default Ember.Component.extend({ + export default Component.extend({ click(event) { // will be called when an instance's // rendered element is clicked @@ -879,7 +879,7 @@ const Component = CoreView.extend( instantiated: ```javascript - export default Ember.Component.extend({ + export default Component.extend({ init() { this._super(...arguments); diff --git a/packages/ember-glimmer/lib/components/link-to.js b/packages/ember-glimmer/lib/components/link-to.js index dd95e9cd9aa..3810ec2d092 100644 --- a/packages/ember-glimmer/lib/components/link-to.js +++ b/packages/ember-glimmer/lib/components/link-to.js @@ -245,13 +245,13 @@ ### Allowing Default Action - By default the `{{link-to}}` component prevents the default browser action - by calling `preventDefault()` as this sort of action bubbling is normally - handled internally and we do not want to take the browser to a new URL (for - example). + By default the `{{link-to}}` component prevents the default browser action + by calling `preventDefault()` as this sort of action bubbling is normally + handled internally and we do not want to take the browser to a new URL (for + example). - If you need to override this behavior specify `preventDefault=false` in - your template: + If you need to override this behavior specify `preventDefault=false` in + your template: ```handlebars {{#link-to 'photoGallery' aPhotoId preventDefault=false}} @@ -496,9 +496,11 @@ const LinkComponent = EmberComponent.extend({ Example: - ```javascript - App.MyLinkComponent = Ember.LinkComponent.extend({ - init: function() { + ```app/components/my-link.js + import LinkComponent from '@ember/routing/link-component'; + + export default LinkComponent.extend({ + init() { this._super(...arguments); Ember.Logger.log('Event is ' + this.get('eventName')); } diff --git a/packages/ember-glimmer/lib/components/text_area.js b/packages/ember-glimmer/lib/components/text_area.js index 1b237e273bf..5720f083677 100644 --- a/packages/ember-glimmer/lib/components/text_area.js +++ b/packages/ember-glimmer/lib/components/text_area.js @@ -51,12 +51,14 @@ import layout from '../templates/empty'; Bound: - In the following example, the `writtenWords` property on `App.ApplicationController` - will be updated live as the user types 'Lots of text that IS bound' into - the text area of their browser's window. + In the following example, the `writtenWords` property on the application + Controller will be updated live as the user types 'Lots of text that IS + bound' into the text area of their browser's window. - ```javascript - App.ApplicationController = Ember.Controller.extend({ + ```app/controllers/application.js + import Controller from '@ember/controller'; + + export default Controller.extend({ writtenWords: "Lots of text that IS bound" }); ``` @@ -65,7 +67,7 @@ import layout from '../templates/empty'; {{textarea value=writtenWords}} ``` - Would result in the following HTML: + Would result in the following HTML: ```html