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

Code before:
    var result = _super.exec.call(this, str);
    if (result) {
      result.groups = buildGroups(result, this);
      var indices = result.indices;
      if (indices) indices.groups = buildGroups(indices, this);
    }
    return result;
  };

  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 match;
          } else {
            var group = groups[name];
            return group
              ? "$" + (Array.isArray(group) ? group.join("$") : 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);
      });

Review comment (suggestion):
End will not actually be `$` but `""`, by `$` I meant the regexp marker for the end of the string :)

Code after:
    var result = _super.exec.call(this, str);
    if (result) {
      result.groups = buildGroups(result, this);
      var indices = result.indices;
      if (indices) indices.groups = buildGroups(indices, this);
    }
    return result;
  };

  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));