(template, variables)
| 113 | } |
| 114 | |
| 115 | export function formatChannelName(template, variables) { |
| 116 | try { |
| 117 | const safeTemplate = template.normalize('NFKC').replace(CONTROL_AND_INVISIBLE_CHARS_REGEX, '').trim(); |
| 118 | validateChannelNameTemplate(safeTemplate); |
| 119 | |
| 120 | if (!variables || typeof variables !== 'object') { |
| 121 | throw new TitanBotError( |
| 122 | 'Invalid variables object for channel formatting', |
| 123 | ErrorTypes.VALIDATION |
| 124 | ); |
| 125 | } |
| 126 | |
| 127 | const sanitized = {}; |
| 128 | for (const [key, value] of Object.entries(variables)) { |
| 129 | if (value === null || value === undefined) { |
| 130 | sanitized[key] = 'Unknown'; |
| 131 | } else { |
| 132 | |
| 133 | sanitized[key] = String(value) |
| 134 | .normalize('NFKC') |
| 135 | .replace(CONTROL_AND_INVISIBLE_CHARS_REGEX, '') |
| 136 | .replace(/[@#:`\n\r\t]/g, '') |
| 137 | .trim() |
| 138 | .substring(0, CHANNEL_VARIABLE_MAX_LENGTH); |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | const replacements = { |
| 143 | '{username}': sanitized.username || 'User', |
| 144 | '{user_tag}': sanitized.userTag || 'User#0000', |
| 145 | '{displayName}': sanitized.displayName || 'User', |
| 146 | '{display_name}': sanitized.displayName || 'User', |
| 147 | '{guildName}': sanitized.guildName || 'Server', |
| 148 | '{guild_name}': sanitized.guildName || 'Server', |
| 149 | '{channelName}': sanitized.channelName || 'Voice Channel', |
| 150 | '{channel_name}': sanitized.channelName || 'Voice Channel', |
| 151 | }; |
| 152 | |
| 153 | let formatted = safeTemplate; |
| 154 | for (const [placeholder, value] of Object.entries(replacements)) { |
| 155 | formatted = formatted.replace(new RegExp(placeholder.replace(/[{}]/g, '\\$&'), 'g'), value); |
| 156 | } |
| 157 | |
| 158 | formatted = formatted |
| 159 | .normalize('NFKC') |
| 160 | .replace(CONTROL_AND_INVISIBLE_CHARS_REGEX, '') |
| 161 | .replace(/[@#:`\n\r\t]/g, '') |
| 162 | .replace(/\s+/g, ' ') |
| 163 | .trim(); |
| 164 | |
| 165 | if (formatted.length === 0) { |
| 166 | formatted = 'Voice Channel'; |
| 167 | } else if (formatted.length > CHANNEL_NAME_MAX_LENGTH) { |
| 168 | formatted = formatted.substring(0, CHANNEL_NAME_MAX_LENGTH); |
| 169 | } |
| 170 | |
| 171 | logger.debug(`Formatted channel name: "${formatted}" from template "${template}"`); |
| 172 | return formatted; |
no test coverage detected