workspace: use esnext set operations

This commit is contained in:
undefined committed 2026-04-05 23:12:48 +08:00
1 parent bf5533040e
commit 9c10219ecb
12 files changed
+28 -43

No files matched your search

+3 -3
View File
@@ -16,7 +16,7 @@ const withoutTypes = (data) => ({
/** @type {import('typescript/lib/typescript').CompilerOptions} */ /** @type {import('typescript/lib/typescript').CompilerOptions} */
const compilerOptionsBase = { const compilerOptionsBase = {
target: 'es2022', target: 'es2022',
lib: ['es2022'], lib: ['esnext'],
module: 'preserve', module: 'preserve',
esModuleInterop: true, esModuleInterop: true,
moduleResolution: 'bundler', moduleResolution: 'bundler',
@@ -106,7 +106,7 @@ const UIConfig = {
outDir: path.join(baseOutDir, 'ui'), outDir: path.join(baseOutDir, 'ui'),
useDefineForClassFields: true, useDefineForClassFields: true,
lib: ['es2022', 'DOM', 'DOM.Iterable'], lib: ['esnext', 'DOM', 'DOM.Iterable'],
/* Bundler mode */ /* Bundler mode */
moduleResolution: 'bundler', moduleResolution: 'bundler',
@@ -143,7 +143,7 @@ const UINextConfig = {
noImplicitAny: false, noImplicitAny: false,
useDefineForClassFields: true, useDefineForClassFields: true,
lib: ['es2022', 'DOM', 'DOM.Iterable'], lib: ['esnext', 'DOM', 'DOM.Iterable'],
/* Bundler mode */ /* Bundler mode */
moduleResolution: 'bundler', moduleResolution: 'bundler',
+5 -14
View File
@@ -7,11 +7,6 @@ declare global {
interface Math { interface Math {
sum: (...args: Array<number[] | number>) => number; sum: (...args: Array<number[] | number>) => number;
} }
interface SetConstructor {
isSuperset: (set: Set<any>, subset: Set<any> | Array<any>) => boolean;
intersection: <T>(setA: Set<T> | Array<T>, setB: Set<T> | Array<T>) => Set<T>;
union: <T>(setA: Set<T> | Array<T>, setB: Set<T> | Array<T>) => Set<T>;
}
} }
const defaultDict = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; const defaultDict = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
@@ -21,10 +16,6 @@ export function randomstring(digit = 32, dict = defaultDict) {
for (let i = 1; i <= digit; i++) str += dict[Math.floor(Math.random() * dict.length)]; for (let i = 1; i <= digit; i++) str += dict[Math.floor(Math.random() * dict.length)];
return str; return str;
} }
try {
// @ts-ignore
String.random = randomstring;
} catch (e) { } // Cannot add property random, object is not extensible
String.prototype.format ||= function formatStr(...args) { String.prototype.format ||= function formatStr(...args) {
let result = this; let result = this;
@@ -68,11 +59,6 @@ export function diffArray(a, b) {
return false; return false;
} }
try {
// @ts-ignore
Array.isDiff = diffArray;
} catch (e) { } // Cannot add property isDiff, object is not extensible
export function formatDate(date: Date, fmt = '%Y-%m-%d %H:%M:%S') { export function formatDate(date: Date, fmt = '%Y-%m-%d %H:%M:%S') {
let m = (date.getMonth() + 1).toString(); let m = (date.getMonth() + 1).toString();
if (m.length < 2) m = `0${m}`; if (m.length < 2) m = `0${m}`;
@@ -105,6 +91,9 @@ Math.sum = function sum(...args) {
return s; return s;
}; };
// TODO: remove these
// @ts-ignore
Set.isSuperset = function isSuperset(set, subset) { Set.isSuperset = function isSuperset(set, subset) {
for (const elem of subset) { for (const elem of subset) {
if (!set.has(elem)) return false; if (!set.has(elem)) return false;
@@ -112,12 +101,14 @@ Set.isSuperset = function isSuperset(set, subset) {
return true; return true;
}; };
// @ts-ignore
Set.union = function Union<T>(setA: Set<T> | Array<T>, setB: Set<T> | Array<T>) { Set.union = function Union<T>(setA: Set<T> | Array<T>, setB: Set<T> | Array<T>) {
const union = new Set(setA); const union = new Set(setA);
for (const elem of setB) union.add(elem); for (const elem of setB) union.add(elem);
return union; return union;
}; };
// @ts-ignore
Set.intersection = function Intersection<T>(A: Set<T> | Array<T> = [], B: Set<T> | Array<T> = []) { Set.intersection = function Intersection<T>(A: Set<T> | Array<T> = [], B: Set<T> | Array<T> = []) {
const intersection = new Set<T>(); const intersection = new Set<T>();
if (A instanceof Array) A = new Set(A); if (A instanceof Array) A = new Set(A);
+2 -2
View File
@@ -66,8 +66,8 @@ export async function judge({
if (stdAns instanceof Array) { if (stdAns instanceof Array) {
const stdSet = new Set(stdAns); const stdSet = new Set(stdAns);
const ans = new Set(answers[key] instanceof Array ? answers[key] : [answers[key]]); const ans = new Set(answers[key] instanceof Array ? answers[key] : [answers[key]]);
if (stdAns.length === ans.size && Set.isSuperset(stdSet, ans)) report(STATUS.STATUS_ACCEPTED, fullScore, 'Correct'); if (stdAns.length === ans.size && stdSet.isSupersetOf(ans)) report(STATUS.STATUS_ACCEPTED, fullScore, 'Correct');
else if (ans.size && Set.isSuperset(stdSet, ans)) report(STATUS.STATUS_WRONG_ANSWER, Math.floor(fullScore / 2), 'Partially Correct'); else if (ans.size && stdSet.isSupersetOf(ans)) report(STATUS.STATUS_WRONG_ANSWER, Math.floor(fullScore / 2), 'Partially Correct');
else report(STATUS.STATUS_WRONG_ANSWER, 0, 'Incorrect'); else report(STATUS.STATUS_WRONG_ANSWER, 0, 'Incorrect');
} else if (stdAns.toString() === usrAns) report(STATUS.STATUS_ACCEPTED, fullScore, 'Correct'); } else if (stdAns.toString() === usrAns) report(STATUS.STATUS_ACCEPTED, fullScore, 'Correct');
else report(STATUS.STATUS_WRONG_ANSWER, 0, 'Incorrect'); else report(STATUS.STATUS_WRONG_ANSWER, 0, 'Incorrect');
+1 -1
View File
@@ -88,7 +88,7 @@ export class ContestDetailBaseHandler extends Handler {
]); ]);
if (this.tdoc.assign?.length && !this.user.own(this.tdoc) && !this.user.hasPerm(PERM.PERM_VIEW_HIDDEN_CONTEST)) { if (this.tdoc.assign?.length && !this.user.own(this.tdoc) && !this.user.hasPerm(PERM.PERM_VIEW_HIDDEN_CONTEST)) {
const groups = await user.listGroup(domainId, this.user._id); const groups = await user.listGroup(domainId, this.user._id);
if (!Set.intersection(this.tdoc.assign, groups.map((i) => i.name)).size) { if (!new Set(this.tdoc.assign).intersection(new Set(groups.map((i) => i.name))).size) {
throw new NotAssignedError('contest', tid); throw new NotAssignedError('contest', tid);
} }
} }
+1 -1
View File
@@ -261,7 +261,7 @@ class DomainRoleHandler extends ManageHandler {
@requireSudo @requireSudo
@param('roles', Types.ArrayOf(Types.Role)) @param('roles', Types.ArrayOf(Types.Role))
async postDelete(domainId: string, roles: string[]) { async postDelete(domainId: string, roles: string[]) {
if (Set.intersection(roles, ['root', 'default', 'guest']).size > 0) { if (new Set(roles).intersection(new Set(['root', 'default', 'guest'])).size > 0) {
throw new ValidationError('role', null, 'You cannot delete root, default or guest roles'); throw new ValidationError('role', null, 'You cannot delete root, default or guest roles');
} }
await Promise.all([ await Promise.all([
+1 -1
View File
@@ -84,7 +84,7 @@ class HomeworkDetailHandler extends Handler {
this.tdoc = await contest.get(domainId, tid); this.tdoc = await contest.get(domainId, tid);
if (this.tdoc.rule !== 'homework') throw new ContestNotFoundError(domainId, tid); if (this.tdoc.rule !== 'homework') throw new ContestNotFoundError(domainId, tid);
if (this.tdoc.assign?.length && !this.user.own(this.tdoc) && !this.user.hasPerm(PERM.PERM_VIEW_HIDDEN_HOMEWORK)) { if (this.tdoc.assign?.length && !this.user.own(this.tdoc) && !this.user.hasPerm(PERM.PERM_VIEW_HIDDEN_HOMEWORK)) {
if (!Set.intersection(this.tdoc.assign, this.user.group).size) { if (!new Set(this.tdoc.assign).intersection(new Set(this.user.group)).size) {
throw new NotAssignedError('homework', this.tdoc.docId); throw new NotAssignedError('homework', this.tdoc.docId);
} }
} }
+1 -1
View File
@@ -418,7 +418,7 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler {
contest.getRelated(this.args.domainId, this.pdoc.docId), contest.getRelated(this.args.domainId, this.pdoc.docId),
contest.getRelated(this.args.domainId, this.pdoc.docId, 'homework'), contest.getRelated(this.args.domainId, this.pdoc.docId, 'homework'),
])).map((tdocs) => tdocs.filter((tdoc) => ])).map((tdocs) => tdocs.filter((tdoc) =>
this.user.hasPerm(PERM.PERM_VIEW_HIDDEN_CONTEST) || !tdoc.assign?.length || Set.intersection(tdoc.assign, this.user.group).size, this.user.hasPerm(PERM.PERM_VIEW_HIDDEN_CONTEST) || !tdoc.assign?.length || new Set(tdoc.assign).intersection(new Set(this.user.group)).size,
)); ));
} }
} }
+1 -1
View File
@@ -138,7 +138,7 @@ class TrainingDetailHandler extends Handler {
for (const node of tdoc.dag) { for (const node of tdoc.dag) {
ndict[node._id] = node; ndict[node._id] = node;
const totalCount = node.pids.length; const totalCount = node.pids.length;
const doneCount = Set.intersection(node.pids, donePids).size; const doneCount = new Set(node.pids).intersection(new Set(donePids)).size;
const nsdoc = { const nsdoc = {
progress: totalCount ? Math.floor(100 * (doneCount / totalCount)) : 100, progress: totalCount ? Math.floor(100 * (doneCount / totalCount)) : 100,
isDone: training.isDone(node, doneNids, donePids), isDone: training.isDone(node, doneNids, donePids),
+2 -2
View File
@@ -313,7 +313,7 @@ export async function getListVnodes(domainId: string, ddocs: any, getHidden = fa
const vnode = await getVnode(domainId, ddoc.parentType, ddoc.parentId.toString()); const vnode = await getVnode(domainId, ddoc.parentType, ddoc.parentId.toString());
res[ddoc.parentType] ||= {}; res[ddoc.parentType] ||= {};
if (!getHidden && vnode.hidden) return; if (!getHidden && vnode.hidden) return;
if (vnode.assign?.length && Set.intersection(vnode.assign, assign).size) return; if (vnode.assign?.length && new Set(vnode.assign).intersection(new Set(assign)).size) return;
res[ddoc.parentType][ddoc.parentId] = vnode; res[ddoc.parentType][ddoc.parentId] = vnode;
} }
await Promise.all(ddocs.map((ddoc) => task(ddoc))); await Promise.all(ddocs.map((ddoc) => task(ddoc)));
@@ -325,7 +325,7 @@ export function checkVNodeVisibility(type: number, vnode: any, user: User) {
if (vnode.hidden && !user.own(vnode) && !user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) return false; if (vnode.hidden && !user.own(vnode) && !user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) return false;
} }
if ([document.TYPE_CONTEST, document.TYPE_TRAINING].includes(type as any)) { if ([document.TYPE_CONTEST, document.TYPE_TRAINING].includes(type as any)) {
if (!user.own(vnode) && vnode.assign?.length && !Set.intersection(vnode.assign, user.group).size) return false; if (!user.own(vnode) && vnode.assign?.length && !new Set(vnode.assign).intersection(new Set(user.group)).size) return false;
} }
return true; return true;
} }
+9 -15
View File
@@ -63,30 +63,24 @@ export function getPids(dag: TrainingNode[]) {
} }
export function isDone(node: TrainingNode, doneNids: Set<number> | number[], donePids: Set<number> | number[]) { export function isDone(node: TrainingNode, doneNids: Set<number> | number[], donePids: Set<number> | number[]) {
return (Set.isSuperset(new Set(doneNids), new Set(node.requireNids)) return new Set(doneNids).isSupersetOf(new Set(node.requireNids))
&& Set.isSuperset(new Set(donePids), new Set(node.pids))); && new Set(donePids).isSupersetOf(new Set(node.pids));
} }
export function isProgress(node: TrainingNode, doneNids: Set<number> | number[], donePids: Set<number> | number[], progPids: Set<number> | number[]) { export function isProgress(node: TrainingNode, doneNids: Set<number> | number[], donePids: Set<number> | number[], progPids: Set<number> | number[]) {
return (Set.isSuperset(new Set(doneNids), new Set(node.requireNids)) return new Set(doneNids).isSupersetOf(new Set(node.requireNids))
&& !Set.isSuperset(new Set(donePids), new Set(node.pids)) && !new Set(donePids).isSupersetOf(new Set(node.pids))
&& Set.intersection( && new Set(donePids).union(new Set(progPids)).intersection(new Set(node.pids)).size;
Set.union(new Set(donePids), new Set(progPids)),
new Set(node.pids),
).size);
} }
export function isOpen(node: TrainingNode, doneNids: Set<number> | number[], donePids: Set<number> | number[], progPids: Set<number> | number[]) { export function isOpen(node: TrainingNode, doneNids: Set<number> | number[], donePids: Set<number> | number[], progPids: Set<number> | number[]) {
return (Set.isSuperset(new Set(doneNids), new Set(node.requireNids)) return new Set(doneNids).isSupersetOf(new Set(node.requireNids))
&& !Set.isSuperset(new Set(donePids), new Set(node.pids)) && !new Set(donePids).isSupersetOf(new Set(node.pids))
&& !Set.intersection( && !new Set(donePids).union(new Set(progPids)).intersection(new Set(node.pids)).size;
Set.union(new Set(donePids), new Set(progPids)),
new Set(node.pids),
).size);
} }
export const isInvalid = (node: TrainingNode, doneNids: Set<number> | number[]) => export const isInvalid = (node: TrainingNode, doneNids: Set<number> | number[]) =>
!Set.isSuperset(new Set(doneNids), new Set(node.requireNids)); !new Set(doneNids).isSupersetOf(new Set(node.requireNids));
export async function count(domainId: string, query: Filter<TrainingDoc>) { export async function count(domainId: string, query: Filter<TrainingDoc>) {
return await document.count(domainId, document.TYPE_TRAINING, query); return await document.count(domainId, document.TYPE_TRAINING, query);
+1 -1
View File
@@ -132,7 +132,7 @@
"html-to-text": "^9.0.5", "html-to-text": "^9.0.5",
"js-yaml": "^4.1.1", "js-yaml": "^4.1.1",
"jsesc": "^3.1.0", "jsesc": "^3.1.0",
"katex": "^0.16.44", "katex": "^0.16.45",
"lodash": "^4.18.1", "lodash": "^4.18.1",
"markdown-it": "^14.1.1", "markdown-it": "^14.1.1",
"markdown-it-anchor": "^9.2.0", "markdown-it-anchor": "^9.2.0",
+1 -1
View File
@@ -27,7 +27,7 @@ class AccountService {
this.api = new Provider(account, async (data) => { this.api = new Provider(account, async (data) => {
await coll.updateOne({ _id: account._id }, { $set: data }); await coll.updateOne({ _id: account._id }, { $set: data });
}); });
this.problemLists = Set.union(this.api.entryProblemLists || ['main'], this.account.problemLists || []); this.problemLists = new Set(this.api.entryProblemLists || ['main']).union(new Set(this.account.problemLists || []));
this.main().catch((e) => { this.main().catch((e) => {
logger.error(`Error occured in ${account.type}/${account.handle}`); logger.error(`Error occured in ${account.type}/${account.handle}`);
this.working = false; this.working = false;