Make ESLint Happy

This commit is contained in:
SukkaW 2023-12-03 02:04:09 +08:00
parent 34ef0e58ff
commit d4ff4c5b2d
36 changed files with 136 additions and 140 deletions

View File

@ -56,7 +56,7 @@ const getS3OSSDomains = async (): Promise<Set<string>> => {
return S3OSSDomains; return S3OSSDomains;
}; };
const buildCdnConf = task(import.meta.path, async () => { const buildCdnConf = task(import.meta.path, async () => {
/** @type {string[]} */ /** @type {string[]} */
const cdnDomainsList: string[] = []; const cdnDomainsList: string[] = [];

View File

@ -18,7 +18,7 @@ const outputSurgeDir = path.resolve(import.meta.dir, '../List');
const outputClashDir = path.resolve(import.meta.dir, '../Clash'); const outputClashDir = path.resolve(import.meta.dir, '../Clash');
export const buildCommon = task(import.meta.path, async () => { export const buildCommon = task(import.meta.path, async () => {
const promises: Promise<unknown>[] = []; const promises: Array<Promise<unknown>> = [];
const pw = new PathScurry(sourceDir); const pw = new PathScurry(sourceDir);
for await (const entry of pw) { for await (const entry of pw) {
@ -57,23 +57,22 @@ const processFile = async (sourcePath: string) => {
let title = ''; let title = '';
const descriptions: string[] = []; const descriptions: string[] = [];
try { try {
for await (const line of readFileByLine(sourcePath)) { for await (const line of readFileByLine(sourcePath)) {
if (line === MAGIC_COMMAND_SKIP) { if (line === MAGIC_COMMAND_SKIP) {
return; return;
} }
if (line.startsWith(MAGIC_COMMAND_TITLE)) { if (line.startsWith(MAGIC_COMMAND_TITLE)) {
title = line.slice(MAGIC_COMMAND_TITLE.length).trim(); title = line.slice(MAGIC_COMMAND_TITLE.length).trim();
continue; continue;
} }
if (line.startsWith(MAGIC_COMMAND_DESCRIPTION)) { if (line.startsWith(MAGIC_COMMAND_DESCRIPTION)) {
descriptions.push(line.slice(MAGIC_COMMAND_DESCRIPTION.length).trim()); descriptions.push(line.slice(MAGIC_COMMAND_DESCRIPTION.length).trim());
continue; continue;
} }
const l = processLine(line); const l = processLine(line);
if (l) { if (l) {
lines.push(l); lines.push(l);

View File

@ -11,15 +11,10 @@ export const buildDomesticRuleset = task(import.meta.path, async () => {
const results = await processLineFromReadline(readFileByLine(path.resolve(import.meta.dir, '../Source/non_ip/domestic.conf'))); const results = await processLineFromReadline(readFileByLine(path.resolve(import.meta.dir, '../Source/non_ip/domestic.conf')));
results.push( results.push(
...Object.entries(DOMESTICS) ...Object.entries(DOMESTICS).reduce<string[]>((acc, [key, { domains }]) => {
.reduce<string[]>( if (key === 'SYSTEM') return acc;
(acc, [key, { domains }]) => { return [...acc, ...domains];
if (key === 'SYSTEM') return acc; }, []).map((domain) => `DOMAIN-SUFFIX,${domain}`)
return [...acc, ...domains];
},
[]
)
.map((domain) => `DOMAIN-SUFFIX,${domain}`)
); );
const rulesetDescription = [ const rulesetDescription = [

View File

@ -1,5 +1,4 @@
// @ts-check import fsp from 'fs/promises';
import fsp from 'fs/promises'
import path from 'path'; import path from 'path';
import * as tldts from 'tldts'; import * as tldts from 'tldts';
import { processLine } from './lib/process-line'; import { processLine } from './lib/process-line';
@ -14,7 +13,7 @@ const escapeRegExp = (string = '') => string.replaceAll(/[$()*+.?[\\\]^{|}]/g, '
export const buildInternalCDNDomains = task(import.meta.path, async () => { export const buildInternalCDNDomains = task(import.meta.path, async () => {
const set = new Set<string>(); const set = new Set<string>();
const keywords = new Set(); const keywords = new Set<string>();
const gorhill = await getGorhillPublicSuffixPromise(); const gorhill = await getGorhillPublicSuffixPromise();
const domainSorter = createDomainSorter(gorhill); const domainSorter = createDomainSorter(gorhill);

View File

@ -1,5 +1,5 @@
import path from 'path'; import path from 'path';
import fsp from 'fs/promises' import fsp from 'fs/promises';
import { parseFelixDnsmasq } from './lib/parse-dnsmasq'; import { parseFelixDnsmasq } from './lib/parse-dnsmasq';
import { task } from './lib/trace-runner'; import { task } from './lib/trace-runner';
import { compareAndWriteFile } from './lib/create-file'; import { compareAndWriteFile } from './lib/create-file';

View File

@ -1,7 +1,7 @@
import { fetchRemoteTextAndCreateReadlineInterface } from './lib/fetch-remote-text-by-line'; import { fetchRemoteTextAndCreateReadlineInterface } from './lib/fetch-remote-text-by-line';
import { processLineFromReadline } from './lib/process-line'; import { processLineFromReadline } from './lib/process-line';
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';
const RESERVED_IPV4_CIDR = [ const RESERVED_IPV4_CIDR = [

View File

@ -1,7 +1,7 @@
const fsPromises = require('fs').promises; const fsPromises = require('fs').promises;
const pathFn = require('path'); const pathFn = require('path');
const table = require('table'); const table = require('table');
import listDir from '@sukka/listdir'; const listDir = require('@sukka/listdir');
const { green, yellow } = require('picocolors'); const { green, yellow } = require('picocolors');
const PRESET_MITM_HOSTNAMES = [ const PRESET_MITM_HOSTNAMES = [

View File

@ -1,10 +1,10 @@
import { processFilterRules, processHosts } from './lib/parse-filter'; import { processHosts } from './lib/parse-filter';
import path from 'path'; import path from 'path';
import { createRuleset } from './lib/create-file'; import { createRuleset } from './lib/create-file';
import { processLine } from './lib/process-line'; import { processLine } from './lib/process-line';
import { createDomainSorter } from './lib/stable-sort-domain'; import { createDomainSorter } from './lib/stable-sort-domain';
import { traceSync, task } from './lib/trace-runner'; import { traceSync, task } from './lib/trace-runner';
import createTrie from './lib/trie'; import { createTrie } from './lib/trie';
import { getGorhillPublicSuffixPromise } from './lib/get-gorhill-publicsuffix'; import { getGorhillPublicSuffixPromise } from './lib/get-gorhill-publicsuffix';
import { createCachedGorhillGetDomain } from './lib/cached-tld-parse'; import { createCachedGorhillGetDomain } from './lib/cached-tld-parse';
import * as tldts from 'tldts'; import * as tldts from 'tldts';
@ -156,11 +156,11 @@ export const buildPhishingDomainSet = task(import.meta.path, async () => {
const results = traceSync('* get final results', () => Object.entries(domainCountMap) const results = traceSync('* get final results', () => Object.entries(domainCountMap)
.reduce<string[]>((acc, [apexDomain, count]) => { .reduce<string[]>((acc, [apexDomain, count]) => {
if (count >= 5) { if (count >= 5) {
acc.push(`.${apexDomain}`); acc.push(`.${apexDomain}`);
} }
return acc; return acc;
}, []) }, [])
.sort(domainSorter)); .sort(domainSorter));
const description = [ const description = [

View File

@ -1,6 +1,6 @@
import listDir from '@sukka/listdir'; 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';
const rootPath = path.resolve(import.meta.dir, '../'); const rootPath = path.resolve(import.meta.dir, '../');

View File

@ -1,9 +1,9 @@
// @ts-check // @ts-check
import fsp from 'fs/promises' import fsp from 'fs/promises';
import path from 'path'; import path from 'path';
import { processHosts, processFilterRules } from './lib/parse-filter'; import { processHosts, processFilterRules } from './lib/parse-filter';
import createTrie from './lib/trie'; import { createTrie } from './lib/trie';
import { HOSTS, ADGUARD_FILTERS, PREDEFINED_WHITELIST, PREDEFINED_ENFORCED_BACKLIST } from './lib/reject-data-source'; import { HOSTS, ADGUARD_FILTERS, PREDEFINED_WHITELIST, PREDEFINED_ENFORCED_BACKLIST } from './lib/reject-data-source';
import { createRuleset, compareAndWriteFile } from './lib/create-file'; import { createRuleset, compareAndWriteFile } from './lib/create-file';
@ -20,13 +20,13 @@ import { SHARED_DESCRIPTION } from './lib/constants';
/** Whitelists */ /** Whitelists */
const filterRuleWhitelistDomainSets = new Set(PREDEFINED_WHITELIST); const filterRuleWhitelistDomainSets = new Set(PREDEFINED_WHITELIST);
/** @type {Set<string>} Dedupe domains inclued by DOMAIN-KEYWORD */ /** @type {Set<string>} Dedupe domains inclued by DOMAIN-KEYWORD */
const domainKeywordsSet: Set<string> = new Set(); const domainKeywordsSet = new Set<string>();
/** @type {Set<string>} Dedupe domains included by DOMAIN-SUFFIX */ /** @type {Set<string>} Dedupe domains included by DOMAIN-SUFFIX */
const domainSuffixSet: Set<string> = new Set(); const domainSuffixSet = new Set<string>();
export const buildRejectDomainSet = task(import.meta.path, async () => { export const buildRejectDomainSet = task(import.meta.path, async () => {
/** @type Set<string> */ /** @type Set<string> */
const domainSets: Set<string> = new Set(); const domainSets = new Set<string>();
// Parse from AdGuard Filters // Parse from AdGuard Filters
console.time('* Download and process Hosts / AdBlock Filter Rules'); console.time('* Download and process Hosts / AdBlock Filter Rules');
@ -91,7 +91,6 @@ export const buildRejectDomainSet = task(import.meta.path, async () => {
console.timeEnd('* Download and process Hosts / AdBlock Filter Rules'); console.timeEnd('* Download and process Hosts / AdBlock Filter Rules');
if (shouldStop) { if (shouldStop) {
// eslint-disable-next-line n/no-process-exit -- force stop
process.exit(1); process.exit(1);
} }
@ -173,7 +172,7 @@ export const buildRejectDomainSet = task(import.meta.path, async () => {
console.log(`Deduped ${previousSize - dudupedDominArray.length} rules!`); console.log(`Deduped ${previousSize - dudupedDominArray.length} rules!`);
// Create reject stats // Create reject stats
const rejectDomainsStats: [string, number][] = traceSync( const rejectDomainsStats: Array<[string, number]> = traceSync(
'* Collect reject domain stats', '* Collect reject domain stats',
() => Object.entries( () => Object.entries(
dudupedDominArray.reduce<Record<string, number>>((acc, cur) => { dudupedDominArray.reduce<Record<string, number>>((acc, cur) => {

View File

@ -14,7 +14,7 @@ const s = new Sema(3);
const latestTopUserAgentsPromise = fetchWithRetry('https://unpkg.com/top-user-agents@latest/index.json') const latestTopUserAgentsPromise = fetchWithRetry('https://unpkg.com/top-user-agents@latest/index.json')
.then(res => res.json() as Promise<string[]>); .then(res => res.json() as Promise<string[]>);
const querySpeedtestApi = async (keyword: string): Promise<(string | null)[]> => { const querySpeedtestApi = async (keyword: string): Promise<Array<string | null>> => {
const [topUserAgents] = await Promise.all([ const [topUserAgents] = await Promise.all([
latestTopUserAgentsPromise, latestTopUserAgentsPromise,
s.acquire() s.acquire()
@ -42,10 +42,10 @@ const querySpeedtestApi = async (keyword: string): Promise<(string | null)[]> =>
} }
}); });
if (!res.ok) { if (!res.ok) {
throw new Error(res.statusText + '\n' + await res.text()); throw new Error(`${res.statusText}\n${await res.text()}`);
} }
const json = await res.json() as { url: string; }[]; const json = await res.json() as Array<{ url: string }>;
s.release(); s.release();
console.timeEnd(key); console.timeEnd(key);
@ -60,7 +60,7 @@ const querySpeedtestApi = async (keyword: string): Promise<(string | null)[]> =>
export const buildSpeedtestDomainSet = task(import.meta.path, async () => { export const buildSpeedtestDomainSet = task(import.meta.path, async () => {
/** @type {Set<string>} */ /** @type {Set<string>} */
const domains: Set<string> = new Set([ const domains = new Set<string>([
'.speedtest.net', '.speedtest.net',
'.speedtestcustom.com', '.speedtestcustom.com',
'.ooklaserver.net', '.ooklaserver.net',

View File

@ -7,7 +7,7 @@ import { createRuleset } from './lib/create-file';
import { ALL, NORTH_AMERICA, EU, HK, TW, JP, KR } from '../Source/stream'; import { ALL, NORTH_AMERICA, EU, HK, TW, JP, KR } from '../Source/stream';
import { SHARED_DESCRIPTION } from './lib/constants'; import { SHARED_DESCRIPTION } from './lib/constants';
const createRulesetForStreamService = (fileId: string, title: string, streamServices: import('../Source/stream').StreamService[]) => { const createRulesetForStreamService = (fileId: string, title: string, streamServices: Array<import('../Source/stream').StreamService>) => {
return [ return [
// Domains // Domains
...createRuleset( ...createRuleset(
@ -15,10 +15,10 @@ const createRulesetForStreamService = (fileId: string, title: string, streamServ
[ [
...SHARED_DESCRIPTION, ...SHARED_DESCRIPTION,
'', '',
...streamServices.map((i: { name: any; }) => `- ${i.name}`) ...streamServices.map((i) => `- ${i.name}`)
], ],
new Date(), new Date(),
streamServices.flatMap((i: { rules: any; }) => i.rules), streamServices.flatMap((i) => i.rules),
'ruleset', 'ruleset',
path.resolve(import.meta.dir, `../List/non_ip/${fileId}.conf`), path.resolve(import.meta.dir, `../List/non_ip/${fileId}.conf`),
path.resolve(import.meta.dir, `../Clash/non_ip/${fileId}.txt`) path.resolve(import.meta.dir, `../Clash/non_ip/${fileId}.txt`)
@ -29,14 +29,14 @@ const createRulesetForStreamService = (fileId: string, title: string, streamServ
[ [
...SHARED_DESCRIPTION, ...SHARED_DESCRIPTION,
'', '',
...streamServices.map((i: { name: any; }) => `- ${i.name}`) ...streamServices.map((i) => `- ${i.name}`)
], ],
new Date(), new Date(),
streamServices.flatMap((i) => ( streamServices.flatMap((i) => (
i.ip i.ip
? [ ? [
...i.ip.v4.map((ip: any) => `IP-CIDR,${ip},no-resolve`), ...i.ip.v4.map((ip) => `IP-CIDR,${ip},no-resolve`),
...i.ip.v6.map((ip: any) => `IP-CIDR6,${ip},no-resolve`) ...i.ip.v6.map((ip) => `IP-CIDR6,${ip},no-resolve`)
] ]
: [] : []
)), )),

View File

@ -71,7 +71,7 @@ export const downloadPreviousBuild = task(import.meta.path, async () => {
return; return;
} }
const relativeEntryPath = entry.path.replace('ruleset.skk.moe-master' + path.sep, ''); const relativeEntryPath = entry.path.replace(`ruleset.skk.moe-master${path.sep}`, '');
const targetPath = path.join(import.meta.dir, '..', relativeEntryPath); const targetPath = path.join(import.meta.dir, '..', relativeEntryPath);
await fsp.mkdir(path.dirname(targetPath), { recursive: true }); await fsp.mkdir(path.dirname(targetPath), { recursive: true });
@ -105,7 +105,7 @@ export const downloadPublicSuffixList = task(import.meta.path, async () => {
fsp.mkdir(publicSuffixDir, { recursive: true }) fsp.mkdir(publicSuffixDir, { recursive: true })
]); ]);
return Bun.write(publicSuffixPath, resp); return Bun.write(publicSuffixPath, resp as Response);
}, 'download-publicsuffixlist'); }, 'download-publicsuffixlist');
if (import.meta.main) { if (import.meta.main) {

View File

@ -98,7 +98,7 @@ import { buildPublicHtml } from './build-public';
printStats(stats); printStats(stats);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
console.error('Something went wrong!') console.error('Something went wrong!');
} }
})(); })();

View File

@ -1,12 +1,12 @@
interface Node { interface Node {
/** @default 0 */ /** @default 0 */
depth?: number; depth?: number,
key: string; key: string,
/** @default false */ /** @default false */
word?: boolean; word?: boolean,
children: Record<string, Node>; children: Record<string, Node>,
fail?: Node; fail?: Node,
count: number; count: number
} }
const createNode = (key: string, depth = 0): Node => ({ const createNode = (key: string, depth = 0): Node => ({
@ -31,15 +31,15 @@ const createKeywordFilter = (keys: string[] | Set<string>) => {
const map = beginNode.children; const map = beginNode.children;
// eslint-disable-next-line guard-for-in -- plain object // eslint-disable-next-line guard-for-in -- plain object
for (const key in beginNode.children) { for (const key in beginNode.children) {
const node = map?.[key]; const node = map[key];
let failNode = beginNode.fail; let failNode = beginNode.fail;
while (failNode && !failNode.children?.[key]) { while (failNode && !failNode.children[key]) {
failNode = failNode.fail; failNode = failNode.fail;
} }
if (node) { if (node) {
node.fail = failNode?.children?.[key] || root; node.fail = failNode?.children[key] || root;
queue.push(node); queue.push(node);
} }
@ -86,8 +86,8 @@ const createKeywordFilter = (keys: string[] | Set<string>) => {
// const key = text.charAt(i); // const key = text.charAt(i);
const key = text[i]; const key = text[i];
while (node && !node?.children[key]) { while (node && !node.children[key]) {
node = node?.fail; node = node.fail;
} }
node = node?.children[key] || root; node = node?.children[key] || root;

View File

@ -1,6 +1,6 @@
import tldts from 'tldts'; import * as tldts from 'tldts';
import { createCache } from './cache-apply'; import { createCache } from './cache-apply';
import { PublicSuffixList } from 'gorhill-publicsuffixlist'; import type { PublicSuffixList } from 'gorhill-publicsuffixlist';
const cache = createCache('cached-tld-parse', true); const cache = createCache('cached-tld-parse', true);
@ -12,6 +12,6 @@ let gothillGetDomainCache: ReturnType<typeof createCache> | null = null;
export const createCachedGorhillGetDomain = (gorhill: PublicSuffixList) => { export const createCachedGorhillGetDomain = (gorhill: PublicSuffixList) => {
return (domain: string) => { return (domain: string) => {
gothillGetDomainCache ??= createCache('cached-gorhill-get-domain', true); gothillGetDomainCache ??= createCache('cached-gorhill-get-domain', true);
return gothillGetDomainCache.sync(domain, () => gorhill.getDomain(domain[0] === '.' ? domain.slice(1) : domain)) return gothillGetDomainCache.sync(domain, () => gorhill.getDomain(domain[0] === '.' ? domain.slice(1) : domain));
}; };
}; };

View File

@ -1,5 +1,5 @@
export const SHARED_DESCRIPTION = [ export const SHARED_DESCRIPTION = [
'License: AGPL 3.0', 'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe', 'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge', 'GitHub: https://github.com/SukkaW/Surge'
] as const; ] as const;

View File

@ -85,7 +85,7 @@ export const createRuleset = (
_clashContent = surgeRulesetToClashClassicalTextRuleset(content); _clashContent = surgeRulesetToClashClassicalTextRuleset(content);
break; break;
default: default:
throw new TypeError(`Unknown type: ${type}`); throw new TypeError(`Unknown type: ${type as any}`);
} }
const clashContent = withBannerArray(title, description, date, _clashContent); const clashContent = withBannerArray(title, description, date, _clashContent);

View File

@ -1,4 +1,4 @@
import createTrie from './trie'; import { createTrie } from './trie';
export const domainDeduper = (inputDomains: string[]): string[] => { export const domainDeduper = (inputDomains: string[]): string[] => {
const trie = createTrie(inputDomains); const trie = createTrie(inputDomains);

View File

@ -9,11 +9,32 @@ const FACTOR = 6;
function isClientError(err: any): err is NodeJS.ErrnoException { function isClientError(err: any): err is NodeJS.ErrnoException {
if (!err) return false; if (!err) return false;
return ( return (
err.code === 'ERR_UNESCAPED_CHARACTERS' || err.code === 'ERR_UNESCAPED_CHARACTERS'
err.message === 'Request path contains unescaped characters' || err.message === 'Request path contains unescaped characters'
); );
} }
export class ResponseError extends Error {
readonly res: Response;
readonly code: number;
readonly statusCode: number;
readonly url: string;
constructor(res: Response) {
super(res.statusText);
if ('captureStackTrace' in Error) {
Error.captureStackTrace(this, ResponseError);
}
this.name = this.constructor.name;
this.res = res;
this.code = res.status;
this.statusCode = res.status;
this.url = res.url;
}
}
interface FetchRetryOpt { interface FetchRetryOpt {
minTimeout?: number, minTimeout?: number,
retries?: number, retries?: number,
@ -32,7 +53,7 @@ function createFetchRetry($fetch: typeof fetch): typeof fetch {
minTimeout: MIN_TIMEOUT, minTimeout: MIN_TIMEOUT,
retries: MAX_RETRIES, retries: MAX_RETRIES,
factor: FACTOR, factor: FACTOR,
maxRetryAfter: MAX_RETRY_AFTER, maxRetryAfter: MAX_RETRY_AFTER
}, },
opts.retry opts.retry
); );
@ -41,19 +62,18 @@ function createFetchRetry($fetch: typeof fetch): typeof fetch {
return await retry(async (bail) => { return await retry(async (bail) => {
try { try {
// this will be retried // this will be retried
const res = await $fetch(url, opts); const res = (await $fetch(url, opts)) as Response;
if ((res.status >= 500 && res.status < 600) || res.status === 429) { if ((res.status >= 500 && res.status < 600) || res.status === 429) {
// NOTE: doesn't support http-date format // NOTE: doesn't support http-date format
const retryAfterHeader = res.headers.get('retry-after'); const retryAfterHeader = res.headers.get('retry-after');
if (retryAfterHeader) { if (retryAfterHeader) {
const retryAfter = parseInt(retryAfterHeader, 10); const retryAfter = Number.parseInt(retryAfterHeader, 10);
if (retryAfter) { if (retryAfter) {
if (retryAfter > retryOpts.maxRetryAfter) { if (retryAfter > retryOpts.maxRetryAfter) {
return res; return res;
} else {
await new Promise((r) => setTimeout(r, retryAfter * 1e3));
} }
await Bun.sleep(retryAfter * 1e3);
} }
} }
throw new ResponseError(res); throw new ResponseError(res);
@ -78,7 +98,7 @@ function createFetchRetry($fetch: typeof fetch): typeof fetch {
} }
throw err; throw err;
} }
} };
for (const k of Object.keys($fetch)) { for (const k of Object.keys($fetch)) {
const key = k as keyof typeof $fetch; const key = k as keyof typeof $fetch;
@ -88,30 +108,10 @@ function createFetchRetry($fetch: typeof fetch): typeof fetch {
return fetchRetry as typeof fetch; return fetchRetry as typeof fetch;
} }
export class ResponseError extends Error {
readonly res: Response;
readonly code: number;
readonly statusCode: number;
readonly url: string;
constructor(res: Response) {
super(res.statusText);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ResponseError);
}
this.name = this.constructor.name;
this.res = res;
this.code = this.statusCode = res.status;
this.url = res.url;
}
}
export const defaultRequestInit: RequestInit = { export const defaultRequestInit: RequestInit = {
headers: { headers: {
'User-Agent': 'curl/8.1.2 (https://github.com/SukkaW/Surge)' 'User-Agent': 'curl/8.1.2 (https://github.com/SukkaW/Surge)'
} }
} };
export const fetchWithRetry = createFetchRetry(fetch); export const fetchWithRetry = createFetchRetry(fetch);

View File

@ -7,7 +7,7 @@ import type { PublicSuffixList } from 'gorhill-publicsuffixlist';
const publicSuffixPath = path.resolve(import.meta.dir, '../../node_modules/.cache/public_suffix_list_dat.txt'); const publicSuffixPath = path.resolve(import.meta.dir, '../../node_modules/.cache/public_suffix_list_dat.txt');
const getGorhillPublicSuffix = () => traceAsync('create gorhill public suffix instance', async () => { const getGorhillPublicSuffix = () => traceAsync('create gorhill public suffix instance', async () => {
const customFetch = async (url: string | URL) => Bun.file(url); const customFetch = (url: string | URL) => Promise.resolve(Bun.file(url));
const publicSuffixFile = Bun.file(publicSuffixPath); const publicSuffixFile = Bun.file(publicSuffixPath);

View File

@ -1,8 +1,8 @@
import { fetchRemoteTextAndCreateReadlineInterface } from './fetch-remote-text-by-line'; import { fetchRemoteTextAndCreateReadlineInterface } from './fetch-remote-text-by-line';
import tldts from 'tldts'; import { parse } from 'tldts';
const isDomainLoose = (domain: string): boolean => { const isDomainLoose = (domain: string): boolean => {
const { isIcann, isPrivate, isIp } = tldts.parse(domain); const { isIcann, isPrivate, isIp } = parse(domain);
return !!(!isIp && (isIcann || isPrivate)); return !!(!isIp && (isIcann || isPrivate));
}; };

View File

@ -8,7 +8,7 @@ import { performance } from 'perf_hooks';
import { getGorhillPublicSuffixPromise } from './get-gorhill-publicsuffix'; import { getGorhillPublicSuffixPromise } from './get-gorhill-publicsuffix';
import type { PublicSuffixList } from 'gorhill-publicsuffixlist'; import type { PublicSuffixList } from 'gorhill-publicsuffixlist';
const DEBUG_DOMAIN_TO_FIND = null; // example.com | null const DEBUG_DOMAIN_TO_FIND: string | null = null; // example.com | null
let foundDebugDomain = false; let foundDebugDomain = false;
const warnOnceUrl = new Set<string>(); const warnOnceUrl = new Set<string>();
@ -63,7 +63,7 @@ export async function processDomainLists(domainListsUrl: string | URL) {
} }
export async function processHosts(hostsUrl: string | URL, includeAllSubDomain = false, skipDomainCheck = false) { export async function processHosts(hostsUrl: string | URL, includeAllSubDomain = false, skipDomainCheck = false) {
console.time(`- processHosts: ${hostsUrl}`); console.time(`- processHosts: ${hostsUrl.toString()}`);
if (typeof hostsUrl === 'string') { if (typeof hostsUrl === 'string') {
hostsUrl = new URL(hostsUrl); hostsUrl = new URL(hostsUrl);
@ -95,14 +95,14 @@ export async function processHosts(hostsUrl: string | URL, includeAllSubDomain =
} }
} }
console.timeEnd(` - processHosts: ${hostsUrl}`); console.timeEnd(` - processHosts: ${hostsUrl.toString()}`);
return domainSets; return domainSets;
} }
export async function processFilterRules( export async function processFilterRules(
filterRulesUrl: string | URL, filterRulesUrl: string | URL,
fallbackUrls?: readonly (string | URL)[] | undefined fallbackUrls?: ReadonlyArray<string | URL> | undefined
): Promise<{ white: Set<string>, black: Set<string>, foundDebugDomain: boolean }> { ): Promise<{ white: Set<string>, black: Set<string>, foundDebugDomain: boolean }> {
const runStart = performance.now(); const runStart = performance.now();
@ -167,7 +167,7 @@ export async function processFilterRules(
addToBlackList(hostname, true); addToBlackList(hostname, true);
break; break;
default: default:
throw new Error(`Unknown flag: ${flag}`); throw new Error(`Unknown flag: ${flag as any}`);
} }
} }
}; };
@ -192,7 +192,7 @@ export async function processFilterRules(
/** @type string[] */ /** @type string[] */
filterRules = ( filterRules = (
await Promise.any( await Promise.any(
[filterRulesUrl, ...(fallbackUrls || [])].map(async url => { [filterRulesUrl, ...fallbackUrls].map(async url => {
const r = await fetchWithRetry(url, { signal: controller.signal, ...defaultRequestInit }); const r = await fetchWithRetry(url, { signal: controller.signal, ...defaultRequestInit });
const text = await r.text(); const text = await r.text();
@ -202,7 +202,7 @@ export async function processFilterRules(
) )
).split('\n'); ).split('\n');
} catch (e) { } catch (e) {
console.log(`Download Rule for [${filterRulesUrl}] failed`); console.log(`Download Rule for [${filterRulesUrl.toString()}] failed`);
throw e; throw e;
} }
downloadTime = performance.now() - downloadStart; downloadTime = performance.now() - downloadStart;
@ -212,7 +212,7 @@ export async function processFilterRules(
} }
} }
console.log(` ┬ processFilterRules (${filterRulesUrl}): ${(performance.now() - runStart).toFixed(3)}ms`); console.log(` ┬ processFilterRules (${filterRulesUrl.toString()}): ${(performance.now() - runStart).toFixed(3)}ms`);
console.log(` └── download time: ${downloadTime.toFixed(3)}ms`); console.log(` └── download time: ${downloadTime.toFixed(3)}ms`);
return { return {

View File

@ -177,7 +177,7 @@ export const PREDEFINED_WHITELIST = [
// https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_trackers.txt // https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_trackers.txt
'vlscppe.microsoft.com', 'vlscppe.microsoft.com',
// OpenAI use this for A/B testing // OpenAI use this for A/B testing
'statsig.com', 'statsig.com'
]; ];
export const PREDEFINED_ENFORCED_BACKLIST = [ export const PREDEFINED_ENFORCED_BACKLIST = [

View File

@ -1,4 +1,5 @@
import domainSorter from './stable-sort-domain'; import domainSorter from './stable-sort-domain';
// eslint-disable-next-line import/no-unresolved -- fuck eslint-import
import { describe, it, expect } from 'bun:test'; import { describe, it, expect } from 'bun:test';
describe('stable-sort-domain', () => { describe('stable-sort-domain', () => {

View File

@ -50,6 +50,7 @@ const createDomainSorter = (gorhill: PublicSuffixList | null = null) => {
}; };
} }
// eslint-disable-next-line @typescript-eslint/no-var-requires -- fuck
const tldts = require('./cached-tld-parse'); const tldts = require('./cached-tld-parse');
return (a: string, b: string) => { return (a: string, b: string) => {

View File

@ -22,7 +22,7 @@ export class PolyfillTextDecoderStream extends TransformStream<Uint8Array, strin
constructor( constructor(
encoding: Encoding = 'utf-8', encoding: Encoding = 'utf-8',
{ fatal = false, ignoreBOM = false }: ConstructorParameters<typeof TextDecoder>[1] = {}, { fatal = false, ignoreBOM = false }: ConstructorParameters<typeof TextDecoder>[1] = {}
) { ) {
const decoder = new TextDecoder(encoding, { fatal, ignoreBOM }); const decoder = new TextDecoder(encoding, { fatal, ignoreBOM });
super({ super({

View File

@ -4,7 +4,7 @@
interface TextLineStreamOptions { interface TextLineStreamOptions {
/** Allow splitting by solo \r */ /** Allow splitting by solo \r */
allowCR: boolean; allowCR: boolean
} }
/** Transform a stream into a stream where each chunk is divided by a newline, /** Transform a stream into a stream where each chunk is divided by a newline,
@ -36,8 +36,8 @@ export class TextLineStream extends TransformStream<string, string> {
const crIndex = chunk.indexOf('\r'); const crIndex = chunk.indexOf('\r');
if ( if (
crIndex !== -1 && crIndex !== (chunk.length - 1) && crIndex !== -1 && crIndex !== (chunk.length - 1)
(lfIndex === -1 || (lfIndex - 1) > crIndex) && (lfIndex === -1 || (lfIndex - 1) > crIndex)
) { ) {
controller.enqueue(chunk.slice(0, crIndex)); controller.enqueue(chunk.slice(0, crIndex));
chunk = chunk.slice(crIndex + 1); chunk = chunk.slice(crIndex + 1);
@ -62,13 +62,14 @@ export class TextLineStream extends TransformStream<string, string> {
}, },
flush(controller) { flush(controller) {
if (__buf.length > 0) { if (__buf.length > 0) {
// eslint-disable-next-line sukka-ts/string/prefer-string-starts-ends-with -- performance
if (allowCR && __buf[__buf.length - 1] === '\r') { if (allowCR && __buf[__buf.length - 1] === '\r') {
controller.enqueue(__buf.slice(0, -1)); controller.enqueue(__buf.slice(0, -1));
} else { } else {
controller.enqueue(__buf); controller.enqueue(__buf);
}; }
} }
}, }
}); });
} }
} }

View File

@ -19,9 +19,9 @@ const traceAsync = async <T>(prefix: string, fn: () => Promise<T>): Promise<T> =
export { traceAsync }; export { traceAsync };
export interface TaskResult { export interface TaskResult {
readonly start: number; readonly start: number,
readonly end: number; readonly end: number,
readonly taskName: string; readonly taskName: string
} }
const task = <T>(importMetaPath: string, fn: () => Promise<T>, customname: string | null = null) => { const task = <T>(importMetaPath: string, fn: () => Promise<T>, customname: string | null = null) => {

View File

@ -1,4 +1,5 @@
import createTrie from './trie'; import { createTrie } from './trie';
// eslint-disable-next-line import/no-unresolved -- fuck eslint-import
import { describe, expect, it } from 'bun:test'; import { describe, expect, it } from 'bun:test';
describe('Trie', () => { describe('Trie', () => {

View File

@ -8,7 +8,7 @@ export const SENTINEL: string = String.fromCodePoint(0);
* @param {string[] | Set<string>} [from] * @param {string[] | Set<string>} [from]
*/ */
export const createTrie = (from?: string[] | Set<string>) => { export const createTrie = (from?: string[] | Set<string>) => {
let size: number = 0; let size = 0;
const root: any = {}; const root: any = {};
/** /**
@ -56,7 +56,7 @@ export const createTrie = (from?: string[] | Set<string>) => {
* @param {boolean} [includeEqualWithSuffix] * @param {boolean} [includeEqualWithSuffix]
* @return {string[]} * @return {string[]}
*/ */
const find = (suffix: string, includeEqualWithSuffix: boolean = true): string[] => { const find = (suffix: string, includeEqualWithSuffix = true): string[] => {
let node: any = root; let node: any = root;
const matches: string[] = []; const matches: string[] = [];
let token: string; let token: string;

32
Build/mod.d.ts vendored
View File

@ -2,33 +2,33 @@ declare module 'gorhill-publicsuffixlist' {
type Selfie = type Selfie =
| string | string
| { | {
magic: number; magic: number,
buf32: number[]; buf32: number[]
}; };
interface Decoder { interface Decoder {
decode: (bufferStr: string, buffer: ArrayBuffer) => void; decode: (bufferStr: string, buffer: ArrayBuffer) => void,
decodeSize: (bufferStr: string) => number; decodeSize: (bufferStr: string) => number
} }
interface Encoder { interface Encoder {
encode: (buffer: ArrayBuffer, length: number) => string; encode: (buffer: ArrayBuffer, length: number) => string
} }
export interface PublicSuffixList { export interface PublicSuffixList {
version: string; version: string,
parse(text: string, toAscii: (input: string) => string): void; parse(text: string, toAscii: (input: string) => string): void,
getPublicSuffix(hostname: string): string; getPublicSuffix(hostname: string): string,
getDomain(hostname: string): string; getDomain(hostname: string): string,
suffixInPSL(hostname: string): boolean; suffixInPSL(hostname: string): boolean,
toSelfie(encoder?: null | Encoder): Selfie; toSelfie(encoder?: null | Encoder): Selfie,
fromSelfie(selfie: Selfie, decoder?: null | Decoder): boolean; fromSelfie(selfie: Selfie, decoder?: null | Decoder): boolean,
enableWASM(options?: { enableWASM(options?: {
customFetch?: null | ((url: URL) => Promise<Blob>); customFetch?: null | ((url: URL) => Promise<Blob>)
}): Promise<boolean>; }): Promise<boolean>,
disableWASM(): Promise<boolean>; disableWASM(): Promise<boolean>
} }
const psl: PublicSuffixList; const psl: PublicSuffixList;

View File

@ -9,7 +9,7 @@ const handleMessage = async (e: MessageEvent<'build' | 'exit'>) => {
if (e.data === 'build') { if (e.data === 'build') {
const stat = await promise; const stat = await promise;
postMessage(stat); postMessage(stat);
} else if (e.data === 'exit') { } else /* if (e.data === 'exit') */ {
self.removeEventListener('message', handleMessage); self.removeEventListener('message', handleMessage);
self.unref(); self.unref();
self.terminate(); self.terminate();

BIN
bun.lockb

Binary file not shown.

View File

@ -5,7 +5,7 @@ module.exports = require('eslint-config-sukka').sukka({
disableNoConsoleInCLI: ['Build/**'], disableNoConsoleInCLI: ['Build/**'],
env: { env: {
customGlobals: { customGlobals: {
'Bun': 'readonly' Bun: 'readonly'
} }
} }
}, },

View File

@ -31,14 +31,14 @@
"tldts": "^6.0.22" "tldts": "^6.0.22"
}, },
"devDependencies": { "devDependencies": {
"@eslint-sukka/node": "4.1.9", "@eslint-sukka/node": "4.1.10-beta.2",
"@eslint-sukka/ts": "4.1.9", "@eslint-sukka/ts": "4.1.10-beta.2",
"@types/async-retry": "^1.4.8", "@types/async-retry": "^1.4.8",
"@types/mocha": "10.0.2", "@types/mocha": "10.0.2",
"@types/tar": "^6.1.9", "@types/tar": "^6.1.9",
"bun-types": "^1.0.11", "bun-types": "^1.0.11",
"chai": "4.3.10", "chai": "4.3.10",
"eslint-config-sukka": "4.1.9", "eslint-config-sukka": "4.1.10-beta.2",
"eslint-formatter-sukka": "4.1.9", "eslint-formatter-sukka": "4.1.9",
"mocha": "^10.2.0", "mocha": "^10.2.0",
"typescript": "^5.2.2" "typescript": "^5.2.2"