Module:Format TemplateData/global

local Export = {
  item = 51435481,
  serial = "2020-08-01",
  subpages = "TemplateData",
  suffix = "tab",
  suite = "TemplateDataGlobal"
}
--[=[
Retrieve TemplateData from Commons:Data (or other global source).

require()

Inspired by [[de: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
  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 r
end -- 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 r
end -- 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 r
end -- 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, r
end -- 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 = {description = got.description}
            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 i
end -- 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 r
end -- 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 = {"description", "format", "maps", "sets", "style"}
  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 r
end -- 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 r
end -- 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, t
end -- Export.fetch()

return Export

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.