mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
workspace: add oxlint
This commit is contained in:
18 files changed
+102
-26
No files matched your search
@@ -30,6 +30,7 @@ yarn.lock
|
|||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
tsconfig.json
|
tsconfig.json
|
||||||
tsconfig.*.json
|
tsconfig.*.json
|
||||||
|
.oxlintrc.json
|
||||||
|
|
||||||
# Project Rules
|
# Project Rules
|
||||||
## Core
|
## 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",
|
"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",
|
"test": "node -r @hydrooj/register packages/common/tests/subtask.spec.ts && node test/entry.js",
|
||||||
"benchmark": "cross-env BENCHMARK=true 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": "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: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",
|
"lint:ui": "yarn workspace @hydrooj/ui-default lint --ext .js,.ts,.jsx,.tsx . --fix",
|
||||||
@@ -53,6 +54,7 @@
|
|||||||
"mongodb-memory-server": "10.1.4",
|
"mongodb-memory-server": "10.1.4",
|
||||||
"nyc": "^17.1.0",
|
"nyc": "^17.1.0",
|
||||||
"ora": "^8.2.0",
|
"ora": "^8.2.0",
|
||||||
|
"oxlint": "^0.15.13",
|
||||||
"package-json": "^10.0.1",
|
"package-json": "^10.0.1",
|
||||||
"semver": "^7.7.1",
|
"semver": "^7.7.1",
|
||||||
"simple-git": "^3.27.0",
|
"simple-git": "^3.27.0",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
param, PRIV, Types, UserModel,
|
param, PRIV, Types, UserModel,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
|
|
||||||
export const TYPE_BLOG: 70 = 70;
|
export const TYPE_BLOG = 70 as const;
|
||||||
export interface BlogDoc {
|
export interface BlogDoc {
|
||||||
docType: 70;
|
docType: 70;
|
||||||
docId: ObjectId;
|
docId: ObjectId;
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ function proc(params: Parameter): Cmd {
|
|||||||
copyOutCached.push('stdout', 'stderr');
|
copyOutCached.push('stdout', 'stderr');
|
||||||
if (params.filename) copyOutCached.push(`${params.filename}.out?`);
|
if (params.filename) copyOutCached.push(`${params.filename}.out?`);
|
||||||
} else if (params.filename) copyOut.push(`${params.filename}.out${supportOptional ? '?' : ''}`);
|
} else if (params.filename) copyOut.push(`${params.filename}.out${supportOptional ? '?' : ''}`);
|
||||||
const copyIn = { ...(params.copyIn || {}) };
|
const copyIn = { ...params.copyIn };
|
||||||
const stdin = params.stdin || { content: '' };
|
const stdin = params.stdin || { content: '' };
|
||||||
if (params.filename) copyIn[`${params.filename}.in`] = stdin;
|
if (params.filename) copyIn[`${params.filename}.in`] = stdin;
|
||||||
const time = params.time || 16000;
|
const time = params.time || 16000;
|
||||||
|
|||||||
@@ -464,7 +464,7 @@ class OauthCallbackHandler extends Handler {
|
|||||||
break;
|
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.bio) set.bio = r.bio;
|
||||||
if (r.viewLang) set.viewLang = r.viewLang;
|
if (r.viewLang) set.viewLang = r.viewLang;
|
||||||
if (r.avatar) set.avatar = r.avatar;
|
if (r.avatar) set.avatar = r.avatar;
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export const PERM = {
|
|||||||
PERM_NEVER: 1n << 60n,
|
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 = [
|
export const PERMS = [
|
||||||
Permission('perm_general', PERM.PERM_VIEW, 'View this domain'),
|
Permission('perm_general', PERM.PERM_VIEW, 'View this domain'),
|
||||||
|
|||||||
@@ -15,22 +15,22 @@ import { ArrayKeys, MaybeArray, NumberKeys, Projection } from '../typeutils';
|
|||||||
import { buildProjection } from '../utils';
|
import { buildProjection } from '../utils';
|
||||||
|
|
||||||
type DocID = ObjectId | string | number;
|
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 coll = db.collection('document');
|
||||||
export const collStatus = db.collection('document.status');
|
export const collStatus = db.collection('document.status');
|
||||||
|
|
||||||
export const TYPE_PROBLEM: 10 = 10;
|
export const TYPE_PROBLEM = 10 as const;
|
||||||
export const TYPE_PROBLEM_SOLUTION: 11 = 11;
|
export const TYPE_PROBLEM_SOLUTION = 11 as const;
|
||||||
export const TYPE_PROBLEM_LIST: 12 = 12;
|
export const TYPE_PROBLEM_LIST = 12 as const;
|
||||||
export const TYPE_DISCUSSION_NODE: 20 = 20;
|
export const TYPE_DISCUSSION_NODE = 20 as const;
|
||||||
export const TYPE_DISCUSSION: 21 = 21;
|
export const TYPE_DISCUSSION = 21 as const;
|
||||||
export const TYPE_DISCUSSION_REPLY: 22 = 22;
|
export const TYPE_DISCUSSION_REPLY = 22 as const;
|
||||||
export const TYPE_CONTEST: 30 = 30;
|
export const TYPE_CONTEST = 30 as const;
|
||||||
export const TYPE_CONTEST_CLARIFICATION: 31 = 31;
|
export const TYPE_CONTEST_CLARIFICATION = 31 as const;
|
||||||
export const TYPE_TRAINING: 40 = 40;
|
export const TYPE_TRAINING = 40 as const;
|
||||||
/** @deprecated use `TYPE_CONTEST` with rule `homework` instead. */
|
/** @deprecated use `TYPE_CONTEST` with rule `homework` instead. */
|
||||||
export const TYPE_HOMEWORK: 60 = 60;
|
export const TYPE_HOMEWORK = 60 as const;
|
||||||
|
|
||||||
export interface DocType {
|
export interface DocType {
|
||||||
[TYPE_PROBLEM]: ProblemDoc;
|
[TYPE_PROBLEM]: ProblemDoc;
|
||||||
|
|||||||
@@ -58,4 +58,4 @@ export { EventMap } from './service/bus';
|
|||||||
export { db, pwsh };
|
export { db, pwsh };
|
||||||
|
|
||||||
// to load ctx.scoreboard
|
// 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) {
|
for (const [plugin, { filename, runtime }] of reloads) {
|
||||||
try {
|
try {
|
||||||
this.ctx.registry.delete(attempts[filename]);
|
this.ctx.registry.delete(attempts[filename]);
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
await reload(plugin, runtime);
|
await reload(plugin, runtime);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn(err);
|
logger.warn(err);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export const coreScripts: MigrationScript[] = [
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
// Init
|
// Init
|
||||||
...new Array(28).fill(unsupportedUpgrade),
|
...new Array(28).fill(unsupportedUpgrade), // oxlint-disable-line no-new-array
|
||||||
async function _29_30() {
|
async function _29_30() {
|
||||||
return await iterateAllDomain((ddoc) => RecordModel.coll.updateMany({ domainId: ddoc._id }, { $set: { pdomain: ddoc._id } }));
|
return await iterateAllDomain((ddoc) => RecordModel.coll.updateMany({ domainId: ddoc._id }, { $set: { pdomain: ddoc._id } }));
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ export function start(data: ResolverInput, options: DisplaySettings) {
|
|||||||
background: 'transparent',
|
background: 'transparent',
|
||||||
}),
|
}),
|
||||||
}}
|
}}
|
||||||
children={<>
|
>
|
||||||
<div className="rank">{team.rank === -1 ? '⭐' : team.rank}</div>
|
<div className="rank">{team.rank === -1 ? '⭐' : team.rank}</div>
|
||||||
{props.showAvatar && <img className="avatar" src={`${teamInfo?.avatar}`} />}
|
{props.showAvatar && <img className="avatar" src={`${teamInfo?.avatar}`} />}
|
||||||
<div className="content">
|
<div className="content">
|
||||||
@@ -279,8 +279,7 @@ export function start(data: ResolverInput, options: DisplaySettings) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="solved">{team.score}</div>
|
<div className="solved">{team.score}</div>
|
||||||
<div className="penalty">{team.penalty}</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>)>(
|
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,
|
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> {
|
): 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);
|
registry.registerMetric(metric);
|
||||||
return metric as any;
|
return metric as any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as status from '@hydrooj/common/status';
|
|||||||
import { findFileSync } from '@hydrooj/utils/lib/utils';
|
import { findFileSync } from '@hydrooj/utils/lib/utils';
|
||||||
import { convert } from 'html-to-text';
|
import { convert } from 'html-to-text';
|
||||||
import {
|
import {
|
||||||
avatar, Context, fs, PERM, PRIV, Service, STATUS, yaml,
|
avatar, Context, difficultyAlgorithm, fs, PERM, PRIV, Service, STATUS, yaml,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
import jsesc from 'jsesc';
|
import jsesc from 'jsesc';
|
||||||
import nunjucks from 'nunjucks';
|
import nunjucks from 'nunjucks';
|
||||||
@@ -134,6 +134,7 @@ class Nunjucks extends nunjucks.Environment {
|
|||||||
this.addGlobal('avatarUrl', avatar);
|
this.addGlobal('avatarUrl', avatar);
|
||||||
this.addGlobal('formatSeconds', misc.formatSeconds);
|
this.addGlobal('formatSeconds', misc.formatSeconds);
|
||||||
this.addGlobal('model', global.Hydro.model);
|
this.addGlobal('model', global.Hydro.model);
|
||||||
|
this.addGlobal('lib', { difficulty: difficultyAlgorithm });
|
||||||
this.addGlobal('ui', global.Hydro.ui);
|
this.addGlobal('ui', global.Hydro.ui);
|
||||||
this.addGlobal('isIE', (str) => {
|
this.addGlobal('isIE', (str) => {
|
||||||
if (!str) return false;
|
if (!str) return false;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export default function reducer(state = {}, action = {}) {
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
[to]: {
|
[to]: {
|
||||||
...state[to] || {},
|
...state[to],
|
||||||
udoc,
|
udoc,
|
||||||
messages: [
|
messages: [
|
||||||
...state[to]?.messages || [],
|
...state[to]?.messages || [],
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ const page = new NamedPage(['problem_detail', 'contest_detail_problem', 'homewor
|
|||||||
function ProblemNavigation() {
|
function ProblemNavigation() {
|
||||||
[, setUpdate] = React.useState(0);
|
[, setUpdate] = React.useState(0);
|
||||||
return <div className="contest-problems" style={{ margin: '1em' }}>
|
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>
|
<span className="id">{i}</span>
|
||||||
</a>)}
|
</a>)}
|
||||||
</div>;
|
</div>;
|
||||||
|
|||||||
@@ -160,12 +160,12 @@ async function get(request: Request) {
|
|||||||
method: request.method,
|
method: request.method,
|
||||||
credentials: isResource ? 'same-origin' : 'include',
|
credentials: isResource ? 'same-origin' : 'include',
|
||||||
headers: request.headers,
|
headers: request.headers,
|
||||||
body: request.body,
|
|
||||||
redirect: request.redirect,
|
redirect: request.redirect,
|
||||||
keepalive: request.keepalive,
|
keepalive: request.keepalive,
|
||||||
referrer: request.referrer,
|
referrer: request.referrer,
|
||||||
referrerPolicy: request.referrerPolicy,
|
referrerPolicy: request.referrerPolicy,
|
||||||
signal: request.signal,
|
signal: request.signal,
|
||||||
|
...(request.method.toLowerCase() === 'get' ? {} : { body: request.body }),
|
||||||
});
|
});
|
||||||
if (r.ok) {
|
if (r.ok) {
|
||||||
console.log('Load success from ', source.toString());
|
console.log('Load success from ', source.toString());
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import importMetaUrlPlugin from '@codingame/esbuild-import-meta-url-plugin';
|
import importMetaUrlPlugin from '@codingame/esbuild-import-meta-url-plugin';
|
||||||
import react from '@vitejs/plugin-react-swc';
|
import react from '@vitejs/plugin-react-swc';
|
||||||
import c2k from 'koa2-connect';
|
import c2k from 'koa2-connect';
|
||||||
import fs from 'fs';
|
|
||||||
import { createServer } from 'vite';
|
import { createServer } from 'vite';
|
||||||
import { } from '@hydrooj/framework';
|
import { } from '@hydrooj/framework';
|
||||||
import { Context } from 'hydrooj';
|
import { Context } from 'hydrooj';
|
||||||
|
|||||||
Reference in new issue
Block a user