From f2ffbe31b036ee67e9c38d2a80466274d281ac5d Mon Sep 17 00:00:00 2001 From: SkyZeroZx <73321943+SkyZeroZx@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:41:48 -0500 Subject: [PATCH] refactor(devtools): enhance route guard handling and add inline function warning refactored route guard handling and added warning for inline functions --- .../src/lib/router-tree.spec.ts | 100 ++++++++++++++++++ .../src/lib/router-tree.ts | 8 +- .../router-tree/router-tree.component.ts | 6 ++ 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/devtools/projects/ng-devtools-backend/src/lib/router-tree.spec.ts b/devtools/projects/ng-devtools-backend/src/lib/router-tree.spec.ts index c76e64a5e12..5c6e6a3b078 100644 --- a/devtools/projects/ng-devtools-backend/src/lib/router-tree.spec.ts +++ b/devtools/projects/ng-devtools-backend/src/lib/router-tree.spec.ts @@ -241,4 +241,104 @@ describe('parseRoutes', () => { 'isActive': true, } as any); }); + + it('should handle guards with named functions', () => { + function canActivateGuard() { + return true; + } + + const nestedRouter = { + config: [ + { + path: 'protected', + component: 'ProtectedComponent', + canActivate: [canActivateGuard], + }, + ], + }; + + const parsedRoutes = parseRoutes(nestedRouter as any); + + expect(parsedRoutes.children![0].canActivateGuards).toEqual(['canActivateGuard()']); + }); + + it('should handle guards with arrow functions', () => { + const arrowGuard = () => true; + + const nestedRouter = { + config: [ + { + path: 'protected', + component: 'ProtectedComponent', + canActivate: [arrowGuard], + }, + ], + }; + + const parsedRoutes = parseRoutes(nestedRouter as any); + + expect(parsedRoutes.children![0].canActivateGuards).toEqual(['arrowGuard()']); + }); + + it('should handle guards with class instances', () => { + class AuthGuard { + canActivate() { + return true; + } + } + + const nestedRouter = { + config: [ + { + path: 'protected', + component: 'ProtectedComponent', + canActivate: [AuthGuard], + }, + ], + }; + + const parsedRoutes = parseRoutes(nestedRouter as any); + + expect(parsedRoutes.children![0].canActivateGuards).toEqual(['AuthGuard']); + }); + + it('should handle multiple guard types', () => { + function canActivateGuard() { + return true; + } + const canMatchGuard = () => true; + class CanDeactivateGuard { + canDeactivate() { + return true; + } + } + + const nestedRouter = { + config: [ + { + path: 'multi-guard', + component: 'MultiGuardComponent', + canActivate: [ + canActivateGuard, + function () { + return true; + }, + () => true, + ], + canMatch: [canMatchGuard], + canDeactivate: [CanDeactivateGuard], + }, + ], + }; + + const parsedRoutes = parseRoutes(nestedRouter as any); + + expect(parsedRoutes.children![0].canActivateGuards).toEqual([ + 'canActivateGuard()', + '[Function]', + '[Function]', + ]); + expect(parsedRoutes.children![0].canMatchGuards).toEqual(['canMatchGuard()']); + expect(parsedRoutes.children![0].canDeactivateGuards).toEqual(['CanDeactivateGuard']); + }); }); diff --git a/devtools/projects/ng-devtools-backend/src/lib/router-tree.ts b/devtools/projects/ng-devtools-backend/src/lib/router-tree.ts index c8fac84391e..ac9475dd57d 100644 --- a/devtools/projects/ng-devtools-backend/src/lib/router-tree.ts +++ b/devtools/projects/ng-devtools-backend/src/lib/router-tree.ts @@ -39,7 +39,7 @@ export function parseRoutes(router: Router): Route { function getGuardNames(child: AngularRoute, type: RouteGuard): string[] { const guards = child?.[type] || []; - const names = guards.map((g: any) => g.name); + const names = guards.map((g: any) => getClassOrFunctionName(g)); return names || []; } @@ -119,9 +119,11 @@ function assignChildrenToParent( * @returns The formatted name: class name, function name with '()', or '[Function]' for anonymous/arrow functions */ function getClassOrFunctionName(fn: Function, defaultName?: string) { - const isArrowWithNoName = !fn.hasOwnProperty('prototype') && fn.name === ''; + const isArrow = !fn.hasOwnProperty('prototype'); - if (isArrowWithNoName) { + const isEmptyName = fn.name === ''; + + if ((isArrow && isEmptyName) || isEmptyName) { return '[Function]'; } diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/router-tree/router-tree.component.ts b/devtools/projects/ng-devtools/src/lib/devtools-tabs/router-tree/router-tree.component.ts index b3c211b4687..72404b4aefe 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/router-tree/router-tree.component.ts +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/router-tree/router-tree.component.ts @@ -124,6 +124,12 @@ export class RouterTreeComponent { return; } + if (className === '[Function]') { + const message = 'Cannot view the source of functions defined inline (arrow or anonymous).'; + this.snackBar.open(message, 'Dismiss', {duration: 5000, horizontalPosition: 'left'}); + return; + } + this.appOperations.viewSourceFromRouter(className, type, this.frameManager.selectedFrame()!); }