@stacksjs/bun-router 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -2047,7 +2047,7 @@ function getPrefix() {
2047
2047
  }
2048
2048
  var prefix = getPrefix();
2049
2049
  // package.json
2050
- var version = "0.0.20";
2050
+ var version = "0.0.22";
2051
2051
 
2052
2052
  // src/cli/middleware.ts
2053
2053
  import fs2 from "fs/promises";
package/dist/index.js CHANGED
@@ -6752,6 +6752,12 @@ class RouteTrie {
6752
6752
  type: "wildcard",
6753
6753
  value: "*"
6754
6754
  });
6755
+ } else if (/^\{[^{}/]+\}\*$/.test(part)) {
6756
+ segments.push({
6757
+ type: "wildcard",
6758
+ value: part,
6759
+ paramName: part.slice(1, part.indexOf("}"))
6760
+ });
6755
6761
  } else if (part.startsWith("{") && part.endsWith("}")) {
6756
6762
  const paramPart = part.slice(1, -1);
6757
6763
  const [paramName, pattern] = paramPart.split(":");
@@ -6837,6 +6843,7 @@ class RouteTrie {
6837
6843
  case "wildcard":
6838
6844
  if (!node.wildcardChild) {
6839
6845
  node.wildcardChild = new TrieNode;
6846
+ node.wildcardChild.paramName = segment.paramName ?? null;
6840
6847
  }
6841
6848
  this.insertRoute(node.wildcardChild, compiled, segmentIndex + 1);
6842
6849
  break;
@@ -6886,7 +6893,7 @@ class RouteTrie {
6886
6893
  if (node.wildcardChild) {
6887
6894
  const compiled = node.wildcardChild.getRoute(method);
6888
6895
  if (compiled) {
6889
- params.wildcard = segments.slice(segmentIndex).join("/");
6896
+ params[node.wildcardChild.paramName ?? "wildcard"] = segments.slice(segmentIndex).join("/");
6890
6897
  return {
6891
6898
  route: compiled.route,
6892
6899
  params,
@@ -7029,8 +7036,18 @@ class RouteCompiler {
7029
7036
  }
7030
7037
  }
7031
7038
  convertToURLPattern(path, constraints) {
7039
+ let staticPath = path;
7040
+ let catchAll = null;
7041
+ const namedCatchAll = staticPath.match(/\{([^{}/]+)\}\*$/);
7042
+ if (namedCatchAll) {
7043
+ catchAll = namedCatchAll[1];
7044
+ staticPath = staticPath.slice(0, namedCatchAll.index);
7045
+ } else if (staticPath.endsWith("*")) {
7046
+ catchAll = "wildcard";
7047
+ staticPath = staticPath.slice(0, -1);
7048
+ }
7032
7049
  const paramTokens = [];
7033
- const withTokens = path.replace(/\{([^}]+)\}/g, (_m, inner) => {
7050
+ const withTokens = staticPath.replace(/\{([^}]+)\}/g, (_m, inner) => {
7034
7051
  paramTokens.push(inner);
7035
7052
  return `\x00${paramTokens.length - 1}\x00`;
7036
7053
  });
@@ -7047,6 +7064,8 @@ class RouteCompiler {
7047
7064
  const leadingSlash = token.startsWith("/") ? "/" : "";
7048
7065
  return isOptional ? `(?:${leadingSlash}${group})?` : `${leadingSlash}${group}`;
7049
7066
  });
7067
+ if (catchAll !== null)
7068
+ regexPattern += `(?<${catchAll}>${constraints?.[catchAll] ?? ".+"})`;
7050
7069
  const regex = new RegExp(`^${regexPattern}$`);
7051
7070
  return {
7052
7071
  exec: (pathname) => {
@@ -8693,6 +8712,13 @@ class Router {
8693
8712
  const value = params?.[name];
8694
8713
  return value !== undefined ? value : defaultValue;
8695
8714
  };
8715
+ enhancedReq.getParamAsInt = (name) => {
8716
+ const value = params?.[name];
8717
+ if (value === undefined || value.trim() === "")
8718
+ return null;
8719
+ const parsed = Number(value);
8720
+ return Number.isSafeInteger(parsed) ? parsed : null;
8721
+ };
8696
8722
  enhancedReq.params = params || {};
8697
8723
  return enhancedReq;
8698
8724
  }
@@ -9353,6 +9379,15 @@ if (!RequestWithMacros.hasMacro("getParam")) {
9353
9379
  return value !== undefined ? value : defaultValue;
9354
9380
  });
9355
9381
  }
9382
+ if (!RequestWithMacros.hasMacro("getParamAsInt")) {
9383
+ RequestWithMacros.macro("getParamAsInt", function(name) {
9384
+ const value = this.params?.[name];
9385
+ if (value === undefined || value.trim() === "")
9386
+ return null;
9387
+ const parsed = Number(value);
9388
+ return Number.isSafeInteger(parsed) ? parsed : null;
9389
+ });
9390
+ }
9356
9391
  if (!RequestWithMacros.hasMacro("get")) {
9357
9392
  RequestWithMacros.macro("get", function(key, defaultValue) {
9358
9393
  const value = getParsedURL(this).searchParams.get(key);
package/dist/types.d.ts CHANGED
@@ -695,6 +695,11 @@ export interface EnhancedRequest extends Request, Omit<RequestMacroMethods, 'ip'
695
695
  * `$request->route('name')` ergonomics.
696
696
  */
697
697
  getParam: <T = string>(name: string, defaultValue?: T) => T | undefined;
698
+ /**
699
+ * Read a route parameter as a safe integer. Missing, fractional, and
700
+ * otherwise invalid numeric values return null.
701
+ */
702
+ getParamAsInt: (name: string) => number | null;
698
703
  /**
699
704
  * Query parameters from the URL
700
705
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/bun-router",
3
3
  "type": "module",
4
- "version": "0.0.20",
4
+ "version": "0.0.22",
5
5
  "description": "A fast, type-safe router for Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",