New build infra: Build for Clash (#11)

This commit is contained in:
Sukka
2023-09-11 00:51:35 +08:00
committed by GitHub
parent fa7e2f775c
commit df4a10e180
45 changed files with 661 additions and 237 deletions

View File

@@ -4,7 +4,7 @@ const { isIPv4, isIPv6 } = require('net');
const { compareAndWriteFile } = require('./lib/string-array-compare');
const { withBannerArray } = require('./lib/with-banner');
const { fetchRemoteTextAndCreateReadlineInterface, readFileByLine } = require('./lib/fetch-remote-text-by-line');
const { minifyRules } = require('./lib/minify-rules');
const { surgeRulesetToClashClassicalTextRuleset } = require('./lib/clash');
(async () => {
console.time('Total Time - build-anti-bogus-domain');
@@ -21,7 +21,6 @@ const { minifyRules } = require('./lib/minify-rules');
console.timeEnd('* Download bogus-nxdomain-list');
const filePath = path.resolve(__dirname, '../Source/ip/reject.conf');
const resultPath = path.resolve(__dirname, '../List/ip/reject.conf');
/** @type {string[]} */
const result = [];
@@ -39,24 +38,37 @@ const { minifyRules } = require('./lib/minify-rules');
}
}
await compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - Anti Bogus Domain',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains known addresses that are hijacking NXDOMAIN results returned by DNS servers.',
'',
'Data from:',
' - https://github.com/felixonmars/dnsmasq-china-list'
],
new Date(),
minifyRules(result)
const description = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains known addresses that are hijacking NXDOMAIN results returned by DNS servers.',
'',
'Data from:',
' - https://github.com/felixonmars/dnsmasq-china-list'
];
await Promise.all([
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Anti Bogus Domain',
description,
new Date(),
result
),
path.resolve(__dirname, '../List/ip/reject.conf')
),
resultPath
);
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Anti Bogus Domain',
description,
new Date(),
surgeRulesetToClashClassicalTextRuleset(result)
),
path.resolve(__dirname, '../Clash/ip/reject.txt')
)
]);
console.timeEnd('Total Time - build-anti-bogus-domain');
})();

View File

@@ -4,48 +4,63 @@ const { compareAndWriteFile } = require('./lib/string-array-compare');
const { withBannerArray } = require('./lib/with-banner');
const { parseFelixDnsmasq } = require('./lib/parse-dnsmasq');
const { surgeRulesetToClashClassicalTextRuleset, surgeDomainsetToClashDomainset } = require('./lib/clash');
(async () => {
console.time('Total Time - build-apple-cdn-conf');
const res = await parseFelixDnsmasq('https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/apple.china.conf');
const description = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains Apple\'s domains using their China mainland CDN servers.',
'',
'Data from:',
' - https://github.com/felixonmars/dnsmasq-china-list'
];
const ruleset = res.map(domain => `DOMAIN-SUFFIX,${domain}`);
const domainset = res.map(i => `.${i}`);
await Promise.all([
compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - Apple CDN',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains Apple\'s domains using their China mainland CDN servers.',
'',
'Data from:',
' - https://github.com/felixonmars/dnsmasq-china-list'
],
'Sukka\'s Ruleset - Apple CDN',
description,
new Date(),
res.map(domain => `DOMAIN-SUFFIX,${domain}`)
ruleset
),
path.resolve(__dirname, '../List/non_ip/apple_cdn.conf')
),
compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - Apple CDN',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains Apple\'s domains using their China mainland CDN servers.',
'',
'Data from:',
' - https://github.com/felixonmars/dnsmasq-china-list'
],
'Sukka\'s Ruleset - Apple CDN',
description,
new Date(),
res.map(i => `.${i}`)
surgeRulesetToClashClassicalTextRuleset(ruleset)
),
path.resolve(__dirname, '../Clash/non_ip/apple_cdn.txt')
),
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Apple CDN',
description,
new Date(),
domainset
),
path.resolve(__dirname, '../List/domainset/apple_cdn.conf')
),
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Apple CDN',
description,
new Date(),
surgeDomainsetToClashDomainset(domainset)
),
path.resolve(__dirname, '../Clash/domainset/apple_cdn.txt')
)
]);

View File

