refactor(devtools): enhance route guard handling and add inline function warning

refactored route guard handling and added warning for inline functions
This commit is contained in:
SkyZeroZx 2025-11-05 16:41:48 -05:00 committed by Jessica Janiuk
parent cb5d36d107
commit f2ffbe31b0
3 changed files with 111 additions and 3 deletions

View file

@ -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']);
});
});

View file

@ -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]';
}

View file

@ -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()!);
}