「モジュール:TemplatePar」の版間の差分

update from global upstream version, as requested by the developer; pre-view tested
(1版)
 
bsd>Leyo
(update from global upstream version, as requested by the developer; pre-view tested)
1行目: 1行目:
--[=[ TemplatePar 2015-02-14
local TemplatePar = { serial  = "2023-03-20",
                      suite  = "TemplatePar",
                      item    = 15393417,
                      globals = { DateTime    = 20652535,
                                  FileMedia    = 24765326,
                                  Multilingual = 47541920,
                                  TemplUtl    = 52364930,
                                  URLutil      = 10859193 } }
--[=[
Template parameter utility
Template parameter utility
* assert
* assert
6行目: 14行目:
* 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 = {}
Local.L10nDef.en = {
L10nDef.en = {
     badPattern  = "#invoke:TemplatePar pattern syntax error",
     badPattern  = "#invoke:TemplatePar pattern syntax error",
     dupOpt      = "#invoke:TemplatePar repeated optional parameter",
     dupOpt      = "#invoke:TemplatePar repeated optional parameter",
33行目: 47行目:
     tooLong    = "Error in template * parameter too long",
     tooLong    = "Error in template * parameter too long",
     tooShort    = "Error in template * parameter too short",
     tooShort    = "Error in template * parameter too short",
    unavailable = "Error in template * parameter name missing",
     undefined  = "Error in template * mandatory parameter missing",
     undefined  = "Error in template * mandatory parameter missing",
     unknown    = "Error in template * unknown parameter name",
     unknown    = "Error in template * unknown parameter name",
     unknownRule = "#invoke:TemplatePar unknown rule"
     unknownRule = "#invoke:TemplatePar unknown rule"
}
}
L10nDef.de  = {
Local.patterns = {
    badPattern  = "#invoke:TemplatePar Syntaxfehler des pattern",
    dupOpt      = "#invoke:TemplatePar Optionsparameter wiederholt",
    dupRule    = "#invoke:TemplatePar Konflikt key/pattern",
    empty      = "Fehler bei Vorlage * Pflichtparameter ohne Wert",
    invalid    = "Fehler bei Vorlage * Parameter ungültig",
    invalidPar  = "#invoke:TemplatePar Ungültiger Parameter",
    minmax      = "#invoke:TemplatePar min > max",
    multiSpell  = "Fehler bei Vorlage * Mehrere Parameter-Schreibweisen",
    noMSGnoCAT  = "#invoke:TemplatePar weder Meldung noch Kategorie",
    noname      = "#invoke:TemplatePar Parameter nicht angegeben",
    notFound    = "Fehler bei Vorlage * Seite fehlt",
    tooLong    = "Fehler bei Vorlage * Parameter zu lang",
    tooShort    = "Fehler bei Vorlage * Parameter zu kurz",
    undefined  = "Fehler bei Vorlage * Pflichtparameter fehlt",
    unknown    = "Fehler bei Vorlage * Parametername unbekannt",
    unknownRule = "#invoke:TemplatePar Unbekannte Regel"
}
local Patterns = {
     [ "ASCII" ]    = "^[ -~]*$",
     [ "ASCII" ]    = "^[ -~]*$",
     [ "ASCII+" ]  = "^[ -~]+$",
     [ "ASCII+" ]  = "^[ -~]+$",
90行目: 87行目:
     [ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%c-%c%c]+$",
     [ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%c-%c%c]+$",
                                     1, 31, 127 ),
                                     1, 31, 127 ),
    [ "ref" ]      = string.format( "%c'%c`UNIQ%s%sref%s%s%sQINU`%c'%c",
                                    127, 34, "%-", "%-", "%-", "%x+",
                                    "%-", 34, 127 ),
     [ "+" ]        = "%S"
     [ "+" ]        = "%S"
}
}
local patternCJK = false
Local.boolean = { ["1"]    = true,
                  ["true"]  = true,
                  y        = true,
                  yes      = true,
                  on        = true,
                  ["0"]    = true,
                  ["false"] = true,
                  ["-"]    = true,
                  n        = true,
                  no        = true,
                  off      = true }
Local.patternCJK = false
 
 
 
local foreignModule = function ( access, advanced, append, alt, alert )
    -- Fetch global module
    -- Precondition:
    --    access    -- string, with name of base module
    --    advanced  -- true, for require(); else mw.loadData()
    --    append    -- string, with subpage part, if any; or false
    --    alt      -- number, of wikidata item of root; or false
    --    alert    -- true, for throwing error on data problem
    -- Postcondition:
    --    Returns whatever, probably table
    -- 2020-01-01
    local storage = access
    local finer = function ()
                      if append then
                          storage = string.format( "%s/%s",
                                                  storage,
                                                  append )
                      end
                  end
    local fun, lucky, r, suited
    if advanced then
        fun = require
    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 containsCJK( s )
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( analyse )
     -- Is any CJK character present?
     -- Is any CJK character present?
     -- Precondition:
     -- Precondition:
     --    s -- string
     --    analyse -- string
     -- Postcondition:
     -- Postcondition:
     --    Return false iff no CJK present
     --    Return false iff no CJK present
     -- Uses:
     -- Uses:
     --    >< patternCJK
     --    >< Local.patternCJK
     --    mw.ustring.char()
     --    mw.ustring.char()
     --    mw.ustring.match()
     --    mw.ustring.match()
     local r = false
     local r = false
     if not patternCJK then
     if not Local.patternCJK then
         patternCJK = mw.ustring.char( 91,
         Local.patternCJK = mw.ustring.char( 91,
                                       13312, 45,  40959,
                                       13312, 45,  40959,
                                       131072, 45, 178207,
                                       131072, 45, 178207,
                                       93 )
                                       93 )
     end
     end
     if mw.ustring.match( s, patternCJK ) then
     if mw.ustring.match( analyse, Local.patternCJK ) then
         r = true
         r = true
     end
     end
138行目: 232行目:
     -- Uses:
     -- Uses:
     --    Module:FileMedia
     --    Module:FileMedia
    --    Foreign()
    --    FileMedia.isFile()
     --    FileMedia.isType()
     --    FileMedia.isType()
     local r
     local r
     if attempt and attempt ~= "" then
     if attempt and attempt ~= "" then
         local lucky, FileMedia = pcall( require, "Module:FileMedia" )
         local FileMedia = Foreign( "FileMedia" )
         if type( FileMedia ) == "table" then
         if FileMedia  and  type( FileMedia.isFile ) == "function"
            FileMedia = FileMedia.FileMedia()
                      and  type( FileMedia.isType ) == "function" then
             local s, live = accept:match( "^([a-z]+)(:?)%+?$" )
             local s, live = accept:match( "^([a-z]+)(:?)%+?$" )
             if live then
             if live then
180行目: 276行目:
     --    Return some message string
     --    Return some message string
     -- Uses:
     -- Uses:
     --    >  MessagePrefix
     --    >  Local.messagePrefix
     --    >  L10nDef
     --    >  Local.L10nDef
    --    mw.message.new()
     --    mw.language.getContentLanguage()
     --    mw.language.getContentLanguage()
     --    mw.message.new()
     --    Module:Multilingual
     local c = mw.language.getContentLanguage():getCode()
    --    Foreign()
     local m = mw.message.new( MessagePrefix .. say )
     --    TemplatePar.framing()
    --    Multilingual.tabData()
     local m = mw.message.new( Local.messagePrefix .. say )
     local r = false
     local r = false
     if m:isBlank() then
     if m:isBlank() then
         local l10n = L10nDef[ c ]
        local c = mw.language.getContentLanguage():getCode()
         if not l10n then
         local l10n = Local.L10nDef[ c ]
             l10n = L10nDef[ "en" ]
         if l10n then
             r = l10n[ say ]
        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
         end
        r = l10n[ say ]
     else
     else
         m:inLanguage( c )
         m:inLanguage( c )
205行目: 316行目:




local function failsafe( story, scan )
local function faculty( accept, attempt )
     -- Test for match (possibly user-defined with syntax error)
     -- Check string as possible boolean
     -- Precondition:
     -- Precondition:
     --    story  -- string; parameter value
     --    accept  -- string; requirement
     --    scan  -- string; pattern
    --                        boolean
    --                        boolean+
     --    attempt  -- string; to be tested
     -- Postcondition:
     -- Postcondition:
     --    Return nil, if not matching, else non-nil
     --    Return error keyword, or false
     -- Uses:
     -- Uses:
     --    mw.ustring.match()
     --    Module:TemplUtl
     return mw.ustring.match( story, scan )
    --    Foreign()
end -- failsafe()
    --    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()




243行目: 381行目:
     return r
     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()




283行目: 587行目:
     --            false if valid or no answer permitted
     --            false if valid or no answer permitted
     -- Uses:
     -- Uses:
     --    >  Patterns
     --    >  Local.patterns
     --    failure()
     --    failure()
     --    mw.text.trim()
     --    mw.text.trim()
    --    faculty()
    --    fast()
     --    facility()
     --    facility()
     --    failsafe()
     --    familiar()
    --    far()
    --    fair()
     --    containsCJK()
     --    containsCJK()
     local r   = false
     local r     = false
     local s   = false
     local s     = false
     local show = nil
     local show = nil
     local scan = false
     local scan = false
    local stuff = mw.text.trim( analyze )
     if type( options.pattern ) == "string" then
     if type( options.pattern ) == "string" then
         if options.key then
         if options.key then
306行目: 615行目:
         end
         end
         if s ~= "*" then
         if s ~= "*" then
             scan = Patterns[ s ]
             scan = Local.patterns[ s ]
         end
         end
         if type( scan ) == "string" then
         if type( scan ) == "string" then
             if s == "n" or s == "0,0" or s == "0.0" then
             if s == "n" or s == "0,0" or s == "0.0" then
                 if not analyze:match( "[0-9]" )  and
                 if not stuff:match( "[0-9]" )  and
                   not analyze:match( "^%s*$" ) then
                   not stuff:match( "^%s*$" ) then
                     scan = false
                     scan = false
                     if options.say then
                     if options.say then
                         show = string.format( "'%s'", options.say )
                         show = string.format( "&quot;%s&quot;", options.say )
                     end
                     end
                     if abbr then
                     if abbr then
328行目: 637行目:
                 n = tonumber( n )
                 n = tonumber( n )
                 if n then
                 if n then
                     local i = tonumber( analyze )
                     local i = tonumber( stuff )
                     if i then
                     if i then
                         if op == "<" then
                         if op == "<" then
352行目: 661行目:
                     r = "undefined"
                     r = "undefined"
                 end
                 end
            elseif s:match( "^boolean%+?$" ) then
                r = faculty( s, stuff )
                n = true
            elseif s:match( "^datetime/?y?m?d?%+?$" ) then
                r = fast( s, stuff )
                n = true
             elseif s:match( "^image%+?:?$" )  or
             elseif s:match( "^image%+?:?$" )  or
                   s:match( "^file%+?:?$" ) then
                   s:match( "^file%+?:?$" ) then
                 r = facility( s, analyze )
                 r = facility( s, stuff )
                n = true
            elseif s:match( "langs?W?%+?" ) then
                r = familiar( s, stuff )
                n = true
            elseif s:match( "url%+?" ) then
                r = far( s, stuff )
                 n = true
                 n = true
            elseif s:match( "langW?%+?" ) then
                n = "lang"
-- lang lang+
-- langW langW+
             end
             end
-- datetime+
-- iso8631+
-- line+
             if not n and not r then
             if not n and not r then
                 r = "unknownRule"
                 r = "unknownRule"
366行目: 686行目:
             if r then
             if r then
                 if options.say then
                 if options.say then
                     show = string.format( "'%s' %s", options.say, s )
                     show = string.format( "&quot;%s&quot; %s", options.say, s )
                 else
                 else
                     show = s
                     show = s
379行目: 699行目:
     end
     end
     if scan then
     if scan then
         local legal, got = pcall( failsafe, analyze, scan )
         local legal, got = pcall( fair, stuff, scan )
         if legal then
         if legal then
             if not got then
             if not got then
                 if s == "aa" then
                 if s == "aa" then
                     got = containsCJK( analyze )
                     got = containsCJK( stuff )
                 end
                 end
                 if not got then
                 if not got then
                     if options.say then
                     if options.say then
                         show = string.format( "'%s'", options.say )
                         show = string.format( "&quot;%s&quot;", options.say )
                     end
                     end
                     if abbr then
                     if abbr then
414行目: 734行目:
     -- Postcondition:
     -- Postcondition:
     --    Return true iff found
     --    Return true iff found
     local k, v
     local k, v, r
     for k, v in pairs( haystack ) do
     for k, v in pairs( haystack ) do
         if k == needle then
         if k == needle then
             return true
             r = true
         end
         end
     end -- for k, v
     end -- for k, v
     return false
     return r or false
end -- fed()
end -- fed()


435行目: 755行目:
     -- Uses:
     -- Uses:
     --    TemplatePar.downcase()
     --    TemplatePar.downcase()
     --    mw.getCurrentFrame()
     --    TemplatePar.framing()
     --    frame:getParent()
     --    frame:getParent()
     local g, k, v
     local g, k, v
442行目: 762行目:
         g = TemplatePar.downcase( options )
         g = TemplatePar.downcase( options )
     else
     else
         g = mw.getCurrentFrame()
         g = TemplatePar.framing()
         if light then
         if light then
             g = g:getParent()
             g = g:getParent()
486行目: 806行目:
         if type( sub ) == "string" then
         if type( sub ) == "string" then
             sub            = sub:gsub( "%%!", "|" )
             sub            = sub:gsub( "%%!", "|" )
            sub            = sub:gsub( "%%%(%(", "{{" )
                                :gsub( "%%%(%(", "{{" )
            sub            = sub:gsub( "%%%)%)", "}}" )
                                :gsub( "%%%)%)", "}}" )
                                :gsub( "\\n", string.char( 10 ) )
             options.pattern = sub
             options.pattern = sub
             options.key    = nil
             options.key    = nil
526行目: 847行目:




local function finalize( submit, options, frame )
local function finalize( submit, options )
     -- Finalize message
     -- Finalize message
     -- Precondition:
     -- Precondition:
535行目: 856行目:
     --                options.cat
     --                options.cat
     --                options.template
     --                options.template
    --    frame    -- object, or false
     -- Postcondition:
     -- Postcondition:
     --    Return string or false
     --    Return string or false
     -- Uses:
     -- Uses:
    --    TemplatePar.framing()
     --    factory()
     --    factory()
     local r = false
     local r = false
     if submit then
     if submit then
        local lazy  = false
        local learn = false
        local show  = false
         local opt, s
         local opt, s
        local lazy = false
        local show = false
         if type( options ) == "table" then
         if type( options ) == "table" then
             opt  = options
             opt  = options
551行目: 873行目:
             s    = opt.preview
             s    = opt.preview
             if type( s ) == "string"  and
             if type( s ) == "string"  and
                s ~= ""  and  s ~= "0"  and  s ~= "-" then
              s ~= ""  and  s ~= "0"  and  s ~= "-" then
                local sniffer = "{{REVISIONID}}"
                 if lazy then
                 if lazy then
                     show = ""
                     show = ""
                     lazy = false
                     lazy = false
                 end
                 end
                 if not frame then
                 if TemplatePar.framing():preprocess( sniffer ) == "" then
                    frame = mw.getCurrentFrame()
                end
                if frame:preprocess( "{{REVISIONID}}" ) == "" then
                     if s == "1" then
                     if s == "1" then
                         show = "*"
                         show = "*"
565行目: 885行目:
                         show = s
                         show = s
                     end
                     end
                    learn = true
                 end
                 end
             end
             end
581行目: 902行目:
             local i
             local i
             if not show  or  show == "*" then
             if not show  or  show == "*" then
                 show = "<span class=\"error\">@@@</span>"
                 local e = mw.html.create( "span" )
                                :attr( "class", "error" )
                                :wikitext( "@@@" )
                if learn then
                    local max  = 1000000000
                    local id  = math.floor( os.clock() * max )
                    local sign = string.format( "error_%d", id )
                    local btn  = mw.html.create( "span" )
                    local top  = mw.html.create( "div" )
                    e:attr( "id", sign )
                    btn:css( { ["background"]      = "#FFFF00",
                              ["border"]          = "#FF0000 3px solid",
                              ["font-weight"]    = "bold",
                              ["padding"]        = "2px",
                              ["text-decoration"] = "none" } )
                      :wikitext( "&gt;&gt;&gt;" )
                    sign = string.format( "[[#%s|%s]]",
                                          sign,  tostring( btn ) )
                    top:wikitext( sign, "&#160;", submit )
                    mw.addWarning( tostring( top ) )
                end
                show = tostring( e )
             end
             end
             i = show:find( "@@@", 1, true )
             i = show:find( "@@@", 1, true )
593行目: 935行目:
                 r = show
                 r = show
             end
             end
        end
        if learn and r then
            -- r = fatal( r )
         end
         end
         s = opt.cat
         s = opt.cat
         if type( s ) == "string" then
         if type( s ) == "string" then
            local link
             if opt.errNS then
             if opt.errNS then
                 local ns = mw.title.getCurrentTitle().namespace
                 local ns = mw.title.getCurrentTitle().namespace
603行目: 949行目:
                     local spaces = string.format( " %s ", opt.errNS )
                     local spaces = string.format( " %s ", opt.errNS )
                     if spaces:match( space ) then
                     if spaces:match( space ) then
                         opt.errNS = false
                         link = true
                     end
                     end
                 elseif st == "table" then
                 elseif st == "table" then
                     for i = 1, #opt.errNS do
                     for i = 1, #opt.errNS do
                         if opt.errNS[ i ] == ns then
                         if opt.errNS[ i ] == ns then
                             opt.errNS = false
                             link = true
                             break    -- for i
                             break    -- for i
                         end
                         end
                     end -- for i
                     end -- for i
                 end
                 end
            else
                link = true
             end
             end
             if opt.errNS then
             if link then
                 r = ""
                 local cats, i
            else
                 if not r then
                 if not r then
                   r = ""
                   r = ""
625行目: 972行目:
                     end
                     end
                 end
                 end
                 local i
                 cats = mw.text.split( s, "%s*#%s*" )
                local cats = mw.text.split( s, "%s*#%s*" )
                 for i = 1, #cats do
                 for i = 1, #cats do
                     s = mw.text.trim( cats[ i ] )
                     s = mw.text.trim( cats[ i ] )
673行目: 1,019行目:
     --    failure()
     --    failure()
     --    fed()
     --    fed()
    local k, v
     local r = false
     local r = false
    local lack
     for k, v in pairs( got ) do
     for k, v in pairs( got ) do
         if not finder( valid, k ) then
         if k == "" then
            lack = true
            break    -- for k, v
        elseif not finder( valid, k ) then
             r = fault( r, k )
             r = fault( r, k )
         end
         end
     end -- for k, v
     end -- for k, v
     if r then
     if lack then
        r = failure( "unavailable", false, options )
    elseif r then
         r = failure( "unknown",
         r = failure( "unknown",
                     string.format( "'%s'", r ),
                     string.format( "&quot;%s&quot;", r ),
                     options )
                     options )
     else -- all names valid
     else -- all names valid
804行目: 1,155行目:
     --                options.mandatory
     --                options.mandatory
     --                options.optional
     --                options.optional
     --    frame    -- object, or false
     --    frame    -- object; #invoke environment, or false
     -- Postcondition:
     -- Postcondition:
     --    Return string with error message as configured;
     --    Return string with error message as configured;
     --            false if valid
     --            false if valid
     -- Uses:
     -- Uses:
    --    TemplatePar.framing()
     --    fold()
     --    fold()
     --    fetch()
     --    fetch()
814行目: 1,166行目:
     --    finalize()
     --    finalize()
     local duty, r
     local duty, r
    if frame then
        TemplatePar.framing( frame )
    end
     if type( options ) == "table" then
     if type( options ) == "table" then
         if type( options.mandatory ) ~= "table" then
         if type( options.mandatory ) ~= "table" then
836行目: 1,191行目:
         end
         end
     end
     end
     return finalize( r, options, frame )
     return finalize( r, options )
end -- form()
end -- form()


871行目: 1,226行目:
                 show = " <" .. options.min
                 show = " <" .. options.min
                 if options.say then
                 if options.say then
                     show = string.format( "%s '%s'", show, options.say )
                     show = string.format( "%s &quot;%s&quot;", show, options.say )
                 end
                 end
                 r = failure( "tooShort", show, options )
                 r = failure( "tooShort", show, options )
884行目: 1,239行目:
                 show = " >" .. options.max
                 show = " >" .. options.max
                 if options.say then
                 if options.say then
                     show = string.format( "%s '%s'", show, options.say )
                     show = string.format( "%s &quot;%s&quot;", show, options.say )
                 end
                 end
                 r = failure( "tooLong", show, options )
                 r = failure( "tooLong", show, options )
907行目: 1,262行目:
     --            false if valid or no answer permitted
     --            false if valid or no answer permitted
     -- Uses:
     -- Uses:
     --    mw.text.trim()  
     --    mw.text.trim()
     --    format()
     --    format()
     --    failure()
     --    failure()
914行目: 1,269行目:
         local story = assignment.args[ access ] or ""
         local story = assignment.args[ access ] or ""
         if type( access ) == "number" then
         if type( access ) == "number" then
             story = mw.text.trim( story )  
             story = mw.text.trim( story )
         end
         end
         if type( options ) ~= "table" then
         if type( options ) ~= "table" then
986行目: 1,341行目:
         end
         end
         if r then
         if r then
             r = finalize( r, options, frame )
             r = finalize( r, options )
         else
         else
             s = frame.args[ 1 ] or ""
             s = frame.args[ 1 ] or ""
994行目: 1,349行目:
             end
             end
             if action == "valid" then
             if action == "valid" then
                 r = TemplatePar.valid( s, options, frame )
                 r = TemplatePar.valid( s, options )
             elseif action == "assert" then
             elseif action == "assert" then
                 r = TemplatePar.assert( s, "", options )
                 r = TemplatePar.assert( s, "", options )
1,021行目: 1,376行目:
         if ( type( append ) == "string" ) then
         if ( type( append ) == "string" ) then
             if ( append ~= "" ) then
             if ( append ~= "" ) then
                 r = string.format( "%s<br />%s", append, r )
                 r = string.format( "%s<br /> %s", append, r )
             end
             end
         else
         else
1,104行目: 1,459行目:




TemplatePar.valid = function ( access, options, frame )
TemplatePar.valid = function ( access, options )
     -- Check validity of one particular template parameter
     -- Check validity of one particular template parameter
     -- Precondition:
     -- Precondition:
1,110行目: 1,465行目:
     --                string or number
     --                string or number
     --    options  -- table or nil; optional details
     --    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;
1,117行目: 1,471行目:
     --    mw.text.trim()
     --    mw.text.trim()
     --    TemplatePar.downcase()
     --    TemplatePar.downcase()
    --    TemplatePar.framing()
     --    frame:getParent()
     --    frame:getParent()
     --    formatted()
     --    formatted()
1,140行目: 1,495行目:
             params = TemplatePar.downcase( options )
             params = TemplatePar.downcase( options )
         else
         else
             params = frame:getParent()
             params = TemplatePar.framing():getParent()
         end
         end
         r = formatted( params, access, options )
         r = formatted( params, access, options )
1,146行目: 1,501行目:
         r = failure( "noname", false, options )
         r = failure( "noname", false, options )
     end
     end
     return finalize( r, options, frame )
     return finalize( r, options )
end -- TemplatePar.valid()
end -- TemplatePar.valid()


1,162行目: 1,517行目:
     return form( false, options, false )
     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()




1,179行目: 1,617行目:
     --    furnish()
     --    furnish()
     return furnish( frame, "assert" )
     return furnish( frame, "assert" )
end -- .assert()
end -- p.assert()




1,216行目: 1,654行目:
     end
     end
     return r or ""
     return r or ""
end -- .check()
end -- p.check()




1,227行目: 1,665行目:
     --    TemplatePar.count()
     --    TemplatePar.count()
     return tostring( TemplatePar.count() )
     return tostring( TemplatePar.count() )
end -- .count()
end -- p.count()




1,238行目: 1,676行目:
     --    TemplatePar.countNotEmpty()
     --    TemplatePar.countNotEmpty()
     return tostring( TemplatePar.countNotEmpty() )
     return tostring( TemplatePar.countNotEmpty() )
end -- .countNotEmpty()
end -- p.countNotEmpty()




1,244行目: 1,682行目:
function p.match( frame )
function p.match( frame )
     -- Combined analysis of parameters and their values
     -- Combined analysis of parameters and their values
    -- Precondition:
    --    frame  -- object; #invoke environment
     -- Postcondition:
     -- Postcondition:
     --    Return string with error message or ""
     --    Return string with error message or ""
     -- Uses:
     -- Uses:
    --    TemplatePar.framing()
     --    mw.text.trim()
     --    mw.text.trim()
     --    mw.ustring.lower()
     --    mw.ustring.lower()
1,266行目: 1,707行目:
     local k, v, s
     local k, v, s
     local params = { }
     local params = { }
    TemplatePar.framing( frame )
     for k, v in pairs( frame.args ) do
     for k, v in pairs( frame.args ) do
         if type( k ) == "number" then
         if type( k ) == "number" then
1,312行目: 1,754行目:
         for k, v in pairs( params ) do
         for k, v in pairs( params ) do
             options.say = k
             options.say = k
            errValue    = false
             s           = targs[ k ]
             s = targs[ k ]
             if s then
             if s then
                 if s == "" then
                 if s == "" then
1,330行目: 1,771行目:
                     if lack then
                     if lack then
                         if errMiss then
                         if errMiss then
                             errMiss = string.format( "%s, '%s'",
                             s      = "%s, &quot;%s&quot;"
                                                    errMiss, k )
                            errMiss = string.format( s, errMiss, k )
                         else
                         else
                             errMiss = string.format( "'%s'", k )
                             errMiss = string.format( "&quot;%s&quot;",
                                                    k )
                         end
                         end
                     elseif not errMiss then
                     elseif not errMiss then
1,349行目: 1,791行目:
                 r = failure( "invalid", errValues, options )
                 r = failure( "invalid", errValues, options )
             end
             end
             r = finalize( r, options, frame )
             r = finalize( r, options )
         end
         end
     end
     end
     return r or ""
     return r or ""
end -- .match()
end -- p.match()




1,366行目: 1,808行目:
     --    furnish()
     --    furnish()
     return furnish( frame, "valid" )
     return furnish( frame, "valid" )
end -- .valid()
end -- p.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




1,375行目: 1,837行目:
     --    Return table with functions
     --    Return table with functions
     return TemplatePar
     return TemplatePar
end -- .TemplatePar()
end -- p.TemplatePar()
 




setmetatable( p,  { __call = function ( func, ... )
                                setmetatable( p, nil )
                                return Failsafe
                            end } )


return p
return p
匿名利用者