mirror of
https://github.com/SukkaW/Surge.git
synced 2025-12-12 01:00:34 +08:00
Chore: say hello to bun
This commit is contained in:
parent
0e8bfc0def
commit
37257958c2
16
.github/workflows/main.yml
vendored
16
.github/workflows/main.yml
vendored
@ -15,19 +15,11 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: oven-sh/setup-bun@v1
|
||||||
name: Install pnpm
|
|
||||||
id: pnpm-install
|
|
||||||
with:
|
with:
|
||||||
version: latest
|
bun-version: latest
|
||||||
run_install: false
|
- run: bun install
|
||||||
- name: Use Node.js
|
- run: bun run build
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version-file: '.node-version'
|
|
||||||
cache: 'pnpm'
|
|
||||||
- run: pnpm i
|
|
||||||
- run: pnpm run build
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
@ -35,6 +35,8 @@ const buildInternalCDNDomains = task(__filename, async () => {
|
|||||||
*/
|
*/
|
||||||
const processLocalDomainSet = async (domainSetPath) => {
|
const processLocalDomainSet = async (domainSetPath) => {
|
||||||
for await (const line of readFileByLine(domainSetPath)) {
|
for await (const line of readFileByLine(domainSetPath)) {
|
||||||
|
// console.log({ line });
|
||||||
|
|
||||||
const parsed = tldts.parse(line, { allowPrivateDomains: true, detectIp: false });
|
const parsed = tldts.parse(line, { allowPrivateDomains: true, detectIp: false });
|
||||||
if (parsed.isIp) continue;
|
if (parsed.isIp) continue;
|
||||||
if (parsed.isIcann || parsed.isPrivate) {
|
if (parsed.isIcann || parsed.isPrivate) {
|
||||||
|
|||||||
@ -1,56 +1,42 @@
|
|||||||
// @ts-check
|
import { downloadPreviousBuild, downloadPublicSuffixList } from './download-previous-build';
|
||||||
|
import { buildCommon } from './build-common';
|
||||||
|
import { buildAntiBogusDomain } from './build-anti-bogus-domain';
|
||||||
|
import { buildAppleCdn } from './build-apple-cdn';
|
||||||
|
import { buildCdnConf } from './build-cdn-conf';
|
||||||
|
import { buildPhishingDomainSet } from './build-phishing-domainset';
|
||||||
|
import { buildRejectDomainSet } from './build-reject-domainset';
|
||||||
|
import { buildTelegramCIDR } from './build-telegram-cidr';
|
||||||
|
import { buildChnCidr } from './build-chn-cidr';
|
||||||
|
import { buildSpeedtestDomainSet } from './build-speedtest-domainset';
|
||||||
|
import { buildInternalCDNDomains } from './build-internal-cdn-rules';
|
||||||
|
import { buildInternalChnDomains } from './build-internal-chn-domains';
|
||||||
|
import { buildDomesticRuleset } from './build-domestic-ruleset';
|
||||||
|
import { buildStreamService } from './build-stream-service';
|
||||||
|
import { buildRedirectModule } from './build-redirect-module';
|
||||||
|
import { validate } from './validate-domainset';
|
||||||
|
|
||||||
const { downloadPreviousBuild, downloadPublicSuffixList } = require('./download-previous-build');
|
import { buildPublicHtml } from './build-public';
|
||||||
const { buildCommon } = require('./build-common');
|
|
||||||
const { buildAntiBogusDomain } = require('./build-anti-bogus-domain');
|
|
||||||
const { buildAppleCdn } = require('./build-apple-cdn');
|
|
||||||
const { buildCdnConf } = require('./build-cdn-conf');
|
|
||||||
const { buildPhishingDomainSet } = require('./build-phishing-domainset');
|
|
||||||
const { buildRejectDomainSet } = require('./build-reject-domainset');
|
|
||||||
const { buildTelegramCIDR } = require('./build-telegram-cidr');
|
|
||||||
const { buildChnCidr } = require('./build-chn-cidr');
|
|
||||||
const { buildSpeedtestDomainSet } = require('./build-speedtest-domainset');
|
|
||||||
const { buildInternalCDNDomains } = require('./build-internal-cdn-rules');
|
|
||||||
const { buildInternalChnDomains } = require('./build-internal-chn-domains');
|
|
||||||
const { buildDomesticRuleset } = require('./build-domestic-ruleset');
|
|
||||||
const { buildStreamService } = require('./build-stream-service');
|
|
||||||
const { buildRedirectModule } = require('./build-redirect-module');
|
|
||||||
const { validate } = require('./validate-domainset');
|
|
||||||
|
|
||||||
const { buildPublicHtml } = require('./build-public');
|
import { Worker } from 'jest-worker';
|
||||||
|
|
||||||
const { Worker } = require('jest-worker');
|
type WithWorker<T> = import('jest-worker').Worker & { __sukka_worker_name: string } & T
|
||||||
|
|
||||||
/**
|
const requireWorker = <T>(path: string): WithWorker<T> => {
|
||||||
* @template T
|
const _worker = new Worker(
|
||||||
* @typedef {import('jest-worker').Worker & { __sukka_worker_name: string } & T} WithWorker
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @template T
|
|
||||||
* @param {string} path
|
|
||||||
* @returns {WithWorker<T>}
|
|
||||||
*/
|
|
||||||
const requireWorker = (path) => {
|
|
||||||
const _worker = /** @type {WithWorker<T>} */ (new Worker(
|
|
||||||
require.resolve(path),
|
require.resolve(path),
|
||||||
{
|
{
|
||||||
numWorkers: 1,
|
numWorkers: 1,
|
||||||
maxRetries: 0,
|
maxRetries: 0,
|
||||||
enableWorkerThreads: true
|
enableWorkerThreads: true
|
||||||
}
|
}
|
||||||
));
|
) as WithWorker<T>;
|
||||||
_worker.getStderr().pipe(process.stderr);
|
_worker.getStderr().pipe(process.stderr);
|
||||||
_worker.getStdout().pipe(process.stdout);
|
_worker.getStdout().pipe(process.stdout);
|
||||||
_worker.__sukka_worker_name = path;
|
_worker.__sukka_worker_name = path;
|
||||||
return _worker;
|
return _worker;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const endWorker = async <T>(worker: WithWorker<T>) => {
|
||||||
* @template T
|
|
||||||
* @param {WithWorker<T>} worker
|
|
||||||
*/
|
|
||||||
const endWorker = async (worker) => {
|
|
||||||
const { forceExited } = await worker.end();
|
const { forceExited } = await worker.end();
|
||||||
if (forceExited && worker.__sukka_worker_name) {
|
if (forceExited && worker.__sukka_worker_name) {
|
||||||
console.log(worker.__sukka_worker_name, 'forceExited');
|
console.log(worker.__sukka_worker_name, 'forceExited');
|
||||||
@ -58,57 +44,43 @@ const endWorker = async (worker) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const buildInternalReverseChnCIDRWorker = /** @type {WithWorker<import('./build-internal-reverse-chn-cidr')>} */ (requireWorker('./build-internal-reverse-chn-cidr'));
|
const buildInternalReverseChnCIDRWorker: WithWorker<typeof import('./build-internal-reverse-chn-cidr')> = requireWorker('./build-internal-reverse-chn-cidr');
|
||||||
const { buildInternalReverseChnCIDR } = buildInternalReverseChnCIDRWorker;
|
const { buildInternalReverseChnCIDR } = buildInternalReverseChnCIDRWorker;
|
||||||
|
|
||||||
// download-previous-build
|
|
||||||
const downloadPreviousBuildPromise = downloadPreviousBuild();
|
const downloadPreviousBuildPromise = downloadPreviousBuild();
|
||||||
const downloadPublicSuffixListPromise = downloadPublicSuffixList();
|
const downloadPublicSuffixListPromise = downloadPublicSuffixList();
|
||||||
// build:common
|
|
||||||
const buildCommonPromise = downloadPreviousBuildPromise.then(() => buildCommon());
|
const buildCommonPromise = downloadPreviousBuildPromise.then(() => buildCommon());
|
||||||
// build:anti-bogus-domain
|
|
||||||
const buildAntiBogusDomainPromise = downloadPreviousBuildPromise.then(() => buildAntiBogusDomain());
|
const buildAntiBogusDomainPromise = downloadPreviousBuildPromise.then(() => buildAntiBogusDomain());
|
||||||
// build:apple-cdn
|
|
||||||
const buildAppleCdnPromise = downloadPreviousBuildPromise.then(() => buildAppleCdn());
|
const buildAppleCdnPromise = downloadPreviousBuildPromise.then(() => buildAppleCdn());
|
||||||
// build:cdn-conf
|
|
||||||
const buildCdnConfPromise = Promise.all([
|
const buildCdnConfPromise = Promise.all([
|
||||||
downloadPreviousBuildPromise,
|
downloadPreviousBuildPromise,
|
||||||
downloadPublicSuffixListPromise
|
downloadPublicSuffixListPromise
|
||||||
]).then(() => buildCdnConf());
|
]).then(() => buildCdnConf());
|
||||||
// build:phishing-domainset
|
|
||||||
const buildPhilishingDomainsetPromise = Promise.all([
|
const buildPhilishingDomainsetPromise = Promise.all([
|
||||||
downloadPreviousBuildPromise,
|
downloadPreviousBuildPromise,
|
||||||
downloadPublicSuffixListPromise
|
downloadPublicSuffixListPromise
|
||||||
]).then(() => buildPhishingDomainSet());
|
]).then(() => buildPhishingDomainSet());
|
||||||
// build:reject-domainset
|
|
||||||
const buildRejectDomainSetPromise = Promise.all([
|
const buildRejectDomainSetPromise = Promise.all([
|
||||||
downloadPreviousBuildPromise,
|
downloadPreviousBuildPromise,
|
||||||
downloadPublicSuffixListPromise,
|
downloadPublicSuffixListPromise,
|
||||||
buildPhilishingDomainsetPromise
|
buildPhilishingDomainsetPromise
|
||||||
]).then(() => buildRejectDomainSet());
|
]).then(() => buildRejectDomainSet());
|
||||||
// build:telegram-cidr
|
|
||||||
const buildTelegramCIDRPromise = downloadPreviousBuildPromise.then(() => buildTelegramCIDR());
|
const buildTelegramCIDRPromise = downloadPreviousBuildPromise.then(() => buildTelegramCIDR());
|
||||||
// build:chn-cidr
|
|
||||||
const buildChnCidrPromise = downloadPreviousBuildPromise.then(() => buildChnCidr());
|
const buildChnCidrPromise = downloadPreviousBuildPromise.then(() => buildChnCidr());
|
||||||
// build:speedtest-domainset
|
|
||||||
const buildSpeedtestDomainSetPromise = downloadPreviousBuildPromise.then(() => buildSpeedtestDomainSet());
|
const buildSpeedtestDomainSetPromise = downloadPreviousBuildPromise.then(() => buildSpeedtestDomainSet());
|
||||||
// build:internal-cdn-rules
|
|
||||||
const buildInternalCDNDomainsPromise = Promise.all([
|
const buildInternalCDNDomainsPromise = Promise.all([
|
||||||
downloadPublicSuffixListPromise,
|
downloadPublicSuffixListPromise,
|
||||||
buildCommonPromise,
|
buildCommonPromise,
|
||||||
buildCdnConfPromise
|
buildCdnConfPromise
|
||||||
]).then(() => buildInternalCDNDomains());
|
]).then(() => buildInternalCDNDomains());
|
||||||
// build:internal-reverse-chn-cidr
|
|
||||||
const buildInternalReverseChnCIDRPromise = buildInternalReverseChnCIDR();
|
const buildInternalReverseChnCIDRPromise = buildInternalReverseChnCIDR();
|
||||||
// build:internal-chn-domains
|
|
||||||
const buildInternalChnDomainsPromise = buildInternalChnDomains();
|
const buildInternalChnDomainsPromise = buildInternalChnDomains();
|
||||||
// build:domestic-ruleset
|
|
||||||
const buildDomesticRulesetPromise = downloadPreviousBuildPromise.then(() => buildDomesticRuleset());
|
const buildDomesticRulesetPromise = downloadPreviousBuildPromise.then(() => buildDomesticRuleset());
|
||||||
|
|
||||||
const buildRedirectModulePromise = downloadPreviousBuildPromise.then(() => buildRedirectModule());
|
const buildRedirectModulePromise = downloadPreviousBuildPromise.then(() => buildRedirectModule());
|
||||||
const buildStreamServicePromise = downloadPreviousBuildPromise.then(() => buildStreamService());
|
const buildStreamServicePromise = downloadPreviousBuildPromise.then(() => buildStreamService());
|
||||||
|
|
||||||
const stats = await Promise.all([
|
const stats: Array<{ start: number, end: number, taskName: string }> = await Promise.all([
|
||||||
downloadPreviousBuildPromise,
|
downloadPreviousBuildPromise,
|
||||||
downloadPublicSuffixListPromise,
|
downloadPublicSuffixListPromise,
|
||||||
buildCommonPromise,
|
buildCommonPromise,
|
||||||
@ -137,20 +109,16 @@ const endWorker = async (worker) => {
|
|||||||
printStats(stats);
|
printStats(stats);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
function printStats(stats: Array<{ start: number, end: number, taskName: string }>): void {
|
||||||
* @param {Array<{ start: number, end: number, taskName: string }>} stats
|
|
||||||
*/
|
|
||||||
function printStats(stats) {
|
|
||||||
// sort stats by start time
|
|
||||||
stats.sort((a, b) => a.start - b.start);
|
stats.sort((a, b) => a.start - b.start);
|
||||||
|
|
||||||
const longestTaskName = Math.max(...stats.map(i => i.taskName.length));
|
const longestTaskName: number = Math.max(...stats.map(i => i.taskName.length));
|
||||||
const realStart = Math.min(...stats.map(i => i.start));
|
const realStart: number = Math.min(...stats.map(i => i.start));
|
||||||
const realEnd = Math.max(...stats.map(i => i.end));
|
const realEnd: number = Math.max(...stats.map(i => i.end));
|
||||||
|
|
||||||
const totalMs = realEnd - realStart;
|
const totalMs: number = realEnd - realStart;
|
||||||
|
|
||||||
const statsStep = (totalMs / 160) | 0;
|
const statsStep: number = (totalMs / 160) | 0;
|
||||||
|
|
||||||
stats.forEach(stat => {
|
stats.forEach(stat => {
|
||||||
console.log(
|
console.log(
|
||||||
@ -44,35 +44,21 @@ async function compareAndWriteFile(linesA, filePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isEqual) {
|
if (!isEqual) {
|
||||||
const stream = fs.createWriteStream(filePath, { encoding: 'utf-8' });
|
const file = Bun.file(filePath);
|
||||||
|
const writer = file.writer();
|
||||||
|
|
||||||
for (let i = 0, len = linesA.length; i < len; i++) {
|
for (let i = 0, len = linesA.length; i < len; i++) {
|
||||||
const p = writeToStream(stream, `${linesA[i]}\n`);
|
writer.write(`${linesA[i]}\n`);
|
||||||
if (p) {
|
|
||||||
// eslint-disable-next-line no-await-in-loop -- backpressure, besides we only wait for drain
|
|
||||||
await p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await writer.end();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
stream.end();
|
|
||||||
} else {
|
|
||||||
console.log(`Same Content, bail out writing: ${filePath}`);
|
console.log(`Same Content, bail out writing: ${filePath}`);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
module.exports.compareAndWriteFile = compareAndWriteFile;
|
module.exports.compareAndWriteFile = compareAndWriteFile;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import('fs').WriteStream} stream
|
|
||||||
* @param {string} data
|
|
||||||
*/
|
|
||||||
function writeToStream(stream, data) {
|
|
||||||
if (!stream.write(data)) {
|
|
||||||
return /** @type {Promise<void>} */(new Promise((resolve) => {
|
|
||||||
stream.once('drain', resolve);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} title
|
* @param {string} title
|
||||||
* @param {string[]} description
|
* @param {string[]} description
|
||||||
|
|||||||
@ -1,33 +1,60 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
const fs = require('fs');
|
|
||||||
const { fetchWithRetry } = require('./fetch-retry');
|
const { fetchWithRetry } = require('./fetch-retry');
|
||||||
const readline = require('readline');
|
|
||||||
const { Readable } = require('stream');
|
|
||||||
|
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
/**
|
/**
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
*/
|
*/
|
||||||
module.exports.readFileByLine = (path) => {
|
module.exports.readFileByLine = async function *(path) {
|
||||||
return readline.createInterface({
|
let buf = '';
|
||||||
input: fs.createReadStream(path, { encoding: 'utf-8' }),
|
|
||||||
crlfDelay: Infinity
|
for await (const chunk of Bun.file(path).stream()) {
|
||||||
});
|
const chunkStr = decoder.decode(chunk).replaceAll('\r\n', '\n');
|
||||||
|
for (let i = 0, len = chunkStr.length; i < len; i++) {
|
||||||
|
const char = chunkStr[i];
|
||||||
|
if (char === '\n') {
|
||||||
|
yield buf;
|
||||||
|
buf = '';
|
||||||
|
} else {
|
||||||
|
buf += char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf) {
|
||||||
|
yield buf;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import('undici').Response} resp
|
* @param {import('undici').Response} resp
|
||||||
*/
|
*/
|
||||||
const createReadlineInterfaceFromResponse = (resp) => {
|
const createReadlineInterfaceFromResponse = async function *(resp) {
|
||||||
if (!resp.body) {
|
if (!resp.body) {
|
||||||
throw new Error('Failed to fetch remote text');
|
throw new Error('Failed to fetch remote text');
|
||||||
}
|
}
|
||||||
if (resp.bodyUsed) {
|
if (resp.bodyUsed) {
|
||||||
throw new Error('Body has already been consumed.');
|
throw new Error('Body has already been consumed.');
|
||||||
}
|
}
|
||||||
return readline.createInterface({
|
|
||||||
input: Readable.fromWeb(resp.body),
|
let buf = '';
|
||||||
crlfDelay: Infinity
|
|
||||||
});
|
for await (const chunk of resp.body) {
|
||||||
|
const chunkStr = decoder.decode(chunk).replaceAll('\r\n', '\n');
|
||||||
|
for (let i = 0, len = chunkStr.length; i < len; i++) {
|
||||||
|
const char = chunkStr[i];
|
||||||
|
if (char === '\n') {
|
||||||
|
yield buf;
|
||||||
|
buf = '';
|
||||||
|
} else {
|
||||||
|
buf += char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf) {
|
||||||
|
yield buf;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.createReadlineInterfaceFromResponse = createReadlineInterfaceFromResponse;
|
module.exports.createReadlineInterfaceFromResponse = createReadlineInterfaceFromResponse;
|
||||||
|
|||||||
@ -2,7 +2,12 @@
|
|||||||
|
|
||||||
module.exports = require('eslint-config-sukka').sukka({
|
module.exports = require('eslint-config-sukka').sukka({
|
||||||
js: {
|
js: {
|
||||||
disableNoConsoleInCLI: ['Build/**']
|
disableNoConsoleInCLI: ['Build/**'],
|
||||||
|
env: {
|
||||||
|
customGlobals: {
|
||||||
|
'Bun': 'readonly'
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
node: true
|
node: true
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
14
package.json
14
package.json
@ -8,7 +8,7 @@
|
|||||||
"url": "git+https://github.com/SukkaW/Surge.git"
|
"url": "git+https://github.com/SukkaW/Surge.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node ./Build/index.js",
|
"build": "bun ./Build/index.ts",
|
||||||
"lint": "eslint --format=sukka ."
|
"lint": "eslint --format=sukka ."
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
@ -35,21 +35,13 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint-sukka/node": "^4.1.7",
|
"@eslint-sukka/node": "^4.1.7",
|
||||||
"@types/mocha": "10.0.2",
|
"@types/mocha": "10.0.2",
|
||||||
"@types/node": "^20.9.0",
|
"bun-types": "^1.0.11",
|
||||||
"chai": "4.3.10",
|
"chai": "4.3.10",
|
||||||
"eslint-config-sukka": "4.1.7",
|
"eslint-config-sukka": "4.1.7",
|
||||||
"eslint-formatter-sukka": "4.1.7",
|
"eslint-formatter-sukka": "4.1.7",
|
||||||
"mocha": "^10.2.0"
|
"mocha": "^10.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"resolutions": {
|
||||||
"node": ">=18.0.0"
|
|
||||||
},
|
|
||||||
"pnpm": {
|
|
||||||
"patchedDependencies": {
|
|
||||||
"@vercel/fetch-retry@5.1.3": "patches/@vercel__fetch-retry@5.1.3.patch"
|
|
||||||
},
|
|
||||||
"overrides": {
|
|
||||||
"has": "npm:@nolyfill/has@latest"
|
"has": "npm:@nolyfill/has@latest"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
1772
pnpm-lock.yaml
generated
1772
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
18
tsconfig.json
Normal file
18
tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"target": "esnext",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"types": ["bun-types"],
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user