sanitizeContent function

Future<String> sanitizeContent(
  1. String content, {
  2. required PartialTextChannel channel,
  3. SanitizerAction action = SanitizerAction.sanitize,
  4. Map<SanitizerTarget, SanitizerAction>? actionOverrides,
})

Find SanitizerTargets in content and sanitize them according to action.

channel must be provided as the channel to which the sanitized content will be sent. It is used to resolve user, role and channel IDs to their names.

actionOverrides can be provided to change the action taken for each SanitizerTarget type.

Implementation

Future<String> sanitizeContent(
  String content, {
  required PartialTextChannel channel,
  SanitizerAction action = SanitizerAction.sanitize,
  Map<SanitizerTarget, SanitizerAction>? actionOverrides,
}) async {
  final client = channel.manager.client;
  final guild = await switch (await channel.get()) {
    GuildChannel(:final guild) => guild.get(),
    _ => null,
  };

  RegExp patternForTarget(SanitizerTarget target) => switch (target) {
        SanitizerTarget.users => userMentionRegex,
        SanitizerTarget.roles => roleMentionRegex,
        SanitizerTarget.everyone => everyoneMentionRegex,
        SanitizerTarget.channels => channelMentionRegex,
        SanitizerTarget.emojis => guildEmojiRegex,
      };

  Future<String> name(Match match, SanitizerTarget target) async => switch (target) {
        SanitizerTarget.everyone => match.group(1)!,
        SanitizerTarget.channels => switch (await client.channels[Snowflake.parse(match.group(1)!)].getOrNull()) {
            GuildChannel(:final name) || GroupDmChannel(:final name) => name,
            DmChannel(:final recipient) => recipient.globalName ?? recipient.username,
            _ => 'Unknown Channel',
          },
        SanitizerTarget.roles => switch (await guild?.roles[Snowflake.parse(match.group(1)!)].getOrNull()) {
            Role(:final name) => name,
            _ => 'Unknown Role',
          },
        SanitizerTarget.users => switch (await guild?.members[Snowflake.parse(match.group(1)!)].getOrNull()) {
            Member(:final nick?) => nick,
            Member(:final user?) => user.globalName ?? user.username,
            _ => switch (await client.users[Snowflake.parse(match.group(1)!)].getOrNull()) {
                User(:final username, :final globalName) => globalName ?? username,
                _ => 'Unknown User',
              },
          },
        SanitizerTarget.emojis => match.group(2)!,
      };

  String prefix(SanitizerTarget target) => switch (target) {
        SanitizerTarget.users || SanitizerTarget.roles => '@',
        SanitizerTarget.everyone => '@$_whitespaceCharacter',
        SanitizerTarget.channels => '#',
        SanitizerTarget.emojis => '',
      };

  String suffix(SanitizerTarget target) => target == SanitizerTarget.emojis ? ':' : '';

  Future<String> resolve(Match match, SanitizerTarget target, SanitizerAction action) async => switch (action) {
        SanitizerAction.ignore => match.group(0)!,
        SanitizerAction.remove => '',
        SanitizerAction.nameNoPrefix => await name(match, target),
        SanitizerAction.name => '${prefix(target)}${await name(match, target)}${suffix(target)}',
        SanitizerAction.sanitize => switch (target) {
            SanitizerTarget.users => '<@$_whitespaceCharacter${match.group(1)!}>',
            SanitizerTarget.roles => '<@&$_whitespaceCharacter${match.group(1)!}>',
            SanitizerTarget.everyone => '@$_whitespaceCharacter${match.group(1)!}',
            SanitizerTarget.channels => '<#$_whitespaceCharacter${match.group(1)!}>',
            SanitizerTarget.emojis => '<$_whitespaceCharacter${match.group(1) ?? ''}:${match.group(2)}:${match.group(3)}>',
          },
      };

  String result = content;
  for (final target in SanitizerTarget.values) {
    final targetAction = actionOverrides?[target] ?? action;
    final pattern = patternForTarget(target);

    int shift = 0;

    for (final match in pattern.allMatches(result)) {
      final sanitized = await resolve(match, target, targetAction);

      result = result.replaceRange(match.start - shift, match.end - shift, sanitized);

      shift += (match.end - match.start) - sanitized.length;
    }
  }

  return result;
}