Modul:WLink

local WLink = { suite = "WLink", serial = "2018-09-23", item  = 19363224 }; --[=[ ansiPercent formatURL getArticleBase getBaseTitle getEscapedTitle getExtension getFile getFragment getLanguage getNamespace getNamespaced getPlain getProject getTarget getTalkPage getTargetPage getTitle getWeblink getWikilink isBracketedLink isBracketedURL isCategorization isExternalLink isInterlanguage isInterwiki isMedia isTalkPage isTitledLink isValidLink isWikilink pageTarget wikilink failsafe ]=]

-- local globals local URLutil = false;

local utilURL = function -- Attach URLutil library module -- Postcondition: --    Returns  table, with URLutil library --    Throws error, if not available if not URLutil then local lucky, util = pcall( require, "Module:URLutil" ); if lucky then if type( util ) == "table" then URLutil = util.URLutil; end util = "library URLutil invalid"; end if type( URLutil ) ~= "table" then error( util, 0 ); end end return URLutil; end -- utilURL

local cleanWikilink = function ( access ) -- Refine wikilink spacing and decode -- Precondition: --    access  -- string, with presumable link -- Postcondition: --    Returns  string, with pretty target local r = access:gsub( "_",       " " ) :gsub( " ",  " " ) :gsub( "&thinsp;", " " ) :gsub( "&#160;",  " " ) :gsub( "&#8239;", " " ) :gsub( "%s+",     " " ); r = mw.text.decode( r ); return r; end -- cleanWikilink

local contentExtlink = function ( attempt ) -- Retrieve span of external link between brackets -- Precondition: --    attempt  -- string, with presumable link --                        the first char is expected to be "[" -- Postcondition: --    Returns  string, number, number --                 string including whitespace --                 number with index of relevant "[" --                 number with index after relevant "]" --             false if nothing found local r1 = false; local r2 = false; local r3 = attempt:find( "]", 2, true ); if r3 then local s = attempt:sub( 2, r3 - 1 ); local i = s:find( "[", 1, true ); if i then r1 = s:sub( i + 1 ); r2 = i;       else r1 = s;           r2 = 1; end else r3 = false; end return r1, r2, r3; end -- contentExtlink

local contentWikilink = function ( attempt ) -- Retrieve span of wikilink between brackets -- Precondition: --    attempt  -- string, with presumable link --                       the first two chars are expected to be ""    -- Postcondition:    --     Returns  string, number, number    --                  string including whitespace    --                  number with index of relevant "[["    --                  number with index after relevant ""    --              false if nothing found    local r1 = false;    local r2 = false;    local r3 = attempt:find( "]]", 3, true ); if r3 then local s = attempt:sub( 3, r3 - 1 ); local i = s:find( "[[", 1, true );       if i then            r1 = s:sub( i + 2 );            r2 = i;        else            r1 = s;            r2 = 1;        end    end    return r1, r2, r3; end -- contentWikilink

local extractExtlink = function ( attempt ) -- Retrieve external link -- Precondition: --    attempt  -- string, with presumable link --                       the first char is expected to be "[" -- Postcondition: --    Returns  string, string --                 first with target and title --                 second result false if not titled --             false if nothing found local r1 = false; local r2 = false; local s = contentExtlink( attempt ); if s then local i = s:find( "%s", 1 ); if i then r1 = s:sub( 1, i - 1 ); r2 = mw.text.trim( s:sub( i + 1 ) ); if r2 == "" then r2 = false; end else r1 = s;       end if r1 then r1 = mw.text.trim( r1 ); if r1 == "" or               not utilURL.isResourceURL( r1 ) then r1 = false; end end if not r1 then r2 = false; end end return r1, r2; end -- extractExtlink