@@ -3,10 +3,9 @@ const path = require('path');
const { compareAndWriteFile } = require('./lib/string-array-compare');
const { withBannerArray } = require('./lib/with-banner');
const { minifyRules } = require('./lib/minify-rules');
const { domainDeduper } = require('./lib/domain-deduper');
const { processLine } = require('./lib/process-line');
const { fetchRemoteTextAndCreateReadlineInterface, readFileByLine } = require('./lib/fetch-remote-text-by-line');
const Trie = require('./lib/trie');
const { surgeRulesetToClashClassicalTextRuleset } = require('./lib/clash');
(async () => {
console.time('Total Time - build-cdn-conf');
@@ -40,51 +39,33 @@ const Trie = require('./lib/trie');
}
}
/**
* Dedupe cdn.conf
*/
/** @type {Set<string>} */
const cdnDomains = new Set();
for await (const line of readFileByLine(
path.resolve(__dirname, '../Source/domainset/cdn.conf')
)) {
const l = processLine(line);
if (l) {
cdnDomains.add(l);
}
}
const description = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains object storage and static assets CDN domains.'
];
const ruleset = minifyRules(cdnDomainsList);
await Promise.all([
compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - CDN Domains',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains object storage and static assets CDN domains.'
],
'Sukka\'s Ruleset - CDN Domains',
description,
new Date(),
minifyRules(cdnDomainsList)
ruleset
),
path.resolve(__dirname, '../List/non_ip/cdn.conf')
),
compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - CDN Domains',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains object storage and static assets CDN domains.'
],
'Sukka\'s Ruleset - CDN Domains',
description,
new Date(),
minifyRules(domainDeduper(Array.from(cdnDomains)))
surgeRulesetToClashClassicalTextRuleset(ruleset)
),
path.resolve(__dirname, '../List/domainset/cdn.conf')
path.resolve(__dirname, '../Clash/non_ip/cdn.txt')
)
]);

View File

@@ -28,21 +28,38 @@ const EXCLUDE_CIDRS = [
const filteredCidr = excludeCidrs(Array.from(cidr), EXCLUDE_CIDRS, true);
console.log('After Merge:', filteredCidr.length);
await compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - Mainland China IPv4 CIDR',
[
'License: CC BY-SA 2.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'Data from https://misaka.io (misakaio @ GitHub)'
],
new Date(),
filteredCidr.map(i => `IP-CIDR,${i}`)
await Promise.all([
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Mainland China IPv4 CIDR',
[
'License: CC BY-SA 2.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'Data from https://misaka.io (misakaio @ GitHub)'
],
new Date(),
filteredCidr.map(i => `IP-CIDR,${i}`)
),
pathResolve(__dirname, '../List/ip/china_ip.conf')
),
pathResolve(__dirname, '../List/ip/china_ip.conf')
);
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Mainland China IPv4 CIDR',
[
'License: CC BY-SA 2.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'Data from https://misaka.io (misakaio @ GitHub)'
],
new Date(),
filteredCidr
),
pathResolve(__dirname, '../Clash/ip/china_ip.txt')
)
]);
console.timeEnd('Total Time - build-chnroutes-cidr');
})();

View File

