route-regex.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.getRouteRegex = getRouteRegex;
  6. exports.getNamedRouteRegex = getNamedRouteRegex;
  7. exports.getNamedMiddlewareRegex = getNamedMiddlewareRegex;
  8. var _extends = require("@swc/helpers/lib/_extends.js").default;
  9. var _escapeRegexp = require("../../escape-regexp");
  10. var _removeTrailingSlash = require("./remove-trailing-slash");
  11. /**
  12. * Parses a given parameter from a route to a data structure that can be used
  13. * to generate the parametrized route. Examples:
  14. * - `[...slug]` -> `{ name: 'slug', repeat: true, optional: true }`
  15. * - `[foo]` -> `{ name: 'foo', repeat: false, optional: true }`
  16. * - `bar` -> `{ name: 'bar', repeat: false, optional: false }`
  17. */ function parseParameter(param) {
  18. const optional = param.startsWith('[') && param.endsWith(']');
  19. if (optional) {
  20. param = param.slice(1, -1);
  21. }
  22. const repeat = param.startsWith('...');
  23. if (repeat) {
  24. param = param.slice(3);
  25. }
  26. return {
  27. key: param,
  28. repeat,
  29. optional
  30. };
  31. }
  32. function getParametrizedRoute(route) {
  33. const segments = (0, _removeTrailingSlash).removeTrailingSlash(route).slice(1).split('/');
  34. const groups = {};
  35. let groupIndex = 1;
  36. return {
  37. parameterizedRoute: segments.map((segment)=>{
  38. if (segment.startsWith('[') && segment.endsWith(']')) {
  39. const { key , optional , repeat } = parseParameter(segment.slice(1, -1));
  40. groups[key] = {
  41. pos: groupIndex++,
  42. repeat,
  43. optional
  44. };
  45. return repeat ? optional ? '(?:/(.+?))?' : '/(.+?)' : '/([^/]+?)';
  46. } else {
  47. return `/${(0, _escapeRegexp).escapeStringRegexp(segment)}`;
  48. }
  49. }).join(''),
  50. groups
  51. };
  52. }
  53. function getRouteRegex(normalizedRoute) {
  54. const { parameterizedRoute , groups } = getParametrizedRoute(normalizedRoute);
  55. return {
  56. re: new RegExp(`^${parameterizedRoute}(?:/)?$`),
  57. groups: groups
  58. };
  59. }
  60. /**
  61. * Builds a function to generate a minimal routeKey using only a-z and minimal
  62. * number of characters.
  63. */ function buildGetSafeRouteKey() {
  64. let routeKeyCharCode = 97;
  65. let routeKeyCharLength = 1;
  66. return ()=>{
  67. let routeKey = '';
  68. for(let i = 0; i < routeKeyCharLength; i++){
  69. routeKey += String.fromCharCode(routeKeyCharCode);
  70. routeKeyCharCode++;
  71. if (routeKeyCharCode > 122) {
  72. routeKeyCharLength++;
  73. routeKeyCharCode = 97;
  74. }
  75. }
  76. return routeKey;
  77. };
  78. }
  79. function getNamedParametrizedRoute(route) {
  80. const segments = (0, _removeTrailingSlash).removeTrailingSlash(route).slice(1).split('/');
  81. const getSafeRouteKey = buildGetSafeRouteKey();
  82. const routeKeys = {};
  83. return {
  84. namedParameterizedRoute: segments.map((segment)=>{
  85. if (segment.startsWith('[') && segment.endsWith(']')) {
  86. const { key , optional , repeat } = parseParameter(segment.slice(1, -1));
  87. // replace any non-word characters since they can break
  88. // the named regex
  89. let cleanedKey = key.replace(/\W/g, '');
  90. let invalidKey = false;
  91. // check if the key is still invalid and fallback to using a known
  92. // safe key
  93. if (cleanedKey.length === 0 || cleanedKey.length > 30) {
  94. invalidKey = true;
  95. }
  96. if (!isNaN(parseInt(cleanedKey.slice(0, 1)))) {
  97. invalidKey = true;
  98. }
  99. if (invalidKey) {
  100. cleanedKey = getSafeRouteKey();
  101. }
  102. routeKeys[cleanedKey] = key;
  103. return repeat ? optional ? `(?:/(?<${cleanedKey}>.+?))?` : `/(?<${cleanedKey}>.+?)` : `/(?<${cleanedKey}>[^/]+?)`;
  104. } else {
  105. return `/${(0, _escapeRegexp).escapeStringRegexp(segment)}`;
  106. }
  107. }).join(''),
  108. routeKeys
  109. };
  110. }
  111. function getNamedRouteRegex(normalizedRoute) {
  112. const result = getNamedParametrizedRoute(normalizedRoute);
  113. return _extends({}, getRouteRegex(normalizedRoute), {
  114. namedRegex: `^${result.namedParameterizedRoute}(?:/)?$`,
  115. routeKeys: result.routeKeys
  116. });
  117. }
  118. function getNamedMiddlewareRegex(normalizedRoute, options) {
  119. const { parameterizedRoute } = getParametrizedRoute(normalizedRoute);
  120. const { catchAll =true } = options;
  121. if (parameterizedRoute === '/') {
  122. let catchAllRegex = catchAll ? '.*' : '';
  123. return {
  124. namedRegex: `^/${catchAllRegex}$`
  125. };
  126. }
  127. const { namedParameterizedRoute } = getNamedParametrizedRoute(normalizedRoute);
  128. let catchAllGroupedRegex = catchAll ? '(?:(/.*)?)' : '';
  129. return {
  130. namedRegex: `^${namedParameterizedRoute}${catchAllGroupedRegex}$`
  131. };
  132. }
  133. //# sourceMappingURL=route-regex.js.map