Merge pull request #1920 from thelounge/xpaw/more-eslint

Enforce padding-line-between-statements
This commit is contained in:
Pavel Djundik 2018-02-20 09:41:40 +02:00 committed by GitHub
commit 1ce2792fc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 161 additions and 0 deletions

View file

@ -48,6 +48,18 @@ rules:
no-var: error no-var: error
object-curly-spacing: [error, never] object-curly-spacing: [error, never]
padded-blocks: [error, never] padded-blocks: [error, never]
padding-line-between-statements:
- error
- blankLine: always
prev:
- block
- block-like
next: "*"
- blankLine: always
prev: "*"
next:
- block
- block-like
prefer-const: error prefer-const: error
prefer-rest-params: error prefer-rest-params: error
prefer-spread: error prefer-spread: error

View file

@ -50,6 +50,7 @@ const nicksStrategy = {
match: /\B(@([a-zA-Z_[\]\\^{}|`@][a-zA-Z0-9_[\]\\^{}|`-]*)?)$/, match: /\B(@([a-zA-Z_[\]\\^{}|`@][a-zA-Z0-9_[\]\\^{}|`-]*)?)$/,
search(term, callback) { search(term, callback) {
term = term.slice(1); term = term.slice(1);
if (term[0] === "@") { if (term[0] === "@") {
callback(completeNicks(term.slice(1), true) callback(completeNicks(term.slice(1), true)
.map((val) => ["@" + val[0], "@" + val[1]])); .map((val) => ["@" + val[0], "@" + val[1]]));
@ -122,6 +123,7 @@ const foregroundColorStrategy = {
post: "</b>", post: "</b>",
}).rendered]; }).rendered];
} }
return i; return i;
}); });
@ -150,6 +152,7 @@ const backgroundColorStrategy = {
post: "</b>", post: "</b>",
}).rendered]; }).rendered];
} }
return pair; return pair;
}) })
.map((pair) => pair.concat(match[1])); // Needed to pass fg color to `template`... .map((pair) => pair.concat(match[1])); // Needed to pass fg color to `template`...
@ -268,9 +271,11 @@ function completeNicks(word, isFuzzy) {
} }
const words = users.data("nicks"); const words = users.data("nicks");
if (isFuzzy) { if (isFuzzy) {
return fuzzyGrep(word, words); return fuzzyGrep(word, words);
} }
return $.grep( return $.grep(
words, words,
(w) => !w.toLowerCase().indexOf(word) (w) => !w.toLowerCase().indexOf(word)
@ -291,6 +296,7 @@ function completeChans(word) {
.find(".chan") .find(".chan")
.each(function() { .each(function() {
const self = $(this); const self = $(this);
if (!self.hasClass("lobby")) { if (!self.hasClass("lobby")) {
words.push(self.attr("aria-label")); words.push(self.attr("aria-label"));
} }

View file

@ -63,6 +63,7 @@ function updateText(condensed, addedTypes) {
}); });
let text = strings.pop(); let text = strings.pop();
if (strings.length) { if (strings.length) {
text = strings.join(", ") + ", and " + text; text = strings.join(", ") + ", and " + text;
} }

View file

@ -68,6 +68,7 @@ sidebar.on("submit", ".join-form", function() {
const key = form.find("input[name='key']"); const key = form.find("input[name='key']");
const keyString = key.val(); const keyString = key.val();
const chan = utils.findCurrentNetworkChan(channelString); const chan = utils.findCurrentNetworkChan(channelString);
if (chan.length) { if (chan.length) {
chan.trigger("click"); chan.trigger("click");
} else { } else {
@ -76,6 +77,7 @@ sidebar.on("submit", ".join-form", function() {
target: form.prev().data("id"), target: form.prev().data("id"),
}); });
} }
closeForm(form.closest(".network")); closeForm(form.closest(".network"));
return false; return false;
}); });

View file

@ -3,6 +3,7 @@
// Generates a string from "color-1" to "color-32" based on an input string // Generates a string from "color-1" to "color-32" based on an input string
module.exports = function(str) { module.exports = function(str) {
let hash = 0; let hash = 0;
for (let i = 0; i < str.length; i++) { for (let i = 0; i < str.length; i++) {
hash += str.charCodeAt(i); hash += str.charCodeAt(i);
} }

View file

@ -16,6 +16,7 @@ function fill(existingEntries, text) {
end: textSegment.start, end: textSegment.start,
}); });
} }
position = textSegment.end; position = textSegment.end;
return acc; return acc;
}, []); }, []);

View file

