ui5-lib-guard-router 1.1.1 → 1.2.0

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 (33) hide show
  1. package/README.md +73 -5
  2. package/dist/.ui5/build-manifest.json +14 -2
  3. package/dist/index.d.ts +3 -2
  4. package/dist/resources/ui5/guard/router/.library +1 -1
  5. package/dist/resources/ui5/guard/router/NavigationOutcome-dbg.js +26 -0
  6. package/dist/resources/ui5/guard/router/NavigationOutcome-dbg.js.map +1 -0
  7. package/dist/resources/ui5/guard/router/NavigationOutcome.d.ts +25 -0
  8. package/dist/resources/ui5/guard/router/NavigationOutcome.d.ts.map +1 -0
  9. package/dist/resources/ui5/guard/router/NavigationOutcome.js +2 -0
  10. package/dist/resources/ui5/guard/router/NavigationOutcome.js.map +1 -0
  11. package/dist/resources/ui5/guard/router/Router-dbg.js +77 -5
  12. package/dist/resources/ui5/guard/router/Router-dbg.js.map +1 -1
  13. package/dist/resources/ui5/guard/router/Router.d.ts +19 -4
  14. package/dist/resources/ui5/guard/router/Router.d.ts.map +1 -1
  15. package/dist/resources/ui5/guard/router/Router.js +1 -1
  16. package/dist/resources/ui5/guard/router/Router.js.map +1 -1
  17. package/dist/resources/ui5/guard/router/library-dbg.js +8 -3
  18. package/dist/resources/ui5/guard/router/library-dbg.js.map +1 -1
  19. package/dist/resources/ui5/guard/router/library-preload.js +4 -3
  20. package/dist/resources/ui5/guard/router/library-preload.js.map +1 -1
  21. package/dist/resources/ui5/guard/router/library.d.ts.map +1 -1
  22. package/dist/resources/ui5/guard/router/library.js +1 -1
  23. package/dist/resources/ui5/guard/router/library.js.map +1 -1
  24. package/dist/resources/ui5/guard/router/manifest.json +1 -1
  25. package/dist/resources/ui5/guard/router/types-dbg.js.map +1 -1
  26. package/dist/resources/ui5/guard/router/types.d.ts +13 -0
  27. package/dist/resources/ui5/guard/router/types.d.ts.map +1 -1
  28. package/package.json +2 -2
  29. package/src/NavigationOutcome.ts +24 -0
  30. package/src/Router.ts +82 -4
  31. package/src/library.ts +5 -1
  32. package/src/manifest.json +1 -1
  33. package/src/types.ts +14 -0
package/README.md CHANGED
@@ -24,9 +24,9 @@ This library solves all three by intercepting at the router level, before any ro
24
24
  npm install ui5-lib-guard-router
25
25
  ```
26
26
 
27
- ### TypeScript (optional)
27
+ ### TypeScript
28
28
 
29
- If your app uses TypeScript and does not already depend on the UI5 typings, install them too (`@sapui5/types` works as well):
29
+ Add the library to `compilerOptions.types` so TypeScript can resolve the type declarations. If your app does not already depend on UI5 typings, install them too (`@sapui5/types` works as well):
30
30
 
31
31
  ```bash
32
32
  npm install -D @openui5/types
@@ -51,6 +51,10 @@ import type { GuardRouter, GuardFn, LeaveGuardFn } from "ui5/guard/router/types"
51
51
  // Guard pipeline: context passed to guards, and the result union they return
52
52
  import type { GuardContext, GuardResult } from "ui5/guard/router/types";
53
53
 
54
+ // Settlement: outcome of a navigation after the guard pipeline finishes
55
+ import type { NavigationResult } from "ui5/guard/router/types";
56
+ import NavigationOutcome from "ui5/guard/router/NavigationOutcome";
57
+
54
58
  // Advanced: object form for redirect-with-parameters and enter+leave registration
55
59
  import type { GuardRedirect, RouteGuardConfig } from "ui5/guard/router/types";
56
60
  ```
@@ -225,7 +229,7 @@ GuardResult = boolean | string | GuardRedirect
225
229
 
226
230
  `GuardRedirect` is the object form of a redirect. Use it when you need to pass route parameters (`parameters`) or nested component targets (`componentTargetInfo`). For simple redirects without parameters, the string shorthand (`return "home"`) is equivalent and shorter.
227
231
 
228
- Any other value (`null`, `undefined`, `0`, etc.) is treated as a block. Only strict `true` allows navigation -- there is no truthy coercion.
232
+ Any other value (`null`, `undefined`, `0`, etc.) is treated as a block. Only strict `true` allows navigation; there is no truthy coercion.
229
233
 
230
234
  On first load, blocking a non-empty hash restores `""` and continues with the app's default route. Blocking the default route itself stays blocked. If you need a specific denied-first-load destination such as `login`, return a redirect instead of `false`.
231
235
 
@@ -245,6 +249,67 @@ Leave guards answer "can I leave?" and cannot redirect. For redirection logic, u
245
249
  | `stop()` | Cancels pending async guards (aborts the `AbortSignal`), resets guard state. A subsequent `initialize()` re-parses the current hash and fires `routeMatched`, matching native router behavior |
246
250
  | `destroy()` | Clears all registered guards (global, enter, leave), cancels pending async guards, then calls `super.destroy()` |
247
251
 
252
+ ### Navigation settlement
253
+
254
+ `navigationSettled()` returns a Promise that resolves when the guard pipeline finishes. The returned `NavigationResult` contains the outcome as a `NavigationOutcome` enum value, the route name, and the hash determined by the guard pipeline.
255
+
256
+ ```typescript
257
+ import type { NavigationResult } from "ui5/guard/router/types";
258
+ import NavigationOutcome from "ui5/guard/router/NavigationOutcome";
259
+
260
+ const result: NavigationResult = await router.navigationSettled();
261
+ ```
262
+
263
+ | `result.status` | Meaning |
264
+ | ------------------------------ | ---------------------------------------------------------------------------- |
265
+ | `NavigationOutcome.Committed` | Guards allowed the navigation; target route is now active |
266
+ | `NavigationOutcome.Blocked` | A guard blocked navigation; previous route stays active |
267
+ | `NavigationOutcome.Redirected` | A guard redirected navigation to a different route |
268
+ | `NavigationOutcome.Cancelled` | Navigation was cancelled before settling (superseded, stopped, or destroyed) |
269
+
270
+ A guard redirect to a nonexistent route name settles as `Blocked` because no route change commits. The router logs a warning with the bad target name.
271
+
272
+ If no navigation is in flight, `navigationSettled()` resolves immediately with the most recent settlement result. That makes it safe to call right after `navTo()`, even when guards settle synchronously. On a fresh router (or after `stop()`/`destroy()`), this defaults to `Committed` with the current state. Multiple callers waiting on the same pending navigation all receive the same result.
273
+
274
+ **App code: busy indicator during async guards**
275
+
276
+ ```typescript
277
+ router.addRouteGuard("dashboard", async (context) => {
278
+ app.setBusy(true);
279
+ try {
280
+ const res = await fetch(`/api/access/${context.toRoute}`, { signal: context.signal });
281
+ return (await res.json()).allowed ? true : "home";
282
+ } finally {
283
+ app.setBusy(false);
284
+ }
285
+ });
286
+
287
+ // Show a global busy while the guard pipeline runs
288
+ router.navTo("dashboard");
289
+ const result = await router.navigationSettled();
290
+ switch (result.status) {
291
+ case NavigationOutcome.Committed:
292
+ break; // navigation succeeded
293
+ case NavigationOutcome.Blocked:
294
+ MessageToast.show("Access denied");
295
+ break;
296
+ case NavigationOutcome.Redirected:
297
+ MessageToast.show(`Redirected to ${result.route}`);
298
+ break;
299
+ case NavigationOutcome.Cancelled:
300
+ break; // superseded by a newer navigation
301
+ }
302
+ ```
303
+
304
+ **Test code: wait for guards deterministically**
305
+
306
+ ```typescript
307
+ router.navTo("protected");
308
+ const result = await router.navigationSettled();
309
+ assert.strictEqual(result.status, NavigationOutcome.Blocked, "Navigation was blocked");
310
+ assert.strictEqual(result.route, "home", "User stays on home");
311
+ ```
312
+
248
313
  ### Execution order
249
314
 
250
315
  1. **Leave guards** for the current route (registration order)
@@ -425,6 +490,9 @@ sap.ushell.Container.registerDirtyStateProvider(dirtyProvider);
425
490
 
426
491
  No `toRoute` check or FLP detection is needed in the leave guard. Cross-app navigation via `toExternal()` operates at the shell level in both production and the FLP sandbox, so the leave guard never runs for cross-app hashes. The leave guard protects in-app route changes; the FLP dirty-state provider protects cross-app navigation, browser close, and the shell home button.
427
492
 
493
+ > [!TIP]
494
+ > **Testing with the FLP preview**: The `fiori-tools-preview` middleware supports `enhancedHomePage: true` (UI5 >= 1.123.0), which uses CDM-based bootstrap for a more complete UShell service layer. This is recommended for testing dirty-state provider integration, as it provides `ShellNavigationHashChanger` and `CrossApplicationNavigation` behavior closer to production FLP.
495
+
428
496
  See the [FLP Dirty State Research](../../docs/research/flp-dirty-state.md) for a detailed analysis of the FLP internals.
429
497
 
430
498
  ## Limitations
@@ -504,12 +572,12 @@ This follows the same pattern as [TanStack Router's `pendingComponent`](https://
504
572
  > [!IMPORTANT]
505
573
  > **Shipped UI5 baseline: 1.144.0**
506
574
  >
507
- > The published package declares `minUI5Version: 1.144.0`, and the full CI suite runs on that shipped baseline. In addition, CI runs the library QUnit suite against OpenUI5 `1.118.0` as a compatibility lane for the core router implementation. That extra lane does not change the published manifest baseline, but it provides a concrete verification signal for consumers evaluating older runtimes.
575
+ > The published package declares `minUI5Version: 1.144.0`, and the full CI suite runs on that shipped baseline. In addition, CI runs the library QUnit suite against OpenUI5 `1.120.0` as a compatibility lane for the core router implementation. The compatibility baseline is 1.120 because `DataType.registerEnum` (used for the `NavigationOutcome` enum) requires that version. That extra lane does not change the published manifest baseline, but it provides a concrete verification signal for consumers evaluating older runtimes.
508
576
 
509
577
  If you maintain an app on an older UI5 stack and want to validate locally, run the dedicated compatibility check from the monorepo root:
510
578
 
511
579
  ```bash
