Refactor: enable new ruleset index template

This commit is contained in:
SukkaW 2023-12-13 18:46:30 +08:00
parent cd229a91a3
commit 713358402d
5 changed files with 125 additions and 31 deletions

View File

@ -1,7 +1,8 @@
import listDir from '@sukka/listdir';
import path from 'path';
import fsp from 'fs/promises';
import { task } from './lib/trace-runner';
import { listDir } from './lib/list-dir';
import type { TreeType, TreeTypeArray } from './lib/list-dir';
const rootPath = path.resolve(import.meta.dir, '../');
const publicPath = path.resolve(import.meta.dir, '../public');
@ -15,7 +16,7 @@ const folderAndFilesToBeDeployed = [
'LICENSE'
];
export const buildPublicHtml = task(import.meta.path, async () => {
export const buildPublic = task(import.meta.path, async () => {
await fsp.mkdir(publicPath, { recursive: true });
await Promise.all(folderAndFilesToBeDeployed.map(dir => fsp.cp(
path.resolve(rootPath, dir),
@ -23,24 +24,37 @@ export const buildPublicHtml = task(import.meta.path, async () => {
{ force: true, recursive: true }
)));
const list = await listDir(publicPath, {
ignoreHidden: true,
ignorePattern: /node_modules|Build|.DS_Store|\.(json|html|md|js)|LICENSE/
});
const tree = await listDir(publicPath);
const html = template(list);
const html = generateHtml(tree);
return Bun.write(path.join(publicPath, 'index.html'), html);
});
if (import.meta.main) {
buildPublicHtml();
buildPublic();
}
function template(urlList: string[]) {
return `
<!DOCTYPE html>
const priorityOrder: Record<'default' | string & {}, number> = {
domainset: 1,
non_ip: 2,
ip: 3,
List: 10,
Surge: 11,
Clash: 12,
Modules: 13,
Script: 14,
Mock: 15,
Assets: 16,
LICENSE: 20,
default: Number.MAX_VALUE
};
const prioritySorter = (a: TreeType, b: TreeType) => (priorityOrder[a.name] || priorityOrder.default) - (priorityOrder[b.name] || priorityOrder.default) || +(a.name > b.name) || -(a.name < b.name);
function generateHtml(tree: TreeTypeArray) {
let html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Surge Ruleset Server | Sukka (@SukkaW)</title>
@ -51,27 +65,51 @@ function template(urlList: string[]) {
<link href="https://cdn.skk.moe/favicon/favicon-32x32.png" rel="icon" type="image/png" sizes="32x32">
<link href="https://cdn.skk.moe/favicon/favicon-16x16.png" rel="icon" type="image/png" sizes="16x16">
<meta name="description" content="Sukka 自用的 Surge 规则组">
<link rel="stylesheet" href="https://cdn.skk.moe/ruleset/css/21d8777a.css" />
<meta property="og:title" content="Surge Ruleset | Sukka (@SukkaW)">
<meta property="og:type" content="Website">
<meta property="og:url" content="https://ruleset.skk.moe/">
<meta property="og:image" content="https://cdn.skk.moe/favicon/android-chrome-192x192.png">
<meta property="og:description" content="Sukka 自用的 Surge 规则组">
<meta property="og:description" content="Sukka 自用的 Surge / Clash Premium 规则组">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="https://ruleset.skk.moe/">
<link rel="stylesheet" href="https://cdn.staticfile.org/picocss/1.5.0/pico.slim.min.css">
</head>
<body>
</head>`;
html += `<body>
<main class="container">
<h1>Sukka Surge Ruleset Server</h1>
<p>Made by <a href="https://skk.moe">Sukka</a> | <a href="https://github.com/SukkaW/Surge/">Source @ GitHub</a> | Licensed under <a href="https://github.com/SukkaW/Surge/blob/master/LICENSE" target="_blank">AGPL-3.0</a></p>
<p>Last Build: ${new Date().toISOString()}</p>
<hr>
<br>
<ul>
${urlList.sort().map(url => `<li><a href="${url}" target="_blank">${url}</a></li>`).join('')}
</ul>
</main>
</body>
</html>
`;
<h1>Sukka Ruleset Server</h1>
<p>
Made by <a href="https://skk.moe">Sukka</a> | <a href="https://github.com/SukkaW/Surge/">Source @ GitHub</a> | Licensed under <a href="/LICENSE" target="_blank">AGPL-3.0</a>
</p>
<p>Last Build: 2023-12-03T16:54:15.820Z</p>
<br>`;
html += '<ul class="directory-list">';
const walk = (tree: TreeTypeArray) => {
tree.sort(prioritySorter);
for (let i = 0, len = tree.length; i < len; i++) {
const entry = tree[i];
if (entry.type === 'directory') {
html += `<li class="folder">${entry.name}`;
html += '<ul>';
walk(entry.children);
html += '</ul>';
} else if (/* entry.type === 'file' && */ entry.name !== 'index.html') {
html += `<li><a class="file directory-list-file" href="${entry.path}">${entry.name}</a></li>`;
}
}
};
walk(tree);
html += '</ul>';
html += `</main>
</body>
</html>`;
return html;
}

View File

@ -44,7 +44,7 @@ export const downloadPreviousBuild = task(import.meta.path, async () => {
if (flag & ALL_FILES_EXISTS) {
console.log('All files exists, skip download.');
// return;
return;
}
const extractedPath = path.join(os.tmpdir(), `sukka-surge-last-build-extracted-${Date.now()}`);

View File

@ -14,7 +14,7 @@ import { buildStreamService } from './build-stream-service';
import { buildRedirectModule } from './build-redirect-module';
import { validate } from './validate-domainset';
import { buildPublicHtml } from './build-public';
import { buildPublic } from './build-public';
// import type { TaskResult } from './lib/trace-runner';
(async () => {
@ -84,7 +84,7 @@ import { buildPublicHtml } from './build-public';
]);
await Promise.all([
buildPublicHtml(),
buildPublic(),
validate()
]);

View File

@ -68,7 +68,6 @@ export async function compareAndWriteFile(linesA: string[], filePath: string) {
writer.write('\n');
}
await writer.flush();
return writer.end();
}, picocolors.gray);
}

57
Build/lib/list-dir.ts Normal file
View File

@ -0,0 +1,57 @@
import type { Path } from 'path-scurry';
import { PathScurry } from 'path-scurry';
interface TreeFileType {
type: 'file',
name: string,
path: string
}
interface TreeDirectoryType {
type: 'directory',
name: string,
path: string,
children: TreeTypeArray
}
export type TreeType = TreeDirectoryType | TreeFileType;
export type TreeTypeArray = TreeType[];
type VoidOrVoidArray = void | VoidOrVoidArray[];
export const listDir = async (path: string): Promise<TreeTypeArray> => {
const pw = new PathScurry(path);
const tree: TreeTypeArray = [];
const walk = async (entry: Path, node: TreeTypeArray): Promise<VoidOrVoidArray> => {
const promises: Array<Promise<VoidOrVoidArray>> = [];
for (const child of await pw.readdir(entry)) {
if (child.isDirectory()) {
const newNode: TreeDirectoryType = {
type: 'directory',
name: child.name,
path: child.relative(),
children: []
};
node.push(newNode);
promises.push(walk(child, newNode.children));
continue;
}
if (child.isFile()) {
const newNode: TreeFileType = {
type: 'file',
name: child.name,
path: child.relative()
};
node.push(newNode);
continue;
}
}
return Promise.all(promises);
};
await walk(pw.cwd, tree);
return tree;
};