local extractWikilink = function ( attempt ) -- Retrieve wikilink -- Precondition: --    attempt  -- string, with presumable link --                       the first two chars are expected to be "[["    -- Postcondition:    --     Returns  string, string    --                  first with target    --                  second result title, or false if not piped    --              false if nothing found    local r1 = false;    local r2 = false;    local s = contentWikilink( attempt );    if s then        local i = s:find( "|", 1, true );        if i then            r1 = s:sub( 1,  i - 1 );            r2 = s:sub( i + 1 );        else            r1 = s;        end        r1 = mw.text.trim( r1 );        if r1 == "" then            r1 = false;        else            r1 = cleanWikilink( r1 );        end    end    return r1, r2; end -- extractWikilink

local prefix = function ( ask ) -- Interprete prefix of language or project type -- Precondition: --    ask    -- string, with presumable prefix -- Postcondition: --    Returns  string,string or nil --                    first  string one of "lead", "lang", "project" --                    second string is formatted value --                      type is one of "lead", "lang", "project" --             nil if nothing found local r1, r2; local prefixes = { b          = true, c          = "commons", d          = true, commons    = true, m          = "meta", mediawiki  = "mw", mw         = true, meta       = true, n          = true, q          = true, s          = true, simple     = false, v          = true, voy        = true, w          = true, wikibooks  = "b", wikidata   = "d", wikinews   = "n", wikipedia  = "w", wikiquote  = "q", wikisource = "s", wikiversity = "v", wikivoyage = "voy", wikt       = true, wiktionary = "wikt" };   local s = mw.text.trim( ask ); if s ~= "" then local p;       s = s:lower; p = prefixes[ s ]; if p == true then r1 = "project"; r2 = s;       elseif p then r1 = "project"; r2 = p;       elseif p == false then r1 = "lang"; r2 = s;       elseif s:match( "^%l%l%l?$" ) and mw.language.isSupportedLanguage( s ) then r1 = "lang"; r2 = s;       end end return r1, r2; end -- prefix

local target = function ( attempt, lonely ) -- Retrieve first target (wikilink or URL), or entire string -- Precondition: --    attempt  -- string, with presumable link somewhere --    lonely   -- remove fragment, if true -- Postcondition: --    Returns  string, number --                 string, with detected link target, or entire --                 number, with number of brackets, if found, or 2 local r1, r2 = WLink.getTarget( attempt ); if not r1 then r1 = mw.text.trim( attempt ); r2 = 2; end if lonely then local i = r1:find( "#", 1, true ); if i == 1 then r1 = ""; elseif i then r1 = r1:sub( 1, i - 1 ); end end return r1, r2; end -- target

function WLink.ansiPercent( attempt, alter ) -- Convert string by ANSI encoding rather than UTF-8 encoding -- Precondition: --    attempt  -- string, with presumable ANSI characters --    alter    -- string or nil, to use for spaces instead of %20 -- Postcondition: --    Returns  string, encoded local k, s;   local r = attempt; if alter then r = r:gsub( " ", alter ); end for i = mw.ustring.len( r ), 1, -1 do       k = mw.ustring.codepoint( r, i, i ); if k <= 32 or  k > 126 then if k > 255 then s = mw.ustring.sub( r, i, i ); if k > 2047 then s = string.format( "%%%2X%%%2X%%%2X",                                      s:byte( 1, 1 ),                                       s:byte( 2, 2 ),                                       s:byte( 3, 3 ) ); else s = string.format( "%%%2X%%%2X",                                      s:byte( 1, 1 ),                                       s:byte( 2, 2 ) ); end else s = string.format( "%%%2X", k ); end r = string.format( "%s%s%s",                              mw.ustring.sub( r,  1,  i - 1 ),                               s,                               mw.ustring.sub( r,  i + 1 ) ); end end -- for --i return r; end -- WLink.ansiPercent

