Repository: babel/babel
File: packages/babel-helpers/src/helpers/wrapRegExp.ts (TypeScript)

Code before:
  };

  BabelRegExp.prototype[Symbol.replace] = function (
    this: BabelRegExp,
    str: string,
    substitution: string | Function,
  ): string {
    if (typeof substitution === "string") {
      var groups = _groups.get(this)!;
      return (
        _super[Symbol.replace] as (
          string: string,
          replaceValue: string,
        ) => string
      ).call(
        this,
        str,
        substitution.replace(/\$<([^>]+)(>|$)/g, function (match, name, end) {
          if (end === "") {
            // return unterminated group name as-is
            return match;
          } else {
            var group = groups[name];
            return Array.isArray(group)
              ? "$" + group.join("$")
              : typeof group === "number"
                ? "$" + +group
                : "";
          }
        }),
      );
    } else if (typeof substitution === "function") {
      var _this = this;
      return (
        _super[Symbol.replace] as (
          string: string,
          replacer: (substring: string, ...args: any[]) => string,
        ) => string
      ).call(this, str, function (this: any) {
        var args: IArguments | any[] = arguments;
        // Modern engines already pass result.groups returned by exec() as the last arg.
        if (typeof args[args.length - 1] !== "object") {
          args = [].slice.call(args) as any[];
          args.push(buildGroups(args, _this));
        }
        return substitution.apply(this, args);
      });
    } else {
      return _super[Symbol.replace].call(this, str, substitution);
    }
  };

Review comment (suggestion):
This check relies on the observation that all builtin object prototype fields are non-number, so that we don't have to emit `{ __proto__: null }` to every `wrapRegExp` calls. Of course this check will break if user modified the object prototype, but that is the case that we do not plan to support.

Code after:
  };

  BabelRegExp.prototype[Symbol.replace] = function (
    this: BabelRegExp,
    str: string,
    substitution: string | Function,
  ): string {
    if (typeof substitution === "string") {
      var groups = _groups.get(this)!;
      return (
        _super[Symbol.replace] as (
          string: string,
          replaceValue: string,
        ) => string
      ).call(
        this,
        str,
        substitution.replace(/\$<([^>]+)(>|$)/g, function (match, name, end) {
          if (end === "") {
            // return unterminated group name as-is
            return match;
          } else {
            var group = groups[name];
            return Array.isArray(group)
              ? "$" + group.join("$")
              : typeof group === "number"
                ? "$" + group
                : "";
          }
        }),
      );
    } else if (typeof substitution === "function") {
      var _this = this;
      return (
        _super[Symbol.replace] as (
          string: string,
          replacer: (substring: string, ...args: any[]) => string,
        ) => string
      ).call(this, str, function (this: any) {
        var args: IArguments | any[] = arguments;
        // Modern engines already pass result.groups returned by exec() as the last arg.
        if (typeof args[args.length - 1] !== "object") {
          args = [].slice.call(args) as any[];
          args.push(buildGroups(args, _this));
        }
        return substitution.apply(this, args);
      });
    } else {
      return _super[Symbol.replace].call(this, str, substitution);
    }
  };