From 33f520cba46486039ff96b40d8dc258d33b7460f Mon Sep 17 00:00:00 2001 From: Orion Date: Sat, 18 Apr 2026 01:13:07 +0800 Subject: [PATCH] =?UTF-8?q?refactor(core):=20=E2=99=BB=EF=B8=8F=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=8A=82=E7=82=B9=E5=90=8D=E7=A7=B0=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E8=84=9A=E6=9C=AC=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构注入脚本逻辑,将固定逻辑与配置分离,引入动态正则编译机制以解决短路匹配问题,并支持通过配置字典灵活扩展节点映射。 --- sntp-rename.js | 96 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/sntp-rename.js b/sntp-rename.js index 4ccbfe2..7e15f5c 100644 --- a/sntp-rename.js +++ b/sntp-rename.js @@ -1,66 +1,86 @@ /** - * Sub-Store 节点名称属性注入脚本 (极致性能 Hash Map 版) - * 核心逻辑:单次复合正则提取 + O(1) 字典映射查找,彻底消除 for 循环。 - * 参考文档 (MDN Map/Object): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object + * Sub-Store 节点名称属性注入脚本 (全自动配置驱动版) + * 核心架构:动态按长度排序编译正则 + 智能边界识别 + O(1) 映射提取 + * 维护说明:仅需修改 featureMap 字典即可,底部逻辑永远无需改动。 */ function operator(proxies) { - // 1. O(1) 映射字典 (Hash Map) - // 键名统一为大写且去除所有空格,以确保后续动态查找时的绝对稳定性 + // ================= 唯一配置区 ================= + // 在这里新增或修改关键词。格式:"节点关键词": "想要注入的标签" + // 支持大小写混合,支持包含空格或特殊符号。 const featureMap = { - "GTM0.5X": "三网", - "GTM": "三网", - "S1": "广移", - "S2": "广电信", - "S3": "广移", - "S4": "广联通", - "BGP": "cn2|5x", - "ANYTLS": "直连" // 新增:Anytls 映射为 直连 + "GTM 0.5x": "三网", + "GTM": "三网", + "S1": "广移", + "S2": "广电信", + "S3": "广移", + "S4": "广联通", + "BGP": "cn2|5x", + "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; - // 3. 执行节点遍历 + // 3. 执行节点遍历与注入 return proxies.map(p => { const name = p.name; - // 步骤 A: 执行单次正则提取 - // match 方法如果匹配成功,match[1] 将包含括号中捕获到的具体特征字符(如 "s1", "GTM 0.5x", "Anytls") + // A. 单次复合正则扫描提取 const match = name.match(featureRegex); + if (!match) return p; // 未命中配置库,直接放行 - // 如果未命中任何特征,直接返回原节点,开销极小 - if (!match) return p; + // B. 清洗提取到的特征词,并去 O(1) 字典中取值 + const mapKey = match[1].toUpperCase().replace(/\s+/g, ''); + const injectPayload = normalizedMap[mapKey]; - // 步骤 B: 结果清洗与 O(1) 字典检索 - // 将捕获到的特征串(如 "Gtm 0.5x")统一转为大写并剔除空格 -> "GTM0.5X",完美匹配 Map 的 Key - const rawFeature = match[1]; - const mapKey = rawFeature.toUpperCase().replace(/\s+/g, ''); - const injectPayload = featureMap[mapKey]; + if (!injectPayload) return p; // 兜底安全校验 - // 兜底安全校验,防止异常空值 - if (!injectPayload) return p; - - // 步骤 C: 格式化与幂等性校验 (防重复注入) + // C. 格式化组装与幂等校验 (防重复注入 Bug) const formatStr = ` [${injectPayload}]`; if (name.includes(formatStr)) { - return p; // 已包含该属性,跳过 + return p; } - // 步骤 D: 执行中缀注入 + // D. 实施中缀注入 (Infix Injection) if (suffixRegex.test(name)) { - // $1 代表 suffixRegex 中捕获到的后缀内容 p.name = name.replace(suffixRegex, `${formatStr}$1`); } else { - // 针对类似 🇯🇵 JP-Anytls-1-0.2x 这种没有任何 - SNTP 后缀的纯净节点,直接追加 + // 纯净节点无后缀时,直接挂载在末尾 p.name = name + formatStr; } - return p; // 返回处理后的最终节点 + return p; }); } \ No newline at end of file