/** * @param pathname A pathname string, such as `/foo` or `/foo/bar` * @param routingRule The routing rule, such as `/foo/*` * @returns True if pathname matches the routing rule * * / -> / * /* -> /* * /foo -> /foo * /foo* -> /foo, /foo-bar, /foo/* * /foo/* -> /foo, /foo/bar */ export function isRoutingRuleMatch( pathname: string, routingRule: string ): boolean { // sanity checks if (!pathname) { throw new Error("Pathname is undefined."); } if (!routingRule) { throw new Error("Routing rule is undefined."); } const ruleRegExp = transformRoutingRuleToRegExp(routingRule); return pathname.match(ruleRegExp) !== null; } function transformRoutingRuleToRegExp(rule: string): RegExp { let transformedRule; if (rule === "/" || rule === "/*") { transformedRule = rule; } else if (rule.endsWith("/*")) { // make `/*` an optional group so we can match both /foo/* and /foo // /foo/* => /foo(/*)? transformedRule = `${rule.substring(0, rule.length - 2)}(/*)?`; } else if (rule.endsWith("/")) { // make `/` an optional group so we can match both /foo/ and /foo // /foo/ => /foo(/)? transformedRule = `${rule.substring(0, rule.length - 1)}(/)?`; } else if (rule.endsWith("*")) { transformedRule = rule; } else { transformedRule = `${rule}(/)?`; } // /foo* => /foo.* => ^/foo.*$ // /*.* => /*\.* => /.*\..* => ^/.*\..*$ transformedRule = `^${transformedRule .replaceAll(/\./g, "\\.") .replaceAll(/\*/g, ".*")}$`; // ^/foo.*$ => /^\/foo.*$/ return new RegExp(transformedRule); }