feat: eslint10 (#13967)

* feat: eslint10

* lint: no-useless-assignment
This commit is contained in:
Barış Uşaklı
2026-02-10 12:39:11 -05:00
committed by GitHub
parent e4455b1cb3
commit 62d88555ae
32 changed files with 55 additions and 67 deletions

View File

@@ -60,6 +60,11 @@ export default defineConfig([
} }
}, },
...publicConfig, ...publicConfig,
...serverConfig ...serverConfig,
{
rules: {
'preserve-caught-error': 'off'
}
}
]); ]);

View File

@@ -164,10 +164,10 @@
"@commitlint/cli": "20.4.1", "@commitlint/cli": "20.4.1",
"@commitlint/config-angular": "20.4.1", "@commitlint/config-angular": "20.4.1",
"coveralls": "3.1.1", "coveralls": "3.1.1",
"@eslint/js": "9.39.2", "@eslint/js": "10.0.1",
"@stylistic/eslint-plugin": "5.8.0", "@stylistic/eslint-plugin": "5.8.0",
"eslint-config-nodebb": "1.1.11", "eslint-config-nodebb": "2.0.1",
"eslint-plugin-import": "2.32.0", "globals": "17.3.0",
"grunt": "1.6.1", "grunt": "1.6.1",
"grunt-contrib-watch": "1.1.0", "grunt-contrib-watch": "1.1.0",
"husky": "8.0.3", "husky": "8.0.3",

View File

@@ -117,23 +117,17 @@ app.onDomReady();
fallback = $(this).text(); fallback = $(this).text();
}); });
let mainTitle;
let pageTitle; let pageTitle;
if (/admin\/plugins\//.test(url)) { if (/admin\/plugins\//.test(url)) {
mainTitle = fallback; pageTitle = '[[admin/menu:section-plugins]] > ' + fallback;
pageTitle = '[[admin/menu:section-plugins]] > ' + mainTitle;
} else { } else {
const matches = url.match(/admin\/(.+?)\/(.+?)$/); const matches = url.match(/admin\/(.+?)\/(.+?)$/);
if (matches) { if (matches) {
mainTitle = '[[admin/menu:' + matches[1] + '/' + matches[2] + ']]'; const mainTitle = '[[admin/menu:' + matches[1] + '/' + matches[2] + ']]';
pageTitle = '[[admin/menu:section-' + pageTitle = '[[admin/menu:section-' +
(matches[1] === 'development' ? 'advanced' : matches[1]) + (matches[1] === 'development' ? 'advanced' : matches[1]) +
']]' + (matches[2] ? (' > ' + mainTitle) : ''); ']]' + (matches[2] ? (' > ' + mainTitle) : '');
if (matches[2] === 'settings') {
mainTitle = translator.compile('admin/menu:settings.page-title', mainTitle);
}
} else { } else {
mainTitle = '[[admin/menu:section-dashboard]]';
pageTitle = '[[admin/menu:section-dashboard]]'; pageTitle = '[[admin/menu:section-dashboard]]';
} }
} }

View File