function WLink.formatURL( adjust ) -- Create bracketed link, if not yet -- Precondition: --    adjust  -- string, with URL or domain/path or bracketed link -- Postcondition: --    Returns  string, with bracketed link --             false on invalid format local r;   if type( adjust ) == "string" then if WLink.isBracketedLink( adjust ) then r = adjust; else local url = mw.text.trim( adjust ); local host; utilURL; host = URLutil.getHost( adjust ); if not host then url = "http://" .. adjust; host = URLutil.getHost( url ); end if host then local path = URLutil.getRelativePath( url ); local show; if path == "/" then if not url:match( "/$" ) then url = url .. "/";                   end show = host; else local i = path:find( "#" ); if i then path = path:sub( 1, i - 1 ); end show = host .. path; end r = string.format( "[%s %s]", url, show ); else r = adjust; end end else r = false; end return r; end -- WLink.formatURL

function WLink.getArticleBase( attempt ) -- Retrieve generic article title, no fragment nor brackets -- Precondition: --    attempt  -- string, with wikilink or page title --                        current page title, if missing -- Postcondition: --    Returns  string, with identified lemma, or all --             false on invalid format local r;   if attempt then local m;       r, m = target( attempt, true ); if m ~= 2 then r = false; end else r = mw.title.getCurrentTitle.text; end if r then local sub = r:match( "^(.*%S) *%(.+%)$" ); if sub then r = sub; end end return r; end -- WLink.getArticleBase

function WLink.getBaseTitle( attempt ) -- Retrieve last segment in subpage, no fragment -- Precondition: --    attempt  -- string, with wikilink or page title -- Postcondition: --    Returns  string, with identified segment, or all local r;   local s, m = target( attempt, true ); if m == 2 then local sub = s:match( "/([^/]+)$" ); if sub then r = sub; else r = s;       end else r = false; end return r; end -- WLink.getBaseTitle

function WLink.getEscapedTitle( attempt ) -- Retrieve escaped link title -- Precondition: --    attempt  -- string, with presumable link title -- Postcondition: --    Returns  string, with suitable link title local s = mw.text.trim( attempt ); return s:gsub( "\n", " " ) :gsub( "%[", "&#91;" ) :gsub( "%]", "&#93;" ) :gsub( "|", "&#124;" ); end -- WLink.getEscapedTitle

function WLink.getExtension( attempt ) -- Retrieve media extension -- Precondition: --    attempt  -- string, with wikilink (media link) or page title --                        if URL, PDF may be detected -- Postcondition: --    Returns  string, with detected downcased media type --             false if no extension found local r = false; local s, m = target( attempt ); if m == 2 then s = s:match( "%.(%a+)$" ); if s then r = s:lower; end elseif s:upper:match( "[%./](PDF)%W?" ) then r = "pdf"; end return r; end -- WLink.getExtension

