From bcd9fe942b9814ae453f4f13103245f8bf32384c Mon Sep 17 00:00:00 2001 From: Roy Li Date: Mon, 4 May 2020 13:37:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20useProviders=20=E5=92=8C=20discardProvi?= =?UTF-8?q?ders=20=E5=A2=9E=E5=8A=A0=E4=B8=A5=E6=A0=BC=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/guide/advance/custom-filter.md | 16 +++++++++---- lib/misc/deprecation.ts | 2 ++ lib/utils/filter.ts | 21 +++++++++++++---- test/utils/filter.test.ts | 36 +++++++++++++++++++++++++---- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/docs/guide/advance/custom-filter.md b/docs/guide/advance/custom-filter.md index 07deb5d4b..f6405e0c4 100644 --- a/docs/guide/advance/custom-filter.md +++ b/docs/guide/advance/custom-filter.md @@ -152,15 +152,17 @@ module.exports = { ``` :::warning 注意 -1. 不能合并排序型过滤器。 -2. 若某个节点同时匹配多个规则,只会出现在第一次匹配的位置。 -3. Provider 的配置项 `nodeFilter` 也支持排序类型的过滤器,但我们并不建议您这么用,因为 Provider 的 `nodeFilter` 配置项仅针对当前 Provider 而非合并进来的所有的节点,再者如果你同时在 `nodeFilter` 和 `getNodeNames`(包括但不限于)中使用排序过滤器,会进行多次排序,很难避免不出错。所以请尽可能在 `nodeFilter` 中使用普通的过滤器。 +1. 不能合并排序型过滤器; +2. 若某个节点同时匹配多个规则,只会出现在第一次匹配的位置; +3. Provider 的配置项 `nodeFilter` 也支持排序类型的过滤器,但我们并不建议您这么用,因为 Provider 的 `nodeFilter` 配置项仅针对当前 Provider 而非合并进来的所有的节点,再者如果你同时在 `nodeFilter` 和 `getNodeNames`(包括但不限于)中使用排序过滤器,会进行多次排序,很难避免不出错。所以请尽可能在 `nodeFilter` 中使用普通的过滤器; ::: ### useProviders 合并 Provider 之后若是想快速地过滤出某几个 Provider 中的节点作为一个策略组,可以使用该过滤器。 +第二个入参是开启严格模式。严格模式下会严格匹配 Provider 名称(注意和 `useKeywords` 的严格模式不同)。 + ```js // surgio.conf.js const { utils } = require('surgio'); @@ -173,13 +175,16 @@ module.exports = { ``` :::warning 注意 -该过滤器不保证顺序。 +1. 该过滤器不保证顺序; +2. 在后面的版本中会默认开启严格模式; ::: ### discardProviders 合并 Provider 之后若是想快速地舍弃某几个 Provider 中的节点作为一个策略组,可以使用该过滤器。 +第二个入参是开启严格模式。严格模式下会严格匹配 Provider 名称(注意和 `useKeywords` 的严格模式不同)。 + ```js // surgio.conf.js const { utils } = require('surgio'); @@ -192,5 +197,6 @@ module.exports = { ``` :::warning 注意 -该过滤器不保证顺序。 +1. 该过滤器不保证顺序; +2. 在后面的版本中会默认开启严格模式; ::: diff --git a/lib/misc/deprecation.ts b/lib/misc/deprecation.ts index 6f917322d..44f6b317d 100644 --- a/lib/misc/deprecation.ts +++ b/lib/misc/deprecation.ts @@ -1,2 +1,4 @@ export const DEP001 = 'nowHandler 已不推荐使用,请参考 http://bit.ly/2q5daCK 尽快更新您的代码'; export const DEP002 = 'udp-relay 的值已改为布尔类型,字符串类型依然可用但推荐更改'; +export const DEP003 = 'useProvider 将在之后版本改为默认使用严格模式'; +export const DEP004 = 'discardProviders 将在之后版本改为默认使用严格模式'; diff --git a/lib/utils/filter.ts b/lib/utils/filter.ts index f09ab2090..dccb86f8c 100644 --- a/lib/utils/filter.ts +++ b/lib/utils/filter.ts @@ -1,8 +1,13 @@ import _ from 'lodash'; +import { deprecate } from 'util'; +import { DEP003, DEP004 } from '../misc/deprecation'; import flag, { TAIWAN } from '../misc/flag_cn'; import { NodeNameFilterType, SimpleNodeConfig, SortedNodeNameFilterType } from '../types'; +const showDEP003 = deprecate(_.noop, DEP003, 'DEP003'); +const showDEP004 = deprecate(_.noop, DEP004, 'DEP004'); + // tslint:disable-next-line:max-classes-per-file export class SortFilterWithSortedFilters implements SortedNodeNameFilterType { public supportSort = true; @@ -94,22 +99,30 @@ export const useRegexp = (regexp: RegExp): NodeNameFilterType => { return item => regexp.test(item.nodeName); }; -export const useProviders = (keywords: ReadonlyArray): NodeNameFilterType => { +export const useProviders = (keywords: ReadonlyArray, isStrict?: boolean): NodeNameFilterType => { // istanbul ignore next if (!Array.isArray(keywords)) { throw new Error('keywords 请使用数组'); } - return item => keywords.some(keyword => item?.provider?.name.includes(keyword)); + if (!isStrict) { + showDEP003(); + } + + return item => keywords.some(keyword => isStrict ? item?.provider?.name === keyword : item?.provider?.name.includes(keyword)); }; -export const discardProviders = (keywords: ReadonlyArray): NodeNameFilterType => { +export const discardProviders = (keywords: ReadonlyArray, isStrict?: boolean): NodeNameFilterType => { // istanbul ignore next if (!Array.isArray(keywords)) { throw new Error('keywords 请使用数组'); } - return item => !keywords.some(keyword => item?.provider?.name.includes(keyword)); + if (!isStrict) { + showDEP004(); + } + + return item => !keywords.some(keyword => isStrict ? item?.provider?.name === keyword : item?.provider?.name.includes(keyword)); }; export const useSortedKeywords = (keywords: ReadonlyArray): SortedNodeNameFilterType => { diff --git a/test/utils/filter.test.ts b/test/utils/filter.test.ts index dd300b92e..ef558931d 100644 --- a/test/utils/filter.test.ts +++ b/test/utils/filter.test.ts @@ -273,36 +273,64 @@ test('mergeFilters', t => { test('useProviders', t => { const fn = filter.useProviders(['测试', 'test']); + const fn2 = filter.useProviders(['测试', 'test'], true); t.is(fn({ ...generateVmessNode('test'), - provider: { name: '测试' } + provider: { name: '测试 asdf' } } as any), true); t.is(fn({ ...generateVmessNode('test'), - provider: { name: 'test' } + provider: { name: 'test asdf' } } as any), true); t.is(fn({ ...generateVmessNode('test'), provider: { name: 'other' } } as any), false); + + t.is(fn2({ + ...generateVmessNode('test'), + provider: { name: '测试 asdf' } + } as any), false); + t.is(fn2({ + ...generateVmessNode('test'), + provider: { name: 'test asdf' } + } as any), false); + t.is(fn2({ + ...generateVmessNode('test'), + provider: { name: 'test' } + } as any), true); }); test('discardProviders', t => { const fn = filter.discardProviders(['测试', 'test']); + const fn2 = filter.discardProviders(['测试', 'test'], true); t.is(fn({ ...generateVmessNode('test'), - provider: { name: '测试' } + provider: { name: '测试 asdf' } } as any), false); t.is(fn({ ...generateVmessNode('test'), - provider: { name: 'test' } + provider: { name: 'test asdf' } } as any), false); t.is(fn({ ...generateVmessNode('test'), provider: { name: 'other' } } as any), true); + + t.is(fn2({ + ...generateVmessNode('test'), + provider: { name: 'test' } + } as any), false); + t.is(fn2({ + ...generateVmessNode('test'), + provider: { name: 'test asdf' } + } as any), true); + t.is(fn2({ + ...generateVmessNode('test'), + provider: { name: 'other' } + } as any), true); }); function generateVmessNode(nodeName: string): VmessNodeConfig {