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 path from 'path';
import fsp from 'fs/promises'; import fsp from 'fs/promises';
import { task } from './lib/trace-runner'; 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 rootPath = path.resolve(import.meta.dir, '../');
const publicPath = path.resolve(import.meta.dir, '../public'); const publicPath = path.resolve(import.meta.dir, '../public');
@ -15,7 +16,7 @@ const folderAndFilesToBeDeployed = [
'LICENSE' 'LICENSE'
]; ];
export const buildPublicHtml = task(import.meta.path, async () => { export const buildPublic = task(import.meta.path, async () => {
await fsp.mkdir(publicPath, { recursive: true }); await fsp.mkdir(publicPath, { recursive: true });
await Promise.all(folderAndFilesToBeDeployed.map(dir => fsp.cp( await Promise.all(folderAndFilesToBeDeployed.map(dir => fsp.cp(
path.resolve(rootPath, dir), path.resolve(rootPath, dir),
@ -23,24 +24,37 @@ export const buildPublicHtml = task(import.meta.path, async () => {
{ force: true, recursive: true } { force: true, recursive: true }
))); )));
const list = await listDir(publicPath, { const tree = await listDir(publicPath);
ignoreHidden: true,
ignorePattern: /node_modules|Build|.DS_Store|\.(json|html|md|js)|LICENSE/
});
const html = template(list); const html = generateHtml(tree);
return Bun.write(path.join(publicPath, 'index.html'), html); return Bun.write(path.join(publicPath, 'index.html'), html);
}); });
if (import.meta.main) { if (import.meta.main) {
buildPublicHtml(); buildPublic();
} }
function template(urlList: string[]) { const priorityOrder: Record<'default' | string & {}, number> = {
return ` domainset: 1,
<!DOCTYPE html> 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"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Surge Ruleset Server | Sukka (@SukkaW)</title> <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-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"> <link href="https://cdn.skk.moe/favicon/favicon-16x16.png" rel="icon" type="image/png" sizes="16x16">
<meta name="description" content="Sukka 自用的 Surge 规则组"> <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:title" content="Surge Ruleset | Sukka (@SukkaW)">
<meta property="og:type" content="Website"> <meta property="og:type" content="Website">
<meta property="og:url" content="https://ruleset.skk.moe/"> <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: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"> <meta name="twitter:card" content="summary">
<link rel="canonical" href="https://ruleset.skk.moe/"> <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>`;
</head>
<body> html += `<body>
<main class="container"> <main class="container">
<h1>Sukka Surge Ruleset Server</h1> <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="https://github.com/SukkaW/Surge/blob/master/LICENSE" target="_blank">AGPL-3.0</a></p> <p>
<p>Last Build: ${new Date().toISOString()}</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>
<hr> </p>
<br> <p>Last Build: 2023-12-03T16:54:15.820Z</p>
<ul> <br>`;
${urlList.sort().map(url => `<li><a href="${url}" target="_blank">${url}</a></li>`).join('')}
</ul> html += '<ul class="directory-list">';
</main>
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> </body>
</html> </html>`;
`;
return html;
} }

View File

@ -44,7 +44,7 @@ export const downloadPreviousBuild = task(import.meta.path, async () => {
if (flag & ALL_FILES_EXISTS) { if (flag & ALL_FILES_EXISTS) {
console.log('All files exists, skip download.'); console.log('All files exists, skip download.');
// return; return;
} }
const extractedPath = path.join(os.tmpdir(), `sukka-surge-last-build-extracted-${Date.now()}`); 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 { buildRedirectModule } from './build-redirect-module';
import { validate } from './validate-domainset'; import { validate } from './validate-domainset';
import { buildPublicHtml } from './build-public'; import { buildPublic } from './build-public';
// import type { TaskResult } from './lib/trace-runner'; // import type { TaskResult } from './lib/trace-runner';
(async () => { (async () => {
@ -84,7 +84,7 @@ import { buildPublicHtml } from './build-public';
]); ]);
await Promise.all([ await Promise.all([
buildPublicHtml(), buildPublic(),
validate() validate()
]); ]);

View File

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