Skip to content

Commit aea0b1a

Browse files
committed
refactor: 自指抑制名单挪到 self-host-suppress.json
之前 SELF_HOST_SUPPRESS 直接写死在 popup-cache.ts 里,新增条目要改代码、重新构建;按项目「规则即数据」的约定挪到 public/rules/self-host-suppress.json,并接入 rules/index.json 里走统一加载链路。运行时通过 loadTechRules 读到 selfHostSuppress 字段,再走原来的主域回退匹配,行为一致。 将版本号提升到 1.3.40。
1 parent bc4100a commit aea0b1a

4 files changed

Lines changed: 82 additions & 64 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "stackprism",
33
"private": true,
4-
"version": "1.3.39",
4+
"version": "1.3.40",
55
"type": "module",
66
"description": "StackPrism 用于检测网页前端、后端、CDN、SaaS、广告营销、统计、登录、支付、网站程序和主题模板线索。",
77
"scripts": {

public/rules/index.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"headers/unknown-cdn-patterns.json",
5151
"headers/cdn-providers.json",
5252
"headers/languages.json",
53-
"headers/website-programs.json"
53+
"headers/website-programs.json",
54+
"self-host-suppress.json"
5455
]
5556
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"selfHostSuppress": {
3+
"github.com": ["GitHub.com", "GitHub", "GitHub Pages", "GitHub Assets", "GitHub Raw Content"],
4+
"github.io": ["GitHub Pages", "GitHub Assets", "GitHub Raw Content"],
5+
"gitlab.com": ["GitLab.com", "GitLab"],
6+
"gitlab.io": ["GitLab Pages"],
7+
"bitbucket.org": ["Bitbucket"],
8+
"codeberg.org": ["Codeberg"],
9+
"gitee.com": ["Gitee"],
10+
"huggingface.co": ["Hugging Face"],
11+
"stackoverflow.com": ["Stack Overflow"],
12+
"stackexchange.com": ["Stack Exchange"],
13+
"npmjs.com": ["npm", "npm 包注册中心"],
14+
"npmmirror.com": ["npmmirror CDN", "npmmirror"],
15+
"pypi.org": ["PyPI"],
16+
"crates.io": ["crates.io"],
17+
"rubygems.org": ["RubyGems"],
18+
"packagist.org": ["Packagist"],
19+
"twitter.com": ["Twitter", "X (Twitter)"],
20+
"x.com": ["Twitter", "X (Twitter)"],
21+
"facebook.com": ["Facebook"],
22+
"instagram.com": ["Instagram"],
23+
"linkedin.com": ["LinkedIn"],
24+
"youtube.com": ["YouTube"],
25+
"tiktok.com": ["TikTok"],
26+
"reddit.com": ["Reddit"],
27+
"discord.com": ["Discord"],
28+
"slack.com": ["Slack"],
29+
"telegram.org": ["Telegram"],
30+
"whatsapp.com": ["WhatsApp"],
31+
"medium.com": ["Medium"],
32+
"substack.com": ["Substack"],
33+
"notion.so": ["Notion"],
34+
"figma.com": ["Figma"],
35+
"linear.app": ["Linear"],
36+
"asana.com": ["Asana"],
37+
"trello.com": ["Trello"],
38+
"monday.com": ["monday.com", "Monday"],
39+
"airtable.com": ["Airtable"],
40+
"shopify.com": ["Shopify Admin"],
41+
"replit.com": ["Replit"],
42+
"codepen.io": ["CodePen"],
43+
"stackblitz.com": ["StackBlitz"],
44+
"codesandbox.io": ["CodeSandbox"],
45+
"jsfiddle.net": ["JSFiddle"],
46+
"google.com": ["Google Search"],
47+
"bing.com": ["Bing"],
48+
"duckduckgo.com": ["DuckDuckGo"],
49+
"baidu.com": ["百度", "Baidu"],
50+
"zhihu.com": ["知乎", "Zhihu"],
51+
"weibo.com": ["微博", "Weibo"],
52+
"bilibili.com": ["哔哩哔哩", "Bilibili"]
53+
}
54+
}