@ -11,6 +11,7 @@ function findNames(text, users) {
} }
let match; let match;
while ((match = nickRegExp.exec(text))) { while ((match = nickRegExp.exec(text))) {
if (users.indexOf(match[1]) > -1) { if (users.indexOf(match[1]) > -1) {
result.push({ result.push({

View file

@ -46,6 +46,7 @@ function parseStyle(text) {
strikethrough = false; strikethrough = false;
monospace = false; monospace = false;
}; };
resetStyle(); resetStyle();
// When called, this "closes" the current fragment by adding an entry to the // When called, this "closes" the current fragment by adding an entry to the
@ -111,9 +112,11 @@ function parseStyle(text) {
if (colorCodes) { if (colorCodes) {
textColor = Number(colorCodes[1]); textColor = Number(colorCodes[1]);
if (colorCodes[2]) { if (colorCodes[2]) {
bgColor = Number(colorCodes[2]); bgColor = Number(colorCodes[2]);
} }
// Color code length is > 1, so bump the current position cursor by as // Color code length is > 1, so bump the current position cursor by as
// much (and reset the start cursor for the current text block as well) // much (and reset the start cursor for the current text block as well)
position += colorCodes[0].length; position += colorCodes[0].length;
@ -123,6 +126,7 @@ function parseStyle(text) {
textColor = undefined; textColor = undefined;
bgColor = undefined; bgColor = undefined;
} }
break; break;
case HEX_COLOR: case HEX_COLOR:
@ -132,9 +136,11 @@ function parseStyle(text) {
if (colorCodes) { if (colorCodes) {
hexColor = colorCodes[1].toUpperCase(); hexColor = colorCodes[1].toUpperCase();
if (colorCodes[2]) { if (colorCodes[2]) {
hexBgColor = colorCodes[2].toUpperCase(); hexBgColor = colorCodes[2].toUpperCase();
} }
// Color code length is > 1, so bump the current position cursor by as // Color code length is > 1, so bump the current position cursor by as
// much (and reset the start cursor for the current text block as well) // much (and reset the start cursor for the current text block as well)
position += colorCodes[0].length; position += colorCodes[0].length;
@ -154,6 +160,7 @@ function parseStyle(text) {
textColor = tmp; textColor = tmp;
break; break;
} }
case ITALIC: case ITALIC:
emitFragment(); emitFragment();
italic = !italic; italic = !italic;
@ -194,12 +201,14 @@ function prepare(text) {
.reduce((prev, curr) => { .reduce((prev, curr) => {
if (prev.length) { if (prev.length) {
const lastEntry = prev[prev.length - 1]; const lastEntry = prev[prev.length - 1];
if (properties.every((key) => curr[key] === lastEntry[key])) { if (properties.every((key) => curr[key] === lastEntry[key])) {
lastEntry.text += curr.text; lastEntry.text += curr.text;
lastEntry.end += curr.text.length; lastEntry.end += curr.text.length;
return prev; return prev;
} }
} }
return prev.concat([curr]); return prev.concat([curr]);
}, []); }, []);
} }

View file

@ -13,24 +13,31 @@ const colorClass = require("./colorClass");
// Create an HTML `span` with styling information for a given fragment // Create an HTML `span` with styling information for a given fragment
function createFragment(fragment) { function createFragment(fragment) {
const classes = []; const classes = [];
if (fragment.bold) { if (fragment.bold) {
classes.push("irc-bold"); classes.push("irc-bold");
} }
if (fragment.textColor !== undefined) { if (fragment.textColor !== undefined) {
classes.push("irc-fg" + fragment.textColor); classes.push("irc-fg" + fragment.textColor);
} }
if (fragment.bgColor !== undefined) { if (fragment.bgColor !== undefined) {
classes.push("irc-bg" + fragment.bgColor); classes.push("irc-bg" + fragment.bgColor);
} }
if (fragment.italic) { if (fragment.italic) {
classes.push("irc-italic"); classes.push("irc-italic");
} }
if (fragment.underline) { if (fragment.underline) {
classes.push("irc-underline"); classes.push("irc-underline");
} }
if (fragment.strikethrough) { if (fragment.strikethrough) {
classes.push("irc-strikethrough"); classes.push("irc-strikethrough");
} }
if (fragment.monospace) { if (fragment.monospace) {
classes.push("irc-monospace"); classes.push("irc-monospace");
} }
@ -89,6 +96,7 @@ module.exports = function parse(text, users) {
if (intersection) { if (intersection) {
return prev; return prev;
} }
return prev.concat([curr]); return prev.concat([curr]);
}, []); }, []);

View file

@ -11,6 +11,7 @@
(function() { (function() {
var displayReload = function displayReload() { var displayReload = function displayReload() {
var loadingReload = document.getElementById("loading-reload"); var loadingReload = document.getElementById("loading-reload");
if (loadingReload) { if (loadingReload) {
loadingReload.style.display = "block"; loadingReload.style.display = "block";
} }

View file

@ -100,6 +100,7 @@ $(function() {
}); });
const channel = target.closest(".chan"); const channel = target.closest(".chan");
if (utils.isOpInChannel(channel) && channel.data("type") === "channel") { if (utils.isOpInChannel(channel) && channel.data("type") === "channel") {
output += templates.contextmenu_divider(); output += templates.contextmenu_divider();
output += templates.contextmenu_item({ output += templates.contextmenu_item({
@ -127,6 +128,7 @@ $(function() {
data: target.data("target"), data: target.data("target"),
}); });
output += templates.contextmenu_divider(); output += templates.contextmenu_divider();
if (target.hasClass("lobby")) { if (target.hasClass("lobby")) {
output += templates.contextmenu_item({ output += templates.contextmenu_item({
class: "list", class: "list",
@ -141,6 +143,7 @@ $(function() {
data: target.data("id"), data: target.data("id"),
}); });
} }
if (target.hasClass("channel")) { if (target.hasClass("channel")) {
output += templates.contextmenu_item({ output += templates.contextmenu_item({
class: "list", class: "list",
@ -149,6 +152,7 @@ $(function() {
data: target.data("id"), data: target.data("id"),
}); });
} }
output += templates.contextmenu_item({ output += templates.contextmenu_item({
class: "close", class: "close",
action: "close", action: "close",
@ -213,6 +217,7 @@ $(function() {
}); });
let focus = $.noop; let focus = $.noop;
if (!("ontouchstart" in window || navigator.maxTouchPoints > 0)) { if (!("ontouchstart" in window || navigator.maxTouchPoints > 0)) {
focus = function() { focus = function() {
if (chat.find(".active").hasClass("chan")) { if (chat.find(".active").hasClass("chan")) {
@ -250,6 +255,7 @@ $(function() {
if (text.charAt(0) === "/") { if (text.charAt(0) === "/") {
const args = text.substr(1).split(" "); const args = text.substr(1).split(" ");
const cmd = args.shift().toLowerCase(); const cmd = args.shift().toLowerCase();
if (typeof utils.inputCommands[cmd] === "function" && utils.inputCommands[cmd](args)) { if (typeof utils.inputCommands[cmd] === "function" && utils.inputCommands[cmd](args)) {
return; return;
} }
@ -336,6 +342,7 @@ $(function() {
const openWindow = function openWindow(e, data) { const openWindow = function openWindow(e, data) {
const self = $(this); const self = $(this);
const target = self.data("target"); const target = self.data("target");
if (!target) { if (!target) {
return; return;
} }
@ -397,13 +404,16 @@ $(function() {
let title = $(document.body).data("app-name"); let title = $(document.body).data("app-name");
const chanTitle = chan.attr("aria-label"); const chanTitle = chan.attr("aria-label");
if (chanTitle.length > 0) { if (chanTitle.length > 0) {
title = `${chanTitle}${title}`; title = `${chanTitle}${title}`;
} }
document.title = title; document.title = title;
const type = chan.data("type"); const type = chan.data("type");
let placeholder = ""; let placeholder = "";
if (type === "channel" || type === "query") { if (type === "channel" || type === "query") {
placeholder = `Write to ${chanTitle}`; placeholder = `Write to ${chanTitle}`;
} }
@ -418,6 +428,7 @@ $(function() {
} }
const chanChat = chan.find(".chat"); const chanChat = chan.find(".chat");
if (chanChat.length > 0 && type !== "special") { if (chanChat.length > 0 && type !== "special") {
chanChat.sticky(); chanChat.sticky();
} }
@ -446,6 +457,7 @@ $(function() {
if (data && data.pushState === false) { if (data && data.pushState === false) {
return; return;
} }
const state = {}; const state = {};
if (self.prop("id")) { if (self.prop("id")) {
@ -486,10 +498,12 @@ $(function() {
if (chan.hasClass("lobby")) { if (chan.hasClass("lobby")) {
cmd = "/quit"; cmd = "/quit";
const server = chan.find(".name").html(); const server = chan.find(".name").html();
if (!confirm("Disconnect from " + server + "?")) { // eslint-disable-line no-alert if (!confirm("Disconnect from " + server + "?")) { // eslint-disable-line no-alert
return false; return false;
} }
} }
socket.emit("input", { socket.emit("input", {
target: chan.data("id"), target: chan.data("id"),
text: cmd, text: cmd,
@ -602,6 +616,7 @@ $(function() {
if ($("body").hasClass("public") && (window.location.hash === "#connect" || window.location.hash === "")) { if ($("body").hasClass("public") && (window.location.hash === "#connect" || window.location.hash === "")) {
$("#connect").one("show", function() { $("#connect").one("show", function() {
const params = URI(document.location.search).search(true); const params = URI(document.location.search).search(true);
// Possible parameters: name, host, port, password, tls, nick, username, realname, join // Possible parameters: name, host, port, password, tls, nick, username, realname, join
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in#Iterating_over_own_properties_only // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in#Iterating_over_own_properties_only
for (let key in params) { for (let key in params) {
@ -611,6 +626,7 @@ $(function() {
key = key.replace(/\W/g, ""); key = key.replace(/\W/g, "");
const element = $("#connect input[name='" + key + "']"); const element = $("#connect input[name='" + key + "']");
// if the element exists, it isn't disabled, and it isn't hidden // if the element exists, it isn't disabled, and it isn't hidden
if (element.length > 0 && !element.is(":disabled") && !element.is(":hidden")) { if (element.length > 0 && !element.is(":disabled") && !element.is(":hidden")) {
if (element.is(":checkbox")) { if (element.is(":checkbox")) {
@ -647,10 +663,12 @@ $(function() {
// This should always be 24h later but re-computing exact value just in case // This should always be 24h later but re-computing exact value just in case
setTimeout(updateDateMarkers, msUntilNextDay()); setTimeout(updateDateMarkers, msUntilNextDay());
} }
setTimeout(updateDateMarkers, msUntilNextDay()); setTimeout(updateDateMarkers, msUntilNextDay());
window.addEventListener("popstate", (e) => { window.addEventListener("popstate", (e) => {
const {state} = e; const {state} = e;
if (!state) { if (!state) {
return; return;
} }

View file

@ -90,6 +90,7 @@ module.exports.initialize = () => {
if (Notification.permission === "default" && desktopNotificationsCheckbox.prop("checked")) { if (Notification.permission === "default" && desktopNotificationsCheckbox.prop("checked")) {
desktopNotificationsCheckbox.prop("checked", false); desktopNotificationsCheckbox.prop("checked", false);
} }
desktopNotificationsCheckbox.prop("disabled", false); desktopNotificationsCheckbox.prop("disabled", false);
warningBlocked.hide(); warningBlocked.hide();
} }
@ -148,6 +149,7 @@ module.exports.initialize = () => {
const highlightsTokens = options.highlights.map(function(h) { const highlightsTokens = options.highlights.map(function(h) {
return escapeRegExp(h); return escapeRegExp(h);
}); });
if (highlightsTokens && highlightsTokens.length) { if (highlightsTokens && highlightsTokens.length) {
module.exports.highlightsRE = new RegExp("\\b(?:" + highlightsTokens.join("|") + ")\\b", "i"); module.exports.highlightsRE = new RegExp("\\b(?:" + highlightsTokens.join("|") + ")\\b", "i");
} else { } else {

View file

@ -141,19 +141,23 @@ function openImageViewer(link, {pushState = true} = {}) {
// Previous image // Previous image
let previousImage = link.closest(".preview").prev(".preview") let previousImage = link.closest(".preview").prev(".preview")
.find(".toggle-content.show .toggle-thumbnail").last(); .find(".toggle-content.show .toggle-thumbnail").last();
if (!previousImage.length) { if (!previousImage.length) {
previousImage = link.closest(".msg").prevAll() previousImage = link.closest(".msg").prevAll()
.find(".toggle-content.show .toggle-thumbnail").last(); .find(".toggle-content.show .toggle-thumbnail").last();
} }
previousImage.addClass("previous-image"); previousImage.addClass("previous-image");
// Next image // Next image
let nextImage = link.closest(".preview").next(".preview") let nextImage = link.closest(".preview").next(".preview")
.find(".toggle-content.show .toggle-thumbnail").first(); .find(".toggle-content.show .toggle-thumbnail").first();
if (!nextImage.length) { if (!nextImage.length) {
nextImage = link.closest(".msg").nextAll() nextImage = link.closest(".msg").nextAll()
.find(".toggle-content.show .toggle-thumbnail").first(); .find(".toggle-content.show .toggle-thumbnail").first();
} }
nextImage.addClass("next-image"); nextImage.addClass("next-image");
imageViewer.html(templates.image_viewer({ imageViewer.html(templates.image_viewer({
@ -173,12 +177,14 @@ function openImageViewer(link, {pushState = true} = {}) {
// History management // History management
if (pushState) { if (pushState) {
let clickTarget = ""; let clickTarget = "";
// Images can be in a message (channel URL previews) or not (window URL // Images can be in a message (channel URL previews) or not (window URL
// preview, e.g. changelog). This is sub-optimal and needs improvement to // preview, e.g. changelog). This is sub-optimal and needs improvement to
// make image preview more generic and not specific for channel previews. // make image preview more generic and not specific for channel previews.
if (link.closest(".msg").length > 0) { if (link.closest(".msg").length > 0) {
clickTarget = `#${link.closest(".msg").prop("id")} `; clickTarget = `#${link.closest(".msg").prop("id")} `;
} }
clickTarget += `a.toggle-thumbnail[href="${link.prop("href")}"] img`; clickTarget += `a.toggle-thumbnail[href="${link.prop("href")}"] img`;
history.pushState({clickTarget}, null, null); history.pushState({clickTarget}, null, null);
} }

View file

@ -5,6 +5,7 @@ const socket = require("../socket");
socket.on("change-password", function(data) { socket.on("change-password", function(data) {
const passwordForm = $("#change-password"); const passwordForm = $("#change-password");
if (data.error || data.success) { if (data.error || data.success) {
const message = data.success ? data.success : data.error; const message = data.success ? data.success : data.error;
const feedback = passwordForm.find(".feedback"); const feedback = passwordForm.find(".feedback");

View file

@ -24,6 +24,7 @@ socket.on("more", function(data) {
// Remove the date-change marker we put at the top, because it may // Remove the date-change marker we put at the top, because it may
// not actually be a date change now // not actually be a date change now
const children = $(chan).children(); const children = $(chan).children();
if (children.eq(0).hasClass("date-marker-container")) { // Check top most child if (children.eq(0).hasClass("date-marker-container")) { // Check top most child
children.eq(0).remove(); children.eq(0).remove();
} else if (children.eq(1).hasClass("date-marker-container")) { } else if (children.eq(1).hasClass("date-marker-container")) {

View file

@ -12,6 +12,7 @@ const chat = $("#chat");
const sidebar = $("#sidebar"); const sidebar = $("#sidebar");
let pop; let pop;
try { try {
pop = new Audio(); pop = new Audio();
pop.src = "audio/pop.ogg"; pop.src = "audio/pop.ogg";
@ -69,6 +70,7 @@ function processReceivedMessage(data) {
notifyMessage(targetId, channel, data); notifyMessage(targetId, channel, data);
const lastVisible = container.find("div:visible").last(); const lastVisible = container.find("div:visible").last();
if (data.msg.self if (data.msg.self
|| lastVisible.hasClass("unread-marker") || lastVisible.hasClass("unread-marker")
|| (lastVisible.hasClass("date-marker") || (lastVisible.hasClass("date-marker")
@ -100,8 +102,10 @@ function processReceivedMessage(data) {
if ((data.msg.type === "message" || data.msg.type === "action") && channel.hasClass("channel")) { if ((data.msg.type === "message" || data.msg.type === "action") && channel.hasClass("channel")) {
const nicks = channel.find(".users").data("nicks"); const nicks = channel.find(".users").data("nicks");
if (nicks) { if (nicks) {
const find = nicks.indexOf(data.msg.from.nick); const find = nicks.indexOf(data.msg.from.nick);
if (find !== -1) { if (find !== -1) {
nicks.splice(find, 1); nicks.splice(find, 1);
nicks.unshift(data.msg.from.nick); nicks.unshift(data.msg.from.nick);
@ -119,6 +123,7 @@ function notifyMessage(targetId, channel, msg) {
} }
const button = sidebar.find(".chan[data-id='" + targetId + "']"); const button = sidebar.find(".chan[data-id='" + targetId + "']");
if (msg.highlight || (options.notifyAllMessages && msg.type === "message")) { if (msg.highlight || (options.notifyAllMessages && msg.type === "message")) {
if (!document.hasFocus() || !channel.hasClass("active")) { if (!document.hasFocus() || !channel.hasClass("active")) {
if (options.notification) { if (options.notification) {
@ -140,12 +145,15 @@ function notifyMessage(targetId, channel, msg) {
body = msg.from.nick + " invited you to " + msg.channel; body = msg.from.nick + " invited you to " + msg.channel;
} else { } else {
title = msg.from.nick; title = msg.from.nick;
if (!button.hasClass("query")) { if (!button.hasClass("query")) {
title += " (" + button.attr("aria-label").trim() + ")"; title += " (" + button.attr("aria-label").trim() + ")";
} }
if (msg.type === "message") { if (msg.type === "message") {
title += " says:"; title += " says:";
} }
body = cleanIrcMessage(msg.text); body = cleanIrcMessage(msg.text);
} }

View file

@ -9,6 +9,7 @@ socket.on("nick", function(data) {
const id = data.network; const id = data.network;
const nick = data.nick; const nick = data.nick;
const network = sidebar.find("#network-" + id).data("nick", nick); const network = sidebar.find("#network-" + id).data("nick", nick);
if (network.find(".active").length) { if (network.find(".active").length) {
utils.setNick(nick); utils.setNick(nick);
} }

View file

@ -66,8 +66,10 @@ function expand() {
function join(args) { function join(args) {
const channel = args[0]; const channel = args[0];
if (channel) { if (channel) {
const chan = findCurrentNetworkChan(channel); const chan = findCurrentNetworkChan(channel);
if (chan.length) { if (chan.length) {
chan.trigger("click"); chan.trigger("click");
} }
@ -113,10 +115,12 @@ function confirmExit() {
function move(array, old_index, new_index) { function move(array, old_index, new_index) {
if (new_index >= array.length) { if (new_index >= array.length) {
let k = new_index - array.length; let k = new_index - array.length;
while ((k--) + 1) { while ((k--) + 1) {
this.push(undefined); this.push(undefined);
} }
} }
array.splice(new_index, 0, array.splice(old_index, 1)[0]); array.splice(new_index, 0, array.splice(old_index, 1)[0]);
return array; return array;
} }

View file

@ -19,6 +19,7 @@ module.exports = requireViews.keys().reduce((acc, path) => {
} else { } else {
tmp[key] = tmp[key] || {}; tmp[key] = tmp[key] || {};
} }
tmp = tmp[key]; tmp = tmp[key];
}); });

View file

@ -9,6 +9,7 @@ process.chdir(__dirname);
// other issues // other issues
// Try to display messages nicely, but gracefully degrade if anything goes wrong // Try to display messages nicely, but gracefully degrade if anything goes wrong
const pkg = require("./package.json"); const pkg = require("./package.json");
if (!require("semver").satisfies(process.version, pkg.engines.node)) { if (!require("semver").satisfies(process.version, pkg.engines.node)) {
let colors; let colors;
let log; let log;

View file

@ -397,6 +397,7 @@ function pullRequestNumbersInCommits(commits) {
if (pullRequestId) { if (pullRequestId) {
array.push(pullRequestId); array.push(pullRequestId);
} }
return array; return array;
}, []); }, []);
} }
@ -439,6 +440,7 @@ function printLine(entry) {
if (entry.title) { if (entry.title) {
return printPullRequest(entry); return printPullRequest(entry);
} }
return printCommit(entry); return printCommit(entry);
} }
@ -569,6 +571,7 @@ function parse(entries) {
if (!result[dependencyType][packageName]) { if (!result[dependencyType][packageName]) {
result[dependencyType][packageName] = []; result[dependencyType][packageName] = [];
} }
result[dependencyType][packageName].push(entry); result[dependencyType][packageName].push(entry);
} else { } else {
log.info(`${colors.bold(packageName)} was updated in ${colors.green("#" + entry.number)} then removed since last release. Skipping.`); log.info(`${colors.bold(packageName)} was updated in ${colors.green("#" + entry.number)} then removed since last release. Skipping.`);
@ -591,6 +594,7 @@ function parse(entries) {
result.uncategorized.other.push(entry); result.uncategorized.other.push(entry);
} }
} }
return result; return result;
}, { }, {
skipped: [], skipped: [],
@ -616,6 +620,7 @@ function extractContributors(entries) {
if (pullRequest.author.login !== "greenkeeper") { if (pullRequest.author.login !== "greenkeeper") {
memo.add("@" + pullRequest.author.login); memo.add("@" + pullRequest.author.login);
} }
return memo; return memo;
}, new Set()); }, new Set());
@ -699,6 +704,7 @@ async function addToChangelog(newEntry) {
} else { } else {
log.error(error); log.error(error);
} }
process.exit(1); process.exit(1);
} }
@ -724,6 +730,7 @@ async function addToChangelog(newEntry) {
// Step 4: Print out some information about what just happened to the console // Step 4: Print out some information about what just happened to the console
const commitCommand = `git commit -m 'Add changelog entry for v${version}' CHANGELOG.md`; const commitCommand = `git commit -m 'Add changelog entry for v${version}' CHANGELOG.md`;
if (isPrerelease(version)) { if (isPrerelease(version)) {
log.info(`You can now run: ${colors.bold(commitCommand)}`); log.info(`You can now run: ${colors.bold(commitCommand)}`);
} else { } else {

View file

@ -115,14 +115,17 @@ Client.prototype.emit = function(event, data) {
Client.prototype.find = function(channelId) { Client.prototype.find = function(channelId) {
let network = null; let network = null;
let chan = null; let chan = null;
for (const i in this.networks) { for (const i in this.networks) {
const n = this.networks[i]; const n = this.networks[i];
chan = _.find(n.channels, {id: channelId}); chan = _.find(n.channels, {id: channelId});
if (chan) { if (chan) {
network = n; network = n;
break; break;
} }
} }
if (network && chan) { if (network && chan) {
return { return {
network: network, network: network,
@ -340,6 +343,7 @@ Client.prototype.input = function(data) {
Client.prototype.inputLine = function(data) { Client.prototype.inputLine = function(data) {
const client = this; const client = this;
const target = client.find(data.target); const target = client.find(data.target);
if (!target) { if (!target) {
return; return;
} }
@ -373,6 +377,7 @@ Client.prototype.inputLine = function(data) {
if (cmd in inputs) { if (cmd in inputs) {
const plugin = inputs[cmd]; const plugin = inputs[cmd];
if (connected || plugin.allowDisconnected) { if (connected || plugin.allowDisconnected) {
connected = true; connected = true;
plugin.input.apply(client, [target.network, target.chan, cmd, args]); plugin.input.apply(client, [target.network, target.chan, cmd, args]);
@ -427,6 +432,7 @@ Client.prototype.open = function(socketId, target) {
} }
target = this.find(target); target = this.find(target);
if (!target) { if (!target) {
return; return;
} }
@ -459,6 +465,7 @@ Client.prototype.sort = function(data) {
case "channels": { case "channels": {
const network = _.find(this.networks, {id: data.target}); const network = _.find(this.networks, {id: data.target});
if (!network) { if (!network) {
return; return;
} }
@ -478,6 +485,7 @@ Client.prototype.sort = function(data) {
Client.prototype.names = function(data) { Client.prototype.names = function(data) {
const client = this; const client = this;
const target = client.find(data.target); const target = client.find(data.target);
if (!target) { if (!target) {
return; return;
} }

View file

@ -52,6 +52,7 @@ ClientManager.prototype.autoloadUsers = function() {
// Existing users removed since last time users were loaded // Existing users removed since last time users were loaded
_.difference(loaded, updatedUsers).forEach((name) => { _.difference(loaded, updatedUsers).forEach((name) => {
const client = _.find(this.clients, {name: name}); const client = _.find(this.clients, {name: name});
if (client) { if (client) {
client.quit(true); client.quit(true);
this.clients = _.without(this.clients, client); this.clients = _.without(this.clients, client);
@ -86,6 +87,7 @@ ClientManager.prototype.loadUser = function(name) {
client = new Client(this, name, userConfig); client = new Client(this, name, userConfig);
this.clients.push(client); this.clients.push(client);
} }
return client; return client;
}; };
@ -131,9 +133,11 @@ ClientManager.prototype.updateUser = function(name, opts, callback) {
if (!user) { if (!user) {
log.error(`Tried to update invalid user ${colors.green(name)}. This is most likely a bug.`); log.error(`Tried to update invalid user ${colors.green(name)}. This is most likely a bug.`);
if (callback) { if (callback) {
callback(true); callback(true);
} }
return false; return false;
} }
@ -151,9 +155,11 @@ ClientManager.prototype.updateUser = function(name, opts, callback) {
return callback ? callback() : true; return callback ? callback() : true;
} catch (e) { } catch (e) {
log.error(`Failed to update user ${colors.green(name)} (${e})`); log.error(`Failed to update user ${colors.green(name)} (${e})`);
if (callback) { if (callback) {
callback(e); callback(e);
} }
throw e; throw e;
} }
}; };

View file

@ -40,9 +40,11 @@ _.merge(Helper.config, program.config);
require("./start"); require("./start");
require("./config"); require("./config");
if (!Helper.config.public && !Helper.config.ldap.enable) { if (!Helper.config.public && !Helper.config.ldap.enable) {
require("./users"); require("./users");
} }
require("./install"); require("./install");
require("./uninstall"); require("./uninstall");

View file

@ -31,6 +31,7 @@ program
} }
const npm = process.platform === "win32" ? "npm.cmd" : "npm"; const npm = process.platform === "win32" ? "npm.cmd" : "npm";
const errorHandler = (error) => { const errorHandler = (error) => {
log.error( log.error(
`Failed to uninstall ${colors.green(packageName)}. ` + `Failed to uninstall ${colors.green(packageName)}. ` +

View file

@ -37,6 +37,7 @@ program
log.error("Password cannot be empty."); log.error("Password cannot be empty.");
return; return;
} }
if (!err) { if (!err) {
log.prompt({ log.prompt({
text: "Save logs to disk?", text: "Save logs to disk?",

View file

@ -28,6 +28,7 @@ program
log.error(`User ${colors.bold(name)} does not exist.`); log.error(`User ${colors.bold(name)} does not exist.`);
return; return;
} }
const child_spawn = child.spawn( const child_spawn = child.spawn(
process.env.EDITOR || "vi", process.env.EDITOR || "vi",
[Helper.getUserConfigPath(name)], [Helper.getUserConfigPath(name)],

View file

@ -27,6 +27,7 @@ program
log.error(`User ${colors.bold(name)} does not exist.`); log.error(`User ${colors.bold(name)} does not exist.`);
return; return;
} }
const file = Helper.getUserConfigPath(name); const file = Helper.getUserConfigPath(name);
const user = require(file); const user = require(file);
log.prompt({ log.prompt({
@ -36,6 +37,7 @@ program
if (err) { if (err) {
return; return;
} }
user.password = Helper.password.hash(password); user.password = Helper.password.hash(password);
user.sessions = {}; user.sessions = {};
fs.writeFileSync( fs.writeFileSync(

View file

@ -56,12 +56,15 @@ class Utils {
} else if (/^\[.*\]$/.test(value)) { // Arrays } else if (/^\[.*\]$/.test(value)) { // Arrays
// Supporting arrays `[a,b]` and `[a, b]` // Supporting arrays `[a,b]` and `[a, b]`
const array = value.slice(1, -1).split(/,\s*/); const array = value.slice(1, -1).split(/,\s*/);
// If [] is given, it will be parsed as `[ "" ]`, so treat this as empty // If [] is given, it will be parsed as `[ "" ]`, so treat this as empty
if (array.length === 1 && array[0] === "") { if (array.length === 1 && array[0] === "") {
return []; return [];
} }
return array.map(parseValue); // Re-parses all values of the array return array.map(parseValue); // Re-parses all values of the array
} }
return value; return value;
}; };

View file

@ -53,10 +53,12 @@ function getVersion() {
} }
let _gitCommit; let _gitCommit;
function getGitCommit() { function getGitCommit() {
if (_gitCommit !== undefined) { if (_gitCommit !== undefined) {
return _gitCommit; return _gitCommit;
} }
try { try {
_gitCommit = require("child_process") _gitCommit = require("child_process")
.execSync("git rev-parse --short HEAD 2> /dev/null") // Returns hash of current commit .execSync("git rev-parse --short HEAD 2> /dev/null") // Returns hash of current commit

View file

@ -141,11 +141,13 @@ Network.prototype.export = function() {
}) })
.map(function(chan) { .map(function(chan) {
const keys = ["name"]; const keys = ["name"];
if (chan.type === Chan.Type.CHANNEL) { if (chan.type === Chan.Type.CHANNEL) {
keys.push("key"); keys.push("key");
} else if (chan.type === Chan.Type.QUERY) { } else if (chan.type === Chan.Type.QUERY) {
keys.push("type"); keys.push("type");
} }
return _.pick(chan, keys); return _.pick(chan, keys);
}); });

View file

@ -96,6 +96,7 @@ function advancedLdapAuth(user, password, callback) {
}); });
res.on("end", function() { res.on("end", function() {
ldapclient.unbind(); ldapclient.unbind();
if (!found) { if (!found) {
callback(false); callback(false);
} }
@ -115,15 +116,18 @@ function ldapAuth(manager, client, user, password, callback) {
if (valid && !client) { if (valid && !client) {
manager.addUser(user, null); manager.addUser(user, null);
} }
callback(valid); callback(valid);
} }
let auth; let auth;
if ("baseDN" in Helper.config.ldap) { if ("baseDN" in Helper.config.ldap) {
auth = simpleLdapAuth; auth = simpleLdapAuth;
} else { } else {
auth = advancedLdapAuth; auth = advancedLdapAuth;
} }
return auth(user, password, callbackWrapper); return auth(user, password, callbackWrapper);
} }

View file

@ -43,6 +43,7 @@ function fetch(callback) {
// Find the current release among releases on GitHub // Find the current release among releases on GitHub
for (i = 0; i < body.length; i++) { for (i = 0; i < body.length; i++) {
release = body[i]; release = body[i];
if (release.tag_name === versions.current.version) { if (release.tag_name === versions.current.version) {
versions.current.changelog = release.body_html; versions.current.changelog = release.body_html;
prerelease = release.prerelease; prerelease = release.prerelease;

View file

@ -19,6 +19,7 @@ exports.input = function(network, chan, cmd, args) {
if (!network.irc.network.cap.isEnabled("echo-message")) { if (!network.irc.network.cap.isEnabled("echo-message")) {
const channel = network.getChannel(target); const channel = network.getChannel(target);
if (typeof channel !== "undefined") { if (typeof channel !== "undefined") {
network.irc.emit("privmsg", { network.irc.emit("privmsg", {
nick: network.irc.user.nick, nick: network.irc.user.nick,

View file

@ -8,6 +8,7 @@ exports.commands = ["query"];
exports.input = function(network, chan, cmd, args) { exports.input = function(network, chan, cmd, args) {
const target = args[0]; const target = args[0];
if (args.length === 0 || target.length === 0) { if (args.length === 0 || target.length === 0) {
chan.pushMessage(this, new Msg({ chan.pushMessage(this, new Msg({
type: Msg.Type.ERROR, type: Msg.Type.ERROR,
@ -17,11 +18,13 @@ exports.input = function(network, chan, cmd, args) {
} }
const query = _.find(network.channels, {name: target}); const query = _.find(network.channels, {name: target});
if (typeof query !== "undefined") { if (typeof query !== "undefined") {
return; return;
} }
const char = target[0]; const char = target[0];
if (network.irc.network.options.CHANTYPES && network.irc.network.options.CHANTYPES.includes(char)) { if (network.irc.network.options.CHANTYPES && network.irc.network.options.CHANTYPES.includes(char)) {
chan.pushMessage(this, new Msg({ chan.pushMessage(this, new Msg({
type: Msg.Type.ERROR, type: Msg.Type.ERROR,

View file

@ -14,6 +14,7 @@ exports.input = function({irc}, chan, cmd, args) {
return; return;
} }
irc.setTopic(chan.name, args.join(" ")); irc.setTopic(chan.name, args.join(" "));
return true; return true;
}; };

View file

@ -9,6 +9,7 @@ module.exports = function(irc, network) {
irc.on("banlist", function(banlist) { irc.on("banlist", function(banlist) {
const channel = banlist.channel; const channel = banlist.channel;
const bans = banlist.bans; const bans = banlist.bans;
if (!bans || bans.length === 0) { if (!bans || bans.length === 0) {
const msg = new Msg({ const msg = new Msg({
time: Date.now(), time: Date.now(),
@ -21,6 +22,7 @@ module.exports = function(irc, network) {
const chanName = `Banlist for ${channel}`; const chanName = `Banlist for ${channel}`;
let chan = network.getChannel(chanName); let chan = network.getChannel(chanName);
if (typeof chan === "undefined") { if (typeof chan === "undefined") {
chan = new Chan({ chan = new Chan({
type: Chan.Type.SPECIAL, type: Chan.Type.SPECIAL,

View file

@ -122,6 +122,7 @@ function parse(msg, preview, res, client) {
if (!preview.link.startsWith("https://")) { if (!preview.link.startsWith("https://")) {
break; break;
} }
preview.type = "audio"; preview.type = "audio";
preview.res = res.type; preview.res = res.type;
@ -133,6 +134,7 @@ function parse(msg, preview, res, client) {
if (!preview.link.startsWith("https://")) { if (!preview.link.startsWith("https://")) {
break; break;
} }
preview.res = res.type; preview.res = res.type;
preview.type = "video"; preview.type = "video";
@ -191,6 +193,7 @@ function emitPreview(client, msg, preview) {
function fetch(uri, cb) { function fetch(uri, cb) {
let req; let req;
try { try {
req = request.get({ req = request.get({
url: uri, url: uri,
@ -214,6 +217,7 @@ function fetch(uri, cb) {
// response is an image // response is an image
// if Content-Length header reports a size exceeding the prefetch limit, abort fetch // if Content-Length header reports a size exceeding the prefetch limit, abort fetch
const contentLength = parseInt(res.headers["content-length"], 10) || 0; const contentLength = parseInt(res.headers["content-length"], 10) || 0;
if (contentLength > limit) { if (contentLength > limit) {
req.abort(); req.abort();
} }

View file

@ -107,6 +107,7 @@ module.exports = function(irc, network) {
} }
let match; let match;
while ((match = nickRegExp.exec(data.message))) { while ((match = nickRegExp.exec(data.message))) {
if (chan.findUser(match[1])) { if (chan.findUser(match[1])) {
msg.users.push(match[1]); msg.users.push(match[1]);

View file

@ -16,6 +16,7 @@ module.exports = function(irc, network) {
} }
const targetChan = network.getChannel(data.channel); const targetChan = network.getChannel(data.channel);
if (typeof targetChan === "undefined") { if (typeof targetChan === "undefined") {
return; return;
} }
@ -39,6 +40,7 @@ module.exports = function(irc, network) {
targetChan = network.channels[0]; targetChan = network.channels[0];
} else { } else {
targetChan = network.getChannel(data.target); targetChan = network.getChannel(data.target);
if (typeof targetChan === "undefined") { if (typeof targetChan === "undefined") {
return; return;
} }
@ -80,6 +82,7 @@ module.exports = function(irc, network) {
} }
const user = targetChan.findUser(mode.param); const user = targetChan.findUser(mode.param);
if (!user) { if (!user) {
return; return;
} }

View file

@ -5,6 +5,7 @@ module.exports = function(irc, network) {
irc.on("userlist", function(data) { irc.on("userlist", function(data) {
const chan = network.getChannel(data.channel); const chan = network.getChannel(data.channel);
if (typeof chan === "undefined") { if (typeof chan === "undefined") {
return; return;
} }

View file

@ -22,6 +22,7 @@ module.exports = function(irc, network) {
} }
let msg; let msg;
if (data.error) { if (data.error) {
msg = new Msg({ msg = new Msg({
type: Msg.Type.ERROR, type: Msg.Type.ERROR,

View file

@ -18,6 +18,7 @@ function loadLocalThemes() {
if (err) { if (err) {
return; return;
} }
builtInThemes builtInThemes
.filter((theme) => theme.endsWith(".css")) .filter((theme) => theme.endsWith(".css"))
.map(makeLocalThemeObject) .map(makeLocalThemeObject)
@ -27,6 +28,7 @@ function loadLocalThemes() {
function addTheme(packageName, packageObject) { function addTheme(packageName, packageObject) {
const theme = makePackageThemeObject(packageName, packageObject); const theme = makePackageThemeObject(packageName, packageObject);
if (theme) { if (theme) {
themes.set(theme.name, theme); themes.set(theme.name, theme);
} }
@ -54,6 +56,7 @@ function makePackageThemeObject(moduleName, module) {
if (!module || module.type !== "theme") { if (!module || module.type !== "theme") {
return; return;
} }
const modulePath = Helper.getPackageModulePath(moduleName); const modulePath = Helper.getPackageModulePath(moduleName);
const displayName = module.name || moduleName; const displayName = module.name || moduleName;
const filename = path.join(modulePath, module.css); const filename = path.join(modulePath, module.css);

View file

@ -55,9 +55,11 @@ module.exports = function() {
app.get("/themes/:theme.css", (req, res) => { app.get("/themes/:theme.css", (req, res) => {
const themeName = req.params.theme; const themeName = req.params.theme;
const theme = themes.getFilename(themeName); const theme = themes.getFilename(themeName);
if (theme === undefined) { if (theme === undefined) {
return res.status(404).send("Not found"); return res.status(404).send("Not found");
} }
return res.sendFile(theme); return res.sendFile(theme);
}); });
@ -65,9 +67,11 @@ module.exports = function() {
const packageName = req.params.package; const packageName = req.params.package;
const fileName = req.params.filename; const fileName = req.params.filename;
const packageFile = packages.getPackage(packageName); const packageFile = packages.getPackage(packageName);
if (!packageFile || !packages.getStylesheets().includes(`${packageName}/${fileName}`)) { if (!packageFile || !packages.getStylesheets().includes(`${packageName}/${fileName}`)) {
return res.status(404).send("Not found"); return res.status(404).send("Not found");
} }
const packagePath = Helper.getPackageModulePath(packageName); const packagePath = Helper.getPackageModulePath(packageName);
return res.sendFile(path.join(packagePath, fileName)); return res.sendFile(path.join(packagePath, fileName));
}); });
@ -161,6 +165,7 @@ module.exports = function() {
// Handle ctrl+c and kill gracefully // Handle ctrl+c and kill gracefully
let suicideTimeout = null; let suicideTimeout = null;
const exitGracefully = function() { const exitGracefully = function() {
if (suicideTimeout !== null) { if (suicideTimeout !== null) {
return; return;
@ -304,12 +309,14 @@ function initializeClient(socket, client, token, lastMessage) {
const old = data.old_password; const old = data.old_password;
const p1 = data.new_password; const p1 = data.new_password;
const p2 = data.verify_password; const p2 = data.verify_password;
if (typeof p1 === "undefined" || p1 === "") { if (typeof p1 === "undefined" || p1 === "") {
socket.emit("change-password", { socket.emit("change-password", {
error: "Please enter a new password", error: "Please enter a new password",
}); });
return; return;
} }
if (p1 !== p2) { if (p1 !== p2) {
socket.emit("change-password", { socket.emit("change-password", {
error: "Both new password fields must match", error: "Both new password fields must match",
@ -326,6 +333,7 @@ function initializeClient(socket, client, token, lastMessage) {
}); });
return; return;
} }
const hash = Helper.password.hash(p1); const hash = Helper.password.hash(p1);
client.setPassword(hash, (success) => { client.setPassword(hash, (success) => {
@ -375,6 +383,7 @@ function initializeClient(socket, client, token, lastMessage) {
socket.on("msg:preview:toggle", function(data) { socket.on("msg:preview:toggle", function(data) {
const networkAndChan = client.find(data.target); const networkAndChan = client.find(data.target);
if (!networkAndChan) { if (!networkAndChan) {
return; return;
} }
@ -602,12 +611,14 @@ function performAuthentication(data) {
let auth = () => { let auth = () => {
log.error("None of the auth plugins is enabled"); log.error("None of the auth plugins is enabled");
}; };
for (let i = 0; i < authPlugins.length; ++i) { for (let i = 0; i < authPlugins.length; ++i) {
if (authPlugins[i].isEnabled()) { if (authPlugins[i].isEnabled()) {
auth = authPlugins[i].auth; auth = authPlugins[i].auth;
break; break;
} }
} }
auth(manager, client, data.user, data.password, authCallback); auth(manager, client, data.user, data.password, authCallback);
} }

View file

@ -22,6 +22,7 @@ module.exports.write = function(user, network, chan, msg) {
let line = `[${time}] `; let line = `[${time}] `;
const type = msg.type.trim(); const type = msg.type.trim();
if (type === "message" || type === "highlight") { if (type === "message" || type === "highlight") {
// Format: // Format:
// [2014-01-01 00:00:00] <Arnold> Put that cookie down.. Now!! // [2014-01-01 00:00:00] <Arnold> Put that cookie down.. Now!!

View file

@ -116,6 +116,7 @@ describe("LDAP authentication plugin", function() {
before(function(done) { before(function(done) {
originalLogInfo = log.info; originalLogInfo = log.info;
log.info = () => {}; log.info = () => {};
server = startLdapServer(done); server = startLdapServer(done);

View file

@ -10,6 +10,7 @@ describe("packages", function() {
beforeEach(function() { beforeEach(function() {
originalLogInfo = log.info; originalLogInfo = log.info;
log.info = () => {}; log.info = () => {};
delete require.cache[require.resolve("../../../src/plugins/packages")]; delete require.cache[require.resolve("../../../src/plugins/packages")];

View file

@ -12,6 +12,7 @@ describe("Server", function() {
before(function() { before(function() {
originalLogInfo = log.info; originalLogInfo = log.info;
log.info = () => {}; log.info = () => {};
server = require("../src/server")(); server = require("../src/server")();

View file

@ -10,6 +10,7 @@ const Chan = require("../src/models/chan");
function MockClient() { function MockClient() {
this.user = {nick: "test-user"}; this.user = {nick: "test-user"};
} }
util.inherits(MockClient, EventEmitter); util.inherits(MockClient, EventEmitter);
MockClient.prototype.createMessage = function(opts) { MockClient.prototype.createMessage = function(opts) {