ember-source 4.3.0-beta.1 → 4.4.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/blueprints/acceptance-test/mocha-files/tests/acceptance/__name__-test.js +4 -4
  2. package/blueprints/acceptance-test/mocha-rfc-232-files/tests/acceptance/__name__-test.js +2 -2
  3. package/blueprints/acceptance-test/qunit-files/tests/acceptance/__name__-test.js +2 -2
  4. package/blueprints/acceptance-test/qunit-rfc-232-files/tests/acceptance/__name__-test.js +2 -2
  5. package/blueprints/component/index.js +2 -2
  6. package/blueprints/component-class/index.js +2 -2
  7. package/blueprints/component-test/mocha-0.12-files/__root__/__testType__/__path__/__test__.js +4 -4
  8. package/blueprints/component-test/mocha-files/__root__/__testType__/__path__/__test__.js +7 -5
  9. package/blueprints/component-test/mocha-rfc-232-files/__root__/__testType__/__path__/__test__.js +4 -4
  10. package/blueprints/component-test/qunit-files/__root__/__testType__/__path__/__test__.js +4 -4
  11. package/blueprints/component-test/qunit-rfc-232-files/__root__/__testType__/__path__/__test__.js +4 -4
  12. package/blueprints/controller/files/__root__/__path__/__name__.js +1 -2
  13. package/blueprints/controller-test/mocha-0.12-files/__root__/__testType__/__path__/__test__.js +2 -2
  14. package/blueprints/controller-test/mocha-files/__root__/__testType__/__path__/__test__.js +5 -3
  15. package/blueprints/controller-test/mocha-rfc-232-files/__root__/__testType__/__path__/__test__.js +2 -2
  16. package/blueprints/controller-test/qunit-files/__root__/__testType__/__path__/__test__.js +1 -1
  17. package/blueprints/controller-test/qunit-rfc-232-files/__root__/__testType__/__path__/__test__.js +2 -2
  18. package/blueprints/helper/files/__root__/__collection__/__name__.js +1 -1
  19. package/blueprints/helper/mu-files/__root__/__collection__/__name__.js +1 -1
  20. package/blueprints/helper-test/mocha-0.12-files/__root__/__testType__/__collection__/__name__-test.js +3 -3
  21. package/blueprints/helper-test/mocha-files/__root__/__testType__/__collection__/__name__-test.js +6 -4
  22. package/blueprints/helper-test/mocha-rfc-232-files/__root__/__testType__/__collection__/__name__-test.js +2 -2
  23. package/blueprints/helper-test/qunit-files/__root__/__testType__/__collection__/__name__-test.js +2 -2
  24. package/blueprints/helper-test/qunit-rfc-232-files/__root__/__testType__/__collection__/__name__-test.js +2 -2
  25. package/blueprints/initializer/files/__root__/initializers/__name__.js +2 -3
  26. package/blueprints/initializer-test/mocha-files/__root__/__testType__/__path__/__name__-test.js +6 -7
  27. package/blueprints/initializer-test/mocha-rfc-232-files/__root__/__testType__/__path__/__name__-test.js +5 -5
  28. package/blueprints/initializer-test/qunit-files/__root__/__testType__/__path__/__name__-test.js +3 -4
  29. package/blueprints/instance-initializer/files/__root__/instance-initializers/__name__.js +2 -3
  30. package/blueprints/instance-initializer-test/mocha-files/__root__/__testType__/__path__/__name__-test.js +5 -5
  31. package/blueprints/instance-initializer-test/mocha-rfc-232-files/__root__/__testType__/__path__/__name__-test.js +5 -5
  32. package/blueprints/instance-initializer-test/qunit-files/__root__/__testType__/__path__/__name__-test.js +2 -2
  33. package/blueprints/mixin/files/__root__/mixins/__name__.js +1 -2
  34. package/blueprints/mixin-test/mocha-files/__root__/__testType__/__name__-test.js +2 -2
  35. package/blueprints/mixin-test/mocha-rfc-232-files/__root__/__testType__/__name__-test.js +2 -2
  36. package/blueprints/mixin-test/qunit-files/__root__/__testType__/__name__-test.js +1 -1
  37. package/blueprints/mixin-test/qunit-rfc-232-files/__root__/__testType__/__name__-test.js +1 -1
  38. package/blueprints/route/files/__root__/__path__/__name__.js +2 -2
  39. package/blueprints/route-test/mocha-0.12-files/__root__/__testType__/__path__/__test__.js +2 -2
  40. package/blueprints/route-test/mocha-files/__root__/__testType__/__path__/__test__.js +5 -3
  41. package/blueprints/route-test/mocha-rfc-232-files/__root__/__testType__/__path__/__test__.js +2 -2
  42. package/blueprints/route-test/qunit-files/__root__/__testType__/__path__/__test__.js +1 -1
  43. package/blueprints/route-test/qunit-rfc-232-files/__root__/__testType__/__path__/__test__.js +2 -2
  44. package/blueprints/service/files/__root__/__path__/__name__.js +1 -2
  45. package/blueprints/service-test/mocha-0.12-files/__root__/__testType__/__path__/__test__.js +2 -2
  46. package/blueprints/service-test/mocha-files/__root__/__testType__/__path__/__test__.js +5 -3
  47. package/blueprints/service-test/mocha-rfc-232-files/__root__/__testType__/__path__/__test__.js +2 -2
  48. package/blueprints/service-test/qunit-files/__root__/__testType__/__path__/__test__.js +1 -1
  49. package/blueprints/service-test/qunit-rfc-232-files/__root__/__testType__/__path__/__test__.js +2 -2
  50. package/blueprints/util-test/mocha-files/__root__/__testType__/__name__-test.js +2 -2
  51. package/blueprints/util-test/mocha-rfc-232-files/__root__/__testType__/__name__-test.js +2 -2
  52. package/blueprints/util-test/qunit-files/__root__/__testType__/__name__-test.js +1 -1
  53. package/blueprints/util-test/qunit-rfc-232-files/__root__/__testType__/__name__-test.js +2 -3
  54. package/build-metadata.json +3 -3
  55. package/dist/dependencies/router_js.js +1 -1
  56. package/dist/ember-template-compiler.js +17 -144
  57. package/dist/ember-template-compiler.map +1 -1
  58. package/dist/ember-testing.js +4 -2
  59. package/dist/ember-testing.map +1 -1
  60. package/dist/ember.debug.js +843 -772
  61. package/dist/ember.debug.map +1 -1
  62. package/dist/header/license.js +1 -1
  63. package/dist/packages/@ember/-internals/container/index.js +3 -3
  64. package/dist/packages/@ember/-internals/glimmer/index.js +55 -29
  65. package/dist/packages/@ember/-internals/metal/index.js +18 -28
  66. package/dist/packages/@ember/-internals/routing/lib/location/hash_location.js +1 -1
  67. package/dist/packages/@ember/-internals/routing/lib/services/router.js +67 -12
  68. package/dist/packages/@ember/-internals/routing/lib/services/routing.js +2 -0
  69. package/dist/packages/@ember/-internals/routing/lib/system/generate_controller.js +3 -1
  70. package/dist/packages/@ember/-internals/routing/lib/system/route.js +16 -9
  71. package/dist/packages/@ember/-internals/routing/lib/system/router.js +15 -20
  72. package/dist/packages/@ember/-internals/routing/lib/utils.js +2 -1
  73. package/dist/packages/@ember/-internals/runtime/lib/compare.js +19 -5
  74. package/dist/packages/@ember/-internals/runtime/lib/mixins/comparable.js +4 -4
  75. package/dist/packages/@ember/-internals/runtime/lib/mixins/container_proxy.js +29 -29
  76. package/dist/packages/@ember/-internals/runtime/lib/mixins/registry_proxy.js +51 -50
  77. package/dist/packages/@ember/-internals/utils/index.js +1 -1
  78. package/dist/packages/@ember/application/instance.js +3 -3
  79. package/dist/packages/@ember/canary-features/index.js +6 -14
  80. package/dist/packages/@ember/debug/lib/capture-render-tree.js +2 -0
  81. package/dist/packages/@ember/debug/lib/handlers.js +1 -1
  82. package/dist/packages/@ember/runloop/index.js +31 -528
  83. package/dist/packages/@ember/runloop/type-tests.ts/begin-end.test.js +5 -0
  84. package/dist/packages/@ember/runloop/type-tests.ts/bind.test.js +59 -0
  85. package/dist/packages/@ember/runloop/type-tests.ts/cancel.test.js +5 -0
  86. package/dist/packages/@ember/runloop/type-tests.ts/debounce.test.js +77 -0
  87. package/dist/packages/@ember/runloop/type-tests.ts/join.test.js +38 -0
  88. package/dist/packages/@ember/runloop/type-tests.ts/later.test.js +38 -0
  89. package/dist/packages/@ember/runloop/type-tests.ts/next.test.js +38 -0
  90. package/dist/packages/@ember/runloop/type-tests.ts/once.test.js +38 -0
  91. package/dist/packages/@ember/runloop/type-tests.ts/run.test.js +38 -0
  92. package/dist/packages/@ember/runloop/type-tests.ts/schedule-once.test.js +39 -0
  93. package/dist/packages/@ember/runloop/type-tests.ts/schedule.test.js +39 -0
  94. package/dist/packages/@ember/runloop/type-tests.ts/throttle.test.js +77 -0
  95. package/dist/packages/ember/index.js +4 -14
  96. package/dist/packages/ember/version.js +1 -1
  97. package/docs/data.json +330 -245
  98. package/package.json +4 -4