src/background/popup-cache.ts

Lines changed: 25 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
suppressFrontendFallbackDuplicates,
1212
suppressWordPressThemeDirectoryFallbacks
1313
} from './merge'
14-
import { loadDetectorSettings } from './detector-settings'
14+
import { loadDetectorSettings, loadTechRules } from './detector-settings'
1515
import { categoryIndex, confidenceRank } from '@/utils/category-order'
1616
import { cleanTechnologyUrl } from '@/utils/url'
1717
import { cleanStringArray } from '@/utils/normalize-settings'
@@ -214,60 +214,8 @@ const cleanRawDynamicObservation = (dynamic: any, data: any) => {
214214
}
215215

216216
// 站点自身的「品牌识别」抑制:当用户就在 github.com 时不再把 GitHub.com 当作一项「使用了的技术」
217-
// 显示给他,那是 URL 栏里已经告诉他的事情
218-
const SELF_HOST_SUPPRESS: Record<string, readonly string[]> = {
219-
'github.com': ['GitHub.com', 'GitHub', 'GitHub Pages', 'GitHub Assets', 'GitHub Raw Content'],
220-
'github.io': ['GitHub Pages', 'GitHub Assets', 'GitHub Raw Content'],
221-
'gitlab.com': ['GitLab.com', 'GitLab'],
222-
'gitlab.io': ['GitLab Pages'],
223-
'npmmirror.com': ['npmmirror CDN', 'npmmirror'],
224-
'bitbucket.org': ['Bitbucket'],
225-
'codeberg.org': ['Codeberg'],
226-
'gitee.com': ['Gitee'],
227-
'huggingface.co': ['Hugging Face'],
228-
'stackoverflow.com': ['Stack Overflow'],
229-
'stackexchange.com': ['Stack Exchange'],
230-
'npmjs.com': ['npm', 'npm 包注册中心'],
231-
'pypi.org': ['PyPI'],
232-
'crates.io': ['crates.io'],
233-
'rubygems.org': ['RubyGems'],
234-
'packagist.org': ['Packagist'],
235-
'twitter.com': ['Twitter', 'X (Twitter)'],
236-
'x.com': ['Twitter', 'X (Twitter)'],
237-
'facebook.com': ['Facebook'],
238-
'instagram.com': ['Instagram'],
239-
'linkedin.com': ['LinkedIn'],
240-
'youtube.com': ['YouTube'],
241-
'tiktok.com': ['TikTok'],
242-
'reddit.com': ['Reddit'],
243-
'discord.com': ['Discord'],
244-
'slack.com': ['Slack'],
245-
'telegram.org': ['Telegram'],
246-
'whatsapp.com': ['WhatsApp'],
247-
'medium.com': ['Medium'],
248-
'substack.com': ['Substack'],
249-
'notion.so': ['Notion'],
250-
'figma.com': ['Figma'],
251-
'linear.app': ['Linear'],
252-
'asana.com': ['Asana'],
253-
'trello.com': ['Trello'],
254-
'monday.com': ['monday.com', 'Monday'],
255-
'airtable.com': ['Airtable'],
256-
'shopify.com': ['Shopify Admin'],
257-
'replit.com': ['Replit'],
258-
'codepen.io': ['CodePen'],
259-
'stackblitz.com': ['StackBlitz'],
260-
'codesandbox.io': ['CodeSandbox'],
261-
'jsfiddle.net': ['JSFiddle'],
262-
'google.com': ['Google Search'],
263-
'bing.com': ['Bing'],
264-
'duckduckgo.com': ['DuckDuckGo'],
265-
'baidu.com': ['百度', 'Baidu'],
266-
'zhihu.com': ['知乎', 'Zhihu'],
267-
'weibo.com': ['微博', 'Weibo'],
268-
'bilibili.com': ['哔哩哔哩', 'Bilibili']
269-
}
270-
217+
// 展示出来——那是 URL 栏已经告诉他的事情。映射表本身放在 public/rules/self-host-suppress.json
218+
// 里,方便添加新条目而不动代码
271219
const extractRegistrableHost = (url: string): string => {
272220
try {
273221
return new URL(url).hostname.toLowerCase().replace(/^www\./, '')
@@ -276,22 +224,35 @@ const extractRegistrableHost = (url: string): string => {
276224
}
277225
}
278226

279-
const suppressSelfHostTechs = (technologies: any[], pageUrl: string): any[] => {
227+
const collectSuppressMap = (rules: any): Record<string, string[]> => {
228+
const raw = rules?.selfHostSuppress
229+
if (!raw || typeof raw !== 'object') return {}
230+
const out: Record<string, string[]> = {}
231+
for (const host of Object.keys(raw)) {
232+
const list = raw[host]
233+
if (!Array.isArray(list)) continue
234+
const names = list.filter((name: unknown): name is string => typeof name === 'string' && Boolean(name))
235+
if (names.length) out[host.toLowerCase()] = names
236+
}
237+
return out
238+
}
239+
240+
const suppressSelfHostTechs = (technologies: any[], pageUrl: string, suppressMap: Record<string, string[]>): any[] => {
280241
const host = extractRegistrableHost(pageUrl)
281242
if (!host) return technologies
282-
// 主域匹配:github.com 时也抑制;gist.github.com 时按完整 host 找不到,回退取末两段
243+
// 主域匹配:github.com 时直接命中;gist.github.com 时按末两段 github.com 回退
283244
const parts = host.split('.')
284245
const candidates = [host, parts.slice(-2).join('.')]
285246
const suppressNames = new Set<string>()
286247
for (const candidate of candidates) {
287-
const list = SELF_HOST_SUPPRESS[candidate]
248+
const list = suppressMap[candidate]
288249
if (list) for (const name of list) suppressNames.add(name)
289250
}
290251
if (!suppressNames.size) return technologies
291252
return technologies.filter(tech => !suppressNames.has(String(tech?.name || '')))
292253
}
293254

294-
const buildDisplayTechnologies = (data: any, settings: any) => {
255+
const buildDisplayTechnologies = (data: any, settings: any, suppressMap: Record<string, string[]>) => {
295256
const all: any[] = []
296257
addAllTechnologies(all, data.page?.technologies)
297258
addAllTechnologies(all, data.main?.technologies)
@@ -329,13 +290,14 @@ const buildDisplayTechnologies = (data: any, settings: any) => {
329290
)
330291
const pageUrl = data.page?.url || data.dynamic?.url || data.main?.url || ''
331292
return filterTechnologiesBySettings(
332-
suppressSelfHostTechs(suppressGenericCdnFallbacks(mergeDisplayTechnologyRecords(all)), pageUrl),
293+
suppressSelfHostTechs(suppressGenericCdnFallbacks(mergeDisplayTechnologyRecords(all)), pageUrl, suppressMap),
333294
settings
334295
)
335296
}
336297

337298
const buildPopupResult = async (data: any, settings: any, tab: any) => {
338-
const technologies = await attachTechnologyLinks(buildDisplayTechnologies(data, settings), settings)
299+
const suppressMap = collectSuppressMap(await loadTechRules())
300+
const technologies = await attachTechnologyLinks(buildDisplayTechnologies(data, settings, suppressMap), settings)
339301
const resources = mergeResourceSummary(data.page?.resources || {}, data.dynamic || {})
340302
const main = data.main || {}
341303
const headerCount =
@@ -354,7 +316,8 @@ const buildPopupResult = async (data: any, settings: any, tab: any) => {
354316
}
355317

356318
export const buildPopupRawResult = async (data: any, settings: any, tab: any) => {
357-
const technologies = await attachTechnologyLinks(buildDisplayTechnologies(data, settings), settings)
319+
const suppressMap = collectSuppressMap(await loadTechRules())
320+
const technologies = await attachTechnologyLinks(buildDisplayTechnologies(data, settings, suppressMap), settings)
358321
const resources = mergeResourceSummary(data.page?.resources || {}, data.dynamic || {})
359322
const headers = data.main?.allHeaders || data.main?.headers || {}
360323
return {

0 commit comments

Comments
 (0)