core-api: add validation of mounted route parameter uniqueness

Co-authored-by: blam <ben@blam.sh>
This commit is contained in:
Patrik Oldsberg
2020-11-27 17:26:38 +01:00
parent 64993c1dd2
commit 4ef2a8769b
2 changed files with 65 additions and 1 deletions
+26 -1
View File
@@ -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',
);
});
});
+39
View File
@@ -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}`,
);
}
}
}
}
}
}