浏览代码

Refactor: make Node.js run compatible

SukkaW 1 年之前
父节点
当前提交
553dd62eb1

+ 4 - 0
.swcrc

@@ -6,5 +6,9 @@
       "syntax": "typescript",
       "dynamicImport": true
     }
+  },
+  "module": {
+    "type": "commonjs",
+    "ignoreDynamic": true
   }
 }

+ 5 - 5
Build/build-apple-cdn.ts

@@ -17,7 +17,7 @@ export const getAppleCdnDomainsPromise = createMemoizedPromise(() => fsFetchCach
   }
 ));
 
-export const buildAppleCdn = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildAppleCdn = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const res: string[] = await span.traceChildPromise('get apple cdn domains', getAppleCdnDomainsPromise());
 
   const description = [
@@ -40,8 +40,8 @@ export const buildAppleCdn = task(import.meta.main, import.meta.path)(async (spa
       new Date(),
       ruleset,
       'ruleset',
-      path.resolve(import.meta.dir, '../List/non_ip/apple_cdn.conf'),
-      path.resolve(import.meta.dir, '../Clash/non_ip/apple_cdn.txt')
+      path.resolve(__dirname, '../List/non_ip/apple_cdn.conf'),
+      path.resolve(__dirname, '../Clash/non_ip/apple_cdn.txt')
     ),
     createRuleset(
       span,
@@ -50,8 +50,8 @@ export const buildAppleCdn = task(import.meta.main, import.meta.path)(async (spa
       new Date(),
       domainset,
       'domainset',
-      path.resolve(import.meta.dir, '../List/domainset/apple_cdn.conf'),
-      path.resolve(import.meta.dir, '../Clash/domainset/apple_cdn.txt')
+      path.resolve(__dirname, '../List/domainset/apple_cdn.conf'),
+      path.resolve(__dirname, '../Clash/domainset/apple_cdn.txt')
     )
   ]);
 });

+ 8 - 8
Build/build-cdn-download-conf.ts

@@ -48,7 +48,7 @@ const getS3OSSDomainsPromise = (async (): Promise<string[]> => {
   return Array.from(S3OSSDomains);
 })();
 
-export const buildCdnDownloadConf = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildCdnDownloadConf = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const [
     S3OSSDomains,
 
@@ -57,9 +57,9 @@ export const buildCdnDownloadConf = task(import.meta.main, import.meta.path)(asy
     steamDomainSet
   ] = await Promise.all([
     getS3OSSDomainsPromise,
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/domainset/cdn.conf')),
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/domainset/download.conf')),
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/domainset/steam.conf'))
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/domainset/cdn.conf')),
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/domainset/download.conf')),
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/domainset/steam.conf'))
   ]);
 
   appendArrayInPlace(downloadDomainSet, S3OSSDomains.map(domain => `.${domain}`));
@@ -77,8 +77,8 @@ export const buildCdnDownloadConf = task(import.meta.main, import.meta.path)(asy
       new Date(),
       sortDomains(domainDeduper(cdnDomainsList)),
       'domainset',
-      path.resolve(import.meta.dir, '../List/domainset/cdn.conf'),
-      path.resolve(import.meta.dir, '../Clash/domainset/cdn.txt')
+      path.resolve(__dirname, '../List/domainset/cdn.conf'),
+      path.resolve(__dirname, '../Clash/domainset/cdn.txt')
     ),
     createRuleset(
       span,
@@ -91,8 +91,8 @@ export const buildCdnDownloadConf = task(import.meta.main, import.meta.path)(asy
       new Date(),
       sortDomains(domainDeduper(downloadDomainSet)),
       'domainset',
-      path.resolve(import.meta.dir, '../List/domainset/download.conf'),
-      path.resolve(import.meta.dir, '../Clash/domainset/download.txt')
+      path.resolve(__dirname, '../List/domainset/download.conf'),
+      path.resolve(__dirname, '../Clash/domainset/download.txt')
     )
   ]);
 });

+ 3 - 3
Build/build-chn-cidr.ts

@@ -16,7 +16,7 @@ export const getChnCidrPromise = createMemoizedPromise(async () => {
   return exclude(cidr, NON_CN_CIDR_INCLUDED_IN_CHNROUTE, true);
 });
 
-export const buildChnCidr = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildChnCidr = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const filteredCidr = await span.traceChildAsync('download chnroutes2', getChnCidrPromise);
 
   // Can not use SHARED_DESCRIPTION here as different license
@@ -38,7 +38,7 @@ export const buildChnCidr = task(import.meta.main, import.meta.path)(async (span
         new Date(),
         filteredCidr.map(i => `IP-CIDR,${i}`)
       ),
-      pathResolve(import.meta.dir, '../List/ip/china_ip.conf')
+      pathResolve(__dirname, '../List/ip/china_ip.conf')
     ),
     compareAndWriteFile(
       span,
@@ -48,7 +48,7 @@ export const buildChnCidr = task(import.meta.main, import.meta.path)(async (span
         new Date(),
         filteredCidr
       ),
-      pathResolve(import.meta.dir, '../Clash/ip/china_ip.txt')
+      pathResolve(__dirname, '../Clash/ip/china_ip.txt')
     )
   ]);
 });

+ 3 - 3
Build/build-cloudmounter-rules.ts

@@ -4,10 +4,10 @@ import { SHARED_DESCRIPTION } from './lib/constants';
 import { createRuleset } from './lib/create-file';
 import { task } from './trace';
 
