Skip to content

Commit 0e66362

Browse files
重构 contestData.d.ts
1 parent ed7de30 commit 0e66362

File tree

5 files changed

+92
-86
lines changed

5 files changed

+92
-86
lines changed

src/compiler/index.ts

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import remarkParse from "remark-parse";
77
import { unified } from "unified";
88
import remarkTypst from "./remarkTypst";
99
import { isAxiosError } from "axios";
10-
import type ContestData from "@/types/contestData";
10+
import type { ContestData } from "@/types/contestData";
1111
import {
1212
type CompileTypstMessage,
1313
type RenderTypstMessage,
@@ -45,11 +45,11 @@ async function downloadMultiData(
4545
percent: number;
4646
loaded: number;
4747
total: number | undefined;
48-
}) => void,
48+
}) => void
4949
) {
5050
const tasks = urls.map(
5151
(
52-
url,
52+
url
5353
): {
5454
loaded: number;
5555
total: number | undefined;
@@ -70,7 +70,7 @@ async function downloadMultiData(
7070
a == undefined || b.total === undefined
7171
? undefined
7272
: a + b.total,
73-
0,
73+
0
7474
);
7575
report({
7676
percent: totalSize ? (totalLoaded / totalSize) * 100 : 0,
@@ -83,11 +83,11 @@ async function downloadMultiData(
8383
url,
8484
new Response(res.data, {
8585
headers: { "Content-Type": "application/octet-stream" },
86-
}),
86+
})
8787
);
8888
return res.data;
8989
},
90-
}),
90+
})
9191
);
9292
return await Promise.all(tasks.map((x) => x.exec()));
9393
}
@@ -109,7 +109,7 @@ export class TypstInitTask {
109109
(e) => {
110110
this.status = "rejected";
111111
throw e;
112-
},
112+
}
113113
);
114114
}
115115
updateProgress(info: {
@@ -143,7 +143,7 @@ export const typstInitInfo: {
143143
} = {
144144
compiler: new TypstInitTask(
145145
downloadMultiData([TypstCompilerWasmUrl, TypstRendererWasmUrl], (x) =>
146-
typstInitInfo.compiler.updateProgress(x),
146+
typstInitInfo.compiler.updateProgress(x)
147147
).then(
148148
(res) => {
149149
typstCompilerWasm = res[0];
@@ -153,8 +153,8 @@ export const typstInitInfo: {
153153
(e) => {
154154
typstInitInfo.compiler.status = "rejected";
155155
throw e;
156-
},
157-
),
156+
}
157+
)
158158
),
159159
font: new TypstInitTask(
160160
(async () => {
@@ -174,7 +174,7 @@ export const typstInitInfo: {
174174
postscriptName: fontName,
175175
blob: () => cached.blob(),
176176
});
177-
}),
177+
})
178178
);
179179
if (unCachedFontUrlEntries.length && window.queryLocalFonts) {
180180
await requestFontAccessConfirm();
@@ -189,60 +189,60 @@ export const typstInitInfo: {
189189
blob: async () => {
190190
const blob = await x.blob();
191191
const fontUrl = unCachedFontUrlEntries.find(
192-
(v) => v[0] === x.postscriptName,
192+
(v) => v[0] === x.postscriptName
193193
)?.[1];
194194
if (fontUrl)
195195
browserCache.put(
196196
fontUrl,
197197
new Response(blob, {
198198
headers: { "Content-Type": "application/octet-stream" },
199-
}),
199+
})
200200
);
201201
return blob;
202202
},
203-
})),
203+
}))
204204
);
205205
} catch {
206206
// ignore
207207
}
208208
}
209209
for (const [fontName, fontUrl] of fontUrlEntries) {
210210
const fontData = localFontDatas.find(
211-
(x) => x.postscriptName === fontName,
211+
(x) => x.postscriptName === fontName
212212
);
213213
if (fontData)
214214
localFontPromises.push(
215-
fontData.blob().then(async (b) => await b.arrayBuffer()),
215+
fontData.blob().then(async (b) => await b.arrayBuffer())
216216
);
217217
else remoteFontUrls.push(fontUrl);
218218
}
219219
fontBuffers = (
220220
await Promise.all([
221221
...localFontPromises,
222222
downloadMultiData(remoteFontUrls, (x) =>
223-
typstInitInfo.font.updateProgress(x),
223+
typstInitInfo.font.updateProgress(x)
224224
),
225225
])
226226
).flat();
227-
})(),
227+
})()
228228
),
229229
package: new TypstInitTask(
230230
(async () => {
231231
const urls = RequiredPreloadPackages.map(
232232
(pkg) =>
233-
`https://packages.typst.org/preview/${pkg.name}-${pkg.version}.tar.gz`,
233+
`https://packages.typst.org/preview/${pkg.name}-${pkg.version}.tar.gz`
234234
);
235235
const datas = await downloadMultiData(urls, (x) =>
236-
typstInitInfo.package.updateProgress(x),
236+
typstInitInfo.package.updateProgress(x)
237237
);
238238
for (let i = 0; i < urls.length; ++i)
239239
preloadedPackages.set(urls[i], datas[i]);
240-
})(),
240+
})()
241241
),
242242
};
243243
export let typstInitStatus: PromiseStatus = "pending";
244244
export const typstInitPromise = Promise.all(
245-
Object.values(typstInitInfo).map((x) => x.promise),
245+
Object.values(typstInitInfo).map((x) => x.promise)
246246
)
247247
.then(async () => {
248248
await send<InitMessage>("init", worker, {
@@ -266,7 +266,7 @@ const processor = unified()
266266
.freeze();
267267

268268
function compilerPrepare(
269-
data: ContestData<{ withMarkdown: true }>,
269+
data: ContestData<{ withMarkdown: true }>
270270
): [ContestData<{ withTypst: true }>, [string, string][]] {
271271
const assets = new Map<string, string>();
272272
const problemsWithTypst = data.problems.map((problem) => {
@@ -376,15 +376,15 @@ async function fetchAsset(url: string): Promise<ArrayBuffer> {
376376
if (url.startsWith("asset://")) {
377377
const uuid = url.substring(8); // Remove "asset://" prefix
378378
const blobUrl = assetUrlMapping.get(uuid);
379-
379+
380380
if (!blobUrl) {
381381
throw new Error(`Asset not found: ${uuid}`);
382382
}
383-
383+
384384
// Fetch the blob URL using axios
385385
url = blobUrl;
386386
}
387-
387+
388388
// Handle regular URLs (including mapped blob URLs)
389389
try {
390390
const response = await axiosInstance.get<ArrayBuffer>(url);
@@ -393,7 +393,7 @@ async function fetchAsset(url: string): Promise<ArrayBuffer> {
393393
if (isAxiosError(e)) {
394394
console.error("Failed to download assets.", e);
395395
throw new Error(
396-
"下载资源失败。这或许是因为浏览器的跨域限制。你可以尝试手动上传图片。",
396+
"下载资源失败。这或许是因为浏览器的跨域限制。你可以尝试手动上传图片。"
397397
);
398398
}
399399
throw e;

src/compiler/typst.worker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
} from "@myriaddreamin/typst.ts/options.init";
1515
import { listen, sendToMain } from "@mr.python/promise-worker-ts";
1616
import { Mutex } from "async-mutex";
17-
import type ContestData from "../types/contestData";
17+
import type { ContestData } from "@/types/contestData";
1818

1919
import TypstDocMain from "typst-template/main.typ?raw";
2020
import TypstDocUtils from "typst-template/utils.typ?raw";

src/contestEditor/exampleStatements.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type ContestData from "@/types/contestData";
1+
import type { ContestData } from "@/types/contestData";
22

33
const exampleFiles = import.meta.glob<true, "raw">(
44
["./*/data.json", "./*/precaution.md", "./*/problem-*.md"],

src/contestEditor/preview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { memo, useEffect, useRef, useState } from "react";
2-
import type ContestData from "@/types/contestData";
2+
import type { ContestData } from "@/types/contestData";
33
import { compileToSvgDebounced } from "@/compiler";
44
import { Alert } from "antd";
55
import { isEqual } from "lodash";

src/types/contestData.d.ts

Lines changed: 62 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
export interface ProblemData {
1+
export type DateArr = [number, number, number, number, number, number];
2+
3+
export interface LanguageConfig {
4+
name: string;
5+
compile_options: string;
6+
}
7+
8+
export interface ProblemDataBase {
29
name: string;
310
title: string;
411
type: string;
@@ -14,80 +21,79 @@ export interface ProblemData {
1421
pretestcase: string;
1522
}
1623

17-
/** [year, month, day, hour, minute, second] */
18-
export type DateArr = [number, number, number, number, number, number];
24+
export type ContentFlags = {
25+
withMarkdown?: boolean;
26+
withTypst?: boolean;
27+
};
28+
29+
type MarkdownProblemExt<Conf extends ContentFlags> =
30+
Conf["withMarkdown"] extends true ? { statementMarkdown: string } : object;
31+
type TypstProblemExt<Conf extends ContentFlags> = Conf["withTypst"] extends true
32+
? { statementTypst: string }
33+
: object;
34+
35+
export type ProblemData<Conf extends ContentFlags = ContentFlags> =
36+
ProblemDataBase & MarkdownProblemExt<Conf> & TypstProblemExt<Conf>;
1937

20-
type ContestData<
21-
Conf extends {
22-
withMarkdown?: boolean;
23-
withTypst?: boolean;
24-
} = {
25-
withMarkdown: false;
26-
withTypst: false;
27-
},
28-
> = {
38+
export interface ContestDateRange {
39+
start: DateArr;
40+
end: DateArr;
41+
}
42+
43+
type MarkdownContestExt<Conf extends ContentFlags> =
44+
Conf["withMarkdown"] extends true ? { precautionMarkdown: string } : object;
45+
type TypstContestExt<Conf extends ContentFlags> = Conf["withTypst"] extends true
46+
? { precautionTypst: string }
47+
: object;
48+
49+
/**
50+
* 基础比赛配置(不含可选扩展)。
51+
*/
52+
export interface ContestDataBase<Conf extends ContentFlags = ContentFlags> {
2953
title: string;
3054
subtitle: string;
3155
dayname: string;
32-
date: {
33-
start: DateArr;
34-
end: DateArr;
35-
};
56+
date: ContestDateRange;
3657
noi_style: boolean;
3758
file_io: boolean;
3859
use_pretest: boolean;
39-
support_languages: {
40-
name: string;
41-
compile_options: string;
42-
}[];
43-
problems: (ProblemData &
44-
(Conf["withMarkdown"] extends true // with markdown
45-
? { statementMarkdown: string }
46-
: unknown) &
47-
(Conf["withTypst"] extends true // with typst
48-
? { statementTypst: string }
49-
: unknown))[];
50-
} & (Conf["withMarkdown"] extends true
51-
? { precautionMarkdown: string }
52-
: unknown) &
53-
(Conf["withTypst"] extends true ? { precautionTypst: string } : unknown);
54-
55-
export default ContestData;
60+
support_languages: LanguageConfig[];
61+
problems: ProblemData<Conf>[];
62+
}
5663

57-
export interface ImmerContestData extends ContestData<{ withMarkdown: true }> {
58-
problems: (ContestData<{ withMarkdown: true }>["problems"][number] & {
59-
key: import("crypto").UUID;
60-
})[];
61-
support_languages: (ContestData<{
62-
withMarkdown: true;
63-
}>["support_languages"][number] & {
64-
key: import("crypto").UUID;
65-
})[];
66-
images: {
67-
uuid: string;
68-
name: string;
69-
url: string; // blob URL for display
70-
}[];
64+
export type ContestData<
65+
Conf extends ContentFlags = { withMarkdown: false; withTypst: false },
66+
> = ContestDataBase<Conf> & MarkdownContestExt<Conf> & TypstContestExt<Conf>;
67+
68+
export type UILanguageConfig = LanguageConfig & { key: import("crypto").UUID };
69+
70+
export type UIProblemData<Conf extends ContentFlags = { withMarkdown: true }> =
71+
ProblemData<Conf> & { key: import("crypto").UUID };
72+
73+
export interface UIImageItem {
74+
uuid: string;
75+
name: string;
76+
url: string; // blob URL for display
7177
}
7278

7379
export interface EditorImageData {
7480
uuid: string;
7581
blob: Blob;
7682
}
7783

84+
export interface ImmerContestData extends ContestData<{ withMarkdown: true }> {
85+
problems: UIProblemData<{ withMarkdown: true }>[];
86+
support_languages: UILanguageConfig[];
87+
images: UIImageItem[];
88+
}
89+
7890
export interface StoredContestData extends ContestData<{ withMarkdown: true }> {
7991
images: {
8092
uuid: string;
8193
name: string;
8294
}[];
8395
}
8496

85-
export type ContestDataWithImages = Omit<ImmerContestData, "problems" | "support_languages" | "images"> & {
86-
images: {
87-
uuid: string;
88-
name: string;
89-
url: string; // blob URL for display (not stored in DB/export)
90-
}[];
91-
problems: Omit<ImmerContestData["problems"][number], "key">[];
92-
support_languages: Omit<ImmerContestData["support_languages"][number], "key">[];
93-
};
97+
export type ContestDataWithImages = ContestData<{ withMarkdown: true }> & {
98+
images: UIImageItem[];
99+
};

0 commit comments

Comments
 (0)