@@ -6,6 +6,7 @@ const { processLine } = require('./lib/process-line');
const { withBannerArray } = require('./lib/with-banner');
const { compareAndWriteFile } = require('./lib/string-array-compare');
const domainSorter = require('./lib/stable-sort-domain');
const { surgeRulesetToClashClassicalTextRuleset } = require('./lib/clash');
(async () => {
const rl = readFileByLine(path.resolve(__dirname, '../Source/non_ip/domestic.conf'));
@@ -25,22 +26,33 @@ const domainSorter = require('./lib/stable-sort-domain');
.map((domain) => `DOMAIN-SUFFIX,${domain}`)
);
const rulesetDescription = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains known addresses that are avaliable in the Mainland China.'
];
await Promise.all([
compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - Domestic Domain',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'This file contains known addresses that are avaliable in the Mainland China.'
],
'Sukka\'s Ruleset - Domestic Domains',
rulesetDescription,
new Date(),
results
),
path.resolve(__dirname, '../List/non_ip/domestic.conf')
),
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Domestic Domains',
rulesetDescription,
new Date(),
surgeRulesetToClashClassicalTextRuleset(results)
),
path.resolve(__dirname, '../Clash/non_ip/domestic.txt')
),
compareAndWriteFile(
[
'#!name=[Sukka] Local DNS Mapping',

View File

@@ -5,6 +5,7 @@ const { withBannerArray } = require('./lib/with-banner.js');
const { compareAndWriteFile } = require('./lib/string-array-compare');
const { processLine } = require('./lib/process-line.js');
const domainSorter = require('./lib/stable-sort-domain');
const { surgeDomainsetToClashDomainset } = require('./lib/clash.js');
const WHITELIST_DOMAIN = new Set([
'w3s.link',
@@ -141,21 +142,34 @@ const BLACK_TLD = new Set([
results.sort(domainSorter);
await compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - Reject Phishing',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'The domainset supports enhanced phishing protection',
'Build from:',
' - https://gitlab.com/malware-filter/phishing-filter'
],
new Date(),
results
const description = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'The domainset supports enhanced phishing protection',
'Build from:',
' - https://gitlab.com/malware-filter/phishing-filter'
];
await Promise.all([
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Reject Phishing',
description,
new Date(),
results
),
path.resolve(__dirname, '../List/domainset/reject_phishing.conf')
),
path.resolve(__dirname, '../List/domainset/reject_phishing.conf')
);
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Reject Phishing',
description,
new Date(),
surgeDomainsetToClashDomainset(results)
),
path.resolve(__dirname, '../Clash/domainset/reject_phishing.txt')
)
]);
})();

View File

