Repository: honojs/hono
File: src/request.ts (TypeScript)

Code before:
   *
   * @see {@link https://hono.dev/docs/api/routing#path-parameter}
   *
   * @example
   * ```ts
   * const name = c.req.param('name')
   * // or all parameters at once
   * const { id, comment_id } = c.req.param()
   * ```
   */
  param<P2 extends ParamKeys<P> = ParamKeys<P>>(key: P2 extends `${infer _}?` ? never : P2): string
  param<P2 extends RemoveQuestion<ParamKeys<P>> = RemoveQuestion<ParamKeys<P>>>(
    key: P2
  ): string | undefined
  param(key: string): string | undefined
  param<P2 extends string = P>(): Simplify<UnionToIntersection<ParamKeyToRecord<ParamKeys<P2>>>>
  param(key?: string): unknown {
    return key ? this.getDecodedParam(key) : this.getAllDecodedParams()
  }

  #tryDecodeURIComponent = (str: string) => tryDecode(str, decodeURIComponent)

  private getDecodedParam(key: string): string | undefined {
    const paramKey = this.#matchResult[0][this.routeIndex][1][key]
    const param = this.getParamValue(paramKey)
    return param ? this.#tryDecodeURIComponent(param) : undefined
  }

  private getAllDecodedParams(): Record<string, string> {
    const decoded: Record<string, string> = {}

    const keys = Object.keys(this.#matchResult[0][this.routeIndex][1])
    for (const key of keys) {
      const value = this.getParamValue(this.#matchResult[0][this.routeIndex][1][key])
      if (value && typeof value === 'string') {
        decoded[key] = this.#tryDecodeURIComponent(value)
      }
    }

    return decoded
  }

  private getParamValue(paramKey: any): string | undefined {
    return this.#matchResult[1] ? this.#matchResult[1][paramKey as any] : paramKey
  }

  /**
   * `.query()` can get querystring parameters.
   *
   * @see {@link https://hono.dev/docs/api/request#query}
   *

Review comment (performance):
I think it's better to keep `/\%/.test(param)` because this call affects the performance of simple requests and benchmarks.

Code after:
  /**
   * `.req.param()` gets the path parameters.
   *
   * @see {@link https://hono.dev/docs/api/routing#path-parameter}
   *
   * @example
   * ```ts
   * const name = c.req.param('name')
   * // or all parameters at once
   * const { id, comment_id } = c.req.param()
   * ```
   */
  param<P2 extends ParamKeys<P> = ParamKeys<P>>(key: P2 extends `${infer _}?` ? never : P2): string
  param<P2 extends RemoveQuestion<ParamKeys<P>> = RemoveQuestion<ParamKeys<P>>>(
    key: P2
  ): string | undefined
  param(key: string): string | undefined
  param<P2 extends string = P>(): Simplify<UnionToIntersection<ParamKeyToRecord<ParamKeys<P2>>>>
  param(key?: string): unknown {
    return key ? this.getDecodedParam(key) : this.getAllDecodedParams()
  }

  private getDecodedParam(key: string): string | undefined {
    const paramKey = this.#matchResult[0][this.routeIndex][1][key]
    const param = this.getParamValue(paramKey)
    return param ? (/\%/.test(param) ? tryDecodeURIComponent(param) : param) : undefined
  }

  private getAllDecodedParams(): Record<string, string> {
    const decoded: Record<string, string> = {}

    const keys = Object.keys(this.#matchResult[0][this.routeIndex][1])
    for (const key of keys) {
      const value = this.getParamValue(this.#matchResult[0][this.routeIndex][1][key])
      if (value && typeof value === 'string') {
        decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value
      }
    }

    return decoded
  }

  private getParamValue(paramKey: any): string | undefined {
    return this.#matchResult[1] ? this.#matchResult[1][paramKey as any] : paramKey
  }

  /**
   * `.query()` can get querystring parameters.
   *
   * @see {@link https://hono.dev/docs/api/request#query}
   *