Switch some js files to ts for better typing

Signed-off-by: Harry Chen <i@harrychen.xyz>
This commit is contained in:
Harry Chen 2024-04-15 21:45:09 +08:00 committed by Miao Wang
parent beaf2b19d0
commit 7328ec3415
16 changed files with 150 additions and 40 deletions

2
.gitignore vendored
View File

@ -17,4 +17,4 @@
/node_modules/
/.jekyll-cache/
_stats.html
/_src/components.d.ts

View File

@ -1,6 +1,6 @@
import Mark from "markup-js";
function fancyIndexRender(r, templateUrl) {
function fancyIndexRender(r: NginxHTTPRequest, templateUrl: string) {
r.subrequest(
templateUrl,
{
@ -25,10 +25,10 @@ function fancyIndexRender(r, templateUrl) {
);
}
export function fancyIndexBeforeRender(r) {
export function fancyIndexBeforeRender(r: NginxHTTPRequest) {
return fancyIndexRender(r, "/fancy-index/before.html");
}
export function fancyIndexAfterRender(r) {
export function fancyIndexAfterRender(r: NginxHTTPRequest) {
return fancyIndexRender(r, "/fancy-index/after.html");
}

View File

@ -1,9 +1,9 @@
import "../lib/njs-polyfill.js";
import "../lib/njs-polyfill";
import Mark from "markup-js";
import processingHandlers from "../lib/mirrorListDataProcessing";
import { TUNASYNC_JSON_PATH } from "../lib/consts";
export function legacyIndexRender(r) {
export function legacyIndexRender(r: NginxHTTPRequest) {
r.subrequest(
"/legacy_index.html",
{

View File

@ -1,4 +1,5 @@
import "../styles/global.scss";
// @ts-ignore
import { suffix as siteSuffix } from "virtual:jekyll-config";
import { load as loadWebFont } from "webfontloader";
@ -17,7 +18,7 @@ const lei3Po8h = ["support", ["tuna", "tsinghua", "edu", "cn"].join(".")].join(
);
Array.from(document.querySelectorAll("a.eib1gieB")).forEach((el) => {
el.textContent = lei3Po8h;
el.href = ["ma", "ilto:"].join("i") + lei3Po8h;
el["href"] = ["ma", "ilto:"].join("i") + lei3Po8h;
});
loadWebFont({

View File

@ -7,7 +7,7 @@ import { createApp } from "vue";
document.getElementById("list").setAttribute("class", "table");
Array.from(document.querySelectorAll("#list tbody tr td:nth-child(3)")).forEach(
(el) => {
const d = new Date(el.innerText);
const d = new Date(el["innerText"]);
if (!isNaN(d.getTime())) {
const date_str =
("000" + d.getFullYear()).substr(-4) +
@ -19,7 +19,7 @@ Array.from(document.querySelectorAll("#list tbody tr td:nth-child(3)")).forEach(
("0" + d.getHours()).substr(-2) +
":" +
("0" + d.getMinutes()).substr(-2));
el.innerText = date_str;
el["innerText"] = date_str;
}
},
);

View File

@ -1,8 +1,9 @@
import {
hide_mirrorz as HideMirrorZ,
hostname as SiteHostname,
mirrorz_help_link as MirrorzHelpLink,
mirrorz_help_link as MirrorzHelpLink, // @ts-ignore
} from "virtual:jekyll-config";
// @ts-ignore
import { options as globalOptions } from "virtual:jekyll-data";
import hljs from "../lib/hljs";
import Mark from "markup-js";
@ -41,7 +42,7 @@ const update_target = (ev) => {
}
// special hack for case-insensitive
if ("sudoe" in template_data) {
template_data.sudoE = template_data.sudoe;
template_data["sudoE"] = template_data.sudoe;
}
const template = document
.querySelector(template_selector)
@ -60,7 +61,9 @@ Array.from(document.querySelectorAll("select.content-select")).map((el) => {
document.getElementById("help-select").addEventListener("change", (ev) => {
let help_url =
ev.target.querySelector("option:checked").attributes["data-help-url"].value;
window.location = `${window.location.protocol}//${window.location.host}${help_url}`;
window.location.assign(
`${window.location.protocol}//${window.location.host}${help_url}`,
);
});
fetch(TUNASYNC_JSON_PATH)

View File

@ -10,7 +10,7 @@ function generateFormConfig(form) {
// FormData ignores unchecked checkboxes, workaround
form.querySelectorAll("input[type=checkbox]:not(:checked)"),
).forEach((elm) => {
formData[elm.name] = "";
formData[elm["name"]] = "";
});
let conf = {};
for (const x in formData) {

View File

@ -1,17 +1,18 @@
import "./default";
import "../styles/notfound.scss";
// @ts-ignore
import { issue_tag as IssueTag } from "virtual:jekyll-config";
const tag = `[${IssueTag}]`;
const bugLink = document.getElementById("new_issue_bug");
const bugURL = new URL(bugLink.href);
const bugURL = new URL(bugLink["href"]);
bugURL.searchParams.append("title", tag + "404 at " + location.pathname);
bugLink.href = bugURL.href;
bugLink["href"] = bugURL.href;
const mrLink = document.getElementById("new_issue_mr");
const mrURL = new URL(mrLink.href);
const mrURL = new URL(mrLink["href"]);
mrURL.searchParams.append(
"title",
tag + "Mirror Request for new mirror " + location.pathname.split("/")[1],
);
mrLink.href = mrURL.href;
mrLink["href"] = mrURL.href;

View File

@ -1,12 +1,14 @@
import { TUNASYNC_JSON_PATH } from "../lib/consts";
// @ts-ignore
import { options as globalOptions } from "virtual:jekyll-data";
import { ref, onMounted, nextTick } from "vue";
import processingHandlers from "../lib/mirrorListDataProcessing";
import { MirrorInfo } from "./types";
const { postProcessStatusData } = processingHandlers(globalOptions);
export const useMirrorList = (additional = []) => {
const mirrorList = ref([]);
export const useMirrorList = (additional: MirrorInfo[] = []) => {
const mirrorList = ref([] as MirrorInfo[]);
let refreshTimer = null;
const refreshMirrorList = async () => {
@ -15,7 +17,7 @@ export const useMirrorList = (additional = []) => {
}
try {
const res = await fetch(TUNASYNC_JSON_PATH);
const status_data = await res.json();
const status_data = (await res.json()) as MirrorInfo[];
mirrorList.value = postProcessStatusData(status_data, additional);
} catch (e) {
throw e;

View File

@ -1,4 +1,5 @@
import { format as TimeAgoFormat } from "timeago.js";
import { MirrorInfo } from "./types";
export default function (globalOptions) {
const label_map = globalOptions.label_map;
@ -13,8 +14,8 @@ export default function (globalOptions) {
globalOptions.mirror_desc.map((m) => [m.name, m.desc]),
);
const processLinkItem = (mirrors) => {
var processed = [];
const processLinkItem = (mirrors: MirrorInfo[]) => {
var processed: MirrorInfo[] = [];
for (let d of mirrors) {
if (d.link_to === undefined) {
processed.push(d);
@ -30,8 +31,6 @@ export default function (globalOptions) {
d.last_update_ago = target.last_update_ago;
d.last_ended = target.last_ended;
d.last_ended_ago = target.last_ended_ago;
d.last_schedule = target.last_schedule;
d.last_schedule_ago = target.last_schedule_ago;
processed.push(d);
break;
}
@ -40,7 +39,7 @@ export default function (globalOptions) {
return processed;
};
const stringifyTime = (ts) => {
const stringifyTime = (ts: number): [string, string] => {
const date = new Date(ts * 1000);
let str = "";
let ago = "";
@ -56,7 +55,7 @@ export default function (globalOptions) {
return [str, ago];
};
const processMirrorItem = (d) => {
const processMirrorItem = (d: MirrorInfo): MirrorInfo => {
if (d.is_master === undefined) {
d.is_master = true;
}
@ -64,7 +63,7 @@ export default function (globalOptions) {
return d;
}
d.label = label_map[d.status];
d.show_status = d.status != "success";
d.show_status = d.status !== "success";
// Strip the second component of last_update
[d.last_update, d.last_update_ago] = stringifyTime(d.last_update_ts);
[d.last_ended, d.last_ended_ago] = stringifyTime(d.last_ended_ts);
@ -73,11 +72,11 @@ export default function (globalOptions) {
return d;
};
const sortAndUniqMirrors = (mirs) => {
const sortAndUniqMirrors = (mirs: MirrorInfo[]): MirrorInfo[] => {
mirs.sort((a, b) => {
return a.name < b.name ? -1 : 1;
});
return mirs.reduce((acc, cur) => {
return mirs.reduce((acc: MirrorInfo[], cur: MirrorInfo) => {
if (acc.length > 1 && acc[acc.length - 1].name == cur.name) {
if (acc[acc.length - 1].last_update_ts && cur.last_update_ts) {
if (acc[acc.length - 1].last_update_ts < cur.last_update_ts) {
@ -93,23 +92,25 @@ export default function (globalOptions) {
}, []);
};
const postProcessStatusData = (status_data, additional) => {
const postProcessStatusData = (
status_data: MirrorInfo[],
additional: MirrorInfo[],
) => {
const processed = status_data
.concat(additional)
.map((d) => processMirrorItem(d));
return sortAndUniqMirrors(processLinkItem(processed));
};
const genMainMirrorList = (status_data, helpPages) => {
const genMainMirrorList = (
status_data: MirrorInfo[],
helpPages: { [k: string]: string },
) => {
return status_data
.filter((d) => !(d.status == "disabled"))
.map((d) => ({
...d,
url: forceHelp[d.name]
? helpPages[d.name]
: d.url
? d.url
: `/${d.name}/`,
url: forceHelp[d.name] ? helpPages[d.name] : d.url ?? `/${d.name}/`,
help_url: helpPages[d.name],
is_new: Boolean(new_mirrors[d.name]),
description: descriptions[d.name],

26
_src/lib/types.ts Normal file
View File

@ -0,0 +1,26 @@
export interface FullMirrorInfo {
is_master: boolean;
last_ended: string;
last_ended_ts: number;
last_started: string;
last_started_ts: number;
last_update: string;
last_update_ts: number;
name: string;
next_schedule: string;
next_schedule_ts: number;
size: string;
status: string;
upstream: string;
link_to: string;
last_update_ago: string;
last_ended_ago: string;
last_started_ago: string;
next_schedule_ago: string;
label: string;
show_status: boolean;
/// The page of help page
url: string;
}
export interface MirrorInfo extends Partial<FullMirrorInfo> {}

13
_src/tsconfig.json Normal file
View File

@ -0,0 +1,13 @@
{
"include": ["**/*.ts", "**/*.js", "**/*.vue"],
"files": [
"../node_modules/njs-types/ngx_http_js_module.d.ts",
"components.d.ts"
],
"compilerOptions": {
"isolatedModules": true,
"target": "ESNext",
"moduleResolution": "NodeNext",
"module": "NodeNext"
}
}

View File

@ -12,6 +12,7 @@ import fs from "node:fs";
import { build as viteBuild, normalizePath } from "vite";
import glob from "fast-glob";
import { getBabelOutputPlugin } from "@rollup/plugin-babel";
import typescript from "@rollup/plugin-typescript";
const visualizer = await (async () => {
if (process.env.VISUALIZER) {
@ -148,7 +149,7 @@ export default defineConfig(({ mode }) => ({
return {
name: "add-njs",
config(config) {
savedConfig.minify = config.build?.minify ? 'terser' : false;
savedConfig.minify = config.build?.minify ? "terser" : false;
savedConfig.root = config.root;
savedConfig.mode = config.mode;
savedConfig.njsFiles = glob.sync("entrypoints-njs/**", {
@ -177,6 +178,9 @@ export default defineConfig(({ mode }) => ({
configFile: false,
logLevel,
plugins: [
typescript({
tsconfig: path.join(root, "tsconfig.json"),
}),
getBabelOutputPlugin({
presets: [
"babel-preset-njs",

57
package-lock.json generated
View File

@ -40,8 +40,12 @@
"whatwg-fetch": "^3.6.20"
},
"devDependencies": {
"@rollup/plugin-typescript": "^11.1.6",
"njs-types": "^0.8.2",
"prettier": "^3.2.5",
"rollup-plugin-visualizer": "^5.12.0"
"rollup-plugin-visualizer": "^5.12.0",
"tslib": "^2.6.2",
"typescript": "^5.4.5"
}
},
"node_modules/@ampproject/remapping": {
@ -2191,6 +2195,32 @@
}
}
},
"node_modules/@rollup/plugin-typescript": {
"version": "11.1.6",
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz",
"integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^5.1.0",
"resolve": "^1.22.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^2.14.0||^3.0.0||^4.0.0",
"tslib": "*",
"typescript": ">=3.7.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
},
"tslib": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
@ -3721,6 +3751,12 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/njs-types": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/njs-types/-/njs-types-0.8.2.tgz",
"integrity": "sha512-6uv1Tcb4khW45LHZqj5vu1uo7WbvB6nINZjDVmryOxiO3K7rDMqRVNJbYtLHOKNbGDqLygIip9iYZbFViIVGqA==",
"dev": true
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
@ -4455,6 +4491,25 @@
"node": ">=8.0"
}
},
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
"dev": true
},
"node_modules/typescript": {
"version": "5.4.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"devOptional": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",

View File

@ -3,7 +3,7 @@
"private": true,
"homepage": "https://github.com/tuna/mirror-web",
"scripts": {
"format": "prettier --write \"_src/**/*.vue\" \"_src/**/*.html\" \"_src/**/*.js\" \"_src/**/*.scss\" *.mjs",
"format": "prettier --write \"_src/**/*.vue\" \"_src/**/*.html\" \"_src/**/*.js\" \"_src/**/*.scss\" \"_src/**/*.ts\" *.mjs",
"postinstall": "patch-package --patch-dir _node_module_patch"
},
"dependencies": {
@ -40,7 +40,11 @@
"whatwg-fetch": "^3.6.20"
},
"devDependencies": {
"@rollup/plugin-typescript": "^11.1.6",
"njs-types": "^0.8.2",
"prettier": "^3.2.5",
"rollup-plugin-visualizer": "^5.12.0"
"rollup-plugin-visualizer": "^5.12.0",
"tslib": "^2.6.2",
"typescript": "^5.4.5"
}
}