ember-source 4.3.0-alpha.2 → 4.4.0-alpha.1

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 (44) hide show
  1. package/CHANGELOG.md +6 -2
  2. package/build-metadata.json +3 -3
  3. package/dist/dependencies/router_js.js +66 -31
  4. package/dist/ember-template-compiler.js +1169 -779
  5. package/dist/ember-template-compiler.map +1 -1
  6. package/dist/ember-testing.js +74 -43
  7. package/dist/ember-testing.map +1 -1
  8. package/dist/ember.debug.js +3290 -2760
  9. package/dist/ember.debug.map +1 -1
  10. package/dist/header/license.js +1 -1
  11. package/dist/packages/@ember/-internals/container/index.js +15 -11
  12. package/dist/packages/@ember/-internals/extension-support/lib/container_debug_adapter.js +3 -3
  13. package/dist/packages/@ember/-internals/extension-support/lib/data_adapter.js +52 -52
  14. package/dist/packages/@ember/-internals/glimmer/index.js +139 -103
  15. package/dist/packages/@ember/-internals/meta/lib/meta.js +8 -9
  16. package/dist/packages/@ember/-internals/metal/index.js +44 -45
  17. package/dist/packages/@ember/-internals/routing/lib/ext/controller.js +10 -8
  18. package/dist/packages/@ember/-internals/routing/lib/location/auto_location.js +3 -1
  19. package/dist/packages/@ember/-internals/routing/lib/services/router.js +155 -190
  20. package/dist/packages/@ember/-internals/routing/lib/services/routing.js +3 -1
  21. package/dist/packages/@ember/-internals/routing/lib/system/route-info.js +2 -2
  22. package/dist/packages/@ember/-internals/routing/lib/system/route.js +110 -378
  23. package/dist/packages/@ember/-internals/routing/lib/system/router.js +74 -36
  24. package/dist/packages/@ember/-internals/routing/lib/utils.js +33 -21
  25. package/dist/packages/@ember/-internals/runtime/lib/mixins/-proxy.js +1 -1
  26. package/dist/packages/@ember/-internals/runtime/lib/mixins/array.js +1 -0
  27. package/dist/packages/@ember/-internals/runtime/lib/mixins/comparable.js +4 -4
  28. package/dist/packages/@ember/-internals/runtime/lib/mixins/container_proxy.js +29 -29
  29. package/dist/packages/@ember/-internals/runtime/lib/mixins/promise_proxy.js +16 -16
  30. package/dist/packages/@ember/-internals/runtime/lib/mixins/registry_proxy.js +48 -48
  31. package/dist/packages/@ember/-internals/runtime/lib/mixins/target_action_support.js +8 -8
  32. package/dist/packages/@ember/-internals/runtime/lib/system/namespace.js +1 -2
  33. package/dist/packages/@ember/-internals/runtime/lib/type-of.js +1 -1
  34. package/dist/packages/@ember/-internals/utils/index.js +10 -8
  35. package/dist/packages/@ember/-internals/views/lib/system/utils.js +2 -0
  36. package/dist/packages/@ember/array/index.js +1 -1
  37. package/dist/packages/@ember/controller/index.js +3 -54
  38. package/dist/packages/@ember/instrumentation/index.js +9 -13
  39. package/dist/packages/@ember/object/compat.js +16 -7
  40. package/dist/packages/@ember/routing/router-service.js +1 -0
  41. package/dist/packages/@ember/service/index.js +6 -73
  42. package/dist/packages/ember/version.js +1 -1
  43. package/docs/data.json +571 -521
  44. package/package.json +13 -13
