11import { fixedEncodeURIComponent , isAKey , isOfType , rejectObsoleteInterface , replaceSpaceByUnderscores } from '../utils/utils.js'
2- import { languages } from './sitelinks_languages.js'
3- import { specialSites } from './special_sites.js'
4- import type { WmLanguageCode } from '../types/options.js'
5- import type { Site } from '../types/sitelinks.js'
2+ import { specialSites , type Site , sites } from './wikimedia_constants.js'
3+ import type { LanguageCode } from '../types/options.js'
64import type { Url } from '../utils/build_url.js'
75
86const wikidataBase = 'https://www.wikidata.org/wiki/'
97
8+ type ValueOf < T > = T [ keyof T ]
9+ type SpecialSiteProjectName = ValueOf < typeof specialSites >
10+
1011export interface GetSitelinkUrlOptions {
11- site : Site
12+ site : Site | SpecialSiteProjectName
1213 title : string
1314}
1415
@@ -34,20 +35,23 @@ export function getSitelinkUrl ({ site, title }: GetSitelinkUrlOptions): Url {
3435
3536const wikimediaSite = ( subdomain : string ) => ( title : string ) => `https://${ subdomain } .wikimedia.org/wiki/${ title } `
3637
37- const siteUrlBuilders = {
38+ const siteUrlBuilders : Readonly < Record < SpecialSiteProjectName , ( s : string ) => string > > = {
3839 commons : wikimediaSite ( 'commons' ) ,
39- mediawiki : ( title : string ) => `https://www.mediawiki.org/wiki/${ title } ` ,
40+ foundation : wikimediaSite ( 'foundation' ) ,
41+ mediawiki : title => `https://www.mediawiki.org/wiki/${ title } ` ,
4042 meta : wikimediaSite ( 'meta' ) ,
43+ outreach : wikimediaSite ( 'outreach' ) ,
44+ sources : title => `https://wikisource.org/wiki/${ title } ` ,
4145 species : wikimediaSite ( 'species' ) ,
42- wikidata : ( entityId : string ) => {
46+ wikidata : entityId => {
4347 const prefix = prefixByEntityLetter [ entityId [ 0 ] ]
4448 let title = prefix ? `${ prefix } :${ entityId } ` : entityId
4549 // Required for forms and senses
4650 title = title . replace ( '-' , '#' )
4751 return `${ wikidataBase } ${ title } `
4852 } ,
4953 wikimania : wikimediaSite ( 'wikimania' ) ,
50- } as const
54+ }
5155
5256const prefixByEntityLetter = {
5357 E : 'EntitySchema' ,
@@ -58,7 +62,7 @@ const prefixByEntityLetter = {
5862const sitelinkUrlPattern = / ^ h t t p s ? : \/ \/ ( [ \w - ] { 2 , 10 } ) \. ( \w + ) \. o r g \/ \w + \/ ( .* ) /
5963
6064export interface SitelinkData {
61- lang : WmLanguageCode
65+ lang : LanguageCode
6266 project : Project
6367 key : string
6468 title ?: string
@@ -72,59 +76,52 @@ export function getSitelinkData (site: Site | Url): SitelinkData {
7276 if ( ! matchData ) throw new Error ( `invalid sitelink url: ${ url } ` )
7377 let [ lang , project , title ] = matchData . slice ( 1 )
7478 title = decodeURIComponent ( title )
75- let key : string
79+ if ( lang === 'commons' ) {
80+ return { lang : 'en' , project : 'commons' , key : 'commons' , title, url }
81+ }
82+
83+ if ( ! isOfType ( projectNames , project ) ) {
84+ throw new Error ( `project is unknown: ${ project } ` )
85+ }
86+
7687 // Known case: wikidata, mediawiki
7788 if ( lang === 'www' ) {
78- lang = 'en'
79- key = project
80- } else if ( lang === 'commons' ) {
81- lang = 'en'
82- project = key = 'commons'
83- } else {
84- // Support multi-parts language codes, such as be_x_old
85- lang = lang . replace ( / - / g, '_' )
86- key = `${ lang } ${ project } ` . replace ( 'wikipedia' , 'wiki' )
89+ return { lang : 'en' , project, key : project , title, url }
8790 }
88- // @ts -expect-error
91+
92+ // Support multi-parts language codes, such as be_x_old
93+ const sitelang = lang . replace ( / - / g, '_' )
94+ const key = `${ sitelang } ${ project } ` . replace ( 'wikipedia' , 'wiki' )
8995 return { lang, project, key, title, url }
9096 } else {
91- const key = site
9297 if ( isAKey ( specialSites , site ) ) {
9398 const project = specialSites [ site ]
94- return { lang : 'en' , project, key }
99+ return { lang : 'en' , project, key : site }
95100 }
96101
97- let [ lang , projectSuffix , rest ] = key . split ( 'wik' )
102+ if ( ! isOfType ( sites , site ) ) {
103+ throw new Error ( `site not found: ${ site } . Updating wikibase-sdk to a more recent version might fix the issue.` )
104+ }
98105
99- // Detecting cases like 'frwikiwiki' that would return [ 'fr', 'i', 'i' ]
100- if ( rest != null ) throw new Error ( `invalid sitelink key: ${ key } ` )
106+ let [ lang , projectSuffix , rest ] = site . split ( 'wik' )
101107
102- if ( ! isOfType ( languages , lang ) ) {
103- throw new Error ( `sitelink lang not found: ${ lang } . Updating wikibase-sdk to a more recent version might fix the issue.` )
104- }
108+ // Detecting cases like 'frwikiwiki' that would return [ 'fr', 'i', 'i' ]
109+ if ( rest != null ) throw new Error ( `invalid sitelink key: ${ site } ` )
105110
106111 // Support keys such as be_x_oldwiki, which refers to be-x-old.wikipedia.org
107112 lang = lang . replace ( / _ / g, '-' )
108113
109114 const project = projectsBySuffix [ projectSuffix ]
110115 if ( ! project ) throw new Error ( `sitelink project not found: ${ project } ` )
111116
112- // @ts -expect-error
113- return { lang, project, key }
117+ return { lang, project, key : site }
114118 }
115119}
116120
117- export const isSitelinkKey = ( site : string ) : boolean => {
118- try {
119- // relies on getSitelinkData validation
120- getSitelinkData ( site )
121- return true
122- } catch ( err ) {
123- return false
124- }
125- }
121+ export const isSite = ( site : string ) : site is Site => isOfType ( sites , site )
126122
127- export const wikimediaLanguageCodes = languages
123+ /** @deprecated use isSite */
124+ export const isSitelinkKey = isSite
128125
129126const projectsBySuffix = {
130127 i : 'wikipedia' ,
0 commit comments