function WLink.getFile( attempt ) -- Retrieve media page identifier -- Precondition: --    attempt  -- string, with wikilink (media link) or page title -- Postcondition: --    Returns  string, with detected file title --                     no namespace nor project --             false if no file found local r = false; local s, m = target( attempt ); if m == 2 then local slow   = ":" .. s:lower; local find = function ( a ) local seek = string.format( ":%s:.+%%.%%a+$",                                                    a:lower ); local join = slow:find( seek ); local ret; if join then ret = s:sub( join + #a + 1 ); end return ret; end; r = find( "file" ); if not r then local trsl = mw.site.namespaces[6]; r = find( trsl.name ); if not r then trsl = trsl.aliases; for k, v in pairs( trsl ) do                   r = find( v ); if r then break; -- for k, v                   end end -- for k, v           end end end return r; end -- WLink.getFile

function WLink.getFragment( attempt ) -- Retrieve fragment -- Precondition: --    attempt  -- string, with presumable fragment -- Postcondition: --    Returns  string, with detected fragment --             false if no address found local r = false; local s, m = target( attempt ); if s then local i = s:find( "#", 1, true ); if i then if i > 1 then s = s:sub( i - 1 ); i = 2; end if s:find( "&#", 1, true ) then s = mw.text.decode( s ); i = s:find( "#", 1, true ); if not i then s = ""; i = 0; end end s = s:sub( i + 1 ); r = mw.text.trim( s ); if r == "" then r = false; elseif m == 2 then r = r:gsub( "%.(%x%x)", "%%%1" ) :gsub( "_", " " ); r = mw.uri.decode( r, "PATH" ); end end end return r; end -- WLink.getFragment

function WLink.getLanguage( attempt ) -- Retrieve language project identifier -- Precondition: --    attempt  -- string, with wikilink or page title -- Postcondition: --    Returns  string, with detected downcased language identifier --             false if no project language found local r = false; local s, m = WLink.getTarget( attempt ); if m == 2 then local w = WLink.wikilink( s ); if w and  w.lang then r = w.lang; end end return r; end -- WLink.getLanguage

function WLink.getNamespace( attempt ) -- Retrieve namespace number -- Precondition: --    attempt  -- string, with wikilink or page title -- Postcondition: --    Returns  number, of detected namespace --             false if no namespace found local r = false; local s, m = WLink.getTarget( attempt ); if m == 2 then local w = WLink.wikilink( s ); if w and  not w.lang  and  not w.project  and  w.ns then r = w.ns; end end return r; end -- WLink.getNamespace

function WLink.getNamespaced( area, attempt ) -- Retrieve page in namespace -- Precondition: --    area     -- string or number, with some namespace spec --    attempt  -- string, with wikilink or page title or page name -- Postcondition: --    Returns  page prefixed by namespace, --             false if invalid local r = false; local s = type( area ); local room; if s == "string" then room = mw.site.namespaces[ tonumber( area ) or  area ]; elseif s == "number" then room = mw.site.namespaces[ area ]; end if room then local m;       s, m = WLink.getTarget( attempt ); if not s then s = attempt; elseif m ~= 2 then s = false; end if s then local w = WLink.wikilink( s ); if w and  not w.lang  and  not w.project  and ( not w.ns or  w.ns == room.id ) then r = string.format( "%s:%s",                                  room.name, w.title ); end end end return r; end -- WLink.getNamespaced

function WLink.getPlain( attempt ) -- Retrieve text with all links replaced by link titles -- Precondition: --    attempt  -- string, with wikitext -- Postcondition: --    Returns  string, with modified wikitext without links local r = attempt; local i = 1; local j, k, n, lean, s, shift, span, space, suffix; while ( true ) do       j = r:find( "[", i, true ); if j then suffix = r:sub( j ); i     = j + 1; lean  = ( r:byte( i, i ) == 91 ); if lean then s, k, n = contentWikilink( suffix ); else s, k, n = contentExtlink( suffix ); end if s then if k > 1 then n     = n - k;                    i      = j + k;                    j      = i - 1; suffix = r:sub( j ); end if lean then s, shift = extractWikilink( suffix ); if s then space = s:match( "^([^:]+):" ); if space then space = mw.site.namespaces[ space ]; if space then space = space.id; end end if space == 6 or  space == 14 then shift = ""; elseif not shift then shift = s;                       end else s    = ""; shift = ""; end else span, shift = extractExtlink( suffix ); if span then if not shift then shift = ""; end else shift = string.format( "[%s]", s ); end i = i - 1; end if j > 1 then s = r:sub( 1, j - 1 ); else s = ""; end r = string.format( "%s%s%s",                                  s,  shift,  r:sub( n + i ) ); i = i + #shift; else break; -- while true end else break; -- while true end end   -- while true return r; end -- WLink.getPlain

function WLink.getProject( attempt ) -- Retrieve wikifarm project identifier -- Precondition: --    attempt  -- string, with wikilink or page title -- Postcondition: --    Returns  string, with detected downcased project identifier --             false if no project identifier found local r = false; local s, m = WLink.getTarget( attempt ); if m == 2 then local w = WLink.wikilink( s ); if w and  w.project then r = w.project; end end return r; end -- WLink.getProject

function WLink.getTalkPage( attempt ) -- Retrieve talk page name for attempt, or that page name itself -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  string  or  false local r = false; local s, m = WLink.getTarget( attempt ); if m ~= 2 and  attempt then s = mw.text.trim( attempt ); end if s and  s ~= "" then local w = mw.title.new( s ); if w then w = w.talkPageTitle; if w then r = w.prefixedText; end end end return r; end -- WLink.getTalkPage

function WLink.getTarget( attempt ) -- Retrieve first target (wikilink or URL) -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  string, number --                 string, with first detected link target --                 number, with number of brackets, if found --             false if nothing found local r1 = false; local r2 = false; local i = attempt:find( "[", 1, true ); if i then local m;       r1 = attempt:sub( i ); if r1:byte( 2, 2 ) == 91 then m = 2; r1 = extractWikilink( r1 ); else m = 1; r1 = extractExtlink( r1 ); end if r1 then r2 = m;       end else r1 = attempt:match( "%A?([hf]t?tps?://%S+)%s?" ); if r1 then if utilURL.isResourceURL( r1 ) then r2 = 0; else r1 = false; end else r1 = false; end end return r1, r2; end -- WLink.getTarget

function WLink.getTargetPage( attempt ) -- Retrieve first target page (page name or URL of page) -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  string, with first detected linked page --             false if nothing found local r1, r2 = WLink.getTarget( attempt ); if r1 then local i = r1:find( "#", 1, true ); if i then if i == 1 then r1 = false; else r1 = mw.text.trim( r1:sub( 1, i - 1 ) ); end end end return r1, r2; end -- WLink.getTargetPage

function WLink.getTitle( attempt ) -- Retrieve first link title (wikilink or URL), or wikilink target -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  string, with first detected link target --             false if nothing found local r = false; local i = attempt:find( "[", 1, true ); if i then local s1, s2; r = attempt:sub( i ); if r:byte( 2, 2 ) == 91 then s1, s2 = extractWikilink( r ); if s2 then r = s2; else r = s1; end else s1, r = extractExtlink( r ); end end return r; end -- WLink.getTitle

function WLink.getWeblink( attempt, anURLutil ) -- Retrieve bracketed link from resource URL -- Precondition: --    attempt    -- string, with URL, or something different --    anURLutil  -- library module object, or nil -- Postcondition: --    Returns  string, with first detected link target --             false if nothing found local second = ".ac.co.go.gv.or."; local r;   if type( anURLutil ) == "table" then URLutil = anURLutil; else utilURL; end if URLutil.isResourceURL( attempt ) then local site   = URLutil.getAuthority( attempt ); local service = attempt; local show; if #attempt == #site then site = site .. "/";       end show = URLutil.getTop3domain( "//" .. site ); if show then local scan  = "[%./](%a[%a%%%-]*%a)(%.%l%l%.)(%a+)$"; local search = "." .. show; local s1, s2, s3 = search:match( scan ); if s2 then if not second:find( s2, 1, true ) then show = string.format( "%s%s", s2:sub( 2 ),  s3 ); end else show = false; end end if not show then show = URLutil.getTop2domain( "//" .. site ); if not show then show = URLutil.getHost( "//" .. site ); end end if not service:match( "^[a-z:]*//.+/" ) then service = service .. "/";       end r = string.format( "[%s %s]", service, show ); else r = attempt; end return r; end -- WLink.getWeblink

function WLink.getWikilink( attempt, appear ) -- Retrieve bracketed link from text -- Precondition: --    attempt  -- string, with current target, or plain --    appear   -- string, with link title, or nil -- Postcondition: --    Returns  string, with first detected link target --             false if nothing found local r = WLink.pageTarget( attempt ); if r then if appear then local show = WLink.getEscapedTitle( appear ); if show ~= r and  show ~= "" then r = string.format( "%s|%s", r, show ); end end r = string.format( "%s", r ); end return r; end -- WLink.getWikilink

function WLink.isBracketedLink( attempt ) -- Does attempt match a bracketed link? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local r = false; local i = attempt:find( "[", 1, true ); if i then local s = attempt:sub( i ); if s:byte( 2, 2 ) == 91 then s = extractWikilink( s ); else s = extractExtlink( s ); end if s then r = true; end end return r; end -- WLink.isBracketedLink

function WLink.isBracketedURL( attempt ) -- Does attempt match a bracketed URL? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local s, r = WLink.getTarget( attempt ); return ( r == 1 ); end -- WLink.isBracketedURL

function WLink.isCategorization( attempt ) -- Does attempt match a categorization? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local r = false; local s, m = WLink.getTarget( attempt ); if m == 2 then local w = WLink.wikilink( s ); if w and  w.ns == 14 and not ( w.lead or w.lang or w.project ) and w.title ~= "" then r = true; end end return r; end -- WLink.isCategorization

function WLink.isExternalLink( attempt ) -- Does attempt match an external link? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local s, r = WLink.getTarget( attempt ); if r then r = ( r < 2 ); end return r; end -- WLink.isExternalLink

function WLink.isInterlanguage( attempt ) -- Does attempt match an interlanguage link? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local r = false; local s, m = WLink.getTarget( attempt ); if m == 2 then local w = WLink.wikilink( s ); if w and w.lang and not w.project and not w.lead and w.title ~= "" then r = true; end end return r; end -- WLink.isInterlanguage

function WLink.isInterwiki( attempt ) -- Does attempt match an interwiki link within wikifarm? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local r = false; local s, m = WLink.getTarget( attempt ); if m == 2 then local w = WLink.wikilink( s ); if w and  ( w.lang or w.project )  and  w.title ~= "" then r = true; end end return r; end -- WLink.isInterwiki

function WLink.isMedia( attempt ) -- Does attempt match a media translusion? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local r = false; local s, m = WLink.getTarget( attempt ); if m == 2 then local w = WLink.wikilink( s ); if w and  w.ns == 6 and not ( w.lead or w.lang or w.project ) and w.title ~= "" and WLink.getExtension( w.title ) then r = true; end end return r; end -- WLink.isMedia

function WLink.isTalkPage( attempt ) -- Does attempt describe a talk page? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local r = false; local s, m = WLink.getTarget( attempt ); if m ~= 2 and  attempt then s = mw.text.trim( attempt ); end if s and  s ~= "" then local w = mw.title.new( s ); if w then r = w.isTalkPage; end end return r; end -- WLink.isTalkPage

function WLink.isTitledLink( attempt ) -- Does attempt match a titled link? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local r = false; local i = attempt:find( "[", 1, true ); if i then local c, n;       local s = attempt:sub( i ); if s:byte( 2, 2 ) == 91 then n = s:find( "%]%]", 5 ); c = "|"; else n = s:find( "%]", 8 ); c = "%s%S"; end if n then local m = s:find( c, 2 ); if m and  m + 1 < n  and  WLink.getTarget( attempt ) then r = true; end end end return r; end -- WLink.isTitledLink

function WLink.isValidLink( attempt ) -- Does attempt match a link? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local s, r = WLink.getTarget( attempt ); if r then r = true; end return r; end -- WLink.isValidLink

function WLink.isWikilink( attempt ) -- Does attempt match a wikilink? -- Precondition: --    attempt  -- string, with presumable link somewhere -- Postcondition: --    Returns  boolean local s, m = WLink.getTarget( attempt ); return ( m == 2 ); end -- WLink.isWikilink

function WLink.pageTarget( attempt ) -- Create standardized wikilink target of a page -- Precondition: --    attempt  -- string, with presumable link --                        expected to be enclosed in "" "" --                        else wikilink -- Postcondition: --    Returns  string with link target local p = WLink.wikilink( attempt ); local r;   if p then local lead; if p.ns then if p.lang  or               ( p.project  and  ( p.project == "commons" or                                   p.project == "d" or                                   p.project == "meta" or                                   p.project == "mw" ) ) then p.space = mw.site.namespaces[ p.ns ].canonicalName; end lead = ( p.ns == 6 or  p.ns == 14 ); end if p.lang then lead = true; end if p.project then r = p.project .. ":";       elseif lead then r = ":"; else r = ""; end if p.lang then r = string.format( "%s%s:", r, p.lang ); end if p.space then r = string.format( "%s%s:", r, p.space ); end if p.title then r = r .. p.title; end if r == "" then r = false; end end if not r then r = string.format( ":%s:",                          mw.language.getContentLanguage:getCode ); end return r; end -- WLink.pageTarget

function WLink.wikilink( attempt ) -- Retrieve wikilink components -- Precondition: --    attempt  -- string, with presumable link --                        expected to be enclosed in "" "" --                        else wikilink -- Postcondition: --    Returns  table or false --             table of assignments with { type, value } --                      type is one of "lead", --                         "project", "lang", --                         "ns", "space", "title" --             false if nothing found local s = contentWikilink( attempt or "" ); local got, n, r;   if not s then s = attempt; end if s:find( "%", 1, true ) then s = mw.uri.decode( s, "PATH" ); end i = s:find( "|", 1, true ); if i then s = s:sub( 1, i - 1 ); end got = mw.text.split( s, ":" ); n  = table.maxn( got ); if n == 1 then r = { title = mw.text.trim( s ) }; else local j, k, o, v;       r = { title = "" }; while ( got[ 1 ] == "" ) do           r.lead = true; table.remove( got, 1 ); n = n - 1; end   -- while  got[ 1 ] == "" if n > 4 then k = 4; elseif n > 1 then k = n - 1; else k = 1; end j = k;       for i = 1, j do            s = mw.text.trim( got[ i ] ); if s ~= "" then o = mw.site.namespaces[ mw.text.trim( got[ i ] ) ]; if o then r.ns   = o.id; r.space = o.name; k = i + 1; j = i - 1; break; -- for i               end end end -- for i       for i = 1, j do            o, v = prefix( got[ i ] ); if o then if r[ o ] then k = i;                   break; -- for i                else if i >= k then k = i + 1; end r[ o ] = v;               end else if i == 1 and  r.ns then r.ns   = false; r.space = false; end k = i;               break; -- for i            end end -- for i       if k > 0 then for i = k, n do               r.title = r.title .. got[ i ]; if i < n then r.title = r.title .. ":";               end end -- for i       end end r.title = cleanWikilink( r.title ); if r.lead and ( r.project or         ( not r.lang  and  r.ns ~= 6  and  r.ns ~= 14 ) ) then r.lead = false; end return r; end -- WLink.wikilink

function WLink.failsafe( assert ) -- Retrieve versioning and check for compliance -- Precondition: --    assert  -- string, with required version or "wikidata", --               or false -- Postcondition: --    Returns  string with appropriate version, or false local since = assert; local r;   if since == "wikidata" then local item = WLink.item; since = false; if type( item ) == "number" and  item > 0 then local ent = mw.wikibase.getEntity( string.format( "Q%d", item ) ); if type( ent ) == "table" then local vsn = ent:formatPropertyValues( "P348" ); if type( vsn ) == "table" and type( vsn.value ) == "string" and vsn.value ~= "" then r = vsn.value; end end end end if not r then if not since or  since <= WLink.serial then r = WLink.serial; else r = false; end end return r; end -- WLink.failsafe

local function Template( frame, action, leave, lone ) -- Run actual code from template transclusion -- Precondition: --    frame   -- object --    action  -- string, with function name --    leave   -- true: keep whitespace around --    lone    -- true: permit call without parameters -- Postcondition: --    Return string; might be error message local lucky = true; local s = false; local r = false; local space; for k, v in pairs( frame.args ) do       if k == 1 then if leave then s = v;           else s = mw.text.trim( v ); end elseif ( k == 2  and                 ( action == "getNamespaced"  or                   action == "getWikilink" ) )    or               ( k == "space"  and  action == "ansiPercent" ) then if v ~= "" then space = v;           end elseif k ~= "template" then lucky = false; if r then r = r .. "|";           else r = "Unknown parameter: "; end r = string.format( "%s%s=", r, k ); end end -- for k, v   if lucky then if s or lone then lucky, r = pcall( WLink[ action ], s,  space ); else r = "Parameter missing"; lucky = false; end end if lucky then if type( r ) == "boolean" then if r then r = "1"; else r = ""; end end else local e = mw.html.create( "span" ); r = tostring( e:addClass( "error" )                      :wikitext( r ) ); end return r; end -- Template

-- Export local p = { };

p.ansiPercent = function ( frame ) return Template( frame, "ansiPercent" ); end p.formatURL = function ( frame ) return Template( frame, "formatURL" ); end p.getArticleBase = function ( frame ) return Template( frame, "getArticleBase", false, true ); end p.getBaseTitle = function ( frame ) return Template( frame, "getBaseTitle" ); end p.getEscapedTitle = function ( frame ) return Template( frame, "getEscapedTitle" ); end p.getExtension = function ( frame ) return Template( frame, "getExtension" ); end p.getFile = function ( frame ) return Template( frame, "getFile" ); end p.getFragment = function ( frame ) return Template( frame, "getFragment" ); end p.getInterwiki = function ( frame ) return Template( frame, "getInterwiki" ); end p.getLanguage = function ( frame ) return Template( frame, "getLanguage" ); end p.getNamespace = function ( frame ) return tostring( Template( frame, "getNamespace" ) ); end p.getNamespaced = function ( frame ) return tostring( Template( frame, "getNamespaced" ) ); end p.getPlain = function ( frame ) return Template( frame, "getPlain" ); end p.getProject = function ( frame ) return Template( frame, "getProject" ); end p.getTalkPage = function ( frame ) return Template( frame, "getTalkPage" ); end p.getTarget = function ( frame ) return Template( frame, "getTarget" ); end p.getTargetPage = function ( frame ) return Template( frame, "getTargetPage" ); end p.getTitle = function ( frame ) return Template( frame, "getTitle" ); end p.getWeblink = function ( frame ) return Template( frame, "getWeblink" ); end p.getWikilink = function ( frame ) return Template( frame, "getWikilink" ); end p.isBracketedLink = function ( frame ) return Template( frame, "isBracketedLink" ); end p.isBracketedURL = function ( frame ) return Template( frame, "isBracketedURL" ); end p.isCategorization = function ( frame ) return Template( frame, "isCategorization" ); end p.isExternalLink = function ( frame ) return Template( frame, "isExternalLink" ); end p.isInterlanguage = function ( frame ) return Template( frame, "isInterlanguage" ); end p.isInterwiki = function ( frame ) return Template( frame, "isInterwiki" ); end p.isMedia = function ( frame ) return Template( frame, "isMedia" ); end p.isTalkPage = function ( frame ) return Template( frame, "isTalkPage" ); end p.isTitledLink = function ( frame ) return Template( frame, "isTitledLink" ); end p.isValidLink = function ( frame ) return Template( frame, "isValidLink" ); end p.isWeblink = function ( frame ) return Template( frame, "isWeblink" ); end p.isWikilink = function ( frame ) return Template( frame, "isWikilink" ); end p.failsafe = function ( frame ) local s = type( frame ); local since; if s == "table" then since = frame.args[ 1 ]; elseif s == "string" then since = frame; end if since then since = mw.text.trim( since ); if since == "" then since = false; end end return WLink.failsafe( since ) or ""; end p.WLink = function return WLink; end

return p;