refactor(core): ♻️ 优化节点名称注入脚本架构
重构注入脚本逻辑,将固定逻辑与配置分离,引入动态正则编译机制以解决短路匹配问题,并支持通过配置字典灵活扩展节点映射。
This commit is contained in:
@@ -1,66 +1,86 @@
|
|||||||
/**
|
/**
|
||||||
* Sub-Store 节点名称属性注入脚本 (极致性能 Hash Map 版)
|
* Sub-Store 节点名称属性注入脚本 (全自动配置驱动版)
|
||||||
* 核心逻辑:单次复合正则提取 + O(1) 字典映射查找,彻底消除 for 循环。
|
* 核心架构:动态按长度排序编译正则 + 智能边界识别 + O(1) 映射提取
|
||||||
* 参考文档 (MDN Map/Object): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object
|
* 维护说明:仅需修改 featureMap 字典即可,底部逻辑永远无需改动。
|
||||||
*/
|
*/
|
||||||
function operator(proxies) {
|
function operator(proxies) {
|
||||||
// 1. O(1) 映射字典 (Hash Map)
|
// ================= 唯一配置区 =================
|
||||||
// 键名统一为大写且去除所有空格,以确保后续动态查找时的绝对稳定性
|
// 在这里新增或修改关键词。格式:"节点关键词": "想要注入的标签"
|
||||||
|
// 支持大小写混合,支持包含空格或特殊符号。
|
||||||
const featureMap = {
|
const featureMap = {
|
||||||
"GTM0.5X": "三网",
|
"GTM 0.5x": "三网",
|
||||||
"GTM": "三网",
|
"GTM": "三网",
|
||||||
"S1": "广移",
|
"S1": "广移",
|
||||||
"S2": "广电信",
|
"S2": "广电信",
|
||||||
"S3": "广移",
|
"S3": "广移",
|
||||||
"S4": "广联通",
|
"S4": "广联通",
|
||||||
"BGP": "cn2|5x",
|
"BGP": "cn2|5x",
|
||||||
"ANYTLS": "直连" // 新增:Anytls 映射为 直连
|
"Anytls": "直连" // 日后如果要加 IEPL,只需在这里写 "IEPL": "专线"
|
||||||
};
|
};
|
||||||
|
// ==============================================
|
||||||
|
|
||||||
// 2. 预编译复合正则表达式 (性能优化的核心)
|
|
||||||
// 利用正则的 alternation (|) 进行单次扫描。
|
|
||||||
// 严格顺序:长尾特征 (GTM\s*0\.5x) 必须排在 (GTM) 之前,防止短路。
|
|
||||||
// \b 用于单词边界,防止匹配到形如 "US1" 或 "AnytlsX" 的错误字符。
|
|
||||||
const featureRegex = /(GTM\s*0\.5x|GTM|\bS1\b|\bS2\b|\bS3\b|\bS4\b|\bBGP\b|\bAnytls\b)/i;
|
|
||||||
|
|
||||||
// 后缀匹配正则预编译,避免在 map 循环中重复创建
|
// ================= 核心逻辑区 (无需修改) =================
|
||||||
|
|
||||||
|
// 1. 初始化预处理:生成稳定的查找字典 (全大写+去空格)
|
||||||
|
// 目的:无论节点名叫 "gtm 0.5x" 还是 "GTM0.5X",都能稳定映射
|
||||||
|
const normalizedMap = {};
|
||||||
|
const originalKeys = Object.keys(featureMap);
|
||||||
|
for (const key of originalKeys) {
|
||||||
|
const safeKey = key.toUpperCase().replace(/\s+/g, '');
|
||||||
|
normalizedMap[safeKey] = featureMap[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 动态构建复合正则表达式 (核心引擎)
|
||||||
|
// 按字符串长度降序排序,彻底解决 "短路匹配" (Short-Circuit) 问题
|
||||||
|
const sortedKeys = originalKeys.sort((a, b) => b.length - a.length);
|
||||||
|
|
||||||
|
const regexParts = sortedKeys.map(key => {
|
||||||
|
// 自动转义正则特殊字符 (防注入报错)
|
||||||
|
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
|
||||||
|
// 智能边界处理:如果关键词仅由字母和数字组成 (如 S1, BGP),追加 \b 边界
|
||||||
|
// 这样能防止配置的 "S1" 错误匹配到 "US1" 或 "TLS1.3"
|
||||||
|
if (/^[A-Za-z0-9]+$/.test(key)) {
|
||||||
|
return `\\b${escapedKey}\\b`;
|
||||||
|
}
|
||||||
|
return escapedKey;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 动态拼接出类似: /(GTM\ 0\.5x|\bAnytls\b|\bBGP\b|...)/i
|
||||||
|
const featureRegex = new RegExp(`(${regexParts.join('|')})`, 'i');
|
||||||
|
|
||||||
|
// 缓存后缀匹配正则,避免循环内重复创建
|
||||||
const suffixRegex = /(\s*-\s*SNTP.*)$/i;
|
const suffixRegex = /(\s*-\s*SNTP.*)$/i;
|
||||||
|
|
||||||
// 3. 执行节点遍历
|
// 3. 执行节点遍历与注入
|
||||||
return proxies.map(p => {
|
return proxies.map(p => {
|
||||||
const name = p.name;
|
const name = p.name;
|
||||||
|
|
||||||
// 步骤 A: 执行单次正则提取
|
// A. 单次复合正则扫描提取
|
||||||
// match 方法如果匹配成功,match[1] 将包含括号中捕获到的具体特征字符(如 "s1", "GTM 0.5x", "Anytls")
|
|
||||||
const match = name.match(featureRegex);
|
const match = name.match(featureRegex);
|
||||||
|
if (!match) return p; // 未命中配置库,直接放行
|
||||||
|
|
||||||
// 如果未命中任何特征,直接返回原节点,开销极小
|
// B. 清洗提取到的特征词,并去 O(1) 字典中取值
|
||||||
if (!match) return p;
|
const mapKey = match[1].toUpperCase().replace(/\s+/g, '');
|
||||||
|
const injectPayload = normalizedMap[mapKey];
|
||||||
|
|
||||||
// 步骤 B: 结果清洗与 O(1) 字典检索
|
if (!injectPayload) return p; // 兜底安全校验
|
||||||
// 将捕获到的特征串(如 "Gtm 0.5x")统一转为大写并剔除空格 -> "GTM0.5X",完美匹配 Map 的 Key
|
|
||||||
const rawFeature = match[1];
|
|
||||||
const mapKey = rawFeature.toUpperCase().replace(/\s+/g, '');
|
|
||||||
const injectPayload = featureMap[mapKey];
|
|
||||||
|
|
||||||
// 兜底安全校验,防止异常空值
|
// C. 格式化组装与幂等校验 (防重复注入 Bug)
|
||||||
if (!injectPayload) return p;
|
|
||||||
|
|
||||||
// 步骤 C: 格式化与幂等性校验 (防重复注入)
|
|
||||||
const formatStr = ` [${injectPayload}]`;
|
const formatStr = ` [${injectPayload}]`;
|
||||||
if (name.includes(formatStr)) {
|
if (name.includes(formatStr)) {
|
||||||
return p; // 已包含该属性,跳过
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 步骤 D: 执行中缀注入
|
// D. 实施中缀注入 (Infix Injection)
|
||||||
if (suffixRegex.test(name)) {
|
if (suffixRegex.test(name)) {
|
||||||
// $1 代表 suffixRegex 中捕获到的后缀内容
|
|
||||||
p.name = name.replace(suffixRegex, `${formatStr}$1`);
|
p.name = name.replace(suffixRegex, `${formatStr}$1`);
|
||||||
} else {
|
} else {
|
||||||
// 针对类似 🇯🇵 JP-Anytls-1-0.2x 这种没有任何 - SNTP 后缀的纯净节点,直接追加
|
// 纯净节点无后缀时,直接挂载在末尾
|
||||||
p.name = name + formatStr;
|
p.name = name + formatStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p; // 返回处理后的最终节点
|
return p;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user