mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
workspace: add oxlint
This commit is contained in:
18 files changed
+120
-44
No files matched your search
@@ -30,6 +30,7 @@ yarn.lock
|
||||
pnpm-lock.yaml
|
||||
tsconfig.json
|
||||
tsconfig.*.json
|
||||
.oxlintrc.json
|
||||
|
||||
# Project Rules
|
||||
## Core
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import fs from 'fs';
|
||||
import { rules as baseBestPracticesRules } from 'eslint-config-airbnb-base/rules/best-practices';
|
||||
import { rules as baseErrorsRules } from 'eslint-config-airbnb-base/rules/errors';
|
||||
import { rules as baseES6Rules } from 'eslint-config-airbnb-base/rules/es6';
|
||||
import { rules as baseStyleRules } from 'eslint-config-airbnb-base/rules/style';
|
||||
import { rules as baseVariablesRules } from 'eslint-config-airbnb-base/rules/variables';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
const base = yaml.load(fs.readFileSync('base.yaml', 'utf8')) as any;
|
||||
const react = yaml.load(fs.readFileSync('react.yaml', 'utf8')) as any;
|
||||
|
||||
function sort<T>(obj: Record<string, T>): Record<string, T> {
|
||||
const clone = { ...obj };
|
||||
Object.keys(clone).sort().reduce(
|
||||
(acc, key) => {
|
||||
acc[key] = clone[key];
|
||||
return acc;
|
||||
},
|
||||
);
|
||||
return clone;
|
||||
}
|
||||
|
||||
// NOTE: oxlint doesn't support most stylistic rules
|
||||
|
||||
const rules = sort({
|
||||
...baseBestPracticesRules,
|
||||
...baseErrorsRules,
|
||||
...baseES6Rules,
|
||||
...baseStyleRules,
|
||||
...baseVariablesRules,
|
||||
...base.rules,
|
||||
...react.rules,
|
||||
'no-unused-vars': [
|
||||
'off',
|
||||
// 'error',
|
||||
// {
|
||||
// caughtErrorsIgnorePattern: '^_|e',
|
||||
// argsIgnorePattern: '^_',
|
||||
// },
|
||||
],
|
||||
|
||||
'no-await-in-loop': 'off', // temporary disable the file until oxlint support extending config
|
||||
|
||||
// Let typescript to the thing
|
||||
'no-undef': 'off',
|
||||
'no-empty-function': 'off',
|
||||
'no-lonely-if': 'off',
|
||||
'no-unsafe-declaration-merging': 'off',
|
||||
'no-this-alias': 'off',
|
||||
'no-new-array': 'off', // It breaks [...new Array(n)].map()
|
||||
'no-useless-spread': 'off', // It breaks [...new Array(n)].map()
|
||||
'no-script-url': 'off', // It breaks createElement('a').setAttribute('href', 'javascript:;')
|
||||
});
|
||||
|
||||
delete rules['@typescript-eslint/no-unused-vars'];
|
||||
|
||||
fs.writeFileSync('.oxlintrc.json', JSON.stringify({
|
||||
$schema: './node_modules/oxlint/configuration_schema.json',
|
||||
rules,
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
jquery: true,
|
||||
node: true,
|
||||
},
|
||||
globals: {
|
||||
UiContext: 'readonly',
|
||||
UserContext: 'readonly',
|
||||
externalModules: 'readonly',
|
||||
LOCALES: 'readonly',
|
||||
},
|
||||
}, null, 2));
|
||||
@@ -20,6 +20,7 @@
|
||||
"build:ui:production:webpack": "cross-env NODE_OPTIONS=--max_old_space_size=8192 node packages/ui-default/build --production",
|
||||
"test": "node -r @hydrooj/register packages/common/tests/subtask.spec.ts && node test/entry.js",
|
||||
"benchmark": "cross-env BENCHMARK=true node test/entry.js",
|
||||
"oxlint": "cd framework/eslint-config && node -r @hydrooj/register build.ts && cd ../../ && oxlint --config framework/eslint-config/.oxlintrc.json",
|
||||
"lint": "eslint packages plugins modules framework --ext .ts,.tsx,.jsx --fix",
|
||||
"lint:ci": "eslint packages plugins modules framework --ext .ts,.tsx,.jsx --max-warnings=0",
|
||||
"lint:ui": "yarn workspace @hydrooj/ui-default lint --ext .js,.ts,.jsx,.tsx . --fix",
|
||||
@@ -53,6 +54,7 @@
|
||||
"mongodb-memory-server": "10.1.4",
|
||||
"nyc": "^17.1.0",
|
||||
"ora": "^8.2.0",
|
||||
"oxlint": "^0.15.13",
|
||||
"package-json": "^10.0.1",
|
||||
"semver": "^7.7.1",
|
||||
"simple-git": "^3.27.0",
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
param, PRIV, Types, UserModel,
|
||||
} from 'hydrooj';
|
||||
|
||||
export const TYPE_BLOG: 70 = 70;
|
||||
export const TYPE_BLOG = 70 as const;
|
||||
export interface BlogDoc {
|
||||
docType: 70;
|
||||
docId: ObjectId;
|
||||
|
||||
@@ -85,7 +85,7 @@ function proc(params: Parameter): Cmd {
|
||||
copyOutCached.push('stdout', 'stderr');
|
||||
if (params.filename) copyOutCached.push(`${params.filename}.out?`);
|
||||
} else if (params.filename) copyOut.push(`${params.filename}.out${supportOptional ? '?' : ''}`);
|
||||
const copyIn = { ...(params.copyIn || {}) };
|
||||
const copyIn = { ...params.copyIn };
|
||||
const stdin = params.stdin || { content: '' };
|
||||
if (params.filename) copyIn[`${params.filename}.in`] = stdin;
|
||||
const time = params.time || 16000;
|
||||
|
||||
@@ -464,7 +464,7 @@ class OauthCallbackHandler extends Handler {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const set: Partial<Udoc> = { ...(r.set || {}), oauth: args.type };
|
||||
const set: Partial<Udoc> = { ...r.set, oauth: args.type };
|
||||
if (r.bio) set.bio = r.bio;
|
||||
if (r.viewLang) set.viewLang = r.viewLang;
|
||||
if (r.avatar) set.avatar = r.avatar;
|
||||
|
||||
@@ -101,7 +101,7 @@ export const PERM = {
|
||||
PERM_NEVER: 1n << 60n,
|
||||
};
|
||||
|
||||
export const Permission = (family: string, key: BigInt, desc: string) => ({ family, key, desc });
|
||||
export const Permission = (family: string, key: bigint, desc: string) => ({ family, key, desc });
|
||||
|
||||
export const PERMS = [
|
||||
Permission('perm_general', PERM.PERM_VIEW, 'View this domain'),
|
||||
|
||||
@@ -15,22 +15,22 @@ import { ArrayKeys, MaybeArray, NumberKeys, Projection } from '../typeutils';
|
||||
import { buildProjection } from '../utils';
|
||||
|
||||
type DocID = ObjectId | string | number;
|
||||
type NormalArrayKeys<O, P = any> = Exclude<ArrayKeys<O, P>, Symbol>;
|
||||
type NormalArrayKeys<O, P = any> = Exclude<ArrayKeys<O, P>, symbol>;
|
||||
|
||||
export const coll = db.collection('document');
|
||||
export const collStatus = db.collection('document.status');
|
||||
|
||||
export const TYPE_PROBLEM: 10 = 10;
|
||||
export const TYPE_PROBLEM_SOLUTION: 11 = 11;
|
||||
export const TYPE_PROBLEM_LIST: 12 = 12;
|
||||
export const TYPE_DISCUSSION_NODE: 20 = 20;
|
||||
export const TYPE_DISCUSSION: 21 = 21;
|
||||
export const TYPE_DISCUSSION_REPLY: 22 = 22;
|
||||
export const TYPE_CONTEST: 30 = 30;
|
||||
export const TYPE_CONTEST_CLARIFICATION: 31 = 31;
|
||||
export const TYPE_TRAINING: 40 = 40;
|
||||
export const TYPE_PROBLEM = 10 as const;
|
||||
export const TYPE_PROBLEM_SOLUTION = 11 as const;
|
||||
export const TYPE_PROBLEM_LIST = 12 as const;
|
||||
export const TYPE_DISCUSSION_NODE = 20 as const;
|
||||
export const TYPE_DISCUSSION = 21 as const;
|
||||
export const TYPE_DISCUSSION_REPLY = 22 as const;
|
||||
export const TYPE_CONTEST = 30 as const;
|
||||
export const TYPE_CONTEST_CLARIFICATION = 31 as const;
|
||||
export const TYPE_TRAINING = 40 as const;
|
||||
/** @deprecated use `TYPE_CONTEST` with rule `homework` instead. */
|
||||
export const TYPE_HOMEWORK: 60 = 60;
|
||||
export const TYPE_HOMEWORK = 60 as const;
|
||||
|
||||
export interface DocType {
|
||||
[TYPE_PROBLEM]: ProblemDoc;
|
||||
|
||||
@@ -58,4 +58,4 @@ export { EventMap } from './service/bus';
|
||||
export { db, pwsh };
|
||||
|
||||
// to load ctx.scoreboard
|
||||
export { } from './handler/contest';
|
||||
export { } from './handler/contest'; // eslint-disable-line @typescript-eslint/no-useless-empty-export
|
||||
@@ -242,6 +242,7 @@ export default class HMR extends Service {
|
||||
for (const [plugin, { filename, runtime }] of reloads) {
|
||||
try {
|
||||
this.ctx.registry.delete(attempts[filename]);
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await reload(plugin, runtime);
|
||||
} catch (err) {
|
||||
logger.warn(err);
|
||||
|
||||
@@ -51,7 +51,7 @@ export const coreScripts: MigrationScript[] = [
|
||||
return true;
|
||||
},
|
||||
// Init
|
||||
...new Array(28).fill(unsupportedUpgrade),
|
||||
...new Array(28).fill(unsupportedUpgrade), // oxlint-disable-line no-new-array
|
||||
async function _29_30() {
|
||||
return await iterateAllDomain((ddoc) => RecordModel.coll.updateMany({ domainId: ddoc._id }, { $set: { pdomain: ddoc._id } }));
|
||||
},
|
||||
|
||||
@@ -259,28 +259,27 @@ export function start(data: ResolverInput, options: DisplaySettings) {
|
||||
background: 'transparent',
|
||||
}),
|
||||
}}
|
||||
children={<>
|
||||
<div className="rank">{team.rank === -1 ? '⭐' : team.rank}</div>
|
||||
{props.showAvatar && <img className="avatar" src={`${teamInfo?.avatar}`} />}
|
||||
<div className="content">
|
||||
<div className="name">
|
||||
{props.showSchool ? `${teamInfo.institution} - ` : ''}{teamInfo.name}
|
||||
</div>
|
||||
<div className="problems">
|
||||
{data.problems.map((v) => {
|
||||
const uncover = team.id === selectedTeam && selectedProblem === v.id;
|
||||
const problemStatus = team.problems.find((idx) => idx.id === v.id);
|
||||
if (!problemStatus) return <span key={v.id} className="item">ERR</span>;
|
||||
return <span key={v.id} className={`${status(problemStatus)} ${uncover ? 'uncover' : ''} item`}>
|
||||
{submissions(problemStatus)}
|
||||
</span>;
|
||||
})}
|
||||
</div>
|
||||
>
|
||||
<div className="rank">{team.rank === -1 ? '⭐' : team.rank}</div>
|
||||
{props.showAvatar && <img className="avatar" src={`${teamInfo?.avatar}`} />}
|
||||
<div className="content">
|
||||
<div className="name">
|
||||
{props.showSchool ? `${teamInfo.institution} - ` : ''}{teamInfo.name}
|
||||
</div>
|
||||
<div className="solved">{team.score}</div>
|
||||
<div className="penalty">{team.penalty}</div>
|
||||
</>}
|
||||
/>;
|
||||
<div className="problems">
|
||||
{data.problems.map((v) => {
|
||||
const uncover = team.id === selectedTeam && selectedProblem === v.id;
|
||||
const problemStatus = team.problems.find((idx) => idx.id === v.id);
|
||||
if (!problemStatus) return <span key={v.id} className="item">ERR</span>;
|
||||
return <span key={v.id} className={`${status(problemStatus)} ${uncover ? 'uncover' : ''} item`}>
|
||||
{submissions(problemStatus)}
|
||||
</span>;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className="solved">{team.score}</div>
|
||||
<div className="penalty">{team.penalty}</div>
|
||||
</animated.div>;
|
||||
})}
|
||||
</>);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function createRegistry(ctx: Context) {
|
||||
function createMetric<Q extends string, T extends (new (a: any) => Metric<Q>)>(
|
||||
C: T, name: string, help: string, extra?: T extends new (a: infer R) => any ? Partial<R> : never,
|
||||
): T extends (new (a) => Gauge<Q>) ? Gauge<Q> : T extends (new (a) => Counter<Q>) ? Counter<Q> : Metric<Q> {
|
||||
const metric = new C({ name, help, ...(extra || {}) });
|
||||
const metric = new C({ name, help, ...extra });
|
||||
registry.registerMetric(metric);
|
||||
return metric as any;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as status from '@hydrooj/common/status';
|
||||
import { findFileSync } from '@hydrooj/utils/lib/utils';
|
||||
import { convert } from 'html-to-text';
|
||||
import {
|
||||
avatar, Context, fs, PERM, PRIV, Service, STATUS, yaml,
|
||||
avatar, Context, difficultyAlgorithm, fs, PERM, PRIV, Service, STATUS, yaml,
|
||||
} from 'hydrooj';
|
||||
import jsesc from 'jsesc';
|
||||
import nunjucks from 'nunjucks';
|
||||
@@ -134,6 +134,7 @@ class Nunjucks extends nunjucks.Environment {
|
||||
this.addGlobal('avatarUrl', avatar);
|
||||
this.addGlobal('formatSeconds', misc.formatSeconds);
|
||||
this.addGlobal('model', global.Hydro.model);
|
||||
this.addGlobal('lib', { difficulty: difficultyAlgorithm });
|
||||
this.addGlobal('ui', global.Hydro.ui);
|
||||
this.addGlobal('isIE', (str) => {
|
||||
if (!str) return false;
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function reducer(state = {}, action = {}) {
|
||||
return {
|
||||
...state,
|
||||
[to]: {
|
||||
...state[to] || {},
|
||||
...state[to],
|
||||
udoc,
|
||||
messages: [
|
||||
...state[to]?.messages || [],
|
||||
|
||||
@@ -242,7 +242,7 @@ const page = new NamedPage(['problem_detail', 'contest_detail_problem', 'homewor
|
||||
function ProblemNavigation() {
|
||||
[, setUpdate] = React.useState(0);
|
||||
return <div className="contest-problems" style={{ margin: '1em' }}>
|
||||
{pids.map((i) => <a href={`#p${i}`} className={ans[i] ? 'pending ' : ''}>
|
||||
{pids.map((i) => <a href={`#p${i}`} key={i} className={ans[i] ? 'pending ' : ''}>
|
||||
<span className="id">{i}</span>
|
||||
</a>)}
|
||||
</div>;
|
||||
|
||||
@@ -160,12 +160,12 @@ async function get(request: Request) {
|
||||
method: request.method,
|
||||
credentials: isResource ? 'same-origin' : 'include',
|
||||
headers: request.headers,
|
||||
body: request.body,
|
||||
redirect: request.redirect,
|
||||
keepalive: request.keepalive,
|
||||
referrer: request.referrer,
|
||||
referrerPolicy: request.referrerPolicy,
|
||||
signal: request.signal,
|
||||
...(request.method.toLowerCase() === 'get' ? {} : { body: request.body }),
|
||||
});
|
||||
if (r.ok) {
|
||||
console.log('Load success from ', source.toString());
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import importMetaUrlPlugin from '@codingame/esbuild-import-meta-url-plugin';
|
||||
import react from '@vitejs/plugin-react-swc';
|
||||
import c2k from 'koa2-connect';
|
||||
import fs from 'fs';
|
||||
import { createServer } from 'vite';
|
||||
import { } from '@hydrooj/framework';
|
||||
import { Context } from 'hydrooj';
|
||||
|
||||
Reference in new issue
Block a user