import path from 'path'; import fs from 'fs'; import fsp from 'fs/promises'; import { task } from './trace'; import { treeDir } from './lib/tree-dir'; import type { TreeType, TreeTypeArray } from './lib/tree-dir'; import { fdir as Fdir } from 'fdir'; import Trie from 'mnemonist/trie'; import { writeFile } from './lib/misc'; const rootPath = path.resolve(__dirname, '../'); const publicPath = path.resolve(__dirname, '../public'); const folderAndFilesToBeDeployed = [ `Mock${path.sep}`, `List${path.sep}`, `Clash${path.sep}`, `Modules${path.sep}`, `Script${path.sep}`, `Internal${path.sep}`, 'LICENSE' ]; export const buildPublic = task(require.main === module, __filename)(async (span) => { fs.mkdirSync(publicPath, { recursive: true }); await span .traceChild('copy public files') .traceAsyncFn(async () => { const trie = Trie.from(await new Fdir() .withRelativePaths() .exclude((dirName) => ( dirName === 'node_modules' || dirName === 'Build' || dirName === 'public' || dirName[0] === '.' )) .crawl(rootPath) .withPromise()); const filesToBeCopied = folderAndFilesToBeDeployed.flatMap(folderOrFile => trie.find(folderOrFile)); return Promise.all(filesToBeCopied.map(file => { const src = path.join(rootPath, file); const dest = path.join(publicPath, file); const destParen = path.dirname(dest); if (!fs.existsSync(destParen)) { fs.mkdirSync(destParen, { recursive: true }); } return fsp.copyFile( src, dest, fs.constants.COPYFILE_FICLONE ); })); }); const html = await span .traceChild('generate index.html') .traceAsyncFn(() => treeDir(publicPath).then(generateHtml)); return writeFile(path.join(publicPath, 'index.html'), 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, Internal: 17, LICENSE: 20, default: Number.MAX_VALUE }; const prioritySorter = (a: TreeType, b: TreeType) => { return ((priorityOrder[a.name] || priorityOrder.default) - (priorityOrder[b.name] || priorityOrder.default)) || a.name.localeCompare(b.name); }; const html = (string: TemplateStringsArray, ...values: any[]) => string.reduce((acc, str, i) => acc + str + (values[i] ?? ''), ''); const walk = (tree: TreeTypeArray) => { let result = ''; tree.sort(prioritySorter); for (let i = 0, len = tree.length; i < len; i++) { const entry = tree[i]; if (entry.type === 'directory') { result += html`
  • ${entry.name}
  • `; } else if (/* entry.type === 'file' && */ entry.name !== 'index.html') { result += html`
  • ${entry.name}
  • `; } } return result; }; function generateHtml(tree: TreeTypeArray) { return html` Surge Ruleset Server | Sukka (@SukkaW)

    Sukka Ruleset Server

    Made by Sukka | Source @ GitHub | Licensed under AGPL-3.0

    Last Build: ${new Date().toISOString()}


    `; }