@@ -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'
1515import { categoryIndex , confidenceRank } from '@/utils/category-order'
1616import { cleanTechnologyUrl } from '@/utils/url'
1717import { 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+ // 里,方便添加新条目而不动代码
271219const extractRegistrableHost = ( url : string ) : string => {
272220 try {
273221 return new URL ( url ) . hostname . toLowerCase ( ) . replace ( / ^ w w w \. / , '' )
@@ -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
337298const 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
356318export 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