1

I have a map of routes with react router path as keys, eg:

const routes = [
  {
    page: "mySettings",
    label: "pages.mySettings",
    path: "/professionels/mes-reglages.html",
    exact: true
  },
  {
    page: "viewUser",
    label: "pages.viewUser",
    path: "/users/:id/view.html",
    exact: true
  }
];

I want from a location retrieved with useHistory().location.pathname, to match all the path that match the key in react-router terms, eg:

  • (pathname) => get(routesMap, "/professionels/mes-reglages.html") => should match routesMap.get('/professionels/mes-reglages.html')
  • (pathname) => get(routesMap, "/users/11/view.html") => should match routesMap.get('/users/:id/view.html')

and all react-router paths so this should work too:

  • (pathname) => get(routesMap, "/users/11/settings/10/items/24/view.html") => should match routesMap.get('/users/:userId/settings/:settingId/items/:id/view.html')

I have started here, any idea how I can do that with a regexp?

https://codesandbox.io/s/youthful-wing-fjgm1

1 Answer 1

2
+50

Based on your comments i adjusted the code a bit and wrote a rapper function for your lookup. The following rules you have to watch out for when creating the urls:

  • The last id always gets replaced by {id}
  • All other ids get replaced by url part to id without plural and "Id" attached ("/users/111" -> "/users/{userId}")

This would be the function:

const getRouteFromPath = (map, url) => {
  if (url.match(/\/\d+\//g).length > 1) {
    let allowedUrlPart = getAllowedIdQualifier(map);
    let urlParts = url.match(/(?<=\/)\w+(?=\/\d+\/)/g);
    urlParts.forEach(val => {
      if (!allowedUrlPart.includes(val)) {
        urlParts = urlParts.slice(urlParts.indexOf(val), 1);
      }
    });
    urlParts.forEach((val, key, arr) => {
      if (key === arr.length - 1) {
        let regex = new RegExp("(?<=/" + val + "/)\\d+", "g");
        let replacement = ":id";
        url = url.replace(regex, replacement);
      } else {
        let regex = new RegExp("(?<=/" + val + "/)\\d+", "g");
        let replacement = ":" + val.slice(0, -1) + "Id";
        url = url.replace(regex, replacement);
      }
    });
    return map.get(url);
  } else {
    url = url.replace(/\/\d+\//g, "/:id/");
    return map.get(url);
  }
};

const getAllowedIdQualifier = map => {
  let allowedQualifiers = [];
  map.forEach(val => {
    let allowed = val.path.match(/(?<=\/)\w+(?=\/:)/g);
    allowed.forEach(e => {
      if (!allowedQualifiers.includes(e)) {
        allowedQualifiers.push(e);
      }
    });
  });
  return allowedQualifiers;
};

export default getRouteFromPath;

As parameter you pass in the url to match as first parameter and the map of routes as the second paramter and call the function getRoute() instead of the direct map.get() call you where using before.

Here is the example with the urls adjusted to follow the rules, since you need some rules to be able to apply RegEx.

EDIT:

I adjusted the script, so that it reads the map first and determines the allowed paths which accept a id and then check the possible ids from an actual url against it.

https://codesandbox.io/s/kind-moon-9oyj9?fontsize=14&hidenavigation=1&theme=dark

Sign up to request clarification or add additional context in comments.

19 Comments

That coule work in manu place but general the last one is just {id} miles /users/10 => /users/{id}
How can I wrap the initial map object in order to keep the map attributes but allow more path such as computed url to be used for getting within the map ?
Also, the way you replace for you to declare all the entities. It would be better if you could do it automatically by detecting the registered placeholders and compute this solution
@DimitriKopriwa adjusted my answer based on your comments
I have created a codesandbox with the fix :id => codesandbox.io/s/exciting-cori-ufnpv It seems to work fine but it is not bullet proof with number, I am looking forward to get the version that allow that. Thanks a lot again
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.