UNPKG

@coldino/tmi.js-clientonly-fork

Version:

Javascript library for the Twitch Messaging Interface, forked to remove all node requirements (to simplify client bundling).

163 lines (136 loc) 5.19 kB
// eslint-disable-next-line no-control-regex const actionMessageRegex = /^\u0001ACTION ([^\u0001]+)\u0001$/; const justinFanRegex = /^(justinfan)(\d+$)/; const unescapeIRCRegex = /\\([sn:r\\])/g; const escapeIRCRegex = /([ \n;\r\\])/g; const ircEscapedChars = { s: ' ', n: '', ':': ';', r: '' }; const ircUnescapedChars = { ' ': 's', '\n': 'n', ';': ':', '\r': 'r' }; const _ = module.exports = { // Return the second value if the first value is undefined.. get: (a, b) => typeof a === 'undefined' ? b : a, // Indirectly use hasOwnProperty hasOwn: (obj, key) => ({}).hasOwnProperty.call(obj, key), // Race a promise against a delay.. promiseDelay: time => new Promise(resolve => setTimeout(resolve, time)), // Value is a finite number.. isFinite: int => isFinite(int) && !isNaN(parseFloat(int)), // Parse string to number. Returns NaN if string can't be parsed to number.. toNumber: (num, precision) => { if(num === null) { return 0; } const factor = Math.pow(10, _.isFinite(precision) ? precision : 0); return Math.round(num * factor) / factor; }, // Value is an integer.. isInteger: int => !isNaN(_.toNumber(int, 0)), // Merge two arrays.. union: (a, b) => [ ...new Set([ ...a, ...b ]) ], // Value is a regex.. isRegex: str => /[|\\^$*+?:#]/.test(str), // Value is a valid url.. isURL: str => new RegExp('^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$', 'i').test(str), // Return a random justinfan username.. justinfan: () => `justinfan${Math.floor((Math.random() * 80000) + 1000)}`, // Username is a justinfan username.. isJustinfan: username => justinFanRegex.test(username), // Return a valid channel name.. channel: str => { const channel = (str ? str : '').toLowerCase(); return channel[0] === '#' ? channel : '#' + channel; }, // Return a valid username.. username: str => { const username = (str ? str : '').toLowerCase(); return username[0] === '#' ? username.slice(1) : username; }, // Return a valid token.. token: str => str ? str.toLowerCase().replace('oauth:', '') : '', // Return a valid password.. password: str => { const token = _.token(str); return token ? `oauth:${token}` : ''; }, actionMessage: msg => msg.match(actionMessageRegex), // Replace all occurences of a string using an object.. replaceAll: (str, obj) => { if(str === null || typeof str === 'undefined') { return null; } for (const x in obj) { str = str.replace(new RegExp(x, 'g'), obj[x]); } return str; }, unescapeHtml: safe => safe.replace(/\\&amp\\;/g, '&') .replace(/\\&lt\\;/g, '<') .replace(/\\&gt\\;/g, '>') .replace(/\\&quot\\;/g, '"') .replace(/\\&#039\\;/g, '\''), // Escaping values: // http://ircv3.net/specs/core/message-tags-3.2.html#escaping-values unescapeIRC: msg => { if(!msg || typeof msg !== 'string' || !msg.includes('\\')) { return msg; } return msg.replace( unescapeIRCRegex, (m, p) => p in ircEscapedChars ? ircEscapedChars[p] : p ); }, escapeIRC: msg => { if(!msg || typeof msg !== 'string') { return msg; } return msg.replace( escapeIRCRegex, (m, p) => p in ircUnescapedChars ? `\\${ircUnescapedChars[p]}` : p ); }, // Add word to a string.. addWord: (line, word) => line.length ? line + ' ' + word : line + word, // Split a line but try not to cut a word in half.. splitLine: (input, length) => { let lastSpace = input.substring(0, length).lastIndexOf(' '); // No spaces found, split at the very end to avoid a loop.. if(lastSpace === -1) { lastSpace = length - 1; } return [ input.substring(0, lastSpace), input.substring(lastSpace + 1) ]; }, // Extract a number from a string.. extractNumber: str => { const parts = str.split(' '); for (let i = 0; i < parts.length; i++) { if(_.isInteger(parts[i])) { return ~~parts[i]; } } return 0; }, // Format the date.. formatDate: date => { let hours = date.getHours(); let mins = date.getMinutes(); hours = (hours < 10 ? '0' : '') + hours; mins = (mins < 10 ? '0' : '') + mins; return `${hours}:${mins}`; }, // Inherit the prototype methods from one constructor into another.. inherits: (ctor, superCtor) => { ctor.super_ = superCtor; const TempCtor = function () {}; TempCtor.prototype = superCtor.prototype; ctor.prototype = new TempCtor(); ctor.prototype.constructor = ctor; }, // Return whether inside a Node application or not.. isNode: () => { try { return typeof process === 'object' && Object.prototype.toString.call(process) === '[object process]'; } catch(e) {} return false; } };