@@ -5,5 +5,5 @@
5
5
  * Portions Copyright 2008-2011 Apple Inc. All rights reserved.
6
6
  * @license Licensed under MIT license
7
7
  * See https://raw.github.com/emberjs/ember.js/master/LICENSE
8
- * @version 4.3.0-beta.1
8
+ * @version 4.4.0-alpha.3
9
9
  */
@@ -187,8 +187,6 @@ class Container {
187
187
  @public
188
188
  @method factoryFor
189
189
  @param {String} fullName
190
- @param {Object} [options]
191
- @param {String} [options.source] The fullname of the request source (used for local lookup)
192
190
  @return {any}
193
191
  */
194
192
 
@@ -199,7 +197,9 @@ class Container {
199
197
  }
200
198
 
201
199
  let normalizedName = this.registry.normalize(fullName);
202
- assert('fullName must be a proper full name', this.registry.isValidFullName(normalizedName));
200
+ assert('fullName must be a proper full name', this.registry.isValidFullName(normalizedName)); // TODO: This needs to return a Factory to be compatible with Owner.
201
+ // We should correctly the types so that this cast is not necessary.
202
+
203
203
  return factoryFor(this, normalizedName, fullName);
204
204
  }
205
205
 
@@ -9,8 +9,9 @@ import { untrack, consumeTag, createCache, getValue, tagFor, beginUntrackFrame,
9
9
  import { tracked, get, PROPERTY_DID_CHANGE, tagForObject, objectAt, tagForProperty, set, _getProp, _setProp } from '@ember/-internals/metal';
10
10
  import { action } from '@ember/object';
11
11
  import { hasDOM } from '@ember/-internals/browser-environment';
12
- import { isSimpleClick, clearElementView, clearViewElement, getViewElement, MUTABLE_CELL, addChildView, setElementView, setViewElement, ActionSupport, ChildViewsSupport, ClassNamesSupport, CoreView, ViewMixin, ViewStateSupport, constructStyleDeprecationMessage, ActionManager, getViewId } from '@ember/-internals/views';
12
+ import { isSimpleClick, clearElementView, clearViewElement, getViewElement, MUTABLE_CELL, addChildView, setElementView, setViewElement, ActionSupport, ChildViewsSupport, ClassNamesSupport, CoreView, EventDispatcher, ViewMixin, ViewStateSupport, constructStyleDeprecationMessage, ActionManager, getViewId } from '@ember/-internals/views';
13
13
  import { getEngineParent } from '@ember/engine';
14
+ import EngineInstance from '@ember/engine/instance';
14
15
  import { flaggedInstrument, _instrumentStart } from '@ember/instrumentation';
15
16
  import { service } from '@ember/service';
16
17
  import { DEBUG } from '@glimmer/env';
@@ -1099,11 +1100,13 @@ class LinkTo extends InternalComponent {
1099
1100
  }
1100
1101
 
1101
1102
  get isEngine() {
1102
- return getEngineParent(this.owner) !== undefined;
1103
+ let owner = this.owner;
1104
+ return owner instanceof EngineInstance && getEngineParent(owner) !== undefined;
1103
1105
  }
1104
1106
 
1105
1107
  get engineMountPoint() {
1106
- return this.owner.mountPoint;
1108
+ let owner = this.owner;
1109
+ return owner instanceof EngineInstance ? owner.mountPoint : undefined;
1107
1110
  }
1108
1111
 
1109
1112
  classFor(state) {
@@ -1960,13 +1963,12 @@ function makeClosureAction(context, target, action$$1, processArgs, debugKey) {
1960
1963
  let self;
1961
1964
  let fn$$1;
1962
1965
  assert(`Action passed is null or undefined in (action) from ${target}.`, action$$1 !== undefined && action$$1 !== null);
1963
- let typeofAction = typeof action$$1;
1964
1966
 
1965
- if (typeofAction === 'string') {
1967
+ if (typeof action$$1 === 'string') {
1966
1968
  self = target;
1967
1969
  fn$$1 = target.actions && target.actions[action$$1];
1968
1970
  assert(`An action named '${action$$1}' was not found in ${target}`, Boolean(fn$$1));
1969
- } else if (typeofAction === 'function') {
1971
+ } else if (typeof action$$1 === 'function') {
1970
1972
  self = context;
1971
1973
  fn$$1 = action$$1;
1972
1974
  } else {
@@ -3165,6 +3167,7 @@ const Component = CoreView.extend(ChildViewsSupport, ViewStateSupport, ClassName
3165
3167
 
3166
3168
  if (owner.lookup('-environment:main').isInteractive) {
3167
3169
  this.__dispatcher = owner.lookup('event_dispatcher:main');
3170
+ assert('Expected dispatcher to be an EventDispatcher', this.__dispatcher instanceof EventDispatcher);
3168
3171
  } else {
3169
3172
  // In FastBoot we have no EventDispatcher. Set to null to not try again to look it up.
3170
3173
  this.__dispatcher = null;
@@ -3787,11 +3790,9 @@ class OutletComponentManager {
3787
3790
  let currentOwner = valueForRef(currentStateRef).render.owner;
3788
3791
 
3789
3792
  if (parentOwner && parentOwner !== currentOwner) {
3790
- let engine = currentOwner;
3791
- assert('invalid engine: missing mountPoint', typeof currentOwner.mountPoint === 'string');
3792
- assert('invalid engine: missing routable', currentOwner.routable === true);
3793
- let mountPoint = engine.mountPoint;
3794
- state.engine = engine;
3793
+ assert('Expected currentOwner to be an EngineInstance', currentOwner instanceof EngineInstance);
3794
+ let mountPoint = currentOwner.mountPoint;
3795
+ state.engine = currentOwner;
3795
3796
  state.engineBucket = {
3796
3797
  mountPoint
3797
3798
  };
@@ -4575,7 +4576,7 @@ var disallowDynamicResolution = internalHelper(({
4575
4576
  assert('[BUG] expecting a string literal for the `original` argument', typeof original === 'string');
4576
4577
  return createComputeRef(() => {
4577
4578
  let nameOrValue = valueForRef(nameOrValueRef);
4578
- assert(`Passing a dynamic string to the \`(${type})\` keyword is disallowed. ` + `(You specified \`(${type} ${original})\` and \`${original}\` evaluated into "${nameOrValue}".) ` + `This ensures we can statically analyze the template and determine which ${type}s are used. ` + `If the ${type} name is always the same, use a string literal instead, i.e. \`(${type} "${nameOrValue}")\`. ` + `Otherwise, import the ${type}s into JavaScript and pass them to the ${type} keyword. ` + 'See https://github.com/emberjs/rfcs/blob/master/text/0496-handlebars-strict-mode.md#4-no-dynamic-resolution for details. ' + loc, typeof nameOrValue !== 'string');
4579
+ assert(`Passing a dynamic string to the \`(${type})\` keyword is disallowed. ` + `(You specified \`(${type} ${original})\` and \`${original}\` evaluated into "${nameOrValue}".) ` + `This ensures we can statically analyze the template and determine which ${type}s are used. ` + `If the ${type} name is always the same, use a string literal instead, i.e. \`(${type} "${nameOrValue}")\`. ` + `Otherwise, import the ${type}s into JavaScript and pass them directly. ` + 'See https://github.com/emberjs/rfcs/blob/master/text/0496-handlebars-strict-mode.md#4-no-dynamic-resolution for details. ' + loc, typeof nameOrValue !== 'string');
4579
4580
  return nameOrValue;
4580
4581
  });
4581
4582
  });
@@ -4933,6 +4934,25 @@ var unbound = internalHelper(({
4933
4934
  return createUnboundRef(valueForRef(positional[0]), '(result of an `unbound` helper)');
4934
4935
  });
4935
4936
 
4937
+ /**
4938
+ @module ember
4939
+ */
4940
+ internalHelper(() => {
4941
+ return createConstRef(uniqueId$1(), 'unique-id');
4942
+ }); // From https://gist.github.com/selfish/fef2c0ba6cdfe07af76e64cecd74888b
4943
+ //
4944
+ // This code should be reasonably fast, and provide a unique value every time
4945
+ // it's called, which is what we need here. It produces a string formatted as a
4946
+ // standard UUID, which avoids accidentally turning Ember-specific
4947
+ // implementation details into an intimate API.
4948
+
4949
+ function uniqueId$1() {
4950
+ // @ts-expect-error this one-liner abuses weird JavaScript semantics that
4951
+ // TypeScript (legitimately) doesn't like, but they're nonetheless valid and
4952
+ // specced.
4953
+ return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, a => (a ^ Math.random() * 16 >> a / 4).toString(16));
4954
+ }
4955
+
4936
4956
  const MODIFIERS = ['alt', 'shift', 'meta', 'ctrl'];
4937
4957
  const POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/;
4938
4958
 
@@ -5165,6 +5185,7 @@ class ActionModifierManager {
5165
5185
 
5166
5186
  ensureEventSetup(actionState) {
5167
5187
  let dispatcher = actionState.owner.lookup('event_dispatcher:main');
5188
+ assert('Expected dispatcher to be an EventDispatcher', dispatcher instanceof EventDispatcher);
5168
5189
  dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.setupHandlerForEmberEvent(actionState.eventName);
5169
5190
  }
5170
5191
 
@@ -5218,6 +5239,7 @@ class MountManager {
5218
5239
  // mount is a runtime helper, this shouldn't use dynamic layout
5219
5240
  // we should resolve the engine app template in the helper
5220
5241
  // it also should use the owner that looked up the mount helper.
5242
+ assert('Expected owner to be an EngineInstance', owner instanceof EngineInstance);
5221
5243
  let engine = owner.buildChildEngineInstance(name);
5222
5244
  engine.boot();
5223
5245
  let applicationFactory = engine.factoryFor(`controller:application`);
@@ -5430,28 +5452,17 @@ const mountHelper = internalHelper((args, owner) => {
5430
5452
  Note: Your content __will not render__ if there isn't an `{{outlet}}` for it.
5431
5453
 
5432
5454
  @method outlet
5433
- @param {String} [name]
5434
5455
  @for Ember.Templates.helpers
5435
5456
  @public
5436
5457
  */
5437
5458
 
5438
- const outletHelper = internalHelper((args, owner, scope) => {
5459
+ const outletHelper = internalHelper((_args, owner, scope) => {
5439
5460
  assert('Expected owner to be present, {{outlet}} requires an owner', owner);
5440
5461
  assert('Expected dynamic scope to be present. You may have attempted to use the {{outlet}} keyword dynamically. This keyword cannot be used dynamically.', scope);
5441
- let nameRef;
5442
-
5443
- if (args.positional.length === 0) {
5444
- nameRef = createPrimitiveRef('main');
5445
- } else {
5446
- let maybeNameRef = args.positional[0];
5447
- assert('Expected at least one positional arg', maybeNameRef);
5448
- nameRef = maybeNameRef;
5449
- }
5450
-
5451
5462
  let outletRef = createComputeRef(() => {
5452
5463
  let state = valueForRef(scope.get('outletState'));
5453
5464
  let outlets = state !== undefined ? state.outlets : undefined;
5454
- return outlets !== undefined ? outlets[valueForRef(nameRef)] : undefined;
5465
+ return outlets !== undefined ? outlets.main : undefined;
5455
5466
  });
5456
5467
  let lastState = null;
5457
5468
  let definition = null;
@@ -5541,9 +5552,9 @@ function instrumentationPayload$1(name) {
5541
5552
  };
5542
5553
  }
5543
5554
 
5544
- function componentFor(name, owner, options) {
5555
+ function componentFor(name, owner) {
5545
5556
  let fullName = `component:${name}`;
5546
- return owner.factoryFor(fullName, options) || null;
5557
+ return owner.factoryFor(fullName) || null;
5547
5558
  }
5548
5559
 
5549
5560
  function layoutFor(name, owner, options) {
@@ -5552,7 +5563,7 @@ function layoutFor(name, owner, options) {
5552
5563
  }
5553
5564
 
5554
5565
  function lookupComponentPair(owner, name, options) {
5555
- let component = componentFor(name, owner, options);
5566
+ let component = componentFor(name, owner);
5556
5567
 
5557
5568
  if (component !== null && component.class !== undefined) {
5558
5569
  let layout = getComponentTemplate(component.class);
@@ -5613,6 +5624,7 @@ const BUILTIN_HELPERS = Object.assign(Object.assign({}, BUILTIN_KEYWORD_HELPERS)
5613
5624
  get: get$1,
5614
5625
  hash
5615
5626
  });
5627
+
5616
5628
  const BUILTIN_KEYWORD_MODIFIERS = {
5617
5629
  action: actionModifier
5618
5630
  };
@@ -6329,7 +6341,9 @@ class OutletView {
6329
6341
  target = selector;
6330
6342
  }
6331
6343
 
6332
- let renderer = this.owner.lookup('renderer:-dom');
6344
+ let renderer = this.owner.lookup('renderer:-dom'); // SAFETY: It's not clear that this cast is safe.
6345
+ // The types for appendOutletView may be incorrect or this is a potential bug.
6346
+
6333
6347
  schedule('render', renderer, 'appendOutletView', this, target);
6334
6348
  }
6335
6349
 
@@ -6391,6 +6405,18 @@ function setupEngineRegistry(registry) {
6391
6405
  }
6392
6406
  }
6393
6407
 
6408
+ /**
6409
+ Associate a class with a component manager (an object that is responsible for
6410
+ coordinating the lifecycle events that occurs when invoking, rendering and
6411
+ re-rendering a component).
6412
+
6413
+ @method setComponentManager
6414
+ @param {Function} factory a function to create the owner for an object
6415
+ @param {Object} obj the object to associate with the componetn manager
6416
+ @return {Object} the same object passed in
6417
+ @public
6418
+ */
6419
+
6394
6420
  function setComponentManager$1(manager, obj) {
6395
6421
  return setComponentManager(manager, obj);
6396
6422
  }
@@ -145,7 +145,7 @@ function sendEvent(obj, eventName, params, actions, _meta) {
145
145
  return true;
146
146
  }
147
147
  /**
148
- @private
148
+ @public
149
149
  @method hasListeners
150
150
  @static
151
151
  @for @ember/object/events
@@ -1782,20 +1782,20 @@ function get(obj, keyName) {
1782
1782
  return isPath(keyName) ? _getPath(obj, keyName) : _getProp(obj, keyName);
1783
1783
  }
1784
1784
  function _getProp(obj, keyName) {
1785
- let type = typeof obj;
1786
- let isObject$$1 = type === 'object';
1787
- let isFunction = type === 'function';
1788
- let isObjectLike = isObject$$1 || isFunction;
1785
+ if (obj == null) {
1786
+ return;
1787
+ }
1788
+
1789
1789
  let value;
1790
1790
 
1791
- if (isObjectLike) {
1791
+ if (typeof obj === 'object' || typeof obj === 'function') {
1792
1792
  if (DEBUG) {
1793
1793
  value = getPossibleMandatoryProxyValue(obj, keyName);
1794
1794
  } else {
1795
1795
  value = obj[keyName];
1796
1796
  }
1797
1797
 
1798
- if (value === undefined && isObject$$1 && !(keyName in obj) && typeof obj.unknownProperty === 'function') {
1798
+ if (value === undefined && typeof obj === 'object' && !(keyName in obj) && typeof obj.unknownProperty === 'function') {
1799
1799
  value = obj.unknownProperty(keyName);
1800
1800
  }
1801
1801
 
@@ -1809,13 +1809,13 @@ function _getProp(obj, keyName) {
1809
1809
  }
1810
1810
  }
1811
1811
  } else {
1812
+ // SAFETY: It should be ok to access properties on any non-nullish value
1812
1813
  value = obj[keyName];
1813
1814
  }
1814
1815
 
1815
1816
  return value;
1816
1817
  }
1817
- function _getPath(root, path) {
1818
- let obj = root;
1818
+ function _getPath(obj, path) {
1819
1819
  let parts = typeof path === 'string' ? path.split('.') : path;
1820
1820
 
1821
1821
  for (let part of parts) {
@@ -1838,12 +1838,12 @@ _getProp({}, 'a');
1838
1838
  _getProp({}, 1);
1839
1839
 
1840
1840
  _getProp({
1841
- unkonwnProperty() {}
1841
+ unknownProperty() {}
1842
1842
 
1843
1843
  }, 'a');
1844
1844
 
1845
1845
  _getProp({
1846
- unkonwnProperty() {}
1846
+ unknownProperty() {}
1847
1847
 
1848
1848
  }, 1);
1849
1849
 
@@ -2125,7 +2125,6 @@ function eachProxyArrayDidChange(array, idx, removedCnt, addedCnt) {
2125
2125
  confusing.
2126
2126
 
2127
2127
  ```javascript
2128
- isNone(); // true
2129
2128
  isNone(null); // true
2130
2129
  isNone(undefined); // true
2131
2130
  isNone(''); // false
@@ -2159,7 +2158,6 @@ function isNone(obj) {
2159
2158
  to check emptiness.
2160
2159
 
2161
2160
  ```javascript
2162
- isEmpty(); // true
2163
2161
  isEmpty(null); // true
2164
2162
  isEmpty(undefined); // true
2165
2163
  isEmpty(''); // true
@@ -2183,31 +2181,21 @@ function isNone(obj) {
2183
2181
  */
2184
2182
 
2185
2183
  function isEmpty(obj) {
2186
- let none = obj === null || obj === undefined;
2187
-
2188
- if (none) {
2189
- return none;
2184
+ if (obj === null || obj === undefined) {
2185
+ return true;
2190
2186
  }
2191
2187
 
2192
2188
  if (typeof obj.unknownProperty !== 'function' && typeof obj.size === 'number') {
2193
2189
  return !obj.size;
2194
2190
  }
2195
2191
 
2196
- let objectType = typeof obj;
2197
-
2198
- if (objectType === 'object') {
2192
+ if (typeof obj === 'object') {
2199
2193
  let size = get(obj, 'size');
2200
2194
 
2201
2195
  if (typeof size === 'number') {
2202
2196
  return !size;
2203
2197
  }
2204
- }
2205
-
2206
- if (typeof obj.length === 'number' && objectType !== 'function') {
2207
- return !obj.length;
2208
- }
2209
2198
 
2210
- if (objectType === 'object') {
2211
2199
  let length = get(obj, 'length');
2212
2200
 
2213
2201
  if (typeof length === 'number') {
@@ -2215,6 +2203,10 @@ function isEmpty(obj) {
2215
2203
  }
2216
2204
  }
2217
2205
 
2206
+ if (typeof obj.length === 'number' && typeof obj !== 'function') {
2207
+ return !obj.length;
2208
+ }
2209
+
2218
2210
  return false;
2219
2211
  }
2220
2212
 
@@ -2228,7 +2220,6 @@ function isEmpty(obj) {
2228
2220
  ```javascript
2229
2221
  import { isBlank } from '@ember/utils';
2230
2222
 
2231
- isBlank(); // true
2232
2223
  isBlank(null); // true
2233
2224
  isBlank(undefined); // true
2234
2225
  isBlank(''); // true
@@ -2262,7 +2253,6 @@ function isBlank(obj) {
2262
2253
  A value is present if it not `isBlank`.
2263
2254
 
2264
2255
  ```javascript
2265
- isPresent(); // false
2266
2256
  isPresent(null); // false
2267
2257
  isPresent(undefined); // false
2268
2258
  isPresent(''); // false
@@ -124,7 +124,7 @@ export default class HashLocation extends EmberObject {
124
124
  onUpdateURL(callback) {
125
125
  this._removeEventListener();
126
126
 
127
- this._hashchangeHandler = bind(this, function () {
127
+ this._hashchangeHandler = bind(this, function (_event) {
128
128
  let path = this.getURL();
129
129
 
130
130
  if (this.lastSetURL === path) {
@@ -13,6 +13,7 @@ import { assert } from '@ember/debug';
13
13
  import { readOnly } from '@ember/object/computed';
14
14
  import Service from '@ember/service';
15
15
  import { consumeTag, tagFor } from '@glimmer/validator';
16
+ import EmberRouter from '../system/router';
16
17
  import { extractRouteArgs, resemblesURL, shallowEqual } from '../utils';
17
18
  const ROUTER = symbol('ROUTER');
18
19
 
@@ -27,6 +28,55 @@ function cleanURL(url, rootURL) {
27
28
  class RouterService extends Service.extend(Evented) {
28
29
  constructor() {
29
30
  super(...arguments);
31
+ /**
32
+ You can register a listener for events emitted by this service with `.on()`:
33
+ ```app/routes/contact-form.js
34
+ import Route from '@ember/routing';
35
+ import { service } from '@ember/service';
36
+ export default class extends Route {
37
+ @service router;
38
+ activate() {
39
+ this.router.on('routeWillChange', (transition) => {
40
+ if (!transition.to.find(route => route.name === this.routeName)) {
41
+ alert("Please save or cancel your changes.");
42
+ transition.abort();
43
+ }
44
+ })
45
+ }
46
+ }
47
+ ```
48
+ @method on
49
+ @param {String} eventName
50
+ @param {Function} callback
51
+ @public
52
+ */
53
+
54
+ /**
55
+ You can unregister a listener for events emitted by this service with `.off()`:
56
+ ```app/routes/contact-form.js
57
+ import Route from '@ember/routing';
58
+ import { service } from '@ember/service';
59
+ export default class extends Route {
60
+ @service router;
61
+ callback = (transition) => {
62
+ if (!transition.to.find(route => route.name === this.routeName)) {
63
+ alert("Please save or cancel your changes.");
64
+ transition.abort();
65
+ }
66
+ };
67
+ activate() {
68
+ this.router.on('routeWillChange', this.callback);
69
+ }
70
+ deactivate() {
71
+ this.router.off('routeWillChange', this.callback);
72
+ }
73
+ ```
74
+ @method off
75
+ @param {String} eventName
76
+ @param {Function} callback
77
+ @public
78
+ */
79
+
30
80
  /**
31
81
  The `routeWillChange` event is fired at the beginning of any
32
82
  attempted transition with a `Transition` object as the sole
@@ -39,9 +89,8 @@ class RouterService extends Service.extend(Evented) {
39
89
  import { service } from '@ember/service';
40
90
  export default class extends Route {
41
91
  @service router;
42
- constructor() {
43
- super(...arguments);
44
- this.router.on('routeWillChange', (transition) => {
92
+ activate() {
93
+ this.router.on('routeWillChange', (transition) => {
45
94
  if (!transition.to.find(route => route.name === this.routeName)) {
46
95
  alert("Please save or cancel your changes.");
47
96
  transition.abort();
@@ -66,9 +115,8 @@ class RouterService extends Service.extend(Evented) {
66
115
  import { service } from '@ember/service';
67
116
  export default class extends Route {
68
117
  @service router;
69
- constructor() {
70
- super(...arguments);
71
- this.router.on('routeDidChange', (transition) => {
118
+ activate() {
119
+ this.router.on('routeDidChange', (transition) => {
72
120
  ga.send('pageView', {
73
121
  current: transition.to.name,
74
122
  from: transition.from.name
@@ -133,6 +181,7 @@ class RouterService extends Service.extend(Evented) {
133
181
  let owner = getOwner(this);
134
182
  assert('RouterService is unexpectedly missing an owner', owner);
135
183
  router = owner.lookup('router:main');
184
+ assert('ROUTER SERVICE BUG: Expected router to be an instance of EmberRouter', router instanceof EmberRouter);
136
185
  return this[ROUTER] = router;
137
186
  }
138
187
 
@@ -195,7 +244,6 @@ class RouterService extends Service.extend(Evented) {
195
244
 
196
245
  let transition = this._router._doTransition(routeName, models, queryParams, true);
197
246
 
198
- transition['_keepDefaultQueryParamValues'] = true;
199
247
  return transition;
200
248
  }
201
249
  /**
@@ -366,19 +414,26 @@ class RouterService extends Service.extend(Evented) {
366
414
  let hasQueryParams = Object.keys(queryParams).length > 0;
367
415
 
368
416
  if (hasQueryParams) {
369
- queryParams = Object.assign({}, queryParams);
370
-
371
- this._router._prepareQueryParams( // UNSAFE: casting `routeName as string` here encodes the existing
417
+ // UNSAFE: casting `routeName as string` here encodes the existing
372
418
  // assumption but may be wrong: `extractRouteArgs` correctly returns it
373
419
  // as `string | undefined`. There may be bugs if `_prepareQueryParams`
374
420
  // does not correctly account for `undefined` values for `routeName`.
375
421
  // Spoilers: under the hood this currently uses router.js APIs which
376
422
  // *do not* account for this being `undefined`.
377
- routeName, models, queryParams, true
423
+ let targetRouteName = routeName;
424
+ queryParams = Object.assign({}, queryParams);
425
+
426
+ this._router._prepareQueryParams(targetRouteName, models, queryParams, true
427
+ /* fromRouterService */
428
+ );
429
+
430
+ let currentQueryParams = Object.assign({}, routerMicrolib.state.queryParams);
431
+
432
+ this._router._prepareQueryParams(targetRouteName, models, currentQueryParams, true
378
433
  /* fromRouterService */
379
434
  );
380
435
 
381
- return shallowEqual(queryParams, routerMicrolib.state.queryParams);
436
+ return shallowEqual(queryParams, currentQueryParams);
382
437
  }
383
438
 
384
439
  return true;
@@ -6,6 +6,7 @@ import { symbol } from '@ember/-internals/utils';
6
6
  import { assert } from '@ember/debug';
7
7
  import { readOnly } from '@ember/object/computed';
8
8
  import Service from '@ember/service';
9
+ import EmberRouter from '../system/router';
9
10
  const ROUTER = symbol('ROUTER');
10
11
  /**
11
12
  The Routing service is used by LinkTo, and provides facilities for
@@ -29,6 +30,7 @@ export default class RoutingService extends Service {
29
30
  let owner = getOwner(this);
30
31
  assert('RoutingService is unexpectedly missing an owner', owner);
31
32
  router = owner.lookup('router:main');
33
+ assert('ROUTING SERVICE BUG: Expected router to be an instance of EmberRouter', router instanceof EmberRouter);
32
34
  router.setupRouter();
33
35
  return this[ROUTER] = router;
34
36
  }
@@ -1,5 +1,6 @@
1
1
  import { get } from '@ember/-internals/metal';
2
- import { info } from '@ember/debug';
2
+ import Controller from '@ember/controller';
3
+ import { assert, info } from '@ember/debug';
3
4
  import { DEBUG } from '@glimmer/env';
4
5
  /**
5
6
  @module ember
@@ -39,6 +40,7 @@ export default function generateController(owner, controllerName) {
39
40
  generateControllerFactory(owner, controllerName);
40
41
  let fullName = `controller:${controllerName}`;
41
42
  let instance = owner.lookup(fullName);
43
+ assert('Expected an instance of controller', instance instanceof Controller);
42
44
 
43
45
  if (DEBUG) {
44
46
  if (get(instance, 'namespace.LOG_ACTIVE_GENERATION')) {
@@ -9,27 +9,31 @@ var __decorate = this && this.__decorate || function (decorators, target, key, d
9
9
  import { privatize as P } from '@ember/-internals/container';
10
10
  import { addObserver, computed, defineProperty, descriptorForProperty, flushAsyncObservers, get, getProperties, isEmpty, set, setProperties } from '@ember/-internals/metal';
11
11
  import { getOwner } from '@ember/-internals/owner';
12
+ import { BucketCache } from '@ember/-internals/routing';
12
13
  import { A as emberA, ActionHandler, Evented, Object as EmberObject, typeOf } from '@ember/-internals/runtime';
13
14
  import { isProxy, lookupDescriptor, symbol } from '@ember/-internals/utils';
15
+ import Controller from '@ember/controller';
14
16
  import { assert, info, isTesting } from '@ember/debug';
17
+ import EngineInstance from '@ember/engine/instance';
15
18
  import { dependentKeyCompat } from '@ember/object/compat';
16
19
  import { once } from '@ember/runloop';
17
20
  import { DEBUG } from '@glimmer/env';
18
21
  import { PARAMS_SYMBOL, STATE_SYMBOL } from 'router_js';
19
22
  import { calculateCacheKey, deprecateTransitionMethods, normalizeControllerQueryParams, prefixRouteNameArg, stashParamNames } from '../utils';
20
23
  import generateController from './generate_controller';
24
+ import EmberRouter from './router';
21
25
  export const ROUTE_CONNECTIONS = new WeakMap();
22
26
  const RENDER = symbol('render');
23
27
 
24
28
  class Route extends EmberObject.extend(ActionHandler, Evented) {
25
29
  constructor(owner) {
26
- super(...arguments);
30
+ super(owner);
27
31
  this.context = {};
28
32
 
29
33
  if (owner) {
30
34
  let router = owner.lookup('router:main');
31
35
  let bucketCache = owner.lookup(P`-bucket-cache:main`);
32
- assert('ROUTER BUG: Expected route injections to be defined on the route. This is an internal bug, please open an issue on Github if you see this message!', router && bucketCache);
36
+ assert('ROUTER BUG: Expected route injections to be defined on the route. This is an internal bug, please open an issue on Github if you see this message!', router instanceof EmberRouter && bucketCache instanceof BucketCache);
33
37
  this._router = router;
34
38
  this._bucketCache = bucketCache;
35
39
  this._topLevelViewTemplate = owner.lookup('template:-outlet');
@@ -110,7 +114,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
110
114
  _setRouteName(name) {
111
115
  this.routeName = name;
112
116
  let owner = getOwner(this);
113
- assert('Route is unexpectedly missing an owner', owner);
117
+ assert('Expected route to have EngineInstance as owner', owner instanceof EngineInstance);
114
118
  this.fullRouteName = getEngineRouteName(owner, name);
115
119
  }
116
120
  /**
@@ -836,8 +840,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
836
840
  } else {
837
841
  if (transition.resolveIndex < 1) {
838
842
  return;
839
- } // SAFETY: These return types should be equivalent but router.js doesn't have enough
840
- // generics to infer it.
843
+ } // SAFETY: This should be correct, but TS is unable to infer this.
841
844
 
842
845
 
843
846
  return transition[STATE_SYMBOL].routeInfos[transition.resolveIndex - 1].context;
@@ -944,6 +947,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
944
947
  // passed a model to skip the assertion.
945
948
 
946
949
  assert(`The controller named '${name}' could not be found. Make sure that this route exists and has already been entered at least once. If you are accessing a controller not associated with a route, make sure the controller class is explicitly defined.`, controller !== undefined || _skipAssert === true);
950
+ assert(`Expected controller:${name} to be an instance of Controller`, controller === undefined || controller instanceof Controller);
947
951
  return controller;
948
952
  }
949
953
  /**
@@ -1008,7 +1012,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1008
1012
  modelFor(_name) {
1009
1013
  let name;
1010
1014
  let owner = getOwner(this);
1011
- assert('Route is unexpectedly missing an owner', owner);
1015
+ assert('Expected router owner to be an EngineInstance', owner instanceof EngineInstance);
1012
1016
  let transition = this._router && this._router._routerMicrolib ? this._router._routerMicrolib.activeTransition : undefined; // Only change the route name when there is an active transition.
1013
1017
  // Otherwise, use the passed in route name.
1014
1018
 
@@ -1136,10 +1140,11 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1136
1140
  let hasRouterDefinedQueryParams = Object.keys(queryParameterConfiguraton).length > 0;
1137
1141
 
1138
1142
  if (controller) {
1139
- // the developer has authored a controller class in their application for
1143
+ assert('Expected an instance of controller', controller instanceof Controller); // the developer has authored a controller class in their application for
1140
1144
  // this route find its query params and normalize their object shape them
1141
1145
  // merge in the query params for the route. As a mergedProperty,
1142
1146
  // Route#queryParams is always at least `{}`
1147
+
1143
1148
  let controllerDefinedQueryParameterConfiguration = get(controller, 'queryParams') || [];
1144
1149
  let normalizedControllerQueryParameterConfiguration = normalizeControllerQueryParams(controllerDefinedQueryParameterConfiguration);
1145
1150
  combinedQueryParameterConfiguration = mergeEachQueryParams(normalizedControllerQueryParameterConfiguration, queryParameterConfiguraton);
@@ -1299,7 +1304,7 @@ function buildRenderOptions(route, nameOrOptions, options) {
1299
1304
  let owner = getOwner(route);
1300
1305
  assert('Route is unexpectedly missing an owner', owner);
1301
1306
  let name, templateName, into, outlet, model;
1302
- let controller = undefined;
1307
+ let controller;
1303
1308
 
1304
1309
  if (options) {
1305
1310
  into = options.into && options.into.replace(/\//g, '.');
@@ -1332,6 +1337,8 @@ function buildRenderOptions(route, nameOrOptions, options) {
1332
1337
  assert(`You passed \`controller: '${controllerName}'\` into the \`render\` method, but no such controller could be found.`, isDefaultRender || controller !== undefined);
1333
1338
  }
1334
1339
 
1340
+ assert('Expected an instance of controller', controller instanceof Controller);
1341
+
1335
1342
  if (model === undefined) {
1336
1343
  model = route.currentModel;
1337
1344
  } else {
@@ -1656,7 +1663,7 @@ Route.reopen({
1656
1663
  qp.serializedValue = svalue;
1657
1664
  let thisQueryParamHasDefaultValue = qp.serializedDefaultValue === svalue;
1658
1665
 
1659
- if (!thisQueryParamHasDefaultValue || transition._keepDefaultQueryParamValues) {
1666
+ if (!thisQueryParamHasDefaultValue) {
1660
1667
  finalParams.push({
1661
1668
  value: svalue,
1662
1669
  visible: true,