@@ -20,47 +20,6 @@ import { calculateCacheKey, deprecateTransitionMethods, normalizeControllerQuery
20
20
  import generateController from './generate_controller';
21
21
  export const ROUTE_CONNECTIONS = new WeakMap();
22
22
  const RENDER = symbol('render');
23
- export function defaultSerialize(model, params) {
24
- if (params.length < 1 || !model) {
25
- return;
26
- }
27
-
28
- let object = {};
29
-
30
- if (params.length === 1) {
31
- let [name] = params;
32
-
33
- if (name in model) {
34
- object[name] = get(model, name);
35
- } else if (/_id$/.test(name)) {
36
- object[name] = get(model, 'id');
37
- } else if (isProxy(model)) {
38
- object[name] = get(model, name);
39
- }
40
- } else {
41
- object = getProperties(model, params);
42
- }
43
-
44
- return object;
45
- }
46
- export function hasDefaultSerialize(route) {
47
- return route.serialize === defaultSerialize;
48
- }
49
- /**
50
- @module @ember/routing
51
- */
52
-
53
- /**
54
- The `Route` class is used to define individual routes. Refer to
55
- the [routing guide](https://guides.emberjs.com/release/routing/) for documentation.
56
-
57
- @class Route
58
- @extends EmberObject
59
- @uses ActionHandler
60
- @uses Evented
61
- @since 1.0.0
62
- @public
63
- */
64
23
 
65
24
  class Route extends EmberObject.extend(ActionHandler, Evented) {
66
25
  constructor(owner) {
@@ -77,6 +36,68 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
77
36
  this._environment = owner.lookup('-environment:main');
78
37
  }
79
38
  }
39
+ /**
40
+ A hook you can implement to convert the route's model into parameters
41
+ for the URL.
42
+ ```app/router.js
43
+ // ...
44
+ Router.map(function() {
45
+ this.route('post', { path: '/posts/:post_id' });
46
+ });
47
+ ```
48
+ ```app/routes/post.js
49
+ import Route from '@ember/routing/route';
50
+ export default class PostRoute extends Route {
51
+ model({ post_id }) {
52
+ // the server returns `{ id: 12 }`
53
+ return fetch(`/posts/${post_id}`;
54
+ }
55
+ serialize(model) {
56
+ // this will make the URL `/posts/12`
57
+ return { post_id: model.id };
58
+ }
59
+ }
60
+ ```
61
+ The default `serialize` method will insert the model's `id` into the
62
+ route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'.
63
+ If the route has multiple dynamic segments or does not contain '_id', `serialize`
64
+ will return `getProperties(model, params)`
65
+ This method is called when `transitionTo` is called with a context
66
+ in order to populate the URL.
67
+ @method serialize
68
+ @param {Object} model the routes model
69
+ @param {Array} params an Array of parameter names for the current
70
+ route (in the example, `['post_id']`.
71
+ @return {Object} the serialized parameters
72
+ @since 1.0.0
73
+ @public
74
+ */
75
+
76
+
77
+ serialize(model, params) {
78
+ if (params.length < 1 || !model) {
79
+ return;
80
+ }
81
+
82
+ let object = {};
83
+
84
+ if (params.length === 1) {
85
+ let [name] = params;
86
+ assert('has name', name);
87
+
88
+ if (name in model) {
89
+ object[name] = get(model, name);
90
+ } else if (/_id$/.test(name)) {
91
+ object[name] = get(model, 'id');
92
+ } else if (isProxy(model)) {
93
+ object[name] = get(model, name);
94
+ }
95
+ } else {
96
+ object = getProperties(model, params);
97
+ }
98
+
99
+ return object;
100
+ }
80
101
  /**
81
102
  Sets the name for this route, including a fully resolved name for routes
82
103
  inside engines.
@@ -88,7 +109,9 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
88
109
 
89
110
  _setRouteName(name) {
90
111
  this.routeName = name;
91
- this.fullRouteName = getEngineRouteName(getOwner(this), name);
112
+ let owner = getOwner(this);
113
+ assert('Route is unexpectedly missing an owner', owner);
114
+ this.fullRouteName = getEngineRouteName(owner, name);
92
115
  }
93
116
  /**
94
117
  @private
@@ -116,9 +139,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
116
139
  namePaths[a] = `${routeInfo.name}.${names[a]}`;
117
140
  }
118
141
 
119
- for (let i = 0; i < qps.length; ++i) {
120
- let qp = qps[i];
121
-
142
+ for (let qp of qps) {
122
143
  if (qp.scope === 'model') {
123
144
  qp.parts = namePaths;
124
145
  }
@@ -188,7 +209,9 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
188
209
 
189
210
 
190
211
  paramsFor(name) {
191
- let route = getOwner(this).lookup(`route:${name}`);
212
+ let owner = getOwner(this);
213
+ assert('Route is unexpectedly missing an owner', owner);
214
+ let route = owner.lookup(`route:${name}`);
192
215
 
193
216
  if (route === undefined) {
194
217
  return {};
@@ -199,9 +222,9 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
199
222
  let fullName = route.fullRouteName;
200
223
  let params = Object.assign({}, state.params[fullName]);
201
224
  let queryParams = getQueryParamsFor(route, state);
202
- return Object.keys(queryParams).reduce((params, key) => {
225
+ return Object.entries(queryParams).reduce((params, [key, value]) => {
203
226
  assert(`The route '${this.routeName}' has both a dynamic segment and query param with name '${key}'. Please rename one to avoid collisions.`, !params[key]);
204
- params[key] = queryParams[key];
227
+ params[key] = value;
205
228
  return params;
206
229
  }, params);
207
230
  }
@@ -318,148 +341,6 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
318
341
  this.activate(transition);
319
342
  this.trigger('activate', transition);
320
343
  }
321
- /**
322
- The `willTransition` action is fired at the beginning of any
323
- attempted transition with a `Transition` object as the sole
324
- argument. This action can be used for aborting, redirecting,
325
- or decorating the transition from the currently active routes.
326
- A good example is preventing navigation when a form is
327
- half-filled out:
328
- ```app/routes/contact-form.js
329
- import Route from '@ember/routing/route';
330
- import { action } from '@ember/object';
331
- export default class ContactFormRoute extends Route {
332
- @action
333
- willTransition(transition) {
334
- if (this.controller.get('userHasEnteredData')) {
335
- this.controller.displayNavigationConfirm();
336
- transition.abort();
337
- }
338
- }
339
- }
340
- ```
341
- You can also redirect elsewhere by calling
342
- `this.transitionTo('elsewhere')` from within `willTransition`.
343
- Note that `willTransition` will not be fired for the
344
- redirecting `transitionTo`, since `willTransition` doesn't
345
- fire when there is already a transition underway. If you want
346
- subsequent `willTransition` actions to fire for the redirecting
347
- transition, you must first explicitly call
348
- `transition.abort()`.
349
- To allow the `willTransition` event to continue bubbling to the parent
350
- route, use `return true;`. When the `willTransition` method has a
351
- return value of `true` then the parent route's `willTransition` method
352
- will be fired, enabling "bubbling" behavior for the event.
353
- @event willTransition
354
- @param {Transition} transition
355
- @since 1.0.0
356
- @public
357
- */
358
-
359
- /**
360
- The `didTransition` action is fired after a transition has
361
- successfully been completed. This occurs after the normal model
362
- hooks (`beforeModel`, `model`, `afterModel`, `setupController`)
363
- have resolved. The `didTransition` action has no arguments,
364
- however, it can be useful for tracking page views or resetting
365
- state on the controller.
366
- ```app/routes/login.js
367
- import Route from '@ember/routing/route';
368
- import { action } from '@ember/object';
369
- export default class LoginRoute extends Route {
370
- @action
371
- didTransition() {
372
- this.controller.get('errors.base').clear();
373
- return true; // Bubble the didTransition event
374
- }
375
- }
376
- ```
377
- @event didTransition
378
- @since 1.2.0
379
- @public
380
- */
381
-
382
- /**
383
- The `loading` action is fired on the route when a route's `model`
384
- hook returns a promise that is not already resolved. The current
385
- `Transition` object is the first parameter and the route that
386
- triggered the loading event is the second parameter.
387
- ```app/routes/application.js
388
- import Route from '@ember/routing/route';
389
- import { action } from '@ember/object';
390
- export default class ApplicationRoute extends Route {
391
- @action
392
- loading(transition, route) {
393
- let controller = this.controllerFor('foo');
394
- // The controller may not be instantiated when initially loading
395
- if (controller) {
396
- controller.currentlyLoading = true;
397
- transition.finally(function() {
398
- controller.currentlyLoading = false;
399
- });
400
- }
401
- }
402
- }
403
- ```
404
- @event loading
405
- @param {Transition} transition
406
- @param {Route} route The route that triggered the loading event
407
- @since 1.2.0
408
- @public
409
- */
410
-
411
- /**
412
- When attempting to transition into a route, any of the hooks
413
- may return a promise that rejects, at which point an `error`
414
- action will be fired on the partially-entered routes, allowing
415
- for per-route error handling logic, or shared error handling
416
- logic defined on a parent route.
417
- Here is an example of an error handler that will be invoked
418
- for rejected promises from the various hooks on the route,
419
- as well as any unhandled errors from child routes:
420
- ```app/routes/admin.js
421
- import { reject } from 'rsvp';
422
- import Route from '@ember/routing/route';
423
- import { action } from '@ember/object';
424
- export default class AdminRoute extends Route {
425
- beforeModel() {
426
- return reject('bad things!');
427
- }
428
- @action
429
- error(error, transition) {
430
- // Assuming we got here due to the error in `beforeModel`,
431
- // we can expect that error === "bad things!",
432
- // but a promise model rejecting would also
433
- // call this hook, as would any errors encountered
434
- // in `afterModel`.
435
- // The `error` hook is also provided the failed
436
- // `transition`, which can be stored and later
437
- // `.retry()`d if desired.
438
- this.transitionTo('login');
439
- }
440
- }
441
- ```
442
- `error` actions that bubble up all the way to `ApplicationRoute`
443
- will fire a default error handler that logs the error. You can
444
- specify your own global default error handler by overriding the
445
- `error` handler on `ApplicationRoute`:
446
- ```app/routes/application.js
447
- import Route from '@ember/routing/route';
448
- import { action } from '@ember/object';
449
- export default class ApplicationRoute extends Route {
450
- @action
451
- error(error, transition) {
452
- this.controllerFor('banner').displayError(error.message);
453
- }
454
- }
455
- ```
456
- @event error
457
- @param {Error} error
458
- @param {Transition} transition
459
- @since 1.0.0
460
- @public
461
- */
462
-
463
344
  /**
464
345
  This event is triggered when the router enters the route. It is
465
346
  not executed when the model for the route changes.
@@ -770,14 +651,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
770
651
  setup(context, transition) {
771
652
  let controllerName = this.controllerName || this.routeName;
772
653
  let definedController = this.controllerFor(controllerName, true);
773
- let controller;
774
-
775
- if (definedController) {
776
- controller = definedController;
777
- } else {
778
- controller = this.generateController(controllerName);
779
- } // SAFETY: Since `_qp` is protected we can't infer the type
780
-
654
+ let controller = definedController !== null && definedController !== void 0 ? definedController : this.generateController(controllerName); // SAFETY: Since `_qp` is protected we can't infer the type
781
655
 
782
656
  let queryParams = get(this, '_qp'); // Assign the route's controller so that it can more easily be
783
657
  // referenced in action handlers. Side effects. Side effects everywhere.
@@ -799,6 +673,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
799
673
  let allParams = queryParams.propertyNames;
800
674
  allParams.forEach(prop => {
801
675
  let aQp = queryParams.map[prop];
676
+ assert('expected aQp', aQp);
802
677
  aQp.values = params;
803
678
  let cacheKey = calculateCacheKey(aQp.route.fullRouteName, aQp.parts, aQp.values);
804
679
  let value = cache.lookup(cacheKey, prop, aQp.undecoratedDefaultValue);
@@ -835,71 +710,10 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
835
710
  let cacheKey = calculateCacheKey(qp.route.fullRouteName, qp.parts, qp.values);
836
711
  cache.stash(cacheKey, prop, value);
837
712
  }
838
- /**
839
- This hook is the first of the route entry validation hooks
840
- called when an attempt is made to transition into a route
841
- or one of its children. It is called before `model` and
842
- `afterModel`, and is appropriate for cases when:
843
- 1) A decision can be made to redirect elsewhere without
844
- needing to resolve the model first.
845
- 2) Any async operations need to occur first before the
846
- model is attempted to be resolved.
847
- This hook is provided the current `transition` attempt
848
- as a parameter, which can be used to `.abort()` the transition,
849
- save it for a later `.retry()`, or retrieve values set
850
- on it from a previous hook. You can also just call
851
- `this.transitionTo` to another route to implicitly
852
- abort the `transition`.
853
- You can return a promise from this hook to pause the
854
- transition until the promise resolves (or rejects). This could
855
- be useful, for instance, for retrieving async code from
856
- the server that is required to enter a route.
857
- @method beforeModel
858
- @param {Transition} transition
859
- @return {any | Promise<any>} if the value returned from this hook is
860
- a promise, the transition will pause until the transition
861
- resolves. Otherwise, non-promise return values are not
862
- utilized in any way.
863
- @since 1.0.0
864
- @public
865
- */
866
-
867
-
868
- beforeModel() {}
869
- /**
870
- This hook is called after this route's model has resolved.
871
- It follows identical async/promise semantics to `beforeModel`
872
- but is provided the route's resolved model in addition to
873
- the `transition`, and is therefore suited to performing
874
- logic that can only take place after the model has already
875
- resolved.
876
- ```app/routes/posts.js
877
- import Route from '@ember/routing/route';
878
- export default class PostsRoute extends Route {
879
- afterModel(posts, transition) {
880
- if (posts.get('length') === 1) {
881
- this.transitionTo('post.show', posts.get('firstObject'));
882
- }
883
- }
884
- }
885
- ```
886
- Refer to documentation for `beforeModel` for a description
887
- of transition-pausing semantics when a promise is returned
888
- from this hook.
889
- @method afterModel
890
- @param {Object} resolvedModel the value returned from `model`,
891
- or its resolved value if it was a promise
892
- @param {Transition} transition
893
- @return {any | Promise<any>} if the value returned from this hook is
894
- a promise, the transition will pause until the transition
895
- resolves. Otherwise, non-promise return values are not
896
- utilized in any way.
897
- @since 1.0.0
898
- @public
899
- */
900
713
 
714
+ beforeModel(_transition) {}
901
715
 
902
- afterModel() {}
716
+ afterModel(_resolvedModel, _transition) {}
903
717
  /**
904
718
  A hook you can implement to optionally redirect to another route.
905
719
  Calling `this.transitionTo` from inside of the `redirect` hook will
@@ -922,7 +736,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
922
736
  */
923
737
 
924
738
 
925
- redirect() {}
739
+ redirect(_model, _transition) {}
926
740
  /**
927
741
  Called when the context is changed by router.js.
928
742
  @private
@@ -1017,11 +831,13 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1017
831
 
1018
832
  if (!name) {
1019
833
  if (sawParams) {
834
+ // SAFETY: This should be equivalent
1020
835
  return Object.assign({}, params);
1021
836
  } else {
1022
837
  if (transition.resolveIndex < 1) {
1023
838
  return;
1024
- }
839
+ } // SAFETY: This should be correct, but TS is unable to infer this.
840
+
1025
841
 
1026
842
  return transition[STATE_SYMBOL].routeInfos[transition.resolveIndex - 1].context;
1027
843
  }
@@ -1112,30 +928,10 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1112
928
  set(controller, 'model', context);
1113
929
  }
1114
930
  }
1115
- /**
1116
- Returns the controller of the current route, or a parent (or any ancestor)
1117
- route in a route hierarchy.
1118
- The controller instance must already have been created, either through entering the
1119
- associated route or using `generateController`.
1120
- ```app/routes/post.js
1121
- import Route from '@ember/routing/route';
1122
- export default class PostRoute extends Route {
1123
- setupController(controller, post) {
1124
- super.setupController(controller, post);
1125
- this.controllerFor('posts').set('currentPost', post);
1126
- }
1127
- }
1128
- ```
1129
- @method controllerFor
1130
- @param {String} name the name of the route or controller
1131
- @return {Controller}
1132
- @since 1.0.0
1133
- @public
1134
- */
1135
931
 
1136
-
1137
- controllerFor(name, _skipAssert) {
932
+ controllerFor(name, _skipAssert = false) {
1138
933
  let owner = getOwner(this);
934
+ assert('Route is unexpectedly missing an owner', owner);
1139
935
  let route = owner.lookup(`route:${name}`);
1140
936
 
1141
937
  if (route && route.controllerName) {
@@ -1169,6 +965,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1169
965
 
1170
966
  generateController(name) {
1171
967
  let owner = getOwner(this);
968
+ assert('Route is unexpectedly missing an owner', owner);
1172
969
  return generateController(owner, name);
1173
970
  }
1174
971
  /**
@@ -1210,6 +1007,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1210
1007
  modelFor(_name) {
1211
1008
  let name;
1212
1009
  let owner = getOwner(this);
1010
+ assert('Route is unexpectedly missing an owner', owner);
1213
1011
  let transition = this._router && this._router._routerMicrolib ? this._router._routerMicrolib.activeTransition : undefined; // Only change the route name when there is an active transition.
1214
1012
  // Otherwise, use the passed in route name.
1215
1013
 
@@ -1230,7 +1028,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1230
1028
  }
1231
1029
  }
1232
1030
 
1233
- return route && route.currentModel;
1031
+ return route === null || route === void 0 ? void 0 : route.currentModel;
1234
1032
  }
1235
1033
  /**
1236
1034
  `this[RENDER]` is used to render a template into a region of another template
@@ -1273,39 +1071,6 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1273
1071
  once(this._router, '_setOutlets');
1274
1072
  }
1275
1073
  }
1276
- /**
1277
- Allows you to produce custom metadata for the route.
1278
- The return value of this method will be attached to
1279
- its corresponding RouteInfoWithAttributes object.
1280
- Example
1281
- ```app/routes/posts/index.js
1282
- import Route from '@ember/routing/route';
1283
- export default class PostsIndexRoute extends Route {
1284
- buildRouteInfoMetadata() {
1285
- return { title: 'Posts Page' }
1286
- }
1287
- }
1288
- ```
1289
- ```app/routes/application.js
1290
- import Route from '@ember/routing/route';
1291
- import { service } from '@ember/service';
1292
- export default class ApplicationRoute extends Route {
1293
- @service router
1294
- constructor() {
1295
- super(...arguments);
1296
- this.router.on('routeDidChange', transition => {
1297
- document.title = transition.to.metadata.title;
1298
- // would update document's title to "Posts Page"
1299
- });
1300
- }
1301
- }
1302
- ```
1303
- @method buildRouteInfoMetadata
1304
- @return any
1305
- @since 3.10.0
1306
- @public
1307
- */
1308
-
1309
1074
 
1310
1075
  buildRouteInfoMetadata() {}
1311
1076
 
@@ -1331,7 +1096,8 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1331
1096
 
1332
1097
 
1333
1098
  get store() {
1334
- let owner = getOwner(this);
1099
+ const owner = getOwner(this);
1100
+ assert('Route is unexpectedly missing an owner', owner);
1335
1101
  let routeName = this.routeName;
1336
1102
  return {
1337
1103
  find(name, value) {
@@ -1363,6 +1129,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1363
1129
  let combinedQueryParameterConfiguration;
1364
1130
  let controllerName = this.controllerName || this.routeName;
1365
1131
  let owner = getOwner(this);
1132
+ assert('Route is unexpectedly missing an owner', owner);
1366
1133
  let controller = owner.lookup(`controller:${controllerName}`);
1367
1134
  let queryParameterConfiguraton = get(this, 'queryParams');
1368
1135
  let hasRouterDefinedQueryParams = Object.keys(queryParameterConfiguraton).length > 0;
@@ -1372,7 +1139,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1372
1139
  // this route find its query params and normalize their object shape them
1373
1140
  // merge in the query params for the route. As a mergedProperty,
1374
1141
  // Route#queryParams is always at least `{}`
1375
- let controllerDefinedQueryParameterConfiguration = get(controller, 'queryParams') || {};
1142
+ let controllerDefinedQueryParameterConfiguration = get(controller, 'queryParams') || [];
1376
1143
  let normalizedControllerQueryParameterConfiguration = normalizeControllerQueryParams(controllerDefinedQueryParameterConfiguration);
1377
1144
  combinedQueryParameterConfiguration = mergeEachQueryParams(normalizedControllerQueryParameterConfiguration, queryParameterConfiguraton);
1378
1145
  } else if (hasRouterDefinedQueryParams) {
@@ -1444,6 +1211,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1444
1211
  */
1445
1212
  inactive: (prop, value) => {
1446
1213
  let qp = map[prop];
1214
+ assert('expected inactive callback to only be called for registered qps', qp);
1447
1215
 
1448
1216
  this._qpChanged(prop, value, qp);
1449
1217
  },
@@ -1455,6 +1223,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1455
1223
  */
1456
1224
  active: (prop, value) => {
1457
1225
  let qp = map[prop];
1226
+ assert('expected active callback to only be called for registered qps', qp);
1458
1227
 
1459
1228
  this._qpChanged(prop, value, qp);
1460
1229
 
@@ -1467,6 +1236,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1467
1236
  */
1468
1237
  allowOverrides: (prop, value) => {
1469
1238
  let qp = map[prop];
1239
+ assert('expected allowOverrides callback to only be called for registered qps', qp);
1470
1240
 
1471
1241
  this._qpChanged(prop, value, qp);
1472
1242
 
@@ -1497,7 +1267,9 @@ function routeInfoFor(route, routeInfos, offset = 0) {
1497
1267
  let current;
1498
1268
 
1499
1269
  for (let i = 0; i < routeInfos.length; i++) {
1500
- current = routeInfos[i].route;
1270
+ let routeInfo = routeInfos[i];
1271
+ assert('has current routeInfo', routeInfo);
1272
+ current = routeInfo.route;
1501
1273
 
1502
1274
  if (current === route) {
1503
1275
  return routeInfos[i + offset];
@@ -1524,6 +1296,7 @@ function buildRenderOptions(route, nameOrOptions, options) {
1524
1296
 
1525
1297
  assert('You passed undefined as the outlet name.', isDefaultRender || !(options && 'outlet' in options && options.outlet === undefined));
1526
1298
  let owner = getOwner(route);
1299
+ assert('Route is unexpectedly missing an owner', owner);
1527
1300
  let name, templateName, into, outlet, model;
1528
1301
  let controller = undefined;
1529
1302
 
@@ -1618,9 +1391,10 @@ export function getFullQueryParams(router, state) {
1618
1391
  function getQueryParamsFor(route, state) {
1619
1392
  state.queryParamsFor = state.queryParamsFor || {};
1620
1393
  let name = route.fullRouteName;
1394
+ let existing = state.queryParamsFor[name];
1621
1395
 
1622
- if (state.queryParamsFor[name]) {
1623
- return state.queryParamsFor[name];
1396
+ if (existing) {
1397
+ return existing;
1624
1398
  }
1625
1399
 
1626
1400
  let fullQueryParams = getFullQueryParams(route._router, state);
@@ -1629,18 +1403,19 @@ function getQueryParamsFor(route, state) {
1629
1403
 
1630
1404
  let qps = get(route, '_qp').qps;
1631
1405
 
1632
- for (let i = 0; i < qps.length; ++i) {
1406
+ for (let qp of qps) {
1633
1407
  // Put deserialized qp on params hash.
1634
- let qp = qps[i];
1635
1408
  let qpValueWasPassedIn = (qp.prop in fullQueryParams);
1636
1409
  params[qp.prop] = qpValueWasPassedIn ? fullQueryParams[qp.prop] : copyDefaultValue(qp.defaultValue);
1637
1410
  }
1638
1411
 
1639
1412
  return params;
1640
- }
1413
+ } // FIXME: This should probably actually return a `NativeArray` if the passed in value is an Array.
1414
+
1641
1415
 
1642
1416
  function copyDefaultValue(value) {
1643
1417
  if (Array.isArray(value)) {
1418
+ // SAFETY: We lost the type data about the array if we don't cast.
1644
1419
  return emberA(value.slice());
1645
1420
  }
1646
1421
 
@@ -1720,54 +1495,12 @@ function getEngineRouteName(engine, routeName) {
1720
1495
 
1721
1496
  return routeName;
1722
1497
  }
1723
- /**
1724
- A hook you can implement to convert the route's model into parameters
1725
- for the URL.
1726
-
1727
- ```app/router.js
1728
- // ...
1729
-
1730
- Router.map(function() {
1731
- this.route('post', { path: '/posts/:post_id' });
1732
- });
1733
-
1734
- ```
1735
-
1736
- ```app/routes/post.js
1737
- import Route from '@ember/routing/route';
1738
-
1739
- export default class PostRoute extends Route {
1740
- model({ post_id }) {
1741
- // the server returns `{ id: 12 }`
1742
- return fetch(`/posts/${post_id}`;
1743
- }
1744
-
1745
- serialize(model) {
1746
- // this will make the URL `/posts/12`
1747
- return { post_id: model.id };
1748
- }
1749
- }
1750
- ```
1751
-
1752
- The default `serialize` method will insert the model's `id` into the
1753
- route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'.
1754
- If the route has multiple dynamic segments or does not contain '_id', `serialize`
1755
- will return `getProperties(model, params)`
1756
1498
 
1757
- This method is called when `transitionTo` is called with a context
1758
- in order to populate the URL.
1759
-
1760
- @method serialize
1761
- @param {Object} model the routes model
1762
- @param {Array} params an Array of parameter names for the current
1763
- route (in the example, `['post_id']`.
1764
- @return {Object} the serialized parameters
1765
- @since 1.0.0
1766
- @public
1767
- */
1768
-
1769
-
1770
- Route.prototype.serialize = defaultSerialize; // Set these here so they can be overridden with extend
1499
+ const defaultSerialize = Route.prototype.serialize;
1500
+ export { defaultSerialize };
1501
+ export function hasDefaultSerialize(route) {
1502
+ return route.serialize === defaultSerialize;
1503
+ } // Set these here so they can be overridden with extend
1771
1504
 
1772
1505
  Route.reopen({
1773
1506
  mergedProperties: ['queryParams'],
@@ -1830,8 +1563,8 @@ Route.reopen({
1830
1563
  let qpMap = get(this, '_qp').map;
1831
1564
  let totalChanged = Object.keys(changed).concat(Object.keys(removed));
1832
1565
 
1833
- for (let i = 0; i < totalChanged.length; ++i) {
1834
- let qp = qpMap[totalChanged[i]];
1566
+ for (let change of totalChanged) {
1567
+ let qp = qpMap[change];
1835
1568
 
1836
1569
  if (qp) {
1837
1570
  let options = this._optionsForQueryParam(qp);
@@ -1868,8 +1601,7 @@ Route.reopen({
1868
1601
  let replaceUrl;
1869
1602
  stashParamNames(router, routeInfos);
1870
1603
 
1871
- for (let i = 0; i < qpMeta.qps.length; ++i) {
1872
- let qp = qpMeta.qps[i];
1604
+ for (let qp of qpMeta.qps) {
1873
1605
  let route = qp.route;
1874
1606
  let controller = route.controller;
1875
1607
  let presentKey = qp.urlKey in params && qp.urlKey; // Do a reverse lookup to see if the changed query