Module:TemplateData
local TemplateData = { serial = "2017-11-06",
suite = "TemplateData" }
local plaintext = require("Module:Plain text") --[=[ improve template:TemplateData ]=] local Config = {
-- multiple #invoke option names mapped into unique internal fields cat = "strange", classNoNumTOC = "suppressTOCnum",
-- classParams = "classTable",
cssParams = "stylesTable", cssParWrap = "stylesTabWrap", debug = false, docpageCreate = "suffix", docpageDetect = "subpage", msgDescMiss = "solo",
-- classTable = false, -- class for params table
loudly = false, -- show exported element, etc. solo = false, -- complaint on missing description strange = false, -- title of maintenance category stylesTable = false, -- styles for params table stylesTabWrap = false, -- styles for params table wrapper subpage = false, -- pattern to identify subpage suffix = false, -- subpage creation scheme suppressTOCnum = false -- class for TOC number suppression
} local Data = {
div = false, --
got = false, -- table, initial templatedata object heirs = false, -- table, params that are inherited less = false, -- main description missing lasting = false, -- old syntax encounteredlazy = false, -- doc mode; do not generate effective ", j, true )
if k then r = mw.text.trim( s:sub( j + 1, k - 1 ) ) end end return r
end -- find()
local function flat( adjust )
-- Remove formatting from text string -- Parameter: -- arglist -- string, to be stripped, or nil -- Returns string, or nil local r if adjust then r = adjust:gsub( "\n", " " ) if r:find( "<noexport>", 1, true ) then r = r:gsub( "<noexport>(.*)</noexport>", "" ) end r = plaintext._main(r) if r:find( "&", 1, true ) then r = mw.text.decode( r ) end end return r
end -- flat()
local function flush()
-- JSON encode narrowed input; obey unnamed (numerical) parameters -- Returns <templatedata> JSON string local r if Data.tag then r = mw.text.jsonEncode( Data.tag ):gsub( "%}$", "," ) else r = "{" end r = r .. "\n\"params\":{" if Data.order then local sep = "" local s for i = 1, #Data.order do s = Data.order[ i ] r = string.format( "%s%s\n%s:%s", r, sep, mw.text.jsonEncode( s ), mw.text.jsonEncode( Data.params[ s ] ) ) sep = ",\n" end -- for i = 1, #Data.order end r = r .. "\n}\n}" return r
end -- flush()
local function focus( access )
-- Check components; focus multilingual description, build trees -- Parameter: -- access -- string, name of parameter, nil for root local f = function ( a, at ) local r if at then r = string.format( "params.%s
", at ) else r = "root" end if a then r = string.format( "%s.%s
", r, a ) end return r end local parent if access then parent = Data.got.params[ access ] else parent = Data.got end if type( parent ) == "table" then local elem, got, permit, s, scope, slot, tag, target if access then permit = Permit.params if type( access ) == "number" then slot = tostring( access ) else slot = access end else permit = Permit.root end for k, v in pairs( parent ) do scope = permit[ k ] if scope then s = type( v ) if s == "string" then v = mw.text.trim( v ) end if scope:find( s, 1, true ) then if scope:find( "I18N", 1, true ) then if s == "string" then elem = handleNoexportWhitespace( v ) else local translated v, translated = faraway( v ) if v then if translated and k == "description" then elem = { [ 1 ] = handleNoexportWhitespace( v ), [ 2 ] = translated } else elem = handleNoexportWhitespace( v ) end else elem = false end end if v then if scope:find( "nowiki", 1, true ) then elem = mw.text.nowiki( v ) else v = flat( v ) end end else if k == "params" and not access then v = nil elem = nil elseif k == "format" and not access then v = mw.text.decode( v ) elem = v elseif k == "inherits" then elem = v if not Data.heirs then Data.heirs = { } end Data.heirs[ slot ] = v v = nil elseif s == "string" then v = mw.text.nowiki( v ) elem = v else elem = v end end if type( elem ) ~= "nil" then if not target then if access then if not Data.tree.params then Data.tree.params = { } end Data.tree.params[ slot ] = { } target = Data.tree.params[ slot ] else Data.tree = { } target = Data.tree end end target[ k ] = elem elem = false end if type( v ) ~= "nil" then if not tag then if access then if not Data.params then Data.params = { } end Data.params[ slot ] = { } tag = Data.params[ slot ] else Data.tag = { } tag = Data.tag end end tag[ k ] = v end else s = string.format( "Type%s
bad for %s", scope, f( k, slot ) ) Fault( s ) end else Fault( "Unknown component " .. f( k, slot ) ) end end -- for k, v else Fault( f() .. " needs to be ofobject
type" ) end
end -- focus()
local function format()
-- Build presented documentation-- Returns
local r = mw.html.create( "div" ) local s = feasible( Data.tree, true ) if s then r:node( s ) end if Data.leading then local toc = mw.html.create( "div" ) if Config.suppressTOCnum then toc:addClass( Config.suppressTOCnum ) end toc:css( "margin-top", "0.5em" ):wikitext( "" )
r:newline() :node( toc ) :newline() end s = features() if s then if Data.leading then r:node( mw.html.create( "h2" ) :wikitext( getLocalizedText( "doc-params" ) ) ) :newline() end r:node( s ) end if Data.tree and Data.tree.format then local e, style s = Data.tree.format:lower( Data.tree.format ) if s == "inline" or s == "block" then style = "i" else style = "code" end r:node( mw.html.create( "p" ) :wikitext( "Format: " ) :node( mw.html.create( style ) :wikitext( s ) ) ) end return r
end -- format()
local function free()
-- Remove JSON comment lines Data.source:gsub( "([{,\"'])(%s*\n%s*//.*\n%s*)([},\"'])", "%1%3" )
end -- free()
local function full()
-- Build HTML table for display from JSON data, and append an invisible -- <templatedata> block. Data.div = mw.html.create( "div" ) :addClass( "mw-templatedata-doc-wrap" ) focus() if Data.tag then if type( Data.got.params ) == "table" then for k, v in pairs( Data.got.params ) do focus( k ) end -- for k, v if Data.heirs then fathers() end end end Data.div:node( format() ) if not Data.lazy then Data.slim = flush() if TemplateData.frame then local div = mw.html.create( "div" ) local tdata = { [ 1 ] = "templatedata", [ 2 ] = Data.slim } Data.strip = TemplateData.frame:callParserFunction( "#tag", tdata ) div:wikitext( Data.strip ) if Config.loudly then -- Display raw templatedata table all the time. Data.div:node( mw.html.create( "hr" ) ) Data.div:node( div ) else -- Creates an expand link to check raw templatedata table. local wrapper = mw.html.create( "div" ) wrapper:addClass( "mw-collapsible" ) wrapper:addClass( "mw-collapsed" ) wrapper:css( "font-size", "85%" ) div:addClass( "mw-collapsible-content" ) wrapper:wikitext( "Test of raw TemplateData output: " ) wrapper:node( div ) Data.div:node( wrapper ) end end end
end -- full()
local function furnish( adapt, arglist )
-- Called by f, this function is the first to do any real work when the -- module is invoked. -- Parameter: -- adapt -- table, #invoke parameters -- arglist -- table, template parameters -- Returns string
--local spy=""
local source for k, v in pairs( Config ) do if adapt[ k ] and adapt[ k ] ~= "" then Config[ v ] = adapt[ k ] end end -- for k, v Config.loudly = faculty( arglist.debug or adapt.debug )
--if mw.site.server:find( "//de.wikipedia.beta.wmflabs.org", 1, true ) then -- Config.loudly = true --end
Data.lazy = faculty( arglist.lazy ) and not Config.loudly Data.leading = faculty( arglist.TOC ) if arglist.JSON then source = arglist.JSON elseif arglist[ 1 ] then local s = mw.text.trim( arglist[ 1 ] ) local start = s:sub( 1, 1 ) if start == "<" then Data.strip = s elseif start == "{" then source = s elseif mw.ustring.sub( s, 1, 8 ) == mw.ustring.char( 127, 39, 34, 96, 85, 78, 73, 81 ) then --' " ` U N I Q Data.strip = s end end if not source then Data.title = mw.title.getCurrentTitle() source = find() if not source and Config.subpage and Config.suffix and not Data.title.text:match( Config.subpage ) then local s = string.format( Config.suffix, Data.title.prefixedText ) Data.title = mw.title.new( s ) if Data.title.exists then source = find() end end
--if source and -- ( source:find( "|", 1, true ) or -- source:find( "}}", 1, true ) ) then -- -- <ref --spy=string.format( "", Config.strange ) --end
end if not Data.lazy and Config.subpage then if not Data.title then Data.title = mw.title.getCurrentTitle() end Data.lazy = Data.title.text:match( Config.subpage ) end TemplateData.getPlainJSON( source ) return finalize()
--return spy .. finalize() end -- furnish()
TemplateData.failsafe = function ( assert ) -- Checks the age of this implementation against some minimum ("assert").
local r if not assert or assert <= TemplateData.serial then r = TemplateData.serial else r = false end return r
end -- TemplateData.failsafe()
TemplateData.getPlainJSON = function ( adapt )
-- Reduce enhanced JSON data to plain text localized JSON -- Parameter: -- adapt -- string, with enhanced JSON -- Returns string, or not if type( adapt ) == "string" then Data.source = adapt free() Data.got = mw.text.jsonDecode( Data.source ) if Data.got then full() if Data.lasting then Fault( "deprecated type syntax" ) end if Data.less then Fault( Config.solo ) end elseif not Data.strip then Fault( "fatal JSON error" ) end end return Data.slim
end -- TemplateData.getPlainJSON()
TemplateData.test = function ( adapt, arglist )
TemplateData.frame = mw.getCurrentFrame() return furnish( adapt, arglist )
end -- TemplateData.test()
-- Export local p = { }
p.f = function ( frame )
-- The entry point for templates invoking the module. -- Just wraps furnish in an exception handler. local lucky, result TemplateData.frame = frame lucky, result = pcall( furnish, frame.args, frame:getParent().args ) if not lucky then Fault( "INTERNAL: " .. result ) result = failures() end return result
end -- p.f()
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 TemplateData.failsafe( since ) or ""
end -- p.failsafe()
p.TemplateData = function ()
-- Module interface return TemplateData
end
return p