eslint: add github/array-foreach rule

pull/654/head
undefined 12 months ago
parent 9901ffa62d
commit 335a272db4
No known key found for this signature in database

@ -12,6 +12,7 @@ plugins:
- '@typescript-eslint'
- simple-import-sort
- eslint-plugin-import
- eslint-plugin-github
rules:
'@typescript-eslint/no-shadow': 1
@ -145,6 +146,8 @@ rules:
message: Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.
- selector: WithStatement
message: '`with` is disallowed in strict mode because it makes code impossible to predict and optimize.'
github/array-foreach: 1
simple-import-sort/imports:
- warn

@ -8,6 +8,7 @@
"@typescript-eslint/parser": "^6.8.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-plugin-github": "^4.10.1",
"eslint-plugin-import": "2.28.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.33.2",

@ -637,9 +637,9 @@ export class ContestUserHandler extends ContestManagementBaseHandler {
const tsdocs = await contest.getMultiStatus(domainId, { docId: tid }).project({
uid: 1, attend: 1, startAt: 1, unrank: 1,
}).toArray();
tsdocs.forEach((i) => {
i.endAt = (this.tdoc.duration && i.startAt) ? moment(i.startAt).add(this.tdoc.duration, 'hours').toDate() : null;
});
for (const tsdoc of tsdocs) {
tsdoc.endAt = (this.tdoc.duration && tsdoc.startAt) ? moment(tsdoc.startAt).add(this.tdoc.duration, 'hours').toDate() : null;
}
const udict = await user.getListForRender(domainId, [this.tdoc.owner, ...tsdocs.map((i) => i.uid)]);
this.response.body = { tdoc: this.tdoc, tsdocs, udict };
this.response.pjax = 'partials/contest_user.html';

@ -36,7 +36,7 @@ export class HomeHandler extends Handler {
uids = new Set<number>();
collectUser(uids: number[]) {
uids.forEach((uid) => this.uids.add(uid));
for (const uid of uids) this.uids.add(uid);
}
async getHomework(domainId: string, limit = 5) {

@ -142,7 +142,7 @@ class DomainModel {
const affected = await UserModel.getMulti({ _id: { $in: uid } })
.project<{ _id: number, mail: string, uname: string }>({ mail: 1, uname: 1 })
.toArray();
affected.forEach((udoc) => deleteUserCache(udoc));
for (const udoc of affected) deleteUserCache(udoc);
return await collUser.updateMany({ domainId, uid: { $in: uid } }, { $set: { role } }, { upsert: true });
}

@ -19,7 +19,7 @@ export async function add(data: Partial<OplogDoc> & { type: string }): Promise<O
function safeKeys(data: any) {
if (['string', 'number', 'boolean'].includes(typeof data)) return data;
if (data instanceof Array) data.forEach(safeKeys);
if (data instanceof Array) for (const d of data) safeKeys(d);
else if (data instanceof ObjectId) return data;
else if (data instanceof Object) {
for (const key in data) {

@ -398,7 +398,7 @@ export function Connection(
closed = true;
bus.emit('connection/close', h);
if (interval) clearInterval(interval);
disposables.forEach((d) => d());
for (const d of disposables) d();
h.cleanup?.(args);
};
interval = setInterval(() => {
@ -555,8 +555,10 @@ ${ctx.response.status} ${endTime - startTime}ms ${ctx.response.length}`);
const layers = [baseLayer, rendererLayer(router, logger), responseLayer(logger), userLayer];
app.use(async (ctx, next) => await next().catch(console.error)).use(domainLayer);
app.use(router.routes()).use(router.allowedMethods());
layers.forEach((layer) => router.use(layer as any));
layers.forEach((layer) => app.use(layer as any));
for (const layer of layers) {
router.use(layer as any);
app.use(layer);
}
app.use((ctx) => handle(ctx, NotFoundHandler, () => true));
wsServer.on('connection', async (socket, request) => {
socket.on('error', (err) => {

@ -1,3 +1,4 @@
// This file was adapted from @koishijs, MIT licensed.
/* eslint-disable consistent-return */
/* eslint-disable import/no-dynamic-require */
/* eslint-disable @typescript-eslint/no-shadow */
@ -13,7 +14,7 @@ function loadDependencies(filename: string, ignored: Set<string>) {
function traverse({ filename, children }: NodeJS.Module) {
if (ignored.has(filename) || dependencies.has(filename) || filename.includes('/node_modules/')) return;
dependencies.add(filename);
children.forEach(traverse);
for (const c of children) traverse(c);
}
traverse(require.cache[filename]);
return dependencies;
@ -87,13 +88,13 @@ export default class Watcher extends Service {
this.accepted = new Set(this.stashed);
this.declined = new Set(this.externals);
this.stashed.forEach((filename) => {
for (const filename of this.stashed) {
const { children } = require.cache[filename];
for (const { filename } of children) {
if (this.accepted.has(filename) || this.declined.has(filename) || filename.includes('/node_modules/')) continue;
pending.push(filename);
}
});
}
while (pending.length) {
let index = 0;
@ -168,7 +169,7 @@ export default class Watcher extends Service {
// we only detect reloads at plugin level
// a plugin will be reloaded if any of its dependencies are accepted
if (!dependencies.some((dep) => this.accepted.has(dep))) continue;
dependencies.forEach((dep) => this.accepted.add(dep));
for (const dep of dependencies) this.accepted.add(dep);
// prepare for reload
let isMarked = false;

@ -434,10 +434,10 @@ const scripts: UpgradeScript[] = [
null,
async function _65_66() {
return await iterateAllDomain(async (ddoc) => {
Object.keys(ddoc.roles).forEach((role) => {
for (const role of Object.keys(ddoc.roles)) {
if (['guest', 'root'].includes(role)) return;
ddoc.roles[role] = (BigInt(ddoc.roles[role]) | PERM.PREM_VIEW_DISPLAYNAME).toString();
});
}
await domain.setRoles(ddoc._id, ddoc.roles);
});
},

@ -331,19 +331,21 @@ export async function run({
if (judgeState) {
if (judgeState.compile?.message) data.compilerTexts.push(judgeState.compile.message.replace(/<.+?>/g, ''));
if (judgeState.judge) {
judgeState.judge.subtasks.forEach((subtask, index) => {
subtask.cases.forEach((curCase, caseIndex) => {
for (let i = 0; i < judgeState.judge.subtasks.length; i++) {
const subtask = judgeState.judge.subtasks.length[i];
for (let j = 0; j < subtask.cases.length; j++) {
const curCase = subtask.cases[j];
data.testCases.push({
subtaskId: index + 1,
id: caseIndex + 1,
subtaskId: i + 1,
id: j + 1,
score: Math.trunc((curCase.result?.scoringRate || 0) * 100),
time: curCase.result?.time || 0,
memory: curCase.result?.memory || 0,
message: curCase.result?.spjMessage || curCase.result?.systemMessage || curCase.result?.userError || '',
status: curCase.status === 2 ? TestcaseJudgeStatusMap[curCase.result.type] : TestcaseStatusMap[curCase.status],
});
});
});
}
}
}
}
if (rdoc.type) {

@ -398,7 +398,7 @@ export async function run({
try {
const details = await xml2js.parseStringPromise(result.details);
if (details.tests.subtask) {
details.tests.subtask.forEach((subtask) => {
for (const subtask of details.tests.subtask) {
if (!subtask.test) {
data.testCases.push({
subtaskId: subtask.$.num,
@ -409,7 +409,7 @@ export async function run({
message: 'Skipped',
status: STATUS.STATUS_CANCELED,
});
return;
continue;
}
data.testCases.push(...subtask.test.map((curCase, caseIndex) => ({
subtaskId: subtask.$.num,
@ -420,7 +420,7 @@ export async function run({
message: curCase.res[0] || '',
status: statusMap[curCase.$.info] || STATUS.STATUS_WAITING,
})));
});
}
} else if (details.tests.test) {
data.testCases.push(...details.tests.test.map((curCase) => ({
subtaskId: 1,

@ -1,3 +1,4 @@
/* eslint-disable github/array-foreach */
import { $, addPage, AutoloadPage } from '@hydrooj/ui-default';
/* global DocsAPI */

@ -20,13 +20,13 @@ export default async function readYamlCases(cfg: Record<string, any> = {}, check
}
if (cfg.interactor) config.interactor = checkFile(cfg.interactor, 'Cannot find interactor {0}.');
if (cfg.validator) config.validator = checkFile(cfg.validator, 'Cannot find validator {0}.');
['judge', 'user'].forEach((n) => {
for (const n of ['judge', 'user']) {
const conf = cfg[`${n}_extra_files`];
if (!conf) return;
if (!conf) continue;
if (conf instanceof Array) {
config[`${n}_extra_files`] = conf.map((file) => checkFile(file, `Cannot find ${n} extra file {0}.`));
} else throw new Error(`Invalid ${n}_extra_files config.`);
});
}
}
if (cfg.cases?.length) {
config.subtasks = [{

@ -27,7 +27,7 @@ export interface LangConfig {
export function parseLang(config: string): Record<string, LangConfig> {
const file = yaml.load(config) as Record<string, LangConfig>;
if (typeof file === 'undefined' || typeof file === 'string' || typeof file === 'number') throw new Error();
Object.keys(file).filter((i) => i.startsWith('_')).forEach((k) => delete file[k]);
for (const key of Object.keys(file)) if (key.startsWith('_')) delete file[key];
for (const key in file) {
const entry = file[key];
if (key.includes('.')) {

@ -36,9 +36,7 @@ export function folderSize(folderPath: string) {
size += stats.size;
const files = fs.readdirSync(p);
if (Array.isArray(files)) {
files.forEach((file) => {
_next(path.join(p, file));
});
for (const file of files) _next(path.join(p, file));
}
}
}
@ -247,9 +245,9 @@ export function CallableInstance(property = '__call__') {
else func = this.constructor.prototype[property];
const apply = function __call__(...args) { return func.apply(apply, ...args); };
Object.setPrototypeOf(apply, this.constructor.prototype);
Object.getOwnPropertyNames(func).forEach((p) => {
for (const p of Object.getOwnPropertyNames(func)) {
Object.defineProperty(apply, p, Object.getOwnPropertyDescriptor(func, p));
});
}
return apply;
}

@ -59,7 +59,7 @@ class AccountService {
await next({ status: STATUS.STATUS_JUDGING, message: `ID = ${rid}` });
const nextFunction = (data) => {
if (data.case) delete data.case.message;
if (data.cases) data.cases.forEach((x) => delete x.message);
if (data.cases) for (const x of data.cases) delete x.message;
return next(data);
};
await this.api.waitForSubmission(rid, task.config?.detail === false ? nextFunction : next, end);

@ -177,15 +177,15 @@ export default class CodeforcesProvider extends BasicFetcher implements IBasicPr
const text = $dom.window.document.querySelector('.problem-statement').innerHTML;
const { window: { document } } = new JSDOM(text);
const files = {};
document.querySelectorAll('img[src]').forEach((ele) => {
for (const ele of document.querySelectorAll('img[src]')) {
const src = ele.getAttribute('src');
if (!src.startsWith('http')) return;
if (!src.startsWith('http')) continue;
const file = new PassThrough();
this.get(src).pipe(file);
const fid = String.random(8);
files[`${fid}.png`] = file;
ele.setAttribute('src', `file://${fid}.png`);
});
}
const title = document.querySelector('.title').innerHTML.trim().split('. ')[1];
const time = parseInt(document.querySelector('.time-limit').innerHTML.substr(53, 2), 10);
const memory = parseInt(document.querySelector('.memory-limit').innerHTML.substr(55, 4), 10);
@ -200,11 +200,11 @@ export default class CodeforcesProvider extends BasicFetcher implements IBasicPr
const note = document.querySelector('.note')?.innerHTML.trim();
document.querySelector('.note')?.remove();
document.querySelector('.sample-tests')?.remove();
document.querySelectorAll('.section-title').forEach((ele) => {
for (const ele of document.querySelectorAll('.section-title')) {
const e = document.createElement('h2');
e.innerHTML = ele.innerHTML;
ele.replaceWith(e);
});
}
const description = document.body.innerHTML.trim();
return {
title: id.startsWith('P921') ? title.replace('1', id.split('P921')[1]) : title,

@ -93,12 +93,12 @@ export default class CSGOJProvider extends BasicFetcher implements IBasicProvide
const pDescription = document.querySelector('div[name="Description"]');
const files = {};
const images = {};
pDescription.querySelectorAll('img[src]').forEach((ele) => {
for (const ele of pDescription.querySelectorAll('img[src]')) {
let src = ele.getAttribute('src').replace('.svg', '.png');
src = new URL(src, 'https://cpc.csgrandeur.cn').toString();
if (images[src]) {
ele.setAttribute('src', `file://${images[src]}.png`);
return;
continue;
}
const file = new PassThrough();
this.get(src).pipe(file);
@ -106,7 +106,7 @@ export default class CSGOJProvider extends BasicFetcher implements IBasicProvide
images[src] = fid;
files[`${fid}.png`] = file;
ele.setAttribute('src', `file://${fid}.png`);
});
}
const description = [...pDescription.children].map((i) => i.outerHTML).join('');
const input = [...document.querySelector('div[name="Input"]').children].map((i) => i.outerHTML).join('');
const output = [...document.querySelector('div[name="Output"]').children].map((i) => i.outerHTML).join('');

@ -113,11 +113,11 @@ export default class POJProvider extends BasicFetcher implements IBasicProvider
content.children[0].remove();
content.children[0].remove();
content.children[0].remove();
content.querySelectorAll('img[src]').forEach((ele) => {
for (const ele of content.querySelectorAll('img[src]')) {
const src = ele.getAttribute('src');
if (images[src]) {
ele.setAttribute('src', `file://${images[src]}.png`);
return;
continue;
}
const file = new PassThrough();
this.get(src).pipe(file);
@ -125,7 +125,7 @@ export default class POJProvider extends BasicFetcher implements IBasicProvider
images[src] = fid;
files[`${fid}.png`] = file;
ele.setAttribute('src', `file://${fid}.png`);
});
}
let lastId = 0;
let markNext = '';
let html = '';

@ -52,15 +52,15 @@ export default class SPOJProvider extends BasicFetcher implements IBasicProvider
logger.info(id);
const { document } = await this.html(`/problems/${id}/`);
const files = {};
document.querySelector('#problem-body').querySelectorAll('img[src]').forEach((ele) => {
for (const ele of document.querySelector('#problem-body').querySelectorAll('img[src]')) {
const src = ele.getAttribute('src');
if (!src.startsWith('http')) return;
if (!src.startsWith('http')) continue;
const file = new PassThrough();
this.get(src).pipe(file);
const fid = String.random(8);
files[`${fid}.png`] = file;
ele.setAttribute('src', `file://${fid}.png`);
});
}
const meta = document.querySelector('#problem-meta').children[1];
const window = await this.html(`/submit/${id}/`);
const langs = Array.from(window.document.querySelector('#lang').querySelectorAll('option'))

@ -71,15 +71,15 @@ export default class UOJProvider extends BasicFetcher implements IBasicProvider
const res = await this.get(`/problem/${id.split('P')[1]}`);
const { window: { document } } = new JSDOM(res.text);
const files = {};
document.querySelectorAll('article>img[src]').forEach((ele) => {
for (const ele of document.querySelectorAll('article>img[src]')) {
const src = ele.getAttribute('src');
if (!src.startsWith('http')) return;
if (!src.startsWith('http')) continue;
const file = new PassThrough();
this.get(src).pipe(file);
const fid = String.random(8);
files[`${fid}.png`] = file;
ele.setAttribute('src', `file://${fid}.png`);
});
}
const contentNode = document.querySelector('article');
const titles = contentNode.querySelectorAll('h3');
for (const title of titles) {

Loading…
Cancel
Save