core-api: add validation of mounted route parameter uniqueness
Co-authored-by: blam <ben@blam.sh>
This commit is contained in:
@@ -25,7 +25,7 @@ import {
|
||||
} from '../extensions/traversal';
|
||||
import { createPlugin } from '../plugin';
|
||||
import { routeCollector, routeParentCollector } from './collectors';
|
||||
import { useRouteRef, RoutingProvider } from './hooks';
|
||||
import { useRouteRef, RoutingProvider, validateRoutes } from './hooks';
|
||||
import { createRouteRef } from './RouteRef';
|
||||
import { RouteRef } from './types';
|
||||
|
||||
@@ -177,4 +177,29 @@ describe('discovery', () => {
|
||||
rendered.getByText('Path at inside: /foo/blob/baz'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should handle relative routing of parameterized routes with duplicate param names', () => {
|
||||
const root = (
|
||||
<MemoryRouter>
|
||||
<Routes>
|
||||
<Extension5 path="/foo/:id">
|
||||
<Extension4 path="/bar/:id" name="borked" routeRef={ref4} />
|
||||
</Extension5>
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const { routes, routeParents } = traverseElementTree({
|
||||
root,
|
||||
discoverers: [childDiscoverer, routeElementDiscoverer],
|
||||
collectors: {
|
||||
routes: routeCollector,
|
||||
routeParents: routeParentCollector,
|
||||
},
|
||||
});
|
||||
|
||||
expect(() => validateRoutes(routes, routeParents)).toThrow(
|
||||
'Parameter :id is duplicated in path /foo/:id/bar/:id',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,3 +75,42 @@ export const RoutingProvider = ({
|
||||
</RoutingContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export function validateRoutes(
|
||||
routes: Map<RouteRef, string>,
|
||||
routeParents: Map<RouteRef, RouteRef | undefined>,
|
||||
) {
|
||||
const notLeafRoutes = new Set(routeParents.values());
|
||||
notLeafRoutes.delete(undefined);
|
||||
|
||||
for (const route of routeParents.keys()) {
|
||||
if (notLeafRoutes.has(route)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let currentRouteRef: RouteRef | undefined = route;
|
||||
|
||||
let fullPath = '';
|
||||
while (currentRouteRef) {
|
||||
const path = routes.get(currentRouteRef);
|
||||
if (!path) {
|
||||
throw new Error(`No path for ${currentRouteRef}`);
|
||||
}
|
||||
fullPath = `${path}${fullPath}`;
|
||||
currentRouteRef = routeParents.get(currentRouteRef);
|
||||
}
|
||||
|
||||
const params = fullPath.match(/:(\w+)/g);
|
||||
if (params) {
|
||||
for (let j = 0; j < params.length; j++) {
|
||||
for (let i = j + 1; i < params.length; i++) {
|
||||
if (params[i] === params[j]) {
|
||||
throw new Error(
|
||||
`Parameter ${params[i]} is duplicated in path ${fullPath}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user