@@ -16,6 +16,7 @@ const { domainDeduper } = require('./lib/domain-deduper');
const createKeywordFilter = require('./lib/aho-corasick');
const { readFileByLine } = require('./lib/fetch-remote-text-by-line');
const domainSorter = require('./lib/stable-sort-domain');
const { surgeDomainsetToClashDomainset } = require('./lib/clash');
/** Whitelists */
const filterRuleWhitelistDomainSets = new Set(PREDEFINED_WHITELIST);
@@ -196,26 +197,38 @@ const domainSuffixSet = new Set();
return acc;
}, {});
const description = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'The domainset supports AD blocking, tracking protection, privacy protection, anti-phishing, anti-mining',
'',
'Build from:',
...HOSTS.map(host => ` - ${host[0]}`),
...ADGUARD_FILTERS.map(filter => ` - ${Array.isArray(filter) ? filter[0] : filter}`)
];
const domainset = dudupedDominArray.sort(domainSorter);
await Promise.all([
compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - Reject Base',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'',
'The domainset supports AD blocking, tracking protection, privacy protection, anti-phishing, anti-mining',
'',
'Build from:',
...HOSTS.map(host => ` - ${host[0]}`),
...ADGUARD_FILTERS.map(filter => ` - ${Array.isArray(filter) ? filter[0] : filter}`)
],
'Sukka\'s Ruleset - Reject Base',
description,
new Date(),
dudupedDominArray.sort(domainSorter)
domainset
),
pathResolve(__dirname, '../List/domainset/reject.conf')
),
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Reject Base',
description,
new Date(),
surgeDomainsetToClashDomainset(domainset)
),
pathResolve(__dirname, '../Clash/domainset/reject.txt')
),
fs.promises.writeFile(
pathResolve(__dirname, '../List/internal/reject-stats.txt'),
Object.entries(rejectDomainsStats)

View File

@@ -6,6 +6,7 @@ const { compareAndWriteFile } = require('./lib/string-array-compare');
const domainSorter = require('./lib/stable-sort-domain');
const { Sema } = require('async-sema');
const { surgeDomainsetToClashDomainset } = require('./lib/clash');
const s = new Sema(2);
/**
@@ -107,19 +108,31 @@ const querySpeedtestApi = async (keyword) => {
}
}
const reduped = domainDeduper(Array.from(domains)).sort(domainSorter);
const deduped = domainDeduper(Array.from(domains)).sort(domainSorter);
const description = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge'
];
await compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - Speedtest Domains',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge'
],
new Date(),
reduped
await Promise.all([
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Speedtest Domains',
description,
new Date(),
deduped
),
path.resolve(__dirname, '../List/domainset/speedtest.conf')
),
path.resolve(__dirname, '../List/domainset/speedtest.conf')
);
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Speedtest Domains',
description,
new Date(),
surgeDomainsetToClashDomainset(deduped)
),
path.resolve(__dirname, '../Clash/domainset/speedtest.txt')
)
]);
})();

View File

@@ -5,6 +5,7 @@ const { isIPv4, isIPv6 } = require('net');
const { withBannerArray } = require('./lib/with-banner');
const { processLine } = require('./lib/process-line');
const { compareAndWriteFile } = require('./lib/string-array-compare');
const { surgeRulesetToClashClassicalTextRuleset } = require('./lib/clash');
(async () => {
console.time('Total Time - build-telegram-cidr');
@@ -34,21 +35,34 @@ const { compareAndWriteFile } = require('./lib/string-array-compare');
throw new Error('Failed to fetch data!');
}
await compareAndWriteFile(
withBannerArray(
'Sukka\'s Surge Rules - Telegram IP CIDR',
[
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'Data from:',
' - https://core.telegram.org/resources/cidr.txt'
],
date,
results
const description = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
'Data from:',
' - https://core.telegram.org/resources/cidr.txt'
];
await Promise.all([
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Telegram IP CIDR',
description,
date,
results
),
path.resolve(__dirname, '../List/ip/telegram.conf')
),
path.resolve(__dirname, '../List/ip/telegram.conf')
);
compareAndWriteFile(
withBannerArray(
'Sukka\'s Ruleset - Telegram IP CIDR',
description,
date,
surgeRulesetToClashClassicalTextRuleset(results)
),
path.resolve(__dirname, '../Clash/ip/telegram.txt')
)
]);
console.timeEnd('Total Time - build-telegram-cidr');
})();

179
Build/build.js Normal file
View File

@@ -0,0 +1,179 @@
// @ts-check
const path = require('path');
const { PathScurry } = require('path-scurry');
const { readFileByLine } = require('./lib/fetch-remote-text-by-line');
const { processLine } = require('./lib/process-line');
const { compareAndWriteFile } = require('./lib/string-array-compare');
const { withBannerArray } = require('./lib/with-banner');
const { domainDeduper } = require('./lib/domain-deduper');
const { surgeRulesetToClashClassicalTextRuleset, surgeDomainsetToClashDomainset } = require('./lib/clash');
const MAGIC_COMMAND_SKIP = '# $ custom_build_script';
const MAGIC_COMMAND_TITLE = '# $ meta_title ';
const MAGIC_COMMAND_DESCRIPTION = '# $ meta_description ';
const sourceDir = path.resolve(__dirname, '../Source');
const outputSurgeDir = path.resolve(__dirname, '../List');
const outputClashDir = path.resolve(__dirname, '../Clash');
(async () => {
/** @type {Promise<void>[]} */
const promises = [];
const pw = new PathScurry(sourceDir);
for await (const entry of pw) {
if (entry.isFile()) {
if (path.extname(entry.name) === '.js') {
continue;
}
const relativePath = entry.relative();
if (relativePath.startsWith('domainset/')) {
promises.push(transformDomainset(entry.fullpath(), relativePath));
continue;
}
if (
relativePath.startsWith('ip/')
|| relativePath.startsWith('non_ip/')
) {
promises.push(transformRuleset(entry.fullpath(), relativePath));
continue;
}
}
}
await Promise.all(promises);
})();
/**
* @param {string} sourcePath
*/
const processFile = async (sourcePath) => {
/** @type {Set<string>} */
const lines = new Set();
let title = '';
/** @type {string[]} */
const descriptions = [];
for await (const line of readFileByLine(sourcePath)) {
if (line === MAGIC_COMMAND_SKIP) {
return;
}
if (line.startsWith(MAGIC_COMMAND_TITLE)) {
title = line.slice(MAGIC_COMMAND_TITLE.length).trim();
continue;
}
if (line.startsWith(MAGIC_COMMAND_DESCRIPTION)) {
descriptions.push(line.slice(MAGIC_COMMAND_DESCRIPTION.length).trim());
continue;
}
const l = processLine(line);
if (l) {
lines.add(l);
}
}
return /** @type {const} */ ([title, descriptions, lines]);
};
/**
* @param {string} sourcePath
* @param {string} relativePath
*/
async function transformDomainset(sourcePath, relativePath) {
const res = await processFile(sourcePath);
if (!res) return;
const [title, descriptions, lines] = res;
const deduped = domainDeduper(Array.from(lines));
const description = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
...(
descriptions.length
? ['', ...descriptions]
: []
)
];
await Promise.all([
// Surge DOMAIN-SET
compareAndWriteFile(
withBannerArray(
title,
description,
new Date(),
deduped
),
path.resolve(outputSurgeDir, relativePath)
),
// Clash domain text
compareAndWriteFile(
withBannerArray(
title,
description,
new Date(),
surgeDomainsetToClashDomainset(deduped)
),
// change path extname to .txt
path.resolve(outputClashDir, `${relativePath.slice(0, -path.extname(relativePath).length)}.txt`)
)
]);
}
/**
* Output Surge RULE-SET and Clash classical text format
*
* @param {string} sourcePath
* @param {string} relativePath
*/
async function transformRuleset(sourcePath, relativePath) {
const res = await processFile(sourcePath);
if (!res) return;
const [title, descriptions, set] = res;
const description = [
'License: AGPL 3.0',
'Homepage: https://ruleset.skk.moe',
'GitHub: https://github.com/SukkaW/Surge',
...(
descriptions.length
? ['', ...descriptions]
: []
)
];
const lines = Array.from(set);
const clashSupported = surgeRulesetToClashClassicalTextRuleset(set);
await Promise.all([
// Surge RULE-SET
compareAndWriteFile(
withBannerArray(
title,
description,
new Date(),
lines
),
path.resolve(outputSurgeDir, relativePath)
),
// Clash domainset
compareAndWriteFile(
withBannerArray(
title,
description,
new Date(),
clashSupported
),
// change path extname to .txt
path.resolve(outputClashDir, `${relativePath.slice(0, -path.extname(relativePath).length)}.txt`)
)
]);
}