@@ -138,7 +138,7 @@ define('autocomplete', [
if (!targetEl) { if (!targetEl) {
return; return;
} }
var editor; let editor;
if (targetEl.nodeName === 'TEXTAREA' || targetEl.nodeName === 'INPUT') { if (targetEl.nodeName === 'TEXTAREA' || targetEl.nodeName === 'INPUT') {
editor = new TextareaEditor(targetEl); editor = new TextareaEditor(targetEl);
} else if (targetEl.nodeName === 'DIV' && targetEl.getAttribute('contenteditable') === 'true') { } else if (targetEl.nodeName === 'DIV' && targetEl.getAttribute('contenteditable') === 'true') {
@@ -150,7 +150,7 @@ define('autocomplete', [
// yuku-t/textcomplete inherits directionality from target element itself // yuku-t/textcomplete inherits directionality from target element itself
targetEl.setAttribute('dir', document.querySelector('html').getAttribute('data-dir')); targetEl.setAttribute('dir', document.querySelector('html').getAttribute('data-dir'));
var textcomplete = new Textcomplete(editor, strategies, { const textcomplete = new Textcomplete(editor, strategies, {
dropdown: options, dropdown: options,
}); });
textcomplete.on('rendered', function () { textcomplete.on('rendered', function () {

View File

@@ -727,7 +727,7 @@ define('navigator', [
} }
} }
let scrollTop = 0; let scrollTop;
if (postHeight < viewportHeight - navbarHeight - topicHeaderHeight) { if (postHeight < viewportHeight - navbarHeight - topicHeaderHeight) {
scrollTop = scrollTo.offset().top - (viewportHeight / 2) + (postHeight / 2); scrollTop = scrollTo.offset().top - (viewportHeight / 2) + (postHeight / 2);
} else { } else {

View File

@@ -88,7 +88,7 @@ define('uploadHelpers', ['alerts'], function (alerts) {
let formData; let formData;
if (window.FormData) { if (window.FormData) {
formData = new FormData(); formData = new FormData();
for (var i = 0; i < files.length; ++i) { for (let i = 0; i < files.length; ++i) {
formData.append('files[]', files[i], files[i].name); formData.append('files[]', files[i], files[i].name);
} }
} }
@@ -215,7 +215,7 @@ define('uploadHelpers', ['alerts'], function (alerts) {
success: function (res) { success: function (res) {
const uploads = res.response.images; const uploads = res.response.images;
if (uploads && uploads.length) { if (uploads && uploads.length) {
for (var i = 0; i < uploads.length; ++i) { for (let i = 0; i < uploads.length; ++i) {
uploads[i].filename = files[i].name; uploads[i].filename = files[i].name;
uploads[i].isImage = /image./.test(files[i].type); uploads[i].isImage = /image./.test(files[i].type);
} }

View File

@@ -344,14 +344,13 @@ ActivityPub.get = async (type, id, uri, options) => {
requestCache.set(cacheKey, body); requestCache.set(cacheKey, body);
return body; return body;
} catch (e) { } catch (err) {
if (String(e.code).startsWith('ap_get_')) { if (String(err.code).startsWith('ap_get_')) {
throw e; throw err;
} }
// Handle things like non-json body, etc. // Handle things like non-json body, etc.
const { cause } = e; throw new Error(`[[error:activitypub.get-failed]]`, { cause: err });
throw new Error(`[[error:activitypub.get-failed]]`, { cause });
} }
}; };

View File

@@ -621,7 +621,7 @@ Mocks.notes.public = async (post) => {
let tag = null; let tag = null;
let followersUrl; let followersUrl;
let name = null; let name;
({ titleRaw: name } = await topics.getTopicFields(post.tid, ['title'])); ({ titleRaw: name } = await topics.getTopicFields(post.tid, ['title']));
if (post.toPid) { // direct reply if (post.toPid) { // direct reply

View File

@@ -17,8 +17,6 @@ const searchApi = module.exports;
searchApi.categories = async (caller, data) => { searchApi.categories = async (caller, data) => {
// used by categorySearch module // used by categorySearch module
let cids = [];
let matchedCids = []; let matchedCids = [];
const privilege = data.privilege || 'topics:read'; const privilege = data.privilege || 'topics:read';
data.states = (data.states || ['watching', 'tracking', 'notwatching', 'ignoring']).map( data.states = (data.states || ['watching', 'tracking', 'notwatching', 'ignoring']).map(
@@ -26,6 +24,7 @@ searchApi.categories = async (caller, data) => {
); );
data.parentCid = parseInt(data.parentCid || 0, 10); data.parentCid = parseInt(data.parentCid || 0, 10);
let cids;
if (data.search) { if (data.search) {
({ cids, matchedCids } = await findMatchedCids(caller.uid, data)); ({ cids, matchedCids } = await findMatchedCids(caller.uid, data));
} else { } else {

View File

@@ -615,15 +615,14 @@ usersAPI.changePicture = async (caller, data) => {
throw new Error('[[error:invalid-data]]'); throw new Error('[[error:invalid-data]]');
} }
const { type, url } = data;
let picture = '';
await user.checkMinReputation(caller.uid, data.uid, 'min:rep:profile-picture'); await user.checkMinReputation(caller.uid, data.uid, 'min:rep:profile-picture');
const canEdit = await privileges.users.canEdit(caller.uid, data.uid); const canEdit = await privileges.users.canEdit(caller.uid, data.uid);
if (!canEdit) { if (!canEdit) {
throw new Error('[[error:no-privileges]]'); throw new Error('[[error:no-privileges]]');
} }
const { type, url } = data;
let picture;
if (type === 'default') { if (type === 'default') {
picture = ''; picture = '';
} else if (type === 'uploaded') { } else if (type === 'uploaded') {

View File

@@ -268,7 +268,6 @@ async function getChildrenTree(category, uid) {
} }
let childrenData = await Categories.getCategoriesData(childrenCids); let childrenData = await Categories.getCategoriesData(childrenCids);
childrenData = childrenData.filter(Boolean); childrenData = childrenData.filter(Boolean);
childrenCids = childrenData.map(child => child.cid);
Categories.getTree([category].concat(childrenData), category.parentCid); Categories.getTree([category].concat(childrenData), category.parentCid);
} }

View File

@@ -72,7 +72,7 @@ module.exports = function (Categories) {
return; return;
} }
const categoriesToLoad = categoryData.filter(c => c && c.numRecentReplies && parseInt(c.numRecentReplies, 10) > 0); const categoriesToLoad = categoryData.filter(c => c && c.numRecentReplies && parseInt(c.numRecentReplies, 10) > 0);
let keys = []; let keys;
if (plugins.hooks.hasListeners('filter:categories.getRecentTopicReplies')) { if (plugins.hooks.hasListeners('filter:categories.getRecentTopicReplies')) {
const result = await plugins.hooks.fire('filter:categories.getRecentTopicReplies', { const result = await plugins.hooks.fire('filter:categories.getRecentTopicReplies', {
categories: categoriesToLoad, categories: categoriesToLoad,

View File

@@ -25,7 +25,7 @@ uploadsController.get = async function (req, res, next) {
} }
const itemsPerPage = 20; const itemsPerPage = 20;
const page = parseInt(req.query.page, 10) || 1; const page = parseInt(req.query.page, 10) || 1;
let files = []; let files;
try { try {
await checkSymLinks(req.query.dir); await checkSymLinks(req.query.dir);
files = await getFilesInFolder(currentFolder); files = await getFilesInFolder(currentFolder);
@@ -149,7 +149,7 @@ async function getFileData(currentDir, file) {
uploadsController.uploadCategoryPicture = async function (req, res, next) { uploadsController.uploadCategoryPicture = async function (req, res, next) {
const uploadedFile = req.files[0]; const uploadedFile = req.files[0];
let params = null; let params;
try { try {
params = JSON.parse(req.body.params); params = JSON.parse(req.body.params);

View File

@@ -77,7 +77,7 @@ async function getUsers(req, res) {
} }
async function getUids(set) { async function getUids(set) {
let uids = []; let uids;
if (Array.isArray(set)) { if (Array.isArray(set)) {
const weights = set.map((s, index) => (index ? 0 : 1)); const weights = set.map((s, index) => (index ? 0 : 1));
uids = await db[reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({ uids = await db[reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({

View File

@@ -16,7 +16,7 @@ helpers.mergeBatch = function (batchData, start, stop, sort) {
} }
return selectedArray.length ? selectedArray.shift() : null; return selectedArray.length ? selectedArray.shift() : null;
} }
let item = null; let item;
const result = []; const result = [];
do { do {
item = getFirst(batchData); item = getFirst(batchData);

View File

@@ -82,7 +82,7 @@ module.exports = function (module) {
limit = 0; limit = 0;
} }
let result = []; let result;
async function doQuery(_key, fields, skip, limit) { async function doQuery(_key, fields, skip, limit) {
return await module.client.collection('objects').find({ return await module.client.collection('objects').find({
...query, ...{ _key: _key }, ...query, ...{ _key: _key },

View File

@@ -228,7 +228,7 @@ SELECT o."_key" k,
if (!Array.isArray(keys)) { if (!Array.isArray(keys)) {
keys = [keys]; keys = [keys];
} }
let counts = []; let counts;
if (min !== '-inf' || max !== '+inf') { if (min !== '-inf' || max !== '+inf') {
if (min === '-inf') { if (min === '-inf') {
min = null; min = null;

View File

@@ -300,7 +300,7 @@ module.exports = function (module) {
let cursor = '0'; let cursor = '0';
const returnData = []; const returnData = [];
let done = false; let done;
const seen = Object.create(null); const seen = Object.create(null);
do { do {
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */

View File

@@ -119,7 +119,7 @@ events.getEvents = async function (options) {
const from = options.hasOwnProperty('from') ? options.from : '-inf'; const from = options.hasOwnProperty('from') ? options.from : '-inf';
const to = options.hasOwnProperty('to') ? options.to : '+inf'; const to = options.hasOwnProperty('to') ? options.to : '+inf';
const { filter, start, stop, uids } = options; const { filter, start, stop, uids } = options;
let eids = []; let eids;
if (Array.isArray(uids)) { if (Array.isArray(uids)) {
if (filter === '') { if (filter === '') {

View File

@@ -755,8 +755,7 @@ Flags.update = async function (flagId, uid, changeset) {
await notifications.push(notifObj, [assigneeId]); await notifications.push(notifObj, [assigneeId]);
}; };
const isAssignable = async function (assigneeId) { const isAssignable = async function (assigneeId) {
let allowed = false; let allowed = await user.isAdminOrGlobalMod(assigneeId);
allowed = await user.isAdminOrGlobalMod(assigneeId);
// Mods are also allowed to be assigned, if flag target is post in uid's moderated cid // Mods are also allowed to be assigned, if flag target is post in uid's moderated cid
if (!allowed && current.type === 'post') { if (!allowed && current.type === 'post') {
@@ -918,7 +917,7 @@ Flags.notify = async function (flagObj, uid, notifySelf = false) {
groups.getMembers('Global Moderators', 0, -1), groups.getMembers('Global Moderators', 0, -1),
]); ]);
let uids = admins.concat(globalMods); let uids = admins.concat(globalMods);
let notifObj = null; let notifObj;
const { displayname } = flagObj.reports[flagObj.reports.length - 1].reporter; const { displayname } = flagObj.reports[flagObj.reports.length - 1].reporter;

View File

@@ -250,7 +250,7 @@ Messaging.generateChatWithMessage = async function (room, callerUid, userLang) {
const usernames = users.map(u => (utils.isNumber(u.uid) ? const usernames = users.map(u => (utils.isNumber(u.uid) ?
`<a href="${relative_path}/uid/${u.uid}">${u.displayname}</a>` : `<a href="${relative_path}/uid/${u.uid}">${u.displayname}</a>` :
`<a href="${relative_path}/user/${u.username}">${u.displayname}</a>`)); `<a href="${relative_path}/user/${u.username}">${u.displayname}</a>`));
let compiled = ''; let compiled;
if (!users.length) { if (!users.length) {
return '[[modules:chat.no-users-in-room]]'; return '[[modules:chat.no-users-in-room]]';
} }

View File

@@ -150,7 +150,7 @@ middleware.routeTouchIcon = function routeTouchIcon(req, res) {
return res.redirect(brandTouchIcon); return res.redirect(brandTouchIcon);
} }
let iconPath = ''; let iconPath;
if (brandTouchIcon) { if (brandTouchIcon) {
const uploadPath = nconf.get('upload_path'); const uploadPath = nconf.get('upload_path');
iconPath = path.join(uploadPath, brandTouchIcon.replace(/assets\/uploads/, '')); iconPath = path.join(uploadPath, brandTouchIcon.replace(/assets\/uploads/, ''));
@@ -242,11 +242,11 @@ middleware.delayLoading = function delayLoading(req, res, next) {
// Introduces an artificial delay during load so that brute force attacks are effectively mitigated // Introduces an artificial delay during load so that brute force attacks are effectively mitigated
// Add IP to cache so if too many requests are made, subsequent requests are blocked for a minute // Add IP to cache so if too many requests are made, subsequent requests are blocked for a minute
let timesSeen = delayCache.get(req.ip) || 0; const timesSeen = delayCache.get(req.ip) || 0;
if (timesSeen > 10) { if (timesSeen > 10) {
return res.sendStatus(429); return res.sendStatus(429);
} }
delayCache.set(req.ip, timesSeen += 1); delayCache.set(req.ip, timesSeen + 1);
setTimeout(next, 1000); setTimeout(next, 1000);
}; };

View File

@@ -76,7 +76,7 @@ async function searchInContent(data) {
} }
return []; return [];
} }
let pids = []; let pids;
let tids = []; let tids = [];
const inTopic = String(data.query || '').match(/^in:topic-([\d]+) /); const inTopic = String(data.query || '').match(/^in:topic-([\d]+) /);
if (inTopic) { if (inTopic) {

View File

@@ -74,7 +74,7 @@ module.exports = function (SocketTopics) {
// used by tag filter search // used by tag filter search
SocketTopics.tagFilterSearch = async function (socket, data) { SocketTopics.tagFilterSearch = async function (socket, data) {
let cids = []; let cids;
if (Array.isArray(data.cids)) { if (Array.isArray(data.cids)) {
cids = await privileges.categories.filterCids('topics:read', data.cids, socket.uid); cids = await privileges.categories.filterCids('topics:read', data.cids, socket.uid);
} else { // if no cids passed in get all cids we can read } else { // if no cids passed in get all cids we can read
@@ -82,7 +82,7 @@ module.exports = function (SocketTopics) {
cids = cids.filter(cid => cid !== -1); cids = cids.filter(cid => cid !== -1);
} }
let tags = []; let tags;
if (data.query) { if (data.query) {
const allowed = await privileges.global.can('search:tags', socket.uid); const allowed = await privileges.global.can('search:tags', socket.uid);
if (!allowed) { if (!allowed) {

View File

@@ -134,10 +134,10 @@ Events.get = async (tid, uid, reverse = false) => {
return []; return [];
} }
let eventIds = await db.getSortedSetRangeWithScores(`topic:${tid}:events`, 0, -1); const eventIds = await db.getSortedSetRangeWithScores(`topic:${tid}:events`, 0, -1);
const keys = eventIds.map(obj => `topicEvent:${obj.value}`); const keys = eventIds.map(obj => `topicEvent:${obj.value}`);
const timestamps = eventIds.map(obj => obj.score); const timestamps = eventIds.map(obj => obj.score);
eventIds = eventIds.map(obj => obj.value);
let events = await db.getObjects(keys); let events = await db.getObjects(keys);
events.forEach((e, idx) => { events.forEach((e, idx) => {
e.timestamp = timestamps[idx]; e.timestamp = timestamps[idx];

View File

@@ -252,7 +252,7 @@ module.exports = function (Topics) {
}; };
Topics.getLatestUndeletedReply = async function (tid) { Topics.getLatestUndeletedReply = async function (tid) {
let isDeleted = false; let isDeleted;
let index = 0; let index = 0;
do { do {
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */

View File

@@ -43,7 +43,7 @@ module.exports = function (Topics) {
const result = await plugins.hooks.fire('filter:topics.getSortedTids', { params: params, tids: [] }); const result = await plugins.hooks.fire('filter:topics.getSortedTids', { params: params, tids: [] });
return result.tids; return result.tids;
} }
let tids = []; let tids;
if (params.term !== 'alltime') { if (params.term !== 'alltime') {
if (params.sort === 'posts') { if (params.sort === 'posts') {
tids = await getTidsWithMostPostsInTerm(params.cids, params.uid, params.term); tids = await getTidsWithMostPostsInTerm(params.cids, params.uid, params.term);

View File

@@ -205,7 +205,7 @@ module.exports = function (Topics) {
}; };
Topics.getTagTopicCount = async function (tag, cids = []) { Topics.getTagTopicCount = async function (tag, cids = []) {
let count = 0; let count;
if (cids.length) { if (cids.length) {
count = await db.sortedSetsCardSum( count = await db.sortedSetsCardSum(
cids.map(cid => `cid:${cid}:tag:${tag}:topics`) cids.map(cid => `cid:${cid}:tag:${tag}:topics`)
@@ -476,7 +476,7 @@ module.exports = function (Topics) {
if (parseInt(data.cid, 10)) { if (parseInt(data.cid, 10)) {
tagWhitelist = await categories.getTagWhitelist([data.cid]); tagWhitelist = await categories.getTagWhitelist([data.cid]);
} }
let tags = []; let tags;
if (Array.isArray(tagWhitelist[0]) && tagWhitelist[0].length) { if (Array.isArray(tagWhitelist[0]) && tagWhitelist[0].length) {
const scores = await db.sortedSetScores(`cid:${data.cid}:tags`, tagWhitelist[0]); const scores = await db.sortedSetScores(`cid:${data.cid}:tags`, tagWhitelist[0]);
tags = tagWhitelist[0].map((tag, index) => ({ value: tag, score: scores[index] })); tags = tagWhitelist[0].map((tag, index) => ({ value: tag, score: scores[index] }));

View File

@@ -110,7 +110,7 @@ module.exports = function (Topics) {
} }
async function getPreviousNonBlockedPost(postData, blockedUids) { async function getPreviousNonBlockedPost(postData, blockedUids) {
let isBlocked = false; let isBlocked;
let prevPost = postData; let prevPost = postData;
const postsPerIteration = 5; const postsPerIteration = 5;
let start = 0; let start = 0;

View File

@@ -110,9 +110,8 @@ module.exports = function (User) {
}; };
function parseCreateOptions(userData) { function parseCreateOptions(userData) {
let opts = {};
try { try {
opts = JSON.parse(userData._opts || '{}'); const opts = JSON.parse(userData._opts || '{}');
delete userData._opts; delete userData._opts;
return opts; return opts;
} catch (err) { } catch (err) {

View File

@@ -257,7 +257,7 @@ module.exports = function (User) {
if (!data.groupTitle) { if (!data.groupTitle) {
return; return;
} }
let groupTitles = []; let groupTitles;
if (validator.isJSON(data.groupTitle)) { if (validator.isJSON(data.groupTitle)) {
groupTitles = JSON.parse(data.groupTitle); groupTitles = JSON.parse(data.groupTitle);
if (!Array.isArray(groupTitles)) { if (!Array.isArray(groupTitles)) {

View File

@@ -888,15 +888,10 @@ describe('Topic\'s', () => {
}); });
const { topics: topicsData } = results; const { topics: topicsData } = results;
let topic;
let i; const topic = topicsData.find(topic => topic.tid === parseInt(newTid, 10));
for (i = 0; i < topicsData.length; i += 1) { assert(topic, 'ignored topic didn\'t appear in the recent list');
if (topicsData[i].tid === parseInt(newTid, 10)) { assert.strictEqual(topic.unread, false, 'ignored topic was marked as unread in recent list');
assert.equal(false, topicsData[i].unread, 'ignored topic was marked as unread in recent list');
return;
}
}
assert.ok(topic, 'topic didn\'t appear in the recent list');
}); });
it('should appear as unread again when marked as following', async () => { it('should appear as unread again when marked as following', async () => {