import { detectDrainageContentWithRules, type DrainageDetectionRuleSnapshot } from './drainage-content-detection'; const rules: DrainageDetectionRuleSnapshot[] = [ { id: 'url', code: 'URL', name: 'URL', category: 'url', priority: 10, version: 1, flags: 'giu', pattern: '(?:https?:\\/\\/)?(?:www\\.)?(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,24}|(?:\\d{1,3}\\.){3}\\d{1,3})(?::\\d{1,5})?(?:\\/[^\\s,,;;!!??<>《》]*)?' }, { id: 'mobile', code: 'MOBILE', name: '手机', category: 'mobile', priority: 20, version: 1, flags: 'giu', pattern: '(?:^|[^0-9])((?:\\+?86)?1[3-9][0-9]{9})(?:$|[^0-9])' }, { id: 'landline', code: 'LANDLINE', name: '固话', category: 'landline', priority: 30, version: 1, flags: 'giu', pattern: '(?:^|[^0-9])((?:\\+?86)?(?:\\(0[0-9]{2,3}\\)|0[0-9]{2,3})-?[0-9]{7,8}(?:(?:转|分机|ext)[0-9]{1,6})?)(?:$|[^0-9])' }, ]; describe('drainage content detection', () => { test.each([ ['裸域名', '访问 t.cn/a1 查看详情', 'url'], ['IP 链接', '入口 192.168.1.10:8080/path。', 'url'], ['中文句号拆分域名', '请访问 example。com 领取', 'url'], ['+86 和空格手机号', '电话 +86 138 0013 8000', 'mobile'], ['短横线手机号', '电话 138-0013-8000', 'mobile'], ['括号区号和分机', '致电(010)8888-8888 转 123', 'landline'], ])('%s', (_name, content, category) => { const result = detectDrainageContentWithRules(content, rules); expect(result.hasDrainageContent).toBe(true); expect((result.drainageDetection as { matches: Array<{ category: string }> }).matches.some((item) => item.category === category)).toBe(true); }); it('does not classify an email address as drainage information', () => { expect(detectDrainageContentWithRules('联系邮箱 service@example.com,谢谢', rules).hasDrainageContent).toBe(false); expect(detectDrainageContentWithRules('邮箱 13800138000 @ example . com', rules).hasDrainageContent).toBe(false); }); it.each([' ', '\t', '\n', '\u3000'])('stops a URL match at whitespace %p', (separator) => { const url = 'https://example.com/path'; const suffix = '后续字符不属于链接'; const content = `详情 ${url}${separator}${suffix}`; const result = detectDrainageContentWithRules(content, rules); const urlMatches = (result.drainageDetection as { matches: Array<{ category: string; text: string; normalizedText: string }> }) .matches.filter((item) => item.category === 'url'); expect(urlMatches).toHaveLength(1); expect(urlMatches[0]).toMatchObject({ text: url, normalizedText: url }); }); it('does not join a domain split by spaces into one URL', () => { const result = detectDrainageContentWithRules('请访问 ex ample . com 领取', rules); expect(result.hasDrainageContent).toBe(false); }); it('keeps original offsets for record-page highlighting', () => { const content = '📨详情请看 example。com/path,谢谢'; const result = detectDrainageContentWithRules(content, rules); const [match] = (result.drainageDetection as { matches: Array<{ start: number; end: number }> }).matches; expect(content.slice(match.start, match.end)).toContain('example。com/path'); }); });