View File

@@ -7,6 +7,7 @@ const { tmpdir } = require('os');
const { Readable } = require('stream');
const { pipeline } = require('stream/promises');
const { readFileByLine } = require('./lib/fetch-remote-text-by-line');
const { isCI } = require('ci-info');
const fileExists = (path) => {
return fs.promises.access(path, fs.constants.F_OK)
@@ -19,18 +20,22 @@ const fileExists = (path) => {
let allFileExists = true;
for await (const line of readFileByLine(resolve(__dirname, '../.gitignore'))) {
if (
(
line.startsWith('List/')
|| line.startsWith('Modules/')
) && !line.endsWith('/')
) {
allFileExists = await fileExists(join(__dirname, '..', line));
filesList.push(line);
if (isCI) {
allFileExists = false;
} else {
for await (const line of readFileByLine(resolve(__dirname, '../.gitignore'))) {
if (
(
// line.startsWith('List/')
line.startsWith('Modules/')
) && !line.endsWith('/')
) {
allFileExists = await fileExists(join(__dirname, '..', line));
filesList.push(line);
if (!allFileExists) {
console.log(`File not exists: ${line}`);
if (!allFileExists) {
console.log(`File not exists: ${line}`);
}
}
}
}

34
Build/lib/clash.js Normal file
View File

@@ -0,0 +1,34 @@
// @ts-check
const _Trie = require('mnemonist/trie');
const Trie = _Trie.default || _Trie;
const CLASH_SUPPORTED_RULE_TYPE = [
'DOMAIN-SUFFIX',
'DOMAIN-KEYWORD',
'DOMAIN',
'SRC-IP-CIDR',
'GEOIP',
'IP-CIDR',
'IP-CIDR6',
'DST-PORT',
'SRC-PORT'
];
/**
* @param {string[] | Set<string>} rules
*/
const surgeRulesetToClashClassicalTextRuleset = (rules) => {
const trie = Trie.from(rules);
return CLASH_SUPPORTED_RULE_TYPE.map(
type => trie.find(`${type},`)
).flat();
};
module.exports.surgeRulesetToClashClassicalTextRuleset = surgeRulesetToClashClassicalTextRuleset;
/**
* @param {string[]} domainset
*/
const surgeDomainsetToClashDomainset = (domainset) => {
return domainset.map(i => (i[0] === '.' ? `+${i}` : i));
};
module.exports.surgeDomainsetToClashDomainset = surgeDomainsetToClashDomainset;