Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert text styles between IRC/Discord #205

Merged
merged 8 commits into from
Mar 29, 2017
9 changes: 8 additions & 1 deletion lib/bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import logger from 'winston';
import discord from 'discord.js';
import { ConfigurationError } from './errors';
import { validateChannelMapping } from './validators';
import { formatFromDiscordToIRC, formatFromIRCToDiscord } from './formatting';

const REQUIRED_FIELDS = ['server', 'nickname', 'channelMapping', 'discordToken'];
const NICK_COLORS = ['light_blue', 'dark_blue', 'light_red', 'dark_red', 'light_green',
Expand Down Expand Up @@ -173,6 +174,9 @@ class Bot {
this.ircClient.say(ircChannel, text);
} else {
if (text !== '') {
// Convert formatting
text = formatFromDiscordToIRC(text);

text = `<${displayUsername}> ${text}`;
logger.debug('Sending message to IRC', ircChannel, text);
this.ircClient.say(ircChannel, text);
Expand Down Expand Up @@ -203,7 +207,10 @@ class Bot {
return;
}

const withMentions = text.replace(/@[^\s]+\b/g, (match) => {
// Convert text formatting (bold, italics, underscore)
const withFormat = formatFromIRCToDiscord(text);

const withMentions = withFormat.replace(/@[^\s]+\b/g, (match) => {
const search = match.substring(1);
const guild = discordChannel.guild;
const nickUser = guild.members.find('nickname', search);
Expand Down
47 changes: 47 additions & 0 deletions lib/formatting.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import ircFormatting from 'irc-formatting';
import SimpleMarkdown from 'simple-markdown';
import colors from 'irc-colors';
import _ from 'lodash';

function mdNodeToIRC(node) {
let content = node.content;
if (_.isArray(content)) content = content.map(mdNodeToIRC).join('');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could just use Array.isArray I guess?

if (node.type === 'em') return colors.italic(content);
if (node.type === 'strong') return colors.bold(content);
if (node.type === 'u') return colors.underline(content);
return content;
}

export function formatFromDiscordToIRC(text) {
const markdownAST = SimpleMarkdown.defaultInlineParse(text);
return markdownAST.map(mdNodeToIRC).join('');
}

export function formatFromIRCToDiscord(text) {
const blocks = ircFormatting.parse(text).map(block =>
// Consider reverse as italic, some IRC clients use that
_.assign({}, block, { italic: block.italic || block.reverse })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package has a Node >6 requirement anyway, since discord.js enforces that, so could do

{
  ...block,
  { italic: block.italic || block.reverse }
}

);
let mdText = '';

for (let i = 0; i <= blocks.length; i += 1) {
// Default to unstyled blocks when index out of range
const block = blocks[i] || {};
Comment on lines +27 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When can blocks[i] ever be undefined?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, i <= blocks.length not i < blocks.length. Sneaky code.

const prevBlock = blocks[i - 1] || {};

// Add start markers when style turns from false to true
if (!prevBlock.italic && block.italic) mdText += '*';
if (!prevBlock.bold && block.bold) mdText += '**';
if (!prevBlock.underline && block.underline) mdText += '__';

// Add end markers when style turns from true to false
// (and apply in reverse order to maintain nesting)
if (prevBlock.underline && !block.underline) mdText += '__';
if (prevBlock.bold && !block.bold) mdText += '**';
if (prevBlock.italic && !block.italic) mdText += '*';

mdText += block.text || '';
}

return mdText;
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@
"commander": "2.9.0",
"discord.js": "11.0.0",
"irc": "0.5.2",
"irc-colors": "^1.3.2",
"irc-formatting": "^1.0.0-rc3",
"lodash": "^4.17.4",
"simple-markdown": "^0.2.1",
"strip-json-comments": "2.0.1",
"winston": "2.3.1"
},
Expand Down
64 changes: 64 additions & 0 deletions test/formatting.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* eslint-disable prefer-arrow-callback */

import chai from 'chai';
import { formatFromDiscordToIRC, formatFromIRCToDiscord } from '../lib/formatting';

chai.should();

describe('Formatting', () => {
describe('Discord to IRC', () => {
it('should convert bold markdown', () => {
formatFromDiscordToIRC('**text**').should.equal('\x02text\x02');
});

it('should convert italic markdown', () => {
formatFromDiscordToIRC('*text*').should.equal('\x16text\x16');
formatFromDiscordToIRC('_text_').should.equal('\x16text\x16');
});

it('should convert underline markdown', () => {
formatFromDiscordToIRC('__text__').should.equal('\x1ftext\x1f');
});

it('should ignore strikethrough markdown', () => {
formatFromDiscordToIRC('~~text~~').should.equal('text');
});

it('should convert nested markdown', () => {
formatFromDiscordToIRC('**bold *italics***')
.should.equal('\x02bold \x16italics\x16\x02');
});
});

describe('IRC to Discord', () => {
it('should convert bold IRC format', () => {
formatFromIRCToDiscord('\x02text\x02').should.equal('**text**');
});

it('should convert reverse IRC format', () => {
formatFromIRCToDiscord('\x16text\x16').should.equal('*text*');
});

it('should convert italic IRC format', () => {
formatFromIRCToDiscord('\x1dtext\x1d').should.equal('*text*');
});

it('should convert underline IRC format', () => {
formatFromIRCToDiscord('\x1ftext\x1f').should.equal('__text__');
});

it('should ignore color IRC format', () => {
formatFromIRCToDiscord('\x0306,08text\x03').should.equal('text');
});

it('should convert nested IRC format', () => {
formatFromIRCToDiscord('\x02bold \x16italics\x16\x02')
.should.equal('**bold *italics***');
});

it('should convert nested IRC format', () => {
formatFromIRCToDiscord('\x02bold \x1funderline\x1f\x02')
.should.equal('**bold __underline__**');
});
});
});