Modul:TemplateData: Unterschied zwischen den Versionen
2019-01-03 |
imported>PerfektesChaos 2020-12-03 |
||
| (Eine dazwischenliegende Version von einem anderen Benutzer wird nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
local TemplateData = { suite = "TemplateData", | local TemplateData = { suite = "TemplateData", | ||
serial = " | serial = "2020-12-03", | ||
item = 46997995 } | item = 46997995 } | ||
--[=[ | --[=[ | ||
improve template:TemplateData | improve template:TemplateData | ||
]=] | ]=] | ||
local Failsafe = TemplateData | |||
| Zeile 48: | Zeile 49: | ||
got = false, -- table, initial templatedata object | got = false, -- table, initial templatedata object | ||
heirs = false, -- table, params that are inherited | heirs = false, -- table, params that are inherited | ||
jump = false, -- source position at end of "params" | |||
less = false, -- main description missing | less = false, -- main description missing | ||
lasting = false, -- old syntax encountered | lasting = false, -- old syntax encountered | ||
| Zeile 57: | Zeile 59: | ||
scream = false, -- error messages | scream = false, -- error messages | ||
sibling = false, -- TOC juxtaposed | sibling = false, -- TOC juxtaposed | ||
slang = | slang = nil, -- project/user language code | ||
slim = false, -- JSON reduced to plain | slim = false, -- JSON reduced to plain | ||
source = false, -- JSON input | source = false, -- JSON input | ||
| Zeile 136: | Zeile 138: | ||
local function Fetch( ask ) | local function Fetch( ask, allow ) | ||
-- Fetch module | -- Fetch module | ||
-- Parameter: | -- Parameter: | ||
-- ask | -- ask -- string, with name | ||
-- | -- "/global" | ||
-- | -- "JSONutil" | ||
-- | -- "Multilingual" | ||
-- | -- "Text" | ||
-- "WLink" | |||
-- allow -- true: no error if unavailable | |||
-- Returns table of module | -- Returns table of module | ||
-- error: Module not available | -- error: Module not available | ||
| Zeile 168: | Zeile 172: | ||
end | end | ||
TemplateData.extern[ sign ] = r | TemplateData.extern[ sign ] = r | ||
elseif not allow then | |||
error( string.format( "Fetch(%s) %s", sign, g ) ) | error( string.format( "Fetch(%s) %s", sign, g ), 0 ) | ||
end | end | ||
end | end | ||
return r | return r | ||
end -- Fetch() | end -- Fetch() | ||
local function Foreign() | |||
-- Guess human language | |||
-- Returns slang, or not | |||
if type( Data.slang ) == "nil" then | |||
local Multilingual = Fetch( "Multilingual", true ) | |||
if Multilingual and | |||
type( Multilingual.userLangCode ) == "function" then | |||
Data.slang = Multilingual.userLangCode() | |||
else | |||
Data.slang = mw.language.getContentLanguage():getCode() | |||
:lower() | |||
end | |||
end | |||
if Data.slang and | |||
mw.ustring.codepoint( Data.slang, 1, 1 ) > 122 then | |||
Data.slang = false | |||
end | |||
return Data.slang | |||
end -- Foreign() | |||
| Zeile 187: | Zeile 213: | ||
:gsub( "([%-.()+*?^$%[%]])", | :gsub( "([%-.()+*?^$%[%]])", | ||
"%%%1" ) ) | "%%%1" ) ) | ||
local i, k = Data.source:find( | local i, k, r, slice, source | ||
if not Data.jump then | |||
Data.jump = Data.source:find( "params", 2 ) | |||
if Data.jump then | |||
Data.jump = Data.jump + 7 | |||
else | |||
Data.jump = 1 | |||
end | |||
end | |||
i, k = Data.source:find( seek, at + Data.jump ) | |||
while i and not r do | while i and not r do | ||
source = Data.source:sub( k + 1 ) | source = Data.source:sub( k + 1 ) | ||
| Zeile 199: | Zeile 233: | ||
r = k | r = k | ||
else | else | ||
i, k = Data.source:find( seek, k ) | i, k = Data.source:find( seek, k ) | ||
end | end | ||
end -- while i | end -- while i | ||
| Zeile 213: | Zeile 247: | ||
-- Returns string, with localized text | -- Returns string, with localized text | ||
local o = mw.message.new( "templatedata-" .. adapt ) | local o = mw.message.new( "templatedata-" .. adapt ) | ||
if | if Foreign() then | ||
o:inLanguage( Data.slang ) | o:inLanguage( Data.slang ) | ||
end | end | ||
| Zeile 360: | Zeile 388: | ||
local variants = { } | local variants = { } | ||
local r1, r2 | local r1, r2 | ||
for k, v in pairs( alternatives ) do | for k, v in pairs( alternatives ) do | ||
if type( v ) == "string" then | if type( v ) == "string" then | ||
v = mw.text.trim( v ) | v = mw.text.trim( v ) | ||
if v ~= "" then | if v ~= "" and type( k ) == "string" then | ||
k = k:lower() | k = k:lower() | ||
variants[ k ] = v | variants[ k ] = v | ||
| Zeile 375: | Zeile 399: | ||
end -- for k, v | end -- for k, v | ||
if n > 0 then | if n > 0 then | ||
local | local Multilingual = Fetch( "Multilingual", true ) | ||
if | if Multilingual and | ||
type( Multilingual.i18n ) == "function" then | |||
local show, slang = Multilingual.i18n( variants ) | |||
if show then | |||
if | r1 = show | ||
r1 = | variants[ slang ] = nil | ||
variants[ | |||
r2 = variants | r2 = variants | ||
end | end | ||
end | end | ||
if not r1 then | if not r1 then | ||
Foreign() | |||
for k, v in pairs( variants ) do | |||
if n == 1 then | |||
r1 = v | |||
elseif Data.slang == k then | |||
variants[ k ] = nil | |||
r1 = v | |||
end | r2 = variants | ||
end | |||
end -- for k, v | |||
end | end | ||
if r2 then | if r2 and Multilingual then | ||
for k, v in pairs( r2 ) do | for k, v in pairs( r2 ) do | ||
if v and not Multilingual.isLang( k, true ) then | if v and not Multilingual.isLang( k, true ) then | ||
Fault( string.format( " | Fault( string.format( "%s <code>lang=%s</code>", | ||
"Invalid", | |||
k ) ) | k ) ) | ||
end | end | ||
| Zeile 656: | Zeile 677: | ||
local pointers = { } | local pointers = { } | ||
local points = { } | local points = { } | ||
local given = { } | |||
for k, v in pairs( Data.tree.params ) do | for k, v in pairs( Data.tree.params ) do | ||
i = facet( k, 1 ) | i = facet( k, 1 ) | ||
if type( v ) == "table" then | |||
if type( v.label ) == "string" then | |||
s = mw.text.trim( v.label ) | |||
if s == "" then | |||
s = k | |||
end | |||
else | |||
s = k | |||
end | |||
if given[ s ] then | |||
if given[ s ] == 1 then | |||
local scream = "Parameter label '%s' detected multiple times" | |||
Fault( string.format( scream, s ) ) | |||
given[ s ] = 2 | |||
end | |||
else | |||
given[ s ] = 1 | |||
end | |||
end | |||
if i then | if i then | ||
table.insert( points, i ) | table.insert( points, i ) | ||
| Zeile 796: | Zeile 837: | ||
if type( boole.show ) == "string" then | if type( boole.show ) == "string" then | ||
local v = mw.html.create( "span" ) | local v = mw.html.create( "span" ) | ||
:attr( "aria-hidden", "true" ) | |||
:wikitext( boole.show ) | :wikitext( boole.show ) | ||
if boole.css then | if boole.css then | ||
| Zeile 822: | Zeile 864: | ||
-- type | -- type | ||
if type( param.type ) == "string" then | |||
param.type = mw.text.trim( param.type ) | |||
if param.type == "" then | |||
param.type = false | |||
end | |||
end | |||
if param.type then | if param.type then | ||
s = Permit.types[ param.type ] | s = Permit.types[ param.type ] | ||
| Zeile 853: | Zeile 901: | ||
typed = mw.html.create( "td" ) | typed = mw.html.create( "td" ) | ||
:wikitext( factory( "doc-param-type-unknown" ) ) | :wikitext( factory( "doc-param-type-unknown" ) ) | ||
Data.params[ access ].type = "unknown" | |||
if param.default then | |||
Data.params[ access ].default = nil | |||
Fault( "Default value requires <code>type</code>" ) | |||
legal = false | |||
end | |||
end | end | ||
| Zeile 889: | Zeile 943: | ||
ranking:tag( "br" ) | ranking:tag( "br" ) | ||
ranking:wikitext( param.deprecated ) | ranking:wikitext( param.deprecated ) | ||
end | |||
if param.suggested and mode == 4 then | |||
s = string.format( "Suggesting deprecated <code>%s</code>", | |||
access ) | |||
Fault( s ) | |||
legal = false | |||
end | end | ||
end | end | ||
| Zeile 998: | Zeile 1.058: | ||
local function | local function fellow( any, assigned, at ) | ||
-- | -- Check sets[] parameter and issue error message, if necessary | ||
-- Parameter: | -- Parameter: | ||
-- advance -- true, for nice | -- any -- should be number | ||
-- Returns string | -- assigned -- parameter name | ||
local r, lapsus | -- at -- number, of set | ||
if Data.div then | local s | ||
if type( any ) ~= "number" then | |||
s = "<code>sets[%d].params[%s]</code>??" | |||
Fault( string.format( s, | |||
at, | |||
mw.text.nowiki( tostring( any ) ) ) ) | |||
elseif type( assigned ) == "string" then | |||
if not Data.got.params[ assigned ] then | |||
s = "<code>sets[%d].params %s</code> is undefined" | |||
Fault( string.format( s, at, assigned ) ) | |||
end | |||
else | |||
s = "<code>sets[%d].params[%d] = %s</code>??" | |||
Fault( string.format( s, k, type( assigned ) ) ) | |||
end | |||
end -- fellow() | |||
local function fellows() | |||
-- Check sets[] and issue error message, if necessary | |||
local s | |||
if type( Data.got.sets ) == "table" then | |||
if type( Data.got.params ) == "table" then | |||
for k, v in pairs( Data.got.sets ) do | |||
if type( k ) == "number" then | |||
if type( v ) == "table" then | |||
for ek, ev in pairs( v ) do | |||
if ek == "label" then | |||
s = type( ev ) | |||
if s ~= "string" and | |||
s ~= "table" then | |||
s = "<code>sets[%d].label</code>??" | |||
Fault( string.format( s, k ) ) | |||
end | |||
elseif ek == "params" and | |||
type( ev ) == "table" then | |||
for pk, pv in pairs( ev ) do | |||
fellow( pk, pv, k ) | |||
end -- for pk, pv | |||
else | |||
ek = mw.text.nowiki( tostring( ek ) ) | |||
s = "<code>sets[%d][%s]</code>??" | |||
Fault( string.format( s, k, ek ) ) | |||
end | |||
end -- for ek, ev | |||
else | |||
k = mw.text.nowiki( tostring( k ) ) | |||
v = mw.text.nowiki( tostring( v ) ) | |||
s = string.format( "<code>sets[%s][%s]</code>??", | |||
k, v ) | |||
Fault( s ) | |||
end | |||
else | |||
k = mw.text.nowiki( tostring( k ) ) | |||
s = string.format( "<code>sets[%s]</code> ?????", k ) | |||
Fault( s ) | |||
end | |||
end -- for k, v | |||
else | |||
s = "<code>params</code> required for <code>sets</code>" | |||
Fault( s ) | |||
end | |||
else | |||
s = "<code>sets</code> needs to be of <code>object</code> type" | |||
Fault( s ) | |||
end | |||
end -- fellows() | |||
local function finalize( advance ) | |||
-- Wrap presentation into frame | |||
-- Parameter: | |||
-- advance -- true, for nice | |||
-- Returns string | |||
local r, lapsus | |||
if Data.div then | |||
r = tostring( Data.div ) | r = tostring( Data.div ) | ||
elseif Data.strip then | elseif Data.strip then | ||
| Zeile 1.263: | Zeile 1.400: | ||
end | end | ||
end -- for k, v | end -- for k, v | ||
if not access and Data.got.sets then | |||
fellows() | |||
end | |||
else | else | ||
Fault( f() .. " needs to be of <code>object</code> type" ) | Fault( f() .. " needs to be of <code>object</code> type" ) | ||
| Zeile 1.497: | Zeile 1.637: | ||
if s then | if s then | ||
if Data.leading then | if Data.leading then | ||
r:node( mw.html.create( " | r:node( mw.html.create( "h" .. Config.nested ) | ||
:wikitext( factory( "doc-params" ) ) ) | :wikitext( factory( "doc-params" ) ) ) | ||
:newline() | :newline() | ||
| Zeile 1.538: | Zeile 1.678: | ||
local function free() | local function free() | ||
-- Remove JSON comment lines | -- Remove JSON comment lines | ||
Data.source:gsub( "([{,\"'])(%s*\n%s*//.*\n%s*)([},\"'])", | if Data.source:find( "//", 1, true ) then | ||
Data.source:gsub( "([{,\"'])(%s*\n%s*//.*\n%s*)([{},\"'])", | |||
"%1%3" ) | |||
end | |||
end -- free() | end -- free() | ||
| Zeile 1.602: | Zeile 1.744: | ||
end | end | ||
end -- for k, v | end -- for k, v | ||
if arglist.heading and arglist.heading:match( "^[3-6]$" ) then | |||
Config.nested = arglist.heading | |||
else | |||
Config.nested = "2" | |||
end | |||
Config.loudly = faculty( arglist.debug or adapt.debug ) | Config.loudly = faculty( arglist.debug or adapt.debug ) | ||
Data.lazy = faculty( arglist.lazy ) and not Config.loudly | Data.lazy = faculty( arglist.lazy ) and not Config.loudly | ||
| Zeile 1.661: | Zeile 1.808: | ||
Failsafe.failsafe = function ( atleast ) | |||
-- Retrieve versioning and check for compliance | -- Retrieve versioning and check for compliance | ||
-- Precondition: | -- Precondition: | ||
-- | -- atleast -- string, with required version | ||
-- | -- or wikidata|item|~|@ or false | ||
-- Postcondition: | -- Postcondition: | ||
-- Returns string with | -- Returns string -- with queried version/item, also if problem | ||
local since = | -- false -- if appropriate | ||
-- 2020-08-17 | |||
local since = atleast | |||
local last = ( since == "~" ) | |||
local linked = ( since == "@" ) | |||
local link = ( since == "item" ) | |||
local r | local r | ||
if since == "wikidata" then | if last or link or linked or since == "wikidata" then | ||
local item = | local item = Failsafe.item | ||
since = false | since = false | ||
if type( item ) == "number" and item > 0 then | if type( item ) == "number" and item > 0 then | ||
local | local suited = string.format( "Q%d", item ) | ||
if link then | |||
r = suited | |||
else | |||
local entity = mw.wikibase.getEntity( suited ) | |||
if type( entity ) == "table" then | |||
local seek = Failsafe.serialProperty or "P348" | |||
local vsn = entity:formatPropertyValues( seek ) | |||
if type( vsn ) == "table" and | |||
type( vsn.value ) == "string" and | |||
vsn.value ~= "" then | |||
if last and vsn.value == Failsafe.serial then | |||
r = false | |||
elseif linked then | |||
if mw.title.getCurrentTitle().prefixedText | |||
== mw.wikibase.getSitelink( suited ) then | |||
r = false | |||
else | |||
r = suited | |||
end | |||
else | |||
r = vsn.value | |||
end | |||
end | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
if | if type( r ) == "nil" then | ||
if not since or since <= | if not since or since <= Failsafe.serial then | ||
r = | r = Failsafe.serial | ||
else | else | ||
r = false | r = false | ||
| Zeile 1.694: | Zeile 1.862: | ||
end | end | ||
return r | return r | ||
end -- | end -- Failsafe.failsafe() | ||
| Zeile 1.730: | Zeile 1.899: | ||
-- Returns string, or not | -- Returns string, or not | ||
if type( adapt ) == "string" then | if type( adapt ) == "string" then | ||
local | local JSONutil = Fetch( "JSONutil", true ) | ||
Data.source = adapt | Data.source = adapt | ||
free() | free() | ||
lucky, Data.got = pcall( mw.text.jsonDecode, Data.source ) | if JSONutil then | ||
if | local Multilingual = Fetch( "Multilingual", true ) | ||
local f | |||
if Multilingual then | |||
f = Multilingual.i18n | |||
end | |||
Data.got = JSONutil.fetch( Data.source, true, f ) | |||
else | |||
local lucky | |||
lucky, Data.got = pcall( mw.text.jsonDecode, Data.source ) | |||
end | |||
if type( Data.got ) == "table" then | |||
full() | full() | ||
elseif not Data.strip then | elseif not Data.strip then | ||
Fault( "fatal JSON error: " .. | local scream = type( Data.got ) | ||
if scream == "string" then | |||
scream = Data.got | |||
else | |||
scream = "Data.got: " .. scream | |||
end | |||
Fault( "fatal JSON error: " .. scream ) | |||
end | end | ||
end | end | ||
| Zeile 1.765: | Zeile 1.950: | ||
end | end | ||
return r | return r | ||
end -- p.f | end -- p.f | ||
p.failsafe = function ( frame ) | p.failsafe = function ( frame ) | ||
| Zeile 1.782: | Zeile 1.967: | ||
end | end | ||
end | end | ||
return | return Failsafe.failsafe( since ) or "" | ||
end -- p.failsafe | end -- p.failsafe | ||
p.TemplateData = function () | p.TemplateData = function () | ||