ember-source 3.24.0 → 3.24.4

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Ember Changelog
2
2
 
3
+ ### v3.24.4 (May 3, 2021)
4
+
5
+ - [#19477](https://github.com/emberjs/ember.js/pull/19477) Allow `<LinkToExternal />` to override internal assertion
6
+
7
+ ### v3.24.3 (March 7, 2021)
8
+
9
+ - [#19448](https://github.com/emberjs/ember.js/pull/19448) Ensure query params are preserved through an intermediate loading state transition
10
+ - [#19450](https://github.com/emberjs/ember.js/pull/19450) Ensure `routerService.currentRoute.name` and `routerService.currentRouteName` match during loading states
11
+ - [#19395](https://github.com/emberjs/ember.js/pull/19395) [BUGFIX] Ensure `<LinkTo>` can return a valid `href` most of the time
12
+ - [#19397](https://github.com/emberjs/ember.js/pull/19397) [BUGFIX] Force building Ember bundles when `targets.node` is defined
13
+
14
+ ### v3.24.2 (February 10, 2021)
15
+
16
+ - [#19326](https://github.com/emberjs/ember.js/pull/19326) / [#19387](https://github.com/emberjs/ember.js/pull/19387) [BUGFIX] Fix usage of `<LinkTo />` prior to routing (e.g. component rendering tests)
17
+
18
+ ### v3.24.1 (January 14, 2021)
19
+
20
+ - [#19337](https://github.com/emberjs/ember.js/pull/19337) [BUGFIX] Ensure query param only `<LinkTo />` are properly scoped in engines
21
+
3
22
  ### v3.24.0 (December 28, 2020)
4
23
 
5
24
  - [#19224](https://github.com/emberjs/ember.js/pull/19224) [FEATURE] Add `{{page-title}}` helper to route template blueprints to implement [RFC #0654](https://github.com/emberjs/rfcs/blob/master/text/0645-add-ember-page-title-addon.md).
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "3.24.0",
2
+ "version": "3.24.4",
3
3
  "buildType": "tag",
4
- "SHA": "75bb0c42dcf526c92ced96c404dc30edcc09c1da",
5
- "assetPath": "/tag/shas/75bb0c42dcf526c92ced96c404dc30edcc09c1da.tgz"
4
+ "SHA": "0b53dcc356bd8bada09caec168675f835bd71950",
5
+ "assetPath": "/tag/shas/0b53dcc356bd8bada09caec168675f835bd71950.tgz"
6
6
  }
@@ -2800,31 +2800,29 @@ APPEND_OPCODES.add(51
2800
2800
  let attribute = vm.elements().setDynamicAttribute(name, value, !!trusting, namespace);
2801
2801
 
2802
2802
  if (!isConstRef(reference)) {
2803
- vm.updateWith(new UpdateDynamicAttributeOpcode(reference, attribute));
2803
+ vm.updateWith(new UpdateDynamicAttributeOpcode(reference, attribute, vm.env));
2804
2804
  }
2805
2805
  });
2806
2806
 
2807
2807
  class UpdateDynamicAttributeOpcode extends UpdatingOpcode {
2808
- constructor(reference, attribute) {
2808
+ constructor(reference, attribute, env) {
2809
2809
  super();
2810
- this.reference = reference;
2811
- this.attribute = attribute;
2812
2810
  this.type = 'patch-element';
2813
- this.lastValue = valueForRef(reference);
2814
- }
2811
+ let initialized = false;
2812
+ this.updateRef = createComputeRef(() => {
2813
+ let value = valueForRef(reference);
2815
2814
 
2816
- evaluate(vm) {
2817
- let {
2818
- attribute,
2819
- reference,
2820
- lastValue
2821
- } = this;
2822
- let currentValue = valueForRef(reference);
2815
+ if (initialized === true) {
2816
+ attribute.update(value, env);
2817
+ } else {
2818
+ initialized = true;
2819
+ }
2820
+ });
2821
+ valueForRef(this.updateRef);
2822
+ }
2823
2823
 
2824
- if (currentValue !== lastValue) {
2825
- attribute.update(currentValue, vm.env);
2826
- this.lastValue = currentValue;
2827
- }
2824
+ evaluate() {
2825
+ valueForRef(this.updateRef);
2828
2826
  }
2829
2827
 
2830
2828
  }
@@ -3274,7 +3272,7 @@ function setDeferredAttr(vm, name, value, namespace, trusting = false) {
3274
3272
  let attribute = vm.elements().setDynamicAttribute(name, valueForRef(value), trusting, namespace);
3275
3273
 
3276
3274
  if (!isConstRef(value)) {
3277
- vm.updateWith(new UpdateDynamicAttributeOpcode(value, attribute));
3275
+ vm.updateWith(new UpdateDynamicAttributeOpcode(value, attribute, vm.env));
3278
3276
  }
3279
3277
  }
3280
3278
  }
@@ -2,22 +2,27 @@ import { Promise } from 'rsvp';
2
2
  import { DEBUG } from '@glimmer/env';
3
3
  import RouteRecognizer from 'route-recognizer';
4
4
 
5
- const TransitionAbortedError = (function () {
6
- TransitionAbortedError.prototype = Object.create(Error.prototype);
7
- TransitionAbortedError.prototype.constructor = TransitionAbortedError;
8
- function TransitionAbortedError(message) {
9
- let error = Error.call(this, message);
10
- this.name = 'TransitionAborted';
11
- this.message = message || 'TransitionAborted';
12
- if (Error.captureStackTrace) {
13
- Error.captureStackTrace(this, TransitionAbortedError);
14
- }
15
- else {
16
- this.stack = error.stack;
17
- }
5
+ function buildTransitionAborted() {
6
+ let error = new Error('TransitionAborted');
7
+ error.name = 'TransitionAborted';
8
+ error.code = 'TRANSITION_ABORTED';
9
+ return error;
10
+ }
11
+ function isTransitionAborted(maybeError) {
12
+ return (typeof maybeError === 'object' &&
13
+ maybeError !== null &&
14
+ maybeError.code === 'TRANSITION_ABORTED');
15
+ }
16
+ function isAbortable(maybeAbortable) {
17
+ return (typeof maybeAbortable === 'object' &&
18
+ maybeAbortable !== null &&
19
+ typeof maybeAbortable.isAborted === 'boolean');
20
+ }
21
+ function throwIfAborted(maybe) {
22
+ if (isAbortable(maybe) && maybe.isAborted) {
23
+ throw buildTransitionAborted();
18
24
  }
19
- return TransitionAbortedError;
20
- })();
25
+ }
21
26
 
22
27
  const slice = Array.prototype.slice;
23
28
  const hasOwnProperty = Object.prototype.hasOwnProperty;
@@ -157,7 +162,7 @@ const STATE_SYMBOL = `__STATE__-2619860001345920-3322w3`;
157
162
  const PARAMS_SYMBOL = `__PARAMS__-261986232992830203-23323`;
158
163
  const QUERY_PARAMS_SYMBOL = `__QPS__-2619863929824844-32323`;
159
164
  /**
160
- A Transition is a thennable (a promise-like object) that represents
165
+ A Transition is a thenable (a promise-like object) that represents
161
166
  an attempt to transition to another route. It can be aborted, either
162
167
  explicitly via `abort` or by attempting another transition while a
163
168
  previous one is still underway. An aborted transition can also
@@ -185,6 +190,7 @@ class Transition {
185
190
  this.isCausedByInitialTransition = false;
186
191
  this.isCausedByAbortingReplaceTransition = false;
187
192
  this._visibleQueryParams = {};
193
+ this.isIntermediate = false;
188
194
  this[STATE_SYMBOL] = state || router.state;
189
195
  this.intent = intent;
190
196
  this.router = router;
@@ -241,15 +247,9 @@ class Transition {
241
247
  this.pivotHandler = handlerInfo.route;
242
248
  }
243
249
  this.sequence = router.currentSequence++;
244
- this.promise = state
245
- .resolve(() => {
246
- if (this.isAborted) {
247
- return Promise.reject(false, promiseLabel('Transition aborted - reject'));
248
- }
249
- return Promise.resolve(true);
250
- }, this)
251
- .catch((result) => {
252
- return Promise.reject(this.router.transitionDidError(result, this));
250
+ this.promise = state.resolve(this).catch((result) => {
251
+ let error = this.router.transitionDidError(result, this);
252
+ throw error;
253
253
  }, promiseLabel('Handle Abort'));
254
254
  }
255
255
  else {
@@ -285,7 +285,7 @@ class Transition {
285
285
  succeeds and rejects if it fails/redirects/aborts.
286
286
 
287
287
  Forwards to the internal `promise` property which you can
288
- use in situations where you want to pass around a thennable,
288
+ use in situations where you want to pass around a thenable,
289
289
  but not the Transition itself.
290
290
 
291
291
  @method then
@@ -318,7 +318,7 @@ class Transition {
318
318
  /**
319
319
 
320
320
  Forwards to the internal `promise` property which you can
321
- use in situations where you want to pass around a thennable,
321
+ use in situations where you want to pass around a thenable,
322
322
  but not the Transition itself.
323
323
 
324
324
  @method finally
@@ -482,7 +482,7 @@ class Transition {
482
482
  */
483
483
  function logAbort(transition) {
484
484
  log(transition.router, transition.sequence, 'detected abort.');
485
- return new TransitionAbortedError();
485
+ return buildTransitionAborted();
486
486
  }
487
487
  function isTransition(obj) {
488
488
  return typeof obj === 'object' && obj instanceof Transition && obj.isTransition;
@@ -608,13 +608,19 @@ class InternalRouteInfo {
608
608
  serialize(_context) {
609
609
  return this.params || {};
610
610
  }
611
- resolve(shouldContinue, transition) {
611
+ resolve(transition) {
612
612
  return Promise.resolve(this.routePromise)
613
- .then((route) => this.checkForAbort(shouldContinue, route))
613
+ .then((route) => {
614
+ throwIfAborted(transition);
615
+ return route;
616
+ })
614
617
  .then(() => this.runBeforeModelHook(transition))
615
- .then(() => this.checkForAbort(shouldContinue, null))
618
+ .then(() => throwIfAborted(transition))
616
619
  .then(() => this.getModel(transition))
617
- .then((resolvedModel) => this.checkForAbort(shouldContinue, resolvedModel))
620
+ .then((resolvedModel) => {
621
+ throwIfAborted(transition);
622
+ return resolvedModel;
623
+ })
618
624
  .then((resolvedModel) => this.runAfterModelHook(transition, resolvedModel))
619
625
  .then((resolvedModel) => this.becomeResolved(transition, resolvedModel));
620
626
  }
@@ -637,7 +643,7 @@ class InternalRouteInfo {
637
643
  }
638
644
  return resolved;
639
645
  }
640
- shouldSupercede(routeInfo) {
646
+ shouldSupersede(routeInfo) {
641
647
  // Prefer this newer routeInfo over `other` if:
642
648
  // 1) The other one doesn't exist
643
649
  // 2) The names don't match
@@ -717,13 +723,6 @@ class InternalRouteInfo {
717
723
  return transition.resolvedModels[name];
718
724
  });
719
725
  }
720
- checkForAbort(shouldContinue, value) {
721
- return Promise.resolve(shouldContinue()).then(function () {
722
- // We don't care about shouldContinue's resolve value;
723
- // pass along the original value passed to this fn.
724
- return value;
725
- }, null);
726
- }
727
726
  stashResolvedModel(transition, resolvedModel) {
728
727
  transition.resolvedModels = transition.resolvedModels || {};
729
728
  transition.resolvedModels[this.name] = resolvedModel;
@@ -757,7 +756,7 @@ class ResolvedRouteInfo extends InternalRouteInfo {
757
756
  this.isResolved = true;
758
757
  this.context = context;
759
758
  }
760
- resolve(_shouldContinue, transition) {
759
+ resolve(transition) {
761
760
  // A ResolvedRouteInfo just resolved with itself.
762
761
  if (transition && transition.resolvedModels) {
763
762
  transition.resolvedModels[this.name] = this.context;
@@ -873,6 +872,47 @@ class TransitionIntent {
873
872
  }
874
873
  }
875
874
 
875
+ function handleError(currentState, transition, error) {
876
+ // This is the only possible
877
+ // reject value of TransitionState#resolve
878
+ let routeInfos = currentState.routeInfos;
879
+ let errorHandlerIndex = transition.resolveIndex >= routeInfos.length ? routeInfos.length - 1 : transition.resolveIndex;
880
+ let wasAborted = transition.isAborted;
881
+ throw new TransitionError(error, currentState.routeInfos[errorHandlerIndex].route, wasAborted, currentState);
882
+ }
883
+ function resolveOneRouteInfo(currentState, transition) {
884
+ if (transition.resolveIndex === currentState.routeInfos.length) {
885
+ // This is is the only possible
886
+ // fulfill value of TransitionState#resolve
887
+ return;
888
+ }
889
+ let routeInfo = currentState.routeInfos[transition.resolveIndex];
890
+ return routeInfo
891
+ .resolve(transition)
892
+ .then(proceed.bind(null, currentState, transition), null, currentState.promiseLabel('Proceed'));
893
+ }
894
+ function proceed(currentState, transition, resolvedRouteInfo) {
895
+ let wasAlreadyResolved = currentState.routeInfos[transition.resolveIndex].isResolved;
896
+ // Swap the previously unresolved routeInfo with
897
+ // the resolved routeInfo
898
+ currentState.routeInfos[transition.resolveIndex++] = resolvedRouteInfo;
899
+ if (!wasAlreadyResolved) {
900
+ // Call the redirect hook. The reason we call it here
901
+ // vs. afterModel is so that redirects into child
902
+ // routes don't re-run the model hooks for this
903
+ // already-resolved route.
904
+ let { route } = resolvedRouteInfo;
905
+ if (route !== undefined) {
906
+ if (route.redirect) {
907
+ route.redirect(resolvedRouteInfo.context, transition);
908
+ }
909
+ }
910
+ }
911
+ // Proceed after ensuring that the redirect hook
912
+ // didn't abort this transition by transitioning elsewhere.
913
+ throwIfAborted(transition);
914
+ return resolveOneRouteInfo(currentState, transition);
915
+ }
876
916
  class TransitionState {
877
917
  constructor() {
878
918
  this.routeInfos = [];
@@ -890,7 +930,7 @@ class TransitionState {
890
930
  });
891
931
  return promiseLabel("'" + targetName + "': " + label);
892
932
  }
893
- resolve(shouldContinue, transition) {
933
+ resolve(transition) {
894
934
  // First, calculate params for this state. This is useful
895
935
  // information to provide to the various route hooks.
896
936
  let params = this.params;
@@ -899,62 +939,11 @@ class TransitionState {
899
939
  return true;
900
940
  });
901
941
  transition.resolveIndex = 0;
902
- let currentState = this;
903
- let wasAborted = false;
904
- // The prelude RSVP.resolve() asyncs us into the promise land.
942
+ // The prelude RSVP.resolve() async moves us into the promise land.
905
943
  return Promise.resolve(null, this.promiseLabel('Start transition'))
906
- .then(resolveOneRouteInfo, null, this.promiseLabel('Resolve route'))
907
- .catch(handleError, this.promiseLabel('Handle error'));
908
- function innerShouldContinue() {
909
- return Promise.resolve(shouldContinue(), currentState.promiseLabel('Check if should continue')).catch(function (reason) {
910
- // We distinguish between errors that occurred
911
- // during resolution (e.g. before"Model/model/afterModel),
912
- // and aborts due to a rejecting promise from shouldContinue().
913
- wasAborted = true;
914
- return Promise.reject(reason);
915
- }, currentState.promiseLabel('Handle abort'));
916
- }
917
- function handleError(error) {
918
- // This is the only possible
919
- // reject value of TransitionState#resolve
920
- let routeInfos = currentState.routeInfos;
921
- let errorHandlerIndex = transition.resolveIndex >= routeInfos.length
922
- ? routeInfos.length - 1
923
- : transition.resolveIndex;
924
- return Promise.reject(new TransitionError(error, currentState.routeInfos[errorHandlerIndex].route, wasAborted, currentState));
925
- }
926
- function proceed(resolvedRouteInfo) {
927
- let wasAlreadyResolved = currentState.routeInfos[transition.resolveIndex].isResolved;
928
- // Swap the previously unresolved routeInfo with
929
- // the resolved routeInfo
930
- currentState.routeInfos[transition.resolveIndex++] = resolvedRouteInfo;
931
- if (!wasAlreadyResolved) {
932
- // Call the redirect hook. The reason we call it here
933
- // vs. afterModel is so that redirects into child
934
- // routes don't re-run the model hooks for this
935
- // already-resolved route.
936
- let { route } = resolvedRouteInfo;
937
- if (route !== undefined) {
938
- if (route.redirect) {
939
- route.redirect(resolvedRouteInfo.context, transition);
940
- }
941
- }
942
- }
943
- // Proceed after ensuring that the redirect hook
944
- // didn't abort this transition by transitioning elsewhere.
945
- return innerShouldContinue().then(resolveOneRouteInfo, null, currentState.promiseLabel('Resolve route'));
946
- }
947
- function resolveOneRouteInfo() {
948
- if (transition.resolveIndex === currentState.routeInfos.length) {
949
- // This is is the only possible
950
- // fulfill value of TransitionState#resolve
951
- return currentState;
952
- }
953
- let routeInfo = currentState.routeInfos[transition.resolveIndex];
954
- return routeInfo
955
- .resolve(innerShouldContinue, transition)
956
- .then(proceed, null, currentState.promiseLabel('Proceed'));
957
- }
944
+ .then(resolveOneRouteInfo.bind(null, this, transition), null, this.promiseLabel('Resolve route'))
945
+ .catch(handleError.bind(null, this, transition), this.promiseLabel('Handle error'))
946
+ .then(() => this);
958
947
  }
959
948
  }
960
949
  class TransitionError {
@@ -1032,7 +1021,7 @@ class NamedTransitionIntent extends TransitionIntent {
1032
1021
  newHandlerInfo.context = oldContext;
1033
1022
  }
1034
1023
  let handlerToUse = oldHandlerInfo;
1035
- if (i >= invalidateIndex || newHandlerInfo.shouldSupercede(oldHandlerInfo)) {
1024
+ if (i >= invalidateIndex || newHandlerInfo.shouldSupersede(oldHandlerInfo)) {
1036
1025
  invalidateIndex = Math.min(i, invalidateIndex);
1037
1026
  handlerToUse = newHandlerInfo;
1038
1027
  }
@@ -1049,6 +1038,9 @@ class NamedTransitionIntent extends TransitionIntent {
1049
1038
  this.invalidateChildren(newState.routeInfos, invalidateIndex);
1050
1039
  }
1051
1040
  merge(newState.queryParams, this.queryParams || {});
1041
+ if (isIntermediate && oldState.queryParams) {
1042
+ merge(newState.queryParams, oldState.queryParams);
1043
+ }
1052
1044
  return newState;
1053
1045
  }
1054
1046
  invalidateChildren(handlerInfos, invalidateIndex) {
@@ -1180,12 +1172,12 @@ class URLTransitionIntent extends TransitionIntent {
1180
1172
  checkHandlerAccessibility(route);
1181
1173
  }
1182
1174
  else {
1183
- // If the hanlder is being loaded asynchronously, check if we can
1175
+ // If the handler is being loaded asynchronously, check if we can
1184
1176
  // access it after it has resolved
1185
1177
  newRouteInfo.routePromise = newRouteInfo.routePromise.then(checkHandlerAccessibility);
1186
1178
  }
1187
1179
  let oldRouteInfo = oldState.routeInfos[i];
1188
- if (statesDiffer || newRouteInfo.shouldSupercede(oldRouteInfo)) {
1180
+ if (statesDiffer || newRouteInfo.shouldSupersede(oldRouteInfo)) {
1189
1181
  statesDiffer = true;
1190
1182
  newState.routeInfos[i] = newRouteInfo;
1191
1183
  }
@@ -1320,6 +1312,7 @@ class Router {
1320
1312
  }
1321
1313
  if (isIntermediate) {
1322
1314
  let transition = new Transition(this, undefined, newState);
1315
+ transition.isIntermediate = true;
1323
1316
  this.toReadOnlyInfos(transition, newState);
1324
1317
  this.setupContexts(newState, transition);
1325
1318
  this.routeWillChange(transition);
@@ -1415,7 +1408,7 @@ class Router {
1415
1408
  return routeInfos[routeInfos.length - 1].route;
1416
1409
  }
1417
1410
  catch (e) {
1418
- if (!(e instanceof TransitionAbortedError)) {
1411
+ if (!isTransitionAborted(e)) {
1419
1412
  let infos = transition[STATE_SYMBOL].routeInfos;
1420
1413
  transition.trigger(true, 'error', e, transition, infos[infos.length - 1].route);
1421
1414
  transition.abort();
@@ -1539,9 +1532,7 @@ class Router {
1539
1532
  route.enter(transition);
1540
1533
  }
1541
1534
  }
1542
- if (transition && transition.isAborted) {
1543
- throw new TransitionAbortedError();
1544
- }
1535
+ throwIfAborted(transition);
1545
1536
  route.context = context;
1546
1537
  if (route.contextDidChange !== undefined) {
1547
1538
  route.contextDidChange();
@@ -1549,9 +1540,7 @@ class Router {
1549
1540
  if (route.setup !== undefined) {
1550
1541
  route.setup(context, transition);
1551
1542
  }
1552
- if (transition && transition.isAborted) {
1553
- throw new TransitionAbortedError();
1554
- }
1543
+ throwIfAborted(transition);
1555
1544
  currentRouteInfos.push(routeInfo);
1556
1545
  return route;
1557
1546
  }
@@ -1668,7 +1657,7 @@ class Router {
1668
1657
  // button
1669
1658
  let initial = transition.isCausedByInitialTransition;
1670
1659
  // say you are at / and you click a link to route /foo. In /foo's
1671
- // route, the transition is aborted using replacewith('/bar').
1660
+ // route, the transition is aborted using replaceWith('/bar').
1672
1661
  // Because the current url is still /, the history entry for / is
1673
1662
  // removed from the history. Clicking back will take you to the page
1674
1663
  // you were on before /, which is often not even the app, thus killing
@@ -1883,23 +1872,23 @@ class Router {
1883
1872
  return false;
1884
1873
  }
1885
1874
  let targetHandler = targetRouteInfos[targetRouteInfos.length - 1].name;
1886
- let recogHandlers = this.recognizer.handlersFor(targetHandler);
1875
+ let recognizerHandlers = this.recognizer.handlersFor(targetHandler);
1887
1876
  let index = 0;
1888
- for (len = recogHandlers.length; index < len; ++index) {
1877
+ for (len = recognizerHandlers.length; index < len; ++index) {
1889
1878
  routeInfo = targetRouteInfos[index];
1890
1879
  if (routeInfo.name === routeName) {
1891
1880
  break;
1892
1881
  }
1893
1882
  }
1894
- if (index === recogHandlers.length) {
1883
+ if (index === recognizerHandlers.length) {
1895
1884
  // The provided route name isn't even in the route hierarchy.
1896
1885
  return false;
1897
1886
  }
1898
1887
  let testState = new TransitionState();
1899
1888
  testState.routeInfos = targetRouteInfos.slice(0, index + 1);
1900
- recogHandlers = recogHandlers.slice(0, index + 1);
1889
+ recognizerHandlers = recognizerHandlers.slice(0, index + 1);
1901
1890
  let intent = new NamedTransitionIntent(this, targetHandler, undefined, contexts);
1902
- let newState = intent.applyToHandlers(testState, recogHandlers, targetHandler, true, true);
1891
+ let newState = intent.applyToHandlers(testState, recognizerHandlers, targetHandler, true, true);
1903
1892
  let routesEqual = routeInfosEqual(newState.routeInfos, testState.routeInfos);
1904
1893
  if (!queryParams || !routesEqual) {
1905
1894
  return routesEqual;