kdu-router 4.0.16-rc.0 → 4.1.6

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.
@@ -1,70 +1,33 @@
1
1
  /*!
2
- * kdu-router v4.0.16-rc.0
3
- * (c) 2021-2022 NKDuy
2
+ * kdu-router v4.1.6
3
+ * (c) 2023 NKDuy
4
4
  * @license MIT
5
5
  */
6
6
  var KduRouter = (function (exports, kdu) {
7
7
  'use strict';
8
8
 
9
- const hasSymbol = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
10
- const PolySymbol = (name) =>
11
- // kr = kdu router
12
- hasSymbol
13
- ? Symbol('[kdu-router]: ' + name )
14
- : ('[kdu-router]: ' ) + name;
15
- // rvlm = Router View Location Matched
16
- /**
17
- * RouteRecord being rendered by the closest ancestor Router View. Used for
18
- * `onBeforeRouteUpdate` and `onBeforeRouteLeave`. rvlm stands for Router View
19
- * Location Matched
20
- *
21
- * @internal
22
- */
23
- const matchedRouteKey = /*#__PURE__*/ PolySymbol('router view location matched' );
24
- /**
25
- * Allows overriding the router view depth to control which component in
26
- * `matched` is rendered. rvd stands for Router View Depth
27
- *
28
- * @internal
29
- */
30
- const viewDepthKey = /*#__PURE__*/ PolySymbol('router view depth' );
31
- /**
32
- * Allows overriding the router instance returned by `useRouter` in tests. r
33
- * stands for router
34
- *
35
- * @internal
36
- */
37
- const routerKey = /*#__PURE__*/ PolySymbol('router' );
38
- /**
39
- * Allows overriding the current route returned by `useRoute` in tests. rl
40
- * stands for route location
41
- *
42
- * @internal
43
- */
44
- const routeLocationKey = /*#__PURE__*/ PolySymbol('route location' );
45
- /**
46
- * Allows overriding the current route used by router-view. Internally this is
47
- * used when the `route` prop is passed.
48
- *
49
- * @internal
50
- */
51
- const routerViewLocationKey = /*#__PURE__*/ PolySymbol('router view location' );
52
-
53
9
  const isBrowser = typeof window !== 'undefined';
54
10
 
55
11
  function isESModule(obj) {
56
- return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module');
12
+ return obj.__esModule || obj[Symbol.toStringTag] === 'Module';
57
13
  }
58
14
  const assign = Object.assign;
59
15
  function applyToParams(fn, params) {
60
16
  const newParams = {};
61
17
  for (const key in params) {
62
18
  const value = params[key];
63
- newParams[key] = Array.isArray(value) ? value.map(fn) : fn(value);
19
+ newParams[key] = isArray(value)
20
+ ? value.map(fn)
21
+ : fn(value);
64
22
  }
65
23
  return newParams;
66
24
  }
67
- const noop = () => { };
25
+ const noop = () => { };
26
+ /**
27
+ * Typesafe alternative to Array.isArray
28
+ * https://github.com/microsoft/TypeScript/pull/48228
29
+ */
30
+ const isArray = Array.isArray;
68
31
 
69
32
  function warn(msg) {
70
33
  // avoid using ...args as it breaks in older Edge builds
@@ -75,7 +38,7 @@ var KduRouter = (function (exports, kdu) {
75
38
  const TRAILING_SLASH_RE = /\/$/;
76
39
  const removeTrailingSlash = (path) => path.replace(TRAILING_SLASH_RE, '');
77
40
  /**
78
- * Transforms an URI into a normalized history location
41
+ * Transforms a URI into a normalized history location
79
42
  *
80
43
  * @param parseQuery
81
44
  * @param location - URI to normalize
@@ -86,8 +49,13 @@ var KduRouter = (function (exports, kdu) {
86
49
  function parseURL(parseQuery, location, currentLocation = '/') {
87
50
  let path, query = {}, searchString = '', hash = '';
88
51
  // Could use URL and URLSearchParams but IE 11 doesn't support it
89
- const searchPos = location.indexOf('?');
90
- const hashPos = location.indexOf('#', searchPos > -1 ? searchPos : 0);
52
+ // TODO: move to new URL()
53
+ const hashPos = location.indexOf('#');
54
+ let searchPos = location.indexOf('?');
55
+ // the hash appears before the search, so it's not part of the search string
56
+ if (hashPos < searchPos && hashPos >= 0) {
57
+ searchPos = -1;
58
+ }
91
59
  if (searchPos > -1) {
92
60
  path = location.slice(0, searchPos);
93
61
  searchString = location.slice(searchPos + 1, hashPos > -1 ? hashPos : location.length);
@@ -119,8 +87,7 @@ var KduRouter = (function (exports, kdu) {
119
87
  return location.path + (query && '?') + query + (location.hash || '');
120
88
  }
121
89
  /**
122
- * Strips off the base from the beginning of a location.pathname in a non
123
- * case-sensitive way.
90
+ * Strips off the base from the beginning of a location.pathname in a non-case-sensitive way.
124
91
  *
125
92
  * @param pathname - location.pathname
126
93
  * @param base - base to strip off
@@ -172,9 +139,9 @@ var KduRouter = (function (exports, kdu) {
172
139
  return true;
173
140
  }
174
141
  function isSameRouteLocationParamsValue(a, b) {
175
- return Array.isArray(a)
142
+ return isArray(a)
176
143
  ? isEquivalentArray(a, b)
177
- : Array.isArray(b)
144
+ : isArray(b)
178
145
  ? isEquivalentArray(b, a)
179
146
  : a === b;
180
147
  }
@@ -186,7 +153,7 @@ var KduRouter = (function (exports, kdu) {
186
153
  * @param b - array of values or a single value
187
154
  */
188
155
  function isEquivalentArray(a, b) {
189
- return Array.isArray(b)
156
+ return isArray(b)
190
157
  ? a.length === b.length && a.every((value, i) => value === b[i])
191
158
  : a.length === 1 && a[0] === b;
192
159
  }
@@ -212,18 +179,24 @@ var KduRouter = (function (exports, kdu) {
212
179
  let segment;
213
180
  for (toPosition = 0; toPosition < toSegments.length; toPosition++) {
214
181
  segment = toSegments[toPosition];
215
- // can't go below zero
216
- if (position === 1 || segment === '.')
182
+ // we stay on the same position
183
+ if (segment === '.')
217
184
  continue;
218
- if (segment === '..')
219
- position--;
220
- // found something that is not relative path
185
+ // go up in the from array
186
+ if (segment === '..') {
187
+ // we can't go below zero, but we still need to increment toPosition
188
+ if (position > 1)
189
+ position--;
190
+ // continue
191
+ }
192
+ // we reached a non-relative path, we stop here
221
193
  else
222
194
  break;
223
195
  }
224
196
  return (fromSegments.slice(0, position).join('/') +
225
197
  '/' +
226
198
  toSegments
199
+ // ensure we use at least the last element in the toSegments
227
200
  .slice(toPosition - (toPosition === toSegments.length ? 1 : 0))
228
201
  .join('/'));
229
202
  }
@@ -452,7 +425,7 @@ var KduRouter = (function (exports, kdu) {
452
425
  pauseState = currentLocation.value;
453
426
  }
454
427
  function listen(callback) {
455
- // setup the listener and prepare teardown callbacks
428
+ // set up the listener and prepare teardown callbacks
456
429
  listeners.push(callback);
457
430
  const teardown = () => {
458
431
  const index = listeners.indexOf(callback);
@@ -475,7 +448,7 @@ var KduRouter = (function (exports, kdu) {
475
448
  window.removeEventListener('popstate', popStateHandler);
476
449
  window.removeEventListener('beforeunload', beforeUnloadListener);
477
450
  }
478
- // setup the listeners and prepare teardown callbacks
451
+ // set up the listeners and prepare teardown callbacks
479
452
  window.addEventListener('popstate', popStateHandler);
480
453
  window.addEventListener('beforeunload', beforeUnloadListener);
481
454
  return {
@@ -513,14 +486,14 @@ var KduRouter = (function (exports, kdu) {
513
486
  // the length is off by one, we need to decrease it
514
487
  position: history.length - 1,
515
488
  replaced: true,
516
- // don't add a scroll as the user may have an anchor and we want
489
+ // don't add a scroll as the user may have an anchor, and we want
517
490
  // scrollBehavior to be triggered without a saved position
518
491
  scroll: null,
519
492
  }, true);
520
493
  }
521
494
  function changeLocation(to, state, replace) {
522
495
  /**
523
- * if a base tag is provided and we are on a normal domain, we have to
496
+ * if a base tag is provided, and we are on a normal domain, we have to
524
497
  * respect the provided `base` attribute because pushState() will use it and
525
498
  * potentially erase anything before the `#` where a base of
526
499
  * `/folder/#` but a base of `/` would erase the `/folder/` section. If
@@ -614,7 +587,7 @@ var KduRouter = (function (exports, kdu) {
614
587
  }
615
588
 
616
589
  /**
617
- * Creates a in-memory based history. The main purpose of this history is to handle SSR. It starts in a special location that is nowhere.
590
+ * Creates an in-memory based history. The main purpose of this history is to handle SSR. It starts in a special location that is nowhere.
618
591
  * It's up to the user to replace that location with the starter location by either calling `router.push` or `router.replace`.
619
592
  *
620
593
  * @param base - Base applied to all urls, defaults to '/'
@@ -699,15 +672,13 @@ var KduRouter = (function (exports, kdu) {
699
672
  }
700
673
 
701
674
  /**
702
- * Creates a hash history. Useful for web applications with no host (e.g.
703
- * `file://`) or when configuring a server to handle any URL is not possible.
675
+ * Creates a hash history. Useful for web applications with no host (e.g. `file://`) or when configuring a server to
676
+ * handle any URL is not possible.
704
677
  *
705
- * @param base - optional base to provide. Defaults to `location.pathname +
706
- * location.search` If there is a `<base>` tag in the `head`, its value will be
707
- * ignored in favor of this parameter **but note it affects all the
708
- * history.pushState() calls**, meaning that if you use a `<base>` tag, it's
709
- * `href` value **has to match this parameter** (ignoring anything after the
710
- * `#`).
678
+ * @param base - optional base to provide. Defaults to `location.pathname + location.search` If there is a `<base>` tag
679
+ * in the `head`, its value will be ignored in favor of this parameter **but note it affects all the history.pushState()
680
+ * calls**, meaning that if you use a `<base>` tag, it's `href` value **has to match this parameter** (ignoring anything
681
+ * after the `#`).
711
682
  *
712
683
  * @example
713
684
  * ```js
@@ -772,7 +743,7 @@ var KduRouter = (function (exports, kdu) {
772
743
  redirectedFrom: undefined,
773
744
  };
774
745
 
775
- const NavigationFailureSymbol = /*#__PURE__*/ PolySymbol('navigation failure' );
746
+ const NavigationFailureSymbol = Symbol('navigation failure' );
776
747
  /**
777
748
  * Enumeration with all possible types for navigation failures. Can be passed to
778
749
  * {@link isNavigationFailure} to check for specific failures.
@@ -797,21 +768,21 @@ var KduRouter = (function (exports, kdu) {
797
768
  })(exports.NavigationFailureType || (exports.NavigationFailureType = {}));
798
769
  // DEV only debug messages
799
770
  const ErrorTypeMessages = {
800
- [1 /* MATCHER_NOT_FOUND */]({ location, currentLocation }) {
771
+ [1 /* ErrorTypes.MATCHER_NOT_FOUND */]({ location, currentLocation }) {
801
772
  return `No match for\n ${JSON.stringify(location)}${currentLocation
802
773
  ? '\nwhile being at\n' + JSON.stringify(currentLocation)
803
774
  : ''}`;
804
775
  },
805
- [2 /* NAVIGATION_GUARD_REDIRECT */]({ from, to, }) {
776
+ [2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */]({ from, to, }) {
806
777
  return `Redirected from "${from.fullPath}" to "${stringifyRoute(to)}" via a navigation guard.`;
807
778
  },
808
- [4 /* NAVIGATION_ABORTED */]({ from, to }) {
779
+ [4 /* ErrorTypes.NAVIGATION_ABORTED */]({ from, to }) {
809
780
  return `Navigation aborted from "${from.fullPath}" to "${to.fullPath}" via a navigation guard.`;
810
781
  },
811
- [8 /* NAVIGATION_CANCELLED */]({ from, to }) {
782
+ [8 /* ErrorTypes.NAVIGATION_CANCELLED */]({ from, to }) {
812
783
  return `Navigation cancelled from "${from.fullPath}" to "${to.fullPath}" with a new navigation.`;
813
784
  },
814
- [16 /* NAVIGATION_DUPLICATED */]({ from, to }) {
785
+ [16 /* ErrorTypes.NAVIGATION_DUPLICATED */]({ from, to }) {
815
786
  return `Avoided redundant navigation to current location: "${from.fullPath}".`;
816
787
  },
817
788
  };
@@ -843,7 +814,7 @@ var KduRouter = (function (exports, kdu) {
843
814
  return JSON.stringify(location, null, 2);
844
815
  }
845
816
 
846
- // default pattern for a param: non greedy everything but /
817
+ // default pattern for a param: non-greedy everything but /
847
818
  const BASE_PARAM_PATTERN = '[^/]+?';
848
819
  const BASE_PATH_PARSER_OPTIONS = {
849
820
  sensitive: false,
@@ -870,23 +841,23 @@ var KduRouter = (function (exports, kdu) {
870
841
  const keys = [];
871
842
  for (const segment of segments) {
872
843
  // the root segment needs special treatment
873
- const segmentScores = segment.length ? [] : [90 /* Root */];
844
+ const segmentScores = segment.length ? [] : [90 /* PathScore.Root */];
874
845
  // allow trailing slash
875
846
  if (options.strict && !segment.length)
876
847
  pattern += '/';
877
848
  for (let tokenIndex = 0; tokenIndex < segment.length; tokenIndex++) {
878
849
  const token = segment[tokenIndex];
879
- // resets the score if we are inside a sub segment /:a-other-:b
880
- let subSegmentScore = 40 /* Segment */ +
881
- (options.sensitive ? 0.25 /* BonusCaseSensitive */ : 0);
882
- if (token.type === 0 /* Static */) {
850
+ // resets the score if we are inside a sub-segment /:a-other-:b
851
+ let subSegmentScore = 40 /* PathScore.Segment */ +
852
+ (options.sensitive ? 0.25 /* PathScore.BonusCaseSensitive */ : 0);
853
+ if (token.type === 0 /* TokenType.Static */) {
883
854
  // prepend the slash if we are starting a new segment
884
855
  if (!tokenIndex)
885
856
  pattern += '/';
886
857
  pattern += token.value.replace(REGEX_CHARS_RE, '\\$&');
887
- subSegmentScore += 40 /* Static */;
858
+ subSegmentScore += 40 /* PathScore.Static */;
888
859
  }
889
- else if (token.type === 1 /* Param */) {
860
+ else if (token.type === 1 /* TokenType.Param */) {
890
861
  const { value, repeatable, optional, regexp } = token;
891
862
  keys.push({
892
863
  name: value,
@@ -896,7 +867,7 @@ var KduRouter = (function (exports, kdu) {
896
867
  const re = regexp ? regexp : BASE_PARAM_PATTERN;
897
868
  // the user provided a custom regexp /:id(\\d+)
898
869
  if (re !== BASE_PARAM_PATTERN) {
899
- subSegmentScore += 10 /* BonusCustomRegExp */;
870
+ subSegmentScore += 10 /* PathScore.BonusCustomRegExp */;
900
871
  // make sure the regexp is valid before using it
901
872
  try {
902
873
  new RegExp(`(${re})`);
@@ -919,13 +890,13 @@ var KduRouter = (function (exports, kdu) {
919
890
  if (optional)
920
891
  subPattern += '?';
921
892
  pattern += subPattern;
922
- subSegmentScore += 20 /* Dynamic */;
893
+ subSegmentScore += 20 /* PathScore.Dynamic */;
923
894
  if (optional)
924
- subSegmentScore += -8 /* BonusOptional */;
895
+ subSegmentScore += -8 /* PathScore.BonusOptional */;
925
896
  if (repeatable)
926
- subSegmentScore += -20 /* BonusRepeatable */;
897
+ subSegmentScore += -20 /* PathScore.BonusRepeatable */;
927
898
  if (re === '.*')
928
- subSegmentScore += -50 /* BonusWildcard */;
899
+ subSegmentScore += -50 /* PathScore.BonusWildcard */;
929
900
  }
930
901
  segmentScores.push(subSegmentScore);
931
902
  }
@@ -936,7 +907,7 @@ var KduRouter = (function (exports, kdu) {
936
907
  // only apply the strict bonus to the last score
937
908
  if (options.strict && options.end) {
938
909
  const i = score.length - 1;
939
- score[i][score[i].length - 1] += 0.7000000000000001 /* BonusStrict */;
910
+ score[i][score[i].length - 1] += 0.7000000000000001 /* PathScore.BonusStrict */;
940
911
  }
941
912
  // TODO: dev only warn double trailing slash
942
913
  if (!options.strict)
@@ -968,20 +939,22 @@ var KduRouter = (function (exports, kdu) {
968
939
  path += '/';
969
940
  avoidDuplicatedSlash = false;
970
941
  for (const token of segment) {
971
- if (token.type === 0 /* Static */) {
942
+ if (token.type === 0 /* TokenType.Static */) {
972
943
  path += token.value;
973
944
  }
974
- else if (token.type === 1 /* Param */) {
945
+ else if (token.type === 1 /* TokenType.Param */) {
975
946
  const { value, repeatable, optional } = token;
976
947
  const param = value in params ? params[value] : '';
977
- if (Array.isArray(param) && !repeatable)
948
+ if (isArray(param) && !repeatable) {
978
949
  throw new Error(`Provided param "${value}" is an array but it is not repeatable (* or + modifiers)`);
979
- const text = Array.isArray(param) ? param.join('/') : param;
950
+ }
951
+ const text = isArray(param)
952
+ ? param.join('/')
953
+ : param;
980
954
  if (!text) {
981
955
  if (optional) {
982
- // if we have more than one optional param like /:a?-static and there are more segments, we don't need to
983
- // care about the optional param
984
- if (segment.length < 2 && segments.length > 1) {
956
+ // if we have more than one optional param like /:a?-static we don't need to care about the optional param
957
+ if (segment.length < 2) {
985
958
  // remove the last slash as we could be at the end
986
959
  if (path.endsWith('/'))
987
960
  path = path.slice(0, -1);
@@ -997,7 +970,8 @@ var KduRouter = (function (exports, kdu) {
997
970
  }
998
971
  }
999
972
  }
1000
- return path;
973
+ // avoid empty path when we have multiple optional params
974
+ return path || '/';
1001
975
  }
1002
976
  return {
1003
977
  re,
@@ -1028,12 +1002,12 @@ var KduRouter = (function (exports, kdu) {
1028
1002
  // if the last subsegment was Static, the shorter segments should be sorted first
1029
1003
  // otherwise sort the longest segment first
1030
1004
  if (a.length < b.length) {
1031
- return a.length === 1 && a[0] === 40 /* Static */ + 40 /* Segment */
1005
+ return a.length === 1 && a[0] === 40 /* PathScore.Static */ + 40 /* PathScore.Segment */
1032
1006
  ? -1
1033
1007
  : 1;
1034
1008
  }
1035
1009
  else if (a.length > b.length) {
1036
- return b.length === 1 && b[0] === 40 /* Static */ + 40 /* Segment */
1010
+ return b.length === 1 && b[0] === 40 /* PathScore.Static */ + 40 /* PathScore.Segment */
1037
1011
  ? 1
1038
1012
  : -1;
1039
1013
  }
@@ -1084,7 +1058,7 @@ var KduRouter = (function (exports, kdu) {
1084
1058
  }
1085
1059
 
1086
1060
  const ROOT_TOKEN = {
1087
- type: 0 /* Static */,
1061
+ type: 0 /* TokenType.Static */,
1088
1062
  value: '',
1089
1063
  };
1090
1064
  const VALID_PARAM_RE = /[a-zA-Z0-9_]/;
@@ -1104,7 +1078,7 @@ var KduRouter = (function (exports, kdu) {
1104
1078
  function crash(message) {
1105
1079
  throw new Error(`ERR (${state})/"${buffer}": ${message}`);
1106
1080
  }
1107
- let state = 0 /* Static */;
1081
+ let state = 0 /* TokenizerState.Static */;
1108
1082
  let previousState = state;
1109
1083
  const tokens = [];
1110
1084
  // the segment will always be valid because we get into the initial state
@@ -1126,19 +1100,19 @@ var KduRouter = (function (exports, kdu) {
1126
1100
  function consumeBuffer() {
1127
1101
  if (!buffer)
1128
1102
  return;
1129
- if (state === 0 /* Static */) {
1103
+ if (state === 0 /* TokenizerState.Static */) {
1130
1104
  segment.push({
1131
- type: 0 /* Static */,
1105
+ type: 0 /* TokenType.Static */,
1132
1106
  value: buffer,
1133
1107
  });
1134
1108
  }
1135
- else if (state === 1 /* Param */ ||
1136
- state === 2 /* ParamRegExp */ ||
1137
- state === 3 /* ParamRegExpEnd */) {
1109
+ else if (state === 1 /* TokenizerState.Param */ ||
1110
+ state === 2 /* TokenizerState.ParamRegExp */ ||
1111
+ state === 3 /* TokenizerState.ParamRegExpEnd */) {
1138
1112
  if (segment.length > 1 && (char === '*' || char === '+'))
1139
1113
  crash(`A repeatable param (${buffer}) must be alone in its segment. eg: '/:ids+.`);
1140
1114
  segment.push({
1141
- type: 1 /* Param */,
1115
+ type: 1 /* TokenType.Param */,
1142
1116
  value: buffer,
1143
1117
  regexp: customRe,
1144
1118
  repeatable: char === '*' || char === '+',
@@ -1155,13 +1129,13 @@ var KduRouter = (function (exports, kdu) {
1155
1129
  }
1156
1130
  while (i < path.length) {
1157
1131
  char = path[i++];
1158
- if (char === '\\' && state !== 2 /* ParamRegExp */) {
1132
+ if (char === '\\' && state !== 2 /* TokenizerState.ParamRegExp */) {
1159
1133
  previousState = state;
1160
- state = 4 /* EscapeNext */;
1134
+ state = 4 /* TokenizerState.EscapeNext */;
1161
1135
  continue;
1162
1136
  }
1163
1137
  switch (state) {
1164
- case 0 /* Static */:
1138
+ case 0 /* TokenizerState.Static */:
1165
1139
  if (char === '/') {
1166
1140
  if (buffer) {
1167
1141
  consumeBuffer();
@@ -1170,32 +1144,32 @@ var KduRouter = (function (exports, kdu) {
1170
1144
  }
1171
1145
  else if (char === ':') {
1172
1146
  consumeBuffer();
1173
- state = 1 /* Param */;
1147
+ state = 1 /* TokenizerState.Param */;
1174
1148
  }
1175
1149
  else {
1176
1150
  addCharToBuffer();
1177
1151
  }
1178
1152
  break;
1179
- case 4 /* EscapeNext */:
1153
+ case 4 /* TokenizerState.EscapeNext */:
1180
1154
  addCharToBuffer();
1181
1155
  state = previousState;
1182
1156
  break;
1183
- case 1 /* Param */:
1157
+ case 1 /* TokenizerState.Param */:
1184
1158
  if (char === '(') {
1185
- state = 2 /* ParamRegExp */;
1159
+ state = 2 /* TokenizerState.ParamRegExp */;
1186
1160
  }
1187
1161
  else if (VALID_PARAM_RE.test(char)) {
1188
1162
  addCharToBuffer();
1189
1163
  }
1190
1164
  else {
1191
1165
  consumeBuffer();
1192
- state = 0 /* Static */;
1166
+ state = 0 /* TokenizerState.Static */;
1193
1167
  // go back one character if we were not modifying
1194
1168
  if (char !== '*' && char !== '?' && char !== '+')
1195
1169
  i--;
1196
1170
  }
1197
1171
  break;
1198
- case 2 /* ParamRegExp */:
1172
+ case 2 /* TokenizerState.ParamRegExp */:
1199
1173
  // TODO: is it worth handling nested regexp? like :p(?:prefix_([^/]+)_suffix)
1200
1174
  // it already works by escaping the closing )
1201
1175
  // is this really something people need since you can also write
@@ -1205,16 +1179,16 @@ var KduRouter = (function (exports, kdu) {
1205
1179
  if (customRe[customRe.length - 1] == '\\')
1206
1180
  customRe = customRe.slice(0, -1) + char;
1207
1181
  else
1208
- state = 3 /* ParamRegExpEnd */;
1182
+ state = 3 /* TokenizerState.ParamRegExpEnd */;
1209
1183
  }
1210
1184
  else {
1211
1185
  customRe += char;
1212
1186
  }
1213
1187
  break;
1214
- case 3 /* ParamRegExpEnd */:
1188
+ case 3 /* TokenizerState.ParamRegExpEnd */:
1215
1189
  // same as finalizing a param
1216
1190
  consumeBuffer();
1217
- state = 0 /* Static */;
1191
+ state = 0 /* TokenizerState.Static */;
1218
1192
  // go back one character if we were not modifying
1219
1193
  if (char !== '*' && char !== '?' && char !== '+')
1220
1194
  i--;
@@ -1225,7 +1199,7 @@ var KduRouter = (function (exports, kdu) {
1225
1199
  break;
1226
1200
  }
1227
1201
  }
1228
- if (state === 2 /* ParamRegExp */)
1202
+ if (state === 2 /* TokenizerState.ParamRegExp */)
1229
1203
  crash(`Unfinished custom RegExp for param "${buffer}"`);
1230
1204
  consumeBuffer();
1231
1205
  finalizeSegment();
@@ -1280,6 +1254,9 @@ var KduRouter = (function (exports, kdu) {
1280
1254
  // used later on to remove by name
1281
1255
  const isRootAdd = !originalRecord;
1282
1256
  const mainNormalizedRecord = normalizeRouteRecord(record);
1257
+ {
1258
+ checkChildMissingNameWithEmptyPath(mainNormalizedRecord, parent);
1259
+ }
1283
1260
  // we might be the child of an alias
1284
1261
  mainNormalizedRecord.aliasOf = originalRecord && originalRecord.record;
1285
1262
  const options = mergeOptions(globalOptions, record);
@@ -1323,11 +1300,11 @@ var KduRouter = (function (exports, kdu) {
1323
1300
  throw new Error('Catch all routes ("*") must now be defined using a param with a custom regexp.\n' +
1324
1301
  'See more at https://kdujs-router.web.app/guide/migration/#removed-star-or-catch-all-routes.');
1325
1302
  }
1326
- // create the object before hand so it can be passed to children
1303
+ // create the object beforehand, so it can be passed to children
1327
1304
  matcher = createRouteRecordMatcher(normalizedRecord, parent, options);
1328
1305
  if (parent && path[0] === '/')
1329
1306
  checkMissingParamsInAbsolutePath(matcher, parent);
1330
- // if we are an alias we must tell the original record that we exist
1307
+ // if we are an alias we must tell the original record that we exist,
1331
1308
  // so we can be removed
1332
1309
  if (originalRecord) {
1333
1310
  originalRecord.alias.push(matcher);
@@ -1345,20 +1322,27 @@ var KduRouter = (function (exports, kdu) {
1345
1322
  if (isRootAdd && record.name && !isAliasRecord(matcher))
1346
1323
  removeRoute(record.name);
1347
1324
  }
1348
- if ('children' in mainNormalizedRecord) {
1325
+ if (mainNormalizedRecord.children) {
1349
1326
  const children = mainNormalizedRecord.children;
1350
1327
  for (let i = 0; i < children.length; i++) {
1351
1328
  addRoute(children[i], matcher, originalRecord && originalRecord.children[i]);
1352
1329
  }
1353
1330
  }
1354
1331
  // if there was no original record, then the first one was not an alias and all
1355
- // other alias (if any) need to reference this record when adding children
1332
+ // other aliases (if any) need to reference this record when adding children
1356
1333
  originalRecord = originalRecord || matcher;
1357
1334
  // TODO: add normalized records for more flexibility
1358
1335
  // if (parent && isAliasRecord(originalRecord)) {
1359
1336
  // parent.children.push(originalRecord)
1360
1337
  // }
1361
- insertMatcher(matcher);
1338
+ // Avoid adding a record that doesn't display anything. This allows passing through records without a component to
1339
+ // not be reached and pass through the catch all route
1340
+ if ((matcher.record.components &&
1341
+ Object.keys(matcher.record.components).length) ||
1342
+ matcher.record.name ||
1343
+ matcher.record.redirect) {
1344
+ insertMatcher(matcher);
1345
+ }
1362
1346
  }
1363
1347
  return originalMatcher
1364
1348
  ? () => {
@@ -1412,16 +1396,27 @@ var KduRouter = (function (exports, kdu) {
1412
1396
  if ('name' in location && location.name) {
1413
1397
  matcher = matcherMap.get(location.name);
1414
1398
  if (!matcher)
1415
- throw createRouterError(1 /* MATCHER_NOT_FOUND */, {
1399
+ throw createRouterError(1 /* ErrorTypes.MATCHER_NOT_FOUND */, {
1416
1400
  location,
1417
1401
  });
1402
+ // warn if the user is passing invalid params so they can debug it better when they get removed
1403
+ {
1404
+ const invalidParams = Object.keys(location.params || {}).filter(paramName => !matcher.keys.find(k => k.name === paramName));
1405
+ if (invalidParams.length) {
1406
+ warn(`Discarded invalid param(s) "${invalidParams.join('", "')}" when navigating.`);
1407
+ }
1408
+ }
1418
1409
  name = matcher.record.name;
1419
1410
  params = assign(
1420
1411
  // paramsFromLocation is a new object
1421
1412
  paramsFromLocation(currentLocation.params,
1422
1413
  // only keep params that exist in the resolved location
1423
1414
  // TODO: only keep optional params coming from a parent record
1424
- matcher.keys.filter(k => !k.optional).map(k => k.name)), location.params);
1415
+ matcher.keys.filter(k => !k.optional).map(k => k.name)),
1416
+ // discard any existing params in the current location that do not exist here
1417
+ // #1497 this ensures better active/exact matching
1418
+ location.params &&
1419
+ paramsFromLocation(location.params, matcher.keys.map(k => k.name)));
1425
1420
  // throws if cannot be stringified
1426
1421
  path = matcher.stringify(params);
1427
1422
  }
@@ -1435,7 +1430,6 @@ var KduRouter = (function (exports, kdu) {
1435
1430
  matcher = matchers.find(m => m.re.test(path));
1436
1431
  // matcher should have a value after the loop
1437
1432
  if (matcher) {
1438
- // TODO: dev warning of unused params if provided
1439
1433
  // we know the matcher works because we tested the regexp
1440
1434
  params = matcher.parse(path);
1441
1435
  name = matcher.record.name;
@@ -1448,7 +1442,7 @@ var KduRouter = (function (exports, kdu) {
1448
1442
  ? matcherMap.get(currentLocation.name)
1449
1443
  : matchers.find(m => m.re.test(currentLocation.path));
1450
1444
  if (!matcher)
1451
- throw createRouterError(1 /* MATCHER_NOT_FOUND */, {
1445
+ throw createRouterError(1 /* ErrorTypes.MATCHER_NOT_FOUND */, {
1452
1446
  location,
1453
1447
  currentLocation,
1454
1448
  });
@@ -1506,8 +1500,8 @@ var KduRouter = (function (exports, kdu) {
1506
1500
  updateGuards: new Set(),
1507
1501
  enterCallbacks: {},
1508
1502
  components: 'components' in record
1509
- ? record.components || {}
1510
- : { default: record.component },
1503
+ ? record.components || null
1504
+ : record.component && { default: record.component },
1511
1505
  };
1512
1506
  }
1513
1507
  /**
@@ -1517,7 +1511,7 @@ var KduRouter = (function (exports, kdu) {
1517
1511
  */
1518
1512
  function normalizeRecordProps(record) {
1519
1513
  const propsObject = {};
1520
- // props does not exist on redirect records but we can set false directly
1514
+ // props does not exist on redirect records, but we can set false directly
1521
1515
  const props = record.props || false;
1522
1516
  if ('component' in record) {
1523
1517
  propsObject.default = props;
@@ -1571,17 +1565,31 @@ var KduRouter = (function (exports, kdu) {
1571
1565
  function checkSameParams(a, b) {
1572
1566
  for (const key of a.keys) {
1573
1567
  if (!key.optional && !b.keys.find(isSameParam.bind(null, key)))
1574
- return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" should have the exact same param named "${key.name}"`);
1568
+ return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" must have the exact same param named "${key.name}"`);
1575
1569
  }
1576
1570
  for (const key of b.keys) {
1577
1571
  if (!key.optional && !a.keys.find(isSameParam.bind(null, key)))
1578
- return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" should have the exact same param named "${key.name}"`);
1572
+ return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" must have the exact same param named "${key.name}"`);
1573
+ }
1574
+ }
1575
+ /**
1576
+ * A route with a name and a child with an empty path without a name should warn when adding the route
1577
+ *
1578
+ * @param mainNormalizedRecord - RouteRecordNormalized
1579
+ * @param parent - RouteRecordMatcher
1580
+ */
1581
+ function checkChildMissingNameWithEmptyPath(mainNormalizedRecord, parent) {
1582
+ if (parent &&
1583
+ parent.record.name &&
1584
+ !mainNormalizedRecord.name &&
1585
+ !mainNormalizedRecord.path) {
1586
+ warn(`The route named "${String(parent.record.name)}" has a child without a name and an empty path. Using that name won't render the empty path child so you probably want to move the name to the child instead. If this is intentional, add a name to the child route to remove the warning.`);
1579
1587
  }
1580
1588
  }
1581
1589
  function checkMissingParamsInAbsolutePath(record, parent) {
1582
1590
  for (const key of parent.keys) {
1583
1591
  if (!record.keys.find(isSameParam.bind(null, key)))
1584
- return warn(`Absolute path "${record.record.path}" should have the exact same param named "${key.name}" as its parent "${parent.record.path}".`);
1592
+ return warn(`Absolute path "${record.record.path}" must have the exact same param named "${key.name}" as its parent "${parent.record.path}".`);
1585
1593
  }
1586
1594
  }
1587
1595
  function isRecordChildOf(record, parent) {
@@ -1595,7 +1603,7 @@ var KduRouter = (function (exports, kdu) {
1595
1603
  * On top of that, the RFC3986 (https://tools.ietf.org/html/rfc3986#section-2.2)
1596
1604
  * defines some extra characters to be encoded. Most browsers do not encode them
1597
1605
  * in encodeURI https://github.com/whatwg/url/issues/369, so it may be safer to
1598
- * also encode `!'()*`. Leaving unencoded only ASCII alphanumeric(`a-zA-Z0-9`)
1606
+ * also encode `!'()*`. Leaving un-encoded only ASCII alphanumeric(`a-zA-Z0-9`)
1599
1607
  * plus `-._~`. This extra safety should be applied to query by patching the
1600
1608
  * string returned by encodeURIComponent encodeURI also encodes `[\]^`. `\`
1601
1609
  * should be encoded to avoid ambiguity. Browsers (IE, FF, C) transform a `\`
@@ -1619,7 +1627,7 @@ var KduRouter = (function (exports, kdu) {
1619
1627
  * application/x-www-form-urlencoded
1620
1628
  * (https://url.spec.whatwg.org/#urlencoded-parsing) and most browsers seems lo
1621
1629
  * leave the plus character as is in queries. To be more flexible, we allow the
1622
- * plus character on the query but it can also be manually encoded by the user.
1630
+ * plus character on the query, but it can also be manually encoded by the user.
1623
1631
  *
1624
1632
  * Resources:
1625
1633
  * - https://url.spec.whatwg.org/#urlencoded-parsing
@@ -1751,7 +1759,7 @@ var KduRouter = (function (exports, kdu) {
1751
1759
  if (key in query) {
1752
1760
  // an extra variable for ts types
1753
1761
  let currentValue = query[key];
1754
- if (!Array.isArray(currentValue)) {
1762
+ if (!isArray(currentValue)) {
1755
1763
  currentValue = query[key] = [currentValue];
1756
1764
  }
1757
1765
  currentValue.push(value);
@@ -1784,7 +1792,7 @@ var KduRouter = (function (exports, kdu) {
1784
1792
  continue;
1785
1793
  }
1786
1794
  // keep null values
1787
- const values = Array.isArray(value)
1795
+ const values = isArray(value)
1788
1796
  ? value.map(v => v && encodeQueryValue(v))
1789
1797
  : [value && encodeQueryValue(value)];
1790
1798
  values.forEach(value => {
@@ -1813,7 +1821,7 @@ var KduRouter = (function (exports, kdu) {
1813
1821
  for (const key in query) {
1814
1822
  const value = query[key];
1815
1823
  if (value !== undefined) {
1816
- normalizedQuery[key] = Array.isArray(value)
1824
+ normalizedQuery[key] = isArray(value)
1817
1825
  ? value.map(v => (v == null ? null : '' + v))
1818
1826
  : value == null
1819
1827
  ? value
@@ -1823,6 +1831,43 @@ var KduRouter = (function (exports, kdu) {
1823
1831
  return normalizedQuery;
1824
1832
  }
1825
1833
 
1834
+ /**
1835
+ * RouteRecord being rendered by the closest ancestor Router View. Used for
1836
+ * `onBeforeRouteUpdate` and `onBeforeRouteLeave`. rvlm stands for Router View
1837
+ * Location Matched
1838
+ *
1839
+ * @internal
1840
+ */
1841
+ const matchedRouteKey = Symbol('router view location matched' );
1842
+ /**
1843
+ * Allows overriding the router view depth to control which component in
1844
+ * `matched` is rendered. rvd stands for Router View Depth
1845
+ *
1846
+ * @internal
1847
+ */
1848
+ const viewDepthKey = Symbol('router view depth' );
1849
+ /**
1850
+ * Allows overriding the router instance returned by `useRouter` in tests. r
1851
+ * stands for router
1852
+ *
1853
+ * @internal
1854
+ */
1855
+ const routerKey = Symbol('router' );
1856
+ /**
1857
+ * Allows overriding the current route returned by `useRoute` in tests. rl
1858
+ * stands for route location
1859
+ *
1860
+ * @internal
1861
+ */
1862
+ const routeLocationKey = Symbol('route location' );
1863
+ /**
1864
+ * Allows overriding the current route used by router-view. Internally this is
1865
+ * used when the `route` prop is passed.
1866
+ *
1867
+ * @internal
1868
+ */
1869
+ const routerViewLocationKey = Symbol('router view location' );
1870
+
1826
1871
  /**
1827
1872
  * Create a list of callbacks that can be reset. Used to create before and after navigation guards list
1828
1873
  */
@@ -1873,7 +1918,7 @@ var KduRouter = (function (exports, kdu) {
1873
1918
  // to avoid warning
1874
1919
  {}).value;
1875
1920
  if (!activeRecord) {
1876
- warn('No active route record was found when calling `onBeforeRouteLeave()`. Make sure you call this function inside of a component child of <router-view>. Maybe you called it inside of App.kdu?');
1921
+ warn('No active route record was found when calling `onBeforeRouteLeave()`. Make sure you call this function inside a component child of <router-view>. Maybe you called it inside of App.kdu?');
1877
1922
  return;
1878
1923
  }
1879
1924
  registerGuard(activeRecord, 'leaveGuards', leaveGuard);
@@ -1894,7 +1939,7 @@ var KduRouter = (function (exports, kdu) {
1894
1939
  // to avoid warning
1895
1940
  {}).value;
1896
1941
  if (!activeRecord) {
1897
- warn('No active route record was found when calling `onBeforeRouteUpdate()`. Make sure you call this function inside of a component child of <router-view>. Maybe you called it inside of App.kdu?');
1942
+ warn('No active route record was found when calling `onBeforeRouteUpdate()`. Make sure you call this function inside a component child of <router-view>. Maybe you called it inside of App.kdu?');
1898
1943
  return;
1899
1944
  }
1900
1945
  registerGuard(activeRecord, 'updateGuards', updateGuard);
@@ -1906,16 +1951,17 @@ var KduRouter = (function (exports, kdu) {
1906
1951
  (record.enterCallbacks[name] = record.enterCallbacks[name] || []);
1907
1952
  return () => new Promise((resolve, reject) => {
1908
1953
  const next = (valid) => {
1909
- if (valid === false)
1910
- reject(createRouterError(4 /* NAVIGATION_ABORTED */, {
1954
+ if (valid === false) {
1955
+ reject(createRouterError(4 /* ErrorTypes.NAVIGATION_ABORTED */, {
1911
1956
  from,
1912
1957
  to,
1913
1958
  }));
1959
+ }
1914
1960
  else if (valid instanceof Error) {
1915
1961
  reject(valid);
1916
1962
  }
1917
1963
  else if (isRouteLocation(valid)) {
1918
- reject(createRouterError(2 /* NAVIGATION_GUARD_REDIRECT */, {
1964
+ reject(createRouterError(2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */, {
1919
1965
  from: to,
1920
1966
  to: valid,
1921
1967
  }));
@@ -1924,8 +1970,9 @@ var KduRouter = (function (exports, kdu) {
1924
1970
  if (enterCallbackArray &&
1925
1971
  // since enterCallbackArray is truthy, both record and name also are
1926
1972
  record.enterCallbacks[name] === enterCallbackArray &&
1927
- typeof valid === 'function')
1973
+ typeof valid === 'function') {
1928
1974
  enterCallbackArray.push(valid);
1975
+ }
1929
1976
  resolve();
1930
1977
  }
1931
1978
  };
@@ -1945,7 +1992,6 @@ var KduRouter = (function (exports, kdu) {
1945
1992
  }
1946
1993
  return resolvedValue;
1947
1994
  });
1948
- // TODO: test me!
1949
1995
  }
1950
1996
  else if (guardReturn !== undefined) {
1951
1997
  // @ts-expect-error: _called is added at canOnlyBeCalledOnce
@@ -1973,6 +2019,10 @@ var KduRouter = (function (exports, kdu) {
1973
2019
  function extractComponentsGuards(matched, guardType, to, from) {
1974
2020
  const guards = [];
1975
2021
  for (const record of matched) {
2022
+ if (!record.components && !record.children.length) {
2023
+ warn(`Record with path "${record.path}" is either missing a "component(s)"` +
2024
+ ` or "children" property.`);
2025
+ }
1976
2026
  for (const name in record.components) {
1977
2027
  let rawComponent = record.components[name];
1978
2028
  {
@@ -2029,6 +2079,7 @@ var KduRouter = (function (exports, kdu) {
2029
2079
  ? resolved.default
2030
2080
  : resolved;
2031
2081
  // replace the function with the resolved component
2082
+ // cannot be null or undefined because we went into the for loop
2032
2083
  record.components[name] = resolvedComponent;
2033
2084
  // __kccOpts is added by kdu-class-component and contain the regular options
2034
2085
  const options = resolvedComponent.__kccOpts || resolvedComponent;
@@ -2042,6 +2093,7 @@ var KduRouter = (function (exports, kdu) {
2042
2093
  }
2043
2094
  /**
2044
2095
  * Allows differentiating lazy components from functional components and kdu-class-component
2096
+ * @internal
2045
2097
  *
2046
2098
  * @param component
2047
2099
  */
@@ -2050,6 +2102,34 @@ var KduRouter = (function (exports, kdu) {
2050
2102
  'displayName' in component ||
2051
2103
  'props' in component ||
2052
2104
  '__kccOpts' in component);
2105
+ }
2106
+ /**
2107
+ * Ensures a route is loaded, so it can be passed as o prop to `<RouterView>`.
2108
+ *
2109
+ * @param route - resolved route to load
2110
+ */
2111
+ function loadRouteLocation(route) {
2112
+ return route.matched.every(record => record.redirect)
2113
+ ? Promise.reject(new Error('Cannot load a route that redirects.'))
2114
+ : Promise.all(route.matched.map(record => record.components &&
2115
+ Promise.all(Object.keys(record.components).reduce((promises, name) => {
2116
+ const rawComponent = record.components[name];
2117
+ if (typeof rawComponent === 'function' &&
2118
+ !('displayName' in rawComponent)) {
2119
+ promises.push(rawComponent().then(resolved => {
2120
+ if (!resolved)
2121
+ return Promise.reject(new Error(`Couldn't resolve component "${name}" at "${record.path}". Ensure you passed a function that returns a promise.`));
2122
+ const resolvedComponent = isESModule(resolved)
2123
+ ? resolved.default
2124
+ : resolved;
2125
+ // replace the function with the resolved component
2126
+ // cannot be null or undefined because we went into the for loop
2127
+ record.components[name] = resolvedComponent;
2128
+ return;
2129
+ }));
2130
+ }
2131
+ return promises;
2132
+ }, [])))).then(() => route);
2053
2133
  }
2054
2134
 
2055
2135
  // TODO: we could allow currentRoute as a prop to expose `isActive` and
@@ -2115,6 +2195,9 @@ var KduRouter = (function (exports, kdu) {
2115
2195
  }, { flush: 'post' });
2116
2196
  }
2117
2197
  }
2198
+ /**
2199
+ * NOTE: update {@link _RouterLinkI}'s `$slots` type when updating this
2200
+ */
2118
2201
  return {
2119
2202
  route,
2120
2203
  href: kdu.computed(() => route.value.href),
@@ -2164,7 +2247,7 @@ var KduRouter = (function (exports, kdu) {
2164
2247
  : null,
2165
2248
  href: link.href,
2166
2249
  // this would override user added attrs but Kdu will still add
2167
- // the listener so we end up triggering both
2250
+ // the listener, so we end up triggering both
2168
2251
  onClick: link.navigate,
2169
2252
  class: elClass.value,
2170
2253
  }, children);
@@ -2209,7 +2292,7 @@ var KduRouter = (function (exports, kdu) {
2209
2292
  return false;
2210
2293
  }
2211
2294
  else {
2212
- if (!Array.isArray(outerValue) ||
2295
+ if (!isArray(outerValue) ||
2213
2296
  outerValue.length !== innerValue.length ||
2214
2297
  innerValue.some((value, i) => value !== outerValue[i]))
2215
2298
  return false;
@@ -2253,9 +2336,21 @@ var KduRouter = (function (exports, kdu) {
2253
2336
  warnDeprecatedUsage();
2254
2337
  const injectedRoute = kdu.inject(routerViewLocationKey);
2255
2338
  const routeToDisplay = kdu.computed(() => props.route || injectedRoute.value);
2256
- const depth = kdu.inject(viewDepthKey, 0);
2257
- const matchedRouteRef = kdu.computed(() => routeToDisplay.value.matched[depth]);
2258
- kdu.provide(viewDepthKey, depth + 1);
2339
+ const injectedDepth = kdu.inject(viewDepthKey, 0);
2340
+ // The depth changes based on empty components option, which allows passthrough routes e.g. routes with children
2341
+ // that are used to reuse the `path` property
2342
+ const depth = kdu.computed(() => {
2343
+ let initialDepth = kdu.unref(injectedDepth);
2344
+ const { matched } = routeToDisplay.value;
2345
+ let matchedRoute;
2346
+ while ((matchedRoute = matched[initialDepth]) &&
2347
+ !matchedRoute.components) {
2348
+ initialDepth++;
2349
+ }
2350
+ return initialDepth;
2351
+ });
2352
+ const matchedRouteRef = kdu.computed(() => routeToDisplay.value.matched[depth.value]);
2353
+ kdu.provide(viewDepthKey, kdu.computed(() => depth.value + 1));
2259
2354
  kdu.provide(matchedRouteKey, matchedRouteRef);
2260
2355
  kdu.provide(routerViewLocationKey, routeToDisplay);
2261
2356
  const viewRef = kdu.ref();
@@ -2267,7 +2362,7 @@ var KduRouter = (function (exports, kdu) {
2267
2362
  // this will update the instance for new instances as well as reused
2268
2363
  // instances when navigating to a new route
2269
2364
  to.instances[name] = instance;
2270
- // the component instance is reused for a different route or name so
2365
+ // the component instance is reused for a different route or name, so
2271
2366
  // we copy any saved update or leave guards. With async setup, the
2272
2367
  // mounting component will mount before the matchedRoute changes,
2273
2368
  // making instance === oldInstance, so we check if guards have been
@@ -2293,16 +2388,16 @@ var KduRouter = (function (exports, kdu) {
2293
2388
  }, { flush: 'post' });
2294
2389
  return () => {
2295
2390
  const route = routeToDisplay.value;
2296
- const matchedRoute = matchedRouteRef.value;
2297
- const ViewComponent = matchedRoute && matchedRoute.components[props.name];
2298
2391
  // we need the value at the time we render because when we unmount, we
2299
2392
  // navigated to a different location so the value is different
2300
2393
  const currentName = props.name;
2394
+ const matchedRoute = matchedRouteRef.value;
2395
+ const ViewComponent = matchedRoute && matchedRoute.components[currentName];
2301
2396
  if (!ViewComponent) {
2302
2397
  return normalizeSlot(slots.default, { Component: ViewComponent, route });
2303
2398
  }
2304
2399
  // props from route configuration
2305
- const routePropsOption = matchedRoute.props[props.name];
2400
+ const routePropsOption = matchedRoute.props[currentName];
2306
2401
  const routeProps = routePropsOption
2307
2402
  ? routePropsOption === true
2308
2403
  ? route.params
@@ -2324,12 +2419,12 @@ var KduRouter = (function (exports, kdu) {
2324
2419
  component.ref) {
2325
2420
  // TODO: can display if it's an alias, its props
2326
2421
  const info = {
2327
- depth,
2422
+ depth: depth.value,
2328
2423
  name: matchedRoute.name,
2329
2424
  path: matchedRoute.path,
2330
2425
  meta: matchedRoute.meta,
2331
2426
  };
2332
- const internalInstances = Array.isArray(component.ref)
2427
+ const internalInstances = isArray(component.ref)
2333
2428
  ? component.ref.map(r => r.i)
2334
2429
  : [component.ref.i];
2335
2430
  internalInstances.forEach(instance => {
@@ -2542,6 +2637,13 @@ var KduRouter = (function (exports, kdu) {
2542
2637
  }
2543
2638
  }
2544
2639
 
2640
+ /**
2641
+ * Copies a route location and removes any problematic properties that cannot be shown in devtools (e.g. Kdu instances).
2642
+ *
2643
+ * @param routeLocation - routeLocation to format
2644
+ * @param tooltip - optional tooltip
2645
+ * @returns a copy of the routeLocation
2646
+ */
2545
2647
  function formatRouteLocation(routeLocation, tooltip) {
2546
2648
  const copy = assign({}, routeLocation, {
2547
2649
  // remove variables that can contain kdu instances
@@ -2583,6 +2685,9 @@ var KduRouter = (function (exports, kdu) {
2583
2685
  componentStateTypes: ['Routing'],
2584
2686
  app,
2585
2687
  }, api => {
2688
+ if (typeof api.now !== 'function') {
2689
+ console.warn('[Kdu Router]: You seem to be using an outdated version of Kdu Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://kdujs-devtools.web.app/guide/installation.html.');
2690
+ }
2586
2691
  // display state added by the router
2587
2692
  api.on.inspectComponent((payload, ctx) => {
2588
2693
  if (payload.instanceData) {
@@ -2606,7 +2711,7 @@ var KduRouter = (function (exports, kdu) {
2606
2711
  });
2607
2712
  }
2608
2713
  // if multiple useLink are used
2609
- if (Array.isArray(componentInstance.__krl_devtools)) {
2714
+ if (isArray(componentInstance.__krl_devtools)) {
2610
2715
  componentInstance.__devtoolsApi = api;
2611
2716
  componentInstance.__krl_devtools.forEach(devtoolsData => {
2612
2717
  let backgroundColor = ORANGE_400;
@@ -2759,7 +2864,7 @@ var KduRouter = (function (exports, kdu) {
2759
2864
  api.on.getInspectorState(payload => {
2760
2865
  if (payload.app === app && payload.inspectorId === routerInspectorId) {
2761
2866
  const routes = matcher.getRoutes();
2762
- const route = routes.find(route => route.record.__vd_id === payload.nodeId);
2867
+ const route = routes.find(route => route.record.__kd_id === payload.nodeId);
2763
2868
  if (route) {
2764
2869
  payload.state = {
2765
2870
  options: formatRouteRecordMatcherForStateInspector(route),
@@ -2823,6 +2928,13 @@ var KduRouter = (function (exports, kdu) {
2823
2928
  value: route.alias.map(alias => alias.record.path),
2824
2929
  });
2825
2930
  }
2931
+ if (Object.keys(route.record.meta).length) {
2932
+ fields.push({
2933
+ editable: false,
2934
+ key: 'meta',
2935
+ value: route.record.meta,
2936
+ });
2937
+ }
2826
2938
  fields.push({
2827
2939
  key: 'score',
2828
2940
  editable: false,
@@ -2865,21 +2977,21 @@ var KduRouter = (function (exports, kdu) {
2865
2977
  backgroundColor: ORANGE_400,
2866
2978
  });
2867
2979
  }
2868
- if (route.__vd_match) {
2980
+ if (route.__kd_match) {
2869
2981
  tags.push({
2870
2982
  label: 'matches',
2871
2983
  textColor: 0,
2872
2984
  backgroundColor: PINK_500,
2873
2985
  });
2874
2986
  }
2875
- if (route.__vd_exactActive) {
2987
+ if (route.__kd_exactActive) {
2876
2988
  tags.push({
2877
2989
  label: 'exact',
2878
2990
  textColor: 0,
2879
2991
  backgroundColor: LIME_500,
2880
2992
  });
2881
2993
  }
2882
- if (route.__vd_active) {
2994
+ if (route.__kd_active) {
2883
2995
  tags.push({
2884
2996
  label: 'active',
2885
2997
  textColor: 0,
@@ -2888,18 +3000,19 @@ var KduRouter = (function (exports, kdu) {
2888
3000
  }
2889
3001
  if (record.redirect) {
2890
3002
  tags.push({
2891
- label: 'redirect: ' +
2892
- (typeof record.redirect === 'string' ? record.redirect : 'Object'),
3003
+ label: typeof record.redirect === 'string'
3004
+ ? `redirect: ${record.redirect}`
3005
+ : 'redirects',
2893
3006
  textColor: 0xffffff,
2894
3007
  backgroundColor: DARK,
2895
3008
  });
2896
3009
  }
2897
3010
  // add an id to be able to select it. Using the `path` is not possible because
2898
3011
  // empty path children would collide with their parents
2899
- let id = record.__vd_id;
3012
+ let id = record.__kd_id;
2900
3013
  if (id == null) {
2901
3014
  id = String(routeRecordId++);
2902
- record.__vd_id = id;
3015
+ record.__kd_id = id;
2903
3016
  }
2904
3017
  return {
2905
3018
  id,
@@ -2916,19 +3029,19 @@ var KduRouter = (function (exports, kdu) {
2916
3029
  // reset the matching state
2917
3030
  const isExactActive = currentRoute.matched.length &&
2918
3031
  isSameRouteRecord(currentRoute.matched[currentRoute.matched.length - 1], route.record);
2919
- route.__vd_exactActive = route.__vd_active = isExactActive;
3032
+ route.__kd_exactActive = route.__kd_active = isExactActive;
2920
3033
  if (!isExactActive) {
2921
- route.__vd_active = currentRoute.matched.some(match => isSameRouteRecord(match, route.record));
3034
+ route.__kd_active = currentRoute.matched.some(match => isSameRouteRecord(match, route.record));
2922
3035
  }
2923
3036
  route.children.forEach(childRoute => markRouteRecordActive(childRoute, currentRoute));
2924
3037
  }
2925
3038
  function resetMatchStateOnRouteRecord(route) {
2926
- route.__vd_match = false;
3039
+ route.__kd_match = false;
2927
3040
  route.children.forEach(resetMatchStateOnRouteRecord);
2928
3041
  }
2929
3042
  function isRouteMatching(route, filter) {
2930
3043
  const found = String(route.re).match(EXTRACT_REGEXP_RE);
2931
- route.__vd_match = false;
3044
+ route.__kd_match = false;
2932
3045
  if (!found || found.length < 3) {
2933
3046
  return false;
2934
3047
  }
@@ -2939,7 +3052,7 @@ var KduRouter = (function (exports, kdu) {
2939
3052
  route.children.forEach(child => isRouteMatching(child, filter));
2940
3053
  // exception case: `/`
2941
3054
  if (route.record.path !== '/' || filter === '/') {
2942
- route.__vd_match = route.re.test(filter);
3055
+ route.__kd_match = route.re.test(filter);
2943
3056
  return true;
2944
3057
  }
2945
3058
  // hide the / route
@@ -3068,7 +3181,7 @@ var KduRouter = (function (exports, kdu) {
3068
3181
  delete targetParams[key];
3069
3182
  }
3070
3183
  }
3071
- // pass encoded values to the matcher so it can produce encoded path and fullPath
3184
+ // pass encoded values to the matcher, so it can produce encoded path and fullPath
3072
3185
  matcherLocation = assign({}, rawLocation, {
3073
3186
  params: encodeParams(rawLocation.params),
3074
3187
  });
@@ -3081,7 +3194,7 @@ var KduRouter = (function (exports, kdu) {
3081
3194
  if (hash && !hash.startsWith('#')) {
3082
3195
  warn(`A \`hash\` should always start with the character "#". Replace "${hash}" with "#${hash}".`);
3083
3196
  }
3084
- // decoding them) the matcher might have merged current location params so
3197
+ // the matcher might have merged current location params, so
3085
3198
  // we need to run the decoding again
3086
3199
  matchedRoute.params = normalizeParams(decodeParams(matchedRoute.params));
3087
3200
  const fullPath = stringifyURL(stringifyQuery$1, assign({}, rawLocation, {
@@ -3122,7 +3235,7 @@ var KduRouter = (function (exports, kdu) {
3122
3235
  }
3123
3236
  function checkCanceledNavigation(to, from) {
3124
3237
  if (pendingLocation !== to) {
3125
- return createRouterError(8 /* NAVIGATION_CANCELLED */, {
3238
+ return createRouterError(8 /* ErrorTypes.NAVIGATION_CANCELLED */, {
3126
3239
  from,
3127
3240
  to,
3128
3241
  });
@@ -3157,7 +3270,8 @@ var KduRouter = (function (exports, kdu) {
3157
3270
  return assign({
3158
3271
  query: to.query,
3159
3272
  hash: to.hash,
3160
- params: to.params,
3273
+ // avoid transferring params if the redirect has a path
3274
+ params: 'path' in newTargetLocation ? {} : to.params,
3161
3275
  }, newTargetLocation);
3162
3276
  }
3163
3277
  }
@@ -3171,7 +3285,9 @@ var KduRouter = (function (exports, kdu) {
3171
3285
  const shouldRedirect = handleRedirectRecord(targetLocation);
3172
3286
  if (shouldRedirect)
3173
3287
  return pushWithRedirect(assign(locationAsObject(shouldRedirect), {
3174
- state: data,
3288
+ state: typeof shouldRedirect === 'object'
3289
+ ? assign({}, data, shouldRedirect.state)
3290
+ : data,
3175
3291
  force,
3176
3292
  replace,
3177
3293
  }),
@@ -3182,7 +3298,7 @@ var KduRouter = (function (exports, kdu) {
3182
3298
  toLocation.redirectedFrom = redirectedFrom;
3183
3299
  let failure;
3184
3300
  if (!force && isSameRouteLocation(stringifyQuery$1, from, targetLocation)) {
3185
- failure = createRouterError(16 /* NAVIGATION_DUPLICATED */, { to: toLocation, from });
3301
+ failure = createRouterError(16 /* ErrorTypes.NAVIGATION_DUPLICATED */, { to: toLocation, from });
3186
3302
  // trigger scroll to allow scrolling to the same anchor
3187
3303
  handleScroll(from, from,
3188
3304
  // this is a push, the only way for it to be triggered from a
@@ -3195,14 +3311,14 @@ var KduRouter = (function (exports, kdu) {
3195
3311
  return (failure ? Promise.resolve(failure) : navigate(toLocation, from))
3196
3312
  .catch((error) => isNavigationFailure(error)
3197
3313
  ? // navigation redirects still mark the router as ready
3198
- isNavigationFailure(error, 2 /* NAVIGATION_GUARD_REDIRECT */)
3314
+ isNavigationFailure(error, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)
3199
3315
  ? error
3200
3316
  : markAsReady(error) // also returns the error
3201
3317
  : // reject any unknown error
3202
3318
  triggerError(error, toLocation, from))
3203
3319
  .then((failure) => {
3204
3320
  if (failure) {
3205
- if (isNavigationFailure(failure, 2 /* NAVIGATION_GUARD_REDIRECT */)) {
3321
+ if (isNavigationFailure(failure, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)) {
3206
3322
  if (// we are redirecting to the same location we were already at
3207
3323
  isSameRouteLocation(stringifyQuery$1, resolve(failure.to), toLocation) &&
3208
3324
  // and we have done it a couple of times
@@ -3217,10 +3333,14 @@ var KduRouter = (function (exports, kdu) {
3217
3333
  }
3218
3334
  return pushWithRedirect(
3219
3335
  // keep options
3220
- assign(locationAsObject(failure.to), {
3221
- state: data,
3222
- force,
3336
+ assign({
3337
+ // preserve an existing replacement but allow the redirect to override it
3223
3338
  replace,
3339
+ }, locationAsObject(failure.to), {
3340
+ state: typeof failure.to === 'object'
3341
+ ? assign({}, data, failure.to.state)
3342
+ : data,
3343
+ force,
3224
3344
  }),
3225
3345
  // preserve the original redirectedFrom if any
3226
3346
  redirectedFrom || toLocation);
@@ -3286,7 +3406,7 @@ var KduRouter = (function (exports, kdu) {
3286
3406
  for (const record of to.matched) {
3287
3407
  // do not trigger beforeEnter on reused views
3288
3408
  if (record.beforeEnter && !from.matched.includes(record)) {
3289
- if (Array.isArray(record.beforeEnter)) {
3409
+ if (isArray(record.beforeEnter)) {
3290
3410
  for (const beforeEnter of record.beforeEnter)
3291
3411
  guards.push(guardToPromiseFn(beforeEnter, to, from));
3292
3412
  }
@@ -3319,7 +3439,7 @@ var KduRouter = (function (exports, kdu) {
3319
3439
  return runGuardQueue(guards);
3320
3440
  })
3321
3441
  // catch any navigation canceled
3322
- .catch(err => isNavigationFailure(err, 8 /* NAVIGATION_CANCELLED */)
3442
+ .catch(err => isNavigationFailure(err, 8 /* ErrorTypes.NAVIGATION_CANCELLED */)
3323
3443
  ? err
3324
3444
  : Promise.reject(err)));
3325
3445
  }
@@ -3366,6 +3486,8 @@ var KduRouter = (function (exports, kdu) {
3366
3486
  if (removeHistoryListener)
3367
3487
  return;
3368
3488
  removeHistoryListener = routerHistory.listen((to, _from, info) => {
3489
+ if (!router.listening)
3490
+ return;
3369
3491
  // cannot be a redirect route because it was in history
3370
3492
  const toLocation = resolve(to);
3371
3493
  // due to dynamic routing, and to hash history with manual navigation
@@ -3384,15 +3506,15 @@ var KduRouter = (function (exports, kdu) {
3384
3506
  }
3385
3507
  navigate(toLocation, from)
3386
3508
  .catch((error) => {
3387
- if (isNavigationFailure(error, 4 /* NAVIGATION_ABORTED */ | 8 /* NAVIGATION_CANCELLED */)) {
3509
+ if (isNavigationFailure(error, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | 8 /* ErrorTypes.NAVIGATION_CANCELLED */)) {
3388
3510
  return error;
3389
3511
  }
3390
- if (isNavigationFailure(error, 2 /* NAVIGATION_GUARD_REDIRECT */)) {
3512
+ if (isNavigationFailure(error, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)) {
3391
3513
  // Here we could call if (info.delta) routerHistory.go(-info.delta,
3392
3514
  // false) but this is bug prone as we have no way to wait the
3393
3515
  // navigation to be finished before calling pushWithRedirect. Using
3394
- // a setTimeout of 16ms seems to work but there is not guarantee for
3395
- // it to work on every browser. So Instead we do not restore the
3516
+ // a setTimeout of 16ms seems to work but there is no guarantee for
3517
+ // it to work on every browser. So instead we do not restore the
3396
3518
  // history entry and trigger a new navigation as requested by the
3397
3519
  // navigation guard.
3398
3520
  // the error is already handled by router.push we just want to avoid
@@ -3402,10 +3524,10 @@ var KduRouter = (function (exports, kdu) {
3402
3524
  )
3403
3525
  .then(failure => {
3404
3526
  // manual change in hash history #916 ending up in the URL not
3405
- // changing but it was changed by the manual url change, so we
3527
+ // changing, but it was changed by the manual url change, so we
3406
3528
  // need to manually change it ourselves
3407
- if (isNavigationFailure(failure, 4 /* NAVIGATION_ABORTED */ |
3408
- 16 /* NAVIGATION_DUPLICATED */) &&
3529
+ if (isNavigationFailure(failure, 4 /* ErrorTypes.NAVIGATION_ABORTED */ |
3530
+ 16 /* ErrorTypes.NAVIGATION_DUPLICATED */) &&
3409
3531
  !info.delta &&
3410
3532
  info.type === NavigationType.pop) {
3411
3533
  routerHistory.go(-1, false);
@@ -3416,8 +3538,9 @@ var KduRouter = (function (exports, kdu) {
3416
3538
  return Promise.reject();
3417
3539
  }
3418
3540
  // do not restore history on unknown direction
3419
- if (info.delta)
3541
+ if (info.delta) {
3420
3542
  routerHistory.go(-info.delta, false);
3543
+ }
3421
3544
  // unrecognized error, transfer to the global handler
3422
3545
  return triggerError(error, toLocation, from);
3423
3546
  })
@@ -3429,11 +3552,14 @@ var KduRouter = (function (exports, kdu) {
3429
3552
  toLocation, from, false);
3430
3553
  // revert the navigation
3431
3554
  if (failure) {
3432
- if (info.delta) {
3555
+ if (info.delta &&
3556
+ // a new navigation has been triggered, so we do not want to revert, that will change the current history
3557
+ // entry while a different route is displayed
3558
+ !isNavigationFailure(failure, 8 /* ErrorTypes.NAVIGATION_CANCELLED */)) {
3433
3559
  routerHistory.go(-info.delta, false);
3434
3560
  }
3435
3561
  else if (info.type === NavigationType.pop &&
3436
- isNavigationFailure(failure, 4 /* NAVIGATION_ABORTED */ | 16 /* NAVIGATION_DUPLICATED */)) {
3562
+ isNavigationFailure(failure, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | 16 /* ErrorTypes.NAVIGATION_DUPLICATED */)) {
3437
3563
  // manual change in hash history #916
3438
3564
  // it's like a push but lacks the information of the direction
3439
3565
  routerHistory.go(-1, false);
@@ -3509,6 +3635,7 @@ var KduRouter = (function (exports, kdu) {
3509
3635
  const installedApps = new Set();
3510
3636
  const router = {
3511
3637
  currentRoute,
3638
+ listening: true,
3512
3639
  addRoute,
3513
3640
  removeRoute,
3514
3641
  hasRoute,
@@ -3572,6 +3699,7 @@ var KduRouter = (function (exports, kdu) {
3572
3699
  }
3573
3700
  unmountApp();
3574
3701
  };
3702
+ // TODO: this probably needs to be updated so it can be used by kdu-termui
3575
3703
  if (isBrowser) {
3576
3704
  addDevtools(app, router, matcher);
3577
3705
  }
@@ -3630,6 +3758,7 @@ var KduRouter = (function (exports, kdu) {
3630
3758
  exports.createWebHashHistory = createWebHashHistory;
3631
3759
  exports.createWebHistory = createWebHistory;
3632
3760
  exports.isNavigationFailure = isNavigationFailure;
3761
+ exports.loadRouteLocation = loadRouteLocation;
3633
3762
  exports.matchedRouteKey = matchedRouteKey;
3634
3763
  exports.onBeforeRouteLeave = onBeforeRouteLeave;
3635
3764
  exports.onBeforeRouteUpdate = onBeforeRouteUpdate;