Module:Format TemplateData/global explained

local Export = --[=[ Retrieve TemplateData from Commons:Data (or other global source) require Inspired by [[User:Yurik]].]=]local Failsafe = Export

local failsafe = function (atleast) -- Retrieve versioning and check for compliance -- Precondition: -- atleast -- string, with required version -- or "wikidata" or "~" or "@" or false -- Postcondition: -- Returns string -- with queried version/item, also if problem -- false -- if appropriate -- 2020-08-01 local last = (atleast

"~") local link = (atleast

"@") local since = atleast local r if last or link 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) 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 link 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 if type(r)

"nil" then if not since or since <= Failsafe.serial then r = Failsafe.serial else r = false end end return rend -- failsafe

local function fair(already, adapt, append) -- Merge local definitions into global base -- Parameter: -- already -- global item -- adapt -- local override item -- append -- append to sequence table -- Returns merged item local r if already and adapt then if type(already)

"table" and type(adapt)

"table" then r = already if append then for i = 1, #adapt do table.insert(r, adapt[i ]) end -- for i else for k, v in pairs(adapt) do r[k ] = v end -- for k, v end else r = adapt end else r = already or adapt end return rend -- fair

local function feed(apply) -- Retrieve override from JSON code -- Parameter: -- apply -- string, with JSON -- Returns string, with error message, or table local lucky, r = pcall(mw.text.jsonDecode, apply) if not lucky then r = "fatal JSON error in LOCAL override" end return rend -- feed

local function find(access) -- Fetch data from page -- Parameter: -- access -- string, with core page name -- Returns -- 1. string, with prefixed page name -- 2. table with JSON data, or error message local storage = access local lucky, r if Export.suffix and not storage:find(".", 2, true) then local k = -1 - #Export.suffix if storage:sub(k) ~= "." .. Export.suffix then storage = string.format("%s.%s", storage, Export.suffix) end end if Export.subpages and not storage:find("/", 1, true) then storage = string.format("%s/%s", Export.subpages, storage) end lucky, r = pcall(mw.ext.data.get, storage, "_") storage = "Data:" .. storage if mw.site.siteName ~= "Wikimedia Commons" then storage = "commons:" .. storage end if type(r) ~= "table" and type(r) ~= "string" then r = "INVALID" end return storage, rend -- find

local function flat(apply) -- Convert tabular data into TemplateData -- Parameter: -- apply -- table, with tabular data -- Returns string, with error message, or table, with TemplateData local r, scream local function failed(at, alert) if scream then scream = string.format("%s * #%d: %s", scream, at, alert) else scream = add end end -- failed if type(apply.schema)

"table" and type(apply.schema.fields)

"table" and type(apply.data)

"table" then local order = local entry, got, params, parOrder, s, sign, td, v for k, v in pairs(apply.schema.fields) do if type(v)

"table" then table.insert(order, v.name) end end -- for k, v for i = 1, #apply.data do entry = apply.data[i ] if type(entry)

"table" then got = sign = false for j = 1, #entry do s = order[j ] v = entry[j ] if type(v)

"string" then v = mw.text.trim(v) if v

"" then v = false end end if v then if s

"name" then sign = v elseif s

"aliases" then if type(v)

"string" then got.aliases = mw.text.split(v, "%s*|%s*") else failed(i, "aliases not a string") end else got[s ] = v end end end -- for j if sign

"|" then if td then failed(i, "root repeated") else td = if type(got.type)

"string" then td.format = got.type:gsub("N", "\n") end end elseif sign then if params then if params[sign ] then failed(i, "name repeated: " .. sign) end else params = parOrder = end params[sign ] = got table.insert(parOrder, sign) else failed(i, "missing name") end else failed(i, "invalid component") end end -- for i r = td or r.params = params r.paramOrder = parOrder else r = "bad tabular structure" end return scream or r or "EMPTY"end -- flat

local function flush(assembly, avoid) -- Remove element from sequence table -- Parameter: -- assembly -- sequence table -- avoid -- element for i = 1, #assembly do if assembly[i ]

avoid then table.remove(assembly, i) break -- for i end end -- for iend -- flush

local function fold(already, adapt) -- Merge local parameter definitions into global base -- Parameter: -- already -- table, with global data -- adapt -- sequence table, with local params overrides -- Returns string, with error message, or table, with TemplateData local order = local params = local r = already local entry, override, s r.params = r.params or r.paramOrder = r.paramOrder or for i = 1, #adapt do override = adapt[i ] if type(override) ~= "table" then r = string.format("No object at LOCAL params[%d]", i) break -- for i elseif type(override.global)

"string" then s = override.global entry = r.params[s ] if type(entry)

"table" then flush(r.paramOrder, s) if type(override["local"])

"string" then s = override["local"] override["local"] = nil elseif override["local"]

false then entry = nil end if entry then override.global = nil for k, v in pairs(override) do entry[k ] = fair(entry[k ], override[k ], (k

"aliases")) end -- for k, v table.insert(order, s) end params[s ] = entry else r = string.format("No GLOBAL params %s for LOCAL [%d]", s, i) break -- for i end elseif type(override["local"])

"string" then s = override["local"] override["local"] = nil params[s ] = override table.insert(order, s) else r = string.format("No name for LOCAL params[%d]", i) break -- for i end end -- for i if type(r)

"table" then for i = 1, #r.paramOrder do s = r.paramOrder[i ] params[s ] = r.params[s ] table.insert(order, s) end -- for i r.params = params r.paramOrder = order end return rend -- fold

local function fork(already, adapt) -- Merge local definitions into global base -- Parameter: -- already -- table, with global data -- adapt -- table, with local overrides -- Returns string, with error message, or table, with TemplateData local root = local r = already for k, v in pairs(root) do if adapt[v ] then r[v ] = fair(r[v ], adapt[v ]) end end -- for k, v if type(adapt.params)

"table" then r = fold(r, adapt.params) end return rend -- fork

local function furnish(apply, at, adapt) -- Convert external data into TemplateData -- Parameter: -- apply -- table, with external data -- at -- string, with page name -- adapt -- JSON string or table or not, with local overrides -- Returns string, with error message, or table, with TemplateData local r if at:sub(-4)

".tab" then r = flat(apply) else r = "Unknown page format: " .. at end if adapt and type(r)

"table" then local override = adapt if type(adapt)

"string" then override = feed(adapt) if type(override)

"string" then r = override end end if type(override)

"table" then r = fork(r, override) end end return rend -- furnish

Export.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(since) or ""end -- Export.failsafe

Export.fetch = function (access, adapt) -- Fetch data from site -- Parameter: -- access -- string, with page specification -- adapt -- JSON string or table or not, with local overrides -- Returns -- 1. string, with error message or prefixed page name -- 2. table with TemplateData, or not local storage, t = find(access) local s if type(t)

"table" then t = furnish(t, storage, adapt) if type(t) ~= "table" then s = t end else s = t end if type(t) ~= "table" then storage = string.format("%s", storage) if s then storage = string.format("%s * %s", storage, s) end t = false end return storage, tend -- Export.fetch

return Export