512
- npm run test:qunit:compat:118
580
+ npm run test:qunit:compat:120
513
581
  ```
514
582
 
515
583
  ## License
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "buildManifest": {
18
18
  "manifestVersion": "0.2",
19
- "timestamp": "2026-03-16T11:10:25.198Z",
19
+ "timestamp": "2026-03-17T12:41:14.778Z",
20
20
  "versions": {
21
21
  "builderVersion": "4.1.4",
22
22
  "projectVersion": "4.0.13",
@@ -31,7 +31,7 @@
31
31
  "includedTasks": [],
32
32
  "excludedTasks": []
33
33
  },
34
- "version": "1.1.1",
34
+ "version": "1.2.0",
35
35
  "namespace": "ui5/guard/router",
36
36
  "tags": {
37
37
  "/resources/ui5/guard/router/library-dbg.js": {
@@ -46,6 +46,18 @@
46
46
  "/resources/ui5/guard/router/library.js.map": {
47
47
  "ui5:HasDebugVariant": true
48
48
  },
49
+ "/resources/ui5/guard/router/NavigationOutcome-dbg.js": {
50
+ "ui5:IsDebugVariant": true
51
+ },
52
+ "/resources/ui5/guard/router/NavigationOutcome-dbg.js.map": {
53
+ "ui5:IsDebugVariant": true
54
+ },
55
+ "/resources/ui5/guard/router/NavigationOutcome.js": {
56
+ "ui5:HasDebugVariant": true
57
+ },
58
+ "/resources/ui5/guard/router/NavigationOutcome.js.map": {
59
+ "ui5:HasDebugVariant": true
60
+ },
49
61
  "/resources/ui5/guard/router/Router-dbg.js": {
50
62
  "ui5:IsDebugVariant": true
51
63
  },
package/dist/index.d.ts CHANGED
@@ -28,6 +28,7 @@
28
28
  // - @types/istanbul-lib-report@3.0.3
29
29
  // - @types/istanbul-lib-coverage@2.0.6
30
30
  // - @types/qunit@2.19.13
31
- /// <reference path="./resources/ui5/guard/router/types.d.ts"/>
31
+ /// <reference path="./resources/ui5/guard/router/Router.d.ts"/>
32
32
  /// <reference path="./resources/ui5/guard/router/library.d.ts"/>
33
- /// <reference path="./resources/ui5/guard/router/Router.d.ts"/>
33
+ /// <reference path="./resources/ui5/guard/router/NavigationOutcome.d.ts"/>
34
+ /// <reference path="./resources/ui5/guard/router/types.d.ts"/>
@@ -2,7 +2,7 @@
2
2
  <library xmlns="http://www.sap.com/sap.ui.library.xsd">
3
3
  <name>ui5.guard.router</name>
4
4
  <vendor>Marco</vendor>
5
- <version>1.1.1</version>
5
+ <version>1.2.0</version>
6
6
  <copyright></copyright>
7
7
  <title>UI5 Router extension with async navigation guards</title>
8
8
  <documentation>Extends sap.m.routing.Router with async navigation guards, running before route matching begins.</documentation>
@@ -0,0 +1,26 @@
1
+ sap.ui.define([], function () {
2
+ "use strict";
3
+
4
+ /**
5
+ * Outcome of a navigation after the guard pipeline settles.
6
+ *
7
+ * Registered as a UI5 enum via `library.ts` so that it is discoverable
8
+ * through `sap.ui.base.DataType.getType()`. Application code can import
9
+ * the value object directly.
10
+ *
11
+ * @enum {string}
12
+ * @namespace ui5.guard.router
13
+ */
14
+ const NavigationOutcome = Object.freeze({
15
+ /** Navigation was allowed and the target route activated. */
16
+ Committed: "committed",
17
+ /** A guard blocked navigation; the previous route remains active. */
18
+ Blocked: "blocked",
19
+ /** A guard redirected navigation to a different route. */
20
+ Redirected: "redirected",
21
+ /** Navigation was cancelled before settling (superseded, stopped, or destroyed). */
22
+ Cancelled: "cancelled"
23
+ });
24
+ return NavigationOutcome;
25
+ });
26
+ //# sourceMappingURL=NavigationOutcome-dbg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavigationOutcome-dbg.js","names":["NavigationOutcome","Object","freeze","Committed","Blocked","Redirected","Cancelled"],"sources":["NavigationOutcome.ts"],"sourcesContent":["/**\n * Outcome of a navigation after the guard pipeline settles.\n *\n * Registered as a UI5 enum via `library.ts` so that it is discoverable\n * through `sap.ui.base.DataType.getType()`. Application code can import\n * the value object directly.\n *\n * @enum {string}\n * @namespace ui5.guard.router\n */\nconst NavigationOutcome = Object.freeze({\n\t/** Navigation was allowed and the target route activated. */\n\tCommitted: \"committed\" as const,\n\t/** A guard blocked navigation; the previous route remains active. */\n\tBlocked: \"blocked\" as const,\n\t/** A guard redirected navigation to a different route. */\n\tRedirected: \"redirected\" as const,\n\t/** Navigation was cancelled before settling (superseded, stopped, or destroyed). */\n\tCancelled: \"cancelled\" as const,\n});\n\ntype NavigationOutcome = (typeof NavigationOutcome)[keyof typeof NavigationOutcome];\n\nexport default NavigationOutcome;\n"],"mappings":";;;EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACA,MAAMA,iBAAiB,GAAGC,MAAM,CAACC,MAAM,CAAC;IACvC;IACAC,SAAS,EAAE,WAAoB;IAC/B;IACAC,OAAO,EAAE,SAAkB;IAC3B;IACAC,UAAU,EAAE,YAAqB;IACjC;IACAC,SAAS,EAAE;EACZ,CAAC,CAAC;EAAC,OAIYN,iBAAiB;AAAA","ignoreList":[]}
@@ -0,0 +1,25 @@
1
+ declare module "ui5/guard/router/NavigationOutcome" {
2
+ /**
3
+ * Outcome of a navigation after the guard pipeline settles.
4
+ *
5
+ * Registered as a UI5 enum via `library.ts` so that it is discoverable
6
+ * through `sap.ui.base.DataType.getType()`. Application code can import
7
+ * the value object directly.
8
+ *
9
+ * @enum {string}
10
+ * @namespace ui5.guard.router
11
+ */
12
+ const NavigationOutcome: Readonly<{
13
+ /** Navigation was allowed and the target route activated. */
14
+ Committed: "committed";
15
+ /** A guard blocked navigation; the previous route remains active. */
16
+ Blocked: "blocked";
17
+ /** A guard redirected navigation to a different route. */
18
+ Redirected: "redirected";
19
+ /** Navigation was cancelled before settling (superseded, stopped, or destroyed). */
20
+ Cancelled: "cancelled";
21
+ }>;
22
+ type NavigationOutcome = (typeof NavigationOutcome)[keyof typeof NavigationOutcome];
23
+ export default NavigationOutcome;
24
+ }
25
+ //# sourceMappingURL=NavigationOutcome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavigationOutcome.d.ts","sourceRoot":"../../../../..","sources":["src/NavigationOutcome.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,oCAAoC,CAAC;IACpD;;;;;;;;;OASG;IACH,MAAM,iBAAiB;QACtB,6DAA6D;;QAE7D,qEAAqE;;QAErE,0DAA0D;;QAE1D,oFAAoF;;MAEnF,CAAC;IAEH,KAAK,iBAAiB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;IAEpF,eAAe,iBAAiB,CAAC;CAEhC"}
@@ -0,0 +1,2 @@
1
+ sap.ui.define([],function(){"use strict";const e=Object.freeze({Committed:"committed",Blocked:"blocked",Redirected:"redirected",Cancelled:"cancelled"});return e});
2
+ //# sourceMappingURL=NavigationOutcome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavigationOutcome.js","names":["NavigationOutcome","Object","freeze","Committed","Blocked","Redirected","Cancelled"],"sources":["NavigationOutcome.ts"],"sourcesContent":["/**\n * Outcome of a navigation after the guard pipeline settles.\n *\n * Registered as a UI5 enum via `library.ts` so that it is discoverable\n * through `sap.ui.base.DataType.getType()`. Application code can import\n * the value object directly.\n *\n * @enum {string}\n * @namespace ui5.guard.router\n */\nconst NavigationOutcome = Object.freeze({\n\t/** Navigation was allowed and the target route activated. */\n\tCommitted: \"committed\" as const,\n\t/** A guard blocked navigation; the previous route remains active. */\n\tBlocked: \"blocked\" as const,\n\t/** A guard redirected navigation to a different route. */\n\tRedirected: \"redirected\" as const,\n\t/** Navigation was cancelled before settling (superseded, stopped, or destroyed). */\n\tCancelled: \"cancelled\" as const,\n});\n\ntype NavigationOutcome = (typeof NavigationOutcome)[keyof typeof NavigationOutcome];\n\nexport default NavigationOutcome;\n"],"mappings":"yCAUA,MAAMA,EAAoBC,OAAOC,OAAO,CAEvCC,UAAW,YAEXC,QAAS,UAETC,WAAY,aAEZC,UAAW,cACT,OAIYN,CAAiB","ignoreList":[]}
@@ -1,6 +1,10 @@
1
- sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], function (MobileRouter, Log, coreLibrary) {
1
+ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library", "./NavigationOutcome"], function (MobileRouter, Log, coreLibrary, __NavigationOutcome) {
2
2
  "use strict";
3
3
 
4
+ function _interopRequireDefault(obj) {
5
+ return obj && obj.__esModule && typeof obj.default !== "undefined" ? obj.default : obj;
6
+ }
7
+ const NavigationOutcome = _interopRequireDefault(__NavigationOutcome);
4
8
  const HistoryDirection = coreLibrary.routing.HistoryDirection;
5
9
  const LOG_COMPONENT = "ui5.guard.router.Router";
6
10
  function isGuardRedirect(value) {
@@ -66,6 +70,8 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
66
70
  this._parseGeneration = 0;
67
71
  this._suppressedHash = null;
68
72
  this._abortController = null;
73
+ this._settlementResolvers = [];
74
+ this._lastSettlement = null;
69
75
  },
70
76
  /**
71
77
  * Register a global guard that runs for every navigation.
@@ -172,6 +178,37 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
172
178
  removeFromGuardMap(this._leaveGuards, routeName, guard);
173
179
  return this;
174
180
  },
181
+ /**
182
+ * Return a Promise that settles when the current guard pipeline finishes.
183
+ *
184
+ * If no navigation is pending, the Promise resolves immediately with the
185
+ * most recent settlement result (or `Committed` with the current state
186
+ * when no navigation has occurred yet). Otherwise it resolves once the
187
+ * pending navigation commits, blocks, redirects, or is cancelled.
188
+ */
189
+ navigationSettled: function _navigationSettled() {
190
+ if (this._pendingHash === null) {
191
+ return Promise.resolve(this._lastSettlement ?? {
192
+ status: NavigationOutcome.Committed,
193
+ route: this._currentRoute,
194
+ hash: this._currentHash ?? ""
195
+ });
196
+ }
197
+ return new Promise(resolve => {
198
+ this._settlementResolvers.push(resolve);
199
+ });
200
+ },
201
+ /**
202
+ * Drain all settlement resolvers with the given result.
203
+ */
204
+ _flushSettlement: function _flushSettlement(result) {
205
+ this._lastSettlement = result;
206
+ const resolvers = this._settlementResolvers;
207
+ this._settlementResolvers = [];
208
+ for (const resolve of resolvers) {
209
+ resolve(result);
210
+ }
211
+ },
175
212
  /**
176
213
  * Intercept hash changes and run the guard pipeline before route matching.
177
214
  *
@@ -294,6 +331,7 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
294
331
  this._suppressedHash = null;
295
332
  this._currentRoute = "";
296
333
  this._currentHash = null;
334
+ this._lastSettlement = null;
297
335
  MobileRouter.prototype.stop.call(this);
298
336
  return this;
299
337
  },
@@ -304,9 +342,16 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
304
342
  */
305
343
  _cancelPendingNavigation: function _cancelPendingNavigation() {
306
344
  ++this._parseGeneration;
307
- this._pendingHash = null;
308
345
  this._abortController?.abort();
309
346
  this._abortController = null;
347
+ if (this._pendingHash !== null) {
348
+ this._flushSettlement({
349
+ status: NavigationOutcome.Cancelled,
350
+ route: this._currentRoute,
351
+ hash: this._currentHash ?? ""
352
+ });
353
+ }
354
+ this._pendingHash = null;
310
355
  },
311
356
  /**
312
357
  * Run leave guards for the current route. Returns boolean (no redirects).
@@ -345,6 +390,11 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
345
390
  this._abortController = null;
346
391
  this._currentHash = hash;
347
392
  this._currentRoute = route ?? this.getRouteInfoByHash(hash)?.name ?? "";
393
+ this._flushSettlement({
394
+ status: this._redirecting ? NavigationOutcome.Redirected : NavigationOutcome.Committed,
395
+ route: this._currentRoute,
396
+ hash
397
+ });
348
398
  MobileRouter.prototype.parse.call(this, hash);
349
399
  },
350
400
  /** Run global guards, then route-specific guards. Stays sync when possible. */_runEnterGuards: function _runEnterGuards(globalGuards, toRoute, context) {
@@ -393,7 +443,7 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
393
443
  * determines what to return for non-true results: leave guards always
394
444
  * return `false`, enter guards validate and may return redirects.
395
445
  *
396
- * Note: `guards` is typed as `GuardFn[]` for reuse. Leave guard callers
446
+ * `guards` is typed as `GuardFn[]` for reuse. Leave guard callers
397
447
  * pass `LeaveGuardFn[]` which is assignable (narrower return type).
398
448
  *
399
449
  * @param isLeaveGuard - When true, error logs reference `fromRoute`; otherwise `toRoute`.
@@ -428,6 +478,7 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
428
478
  /** Perform a guard redirect (string route name or GuardRedirect object). */_redirect: function _redirect(target) {
429
479
  this._pendingHash = null;
430
480
  this._abortController = null;
481
+ const settlementBefore = this._lastSettlement;
431
482
  this._redirecting = true;
432
483
  try {
433
484
  if (typeof target === "string") {
@@ -438,10 +489,30 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
438
489
  } finally {
439
490
  this._redirecting = false;
440
491
  }
492
+
493
+ // Safety net: if navTo did not trigger a re-entrant parse() (e.g. the
494
+ // target route does not exist and the hash did not change), no
495
+ // _commitNavigation ran and _lastSettlement was not updated. Treat as
496
+ // blocked because the observable outcome is that the user stays on the
497
+ // current route. Log a warning so the developer sees the bad target.
498
+ if (this._lastSettlement === settlementBefore) {
499
+ const targetName = typeof target === "string" ? target : target.route;
500
+ Log.warning(`Guard redirect target "${targetName}" did not produce a navigation, treating as blocked`, undefined, LOG_COMPONENT);
501
+ this._flushSettlement({
502
+ status: NavigationOutcome.Blocked,
503
+ route: this._currentRoute,
504
+ hash: this._currentHash ?? ""
505
+ });
506
+ }
441
507
  },
442
508
  /** Clear pending state and restore the previous hash. */_blockNavigation: function _blockNavigation(attemptedHash) {
443
509
  this._pendingHash = null;
444
510
  this._abortController = null;
511
+ this._flushSettlement({
512
+ status: NavigationOutcome.Blocked,
513
+ route: this._currentRoute,
514
+ hash: this._currentHash ?? ""
515
+ });
445
516
  if (this._currentHash === null && attemptedHash && attemptedHash !== "") {
446
517
  this._restoreHash("", false);
447
518
  return;
@@ -451,8 +522,8 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
451
522
  /**
452
523
  * Restore the previous hash without creating a history entry.
453
524
  * Assumes replaceHash fires hashChanged synchronously (validated by test).
454
- * Note: _currentRoute intentionally stays unchanged. The blocked navigation
455
- * never committed, so the user remains on the same logical route.
525
+ * `_currentRoute` stays unchanged because the blocked navigation never
526
+ * committed. The user remains on the same logical route.
456
527
  */
457
528
  _restoreHash: function _restoreHash(hash, suppressParse = true) {
458
529
  const hashChanger = this.getHashChanger();
@@ -471,6 +542,7 @@ sap.ui.define(["sap/m/routing/Router", "sap/base/Log", "sap/ui/core/library"], f
471
542
  this._cancelPendingNavigation();
472
543
  this._redirecting = false;
473
544
  this._suppressedHash = null;
545
+ this._lastSettlement = null;
474
546
  MobileRouter.prototype.destroy.call(this);
475
547
  return this;
476
548
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Router-dbg.js","names":["HistoryDirection","coreLibrary","routing","LOG_COMPONENT","isGuardRedirect","value","route","length","isPromiseLike","then","isRouteGuardConfig","guard","addToGuardMap","map","key","guards","get","set","push","removeFromGuardMap","index","indexOf","splice","delete","Router","MobileRouter","extend","constructor","prototype","apply","arguments","_globalGuards","_enterGuards","Map","_leaveGuards","_currentRoute","_currentHash","_pendingHash","_redirecting","_parseGeneration","_suppressedHash","_abortController","addGuard","_addGuard","Log","warning","undefined","removeGuard","_removeGuard","addRouteGuard","_addRouteGuard","routeName","hasHandler","beforeEnter","beforeLeave","addLeaveGuard","info","removeRouteGuard","_removeRouteGuard","removeLeaveGuard","_addLeaveGuard","_removeLeaveGuard","parse","_parse","newHash","_commitNavigation","_cancelPendingNavigation","routeInfo","getRouteInfoByHash","toRoute","name","generation","hasLeaveGuards","has","hasEnterGuards","AbortController","context","toHash","toArguments","fromRoute","fromHash","signal","runEnterGuards","enterResult","_runEnterGuards","guardResult","debug","_blockNavigation","_redirect","catch","error","String","leaveResult","_runLeaveGuards","allowed","stop","_stop","MobileRouter.prototype.stop.call","abort","registered","slice","i","result","_continueGuardsAsync","hash","MobileRouter.prototype.parse.call","globalGuards","globalResult","_runGuards","aborted","_runRouteGuards","candidate","_validateGuardResult","pendingResult","currentIndex","onBlock","label","isLeaveGuard","guardIndex","nextResult","target","navTo","parameters","componentTargetInfo","attemptedHash","_restoreHash","suppressParse","hashChanger","getHashChanger","replaceHash","Unknown","destroy","_destroy","clear","MobileRouter.prototype.destroy.call"],"sources":["Router.ts"],"sourcesContent":["import MobileRouter from \"sap/m/routing/Router\";\nimport Log from \"sap/base/Log\";\nimport coreLibrary from \"sap/ui/core/library\";\nimport type {\n\tGuardFn,\n\tGuardContext,\n\tGuardResult,\n\tGuardRedirect,\n\tGuardRouter,\n\tLeaveGuardFn,\n\tRouteGuardConfig,\n} from \"./types\";\n\nconst HistoryDirection = coreLibrary.routing.HistoryDirection;\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isGuardRedirect(value: unknown): value is GuardRedirect {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst { route } = value as GuardRedirect;\n\treturn typeof route === \"string\" && route.length > 0;\n}\n\nfunction isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as PromiseLike<T>).then === \"function\";\n}\n\nfunction isRouteGuardConfig(guard: GuardFn | RouteGuardConfig): guard is RouteGuardConfig {\n\treturn typeof guard === \"object\" && guard !== null;\n}\n\nfunction addToGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\tlet guards = map.get(key);\n\tif (!guards) {\n\t\tguards = [];\n\t\tmap.set(key, guards);\n\t}\n\tguards.push(guard);\n}\n\nfunction removeFromGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\tconst guards = map.get(key);\n\tif (!guards) return;\n\tconst index = guards.indexOf(guard);\n\tif (index !== -1) guards.splice(index, 1);\n\tif (guards.length === 0) map.delete(key);\n}\n\n/**\n * Router with navigation guard support.\n *\n * Extends `sap.m.routing.Router` by overriding `parse()` to run\n * registered guard functions before any route matching, target loading,\n * or event firing occurs.\n *\n * Key assumptions (see docs/reference/architecture.md for full rationale):\n * - `parse()` is intentionally NOT async. Sync guards execute in the\n * same tick; async guards fall back to a deferred path.\n * - `replaceHash` fires `hashChanged` synchronously (validated by test).\n * - Redirect targets bypass guards to prevent infinite loops.\n *\n * @namespace ui5.guard.router\n * @extends sap.m.routing.Router\n */\nexport default class Router extends MobileRouter implements GuardRouter {\n\tprivate _globalGuards: GuardFn[] = [];\n\tprivate _enterGuards = new Map<string, GuardFn[]>();\n\tprivate _leaveGuards = new Map<string, LeaveGuardFn[]>();\n\tprivate _currentRoute = \"\";\n\tprivate _currentHash: string | null = null;\n\tprivate _pendingHash: string | null = null;\n\tprivate _redirecting = false;\n\tprivate _parseGeneration = 0;\n\tprivate _suppressedHash: string | null = null;\n\tprivate _abortController: AbortController | null = null;\n\n\t/**\n\t * Register a global guard that runs for every navigation.\n\t */\n\taddGuard(guard: GuardFn): this {\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"addGuard called with invalid guard, ignoring\", undefined, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tthis._globalGuards.push(guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a previously registered global guard.\n\t */\n\tremoveGuard(guard: GuardFn): this {\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"removeGuard called with invalid guard, ignoring\", undefined, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tconst index = this._globalGuards.indexOf(guard);\n\t\tif (index !== -1) {\n\t\t\tthis._globalGuards.splice(index, 1);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Register a guard for a specific route.\n\t *\n\t * Accepts either a guard function (registered as an enter guard) or a\n\t * configuration object with `beforeEnter` and/or `beforeLeave` guards.\n\t */\n\taddRouteGuard(routeName: string, guard: GuardFn | RouteGuardConfig): this {\n\t\tif (isRouteGuardConfig(guard)) {\n\t\t\tlet hasHandler = false;\n\n\t\t\tif (guard.beforeEnter !== undefined) {\n\t\t\t\thasHandler = true;\n\t\t\t\tthis.addRouteGuard(routeName, guard.beforeEnter);\n\t\t\t}\n\t\t\tif (guard.beforeLeave !== undefined) {\n\t\t\t\thasHandler = true;\n\t\t\t\tthis.addLeaveGuard(routeName, guard.beforeLeave);\n\t\t\t}\n\n\t\t\tif (!hasHandler) {\n\t\t\t\tLog.info(\n\t\t\t\t\t\"addRouteGuard called with config missing both beforeEnter and beforeLeave\",\n\t\t\t\t\trouteName,\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"addRouteGuard called with invalid guard, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\taddToGuardMap(this._enterGuards, routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a guard from a specific route.\n\t *\n\t * Accepts the same forms as `addRouteGuard`: a guard function removes\n\t * an enter guard; a configuration object removes `beforeEnter` and/or\n\t * `beforeLeave` by reference.\n\t */\n\tremoveRouteGuard(routeName: string, guard: GuardFn | RouteGuardConfig): this {\n\t\tif (isRouteGuardConfig(guard)) {\n\t\t\tif (typeof guard.beforeEnter === \"function\") {\n\t\t\t\tthis.removeRouteGuard(routeName, guard.beforeEnter);\n\t\t\t}\n\t\t\tif (typeof guard.beforeLeave === \"function\") {\n\t\t\t\tthis.removeLeaveGuard(routeName, guard.beforeLeave);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"removeRouteGuard called with invalid guard, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tremoveFromGuardMap(this._enterGuards, routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Leave guards run when navigating **away from** the route, before any\n\t * enter guards for the target route. They answer the binary question\n\t * \"can I leave?\" and return only a boolean (no redirects).\n\t */\n\taddLeaveGuard(routeName: string, guard: LeaveGuardFn): this {\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"addLeaveGuard called with invalid guard, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\taddToGuardMap(this._leaveGuards, routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a leave guard from a specific route.\n\t */\n\tremoveLeaveGuard(routeName: string, guard: LeaveGuardFn): this {\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"removeLeaveGuard called with invalid guard, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tremoveFromGuardMap(this._leaveGuards, routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Intercept hash changes and run the guard pipeline before route matching.\n\t *\n\t * Called by the HashChanger on every `hashChanged` event. Runs leave guards\n\t * (current route), then global + route-specific enter guards (target route).\n\t * Stays synchronous when all guards return plain values; falls back to async\n\t * when a guard returns a Promise. A generation counter discards stale results\n\t * when navigations overlap.\n\t *\n\t * @override sap.ui.core.routing.Router#parse\n\t */\n\toverride parse(newHash: string): void {\n\t\tif (this._suppressedHash !== null) {\n\t\t\tif (newHash === this._suppressedHash) {\n\t\t\t\tthis._suppressedHash = null;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._suppressedHash = null;\n\t\t}\n\n\t\tif (this._redirecting) {\n\t\t\tthis._commitNavigation(newHash);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._currentHash !== null && newHash === this._currentHash) {\n\t\t\tthis._cancelPendingNavigation();\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._pendingHash !== null && newHash === this._pendingHash) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst routeInfo = this.getRouteInfoByHash(newHash);\n\t\tconst toRoute = routeInfo?.name ?? \"\";\n\n\t\tthis._cancelPendingNavigation();\n\t\tconst generation = this._parseGeneration;\n\n\t\tthis._pendingHash = newHash;\n\n\t\tconst hasLeaveGuards = this._currentRoute !== \"\" && this._leaveGuards.has(this._currentRoute);\n\t\tconst hasEnterGuards = this._globalGuards.length > 0 || (toRoute !== \"\" && this._enterGuards.has(toRoute));\n\n\t\tif (!hasLeaveGuards && !hasEnterGuards) {\n\t\t\tthis._commitNavigation(newHash, toRoute);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._abortController = new AbortController();\n\n\t\tconst context: GuardContext = {\n\t\t\ttoRoute,\n\t\t\ttoHash: newHash,\n\t\t\ttoArguments: routeInfo?.arguments ?? {},\n\t\t\tfromRoute: this._currentRoute,\n\t\t\tfromHash: this._currentHash ?? \"\",\n\t\t\tsignal: this._abortController.signal,\n\t\t};\n\n\t\tconst runEnterGuards = (): void => {\n\t\t\tconst enterResult = this._runEnterGuards(this._globalGuards, toRoute, context);\n\n\t\t\tif (isPromiseLike(enterResult)) {\n\t\t\t\tenterResult\n\t\t\t\t\t.then((guardResult: GuardResult) => {\n\t\t\t\t\t\tif (generation !== this._parseGeneration) {\n\t\t\t\t\t\t\tLog.debug(\n\t\t\t\t\t\t\t\t\"Async enter guard result discarded (superseded by newer navigation)\",\n\t\t\t\t\t\t\t\tnewHash,\n\t\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (guardResult === true) {\n\t\t\t\t\t\t\tthis._commitNavigation(newHash, toRoute);\n\t\t\t\t\t\t} else if (guardResult === false) {\n\t\t\t\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._redirect(guardResult);\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t\tif (generation !== this._parseGeneration) return;\n\t\t\t\t\t\tLog.error(\n\t\t\t\t\t\t\t`Async enter guard for route \"${toRoute}\" failed, blocking navigation`,\n\t\t\t\t\t\t\tString(error),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (enterResult === true) {\n\t\t\t\tthis._commitNavigation(newHash, toRoute);\n\t\t\t} else if (enterResult === false) {\n\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t} else {\n\t\t\t\tthis._redirect(enterResult);\n\t\t\t}\n\t\t};\n\n\t\tif (hasLeaveGuards) {\n\t\t\tconst leaveResult = this._runLeaveGuards(context);\n\n\t\t\tif (isPromiseLike(leaveResult)) {\n\t\t\t\tleaveResult\n\t\t\t\t\t.then((allowed: boolean) => {\n\t\t\t\t\t\tif (generation !== this._parseGeneration) {\n\t\t\t\t\t\t\tLog.debug(\n\t\t\t\t\t\t\t\t\"Async leave guard result discarded (superseded by newer navigation)\",\n\t\t\t\t\t\t\t\tnewHash,\n\t\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (allowed !== true) {\n\t\t\t\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\trunEnterGuards();\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t\tif (generation !== this._parseGeneration) return;\n\t\t\t\t\t\tLog.error(\n\t\t\t\t\t\t\t`Async leave guard on route \"${this._currentRoute}\" failed, blocking navigation`,\n\t\t\t\t\t\t\tString(error),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (leaveResult !== true) {\n\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\trunEnterGuards();\n\t}\n\n\t/**\n\t * Stop listening to hash changes and reset guard state.\n\t *\n\t * Resets `_currentRoute` and `_currentHash` so that a subsequent\n\t * `initialize()` re-parses the current hash and fires `routeMatched`,\n\t * matching the native `sap.m.routing.Router` behavior.\n\t *\n\t * @override sap.ui.core.routing.Router#stop\n\t */\n\toverride stop(): this {\n\t\tthis._cancelPendingNavigation();\n\t\tthis._redirecting = false;\n\t\tthis._suppressedHash = null;\n\t\tthis._currentRoute = \"\";\n\t\tthis._currentHash = null;\n\t\tsuper.stop();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Invalidate any in-flight async guard work. Bumps the generation counter\n\t * so pending `.then()` callbacks see they are stale, aborts the signal,\n\t * and clears the pending hash.\n\t */\n\tprivate _cancelPendingNavigation(): void {\n\t\t++this._parseGeneration;\n\t\tthis._pendingHash = null;\n\t\tthis._abortController?.abort();\n\t\tthis._abortController = null;\n\t}\n\n\t/**\n\t * Run leave guards for the current route. Returns boolean (no redirects).\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runLeaveGuards(context: GuardContext): boolean | Promise<boolean> {\n\t\tconst registered = this._leaveGuards.get(this._currentRoute);\n\t\tif (!registered || registered.length === 0) return true;\n\n\t\tconst guards = registered.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t() => false,\n\t\t\t\t\t\t\"Leave guard\",\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t) as Promise<boolean>;\n\t\t\t\t}\n\t\t\t\tif (result !== true) return false;\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Leave guard [${i}] on route \"${this._currentRoute}\" threw, blocking navigation`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Delegate to the parent router and update internal state.\n\t *\n\t * State is updated BEFORE calling parse to ensure that if event handlers\n\t * (e.g., routeMatched) trigger nested navigation, the leave guards will\n\t * run for the correct (new) route rather than the old one.\n\t */\n\tprivate _commitNavigation(hash: string, route?: string): void {\n\t\tthis._pendingHash = null;\n\t\tthis._abortController = null;\n\t\tthis._currentHash = hash;\n\t\tthis._currentRoute = route ?? this.getRouteInfoByHash(hash)?.name ?? \"\";\n\t\tsuper.parse(hash);\n\t}\n\n\t/** Run global guards, then route-specific guards. Stays sync when possible. */\n\tprivate _runEnterGuards(\n\t\tglobalGuards: GuardFn[],\n\t\ttoRoute: string,\n\t\tcontext: GuardContext,\n\t): GuardResult | Promise<GuardResult> {\n\t\tconst globalResult = this._runGuards(globalGuards, context);\n\n\t\tif (isPromiseLike(globalResult)) {\n\t\t\treturn globalResult.then((result: GuardResult) => {\n\t\t\t\tif (result !== true) return result;\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\treturn this._runRouteGuards(toRoute, context);\n\t\t\t});\n\t\t}\n\t\tif (globalResult !== true) return globalResult;\n\t\treturn this._runRouteGuards(toRoute, context);\n\t}\n\n\t/** Run route-specific guards if any are registered. */\n\tprivate _runRouteGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tif (!toRoute || !this._enterGuards.has(toRoute)) return true;\n\t\treturn this._runGuards(this._enterGuards.get(toRoute)!, context);\n\t}\n\n\t/**\n\t * Run guards sync; switch to async path if a Promise is returned.\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runGuards(guards: GuardFn[], context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tguards = guards.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateGuardResult(candidate),\n\t\t\t\t\t\t\"Enter guard\",\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Enter guard [${i}] for route \"${context.toRoute}\" threw, blocking navigation`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Continue guard array async from the first Promise onward.\n\t *\n\t * Shared by both enter and leave guard pipelines. The `onBlock` callback\n\t * determines what to return for non-true results: leave guards always\n\t * return `false`, enter guards validate and may return redirects.\n\t *\n\t * Note: `guards` is typed as `GuardFn[]` for reuse. Leave guard callers\n\t * pass `LeaveGuardFn[]` which is assignable (narrower return type).\n\t *\n\t * @param isLeaveGuard - When true, error logs reference `fromRoute`; otherwise `toRoute`.\n\t */\n\tprivate async _continueGuardsAsync(\n\t\tpendingResult: PromiseLike<GuardResult>,\n\t\tguards: GuardFn[],\n\t\tcurrentIndex: number,\n\t\tcontext: GuardContext,\n\t\tonBlock: (result: unknown) => GuardResult,\n\t\tlabel: string,\n\t\tisLeaveGuard: boolean,\n\t): Promise<GuardResult> {\n\t\tlet guardIndex = currentIndex;\n\t\ttry {\n\t\t\tconst result = await pendingResult;\n\t\t\tif (result !== true) return onBlock(result);\n\n\t\t\tfor (let i = currentIndex + 1; i < guards.length; i++) {\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tguardIndex = i;\n\t\t\t\tconst nextResult = await guards[i](context);\n\t\t\t\tif (nextResult !== true) return onBlock(nextResult);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (!context.signal.aborted) {\n\t\t\t\tconst route = isLeaveGuard ? context.fromRoute : context.toRoute;\n\t\t\t\tLog.error(\n\t\t\t\t\t`${label} [${guardIndex}] on route \"${route}\" threw, blocking navigation`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Validate a non-true guard result; invalid values become false. */\n\tprivate _validateGuardResult(result: unknown): GuardResult {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tif (typeof result === \"string\" && result.length > 0) return result;\n\t\tif (isGuardRedirect(result)) return result;\n\t\tLog.warning(\"Guard returned invalid value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/** Perform a guard redirect (string route name or GuardRedirect object). */\n\tprivate _redirect(target: string | GuardRedirect): void {\n\t\tthis._pendingHash = null;\n\t\tthis._abortController = null;\n\t\tthis._redirecting = true;\n\t\ttry {\n\t\t\tif (typeof target === \"string\") {\n\t\t\t\tthis.navTo(target, {}, {}, true);\n\t\t\t} else {\n\t\t\t\tthis.navTo(target.route, target.parameters ?? {}, target.componentTargetInfo, true);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis._redirecting = false;\n\t\t}\n\t}\n\n\t/** Clear pending state and restore the previous hash. */\n\tprivate _blockNavigation(attemptedHash?: string): void {\n\t\tthis._pendingHash = null;\n\t\tthis._abortController = null;\n\t\tif (this._currentHash === null && attemptedHash && attemptedHash !== \"\") {\n\t\t\tthis._restoreHash(\"\", false);\n\t\t\treturn;\n\t\t}\n\t\tthis._restoreHash(this._currentHash ?? \"\");\n\t}\n\n\t/**\n\t * Restore the previous hash without creating a history entry.\n\t * Assumes replaceHash fires hashChanged synchronously (validated by test).\n\t * Note: _currentRoute intentionally stays unchanged. The blocked navigation\n\t * never committed, so the user remains on the same logical route.\n\t */\n\tprivate _restoreHash(hash: string, suppressParse = true): void {\n\t\tconst hashChanger = this.getHashChanger();\n\t\tif (hashChanger) {\n\t\t\tthis._suppressedHash = suppressParse ? hash : null;\n\t\t\thashChanger.replaceHash(hash, HistoryDirection.Unknown);\n\t\t\tif (this._suppressedHash === hash) {\n\t\t\t\tthis._suppressedHash = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Clean up guards on destroy. Bumps generation to discard pending async results. */\n\toverride destroy(): this {\n\t\tthis._globalGuards = [];\n\t\tthis._enterGuards.clear();\n\t\tthis._leaveGuards.clear();\n\t\tthis._cancelPendingNavigation();\n\t\tthis._redirecting = false;\n\t\tthis._suppressedHash = null;\n\t\tsuper.destroy();\n\t\treturn this;\n\t}\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"Router-dbg.js","names":["NavigationOutcome","_interopRequireDefault","__NavigationOutcome","HistoryDirection","coreLibrary","routing","LOG_COMPONENT","isGuardRedirect","value","route","length","isPromiseLike","then","isRouteGuardConfig","guard","addToGuardMap","map","key","guards","get","set","push","removeFromGuardMap","index","indexOf","splice","delete","Router","MobileRouter","extend","constructor","prototype","apply","arguments","_globalGuards","_enterGuards","Map","_leaveGuards","_currentRoute","_currentHash","_pendingHash","_redirecting","_parseGeneration","_suppressedHash","_abortController","_settlementResolvers","_lastSettlement","addGuard","_addGuard","Log","warning","undefined","removeGuard","_removeGuard","addRouteGuard","_addRouteGuard","routeName","hasHandler","beforeEnter","beforeLeave","addLeaveGuard","info","removeRouteGuard","_removeRouteGuard","removeLeaveGuard","_addLeaveGuard","_removeLeaveGuard","navigationSettled","_navigationSettled","Promise","resolve","status","Committed","hash","_flushSettlement","result","resolvers","parse","_parse","newHash","_commitNavigation","_cancelPendingNavigation","routeInfo","getRouteInfoByHash","toRoute","name","generation","hasLeaveGuards","has","hasEnterGuards","AbortController","context","toHash","toArguments","fromRoute","fromHash","signal","runEnterGuards","enterResult","_runEnterGuards","guardResult","debug","_blockNavigation","_redirect","catch","error","String","leaveResult","_runLeaveGuards","allowed","stop","_stop","MobileRouter.prototype.stop.call","abort","Cancelled","registered","slice","i","_continueGuardsAsync","Redirected","MobileRouter.prototype.parse.call","globalGuards","globalResult","_runGuards","aborted","_runRouteGuards","candidate","_validateGuardResult","pendingResult","currentIndex","onBlock","label","isLeaveGuard","guardIndex","nextResult","target","settlementBefore","navTo","parameters","componentTargetInfo","targetName","Blocked","attemptedHash","_restoreHash","suppressParse","hashChanger","getHashChanger","replaceHash","Unknown","destroy","_destroy","clear","MobileRouter.prototype.destroy.call"],"sources":["Router.ts"],"sourcesContent":["import MobileRouter from \"sap/m/routing/Router\";\nimport Log from \"sap/base/Log\";\nimport coreLibrary from \"sap/ui/core/library\";\nimport type {\n\tGuardFn,\n\tGuardContext,\n\tGuardResult,\n\tGuardRedirect,\n\tGuardRouter,\n\tLeaveGuardFn,\n\tNavigationResult,\n\tRouteGuardConfig,\n} from \"./types\";\nimport NavigationOutcome from \"./NavigationOutcome\";\n\nconst HistoryDirection = coreLibrary.routing.HistoryDirection;\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isGuardRedirect(value: unknown): value is GuardRedirect {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst { route } = value as GuardRedirect;\n\treturn typeof route === \"string\" && route.length > 0;\n}\n\nfunction isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as PromiseLike<T>).then === \"function\";\n}\n\nfunction isRouteGuardConfig(guard: GuardFn | RouteGuardConfig): guard is RouteGuardConfig {\n\treturn typeof guard === \"object\" && guard !== null;\n}\n\nfunction addToGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\tlet guards = map.get(key);\n\tif (!guards) {\n\t\tguards = [];\n\t\tmap.set(key, guards);\n\t}\n\tguards.push(guard);\n}\n\nfunction removeFromGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\tconst guards = map.get(key);\n\tif (!guards) return;\n\tconst index = guards.indexOf(guard);\n\tif (index !== -1) guards.splice(index, 1);\n\tif (guards.length === 0) map.delete(key);\n}\n\n/**\n * Router with navigation guard support.\n *\n * Extends `sap.m.routing.Router` by overriding `parse()` to run\n * registered guard functions before any route matching, target loading,\n * or event firing occurs.\n *\n * Key assumptions (see docs/reference/architecture.md for full rationale):\n * - `parse()` is intentionally NOT async. Sync guards execute in the\n * same tick; async guards fall back to a deferred path.\n * - `replaceHash` fires `hashChanged` synchronously (validated by test).\n * - Redirect targets bypass guards to prevent infinite loops.\n *\n * @namespace ui5.guard.router\n * @extends sap.m.routing.Router\n */\nexport default class Router extends MobileRouter implements GuardRouter {\n\tprivate _globalGuards: GuardFn[] = [];\n\tprivate _enterGuards = new Map<string, GuardFn[]>();\n\tprivate _leaveGuards = new Map<string, LeaveGuardFn[]>();\n\tprivate _currentRoute = \"\";\n\tprivate _currentHash: string | null = null;\n\tprivate _pendingHash: string | null = null;\n\tprivate _redirecting = false;\n\tprivate _parseGeneration = 0;\n\tprivate _suppressedHash: string | null = null;\n\tprivate _abortController: AbortController | null = null;\n\tprivate _settlementResolvers: ((result: NavigationResult) => void)[] = [];\n\tprivate _lastSettlement: NavigationResult | null = null;\n\n\t/**\n\t * Register a global guard that runs for every navigation.\n\t */\n\taddGuard(guard: GuardFn): this {\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"addGuard called with invalid guard, ignoring\", undefined, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tthis._globalGuards.push(guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a previously registered global guard.\n\t */\n\tremoveGuard(guard: GuardFn): this {\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"removeGuard called with invalid guard, ignoring\", undefined, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tconst index = this._globalGuards.indexOf(guard);\n\t\tif (index !== -1) {\n\t\t\tthis._globalGuards.splice(index, 1);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Register a guard for a specific route.\n\t *\n\t * Accepts either a guard function (registered as an enter guard) or a\n\t * configuration object with `beforeEnter` and/or `beforeLeave` guards.\n\t */\n\taddRouteGuard(routeName: string, guard: GuardFn | RouteGuardConfig): this {\n\t\tif (isRouteGuardConfig(guard)) {\n\t\t\tlet hasHandler = false;\n\n\t\t\tif (guard.beforeEnter !== undefined) {\n\t\t\t\thasHandler = true;\n\t\t\t\tthis.addRouteGuard(routeName, guard.beforeEnter);\n\t\t\t}\n\t\t\tif (guard.beforeLeave !== undefined) {\n\t\t\t\thasHandler = true;\n\t\t\t\tthis.addLeaveGuard(routeName, guard.beforeLeave);\n\t\t\t}\n\n\t\t\tif (!hasHandler) {\n\t\t\t\tLog.info(\n\t\t\t\t\t\"addRouteGuard called with config missing both beforeEnter and beforeLeave\",\n\t\t\t\t\trouteName,\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"addRouteGuard called with invalid guard, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\taddToGuardMap(this._enterGuards, routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a guard from a specific route.\n\t *\n\t * Accepts the same forms as `addRouteGuard`: a guard function removes\n\t * an enter guard; a configuration object removes `beforeEnter` and/or\n\t * `beforeLeave` by reference.\n\t */\n\tremoveRouteGuard(routeName: string, guard: GuardFn | RouteGuardConfig): this {\n\t\tif (isRouteGuardConfig(guard)) {\n\t\t\tif (typeof guard.beforeEnter === \"function\") {\n\t\t\t\tthis.removeRouteGuard(routeName, guard.beforeEnter);\n\t\t\t}\n\t\t\tif (typeof guard.beforeLeave === \"function\") {\n\t\t\t\tthis.removeLeaveGuard(routeName, guard.beforeLeave);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"removeRouteGuard called with invalid guard, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tremoveFromGuardMap(this._enterGuards, routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Leave guards run when navigating **away from** the route, before any\n\t * enter guards for the target route. They answer the binary question\n\t * \"can I leave?\" and return only a boolean (no redirects).\n\t */\n\taddLeaveGuard(routeName: string, guard: LeaveGuardFn): this {\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"addLeaveGuard called with invalid guard, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\taddToGuardMap(this._leaveGuards, routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a leave guard from a specific route.\n\t */\n\tremoveLeaveGuard(routeName: string, guard: LeaveGuardFn): this {\n\t\tif (typeof guard !== \"function\") {\n\t\t\tLog.warning(\"removeLeaveGuard called with invalid guard, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tremoveFromGuardMap(this._leaveGuards, routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Return a Promise that settles when the current guard pipeline finishes.\n\t *\n\t * If no navigation is pending, the Promise resolves immediately with the\n\t * most recent settlement result (or `Committed` with the current state\n\t * when no navigation has occurred yet). Otherwise it resolves once the\n\t * pending navigation commits, blocks, redirects, or is cancelled.\n\t */\n\tnavigationSettled(): Promise<NavigationResult> {\n\t\tif (this._pendingHash === null) {\n\t\t\treturn Promise.resolve(\n\t\t\t\tthis._lastSettlement ?? {\n\t\t\t\t\tstatus: NavigationOutcome.Committed,\n\t\t\t\t\troute: this._currentRoute,\n\t\t\t\t\thash: this._currentHash ?? \"\",\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._settlementResolvers.push(resolve);\n\t\t});\n\t}\n\n\t/**\n\t * Drain all settlement resolvers with the given result.\n\t */\n\tprivate _flushSettlement(result: NavigationResult): void {\n\t\tthis._lastSettlement = result;\n\t\tconst resolvers = this._settlementResolvers;\n\t\tthis._settlementResolvers = [];\n\t\tfor (const resolve of resolvers) {\n\t\t\tresolve(result);\n\t\t}\n\t}\n\n\t/**\n\t * Intercept hash changes and run the guard pipeline before route matching.\n\t *\n\t * Called by the HashChanger on every `hashChanged` event. Runs leave guards\n\t * (current route), then global + route-specific enter guards (target route).\n\t * Stays synchronous when all guards return plain values; falls back to async\n\t * when a guard returns a Promise. A generation counter discards stale results\n\t * when navigations overlap.\n\t *\n\t * @override sap.ui.core.routing.Router#parse\n\t */\n\toverride parse(newHash: string): void {\n\t\tif (this._suppressedHash !== null) {\n\t\t\tif (newHash === this._suppressedHash) {\n\t\t\t\tthis._suppressedHash = null;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._suppressedHash = null;\n\t\t}\n\n\t\tif (this._redirecting) {\n\t\t\tthis._commitNavigation(newHash);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._currentHash !== null && newHash === this._currentHash) {\n\t\t\tthis._cancelPendingNavigation();\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._pendingHash !== null && newHash === this._pendingHash) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst routeInfo = this.getRouteInfoByHash(newHash);\n\t\tconst toRoute = routeInfo?.name ?? \"\";\n\n\t\tthis._cancelPendingNavigation();\n\t\tconst generation = this._parseGeneration;\n\n\t\tthis._pendingHash = newHash;\n\n\t\tconst hasLeaveGuards = this._currentRoute !== \"\" && this._leaveGuards.has(this._currentRoute);\n\t\tconst hasEnterGuards = this._globalGuards.length > 0 || (toRoute !== \"\" && this._enterGuards.has(toRoute));\n\n\t\tif (!hasLeaveGuards && !hasEnterGuards) {\n\t\t\tthis._commitNavigation(newHash, toRoute);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._abortController = new AbortController();\n\n\t\tconst context: GuardContext = {\n\t\t\ttoRoute,\n\t\t\ttoHash: newHash,\n\t\t\ttoArguments: routeInfo?.arguments ?? {},\n\t\t\tfromRoute: this._currentRoute,\n\t\t\tfromHash: this._currentHash ?? \"\",\n\t\t\tsignal: this._abortController.signal,\n\t\t};\n\n\t\tconst runEnterGuards = (): void => {\n\t\t\tconst enterResult = this._runEnterGuards(this._globalGuards, toRoute, context);\n\n\t\t\tif (isPromiseLike(enterResult)) {\n\t\t\t\tenterResult\n\t\t\t\t\t.then((guardResult: GuardResult) => {\n\t\t\t\t\t\tif (generation !== this._parseGeneration) {\n\t\t\t\t\t\t\tLog.debug(\n\t\t\t\t\t\t\t\t\"Async enter guard result discarded (superseded by newer navigation)\",\n\t\t\t\t\t\t\t\tnewHash,\n\t\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (guardResult === true) {\n\t\t\t\t\t\t\tthis._commitNavigation(newHash, toRoute);\n\t\t\t\t\t\t} else if (guardResult === false) {\n\t\t\t\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._redirect(guardResult);\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t\tif (generation !== this._parseGeneration) return;\n\t\t\t\t\t\tLog.error(\n\t\t\t\t\t\t\t`Async enter guard for route \"${toRoute}\" failed, blocking navigation`,\n\t\t\t\t\t\t\tString(error),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (enterResult === true) {\n\t\t\t\tthis._commitNavigation(newHash, toRoute);\n\t\t\t} else if (enterResult === false) {\n\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t} else {\n\t\t\t\tthis._redirect(enterResult);\n\t\t\t}\n\t\t};\n\n\t\tif (hasLeaveGuards) {\n\t\t\tconst leaveResult = this._runLeaveGuards(context);\n\n\t\t\tif (isPromiseLike(leaveResult)) {\n\t\t\t\tleaveResult\n\t\t\t\t\t.then((allowed: boolean) => {\n\t\t\t\t\t\tif (generation !== this._parseGeneration) {\n\t\t\t\t\t\t\tLog.debug(\n\t\t\t\t\t\t\t\t\"Async leave guard result discarded (superseded by newer navigation)\",\n\t\t\t\t\t\t\t\tnewHash,\n\t\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (allowed !== true) {\n\t\t\t\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\trunEnterGuards();\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t\tif (generation !== this._parseGeneration) return;\n\t\t\t\t\t\tLog.error(\n\t\t\t\t\t\t\t`Async leave guard on route \"${this._currentRoute}\" failed, blocking navigation`,\n\t\t\t\t\t\t\tString(error),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (leaveResult !== true) {\n\t\t\t\tthis._blockNavigation(newHash);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\trunEnterGuards();\n\t}\n\n\t/**\n\t * Stop listening to hash changes and reset guard state.\n\t *\n\t * Resets `_currentRoute` and `_currentHash` so that a subsequent\n\t * `initialize()` re-parses the current hash and fires `routeMatched`,\n\t * matching the native `sap.m.routing.Router` behavior.\n\t *\n\t * @override sap.ui.core.routing.Router#stop\n\t */\n\toverride stop(): this {\n\t\tthis._cancelPendingNavigation();\n\t\tthis._redirecting = false;\n\t\tthis._suppressedHash = null;\n\t\tthis._currentRoute = \"\";\n\t\tthis._currentHash = null;\n\t\tthis._lastSettlement = null;\n\t\tsuper.stop();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Invalidate any in-flight async guard work. Bumps the generation counter\n\t * so pending `.then()` callbacks see they are stale, aborts the signal,\n\t * and clears the pending hash.\n\t */\n\tprivate _cancelPendingNavigation(): void {\n\t\t++this._parseGeneration;\n\t\tthis._abortController?.abort();\n\t\tthis._abortController = null;\n\t\tif (this._pendingHash !== null) {\n\t\t\tthis._flushSettlement({\n\t\t\t\tstatus: NavigationOutcome.Cancelled,\n\t\t\t\troute: this._currentRoute,\n\t\t\t\thash: this._currentHash ?? \"\",\n\t\t\t});\n\t\t}\n\t\tthis._pendingHash = null;\n\t}\n\n\t/**\n\t * Run leave guards for the current route. Returns boolean (no redirects).\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runLeaveGuards(context: GuardContext): boolean | Promise<boolean> {\n\t\tconst registered = this._leaveGuards.get(this._currentRoute);\n\t\tif (!registered || registered.length === 0) return true;\n\n\t\tconst guards = registered.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t() => false,\n\t\t\t\t\t\t\"Leave guard\",\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t) as Promise<boolean>;\n\t\t\t\t}\n\t\t\t\tif (result !== true) return false;\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Leave guard [${i}] on route \"${this._currentRoute}\" threw, blocking navigation`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Delegate to the parent router and update internal state.\n\t *\n\t * State is updated BEFORE calling parse to ensure that if event handlers\n\t * (e.g., routeMatched) trigger nested navigation, the leave guards will\n\t * run for the correct (new) route rather than the old one.\n\t */\n\tprivate _commitNavigation(hash: string, route?: string): void {\n\t\tthis._pendingHash = null;\n\t\tthis._abortController = null;\n\t\tthis._currentHash = hash;\n\t\tthis._currentRoute = route ?? this.getRouteInfoByHash(hash)?.name ?? \"\";\n\t\tthis._flushSettlement({\n\t\t\tstatus: this._redirecting ? NavigationOutcome.Redirected : NavigationOutcome.Committed,\n\t\t\troute: this._currentRoute,\n\t\t\thash,\n\t\t});\n\t\tsuper.parse(hash);\n\t}\n\n\t/** Run global guards, then route-specific guards. Stays sync when possible. */\n\tprivate _runEnterGuards(\n\t\tglobalGuards: GuardFn[],\n\t\ttoRoute: string,\n\t\tcontext: GuardContext,\n\t): GuardResult | Promise<GuardResult> {\n\t\tconst globalResult = this._runGuards(globalGuards, context);\n\n\t\tif (isPromiseLike(globalResult)) {\n\t\t\treturn globalResult.then((result: GuardResult) => {\n\t\t\t\tif (result !== true) return result;\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\treturn this._runRouteGuards(toRoute, context);\n\t\t\t});\n\t\t}\n\t\tif (globalResult !== true) return globalResult;\n\t\treturn this._runRouteGuards(toRoute, context);\n\t}\n\n\t/** Run route-specific guards if any are registered. */\n\tprivate _runRouteGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tif (!toRoute || !this._enterGuards.has(toRoute)) return true;\n\t\treturn this._runGuards(this._enterGuards.get(toRoute)!, context);\n\t}\n\n\t/**\n\t * Run guards sync; switch to async path if a Promise is returned.\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runGuards(guards: GuardFn[], context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tguards = guards.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateGuardResult(candidate),\n\t\t\t\t\t\t\"Enter guard\",\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Enter guard [${i}] for route \"${context.toRoute}\" threw, blocking navigation`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Continue guard array async from the first Promise onward.\n\t *\n\t * Shared by both enter and leave guard pipelines. The `onBlock` callback\n\t * determines what to return for non-true results: leave guards always\n\t * return `false`, enter guards validate and may return redirects.\n\t *\n\t * `guards` is typed as `GuardFn[]` for reuse. Leave guard callers\n\t * pass `LeaveGuardFn[]` which is assignable (narrower return type).\n\t *\n\t * @param isLeaveGuard - When true, error logs reference `fromRoute`; otherwise `toRoute`.\n\t */\n\tprivate async _continueGuardsAsync(\n\t\tpendingResult: PromiseLike<GuardResult>,\n\t\tguards: GuardFn[],\n\t\tcurrentIndex: number,\n\t\tcontext: GuardContext,\n\t\tonBlock: (result: unknown) => GuardResult,\n\t\tlabel: string,\n\t\tisLeaveGuard: boolean,\n\t): Promise<GuardResult> {\n\t\tlet guardIndex = currentIndex;\n\t\ttry {\n\t\t\tconst result = await pendingResult;\n\t\t\tif (result !== true) return onBlock(result);\n\n\t\t\tfor (let i = currentIndex + 1; i < guards.length; i++) {\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tguardIndex = i;\n\t\t\t\tconst nextResult = await guards[i](context);\n\t\t\t\tif (nextResult !== true) return onBlock(nextResult);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (!context.signal.aborted) {\n\t\t\t\tconst route = isLeaveGuard ? context.fromRoute : context.toRoute;\n\t\t\t\tLog.error(\n\t\t\t\t\t`${label} [${guardIndex}] on route \"${route}\" threw, blocking navigation`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Validate a non-true guard result; invalid values become false. */\n\tprivate _validateGuardResult(result: unknown): GuardResult {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tif (typeof result === \"string\" && result.length > 0) return result;\n\t\tif (isGuardRedirect(result)) return result;\n\t\tLog.warning(\"Guard returned invalid value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/** Perform a guard redirect (string route name or GuardRedirect object). */\n\tprivate _redirect(target: string | GuardRedirect): void {\n\t\tthis._pendingHash = null;\n\t\tthis._abortController = null;\n\t\tconst settlementBefore = this._lastSettlement;\n\t\tthis._redirecting = true;\n\t\ttry {\n\t\t\tif (typeof target === \"string\") {\n\t\t\t\tthis.navTo(target, {}, {}, true);\n\t\t\t} else {\n\t\t\t\tthis.navTo(target.route, target.parameters ?? {}, target.componentTargetInfo, true);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis._redirecting = false;\n\t\t}\n\n\t\t// Safety net: if navTo did not trigger a re-entrant parse() (e.g. the\n\t\t// target route does not exist and the hash did not change), no\n\t\t// _commitNavigation ran and _lastSettlement was not updated. Treat as\n\t\t// blocked because the observable outcome is that the user stays on the\n\t\t// current route. Log a warning so the developer sees the bad target.\n\t\tif (this._lastSettlement === settlementBefore) {\n\t\t\tconst targetName = typeof target === \"string\" ? target : target.route;\n\t\t\tLog.warning(\n\t\t\t\t`Guard redirect target \"${targetName}\" did not produce a navigation, treating as blocked`,\n\t\t\t\tundefined,\n\t\t\t\tLOG_COMPONENT,\n\t\t\t);\n\t\t\tthis._flushSettlement({\n\t\t\t\tstatus: NavigationOutcome.Blocked,\n\t\t\t\troute: this._currentRoute,\n\t\t\t\thash: this._currentHash ?? \"\",\n\t\t\t});\n\t\t}\n\t}\n\n\t/** Clear pending state and restore the previous hash. */\n\tprivate _blockNavigation(attemptedHash?: string): void {\n\t\tthis._pendingHash = null;\n\t\tthis._abortController = null;\n\t\tthis._flushSettlement({\n\t\t\tstatus: NavigationOutcome.Blocked,\n\t\t\troute: this._currentRoute,\n\t\t\thash: this._currentHash ?? \"\",\n\t\t});\n\t\tif (this._currentHash === null && attemptedHash && attemptedHash !== \"\") {\n\t\t\tthis._restoreHash(\"\", false);\n\t\t\treturn;\n\t\t}\n\t\tthis._restoreHash(this._currentHash ?? \"\");\n\t}\n\n\t/**\n\t * Restore the previous hash without creating a history entry.\n\t * Assumes replaceHash fires hashChanged synchronously (validated by test).\n\t * `_currentRoute` stays unchanged because the blocked navigation never\n\t * committed. The user remains on the same logical route.\n\t */\n\tprivate _restoreHash(hash: string, suppressParse = true): void {\n\t\tconst hashChanger = this.getHashChanger();\n\t\tif (hashChanger) {\n\t\t\tthis._suppressedHash = suppressParse ? hash : null;\n\t\t\thashChanger.replaceHash(hash, HistoryDirection.Unknown);\n\t\t\tif (this._suppressedHash === hash) {\n\t\t\t\tthis._suppressedHash = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Clean up guards on destroy. Bumps generation to discard pending async results. */\n\toverride destroy(): this {\n\t\tthis._globalGuards = [];\n\t\tthis._enterGuards.clear();\n\t\tthis._leaveGuards.clear();\n\t\tthis._cancelPendingNavigation();\n\t\tthis._redirecting = false;\n\t\tthis._suppressedHash = null;\n\t\tthis._lastSettlement = null;\n\t\tsuper.destroy();\n\t\treturn this;\n\t}\n}\n"],"mappings":"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","ignoreList":[]}