diff --git a/Build/build-sgmodule-redirect.ts b/Build/build-sgmodule-redirect.ts index f83e98a7..633fcacc 100644 --- a/Build/build-sgmodule-redirect.ts +++ b/Build/build-sgmodule-redirect.ts @@ -2,7 +2,7 @@ import path from 'node:path'; import { task } from './trace'; import { compareAndWriteFile } from './lib/create-file'; import { getHostname } from 'tldts-experimental'; -import { isTruthy } from './lib/misc'; +import { isTruthy } from 'foxts/guard'; import { OUTPUT_MODULES_DIR } from './constants/dir'; function escapeRegExp(string = '') { diff --git a/Build/build-sspanel-appprofile.ts b/Build/build-sspanel-appprofile.ts index 81e39d67..a6063e03 100644 --- a/Build/build-sspanel-appprofile.ts +++ b/Build/build-sspanel-appprofile.ts @@ -9,7 +9,7 @@ import { getChnCidrPromise } from './build-chn-cidr'; import { getTelegramCIDRPromise } from './build-telegram-cidr'; import { compareAndWriteFile, RulesetOutput } from './lib/create-file'; import { getMicrosoftCdnRulesetPromise } from './build-microsoft-cdn'; -import { isTruthy } from './lib/misc'; +import { isTruthy } from 'foxts/guard'; import { appendArrayInPlace } from './lib/append-array-in-place'; import { OUTPUT_INTERNAL_DIR, OUTPUT_SURGE_DIR, SOURCE_DIR } from './constants/dir'; diff --git a/Build/lib/cache-filesystem.ts b/Build/lib/cache-filesystem.ts index 79a7b95d..dd3d1549 100644 --- a/Build/lib/cache-filesystem.ts +++ b/Build/lib/cache-filesystem.ts @@ -4,7 +4,10 @@ import os from 'node:os'; import path from 'node:path'; import { mkdirSync } from 'node:fs'; import picocolors from 'picocolors'; -import { fastStringArrayJoin, identity, mergeHeaders } from './misc'; +import { mergeHeaders } from 'foxts/merge-headers'; +import { headersToObject } from 'foxts/headers-to-object'; +import { identity } from 'foxts/identity'; +import { fastStringArrayJoin } from 'foxts/fast-string-array-join'; import { performance } from 'node:perf_hooks'; import fs from 'node:fs'; import { stringHash } from './string-hash'; @@ -250,7 +253,7 @@ export class Cache { { ...defaultRequestInit, headers: (typeof etag === 'string' && etag.length > 0) - ? mergeHeaders>(defaultRequestInit.headers, { 'If-None-Match': etag }) + ? headersToObject(mergeHeaders(defaultRequestInit.headers, { 'If-None-Match': etag })) : defaultRequestInit.headers } ); @@ -308,7 +311,7 @@ export class Cache { signal: controller.signal, ...defaultRequestInit, headers: (typeof etag === 'string' && etag.length > 0 && typeof previouslyCached === 'string' && previouslyCached.length > 1) - ? mergeHeaders>(defaultRequestInit.headers, { 'If-None-Match': etag }) + ? headersToObject(mergeHeaders(defaultRequestInit.headers, { 'If-None-Match': etag })) : defaultRequestInit.headers } ); diff --git a/Build/lib/fs-memo.ts b/Build/lib/fs-memo.ts index 19efb41a..ed7a43fe 100644 --- a/Build/lib/fs-memo.ts +++ b/Build/lib/fs-memo.ts @@ -6,7 +6,8 @@ import { isCI } from 'ci-info'; import { xxhash64 } from 'hash-wasm'; import picocolors from 'picocolors'; -import { fastStringArrayJoin, identity } from './misc'; +import { fastStringArrayJoin } from 'foxts/fast-string-array-join'; +import { identity } from 'foxts/identity'; const fsMemoCache = new Cache({ cachePath: path.resolve(__dirname, '../../.cache'), tableName: 'fs_memo_cache' }); diff --git a/Build/lib/misc.ts b/Build/lib/misc.ts index 0db5c4e2..6d269fa5 100644 --- a/Build/lib/misc.ts +++ b/Build/lib/misc.ts @@ -2,24 +2,6 @@ import path, { dirname } from 'node:path'; import fs from 'node:fs'; import fsp from 'node:fs/promises'; import { OUTPUT_CLASH_DIR, OUTPUT_SINGBOX_DIR, OUTPUT_SURGE_DIR } from '../constants/dir'; -import type { HeadersInit } from 'undici'; - -export const isTruthy = (i: T | 0 | '' | false | null | undefined): i is T => !!i; - -export function fastStringArrayJoin(arr: string[], sep: string) { - const len = arr.length; - if (len === 0) { - return ''; - } - - let result = arr[0]; - - for (let i = 1; i < len; i++) { - result += sep; - result += arr[i]; - } - return result; -} export function fastStringCompare(a: string, b: string) { const lenA = a.length; @@ -86,22 +68,6 @@ export function domainWildCardToRegex(domain: string) { return result; } -export const identity = (x: T): R => x as any; - -export function appendArrayFromSet(dest: T[], source: Set | Array>, transformer: (item: T) => T = identity) { - const casted = Array.isArray(source) ? source : [source]; - for (let i = 0, len = casted.length; i < len; i++) { - const iterator = casted[i].values(); - let step: IteratorResult; - - while ((step = iterator.next(), !step.done)) { - dest.push(transformer(step.value)); - } - } - - return dest; -} - export function output(id: string, type: 'non_ip' | 'ip' | 'domainset') { return [ path.join(OUTPUT_SURGE_DIR, type, id + '.conf'), @@ -122,30 +88,3 @@ export function withBannerArray(title: string, description: string[] | readonly '################## EOF ##################' ]; }; - -export function mergeHeaders(headersA: T | undefined, headersB: T | undefined): T { - if (headersA == null) { - return headersB!; - } - - if (Array.isArray(headersB)) { - throw new TypeError('Array headers is not supported'); - } - - const result = new Headers(headersA as any); - - if (headersB instanceof Headers) { - headersB.forEach((value, key) => { - result.set(key, value); - }); - return result as T; - } - - for (const key in headersB) { - if (Object.hasOwn(headersB, key)) { - result.set(key, (headersB as Record)[key]); - } - } - - return result as T; -} diff --git a/Build/lib/parse-filter.ts b/Build/lib/parse-filter.ts index 3ee26b3c..643f3eb2 100644 --- a/Build/lib/parse-filter.ts +++ b/Build/lib/parse-filter.ts @@ -8,7 +8,7 @@ import { deserializeArray, fsFetchCache, serializeArray, getFileContentHash } fr import type { Span } from '../trace'; import createKeywordFilter from './aho-corasick'; import { looseTldtsOpt } from '../constants/loose-tldts-opt'; -import { identity } from './misc'; +import { identity } from 'foxts/identity'; import { DEBUG_DOMAIN_TO_FIND } from '../constants/reject-data-source'; let foundDebugDomain = false; diff --git a/Build/lib/rules/base.ts b/Build/lib/rules/base.ts index 0d3450a1..57a94430 100644 --- a/Build/lib/rules/base.ts +++ b/Build/lib/rules/base.ts @@ -7,7 +7,8 @@ import { withBannerArray } from '../misc'; import { invariant } from 'foxact/invariant'; import picocolors from 'picocolors'; import fs from 'node:fs'; -import { fastStringArrayJoin, writeFile } from '../misc'; +import { writeFile } from '../misc'; +import { fastStringArrayJoin } from 'foxts/fast-string-array-join'; import { readFileByLine } from '../fetch-text-by-line'; import { asyncWriteToStream } from '../async-write-to-stream'; diff --git a/Build/lib/rules/ip.ts b/Build/lib/rules/ip.ts index fc8ba9da..e0b1082b 100644 --- a/Build/lib/rules/ip.ts +++ b/Build/lib/rules/ip.ts @@ -1,6 +1,6 @@ import type { Span } from '../../trace'; import { appendArrayInPlace } from '../append-array-in-place'; -import { appendArrayFromSet } from '../misc'; +import { appendSetElementsToArray } from 'foxts/append-set-elements-to-array'; import type { SingboxSourceFormat } from '../singbox'; import { RuleOutput } from './base'; @@ -26,8 +26,8 @@ export class IPListOutput extends RuleOutput { true ) ); - appendArrayFromSet(results, this.ipcidr6NoResolve); - appendArrayFromSet(results, this.ipcidr6); + appendSetElementsToArray(results, this.ipcidr6NoResolve); + appendSetElementsToArray(results, this.ipcidr6); return results; } @@ -42,12 +42,12 @@ export class IPListOutput extends RuleOutput { results, merge(Array.from(this.ipcidrNoResolve)).map(i => `IP-CIDR,${i},no-resolve`, true) ); - appendArrayFromSet(results, this.ipcidr6NoResolve, i => `IP-CIDR6,${i},no-resolve`); + appendSetElementsToArray(results, this.ipcidr6NoResolve, i => `IP-CIDR6,${i},no-resolve`); appendArrayInPlace( results, merge(Array.from(this.ipcidr)).map(i => `IP-CIDR,${i}`, true) ); - appendArrayFromSet(results, this.ipcidr6, i => `IP-CIDR6,${i}`); + appendSetElementsToArray(results, this.ipcidr6, i => `IP-CIDR6,${i}`); this.$surge = results; } diff --git a/Build/lib/rules/ruleset.ts b/Build/lib/rules/ruleset.ts index 32ba4133..d28562d1 100644 --- a/Build/lib/rules/ruleset.ts +++ b/Build/lib/rules/ruleset.ts @@ -2,7 +2,7 @@ import { merge } from 'fast-cidr-tools'; import type { Span } from '../../trace'; import createKeywordFilter from '../aho-corasick'; import { appendArrayInPlace } from '../append-array-in-place'; -import { appendArrayFromSet } from '../misc'; +import { appendSetElementsToArray } from 'foxts/append-set-elements-to-array'; import type { SingboxSourceFormat } from '../singbox'; import { RuleOutput } from './base'; import picocolors from 'picocolors'; @@ -43,37 +43,37 @@ export class RulesetOutput extends RuleOutput { const results: string[] = ['DOMAIN,this_ruleset_is_made_by_sukkaw.ruleset.skk.moe']; appendArrayInPlace(results, this.$preprocessed[2]); - appendArrayFromSet(results, this.domainKeywords, i => `DOMAIN-KEYWORD,${i}`); - appendArrayFromSet(results, this.domainWildcard, i => `DOMAIN-WILDCARD,${i}`); + appendSetElementsToArray(results, this.domainKeywords, i => `DOMAIN-KEYWORD,${i}`); + appendSetElementsToArray(results, this.domainWildcard, i => `DOMAIN-WILDCARD,${i}`); - appendArrayFromSet(results, this.userAgent, i => `USER-AGENT,${i}`); + appendSetElementsToArray(results, this.userAgent, i => `USER-AGENT,${i}`); - appendArrayFromSet(results, this.processName, i => `PROCESS-NAME,${i}`); - appendArrayFromSet(results, this.processPath, i => `PROCESS-NAME,${i}`); + appendSetElementsToArray(results, this.processName, i => `PROCESS-NAME,${i}`); + appendSetElementsToArray(results, this.processPath, i => `PROCESS-NAME,${i}`); - appendArrayFromSet(results, this.sourceIpOrCidr, i => `SRC-IP,${i}`); - appendArrayFromSet(results, this.sourcePort, i => `SRC-PORT,${i}`); - appendArrayFromSet(results, this.destPort, i => `DEST-PORT,${i}`); + appendSetElementsToArray(results, this.sourceIpOrCidr, i => `SRC-IP,${i}`); + appendSetElementsToArray(results, this.sourcePort, i => `SRC-PORT,${i}`); + appendSetElementsToArray(results, this.destPort, i => `DEST-PORT,${i}`); appendArrayInPlace(results, this.otherRules); - appendArrayFromSet(results, this.urlRegex, i => `URL-REGEX,${i}`); + appendSetElementsToArray(results, this.urlRegex, i => `URL-REGEX,${i}`); appendArrayInPlace( results, merge(Array.from(this.ipcidrNoResolve)).map(i => `IP-CIDR,${i},no-resolve`, true) ); - appendArrayFromSet(results, this.ipcidr6NoResolve, i => `IP-CIDR6,${i},no-resolve`); - appendArrayFromSet(results, this.ipasnNoResolve, i => `IP-ASN,${i},no-resolve`); - appendArrayFromSet(results, this.groipNoResolve, i => `GEOIP,${i},no-resolve`); + appendSetElementsToArray(results, this.ipcidr6NoResolve, i => `IP-CIDR6,${i},no-resolve`); + appendSetElementsToArray(results, this.ipasnNoResolve, i => `IP-ASN,${i},no-resolve`); + appendSetElementsToArray(results, this.groipNoResolve, i => `GEOIP,${i},no-resolve`); appendArrayInPlace( results, merge(Array.from(this.ipcidr)).map(i => `IP-CIDR,${i}`, true) ); - appendArrayFromSet(results, this.ipcidr6, i => `IP-CIDR6,${i}`); - appendArrayFromSet(results, this.ipasn, i => `IP-ASN,${i}`); - appendArrayFromSet(results, this.geoip, i => `GEOIP,${i}`); + appendSetElementsToArray(results, this.ipcidr6, i => `IP-CIDR6,${i}`); + appendSetElementsToArray(results, this.ipasn, i => `IP-ASN,${i}`); + appendSetElementsToArray(results, this.geoip, i => `GEOIP,${i}`); return results; } @@ -83,13 +83,13 @@ export class RulesetOutput extends RuleOutput { appendArrayInPlace(results, this.$preprocessed[2]); - appendArrayFromSet(results, this.domainKeywords, i => `DOMAIN-KEYWORD,${i}`); - appendArrayFromSet(results, this.domainWildcard, i => `DOMAIN-REGEX,${RuleOutput.domainWildCardToRegex(i)}`); + appendSetElementsToArray(results, this.domainKeywords, i => `DOMAIN-KEYWORD,${i}`); + appendSetElementsToArray(results, this.domainWildcard, i => `DOMAIN-REGEX,${RuleOutput.domainWildCardToRegex(i)}`); - appendArrayFromSet(results, this.processName, i => `PROCESS-NAME,${i}`); - appendArrayFromSet(results, this.processPath, i => `PROCESS-PATH,${i}`); + appendSetElementsToArray(results, this.processName, i => `PROCESS-NAME,${i}`); + appendSetElementsToArray(results, this.processPath, i => `PROCESS-PATH,${i}`); - appendArrayFromSet(results, this.sourceIpOrCidr, value => { + appendSetElementsToArray(results, this.sourceIpOrCidr, value => { if (value.includes('/')) { return `SRC-IP-CIDR,${value}`; } @@ -101,8 +101,8 @@ export class RulesetOutput extends RuleOutput { } return ''; }); - appendArrayFromSet(results, this.sourcePort, i => `SRC-PORT,${i}`); - appendArrayFromSet(results, this.destPort, i => `DST-PORT,${i}`); + appendSetElementsToArray(results, this.sourcePort, i => `SRC-PORT,${i}`); + appendSetElementsToArray(results, this.destPort, i => `DST-PORT,${i}`); // appendArrayInPlace(results, this.otherRules); @@ -110,17 +110,17 @@ export class RulesetOutput extends RuleOutput { results, merge(Array.from(this.ipcidrNoResolve)).map(i => `IP-CIDR,${i},no-resolve`, true) ); - appendArrayFromSet(results, this.ipcidr6NoResolve, i => `IP-CIDR6,${i},no-resolve`); - appendArrayFromSet(results, this.ipasnNoResolve, i => `IP-ASN,${i},no-resolve`); - appendArrayFromSet(results, this.groipNoResolve, i => `GEOIP,${i},no-resolve`); + appendSetElementsToArray(results, this.ipcidr6NoResolve, i => `IP-CIDR6,${i},no-resolve`); + appendSetElementsToArray(results, this.ipasnNoResolve, i => `IP-ASN,${i},no-resolve`); + appendSetElementsToArray(results, this.groipNoResolve, i => `GEOIP,${i},no-resolve`); appendArrayInPlace( results, merge(Array.from(this.ipcidr)).map(i => `IP-CIDR,${i}`, true) ); - appendArrayFromSet(results, this.ipcidr6, i => `IP-CIDR6,${i}`); - appendArrayFromSet(results, this.ipasn, i => `IP-ASN,${i}`); - appendArrayFromSet(results, this.geoip, i => `GEOIP,${i}`); + appendSetElementsToArray(results, this.ipcidr6, i => `IP-CIDR6,${i}`); + appendSetElementsToArray(results, this.ipasn, i => `IP-ASN,${i}`); + appendSetElementsToArray(results, this.geoip, i => `GEOIP,${i}`); return results; } @@ -134,8 +134,8 @@ export class RulesetOutput extends RuleOutput { true ) ); - appendArrayFromSet(ip_cidr, this.ipcidr6NoResolve); - appendArrayFromSet(ip_cidr, this.ipcidr6); + appendSetElementsToArray(ip_cidr, this.ipcidr6NoResolve); + appendSetElementsToArray(ip_cidr, this.ipcidr6); const singbox: SingboxSourceFormat = { version: 2, diff --git a/Build/lib/trie.ts b/Build/lib/trie.ts index 36ecb580..e4ef8794 100644 --- a/Build/lib/trie.ts +++ b/Build/lib/trie.ts @@ -2,9 +2,10 @@ * Hostbane-Optimized Trie based on Mnemonist Trie */ -import { fastStringArrayJoin, fastStringCompare } from './misc'; +import { fastStringCompare } from './misc'; import util from 'node:util'; import { noop } from 'foxact/noop'; +import { fastStringArrayJoin } from 'foxts/fast-string-array-join'; import FIFO from './fifo'; type TrieNode = [ diff --git a/package.json b/package.json index 436fc2b8..f6b9b557 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "fast-cidr-tools": "^0.3.1", "fdir": "^6.4.2", "foxact": "^0.2.42", + "foxts": "1.0.4", "hash-wasm": "^4.12.0", "json-stringify-pretty-compact": "^3.0.0", "make-fetch-happen": "^14.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9acedcd6..99b20cde 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: foxact: specifier: ^0.2.42 version: 0.2.42 + foxts: + specifier: 1.0.4 + version: 1.0.4 hash-wasm: specifier: ^4.12.0 version: 4.12.0 @@ -1150,6 +1153,9 @@ packages: react: optional: true + foxts@1.0.4: + resolution: {integrity: sha512-RMQrpp4uLC2GIuW1G/RvwiHAhYHT2qU5elsOlNtkYibDfMgd+vQWfcP27mmlfy+nIuTYbiI1AB205KxnMsIi9g==} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -3015,6 +3021,8 @@ snapshots: client-only: 0.0.1 server-only: 0.0.1 + foxts@1.0.4: {} + fs-constants@1.0.0: {} fs-minipass@3.0.3: