Module:TemplatePar and Module:TemplatePar/sandbox: Difference between pages
Appearance
(Difference between pages)
Content deleted Content added
update from global upstream version, as requested by the developer; pre-view tested |
mild simplifications, replace quintuple spaces with tabs |
||
Line 1: | Line 1: | ||
--[=[ TemplatePar 2015-02-14 |
|||
suite = "TemplatePar", |
|||
item = 15393417, |
|||
globals = { DateTime = 20652535, |
|||
FileMedia = 24765326, |
|||
Multilingual = 47541920, |
|||
TemplUtl = 52364930, |
|||
URLutil = 10859193 } } |
|||
--[=[ |
|||
Template parameter utility |
Template parameter utility |
||
* assert |
* assert |
||
Line 14: | Line 6: | ||
* countNotEmpty |
* countNotEmpty |
||
* downcase() |
* downcase() |
||
* duplicates |
|||
* match |
* match |
||
* valid |
* valid |
||
* verify() |
* verify() |
||
* TemplatePar() |
* TemplatePar() |
||
* failsafe() |
|||
]=] |
]=] |
||
local Local = { frame = false } |
|||
local Failsafe = TemplatePar |
|||
local GlobalMod = Local |
|||
-- Module globals |
-- Module globals |
||
local TemplatePar = { } |
|||
Local.messagePrefix = "lua-module-TemplatePar-" |
|||
local MessagePrefix = "lua-module-TemplatePar-" |
|||
Local.L10nDef = {} |
|||
local L10nDef = {} |
|||
L10nDef.en = { |
|||
badPattern = "#invoke:TemplatePar pattern syntax error", |
|||
badPattern = "#invoke:TemplatePar pattern syntax error", |
|||
dupOpt = "#invoke:TemplatePar repeated optional parameter", |
|||
dupRule = "#invoke:TemplatePar conflict key/pattern", |
|||
empty = "Error in template * undefined value for mandatory", |
|||
empty = "Error in template * undefined value for mandatory", |
|||
invalid = "Error in template * invalid parameter", |
|||
invalidPar = "#invoke:TemplatePar invalid parameter", |
|||
minmax = "#invoke:TemplatePar min > max", |
|||
missing = "#invoke:TemplatePar missing library", |
|||
multiSpell = "Error in template * multiple spelling of parameter", |
|||
multiSpell = "Error in template * multiple spelling of parameter", |
|||
noMSGnoCAT = "#invoke:TemplatePar neither message nor category", |
|||
noMSGnoCAT = "#invoke:TemplatePar neither message nor category", |
|||
noname = "#invoke:TemplatePar missing parameter name", |
|||
notFound = "Error in template * missing page", |
|||
notFound = "Error in template * missing page", |
|||
tooLong = "Error in template * parameter too long", |
|||
tooShort = "Error in template * parameter too short", |
|||
undefined = "Error in template * mandatory parameter missing", |
|||
unknown = "Error in template * unknown parameter name", |
|||
unknownRule = "#invoke:TemplatePar unknown rule" |
|||
} |
} |
||
L10nDef.de = { |
|||
badPattern = "#invoke:TemplatePar Syntaxfehler des pattern", |
|||
[ "ASCII" ] = "^[ -~]*$", |
|||
dupOpt = "#invoke:TemplatePar Optionsparameter wiederholt", |
|||
[ "ASCII+" ] = "^[ -~]+$", |
|||
dupRule = "#invoke:TemplatePar Konflikt key/pattern", |
|||
[ "ASCII+1" ] = "^[!-~]+$", |
|||
empty = "Fehler bei Vorlage * Pflichtparameter ohne Wert", |
|||
[ "n" ] = "^[%-]?[0-9]*$", |
|||
invalid = "Fehler bei Vorlage * Parameter ungültig", |
|||
[ "n>0" ] = "^[0-9]*[1-9][0-9]*$", |
|||
invalidPar = "#invoke:TemplatePar Ungültiger Parameter", |
|||
[ "N+" ] = "^[%-]?[1-9][0-9]*$", |
|||
minmax = "#invoke:TemplatePar min > max", |
|||
[ "N>0" ] = "^[1-9][0-9]*$", |
|||
multiSpell = "Fehler bei Vorlage * Mehrere Parameter-Schreibweisen", |
|||
[ "x" ] = "^[0-9A-Fa-f]*$", |
|||
noMSGnoCAT = "#invoke:TemplatePar weder Meldung noch Kategorie", |
|||
[ "x+" ] = "^[0-9A-Fa-f]+$", |
|||
noname = "#invoke:TemplatePar Parameter nicht angegeben", |
|||
[ "X" ] = "^[0-9A-F]*$", |
|||
notFound = "Fehler bei Vorlage * Seite fehlt", |
|||
[ "X+" ] = "^[0-9A-F]+$", |
|||
tooLong = "Fehler bei Vorlage * Parameter zu lang", |
|||
[ "0,0" ] = "^[%-]?[0-9]*,?[0-9]*$", |
|||
tooShort = "Fehler bei Vorlage * Parameter zu kurz", |
|||
[ "0,0+" ] = "^[%-]?[0-9]+,[0-9]+$", |
|||
undefined = "Fehler bei Vorlage * Pflichtparameter fehlt", |
|||
[ "0,0+?" ] = "^[%-]?[0-9]+,?[0-9]*$", |
|||
unknown = "Fehler bei Vorlage * Parametername unbekannt", |
|||
[ "0.0" ] = "^[%-]?[0-9]*[%.]?[0-9]*$", |
|||
unknownRule = "#invoke:TemplatePar Unbekannte Regel" |
|||
[ "0.0+" ] = "^[%-]?[0-9]+%.[0-9]+$", |
|||
[ "0.0+?" ] = "^[%-]?[0-9]+[%.]?[0-9]*$", |
|||
[ ".0+" ] = "^[%-]?[0-9]*[%.]?[0-9]+$", |
|||
[ "ID" ] = "^[A-Za-z]?[A-Za-z_0-9]*$", |
|||
[ "ID+" ] = "^[A-Za-z][A-Za-z_0-9]*$", |
|||
[ "ABC" ] = "^[A-Z]*$", |
|||
[ "ABC+" ] = "^[A-Z]+$", |
|||
[ "Abc" ] = "^[A-Z]*[a-z]*$", |
|||
[ "Abc+" ] = "^[A-Z][a-z]+$", |
|||
[ "abc" ] = "^[a-z]*$", |
|||
[ "abc+" ] = "^[a-z]+$", |
|||
[ "aBc+" ] = "^[a-z]+[A-Z][A-Za-z]*$", |
|||
[ "w" ] = "^%S*$", |
|||
[ "w+" ] = "^%S+$", |
|||
[ "base64" ] = "^[A-Za-z0-9%+/]*$", |
|||
[ "base64+" ] = "^[A-Za-z0-9%+/]+$", |
|||
[ "aa" ] = "[%a%a].*[%a%a]", |
|||
[ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%c-%c%c]+$", |
|||
1, 31, 127 ), |
|||
[ "ref" ] = string.format( "%c'%c`UNIQ%s%sref%s%s%sQINU`%c'%c", |
|||
127, 34, "%-", "%-", "%-", "%x+", |
|||
"%-", 34, 127 ), |
|||
[ "+" ] = "%S" |
|||
} |
} |
||
local Patterns = { |
|||
Local.boolean = { ["1"] = true, |
|||
[ "ASCII" ] = "^[ -~]*$", |
|||
["true"] = true, |
|||
[ "ASCII+" ] = "^[ -~]+$", |
|||
y = true, |
|||
[ "ASCII+1" ] = "^[!-~]+$", |
|||
yes = true, |
|||
[ "n" ] = "^[%-]?[0-9]*$", |
|||
on = true, |
|||
[ "n>0" ] = "^[0-9]*[1-9][0-9]*$", |
|||
["0"] = true, |
|||
[ "N+" ] = "^[%-]?[1-9][0-9]*$", |
|||
["false"] = true, |
|||
[ "N>0" ] = "^[1-9][0-9]*$", |
|||
["-"] = true, |
|||
[ "x" ] = "^[0-9A-Fa-f]*$", |
|||
n = true, |
|||
[ "x+" ] = "^[0-9A-Fa-f]+$", |
|||
no = true, |
|||
[ "X" ] = "^[0-9A-F]*$", |
|||
off = true } |
|||
[ "X+" ] = "^[0-9A-F]+$", |
|||
Local.patternCJK = false |
|||
[ "0,0" ] = "^[%-]?[0-9]*,?[0-9]*$", |
|||
[ "0,0+" ] = "^[%-]?[0-9]+,[0-9]+$", |
|||
[ "0,0+?" ] = "^[%-]?[0-9]+,?[0-9]*$", |
|||
[ "0.0" ] = "^[%-]?[0-9]*[%.]?[0-9]*$", |
|||
local foreignModule = function ( access, advanced, append, alt, alert ) |
|||
[ "0.0+" ] = "^[%-]?[0-9]+%.[0-9]+$", |
|||
-- Fetch global module |
|||
[ "0.0+?" ] = "^[%-]?[0-9]+[%.]?[0-9]*$", |
|||
-- Precondition: |
|||
[ ".0+" ] = "^[%-]?[0-9]*[%.]?[0-9]+$", |
|||
-- access -- string, with name of base module |
|||
[ "ID" ] = "^[A-Za-z]?[A-Za-z_0-9]*$", |
|||
-- advanced -- true, for require(); else mw.loadData() |
|||
[ "ID+" ] = "^[A-Za-z][A-Za-z_0-9]*$", |
|||
-- append -- string, with subpage part, if any; or false |
|||
[ "ABC" ] = "^[A-Z]*$", |
|||
-- alt -- number, of wikidata item of root; or false |
|||
[ "ABC+" ] = "^[A-Z]+$", |
|||
-- alert -- true, for throwing error on data problem |
|||
[ "Abc" ] = "^[A-Z]*[a-z]*$", |
|||
-- Postcondition: |
|||
[ "Abc+" ] = "^[A-Z][a-z]+$", |
|||
-- Returns whatever, probably table |
|||
[ "abc" ] = "^[a-z]*$", |
|||
-- 2020-01-01 |
|||
[ "abc+" ] = "^[a-z]+$", |
|||
local storage = access |
|||
[ "aBc+" ] = "^[a-z]+[A-Z][A-Za-z]*$", |
|||
local finer = function () |
|||
[ "w" ] = "^%S*$", |
|||
if append then |
|||
[ "w+" ] = "^%S+$", |
|||
storage = string.format( "%s/%s", |
|||
[ "base64" ] = "^[A-Za-z0-9%+/]*$", |
|||
storage, |
|||
[ "base64+" ] = "^[A-Za-z0-9%+/]+$", |
|||
append ) |
|||
[ "aa" ] = "[%a%a].*[%a%a]", |
|||
end |
|||
[ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%c-%c%c]+$", |
|||
end |
|||
1, 31, 127 ), |
|||
local fun, lucky, r, suited |
|||
[ "+" ] = "%S" |
|||
if advanced then |
|||
} |
|||
fun = require |
|||
local patternCJK = false |
|||
else |
|||
fun = mw.loadData |
|||
end |
|||
GlobalMod.globalModules = GlobalMod.globalModules or { } |
|||
suited = GlobalMod.globalModules[ access ] |
|||
if not suited then |
|||
finer() |
|||
lucky, r = pcall( fun, "Module:" .. storage ) |
|||
end |
|||
if not lucky then |
|||
if not suited and |
|||
type( alt ) == "number" and |
|||
alt > 0 then |
|||
suited = string.format( "Q%d", alt ) |
|||
suited = mw.wikibase.getSitelink( suited ) |
|||
GlobalMod.globalModules[ access ] = suited or true |
|||
end |
|||
if type( suited ) == "string" then |
|||
storage = suited |
|||
finer() |
|||
lucky, r = pcall( fun, storage ) |
|||
end |
|||
if not lucky and alert then |
|||
error( "Missing or invalid page: " .. storage ) |
|||
end |
|||
end |
|||
return r |
|||
end -- foreignModule() |
|||
local function Foreign( access ) |
|||
-- Access standardized library |
|||
-- Precondition: |
|||
-- access -- string, with name of base module |
|||
-- Postcondition: |
|||
-- Return library table, or not |
|||
-- Uses: |
|||
local r |
|||
if Local[ access ] then |
|||
r = Local[ access ] |
|||
else |
|||
local bib = foreignModule( access, |
|||
true, |
|||
false, |
|||
TemplatePar.globals[ access ], |
|||
false ) |
|||
if type( bib ) == "table" and |
|||
type( bib[ access ] ) == "function" then |
|||
bib = bib[ access ]() |
|||
if type( bib ) == "table" then |
|||
r = bib |
|||
Local[ access ] = bib |
|||
end |
|||
end |
|||
end |
|||
return r |
|||
end -- Foreign() |
|||
local function containsCJK( |
local function containsCJK( s ) |
||
-- Is any CJK character present? |
|||
-- Precondition: |
|||
-- s -- string |
|||
-- Postcondition: |
|||
-- Return false iff no CJK present |
|||
-- Uses: |
|||
-- >< patternCJK |
|||
-- mw.ustring.char() |
|||
-- mw.ustring.match() |
|||
local r = false |
|||
patternCJK = patternCJK or mw.ustring.char(91, |
|||
if not Local.patternCJK then |
|||
13312, 45, 40959, |
|||
Local.patternCJK = mw.ustring.char( 91, |
|||
131072, 45, 178207, |
|||
13312, 45, 40959, |
|||
93 ) |
|||
131072, 45, 178207, |
|||
if mw.ustring.match( s, patternCJK ) then |
|||
93 ) |
|||
r = true |
|||
end |
|||
end |
|||
if mw.ustring.match( analyse, Local.patternCJK ) then |
|||
return r |
|||
r = true |
|||
end |
|||
return r |
|||
end -- containsCJK() |
end -- containsCJK() |
||
Line 216: | Line 120: | ||
local function facility( accept, attempt ) |
local function facility( accept, attempt ) |
||
-- Check string as possible file name or other source page |
|||
-- Precondition: |
|||
-- accept -- string; requirement |
|||
-- file |
|||
-- file |
|||
-- file+ |
|||
-- file: |
|||
-- file:+ |
|||
-- image |
|||
-- image+ |
|||
-- image: |
|||
-- image:+ |
|||
-- attempt -- string; to be tested |
|||
-- Postcondition: |
|||
-- Return error keyword, or false |
|||
-- Uses: |
|||
-- Module:FileMedia |
|||
-- FileMedia.isType() |
|||
-- Foreign() |
|||
local r |
|||
-- FileMedia.isFile() |
|||
if attempt and attempt ~= "" then |
|||
-- FileMedia.isType() |
|||
local lucky, FileMedia = pcall( require, "Module:FileMedia" ) |
|||
local r |
|||
if type( FileMedia ) == "table" then |
|||
FileMedia = FileMedia.FileMedia() |
|||
local s, live = accept:match( "^([a-z]+)(:?)%+?$" ) |
|||
if FileMedia and type( FileMedia.isFile ) == "function" |
|||
if live then |
|||
and type( FileMedia.isType ) == "function" then |
|||
if FileMedia.isType( attempt, s ) then |
|||
local s, live = accept:match( "^([a-z]+)(:?)%+?$" ) |
|||
if FileMedia.isFile( attempt ) then |
|||
if live then |
|||
r = false |
|||
if FileMedia.isType( attempt, s ) then |
|||
else |
|||
if FileMedia.isFile( attempt ) then |
|||
r = "notFound" |
|||
r = false |
|||
end |
|||
else |
|||
else |
|||
r = "notFound" |
|||
r = "invalid" |
|||
end |
|||
end |
|||
else |
|||
elseif FileMedia.isType( attempt, s ) then |
|||
r = "invalid" |
|||
r = false |
|||
end |
|||
else |
|||
elseif FileMedia.isType( attempt, s ) then |
|||
r = "invalid" |
|||
r = false |
|||
end |
|||
else |
|||
else |
|||
r = "invalid" |
|||
r = "missing" |
|||
end |
|||
end |
|||
else |
|||
elseif accept:match( "%+$" ) then |
|||
r = "missing" |
|||
r = "empty" |
|||
end |
|||
else |
|||
elseif accept:match( "%+$" ) then |
|||
r = false |
|||
end |
|||
else |
|||
return r |
|||
r = false |
|||
end |
|||
return r |
|||
end -- facility() |
end -- facility() |
||
Line 270: | Line 172: | ||
local function factory( say ) |
local function factory( say ) |
||
-- Retrieve localized message string in content language |
|||
-- Precondition: |
|||
-- say -- string; message ID |
|||
-- Postcondition: |
|||
-- Return some message string |
|||
-- Uses: |
|||
-- > MessagePrefix |
|||
-- > Local.messagePrefix |
|||
-- > L10nDef |
|||
-- mw.language.getContentLanguage() |
|||
-- mw.message.new() |
|||
local c = mw.language.getContentLanguage():getCode() |
|||
-- Module:Multilingual |
|||
local m = mw.message.new( MessagePrefix .. say ) |
|||
-- Foreign() |
|||
local r = false |
|||
-- TemplatePar.framing() |
|||
if m:isBlank() then |
|||
-- Multilingual.tabData() |
|||
local l10n = L10nDef[ c ] or L10nDef[ "en" ] |
|||
local m = mw.message.new( Local.messagePrefix .. say ) |
|||
r = l10n[ say ] |
|||
local r = false |
|||
else |
|||
if m:isBlank() then |
|||
m:inLanguage( c ) |
|||
local c = mw.language.getContentLanguage():getCode() |
|||
r = m:plain() |
|||
local l10n = Local.L10nDef[ c ] |
|||
end |
|||
if l10n then |
|||
r = r or string.format( "(((%s)))", say ) |
|||
return r |
|||
else |
|||
local MultiL = Foreign( "Multilingual" ) |
|||
if MultiL and type( MultiL.tabData ) == "function" then |
|||
local lang |
|||
r, lang = MultiL.tabData( "I18n/Module:TemplatePar", |
|||
say, |
|||
false, |
|||
TemplatePar.framing() ) |
|||
end |
|||
end |
|||
if not r then |
|||
r = Local.L10nDef.en[ say ] |
|||
end |
|||
else |
|||
m:inLanguage( c ) |
|||
r = m:plain() |
|||
end |
|||
if not r then |
|||
r = string.format( "(((%s)))", say ) |
|||
end |
|||
return r |
|||
end -- factory() |
end -- factory() |
||
local function |
local function failsafe( story, scan ) |
||
-- Test for match (possibly user-defined with syntax error) |
|||
-- Check string as possible boolean |
|||
-- Precondition: |
|||
-- story -- string; parameter value |
|||
-- scan -- string; pattern |
|||
-- boolean |
|||
-- Postcondition: |
|||
-- boolean+ |
|||
-- Return nil, if not matching, else non-nil |
|||
-- attempt -- string; to be tested |
|||
-- Uses: |
|||
-- Postcondition: |
|||
-- mw.ustring.match() |
|||
-- Return error keyword, or false |
|||
return mw.ustring.match( story, scan ) |
|||
-- Uses: |
|||
end -- failsafe() |
|||
-- Module:TemplUtl |
|||
-- Foreign() |
|||
-- TemplUtl.faculty() |
|||
local r |
|||
r = mw.text.trim( attempt ):lower() |
|||
if r == "" then |
|||
if accept == "boolean+" then |
|||
r = "empty" |
|||
else |
|||
r = false |
|||
end |
|||
elseif Local.boolean[ r ] or r:match( "^[01%-]+$" ) then |
|||
r = false |
|||
else |
|||
local TemplUtl = Foreign( "TemplUtl" ) |
|||
if TemplUtl and type( TemplUtl.faculty ) == "function" then |
|||
r = TemplUtl.faculty( r, "-" ) |
|||
if r == "-" then |
|||
r = "invalid" |
|||
else |
|||
r = false |
|||
end |
|||
else |
|||
r = "invalid" |
|||
end |
|||
end |
|||
return r |
|||
end -- faculty() |
|||
local function failure( spec, suspect, options ) |
local function failure( spec, suspect, options ) |
||
-- Submit localized error message |
|||
-- Precondition: |
|||
-- spec -- string; message ID |
|||
-- suspect -- string or nil; additional information |
|||
-- options -- table or nil; optional details |
|||
-- options.template |
|||
-- Postcondition: |
|||
-- Return string |
|||
-- Uses: |
|||
-- factory() |
|||
local r = factory( spec ) |
|||
if type( options ) == "table" then |
|||
if type( options.template ) == "string" then |
|||
if #options.template > 0 then |
|||
r = string.format( "%s (%s)", r, options.template ) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
if suspect then |
|||
r = string.format( "%s: %s", r, suspect ) |
|||
end |
|||
return r |
|||
end -- failure() |
end -- failure() |
||
local function fair( story, scan ) |
|||
-- Test for match (possibly user-defined with syntax error) |
|||
-- Precondition: |
|||
-- story -- string; parameter value |
|||
-- scan -- string; pattern |
|||
-- Postcondition: |
|||
-- Return nil, if not matching, else non-nil |
|||
-- Uses: |
|||
-- mw.ustring.match() |
|||
return mw.ustring.match( story, scan ) |
|||
end -- fair() |
|||
local function familiar( accept, attempt ) |
|||
-- Check string as possible language name or list |
|||
-- Precondition: |
|||
-- accept -- string; requirement |
|||
-- lang |
|||
-- langs |
|||
-- langW |
|||
-- langsW |
|||
-- lang+ |
|||
-- langs+ |
|||
-- langW+ |
|||
-- langsW+ |
|||
-- attempt -- string; to be tested |
|||
-- Postcondition: |
|||
-- Return error keyword, or false |
|||
-- Uses: |
|||
-- Module:Multilingual |
|||
-- Foreign() |
|||
-- Multilingual.isLang() |
|||
local r |
|||
if attempt and attempt ~= "" then |
|||
local MultiL = Foreign( "Multilingual" ) |
|||
if MultiL and type( MultiL.isLang ) == "function" then |
|||
local lazy = accept:find( "W", 1, true ) |
|||
if accept:find( "s", 1, true ) then |
|||
local group = mw.text.split( attempt, "%s+" ) |
|||
r = false |
|||
for i = 1, #group do |
|||
if not MultiL.isLang( group[ i ], lazy ) then |
|||
r = "invalid" |
|||
break -- for i |
|||
end |
|||
end -- for i |
|||
elseif MultiL.isLang( attempt, lazy ) then |
|||
r = false |
|||
else |
|||
r = "invalid" |
|||
end |
|||
else |
|||
r = "missing" |
|||
end |
|||
elseif accept:find( "+", 1, true ) then |
|||
r = "empty" |
|||
else |
|||
r = false |
|||
end |
|||
return r |
|||
end -- familiar() |
|||
local function far( accept, attempt ) |
|||
-- Check string as possible URL |
|||
-- Precondition: |
|||
-- accept -- string; requirement |
|||
-- url |
|||
-- url+ |
|||
-- attempt -- string; to be tested |
|||
-- Postcondition: |
|||
-- Return error keyword, or false |
|||
-- Uses: |
|||
-- Module:URLutil |
|||
-- Foreign() |
|||
-- URLutil.isWebURL() |
|||
local r |
|||
if attempt and attempt ~= "" then |
|||
local URLutil = Foreign( "URLutil" ) |
|||
if URLutil and type( URLutil.isWebURL ) == "function" then |
|||
if URLutil.isWebURL( attempt ) then |
|||
r = false |
|||
else |
|||
r = "invalid" |
|||
end |
|||
else |
|||
r = "missing" |
|||
end |
|||
elseif accept:find( "+", 1, true ) then |
|||
r = "empty" |
|||
else |
|||
r = false |
|||
end |
|||
return r |
|||
end -- far() |
|||
local function fast( accept, attempt ) |
|||
-- Check string as possible date or time |
|||
-- Precondition: |
|||
-- accept -- string; requirement |
|||
-- datetime |
|||
-- datetime+ |
|||
-- datetime/y |
|||
-- datetime/y+ |
|||
-- datetime/ym |
|||
-- datetime/ym+ |
|||
-- datetime/ymd |
|||
-- datetime/ymd+ |
|||
-- attempt -- string; to be tested |
|||
-- Postcondition: |
|||
-- Return error keyword, or false |
|||
-- Uses: |
|||
-- Module:DateTime |
|||
-- Foreign() |
|||
-- DateTime.DateTime() |
|||
local r |
|||
r = mw.text.trim( attempt ) |
|||
if r == "" then |
|||
if accept:find( "+", 1, true ) then |
|||
r = "empty" |
|||
else |
|||
r = false |
|||
end |
|||
else |
|||
local DateTime = Foreign( "DateTime" ) |
|||
if type( DateTime ) == "table" then |
|||
local d = DateTime( attempt ) |
|||
if type( d ) == "table" then |
|||
if accept:find( "/", 1, true ) then |
|||
r = "invalid" |
|||
if accept:sub( 1, 10 ) == "datetime/y" then |
|||
if d.year then |
|||
r = false |
|||
if accept:sub( 1, 11 ) == "datetime/ym" then |
|||
if d.month then |
|||
if accept:sub( 1, 12 ) |
|||
== "datetime/ymd" then |
|||
if not d.dom then |
|||
r = "invalid" |
|||
end |
|||
end |
|||
else |
|||
r = "invalid" |
|||
end |
|||
end |
|||
end |
|||
end |
|||
else |
|||
r = false |
|||
end |
|||
else |
|||
r = "invalid" |
|||
end |
|||
else |
|||
r = "invalid" |
|||
end |
|||
end |
|||
return r |
|||
end -- fast() |
|||
local function fault( store, key ) |
local function fault( store, key ) |
||
-- Add key to collection string and insert separator |
|||
-- Precondition: |
|||
-- store -- string or nil or false; collection string |
|||
-- key -- string or number; to be appended |
|||
-- Postcondition: |
|||
-- Return string; extended |
|||
local r |
|||
local s |
|||
if type( key ) == "number" then |
|||
s = tostring( key ) |
|||
else |
|||
s = key |
|||
end |
|||
if store then |
|||
r = string.format( "%s; %s", store, s ) |
|||
else |
|||
r = s |
|||
end |
|||
return r |
|||
end -- fault() |
end -- fault() |
||
Line 575: | Line 264: | ||
local function feasible( analyze, options, abbr ) |
local function feasible( analyze, options, abbr ) |
||
-- Check content of a value |
|||
-- Precondition: |
|||
-- analyze -- string to be analyzed |
|||
-- options -- table or nil; optional details |
|||
-- options.pattern |
|||
-- options.key |
|||
-- options.say |
|||
-- abbr -- true: abbreviated error message |
|||
-- Postcondition: |
|||
-- Return string with error message as configured; |
|||
-- false if valid or no answer permitted |
|||
-- Uses: |
|||
-- > Patterns |
|||
-- failure() |
|||
-- mw.text.trim() |
|||
-- facility() |
|||
-- failsafe() |
|||
-- containsCJK() |
|||
local r = false |
|||
-- familiar() |
|||
local s = false |
|||
-- far() |
|||
local show = nil |
|||
-- fair() |
|||
local scan = false |
|||
-- containsCJK() |
|||
if type( options.pattern ) == "string" then |
|||
local r = false |
|||
if options.key then |
|||
local s = false |
|||
r = failure( "dupRule", false, options ) |
|||
local show = nil |
|||
else |
|||
local scan = false |
|||
scan = options.pattern |
|||
local stuff = mw.text.trim( analyze ) |
|||
end |
|||
if type( options.pattern ) == "string" then |
|||
else |
|||
if options.key then |
|||
if type( options.key ) == "string" then |
|||
r = failure( "dupRule", false, options ) |
|||
s = mw.text.trim( options.key ) |
|||
else |
|||
else |
|||
scan = options.pattern |
|||
s = "+" |
|||
end |
|||
end |
|||
else |
|||
if s ~= "*" then |
|||
scan = Patterns[ s ] |
|||
s = mw.text.trim( options.key ) |
|||
end |
|||
else |
|||
if type( scan ) == "string" then |
|||
s = "+" |
|||
if s == "n" or s == "0,0" or s == "0.0" then |
|||
end |
|||
if not analyze:match( "[0-9]" ) and |
|||
if s ~= "*" then |
|||
not analyze:match( "^%s*$" ) then |
|||
scan = Local.patterns[ s ] |
|||
scan = false |
|||
end |
|||
if options.say then |
|||
if type( scan ) == "string" then |
|||
show = string.format( "'%s'", options.say ) |
|||
if s == "n" or s == "0,0" or s == "0.0" then |
|||
end |
|||
if not stuff:match( "[0-9]" ) and |
|||
if abbr then |
|||
not stuff:match( "^%s*$" ) then |
|||
r = show |
|||
scan = false |
|||
else |
|||
if options.say then |
|||
r = failure( "invalid", show, options ) |
|||
end |
|||
end |
|||
end |
|||
if abbr then |
|||
end |
|||
r = show |
|||
elseif s ~= "*" then |
|||
else |
|||
local op, n, plus = s:match( "([<!=>]=?)([-0-9][%S]*)(+?)" ) |
|||
r = failure( "invalid", show, options ) |
|||
if op then |
|||
end |
|||
n = tonumber( n ) |
|||
end |
|||
if n then |
|||
end |
|||
local i = tonumber( analyze ) |
|||
elseif s ~= "*" then |
|||
if i then |
|||
local op, n, plus = s:match( "([<!=>]=?)([-0-9][%S]*)(+?)" ) |
|||
if op == "<" then |
|||
i = ( i < n ) |
|||
n = tonumber( n ) |
|||
elseif op == "<=" then |
|||
if n then |
|||
i = ( i <= n ) |
|||
local i = tonumber( stuff ) |
|||
elseif op == ">" then |
|||
if i then |
|||
i = ( i > n ) |
|||
if op == "<" then |
|||
elseif op == ">=" then |
|||
i = ( i < n ) |
|||
i = ( i >= n ) |
|||
elseif op == "<=" then |
|||
elseif op == "==" then |
|||
i = ( i <= n ) |
|||
i = ( i == n ) |
|||
elseif op == ">" then |
|||
elseif op == "!=" then |
|||
i = ( i > n ) |
|||
i = ( i ~= n ) |
|||
elseif op == ">=" then |
|||
else |
|||
i = ( i >= n ) |
|||
n = false |
|||
elseif op == "==" then |
|||
end |
|||
i = ( i == n ) |
|||
end |
|||
elseif op == "!=" then |
|||
if not i then |
|||
i = ( i ~= n ) |
|||
r = "invalid" |
|||
else |
|||
end |
|||
n = false |
|||
elseif plus then |
|||
end |
|||
r = "undefined" |
|||
end |
|||
end |
|||
if not i then |
|||
elseif s:match( "^image%+?:?$" ) or |
|||
r = "invalid" |
|||
s:match( "^file%+?:?$" ) then |
|||
end |
|||
r = facility( s, analyze ) |
|||
elseif plus then |
|||
n = true |
|||
r = "undefined" |
|||
elseif s:match( "langW?%+?" ) then |
|||
end |
|||
n = "lang" |
|||
elseif s:match( "^boolean%+?$" ) then |
|||
-- lang lang+ |
|||
r = faculty( s, stuff ) |
|||
-- langW langW+ |
|||
n = true |
|||
end |
|||
elseif s:match( "^datetime/?y?m?d?%+?$" ) then |
|||
if not n and not r then |
|||
r = fast( s, stuff ) |
|||
r = "unknownRule" |
|||
n = true |
|||
end |
|||
elseif s:match( "^image%+?:?$" ) or |
|||
if r then |
|||
s:match( "^file%+?:?$" ) then |
|||
if options.say then |
|||
r = facility( s, stuff ) |
|||
show = string.format( "'%s' %s", options.say, s ) |
|||
n = true |
|||
else |
|||
elseif s:match( "langs?W?%+?" ) then |
|||
show = s |
|||
r = familiar( s, stuff ) |
|||
end |
|||
n = true |
|||
if abbr then |
|||
elseif s:match( "url%+?" ) then |
|||
r = show |
|||
r = far( s, stuff ) |
|||
else |
|||
n = true |
|||
r = failure( r, show, options ) |
|||
end |
|||
end |
|||
-- datetime+ |
|||
end |
|||
-- iso8631+ |
|||
end |
|||
-- line+ |
|||
end |
|||
if not n and not r then |
|||
if scan then |
|||
r = "unknownRule" |
|||
local legal, got = pcall( failsafe, analyze, scan ) |
|||
end |
|||
if legal then |
|||
if not got then |
|||
if options.say then |
|||
if s == "aa" then |
|||
show = string.format( ""%s" %s", options.say, s ) |
|||
got = containsCJK( analyze ) |
|||
else |
|||
end |
|||
show = s |
|||
if not got then |
|||
end |
|||
if options.say then |
|||
show = string.format( "'%s'", options.say ) |
|||
r = show |
|||
end |
|||
else |
|||
if abbr then |
|||
r = failure( r, show, options ) |
|||
r = show |
|||
end |
|||
else |
|||
end |
|||
r = failure( "invalid", show, options ) |
|||
end |
|||
end |
|||
end |
|||
if scan then |
|||
end |
|||
local legal, got = pcall( fair, stuff, scan ) |
|||
else |
|||
if legal then |
|||
r = failure( "badPattern", |
|||
if not got then |
|||
string.format( "%s *** %s", scan, got ), |
|||
if s == "aa" then |
|||
options ) |
|||
got = containsCJK( stuff ) |
|||
end |
|||
end |
|||
end |
|||
if not got then |
|||
return r |
|||
if options.say then |
|||
show = string.format( ""%s"", options.say ) |
|||
end |
|||
if abbr then |
|||
r = show |
|||
else |
|||
r = failure( "invalid", show, options ) |
|||
end |
|||
end |
|||
end |
|||
else |
|||
r = failure( "badPattern", |
|||
string.format( "%s *** %s", scan, got ), |
|||
options ) |
|||
end |
|||
end |
|||
return r |
|||
end -- feasible() |
end -- feasible() |
||
Line 728: | Line 401: | ||
local function fed( haystack, needle ) |
local function fed( haystack, needle ) |
||
-- Find needle in haystack map |
|||
-- Precondition: |
|||
-- haystack -- table; map of key values |
|||
-- needle -- any; identifier |
|||
-- Postcondition: |
|||
-- Return true iff found |
|||
local k, v |
|||
for k, v in pairs( haystack ) do |
|||
if k == needle then |
|||
return true |
|||
end |
|||
end -- for k, v |
|||
return false |
|||
end -- fed() |
end -- fed() |
||
Line 746: | Line 419: | ||
local function fetch( light, options ) |
local function fetch( light, options ) |
||
-- Return regular table with all parameters |
|||
-- Precondition: |
|||
-- light -- true: template transclusion; false: #invoke |
|||
-- options -- table; optional details |
|||
-- options.low |
|||
-- Postcondition: |
|||
-- Return table; whitespace-only values as false |
|||
-- Uses: |
|||
-- TemplatePar.downcase() |
|||
-- mw.getCurrentFrame() |
|||
-- TemplatePar.framing() |
|||
-- frame:getParent() |
|||
local g, k, v |
|||
local r = { } |
|||
if options.low then |
|||
g = TemplatePar.downcase( options ) |
|||
else |
|||
g = mw.getCurrentFrame() |
|||
g = TemplatePar.framing() |
|||
if light then |
|||
g = g:getParent() |
|||
end |
|||
g = g.args |
|||
end |
|||
if type( g ) == "table" then |
|||
r = { } |
|||
for k, v in pairs( g ) do |
|||
if type( v ) == "string" then |
|||
if v:match( "^%s*$" ) then |
|||
v = false |
|||
end |
|||
end |
|||
else |
|||
v = false |
|||
end |
|||
end |
|||
if type( k ) == "number" then |
|||
k = tostring( k ) |
|||
end |
|||
end |
|||
r[ k ] = v |
|||
end -- for k, v |
|||
else |
|||
r = g |
|||
end |
|||
return r |
|||
end -- fetch() |
end -- fetch() |
||
Line 792: | Line 465: | ||
local function figure( append, options ) |
local function figure( append, options ) |
||
-- Extend options by rule from #invoke strings |
|||
-- Precondition: |
|||
-- append -- string or nil; requested rule |
|||
-- options -- table; details |
|||
-- ++ .key |
|||
-- ++ .pattern |
|||
-- Postcondition: |
|||
-- Return sequence table |
|||
local r = options |
|||
if type( append ) == "string" then |
|||
local story = mw.text.trim( append ) |
|||
local sub = story:match( "^/(.*%S)/$" ) |
|||
if type( sub ) == "string" then |
|||
sub = sub:gsub( "%%!", "|" ) |
|||
sub = sub:gsub( "%%%(%(", "{{" ) |
|||
sub = sub:gsub( "%%%)%)", "}}" ) |
|||
options.pattern = sub |
|||
:gsub( "\\n", string.char( 10 ) ) |
|||
options.key = nil |
|||
else |
|||
options.key = nil |
|||
options.key = story |
|||
else |
|||
options.pattern = nil |
|||
end |
|||
options.pattern = nil |
|||
end |
|||
return r |
|||
end |
|||
return r |
|||
end -- figure() |
end -- figure() |
||
Line 822: | Line 494: | ||
local function fill( specified ) |
local function fill( specified ) |
||
-- Split requirement string separated by '=' |
|||
-- Precondition: |
|||
-- specified -- string or nil; requested parameter set |
|||
-- Postcondition: |
|||
-- Return sequence table |
|||
-- Uses: |
|||
-- mw.text.split() |
|||
local r |
|||
if specified then |
|||
local i, s |
|||
r = mw.text.split( specified, "%s*=%s*" ) |
|||
for i = #r, 1, -1 do |
|||
s = r[ i ] |
|||
if #s == 0 then |
|||
table.remove( r, i ) |
|||
end |
|||
end |
|||
end -- for i, -1 |
|||
else |
|||
r = { } |
|||
end |
|||
return r |
|||
end -- fill() |
end -- fill() |
||
local function finalize( submit, options ) |
local function finalize( submit, options, frame ) |
||
-- Finalize message |
|||
-- Precondition: |
|||
-- submit -- string or false or nil; non-empty error message |
|||
-- options -- table or nil; optional details |
|||
-- options.format |
|||
-- options.preview |
|||
-- options.cat |
|||
-- options.template |
|||
-- frame -- object, or false |
|||
-- Postcondition: |
|||
-- Postcondition: |
|||
-- Return string or false |
|||
-- Return string or false |
|||
-- Uses: |
|||
-- Uses: |
|||
-- TemplatePar.framing() |
|||
-- factory() |
|||
local r = false |
|||
if submit then |
|||
local opt, s |
|||
local lazy = false |
|||
local show = false |
|||
if type( options ) == "table" then |
|||
local opt, s |
|||
opt = options |
|||
show = opt.format |
|||
opt = options |
|||
show = |
lazy = ( show == "" or show == "0" or show == "-" ) |
||
s = opt.preview |
|||
lazy = ( show == "" or show == "0" or show == "-" ) |
|||
if type( s ) == "string" and |
|||
s = opt.preview |
|||
s ~= "" and s ~= "0" and s ~= "-" then |
|||
if lazy then |
|||
s ~= "" and s ~= "0" and s ~= "-" then |
|||
show = "" |
|||
local sniffer = "{{REVISIONID}}" |
|||
lazy = false |
|||
if lazy then |
|||
end |
|||
show = "" |
|||
frame = frame or mw.getCurrentFrame() |
|||
lazy = false |
|||
if frame:preprocess( "{{REVISIONID}}" ) == "" then |
|||
end |
|||
if s == "1" then |
|||
if TemplatePar.framing():preprocess( sniffer ) == "" then |
|||
show = "*" |
|||
if s == "1" then |
|||
else |
|||
show = "*" |
|||
show = s |
|||
else |
|||
end |
|||
show = s |
|||
end |
|||
end |
|||
end |
|||
learn = true |
|||
else |
|||
end |
|||
opt = { } |
|||
end |
|||
end |
|||
else |
|||
if lazy then |
|||
opt = { } |
|||
if not opt.cat then |
|||
end |
|||
r = string.format( "%s %s", |
|||
if lazy then |
|||
submit, factory( "noMSGnoCAT" ) ) |
|||
if not opt.cat then |
|||
end |
|||
r = string.format( "%s %s", |
|||
else |
|||
submit, factory( "noMSGnoCAT" ) ) |
|||
r = submit |
|||
end |
|||
end |
|||
else |
|||
if r and not lazy then |
|||
r = submit |
|||
local i |
|||
end |
|||
if not show or show == "*" then |
|||
show = "<span class=\"error\">@@@</span>" |
|||
local i |
|||
end |
|||
if not show or show == "*" then |
|||
i = show:find( "@@@", 1, true ) |
|||
local e = mw.html.create( "span" ) |
|||
if i then |
|||
:attr( "class", "error" ) |
|||
-- No gsub() since r might contain "%3" (e.g. URL) |
|||
:wikitext( "@@@" ) |
|||
r = string.format( "%s%s%s", |
|||
if learn then |
|||
show:sub( 1, i - 1 ), |
|||
local max = 1000000000 |
|||
r, |
|||
local id = math.floor( os.clock() * max ) |
|||
show:sub( i + 3 ) ) |
|||
local sign = string.format( "error_%d", id ) |
|||
else |
|||
local btn = mw.html.create( "span" ) |
|||
r = show |
|||
local top = mw.html.create( "div" ) |
|||
end |
|||
e:attr( "id", sign ) |
|||
end |
|||
btn:css( { ["background"] = "#FFFF00", |
|||
s = opt.cat |
|||
["border"] = "#FF0000 3px solid", |
|||
if type( s ) == "string" then |
|||
["font-weight"] = "bold", |
|||
if opt.errNS then |
|||
["padding"] = "2px", |
|||
local ns = mw.title.getCurrentTitle().namespace |
|||
["text-decoration"] = "none" } ) |
|||
local st = type( opt.errNS ) |
|||
:wikitext( ">>>" ) |
|||
if st == "string" then |
|||
sign = string.format( "[[#%s|%s]]", |
|||
local space = string.format( ".*%%s%d%%s.*", ns ) |
|||
sign, tostring( btn ) ) |
|||
local spaces = string.format( " %s ", opt.errNS ) |
|||
top:wikitext( sign, " ", submit ) |
|||
if spaces:match( space ) then |
|||
mw.addWarning( tostring( top ) ) |
|||
opt.errNS = false |
|||
end |
|||
end |
|||
show = tostring( e ) |
|||
elseif st == "table" then |
|||
end |
|||
for i = 1, #opt.errNS do |
|||
i = show:find( "@@@", 1, true ) |
|||
if opt.errNS[ i ] == ns then |
|||
opt.errNS = false |
|||
-- No gsub() since r might contain "%3" (e.g. URL) |
|||
break -- for i |
|||
r = string.format( "%s%s%s", |
|||
end |
|||
show:sub( 1, i - 1 ), |
|||
end -- for i |
|||
r, |
|||
end |
|||
show:sub( i + 3 ) ) |
|||
end |
|||
else |
|||
if opt.errNS then |
|||
r = show |
|||
r = "" |
|||
end |
|||
else |
|||
end |
|||
r = r or "" |
|||
if learn and r then |
|||
if s:find( "@@@" ) then |
|||
-- r = fatal( r ) |
|||
if type( opt.template ) == "string" then |
|||
end |
|||
s = s:gsub( "@@@", opt.template ) |
|||
end |
|||
if type( s ) == "string" then |
|||
end |
|||
local link |
|||
local i |
|||
if opt.errNS then |
|||
local cats = mw.text.split( s, "%s*#%s*" ) |
|||
local ns = mw.title.getCurrentTitle().namespace |
|||
for i = 1, #cats do |
|||
local st = type( opt.errNS ) |
|||
s = mw.text.trim( cats[ i ] ) |
|||
if st == "string" then |
|||
if #s > 0 then |
|||
local space = string.format( ".*%%s%d%%s.*", ns ) |
|||
r = string.format( "%s[[Category:%s]]", r, s ) |
|||
end |
|||
if spaces:match( space ) then |
|||
end -- for i |
|||
link = true |
|||
end |
|||
end |
|||
end |
|||
elseif st == "table" then |
|||
end |
|||
for i = 1, #opt.errNS do |
|||
return r |
|||
if opt.errNS[ i ] == ns then |
|||
link = true |
|||
break -- for i |
|||
end |
|||
end -- for i |
|||
end |
|||
else |
|||
link = true |
|||
end |
|||
if link then |
|||
local cats, i |
|||
if not r then |
|||
r = "" |
|||
end |
|||
if s:find( "@@@" ) then |
|||
if type( opt.template ) == "string" then |
|||
s = s:gsub( "@@@", opt.template ) |
|||
end |
|||
end |
|||
cats = mw.text.split( s, "%s*#%s*" ) |
|||
for i = 1, #cats do |
|||
s = mw.text.trim( cats[ i ] ) |
|||
if #s > 0 then |
|||
r = string.format( "%s[[Category:%s]]", r, s ) |
|||
end |
|||
end -- for i |
|||
end |
|||
end |
|||
end |
|||
return r |
|||
end -- finalize() |
end -- finalize() |
||
Line 988: | Line 631: | ||
local function finder( haystack, needle ) |
local function finder( haystack, needle ) |
||
-- Find needle in haystack sequence |
|||
-- Precondition: |
|||
-- haystack -- table; sequence of key names, downcased if low |
|||
-- needle -- any; key name |
|||
-- Postcondition: |
|||
-- Return true iff found |
|||
local i |
|||
for i = 1, #haystack do |
|||
if haystack[ i ] == needle then |
|||
return true |
|||
end |
|||
end -- for i |
|||
return false |
|||
end -- finder() |
end -- finder() |
||
Line 1,006: | Line 649: | ||
local function fix( valid, duty, got, options ) |
local function fix( valid, duty, got, options ) |
||
-- Perform parameter analysis |
|||
-- Precondition: |
|||
-- valid -- table; unique sequence of known parameters |
|||
-- duty -- table; sequence of mandatory parameters |
|||
-- got -- table; sequence of current parameters |
|||
-- options -- table or nil; optional details |
|||
-- Postcondition: |
|||
-- Return string as configured; empty if valid |
|||
-- Uses: |
|||
-- finder() |
|||
-- fault() |
|||
-- failure() |
|||
-- fed() |
|||
local k, v |
|||
local r = false |
|||
local lack |
|||
for k, v in pairs( got ) do |
|||
if not finder( valid, k ) then |
|||
r = fault( r, k ) |
|||
lack = true |
|||
end |
|||
break -- for k, v |
|||
end -- for k, v |
|||
elseif not finder( valid, k ) then |
|||
if r then |
|||
r = fault( r, k ) |
|||
r = failure( "unknown", |
|||
end |
|||
string.format( "'%s'", r ), |
|||
end -- for k, v |
|||
options ) |
|||
if lack then |
|||
else -- all names valid |
|||
r = failure( "unavailable", false, options ) |
|||
local i, s |
|||
elseif r then |
|||
for i = 1, #duty do |
|||
r = failure( "unknown", |
|||
s = duty[ i ] |
|||
string.format( ""%s"", r ), |
|||
if not fed( got, s ) then |
|||
options ) |
|||
r = fault( r, s ) |
|||
else -- all names valid |
|||
end |
|||
local i, s |
|||
end -- for i |
|||
if r then |
|||
s = duty[ i ] |
|||
r = failure( "undefined", r, options ) |
|||
if not fed( got, s ) then |
|||
else -- all mandatory present |
|||
r = fault( r, s ) |
|||
for i = 1, #duty do |
|||
end |
|||
s = duty[ i ] |
|||
end -- for i |
|||
if not got[ s ] then |
|||
r = fault( r, s ) |
|||
end |
|||
else -- all mandatory present |
|||
end -- for i |
|||
for i = 1, #duty do |
|||
if r then |
|||
s = duty[ i ] |
|||
r = failure( "empty", r, options ) |
|||
if not got[ s ] then |
|||
end |
|||
r = fault( r, s ) |
|||
end |
|||
end |
|||
end |
|||
end -- for i |
|||
return r |
|||
if r then |
|||
r = failure( "empty", r, options ) |
|||
end |
|||
end |
|||
end |
|||
return r |
|||
end -- fix() |
end -- fix() |
||
Line 1,063: | Line 701: | ||
local function flat( collection, options ) |
local function flat( collection, options ) |
||
-- Return all table elements with downcased string |
|||
-- Precondition: |
|||
-- collection -- table; k=v pairs |
|||
-- options -- table or nil; optional messaging details |
|||
-- Postcondition: |
|||
-- Return table, may be empty; or string with error message. |
|||
-- Uses: |
|||
-- mw.ustring.lower() |
|||
-- fault() |
|||
-- failure() |
|||
local k, v |
|||
local r = { } |
|||
local e = false |
|||
for k, v in pairs( collection ) do |
|||
if type ( k ) == "string" then |
|||
k = mw.ustring.lower( k ) |
|||
if r[ k ] then |
|||
e = fault( e, k ) |
|||
end |
|||
end |
|||
end |
|||
r[ k ] = v |
|||
end -- for k, v |
|||
if e then |
|||
r = failure( "multiSpell", e, options ) |
|||
end |
|||
return r |
|||
end -- flat() |
end -- flat() |
||
Line 1,094: | Line 732: | ||
local function fold( options ) |
local function fold( options ) |
||
-- Merge two tables, create new sequence if both not empty |
|||
-- Precondition: |
|||
-- options -- table; details |
|||
-- options.mandatory sequence to keep unchanged |
|||
-- options.optional sequence to be appended |
|||
-- options.low downcased expected |
|||
-- Postcondition: |
|||
-- Return merged table, or message string if error |
|||
-- Uses: |
|||
-- finder() |
|||
-- fault() |
|||
-- failure() |
|||
-- flat() |
|||
local i, e, r, s |
|||
local base = options.mandatory |
|||
local extend = options.optional |
|||
if #base == 0 then |
|||
if #extend == 0 then |
|||
r = { } |
|||
else |
|||
r = extend |
|||
end |
|||
else |
|||
if #extend == 0 then |
|||
r = base |
|||
else |
|||
e = false |
|||
for i = 1, #extend do |
|||
s = extend[ i ] |
|||
if finder( base, s ) then |
|||
e = fault( e, s ) |
|||
end |
|||
end |
|||
end -- for i |
|||
if e then |
|||
r = failure( "dupOpt", e, options ) |
|||
else |
|||
r = { } |
|||
for i = 1, #base do |
|||
table.insert( r, base[ i ] ) |
|||
end -- for i |
|||
for i = 1, #extend do |
|||
table.insert( r, extend[ i ] ) |
|||
end -- for i |
|||
end |
|||
end |
|||
end |
|||
end |
|||
if options.low and type( r ) == "table" then |
|||
r = flat( r, options ) |
|||
end |
|||
return r |
|||
end -- fold() |
end -- fold() |
||
Line 1,149: | Line 787: | ||
local function form( light, options, frame ) |
local function form( light, options, frame ) |
||
-- Run parameter analysis on current environment |
|||
-- Precondition: |
|||
-- light -- true: template transclusion; false: #invoke |
|||
-- options -- table or nil; optional details |
|||
-- options.mandatory |
|||
-- options.optional |
|||
-- frame -- object, or false |
|||
-- Postcondition: |
|||
-- Return string with error message as configured; |
|||
-- false if valid |
|||
-- Uses: |
|||
-- fold() |
|||
-- TemplatePar.framing() |
|||
-- fetch() |
|||
-- fix() |
|||
-- finalize() |
|||
local duty, r |
|||
-- finalize() |
|||
if type( options ) == "table" then |
|||
local duty, r |
|||
if type( options.mandatory ) ~= "table" then |
|||
options.mandatory = { } |
|||
TemplatePar.framing( frame ) |
|||
end |
|||
duty = options.mandatory |
|||
if type( options.optional ) ~= "table" then |
|||
options.optional = { } |
|||
end |
|||
r = fold( options ) |
|||
duty = options.mandatory |
|||
else |
|||
if type( options.optional ) ~= "table" then |
|||
options = { } |
|||
duty = { } |
|||
end |
|||
r = { } |
|||
r = fold( options ) |
|||
end |
|||
else |
|||
if type( r ) == "table" then |
|||
options = { } |
|||
local got = fetch( light, options ) |
|||
duty = { } |
|||
if type( got ) == "table" then |
|||
r = { } |
|||
r = fix( r, duty, got, options ) |
|||
end |
|||
else |
|||
if type( r ) == "table" then |
|||
r = got |
|||
local got = fetch( light, options ) |
|||
end |
|||
if type( got ) == "table" then |
|||
end |
|||
r = fix( r, duty, got, options ) |
|||
return finalize( r, options, frame ) |
|||
else |
|||
r = got |
|||
end |
|||
end |
|||
return finalize( r, options ) |
|||
end -- form() |
end -- form() |
||
Line 1,197: | Line 831: | ||
local function format( analyze, options ) |
local function format( analyze, options ) |
||
-- Check validity of a value |
|||
-- Precondition: |
|||
-- analyze -- string to be analyzed |
|||
-- options -- table or nil; optional details |
|||
-- options.say |
|||
-- options.min |
|||
-- options.max |
|||
-- Postcondition: |
|||
-- Return string with error message as configured; |
|||
-- false if valid or no answer permitted |
|||
-- Uses: |
|||
-- feasible() |
|||
-- failure() |
|||
local r = feasible( analyze, options, false ) |
|||
local show |
|||
if options.min and not r then |
|||
if type( options.min ) == "number" then |
|||
if type( options.max ) == "number" then |
|||
if options.max < options.min then |
|||
r = failure( "minmax", |
|||
string.format( "%d > %d", |
|||
options.min, |
|||
options.min, |
|||
options.max ), |
|||
options ) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
if #analyze < options.min and not r then |
|||
show = " <" .. options.min |
|||
if options.say then |
|||
show = string.format( "%s '%s'", show, options.say ) |
|||
end |
|||
end |
|||
r = failure( "tooShort", show, options ) |
|||
end |
|||
end |
|||
else |
|||
r = failure( "invalidPar", "min", options ) |
|||
end |
|||
end |
|||
if options.max and not r then |
|||
if type( options.max ) == "number" then |
|||
if #analyze > options.max then |
|||
show = " >" .. options.max |
|||
if options.say then |
|||
show = string.format( "%s '%s'", show, options.say ) |
|||
end |
|||
end |
|||
r = failure( "tooLong", show, options ) |
|||
end |
|||
end |
|||
else |
|||
r = failure( "invalidPar", "max", options ) |
|||
end |
|||
end |
|||
return r |
|||
end -- format() |
end -- format() |
||
Line 1,253: | Line 887: | ||
local function formatted( assignment, access, options ) |
local function formatted( assignment, access, options ) |
||
-- Check validity of one particular parameter in a collection |
|||
-- Precondition: |
|||
-- assignment -- collection |
|||
-- access -- id of parameter in collection |
|||
-- options -- table or nil; optional details |
|||
-- Postcondition: |
|||
-- Return string with error message as configured; |
|||
-- false if valid or no answer permitted |
|||
-- Uses: |
|||
-- mw.text.trim() |
|||
-- format() |
|||
-- failure() |
|||
local r = false |
|||
if type( assignment ) == "table" then |
|||
local story = assignment.args[ access ] or "" |
|||
if type( access ) == "number" then |
|||
story = mw.text.trim( story ) |
|||
end |
|||
if type( options ) ~= "table" then |
|||
options = { } |
|||
end |
|||
options.say = access |
|||
r = format( story, options ) |
|||
end |
|||
return r |
|||
end -- formatted() |
end -- formatted() |
||
Line 1,283: | Line 917: | ||
local function furnish( frame, action ) |
local function furnish( frame, action ) |
||
-- Prepare #invoke evaluation of .assert() or .valid() |
|||
-- Precondition: |
|||
-- frame -- object; #invoke environment |
|||
-- action -- "assert" or "valid" |
|||
-- Postcondition: |
|||
-- Return string with error message or "" |
|||
-- Uses: |
|||
-- form() |
|||
-- failure() |
|||
-- finalize() |
|||
-- TemplatePar.valid() |
|||
-- TemplatePar.assert() |
|||
local options = { mandatory = { "1" }, |
|||
optional = { "2", |
|||
"cat", |
|||
"cat", |
|||
"errNS", |
|||
"errNS", |
|||
"low", |
|||
"low", |
|||
"max", |
|||
"max", |
|||
"min", |
|||
"min", |
|||
"format", |
|||
"format", |
|||
"preview", |
|||
"template" }, |
|||
template = string.format( "#invoke:%s|%s|", |
|||
"TemplatePar", |
|||
action ) |
|||
action ) |
|||
} |
|||
} |
|||
local r = form( false, options, frame ) |
|||
if not r then |
|||
local s |
|||
options = { cat = frame.args.cat, |
|||
errNS = frame.args.errNS, |
|||
low = frame.args.low, |
|||
format = frame.args.format, |
|||
preview = frame.args.preview, |
|||
template = frame.args.template |
|||
} |
|||
} |
|||
options = figure( frame.args[ 2 ], options ) |
|||
if type( frame.args.min ) == "string" then |
|||
s = frame.args.min:match( "^%s*([0-9]+)%s*$" ) |
|||
if s then |
|||
options.min = tonumber( s ) |
|||
else |
|||
r = failure( "invalidPar", |
|||
"min=" .. frame.args.min, |
|||
options ) |
|||
end |
|||
end |
|||
end |
|||
if type( frame.args.max ) == "string" then |
|||
s = frame.args.max:match( "^%s*([1-9][0-9]*)%s*$" ) |
|||
if s then |
|||
options.max = tonumber( s ) |
|||
else |
|||
r = failure( "invalidPar", |
|||
"max=" .. frame.args.max, |
|||
options ) |
|||
end |
|||
end |
|||
end |
|||
if r then |
|||
r = finalize( r, options, frame ) |
|||
else |
|||
s = frame.args[ 1 ] or "" |
|||
r = tonumber( s ) |
|||
if ( r ) then |
|||
s = r |
|||
end |
|||
end |
|||
if action == "valid" then |
|||
r = TemplatePar.valid( s, options, frame ) |
|||
elseif action == "assert" then |
|||
r = TemplatePar.assert( s, "", options ) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
return r or "" |
|||
end -- furnish() |
end -- furnish() |
||
Line 1,361: | Line 995: | ||
TemplatePar.assert = function ( analyze, append, options ) |
TemplatePar.assert = function ( analyze, append, options ) |
||
-- Perform parameter analysis on a single string |
|||
-- Precondition: |
|||
-- analyze -- string to be analyzed |
|||
-- append -- string: append error message, prepending <br /> |
|||
-- false or nil: throw error with message |
|||
-- options -- table; optional details |
|||
-- Postcondition: |
|||
-- Return string with error message as configured; |
|||
-- false if valid |
|||
-- Uses: |
|||
-- format() |
|||
local r = format( analyze, options ) |
|||
if ( r ) then |
|||
if ( type( append ) == "string" ) then |
|||
if ( append ~= "" ) then |
|||
r = string.format( "%s<br />%s", append, r ) |
|||
end |
|||
end |
|||
else |
|||
error( r, 0 ) |
|||
end |
|||
end |
|||
return r |
|||
end -- TemplatePar.assert() |
end -- TemplatePar.assert() |
||
Line 1,388: | Line 1,022: | ||
TemplatePar.check = function ( options ) |
TemplatePar.check = function ( options ) |
||
-- Run parameter analysis on current template environment |
|||
-- Precondition: |
|||
-- options -- table or nil; optional details |
|||
-- options.mandatory |
|||
-- options.optional |
|||
-- Postcondition: |
|||
-- Return string with error message as configured; |
|||
-- false if valid |
|||
-- Uses: |
|||
-- form() |
|||
return form( true, options, false ) |
|||
end -- TemplatePar.check() |
end -- TemplatePar.check() |
||
Line 1,404: | Line 1,038: | ||
TemplatePar.count = function () |
TemplatePar.count = function () |
||
-- Return number of template parameters |
|||
-- Postcondition: |
|||
-- Return number, starting at 0 |
|||
-- Uses: |
|||
-- mw.getCurrentFrame() |
|||
-- frame:getParent() |
|||
local k, v |
|||
local r = 0 |
|||
local t = mw.getCurrentFrame():getParent() |
|||
local o = t.args |
|||
for k, v in pairs( o ) do |
|||
r = r + 1 |
|||
end -- for k, v |
|||
return r |
|||
end -- TemplatePar.count() |
end -- TemplatePar.count() |
||
Line 1,423: | Line 1,057: | ||
TemplatePar.countNotEmpty = function () |
TemplatePar.countNotEmpty = function () |
||
-- Return number of template parameters with more than whitespace |
|||
-- Postcondition: |
|||
-- Return number, starting at 0 |
|||
-- Uses: |
|||
-- mw.getCurrentFrame() |
|||
-- frame:getParent() |
|||
local k, v |
|||
local r = 0 |
|||
local t = mw.getCurrentFrame():getParent() |
|||
local o = t.args |
|||
for k, v in pairs( o ) do |
|||
if not v:match( "^%s*$" ) then |
|||
r = r + 1 |
|||
end |
|||
end -- for k, v |
|||
return r |
|||
end -- TemplatePar.countNotEmpty() |
end -- TemplatePar.countNotEmpty() |
||
Line 1,444: | Line 1,078: | ||
TemplatePar.downcase = function ( options ) |
TemplatePar.downcase = function ( options ) |
||
-- Return all template parameters with downcased name |
|||
-- Precondition: |
|||
-- options -- table or nil; optional messaging details |
|||
-- Postcondition: |
|||
-- Return table, may be empty; or string with error message. |
|||
-- Uses: |
|||
-- mw.getCurrentFrame() |
|||
-- frame:getParent() |
|||
-- flat() |
|||
local t = mw.getCurrentFrame():getParent() |
|||
return flat( t.args, options ) |
|||
end -- TemplatePar.downcase() |
end -- TemplatePar.downcase() |
||
TemplatePar.valid = function ( access, options ) |
TemplatePar.valid = function ( access, options, frame ) |
||
-- Check validity of one particular template parameter |
|||
-- Precondition: |
|||
-- access -- id of parameter in template transclusion |
|||
-- string or number |
|||
-- options -- table or nil; optional details |
|||
-- frame -- object; #invoke environment |
|||
-- Postcondition: |
|||
-- Postcondition: |
|||
-- Return string with error message as configured; |
|||
-- Return string with error message as configured; |
|||
-- false if valid or no answer permitted |
|||
-- false if valid or no answer permitted |
|||
-- Uses: |
|||
-- Uses: |
|||
-- mw.text.trim() |
|||
-- mw.text.trim() |
|||
-- TemplatePar.downcase() |
|||
-- TemplatePar.downcase() |
|||
-- frame:getParent() |
|||
-- formatted() |
|||
-- failure() |
|||
-- finalize() |
|||
local r = type( access ) |
|||
if r == "string" then |
|||
r = mw.text.trim( access ) |
|||
if #r == 0 then |
|||
r = false |
|||
end |
|||
elseif r == "number" then |
|||
r = access |
|||
else |
|||
r = false |
|||
end |
|||
if r then |
|||
local params |
|||
if type( options ) ~= "table" then |
|||
options = { } |
|||
end |
|||
if options.low then |
|||
params = TemplatePar.downcase( options ) |
|||
else |
|||
params = frame:getParent() |
|||
end |
|||
r = formatted( params, access, options ) |
|||
else |
|||
r = failure( "noname", false, options ) |
|||
end |
|||
return finalize( r, options, frame ) |
|||
end -- TemplatePar.valid() |
end -- TemplatePar.valid() |
||
Line 1,507: | Line 1,141: | ||
TemplatePar.verify = function ( options ) |
TemplatePar.verify = function ( options ) |
||
-- Perform #invoke parameter analysis |
|||
-- Precondition: |
|||
-- options -- table or nil; optional details |
|||
-- Postcondition: |
|||
-- Return string with error message as configured; |
|||
-- false if valid |
|||
-- Uses: |
|||
-- form() |
|||
return form( false, options, false ) |
|||
end -- TemplatePar.verify() |
end -- TemplatePar.verify() |
||
TemplatePar.framing = function( frame ) |
|||
-- Ensure availability of frame object |
|||
-- Precondition: |
|||
-- frame -- object; #invoke environment, or false |
|||
-- Postcondition: |
|||
-- Return frame object |
|||
-- Uses: |
|||
-- >< Local.frame |
|||
if not Local.frame then |
|||
if type( frame ) == "table" and |
|||
type( frame.args ) == "table" and |
|||
type( frame.getParent ) == "function" and |
|||
type( frame:getParent() ) == "table" and |
|||
type( frame:getParent().getParent ) == "function" and |
|||
type( frame:getParent():getParent() ) == "nil" then |
|||
Local.frame = frame |
|||
else |
|||
Local.frame = mw.getCurrentFrame() |
|||
end |
|||
end |
|||
return Local.frame |
|||
end -- TemplatePar.framing() |
|||
Failsafe.failsafe = function ( atleast ) |
|||
-- Retrieve versioning and check for compliance |
|||
-- Precondition: |
|||
-- atleast -- string, with required version |
|||
-- or wikidata|item|~|@ or false |
|||
-- Postcondition: |
|||
-- Returns string -- with queried version/item, also if problem |
|||
-- false -- if appropriate |
|||
-- 2020-08-17 |
|||
local since = atleast |
|||
local last = ( since == "~" ) |
|||
local linked = ( since == "@" ) |
|||
local link = ( since == "item" ) |
|||
local r |
|||
if last or link or linked or since == "wikidata" then |
|||
local item = Failsafe.item |
|||
since = false |
|||
if type( item ) == "number" and item > 0 then |
|||
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 |
|||
if type( r ) == "nil" then |
|||
if not since or since <= Failsafe.serial then |
|||
r = Failsafe.serial |
|||
else |
|||
r = false |
|||
end |
|||
end |
|||
return r |
|||
end -- Failsafe.failsafe() |
|||
Line 1,609: | Line 1,160: | ||
function p.assert( frame ) |
function p.assert( frame ) |
||
-- Perform parameter analysis on some single string |
|||
-- Precondition: |
|||
-- frame -- object; #invoke environment |
|||
-- Postcondition: |
|||
-- Return string with error message or "" |
|||
-- Uses: |
|||
-- furnish() |
|||
return furnish( frame, "assert" ) |
|||
end -- |
end -- .assert() |
||
function p.check( frame ) |
function p.check( frame ) |
||
-- Check validity of template parameters |
|||
-- Precondition: |
|||
-- frame -- object; #invoke environment |
|||
-- Postcondition: |
|||
-- Return string with error message or "" |
|||
-- Uses: |
|||
-- form() |
|||
-- fill() |
|||
local options = { optional = { "all", |
|||
"opt", |
|||
"opt", |
|||
"cat", |
|||
"cat", |
|||
"errNS", |
|||
"errNS", |
|||
"low", |
|||
"low", |
|||
"format", |
|||
"format", |
|||
"preview", |
|||
"template" }, |
|||
template = "#invoke:TemplatePar|check|" |
|||
} |
|||
} |
|||
local r = form( false, options, frame ) |
|||
if not r then |
|||
options = { mandatory = fill( frame.args.all ), |
|||
optional = fill( frame.args.opt ), |
|||
cat = frame.args.cat, |
|||
errNS = frame.args.errNS, |
|||
low = frame.args.low, |
|||
format = frame.args.format, |
|||
preview = frame.args.preview, |
|||
template = frame.args.template |
|||
} |
|||
} |
|||
r = form( true, options, frame ) |
|||
end |
|||
return r or "" |
|||
end -- |
end -- .check() |
||
function p.count( frame ) |
function p.count( frame ) |
||
-- Count number of template parameters |
|||
-- Postcondition: |
|||
-- Return string with digits including "0" |
|||
-- Uses: |
|||
-- TemplatePar.count() |
|||
return tostring( TemplatePar.count() ) |
|||
end -- |
end -- .count() |
||
function p.countNotEmpty( frame ) |
function p.countNotEmpty( frame ) |
||
-- Count number of template parameters which are not empty |
|||
-- Postcondition: |
|||
-- Return string with digits including "0" |
|||
-- Uses: |
|||
-- TemplatePar.countNotEmpty() |
|||
return tostring( TemplatePar.countNotEmpty() ) |
|||
end -- |
end -- .countNotEmpty() |
||
function p.match( frame ) |
function p.match( frame ) |
||
-- Combined analysis of parameters and their values |
|||
-- Postcondition: |
|||
-- Precondition: |
|||
-- Return string with error message or "" |
|||
-- frame -- object; #invoke environment |
|||
-- Uses: |
|||
-- Postcondition: |
|||
-- mw.text.trim() |
|||
-- Return string with error message or "" |
|||
-- mw.ustring.lower() |
|||
-- Uses: |
|||
-- failure() |
|||
-- TemplatePar.framing() |
|||
-- form() |
|||
-- mw.text.trim() |
|||
-- TemplatePar.downcase() |
|||
-- mw.ustring.lower() |
|||
-- figure() |
|||
-- feasible() |
|||
-- fault() |
|||
-- TemplatePar.downcase() |
|||
-- finalize() |
|||
local r = false |
|||
-- feasible() |
|||
local options = { cat = frame.args.cat, |
|||
-- fault() |
|||
errNS = frame.args.errNS, |
|||
-- finalize() |
|||
low = frame.args.low, |
|||
local r = false |
|||
format = frame.args.format, |
|||
preview = frame.args.preview, |
|||
template = frame.args.template |
|||
} |
|||
format = frame.args.format, |
|||
local k, v, s |
|||
preview = frame.args.preview, |
|||
local params = { } |
|||
template = frame.args.template |
|||
for k, v in pairs( frame.args ) do |
|||
} |
|||
if type( k ) == "number" then |
|||
local k, v, s |
|||
s, v = v:match( "^ *([^=]+) *= *(%S.*%S*) *$" ) |
|||
local params = { } |
|||
if s then |
|||
TemplatePar.framing( frame ) |
|||
s = mw.text.trim( s ) |
|||
for k, v in pairs( frame.args ) do |
|||
if s == "" then |
|||
s = false |
|||
s, v = v:match( "^ *([^=]+) *= *(%S.*%S*) *$" ) |
|||
end |
|||
if s then |
|||
end |
|||
s = mw.text.trim( s ) |
|||
if s then |
|||
if options.low then |
|||
s = false |
|||
s = mw.ustring.lower( s ) |
|||
end |
|||
end |
|||
end |
|||
if params[ s ] then |
|||
s = params[ s ] |
|||
if options.low then |
|||
s[ #s + 1 ] = v |
|||
s = mw.ustring.lower( s ) |
|||
else |
|||
end |
|||
params[ s ] = { v } |
|||
end |
|||
s = params[ s ] |
|||
else |
|||
s[ #s + 1 ] = v |
|||
r = failure( "invalidPar", tostring( k ), options ) |
|||
else |
|||
break -- for k, v |
|||
params[ s ] = { v } |
|||
end |
|||
end |
|||
end |
|||
else |
|||
end -- for k, v |
|||
r = failure( "invalidPar", tostring( k ), options ) |
|||
if not r then |
|||
break -- for k, v |
|||
s = { } |
|||
end |
|||
for k, v in pairs( params ) do |
|||
s[ #s + 1 ] = k |
|||
end -- for k, v |
|||
if not r then |
|||
options.optional = s |
|||
s = { } |
|||
r = form( true, options, frame ) |
|||
for k, v in pairs( params ) do |
|||
end |
|||
s[ #s + 1 ] = k |
|||
if not r then |
|||
end -- for k, v |
|||
local errMiss, errValues, lack, rule |
|||
options.optional = s |
|||
local targs = frame:getParent().args |
|||
r = form( true, options, frame ) |
|||
options.optional = nil |
|||
end |
|||
if options.low then |
|||
targs = TemplatePar.downcase() |
|||
local errMiss, errValues, lack, rule |
|||
else |
|||
local targs = frame:getParent().args |
|||
targs = frame:getParent().args |
|||
options.optional = nil |
|||
end |
|||
if options.low then |
|||
errMiss = false |
|||
targs = TemplatePar.downcase() |
|||
errValues = false |
|||
else |
|||
for k, v in pairs( params ) do |
|||
targs = frame:getParent().args |
|||
options.say = k |
|||
end |
|||
errValue = false |
|||
s = targs[ k ] |
|||
errValues = false |
|||
if s then |
|||
for k, v in pairs( params ) do |
|||
if s == "" then |
|||
options.say = k |
|||
lack = true |
|||
s = targs[ k ] |
|||
else |
|||
if s then |
|||
lack = false |
|||
if s == "" then |
|||
end |
|||
lack = true |
|||
else |
|||
else |
|||
s = "" |
|||
lack = false |
|||
lack = true |
|||
end |
|||
end |
|||
else |
|||
for r, rule in pairs( v ) do |
|||
s = "" |
|||
options = figure( rule, options ) |
|||
lack = true |
|||
r = feasible( s, options, true ) |
|||
end |
|||
if r then |
|||
for r, rule in pairs( v ) do |
|||
if lack then |
|||
options = figure( rule, options ) |
|||
if errMiss then |
|||
r = feasible( s, options, true ) |
|||
errMiss = string.format( "%s, '%s'", |
|||
if r then |
|||
errMiss, k ) |
|||
if lack then |
|||
else |
|||
if errMiss then |
|||
errMiss = string.format( "'%s'", k ) |
|||
s = "%s, "%s"" |
|||
end |
|||
errMiss = string.format( s, errMiss, k ) |
|||
elseif not errMiss then |
|||
else |
|||
errValues = fault( errValues, r ) |
|||
errMiss = string.format( ""%s"", |
|||
end |
|||
k ) |
|||
break -- for r, rule |
|||
end |
|||
end |
|||
elseif not errMiss then |
|||
end -- for s, rule |
|||
errValues = fault( errValues, r ) |
|||
end -- for k, v |
|||
end |
|||
r = ( errMiss or errValues ) |
|||
break -- for r, rule |
|||
if r then |
|||
end |
|||
if errMiss then |
|||
end -- for s, rule |
|||
r = failure( "undefined", errMiss, options ) |
|||
end -- for k, v |
|||
else |
|||
r = ( errMiss or errValues ) |
|||
r = failure( "invalid", errValues, options ) |
|||
if r then |
|||
end |
|||
if errMiss then |
|||
r = finalize( r, options, frame ) |
|||
r = failure( "undefined", errMiss, options ) |
|||
end |
|||
else |
|||
end |
|||
r = failure( "invalid", errValues, options ) |
|||
return r or "" |
|||
end |
|||
end -- .match() |
|||
r = finalize( r, options ) |
|||
end |
|||
end |
|||
return r or "" |
|||
end -- p.match() |
|||
function p.valid( frame ) |
function p.valid( frame ) |
||
-- Check validity of one particular template parameter |
|||
-- Precondition: |
|||
-- frame -- object; #invoke environment |
|||
-- Postcondition: |
|||
-- Return string with error message or "" |
|||
-- Uses: |
|||
-- furnish() |
|||
return furnish( frame, "valid" ) |
|||
end -- |
end -- .valid() |
||
p.failsafe = function ( frame ) |
|||
-- Versioning interface |
|||
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 Failsafe.failsafe( since ) or "" |
|||
end -- p.failsafe |
|||
function p.TemplatePar() |
function p.TemplatePar() |
||
-- Retrieve function access for modules |
|||
-- Postcondition: |
|||
-- Return table with functions |
|||
return TemplatePar |
|||
end -- |
end -- .TemplatePar() |
||
setmetatable( p, { __call = function ( func, ... ) |
|||
setmetatable( p, nil ) |
|||
return Failsafe |
|||
end } ) |
|||
return p |
return p |