Jump to content
MediaWiki

Module:Extension

From mediawiki.org
Module documentation

Used primarily by Template:Extension and Template:Skin. Also defines a isOnGerrit function that is used by Template:Unmaintained extension, Template:ExtensionInstall, and Template:SkinInstall. Autofill feature depends on Module:ExtensionJson.

The above documentation is transcluded from Module:Extension/doc. (edit | history)
Editors can experiment in this module’s sandbox (edit | diff) and testcases (create) pages.
Subpages of this module.

 locallang=mw.language.getContentLanguage()
 localtranslation=mw.getCurrentFrame():callParserFunction{name='#translation',args="1"}
 localaddr={
 GNU='//www.gnu.org/licenses/',
 OSI='//opensource.org/licenses/',
 CC='//creativecommons.org/licenses/',
 Mozilla='//www.mozilla.org/'
 }
 localcats={
 GPL='GPL licensed extensions',
 FDL='FDL licensed extensions',
 LGPL='LGPL licensed extensions',
 AGPL='AGPL licensed extensions',
 MIT='MIT licensed extensions',
 ISC='ISC licensed extensions',
 BSD='BSD licensed extensions',
 MPL='MPL licensed extensions',
 WTFPL='WTFPL licensed extensions',
 Apache='Apache licensed extensions',
 PD='Public domain licensed extensions',
 CC='Creative Commons licensed extensions',
 ECL='Educational Community licensed extensions',
 Unlicense='The Unlicense licensed extensions',
 BLANK='Extensions with no license specified'
 }
 locallicenses={
 ['AGPL-3.0']={addr.GNU..'agpl-3.0.html','GNU Affero General Public License 3.0','AGPL'},
 ['AGPL-3.0-only']={addr.GNU..'agpl-3.0.html','GNU Affero General Public License 3.0','AGPL'},
 ['AGPL-3.0-or-later']={addr.GNU..'agpl-3.0.html','GNU Affero General Public License 3.0 or later','AGPL'},
 ['Apache-2.0']={'//www.apache.org/licenses/LICENSE-2.0','Apache License 2.0','Apache'},
 ['BSD-2-Clause']={addr.OSI..'BSD-2-Clause','BSD 2-clause "Simplified" License','BSD'},
 ['BSD-3-Clause']={addr.OSI..'BSD-3-Clause','BSD 3-clause "Modified" License','BSD'},
 ['BSD-4-Clause']={addr.GNU..'license-list.html#OriginalBSD','BSD 4-clause "Original" License','BSD'},
 ['CC-BY-3.0']={addr.CC..'by/3.0/','Creative Commons Attribution 3.0','CC'},
 ['CC-BY-3.0-US']={addr.CC..'by/3.0/us/','Creative Commons Attribution 3.0 United States','CC'},
 ['CC-BY-NC-3.0']={addr.CC..'by-nc/3.0/','Creative Commons Attribution NonCommercial 3.0','CC'},
 ['CC-BY-NC-SA-2.5']={addr.CC..'by-nc-sa/2.5/','Creative Commons Attribution NonCommercial Share Alike 2.5','CC'},
 ['CC-BY-NC-SA-3.0']={addr.CC..'by-nc-sa/3.0/','Creative Commons Attribution NonCommercial Share Alike 3.0','CC'},
 ['CC-BY-NC-SA-4.0']={addr.CC..'by-nc-sa/4.0/','Creative Commons Attribution NonCommercial Share Alike 4.0','CC'},
 ['CC-BY-SA-2.0']={addr.CC..'by-sa/2.0/','Creative Commons Attribution Share Alike 2.0','CC'},
 ['CC-BY-SA-2.0-UK']={addr.CC..'by-sa/2.0/uk/','Creative Commons Attribution Share Alike 2.0 England and Wales','CC'},
 ['CC-BY-SA-2.5']={addr.CC..'by-sa/2.5/','Creative Commons Attribution Share Alike 2.5','CC'},
 ['CC-BY-SA-3.0']={addr.CC..'by-sa/3.0/','Creative Commons Attribution Share Alike 3.0','CC'},
 ['CC-BY-SA-4.0']={addr.CC..'by-sa/4.0/','Creative Commons Attribution Share Alike 4.0','CC'},
 ['CC0-1.0']={'//creativecommons.org/publicdomain/zero/1.0/','Creative Commons Zero v1.0 Universal','PD'},
 ['ECL-2.0']={'','[[wikipedia:Educational Community License|Educational Community License 2.0]]','ECL'},
 ['FDL']={addr.GNU..'fdl.html','GNU Free Documentation License','FDL'},
 ['GPL-2.0']={addr.GNU..'old-licenses/gpl-2.0-standalone.html','GNU General Public License 2.0','GPL'},
 ['GPL-2.0-only']={addr.GNU..'old-licenses/gpl-2.0-standalone.html','GNU General Public License 2.0 only','GPL'},
 ['GPL-2.0-or-later']={addr.GNU..'old-licenses/gpl-2.0-standalone.html','GNU General Public License 2.0 or later','GPL'},
 ['GPL-3.0']={addr.GNU..'gpl-3.0-standalone.html','GNU General Public License 3.0','GPL'},
 ['GPL-3.0-only']={addr.GNU..'gpl-3.0-standalone.html','GNU General Public License 3.0 only','GPL'},
 ['GPL-3.0-or-later']={addr.GNU..'gpl-3.0-standalone.html','GNU General Public License 3.0 or later','GPL'},
 ['ISC']={addr.OSI..'ISC','ISC License','ISC'},
 ['LGPL-2.0-only']={addr.GNU..'old-licenses/lgpl-2.0-standalone.html','GNU Library General Public License v2 only','LGPL'},
 ['LGPL-2.1']={addr.GNU..'old-licenses/lgpl-2.1-standalone.html','GNU Lesser General Public License 2.1','LGPL'},
 ['LGPL-2.1-only']={addr.GNU..'old-licenses/lgpl-2.1-standalone.html','GNU Lesser General Public License 2.1 only','LGPL'},
 ['LGPL-2.1-or-later']={addr.GNU..'old-licenses/lgpl-2.1-standalone.html','GNU Lesser General Public License 2.1 or later','LGPL'},
 ['LGPL-3.0']={addr.GNU..'lgpl-3.0-standalone.html','GNU Lesser General Public License 3.0','LGPL'},
 ['LGPL-3.0-only']={addr.GNU..'lgpl-3.0-standalone.html','GNU Lesser General Public License 3.0 only','LGPL'},
 ['LGPL-3.0-or-later']={addr.GNU..'lgpl-3.0-standalone.html','GNU Lesser General Public License 3.0 or later','LGPL'},
 ['MIT']={addr.OSI..'mit-license.php','MIT License','MIT'},
 ['MPL-1.0']={addr.Mozilla..'MPL/1.0/','Mozilla Public License 1.0','MPL'},
 ['MPL-2.0']={addr.Mozilla..'MPL/2.0/','Mozilla Public License 2.0','MPL'},
 ['PD']={'','[[wikipedia:Public domain|Public domain]]','PD'},
 ['Unlicense']={'https://unlicense.org/','The Unlicense','Unlicense'},
 ['WTFPL']={'http://www.wtfpl.net','WTFPL 2.0','WTFPL'},
 ['Zlib']={addr.OSI..'Zlib','zlib License'},
 ['unspecified']={'','No license specified','BLANK'}
 }
 localtypes={
 ai={'[[w:Artificial intelligence|Artificial intelligence]]','Artificial intelligence extensions'},
 ajax={'[[w:AJAX|Ajax]]','Ajax extensions'},
 api={'[[API:Action API|API]]','API extensions'},
 ['beta feature']={'[[Beta Features|Beta Feature]]','Beta Feature extensions'},
 contenthandler={'[[Manual:ContentHandler|ContentHandler]]','ContentHandler extensions'},
 database={'[[Manual:Database layout|Database]]','Database extensions'},
 ['data extraction']={'Data extraction','Data extraction extensions'},
 example={'Example','Extension examples'},
 ['extended syntax']={'[[Manual:Extending wiki markup|Extended syntax]]','Extended syntax extensions'},
 filerepo={'File repository','File repository extensions'},
 hook={'[[Manual:Hooks|Hook]]','Hook extensions'},
 interface={'User interface','User interface extensions'},
 link={'[[Manual:Extending wiki markup|Link markup]]','Link markup extensions'},
 media={'Media','Media handling extensions'},
 mywiki={'[[Manual:Personalization|MyWiki]]','Personalization extensions'},
 notify={'Notify','Notification extensions'},
 ['page action']={'[[Manual:Parameters to index.php#Actions|Page action]]','Page action extensions'},
 parser={'[[Manual:Extending wiki markup|Parser extension]]','Parser extensions'},
 ['parser function']={'[[Manual:Parser functions|Parser function]]','Parser function extensions'},
 php={'PHP','PHP extensions'},
 search={'Search','Search extensions'},
 skin={'[[Manual:Skins|Skin]]','Skin extensions'},
 ['special page']={'[[Manual:Special pages|Special page]]','Special page extensions'},
 locale={'[[Manual:Localization|Locale]]','Internationalization extensions'},
 tag={'[[Manual:Tag extensions|Tag]]','Tag extensions'},
 ['user access']={'[[Manual:Security|User access]]','User access extensions'},
 ['user identity']={'[[Manual:Security|User identity]]','User identity extensions'},
 ['user rights']={'[[Manual:Security|User rights]]','User rights extensions'},
 ['user activity']={'[[Manual:Security|User activity]]','User activity extensions'},
 variable={'[[Manual:Variables|Variable]]','Variable extensions'},
 }

 localtypeAliases={
 db='database',
 pfunc='parser function',
 special='special page',
 }

 localfunctionsetI18n(from,to,index)
 forn,vinpairs(from)do
 ifto[n]then
 to[n][index]=v
 end
 end
 end

 localfunctioncat(title)
 return'[[Category:'..title..']]'
 end

 localfunctiontcat(title)
 returncat(title..translation)
 end

 localfunctiongetType(str,str2)
 localstr=mw.ustring.lower(str)
 iftypeAliases[str]then
 str=typeAliases[str]
 end
 localcnf=types[str]
 localres
 ifcnfthen
 res=cnf[1]..'[[Category:'..cnf[2]..translation..']]'
 else
 ifstr=='_missing_'then
 res=tcat('Extensions with invalid or missing type')
 elseifstr=='_demomode_'then
 ifstr2then
 res=lang:ucfirst(str2)
 else
 res="''unknown''"
 end
 else
 res=(stror'\'\'unknown\'\'')..
 ' [[Special:MyLanguage/Template:Extension#type|(\'\'\'\'\'invalid type\'\'\'\'\')]]'..
 tcat('Extensions with invalid or missing type')
 end
 end
 returnres
 end

 localfunctiongetExtData()
 localpg
 localpframe=mw.getCurrentFrame():getParent()
 ifpframeandpframe.args.repothen
 pg=pframe.args.repo
 else
 pg=mw.title.getCurrentTitle().rootPageTitle:partialUrl()-- need to get rid of translation subpage.
 end
 localdataTitle=mw.title.new('ExtensionJson/'..pg..'.json','Module')
 ifdataTitleanddataTitle.existsanddataTitle.contentModel=='json'then
 returnmw.loadJsonData(dataTitle.prefixedText)['master']
 end
 returnnil
 end

 localfunctiongetPopularityData()
 localpg
 localpframe=mw.getCurrentFrame():getParent()
 ifpframeandpframe.args.repothen
 pg=pframe.args.repo
 else
 pg=mw.title.getCurrentTitle().rootPageTitle:partialUrl()-- need to get rid of translation subpage.
 end
 type='extensions'
 ifmw.title.getCurrentTitle().rootPageTitle:inNamespace('skin')then
 type="skins"
 end
 returnmw.loadJsonData('Template:Extension/popularity.json')[type][pg]
 end

 localfunctiongetLicenseString(str)
 str=mw.text.trim(str)
 ifstr==""orstr==nilthen
 localdata=getExtData()
 ifdataanddata["license-name"]then
 str=data["license-name"]
 else
 str="unspecified"
 end
 end
 returnstr
 end
 localfunctiongetLicenseCategory(str)
 str=getLicenseString(str)
 ifmw.ustring.sub(str,-1)=='+'then
 str=mw.ustring.sub(str,1,-2)
 end
 localcnf=licenses[str]
 ifcnfthen
 if#cnf>2then
 returntcat(cats[cnf[3]])
 end
 else
 returntcat('Extensions with unknown license')
 end
 end

 localfunctiongetFormattedLicense(str,orlatertext)
 localorlater=''
 locallicense=getLicenseString(str)
 ifmw.ustring.sub(license,-1)=='+'then
 license=mw.ustring.sub(license,1,-2)
 orlater=orlatertext
 end
 localcnf=licenses[license]
 ifcnfthen
 return(cnf[1]~=''and('['..cnf[1]..' '..cnf[2]..']')orcnf[2])..orlater
 else
 returnlicense
 end
 end

 localp={}

 functionp.getTypes(frame)
 setI18n(frame.args,types,1)
 localargs=frame:getParent().args
 localtypes={}
 localparams={
 args.type1orargs['type']or'missing',
 args.type2,
 args.type3,
 args.type4,
 args.type5,
 args.type6,
 }
 for_,paraminipairs(params)do
 ifparam==nilormw.text.trim(param)==''then
 break
 end
 localparam=mw.text.trim(param)
 ifargs.templatemode=='nocats'then
 table.insert(types,getType('_demomode_',param))
 else
 table.insert(types,getType(param))
 end
 end
 returntable.concat(types,', ')
 end

 functionp.getType(frame)
 setI18n(frame.args,types,1)
 returngetType(frame.args[1])
 end

 functionp.getLicenseCategory(frame)
 returngetLicenseCategory(frame.args[1])
 end

 functionp.getFormattedLicense(frame)
 setI18n(frame.args,licenses,2)
 returngetFormattedLicense(frame.args[1],frame.args['+']or' or later')
 end


 -- Return if the extension does schema updates
 -- Only answer yes. For now be silent on no or unknown, as its unclear
 -- if this info should be in infobox if the answer is not yes.
 functionp.getNeedsUpdates(frame)
 localdata=getExtData()
 ifdata~=nilanddata.Hooks~=nilanddata.Hooks.LoadExtensionSchemaUpdates~=nilthen
 return'yes'
 end
 return''
 end

 functionp.getVersion(frame)

 ifframe.args[1]~=nilandmw.text.trim(frame.args[1])~=""then
 returnframe.args[1]
 end
 localdata=getExtData()
 ifdata~=nilanddata.version~=nilthen
 returndata.version
 end
 return''
 end

 -- --
 -- Get the requires.MediaWiki value from extension.json
 -- @link https://www.mediawiki.org/wiki/Manual:Extension.json/Schema#requires
 -- --
 functionp.getMediaWikiRequirement(frame)
 -- If the first arg is given, it'll be the manual override value.
 ifframe.args[1]~=nilandmw.text.trim(frame.args[1])~=""then
 returnframe.args[1]..tcat('Extensions with manual MediaWiki version')
 end
 -- If the compatibility policy is rel or ltsrel, then don't display something
 -- here because it likely disagrees with the compatibility policy.
 ifframe.args[2]~=nilandmw.ustring.find(frame.args[2],'rel')then
 return''
 end
 -- Otherwise, look it up from extension.json.
 localdata=getExtData()
 ifdataanddata.requiresanddata.requires.MediaWikithen
 returndata.requires.MediaWiki
 end
 localpargs=frame:getParent().args
 ifpargs.templatemode=="nocats"then
 return''
 end
 -- If neither are given, just categorize.
 returntcat('Extensions without MediaWiki version')
 end

 functionp.getPHPRequirement(frame)
 -- If the first arg is given, it'll be the manual override value.
 ifframe.args[1]~=nilandmw.text.trim(frame.args[1])~=""then
 returnframe.args[1]
 end
 -- Otherwise, look it up from extension.json.
 localdata=getExtData()
 -- unclear if we should somehow return other platform requirements
 ifdataanddata.requiresanddata.requires.platformanddata.requires.platform.phpthen
 returndata.requires.platform.php
 end
 -- Return nothing if unknown
 return
 end

 -- --
 -- Get the Composer name for the extension, with relevant categories.
 -- --
 functionp.getComposerName(frame)
 localname=nil
 localhasManualName=false
 -- If the first arg is given, it'll be the manual override value.
 ifframe.args[1]~=nilandmw.text.trim(frame.args[1])~=""then
 name=frame.args[1]
 hasManualName=true
 end
 -- Otherwise, look it up from extension.json.
 localdata=getExtData()
 localhasComposerName=false
 ifdataanddata.composerthen
 name=data.composer
 hasComposerName=true
 end
 -- Tracking category for possibly mis-configured packages.
 ifhasManualNameandnothasComposerNamethen
 cat('Extensions without name in composer.json')
 end
 ifname~=nilthen
 return'[https://packagist.org/packages/'..name..' '..name..']'
 ..tcat('Extensions supporting Composer')
 end
 end

 functionp.getHooks(frame)
 localhookOutput=frame.args.header
 localhooks={}
 localindex=1
 localpframe=frame:getParent()
 localfoundLocalHooks=false
 whiletruedo
 localargument=pframe.args["hook"..index]
 ifargumentandmw.text.trim(argument)~=""then
 hooks[#hooks+1]=mw.text.trim(argument)
 foundLocalHooks=true
 else
 break
 end
 index=index+1
 end
 ifnotfoundLocalHooksthen
 localdata=getExtData()
 ifdata==nilordata.Hooks==nilthen
 return""
 end
 forhook,_inpairs(data.Hooks)do
 hooks[#hooks+1]=hook
 end
 table.sort(hooks)
 end
 localfirst=true
 for_,hookinipairs(hooks)do
 iffirstthen
 first=false
 else
 hookOutput=hookOutput..frame.args.delim
 end
 hookOutput=hookOutput..frame:expandTemplate{title="Extension/HookInUse",args={hook,templatemode=pframe.args.templatemode}}
 end
 returnhookOutput..frame.args.footer
 end
 functionp.getParameters(frame)
 localdata=getExtData()
 ifdata==nilthen
 return""
 end
 localconfig=data.config
 ifconfig==nilthen
 return""
 end
 localprefix="wg"
 localskip_prefix=false
 ifdata.manifest_versionanddata.manifest_version>=2then
 ifdata.config_prefixthen
 prefix=data.config_prefix
 end
 else
 ifconfig._prefixthen
 prefix=config._prefix
 skip_prefix=true
 end
 end
 localout=""
 forkey,vinpairs(config)do
 localwrapper='<span class="configvariable">'
 iftype(v)=='table'andv.description~=nilthen
 localdesc=v.description
 iftype(desc)=='table'then
 -- Shallow clone in order to make the table library happy with mw.loadData
 desc=require("Module:TableTools").shallowClone(desc)
 desc=table.concat(desc," ")
 end
 wrapper='<span class="configvariable" title="'..mw.text.nowiki(desc)..'">'
 end
 ifkey~='_prefix'ornotskip_prefixthen
 out=out.."* "..wrapper.."$"..prefix..key.."</span>\n"
 end
 end
 returnout
 end

 -- Used by Template:ParameterList
 functionp.makeParametersList(frame)
 localdata=getExtData()
 ifdata==nilthen
 return""
 end
 localconfig=data.config
 ifconfig==nilthen
 return""
 end
 localprefix="wg"
 localskip_prefix=false
 ifdata.manifest_versionanddata.manifest_version>=2then
 ifdata.config_prefixthen
 prefix=data.config_prefix
 end
 else
 ifconfig._prefixthen
 prefix=config._prefix
 skip_prefix=true
 end
 end
 localout=""
 forkey,vinpairs(config)do
 localwrapper='<code class="configvariablevar">'
 localdesc=nil
 iftype(v)=='table'andv.description~=nilthen
 desc=v.description
 iftype(desc)=='table'then
 -- Shallow clone in order to make the table library happy with mw.loadData
 desc=require("Module:TableTools").shallowClone(desc)
 desc=table.concat(desc," ")
 end
 end
 ifkey~='_prefix'ornotskip_prefixthen
 out=out.."; "..wrapper.."$"..prefix..key.."</code>\n"
 ifdescthen
 out=out..":"..mw.text.nowiki(desc).."\n"
 end
 end
 end
 returnout
 end

 functionp.getRights(frame)
 localdata=getExtData()
 ifdata==nilthen
 return""
 end
 localrights=data.AvailableRights
 ifrights==nilthen
 return""
 end
 localout=""
 for_,rightinipairs(rights)do
 out=out.."* "..right.."\n"
 end
 returnout
 end
 functionp.unmaintained(frame)
 localcontent=mw.title.getCurrentTitle():getContent()
 ifnotcontent:find("{{[uU]nmaintained extension")andnotcontent:find("{{TNT|[uU]nmaintained extension")
 andnotcontent:find("{{User:Jeroen[ _]De[ _]Dauw/unmaintained")then
 localargs={}
 localpargs=frame:getParent().args
 ifpargs.templatemode=="nocats"then
 args.nocat="yes"
 end
 args.alternative=pargs.alternative
 returnframe:expandTemplate{title="Unmaintained extension",args=args}
 end
 end
 functionp.maintenanceLinks(frame)
 localbase=frame:expandTemplate{title="translatable"}
 ifbase==mw.title.getCurrentTitle().prefixedTextthen
 return
 end
 localout=""
 localcontent=mw.title.new(base):getContent()
 -- Check if the source page was archived or not
 ifcontent:find("{{[aA]rchived ?[Ee]xtension")orcontent:find("{{TNT|[Aa]rchived ?[Ee]xtension")then
 return"<span style='display:none'>[[Template:Extension/archived]]</span>"
 --Check if the source page was deleted or not
 elseifcontent:find("{{[dD]eleted extension security warning")then
 return"<span style='display:none'>[[Template:Extension/vulnerabilities]]</span>"
 end
 end
 functionp.isOnGerrit(frame)
 localtitle=mw.title.getCurrentTitle()
 ifnottitle:inNamespace("Extension")andnottitle:inNamespace("Skin")then
 return"n/a"
 end
 localbase=frame:expandTemplate{title="translatable"}
 localcontent=mw.title.new(base):getContent()
 ifcontent:find("{{Not on Gerrit")then
 return""
 end
 ifcontent:find("{{WikimediaDownload")orcontent:find("TNT|WikimediaDownload")orcontent:find("|repo%s*=")then
 return"yes"
 end
 end

 -- --
 -- Get a category if the extension isn't in Module:ExtensionJson.
 --
 functionp.getExtensionJsonCategory(frame)
 ifgetExtData()==nilthen
 returntcat('Extensions not in ExtensionJson')
 end
 end


 -- --
 -- Turn 1 into 1st. Probably bad for i18n.
 localfunctiongetOrdinal(n)
 ifn%10==1andn~=11then
 returnn.."<sup>st</sup>"
 end
 ifn%10==2andn~=12then
 returnn.."<sup>nd</sup>"
 end
 ifn%10==3andn~=13then
 returnn.."<sup>rd</sup>"
 end
 returnn.."<sup>th</sup>"
 end

 -- --
 -- Get number of downloads this quarter
 functionp.getDownloads(frame)
 localdata=getPopularityData()
 ifdata==nilordata.downloads==nilthen
 return''
 end
 localnum=data.downloads['13w'];
 ifnum==0then
 return"0"
 end
 localout=mw.getContentLanguage():formatNum(num)
 out=out.." (Ranked "..getOrdinal(data.downloadsRank['13w'])..")"
 returnout
 end

 -- --
 -- Get number of downloads this quarter
 functionp.getPublicSites(frame)
 localdata=getPopularityData()
 ifdata==nilordata.siteCount==nilthen
 return''
 end
 localout=mw.getContentLanguage():formatNum(data.siteCount)
 out=out.." (Ranked "..getOrdinal(data.siteCountRank)..")"
 returnout
 end

 -- --
 -- Get sites using this skin as default skin
 functionp.getPublicSitesSkinDefault(frame)
 localdata=getPopularityData()
 ifdata==nilordata.siteCountDefault==nilthen
 return''
 end
 localout=mw.getContentLanguage():formatNum(data.siteCountDefault)
 returnout
 end


 functionp.getAuthor(frame)
 ifframe.args[1]~=nilandmw.text.trim(frame.args[1])~=""then
 returnframe.args[1]
 end
 localdata=getExtData()
 ifdata~=nilanddata.author~=nilthen
 iftype(data.author)=="table"then
 res=''
 fork,vinipairs(data.author)do
 ifres~=''then
 res=res..', '
 end
 res=res..v
 end
 returnres
 else
 returndata.author
 end
 end
 return''
 end

 functionp.getDownload(frame)
 localdata=getExtData()
 ifdata~=nilthen
 repo_url=data.repository
 ifrepo_url==nilthen
 repo_url=data.url
 end
 ifrepo_url==nilthen
 error("AutoDownload: no repo URL")
 end
 account,repo=string.match(repo_url,"^https://github.com/([^/]+)/([^/]+)/?$")
 ifaccountthen
 returnframe:expandTemplate{title="GithubDownload",args={account,repo:gsub("%.git","")}}
 end
 account,repo=string.match(repo_url,"^https://gitlab.com/(.+)/([^/]+)/?$")
 ifaccountthen
 returnframe:expandTemplate{title="GitlabDownload",args={account,repo:gsub("%.git","")}}
 end
 account,repo=string.match(repo_url,"^https://bitbucket.org/([^/]+)/([^/]+)/?$")
 ifaccountthen
 returnframe:expandTemplate{title="BitbucketDownload",args={account,repo:gsub("%.git","")}}
 end
 repo=string.match(repo_url,"^https://gerrit.wikimedia.org/r/mediawiki/extensions/([^/]+)/?$")
 ifrepothen
 returnframe:expandTemplate{title="WikimediaDownload",args={repo}}
 end
 returnrepo_url
 end
 error("AutoDownload: Could not find ExtensionJson data")
 end

 returnp

AltStyle によって変換されたページ (->オリジナル) /