-const outputSurgeDir = path.resolve(import.meta.dir, '../List');
-const outputClashDir = path.resolve(import.meta.dir, '../Clash');
+const outputSurgeDir = path.resolve(__dirname, '../List');
+const outputClashDir = path.resolve(__dirname, '../Clash');
 
-export const buildCloudMounterRules = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildCloudMounterRules = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   // AND,((SRC-IP,192.168.1.110), (DOMAIN, example.com))
 
   const results = DOMAINS.flatMap(domain => {

+ 4 - 4
Build/build-common.ts

@@ -15,13 +15,13 @@ const MAGIC_COMMAND_SKIP = '# $ custom_build_script';
 const MAGIC_COMMAND_TITLE = '# $ meta_title ';
 const MAGIC_COMMAND_DESCRIPTION = '# $ meta_description ';
 
-const sourceDir = path.resolve(import.meta.dir, '../Source');
-const outputSurgeDir = path.resolve(import.meta.dir, '../List');
-const outputClashDir = path.resolve(import.meta.dir, '../Clash');
+const sourceDir = path.resolve(__dirname, '../Source');
+const outputSurgeDir = path.resolve(__dirname, '../List');
+const outputClashDir = path.resolve(__dirname, '../Clash');
 
 const domainsetSrcFolder = 'domainset' + path.sep;
 
-export const buildCommon = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildCommon = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const promises: Array<Promise<unknown>> = [];
 
   const paths = await new Fdir()

+ 3 - 3
Build/build-deprecate-files.ts

@@ -8,10 +8,10 @@ const DEPRECATED_FILES = [
   ['domainset/reject_phishing', 'This file has been merged with domainset/reject']
 ];
 
-const outputSurgeDir = path.resolve(import.meta.dir, '../List');
-const outputClashDir = path.resolve(import.meta.dir, '../Clash');
+const outputSurgeDir = path.resolve(__dirname, '../List');
+const outputClashDir = path.resolve(__dirname, '../Clash');
 
-export const buildDeprecateFiles = task(import.meta.main, import.meta.path)((span) => span.traceChildAsync('create deprecated files', async (childSpan) => {
+export const buildDeprecateFiles = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)((span) => span.traceChildAsync('create deprecated files', async (childSpan) => {
   const promises: Array<Promise<unknown>> = [];
 
   for (const [filePath, description] of DEPRECATED_FILES) {

+ 11 - 11
Build/build-domestic-direct-lan-ruleset-dns-mapping-module.ts

@@ -12,8 +12,8 @@ import * as yaml from 'yaml';
 import { appendArrayInPlace } from './lib/append-array-in-place';
 
 export const getDomesticAndDirectDomainsRulesetPromise = createMemoizedPromise(async () => {
-  const domestics = await readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/domestic.conf'));
-  const directs = await readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/direct.conf'));
+  const domestics = await readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/domestic.conf'));
+  const directs = await readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/direct.conf'));
   const lans: string[] = [];
 
   Object.entries(DOMESTICS).forEach(([, { domains }]) => {
@@ -29,7 +29,7 @@ export const getDomesticAndDirectDomainsRulesetPromise = createMemoizedPromise(a
   return [domestics, directs, lans] as const;
 });
 
-export const buildDomesticRuleset = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildDomesticRuleset = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const res = await getDomesticAndDirectDomainsRulesetPromise();
 
   const dataset = Object.entries(DOMESTICS);
@@ -48,8 +48,8 @@ export const buildDomesticRuleset = task(import.meta.main, import.meta.path)(asy
       new Date(),
       res[0],
       'ruleset',
-      path.resolve(import.meta.dir, '../List/non_ip/domestic.conf'),
-      path.resolve(import.meta.dir, '../Clash/non_ip/domestic.txt')
+      path.resolve(__dirname, '../List/non_ip/domestic.conf'),
+      path.resolve(__dirname, '../Clash/non_ip/domestic.txt')
     ),
     createRuleset(
       span,
@@ -62,8 +62,8 @@ export const buildDomesticRuleset = task(import.meta.main, import.meta.path)(asy
       new Date(),
       res[1],
       'ruleset',
-      path.resolve(import.meta.dir, '../List/non_ip/direct.conf'),
-      path.resolve(import.meta.dir, '../Clash/non_ip/direct.txt')
+      path.resolve(__dirname, '../List/non_ip/direct.conf'),
+      path.resolve(__dirname, '../Clash/non_ip/direct.txt')
     ),
     createRuleset(
       span,
@@ -76,8 +76,8 @@ export const buildDomesticRuleset = task(import.meta.main, import.meta.path)(asy
       new Date(),
       res[2],
       'ruleset',
-      path.resolve(import.meta.dir, '../List/non_ip/lan.conf'),
-      path.resolve(import.meta.dir, '../Clash/non_ip/lan.txt')
+      path.resolve(__dirname, '../List/non_ip/lan.conf'),
+      path.resolve(__dirname, '../Clash/non_ip/lan.txt')
     ),
     compareAndWriteFile(
       span,
@@ -94,10 +94,10 @@ export const buildDomesticRuleset = task(import.meta.main, import.meta.path)(asy
           ])
         ])
       ],
-      path.resolve(import.meta.dir, '../Modules/sukka_local_dns_mapping.sgmodule')
+      path.resolve(__dirname, '../Modules/sukka_local_dns_mapping.sgmodule')
     ),
     fsp.writeFile(
-      path.resolve(import.meta.dir, '../Internal/clash_nameserver_policy.yaml'),
+      path.resolve(__dirname, '../Internal/clash_nameserver_policy.yaml'),
       yaml.stringify(
         {
           dns: {

+ 2 - 2
Build/build-internal-reverse-chn-cidr.ts

@@ -7,7 +7,7 @@ import { NON_CN_CIDR_INCLUDED_IN_CHNROUTE, RESERVED_IPV4_CIDR } from './constant
 
 import fsp from 'fs/promises';
 
-export const buildInternalReverseChnCIDR = task(import.meta.main, import.meta.path)(async () => {
+export const buildInternalReverseChnCIDR = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async () => {
   const cidr = await getChnCidrPromise();
 
   const reversedCidr = merge(
@@ -22,7 +22,7 @@ export const buildInternalReverseChnCIDR = task(import.meta.main, import.meta.pa
   );
 
   return fsp.writeFile(
-    path.resolve(import.meta.dir, '../Internal/reversed-chn-cidr.txt'),
+    path.resolve(__dirname, '../Internal/reversed-chn-cidr.txt'),
     reversedCidr.join('\n') + '\n',
     { encoding: 'utf-8' }
   );

+ 3 - 3
Build/build-microsoft-cdn.ts

@@ -44,7 +44,7 @@ export const getMicrosoftCdnRulesetPromise = createMemoizedPromise(async () => {
     .concat(WHITELIST);
 });
 
-export const buildMicrosoftCdn = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildMicrosoftCdn = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const description = [
     ...SHARED_DESCRIPTION,
     '',
@@ -63,7 +63,7 @@ export const buildMicrosoftCdn = task(import.meta.main, import.meta.path)(async
     new Date(),
     res,
     'ruleset',
-    path.resolve(import.meta.dir, '../List/non_ip/microsoft_cdn.conf'),
-    path.resolve(import.meta.dir, '../Clash/non_ip/microsoft_cdn.txt')
+    path.resolve(__dirname, '../List/non_ip/microsoft_cdn.conf'),
+    path.resolve(__dirname, '../Clash/non_ip/microsoft_cdn.txt')
   );
 });

+ 3 - 3
Build/build-public.ts

@@ -8,8 +8,8 @@ import { sort } from './lib/timsort';
 
 import Trie from 'mnemonist/trie';
 
-const rootPath = path.resolve(import.meta.dir, '../');
-const publicPath = path.resolve(import.meta.dir, '../public');
+const rootPath = path.resolve(__dirname, '../');
+const publicPath = path.resolve(__dirname, '../public');
 
 const folderAndFilesToBeDeployed = [
   `Mock${path.sep}`,
@@ -21,7 +21,7 @@ const folderAndFilesToBeDeployed = [
   'LICENSE'
 ];
 
-export const buildPublic = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildPublic = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   await span
     .traceChild('copy public files')
     .traceAsyncFn(async () => {

+ 8 - 8
Build/build-reject-domainset.ts

@@ -20,9 +20,9 @@ import { getPhishingDomains } from './lib/get-phishing-domains';
 import { setAddFromArray, setAddFromArrayCurried } from './lib/set-add-from-array';
 import { sort } from './lib/timsort';
 
-const getRejectSukkaConfPromise = readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/domainset/reject_sukka.conf'));
+const getRejectSukkaConfPromise = readFileIntoProcessedArray(path.resolve(__dirname, '../Source/domainset/reject_sukka.conf'));
 
-export const buildRejectDomainSet = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildRejectDomainSet = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   /** Whitelists */
   const filterRuleWhitelistDomainSets = new Set(PREDEFINED_WHITELIST);
 
@@ -98,7 +98,7 @@ export const buildRejectDomainSet = task(import.meta.main, import.meta.path)(asy
     /** Collect DOMAIN-KEYWORD from non_ip/reject.conf for deduplication */
     const domainKeywordsSet = new Set<string>();
 
-    for await (const line of readFileByLine(path.resolve(import.meta.dir, '../Source/non_ip/reject.conf'))) {
+    for await (const line of readFileByLine(path.resolve(__dirname, '../Source/non_ip/reject.conf'))) {
       const [type, value] = line.split(',');
 
       if (type === 'DOMAIN-KEYWORD') {
@@ -191,8 +191,8 @@ export const buildRejectDomainSet = task(import.meta.main, import.meta.path)(asy
       new Date(),
       span.traceChildSync('sort reject domainset (base)', () => sortDomains(dudupedDominArray, domainArrayMainDomainMap, domainArraySubdomainMap)),
       'domainset',
-      path.resolve(import.meta.dir, '../List/domainset/reject.conf'),
-      path.resolve(import.meta.dir, '../Clash/domainset/reject.txt')
+      path.resolve(__dirname, '../List/domainset/reject.conf'),
+      path.resolve(__dirname, '../Clash/domainset/reject.txt')
     ),
     createRuleset(
       span,
@@ -211,13 +211,13 @@ export const buildRejectDomainSet = task(import.meta.main, import.meta.path)(asy
       new Date(),
       span.traceChildSync('sort reject domainset (extra)', () => sortDomains(dudupedDominArrayExtra, domainArrayMainDomainMap, domainArraySubdomainMap)),
       'domainset',
-      path.resolve(import.meta.dir, '../List/domainset/reject_extra.conf'),
-      path.resolve(import.meta.dir, '../Clash/domainset/reject_extra.txt')
+      path.resolve(__dirname, '../List/domainset/reject_extra.conf'),
+      path.resolve(__dirname, '../Clash/domainset/reject_extra.txt')
     ),
     compareAndWriteFile(
       span,
       rejectDomainsStats.map(([domain, count]) => `${domain}${' '.repeat(100 - domain.length)}${count}`),
-      path.resolve(import.meta.dir, '../Internal/reject-stats.txt')
+      path.resolve(__dirname, '../Internal/reject-stats.txt')
     )
   ]);
 });

+ 4 - 4
Build/build-reject-ip-list.ts

@@ -65,9 +65,9 @@ const getBotNetFilterIPsPromise = fsFetchCache.apply(
   }
 );
 
-const localRejectIPSourcesPromise = readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/ip/reject.conf'));
+const localRejectIPSourcesPromise = readFileIntoProcessedArray(path.resolve(__dirname, '../Source/ip/reject.conf'));
 
-export const buildRejectIPList = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildRejectIPList = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const result = await localRejectIPSourcesPromise;
 
   const bogusNxDomainIPs = await span.traceChildPromise('get bogus nxdomain ips', getBogusNxDomainIPsPromise);
@@ -93,7 +93,7 @@ export const buildRejectIPList = task(import.meta.main, import.meta.path)(async
     new Date(),
     result,
     'ruleset',
-    path.resolve(import.meta.dir, '../List/ip/reject.conf'),
-    path.resolve(import.meta.dir, '../Clash/ip/reject.txt')
+    path.resolve(__dirname, '../List/ip/reject.conf'),
+    path.resolve(__dirname, '../Clash/ip/reject.txt')
   );
 });

+ 3 - 3
Build/build-sgmodule-always-realip.ts

@@ -43,7 +43,7 @@ const HOSTNAMES = [
   '*.battlenet.com'
 ];
 
-export const buildAlwaysRealIPModule = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildAlwaysRealIPModule = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   // Intranet, Router Setup, and mant more
   const dataset = [Object.entries(DIRECTS), Object.entries(LANS)];
   const surge = dataset.flatMap(data => data.flatMap(([, { domains }]) => domains.flatMap((domain) => [`*.${domain}`, domain])));
@@ -59,10 +59,10 @@ export const buildAlwaysRealIPModule = task(import.meta.main, import.meta.path)(
         '[General]',
         `always-real-ip = %APPEND% ${HOSTNAMES.concat(surge).join(', ')}`
       ],
-      path.resolve(import.meta.dir, '../Modules/sukka_common_always_realip.sgmodule')
+      path.resolve(__dirname, '../Modules/sukka_common_always_realip.sgmodule')
     ),
     fsp.writeFile(
-      path.resolve(import.meta.dir, '../Internal/clash_fake_ip_filter.yaml'),
+      path.resolve(__dirname, '../Internal/clash_fake_ip_filter.yaml'),
       yaml.stringify(
         {
           dns: {

+ 2 - 2
Build/build-sgmodule-redirect.ts

@@ -120,7 +120,7 @@ const REDIRECT_FAKEWEBSITES = [
   ['zbrushcn.com', 'https://www.maxon.net/en/zbrush']
 ] as const;
 
-export const buildRedirectModule = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildRedirectModule = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const domains = Array.from(new Set([
     ...REDIRECT_MIRROR.map(([from]) => getHostname(from, { detectIp: false })),
     ...REDIRECT_FAKEWEBSITES.flatMap(([from]) => [from, `www.${from}`])
@@ -139,6 +139,6 @@ export const buildRedirectModule = task(import.meta.main, import.meta.path)(asyn
       ...REDIRECT_MIRROR.map(([from, to]) => `^https?://${escapeRegExp(from)}(.*) ${to}$1`),
       ...REDIRECT_FAKEWEBSITES.map(([from, to]) => `^https?://(www.)?${escapeRegExp(from)} ${to}`)
     ],
-    path.resolve(import.meta.dir, '../Modules/sukka_url_redirect.sgmodule')
+    path.resolve(__dirname, '../Modules/sukka_url_redirect.sgmodule')
   );
 });

+ 4 - 4
Build/build-speedtest-domainset.ts

@@ -82,7 +82,7 @@ const querySpeedtestApi = async (keyword: string): Promise<Array<string | null>>
   }
 };
 
-export const buildSpeedtestDomainSet = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildSpeedtestDomainSet = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const domainTrie = createTrie(
     [
       // speedtest.net
@@ -183,7 +183,7 @@ export const buildSpeedtestDomainSet = task(import.meta.main, import.meta.path)(
     async () => {
       try {
         (
-          await readFileIntoProcessedArray(path.resolve(import.meta.dir, '../List/domainset/speedtest.conf'))
+          await readFileIntoProcessedArray(path.resolve(__dirname, '../List/domainset/speedtest.conf'))
         ) .forEach(line => {
           const hn = getHostname(line, { detectIp: false, validateHostname: true });
           if (hn) {
@@ -267,7 +267,7 @@ export const buildSpeedtestDomainSet = task(import.meta.main, import.meta.path)(
     new Date(),
     deduped,
     'domainset',
-    path.resolve(import.meta.dir, '../List/domainset/speedtest.conf'),
-    path.resolve(import.meta.dir, '../Clash/domainset/speedtest.txt')
+    path.resolve(__dirname, '../List/domainset/speedtest.conf'),
+    path.resolve(__dirname, '../Clash/domainset/speedtest.txt')
   );
 });

+ 10 - 10
Build/build-sspanel-appprofile.ts

@@ -28,7 +28,7 @@ const removeNoResolved = (line: string) => line.replace(',no-resolve', '');
 /**
  * This only generates a simplified version, for under-used users only.
  */
-export const buildSSPanelUIMAppProfile = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildSSPanelUIMAppProfile = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const [
     [domesticDomains, directDomains, lanDomains],
     appleCdnDomains,
@@ -55,18 +55,18 @@ export const buildSSPanelUIMAppProfile = task(import.meta.main, import.meta.path
       ),
     getAppleCdnDomainsPromise().then(domains => domains.map(domain => `DOMAIN-SUFFIX,${domain}`)),
     getMicrosoftCdnRulesetPromise().then(surgeRulesetToClashClassicalTextRuleset),
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/apple_cn.conf')),
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/neteasemusic.conf')).then(surgeRulesetToClashClassicalTextRuleset),
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/apple_cn.conf')),
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/neteasemusic.conf')).then(surgeRulesetToClashClassicalTextRuleset),
     // microsoft & apple - domains
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/microsoft.conf')),
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/apple_services.conf')).then(surgeRulesetToClashClassicalTextRuleset),
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/microsoft.conf')),
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/apple_services.conf')).then(surgeRulesetToClashClassicalTextRuleset),
     // stream - domains
     surgeRulesetToClashClassicalTextRuleset(AllStreamServices.flatMap((i) => i.rules)),
     // steam - domains
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/domainset/steam.conf')).then(surgeDomainsetToClashRuleset),
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/domainset/steam.conf')).then(surgeDomainsetToClashRuleset),
     // global - domains
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/global.conf')).then(surgeRulesetToClashClassicalTextRuleset),
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/telegram.conf')).then(surgeRulesetToClashClassicalTextRuleset),
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/global.conf')).then(surgeRulesetToClashClassicalTextRuleset),
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/telegram.conf')).then(surgeRulesetToClashClassicalTextRuleset),
     // domestic - ip cidr
     getChnCidrPromise().then(cidrs => cidrs.map(cidr => `IP-CIDR,${cidr}`)),
     AllStreamServices.flatMap((i) => (
@@ -80,7 +80,7 @@ export const buildSSPanelUIMAppProfile = task(import.meta.main, import.meta.path
     // global - ip cidr
     getTelegramCIDRPromise(),
     // lan - ip cidr
-    readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/ip/lan.conf'))
+    readFileIntoProcessedArray(path.resolve(__dirname, '../Source/ip/lan.conf'))
   ] as const);
 
   const telegramCidrs = rawTelegramCidrs.map(removeNoResolved);
@@ -118,7 +118,7 @@ export const buildSSPanelUIMAppProfile = task(import.meta.main, import.meta.path
   await compareAndWriteFile(
     span,
     output,
-    path.resolve(import.meta.dir, '../Internal/appprofile.php')
+    path.resolve(__dirname, '../Internal/appprofile.php')
   );
 });
 

+ 5 - 5
Build/build-stream-service.ts

@@ -22,8 +22,8 @@ export const createRulesetForStreamService = (span: Span, fileId: string, title:
       new Date(),
       streamServices.flatMap((i) => i.rules),
       'ruleset',
-      path.resolve(import.meta.dir, `../List/non_ip/${fileId}.conf`),
-      path.resolve(import.meta.dir, `../Clash/non_ip/${fileId}.txt`)
+      path.resolve(__dirname, `../List/non_ip/${fileId}.conf`),
+      path.resolve(__dirname, `../Clash/non_ip/${fileId}.txt`)
     ),
     // IP
     createRuleset(
@@ -44,13 +44,13 @@ export const createRulesetForStreamService = (span: Span, fileId: string, title:
           : []
       )),
       'ruleset',
-      path.resolve(import.meta.dir, `../List/ip/${fileId}.conf`),
-      path.resolve(import.meta.dir, `../Clash/ip/${fileId}.txt`)
+      path.resolve(__dirname, `../List/ip/${fileId}.conf`),
+      path.resolve(__dirname, `../Clash/ip/${fileId}.txt`)
     )
   ]));
 };
 
-export const buildStreamService = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildStreamService = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   return Promise.all([
     createRulesetForStreamService(span, 'stream', 'All', ALL),
     createRulesetForStreamService(span, 'stream_us', 'North America', NORTH_AMERICA),

+ 3 - 3
Build/build-telegram-cidr.ts

@@ -32,7 +32,7 @@ export const getTelegramCIDRPromise = createMemoizedPromise(async () => {
   return { date, results };
 });
 
-export const buildTelegramCIDR = task(import.meta.main, import.meta.path)(async (span) => {
+export const buildTelegramCIDR = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const { date, results } = await span.traceChildAsync('get telegram cidr', getTelegramCIDRPromise);
 
   if (results.length === 0) {
@@ -52,7 +52,7 @@ export const buildTelegramCIDR = task(import.meta.main, import.meta.path)(async
     date,
     results,
     'ruleset',
-    path.resolve(import.meta.dir, '../List/ip/telegram.conf'),
-    path.resolve(import.meta.dir, '../Clash/ip/telegram.txt')
+    path.resolve(__dirname, '../List/ip/telegram.conf'),
+    path.resolve(__dirname, '../Clash/ip/telegram.txt')
   );
 });

+ 2 - 2
Build/download-mock-assets.ts

@@ -13,9 +13,9 @@ const ASSETS_LIST = {
   'amazon-adsystem-com_amazon-apstag.js': 'https://raw.githubusercontent.com/AdguardTeam/Scriptlets/master/dist/redirect-files/amazon-apstag.js'
 } as const;
 
-const mockDir = path.resolve(import.meta.dir, '../Mock');
+const mockDir = path.resolve(__dirname, '../Mock');
 
-export const downloadMockAssets = task(import.meta.main, import.meta.path)((span) => Promise.all(Object.entries(ASSETS_LIST).map(
+export const downloadMockAssets = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)((span) => Promise.all(Object.entries(ASSETS_LIST).map(
   ([filename, url]) => span
     .traceChild(url)
     .traceAsyncFn(() => fetchWithRetry(url).then(res => {

+ 4 - 4
Build/download-previous-build.ts

@@ -13,7 +13,7 @@ import { Readable } from 'stream';
 const IS_READING_BUILD_OUTPUT = 1 << 2;
 const ALL_FILES_EXISTS = 1 << 3;
 
-export const downloadPreviousBuild = task(import.meta.main, import.meta.path)(async (span) => {
+export const downloadPreviousBuild = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
   const buildOutputList: string[] = [];
 
   let flag = 1 | ALL_FILES_EXISTS;
@@ -21,7 +21,7 @@ export const downloadPreviousBuild = task(import.meta.main, import.meta.path)(as
   await span
     .traceChild('read .gitignore')
     .traceAsyncFn(async () => {
-      for await (const line of readFileByLine(path.resolve(import.meta.dir, '../.gitignore'))) {
+      for await (const line of readFileByLine(path.resolve(__dirname, '../.gitignore'))) {
         if (line === '# $ build output') {
           flag = flag | IS_READING_BUILD_OUTPUT;
           continue;
@@ -33,7 +33,7 @@ export const downloadPreviousBuild = task(import.meta.main, import.meta.path)(as
         buildOutputList.push(line);
 
         if (!isCI) {
-          if (!existsSync(path.join(import.meta.dir, '..', line))) {
+          if (!existsSync(path.join(__dirname, '..', line))) {
             flag = flag & ~ALL_FILES_EXISTS;
           }
         }
@@ -83,7 +83,7 @@ export const downloadPreviousBuild = task(import.meta.main, import.meta.path)(as
         }
 
         const relativeEntryPath = entry.header.name.replace(pathPrefix, '');
-        const targetPath = path.join(import.meta.dir, '..', relativeEntryPath);
+        const targetPath = path.join(__dirname, '..', relativeEntryPath);
 
         await mkdir(path.dirname(targetPath), { recursive: true });
         await pipeline(entry, createWriteStream(targetPath));

+ 18 - 17
Build/lib/cache-filesystem.ts

@@ -1,11 +1,11 @@
-// eslint-disable-next-line import-x/no-unresolved -- bun built-in module
-import { Database } from 'bun:sqlite';
+import createDb from 'better-sqlite3';
+import type { Database } from 'better-sqlite3';
 import os from 'os';
 import path from 'path';
 import { mkdirSync } from 'fs';
 import picocolors from 'picocolors';
 import { fastStringArrayJoin } from './misc';
-import { peek } from 'bun';
+import { peek } from './bun';
 import { performance } from 'perf_hooks';
 
 const identity = (x: any) => x;
@@ -92,12 +92,12 @@ export class Cache<S = string> {
       this.type = 'string';
     }
 
-    const db = new Database(path.join(this.cachePath, 'cache.db'));
+    const db = createDb(path.join(this.cachePath, 'cache.db'));
 
-    db.exec('PRAGMA journal_mode = WAL;');
-    db.exec('PRAGMA synchronous = normal;');
-    db.exec('PRAGMA temp_store = memory;');
-    db.exec('PRAGMA optimize;');
+    db.pragma('journal_mode = WAL');
+    db.pragma('synchronous = normal');
+    db.pragma('temp_store = memory');
+    db.pragma('optimize');
 
     db.prepare(`CREATE TABLE IF NOT EXISTS ${this.tableName} (key TEXT PRIMARY KEY, value ${this.type === 'string' ? 'TEXT' : 'BLOB'}, ttl REAL NOT NULL);`).run();
     db.prepare(`CREATE INDEX IF NOT EXISTS cache_ttl ON ${this.tableName} (ttl);`).run();
@@ -130,15 +130,20 @@ export class Cache<S = string> {
       `INSERT INTO ${this.tableName} (key, value, ttl) VALUES ($key, $value, $valid) ON CONFLICT(key) DO UPDATE SET value = $value, ttl = $valid`
     );
 
+    const valid = Date.now() + ttl;
+
     insert.run({
       $key: key,
+      key,
       $value: value,
-      $valid: Date.now() + ttl
+      value,
+      $valid: valid,
+      valid
     });
   }
 
   get(key: string, defaultValue?: S): S | undefined {
-    const rv = this.db.prepare<{ value: S }, string>(
+    const rv = this.db.prepare<string, { value: S }>(
       `SELECT value FROM ${this.tableName} WHERE key = ? LIMIT 1`
     ).get(key);
 
@@ -148,7 +153,7 @@ export class Cache<S = string> {
 
   has(key: string): CacheStatus {
     const now = Date.now();
-    const rv = this.db.prepare<{ ttl: number }, string>(`SELECT ttl FROM ${this.tableName} WHERE key = ?`).get(key);
+    const rv = this.db.prepare<string, { ttl: number }>(`SELECT ttl FROM ${this.tableName} WHERE key = ?`).get(key);
 
     return !rv ? CacheStatus.Miss : (rv.ttl > now ? CacheStatus.Hit : CacheStatus.Stale);
   }
@@ -206,18 +211,14 @@ export class Cache<S = string> {
   }
 }
 
-export const fsFetchCache = new Cache({ cachePath: path.resolve(import.meta.dir, '../../.cache') });
+export const fsFetchCache = new Cache({ cachePath: path.resolve(__dirname, '../../.cache') });
 // process.on('exit', () => {
 //   fsFetchCache.destroy();
 // });
 
-// export const fsCache = traceSync('initializing filesystem cache', () => new Cache<Uint8Array>({ cachePath: path.resolve(import.meta.dir, '../../.cache'), type: 'buffer' }));
+// export const fsCache = traceSync('initializing filesystem cache', () => new Cache<Uint8Array>({ cachePath: path.resolve(__dirname, '../../.cache'), type: 'buffer' }));
 
 const separator = '\u0000';
-// const textEncoder = new TextEncoder();
-// const textDecoder = new TextDecoder();
-// export const serializeString = (str: string) => textEncoder.encode(str);
-// export const deserializeString = (str: string) => textDecoder.decode(new Uint8Array(str.split(separator).map(Number)));
 export const serializeSet = (set: Set<string>) => fastStringArrayJoin(Array.from(set), separator);
 export const deserializeSet = (str: string) => new Set(str.split(separator));
 export const serializeArray = (arr: string[]) => fastStringArrayJoin(arr, separator);

+ 4 - 8
Build/lib/create-file.ts

@@ -11,8 +11,6 @@ import { readFileByLine } from './fetch-text-by-line';
 
 export async function compareAndWriteFile(span: Span, linesA: string[], filePath: string) {
   let isEqual = true;
-  const fd = await fsp.open(filePath);
-
   const linesALen = linesA.length;
 
   if (!fs.existsSync(filePath)) {
@@ -22,12 +20,10 @@ export async function compareAndWriteFile(span: Span, linesA: string[], filePath
     console.log(`Nothing to write to ${filePath}...`);
     isEqual = false;
   } else {
-    /* The `isEqual` variable is used to determine whether the content of a file is equal to the
-    provided lines or not. It is initially set to `true`, and then it is updated based on different
-    conditions: */
+    const fd = await fsp.open(filePath);
+
     isEqual = await span.traceChildAsync(`comparing ${filePath}`, async () => {
       let index = 0;
-
       for await (const lineB of readFileByLine(fd)) {
         const lineA = linesA[index] as string | undefined;
         index++;
@@ -63,6 +59,8 @@ export async function compareAndWriteFile(span: Span, linesA: string[], filePath
 
       return true;
     });
+
+    await fd.close();
   }
 
   if (isEqual) {
@@ -83,8 +81,6 @@ export async function compareAndWriteFile(span: Span, linesA: string[], filePath
 
     // return writer.end();
   });
-
-  await fd.close();
 }
 
 export const withBannerArray = (title: string, description: string[] | readonly string[], date: Date, content: string[]) => {

+ 1 - 1
Build/lib/fetch-text-by-line.bench.ts

@@ -4,7 +4,7 @@ import { readFileByLine } from './fetch-text-by-line';
 import path from 'path';
 import fsp from 'fs/promises';
 
-const file = path.resolve(import.meta.dir, '../../Source/domainset/cdn.conf');
+const file = path.resolve(__dirname, '../../Source/domainset/cdn.conf');
 
 group('read file by line', () => {
   bench('readline', () => processLineFromReadline(readFileByLine(file)));

+ 26 - 10
Build/lib/fetch-text-by-line.ts

@@ -1,9 +1,12 @@
+import fs from 'fs';
+import { Readable } from 'stream';
 import type { BunFile } from 'bun';
 import { fetchWithRetry, defaultRequestInit } from './fetch-retry';
 import type { FileHandle } from 'fs/promises';
 
 import { TextLineStream } from './text-line-transform-stream';
 import { PolyfillTextDecoderStream } from './text-decoder-stream';
+import { TextDecoderStream as NodeTextDecoderStream } from 'stream/web';
 import { processLine } from './process-line';
 
 const enableTextLineStream = !!process.env.ENABLE_TEXT_LINE_STREAM;
@@ -36,19 +39,32 @@ async function *createTextLineAsyncIterableFromStreamSource(stream: ReadableStre
   }
 }
 
-const getReadableStream = (file: string | BunFile | FileHandle): ReadableStream => {
-  if (typeof file === 'string') {
-    return Bun.file(file).stream();
-  }
-  if ('writer' in file) {
-    return file.stream();
+const getReadableStream = typeof Bun !== 'undefined'
+  ? (file: string | BunFile | FileHandle): ReadableStream => {
+    if (typeof file === 'string') {
+      return Bun.file(file).stream();
+    }
+    if ('writer' in file) {
+      return file.stream();
+    }
+    return file.readableWebStream();
   }
-  return file.readableWebStream();
-};
+  : (file: string | BunFile | FileHandle): ReadableStream => {
+    if (typeof file === 'string') {
+      return Readable.toWeb(fs.createReadStream(file /* { encoding: 'utf-8' } */));
+    }
+    if ('writer' in file) {
+      return file.stream();
+    }
+    return file.readableWebStream();
+  };
+
+// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- On Bun, NodeTextDecoderStream is undefined
+const TextDecoderStream = NodeTextDecoderStream ?? PolyfillTextDecoderStream;
 
 // TODO: use FileHandle.readLine()
 export const readFileByLine: ((file: string | BunFile | FileHandle) => AsyncIterable<string>) = enableTextLineStream
-  ? (file: string | BunFile | FileHandle) => getReadableStream(file).pipeThrough(new PolyfillTextDecoderStream()).pipeThrough(new TextLineStream())
+  ? (file: string | BunFile | FileHandle) => getReadableStream(file).pipeThrough(new TextDecoderStream()).pipeThrough(new TextLineStream())
   : (file: string | BunFile | FileHandle) => createTextLineAsyncIterableFromStreamSource(getReadableStream(file));
 
 const ensureResponseBody = (resp: Response) => {
@@ -62,7 +78,7 @@ const ensureResponseBody = (resp: Response) => {
 };
 
 export const createReadlineInterfaceFromResponse: ((resp: Response) => AsyncIterable<string>) = enableTextLineStream
-  ? (resp) => ensureResponseBody(resp).pipeThrough(new PolyfillTextDecoderStream()).pipeThrough(new TextLineStream())
+  ? (resp) => ensureResponseBody(resp).pipeThrough(new TextDecoderStream()).pipeThrough(new TextLineStream())
   : (resp) => createTextLineAsyncIterableFromStreamSource(ensureResponseBody(resp));
 
 export function fetchRemoteTextByLine(url: string | URL) {

+ 8 - 2
Build/lib/get-gorhill-publicsuffix.ts

@@ -1,10 +1,16 @@
-import { toASCII } from 'punycode';
+import fsp from 'fs/promises';
+import { toASCII } from 'punycode/punycode';
 import { createMemoizedPromise } from './memo-promise';
 import { getPublicSuffixListTextPromise } from './download-publicsuffixlist';
+import { fileURLToPath } from 'url';
 
 const customFetch = typeof Bun !== 'undefined'
   ? (url: string | URL) => Promise.resolve(Bun.file(url))
-  : (url: string | URL) => fetch(url).then(resp => resp.blob() as Promise<Blob>);
+  : async (url: string | URL) => {
+    const filePath = fileURLToPath(url);
+    const file = await fsp.readFile(filePath);
+    return new Blob([file]) as any;
+  };
 
 export const getGorhillPublicSuffixPromise = createMemoizedPromise(async () => {
   const [publicSuffixListDat, { default: gorhill }] = await Promise.all([

+ 2 - 2
Build/trace/index.ts

@@ -1,4 +1,4 @@
-import path from 'path';
+import { basename, extname } from 'path';
 import picocolors from 'picocolors';
 
 const SPAN_STATUS_START = 0;
@@ -95,7 +95,7 @@ export const createSpan = (name: string, parentTraceResult?: TraceResult): Span
 };
 
 export const task = (importMetaMain: boolean, importMetaPath: string) => <T>(fn: (span: Span) => Promise<T>, customName?: string) => {
-  const taskName = customName ?? path.basename(importMetaPath, path.extname(importMetaPath));
+  const taskName = customName ?? basename(importMetaPath, extname(importMetaPath));
 
   const dummySpan = createSpan(taskName);
 

+ 1 - 1
Build/trim-source.ts

@@ -3,7 +3,7 @@ import fsp from 'fs/promises';
 import { fdir as Fdir } from 'fdir';
 import { readFileByLine } from './lib/fetch-text-by-line';
 
-const sourceDir = path.resolve(import.meta.dir, '../Source');
+const sourceDir = path.resolve(__dirname, '../Source');
 
 (async () => {
   const promises: Array<Promise<unknown>> = [];

+ 1 - 1
Build/validate-domestic.ts

@@ -62,7 +62,7 @@ export const parseDomesticList = async () => {
   };
 
   // await Promise.all([
-  await runAgainstRuleset(path.resolve(import.meta.dir, '../List/non_ip/domestic.conf'));
+  await runAgainstRuleset(path.resolve(__dirname, '../List/non_ip/domestic.conf'));
   // ]);
 
   console.log(notIncludedDomestic.size, notIncludedDomestic);

+ 3 - 3
Build/validate-gfwlist.ts

@@ -105,9 +105,9 @@ export const parseGfwList = async () => {
   };
 
   await Promise.all([
-    runAgainstRuleset(path.resolve(import.meta.dir, '../Source/non_ip/global.conf')),
-    runAgainstRuleset(path.resolve(import.meta.dir, '../Source/non_ip/telegram.conf')),
-    runAgainstRuleset(path.resolve(import.meta.dir, '../List/non_ip/stream.conf'))
+    runAgainstRuleset(path.resolve(__dirname, '../Source/non_ip/global.conf')),
+    runAgainstRuleset(path.resolve(__dirname, '../Source/non_ip/telegram.conf')),
+    runAgainstRuleset(path.resolve(__dirname, '../List/non_ip/stream.conf'))
   ]);
 
   console.log(notIncludedTop500Gfwed);

二进制
bun.lockb


+ 5 - 1
package.json

@@ -9,7 +9,7 @@
   },
   "scripts": {
     "build": "bun ./Build/index.ts",
-    "build-node": "ENABLE_TEXT_LINE_STREAM=true node -r @swc-node/register ./Build/index.ts",
+    "build-node": "SWCRC=true ENABLE_TEXT_LINE_STREAM=true node -r @swc-node/register ./Build/index.ts",
     "build-stream": "ENABLE_TEXT_LINE_STREAM=true bun ./Build/index.ts",
     "lint": "eslint --format=sukka ."
   },
@@ -20,6 +20,7 @@
     "@gorhill/publicsuffixlist": "3.0.1",
     "async-retry": "^1.3.3",
     "async-sema": "^3.1.1",
+    "better-sqlite3": "^11.1.2",
     "ci-info": "^4.0.0",
     "csv-parse": "^5.5.6",
     "fast-cidr-tools": "^0.2.5",
@@ -38,8 +39,11 @@
   "devDependencies": {
     "@eslint-sukka/node": "^6.1.6",
     "@swc-node/register": "^1.10.9",
+    "@swc/core": "^1.7.0",
     "@types/async-retry": "^1.4.8",
+    "@types/better-sqlite3": "^7.6.11",
     "@types/bun": "^1.1.6",
+    "@types/punycode": "^2.1.4",
     "@types/tar-stream": "^3.1.3",
     "bun-types": "^1.1.20",
     "eslint": "^9.7.0",