Module:Version
The above documentation is transcluded from Module:Version/doc. 
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
local getArgs = require('Module:Arguments').getArgs
local util = require('Module:Util')
local cargo = mw.ext.cargo
local string_format = string.format
local table_concat = table.concat
local mw_html = mw.html
local mw_language = mw.getLanguage('en')
local p = {}
local date_format = 'd F Y H:i:s'
-----
------------------------------------------------------------------------------------------------------
-- Template: Version
function validate_version(value)
    if value == nil then
        return value
    else
        return util.cast.version(value, {return_type='string'})
    end
end
function show_date(args)
    return function(tpl_args, frame)
        local version = tpl_args[args.key]
        local date = tpl_args[string.format('%s_date', args.key)]
        if version and date then
            date = mw_language:formatDate(date_format, date)
            if args.key == 'before' then
                return string_format('← [[Version %s|%s]]<br>%s', version, version, date)
            elseif args.key == 'after' then
                return string_format('[[Version %s|%s]] →<br>%s', version, version, date)
            end
        else
            return ''
        end
    end
end
local version_map = {
    table = 'versions',
    fields = {
        patch = {
            field = 'version',
            type = 'String',
            validate = validate_version,
        },
        patchdate = {
            field = 'release_date',
            type = 'Datetime',
            validate = tostring,
        },
        major_part = {
            field = 'major_part',
            type = 'Integer',
        },
        minor_part = {
            field = 'minor_part',
            type = 'Integer',
        },
        patch_part = {
            field = 'patch_part',
            type = 'Integer',
        },
        revision_part = {
            field = 'revision_part',
            type = 'String',
        },
        before = {
            field = 'before',
            type = 'String',
            validate = validate_version,
            show = show_date{key='before'},
        },
        after = {
            field = 'after',
            type = 'String',
            validate = validate_version,
            show = show_date{key='after'},
        },
    },
}
p.table_versions = util.cargo.declare_factory{data=version_map}
p.version = function(frame)
    local args = getArgs(frame, {parentFirst = true})
    local frame = util.misc.get_frame(frame)
    --[[
    = p.version({
        before = '2.4.1a',
        patch = '2.4.1b',
        patchdate = 'October 18, 2016',
        after = '2.4.2',
    })
    --]]
    for k, data in pairs(version_map.fields) do
        if data.validate ~= nil then
            args[k] = data.validate(args[k])
        end
    end
    if not args.patch or not args.patchdate then
        error('Arguments "patch" and "patchdate" are required')
    end
    
    local version_parts = util.cast.version(args.patch, {return_type='table'})
    args.major_part = tonumber(version_parts[1])
    args.minor_part = tonumber(version_parts[2])
    args.patch_part = tonumber(version_parts[3])
    if version_parts[4] then
        args.revision_part = version_parts[4]
    end
    -- Check and set 'before' and 'after' args
    local edge_names = {'before', 'after'}
    for _, key in ipairs(edge_names) do
        local v = args[key]
        if v then
            local results = cargo.query(
                'versions', 
                'versions.release_date', 
                {
                    where=string.format('version="%s"', v),
                    -- Cargo bug work around
                    groupBy='versions._pageID',
                }
            )
            if #results == 1 then
                args[string.format('%s_date', key)] = results[1]['versions.release_date']
            elseif #results > 1 then
                error('There are multiple versions with the same name')
            end
        end
    end
    -- Set Cargo data
    local _properties = {
        _table = version_map.table,
    }
    for key, data in pairs(version_map.fields) do
        if args[key] ~= nil then
            _properties[data.field] = args[key]
       end
    end
    
    util.cargo.store(frame, _properties)
    -- Generate output
    -- todo: rework it somehow
    local release_date = mw_language:formatDate(date_format, args.patchdate)
    local tbl = mw_html.create('table')
    tbl
        :addClass('wikitable successionbox')
        :tag('tr')
            :tag('th')
                :attr('colspan', 3)
                :wikitext('[[Version history|Version History]]')
                :done()
            :done()
        :tag('tr')
            :tag('td')
                :cssText('width: 30%')
                :wikitext(version_map.fields.before.show(args, frame))
                :done()
            :tag('td')
                :cssText('width: 40%')
                :wikitext(string_format('<b>%s</b><br>%s', args.patch, release_date))
                :done()
            :tag('td')
                :cssText('width: 30%')
                :wikitext(version_map.fields.after.show(args, frame))
    local cats = {
        'Versions',
    }
    return tostring(tbl) .. util.misc.add_category(cats)
end
-----
p.version_declare = function(frame)
    -- local args = getArgs(frame, {parentFirst = true})
    local frame = util.misc.get_frame(frame)
    local props = {
        _table = 'Versions',
    }
--    for i, _ in pairs(version_map) do
--        props[i] = _.datatype
--    end
    for i = 1, #temp_map_for_cargo do
        local v = temp_map_for_cargo[i]
        local _ = version_map[v]
        props[v] = _.datatype
    end
    --mw.logObject(props)
    return util.cargo.declare(frame, props)
end
-----
------------------------------------------------------------------------------------------------------
-- Template: Version history list
p.version_history_list = function(frame)
    local args = getArgs(frame, {parentFirst = true})
    local frame = util.misc.get_frame(frame)
    -- = p.version_history_list({conditions='[[Is version::~1*||~2*]]'})
    -- = p.version_history_list({conditions='[[Is version::~0.9*]]'})
    -- = p.version_history_list({conditions='[[Is version::~0.5*]]'})
    if args.conditions then
        args.conditions = args.conditions .. '[[Has release date::+]]'
    else
        args.conditions = '[[Is version::+]][[Has release date::+]]'
    end
    local query = {
        args.conditions,
        '?Is version',
        '?Has release date',
        sort = 'Has release date, Is version',
        order = 'desc, desc',
        link = 'none',
        offset = 0,
    }
    local results = {}
    repeat
        local result = util.smw.query(query, frame)
        local length = #result
        query.offset = query.offset + length
        for i = 1, length do
            results[#results + 1] = result[i]
        end
    until length < 1000
    local out = {}
    local last_minor_version, current_list
    for i = 1, #results do
        local result = results[i]
        local date = result['Has release date']
        local version = result['Is version']
        local v = util.cast.version(result['Is version'])
        local minor_version = table_concat({v[1], v[2], v[3]}, '.') -- todo: rework it
        if minor_version ~= last_minor_version then
            if current_list ~= nil then
                out[#out + 1] = tostring(current_list)
            end
            out[#out + 1] = string_format('===Version %s===', minor_version)
            current_list = mw_html.create('ul')
        end
        current_list:tag('li'):wikitext(string_format('%s – [[Version %s]]', date, version))
        -- save the last list
        if i == #results and current_list ~= nil then
            out[#out + 1] = tostring(current_list)
        end
        last_minor_version = minor_version
    end
    return table_concat(out, '\n')
end
-----
p.version_history_list_2 = function(frame)
    local args = getArgs(frame, {parentFirst = true})
    local frame = util.misc.get_frame(frame)
    -- = p.version_history_list({conditions='[[Is version::~1*||~2*]]'})
    -- = p.version_history_list({conditions='[[Is version::~0.9*]]'})
    -- = p.version_history_list({conditions='[[Is version::~0.5*]]'})
    if args.conditions then
        args.conditions = args.conditions .. '[[Has release date::+]]'
    else
        args.conditions = '[[Is version::+]] [[Has release date::+]]'
    end
    local query = {
        args.conditions,
        '?Is version',
        '?Has release date',
        '?Has major version part',
        '?Has minor version part',
        '?Has patch version part',
--        '?Has revision version part',
        sort = 'Has major version part, Has minor version part, Has patch version part, Is version',
        order = 'desc, desc, desc, desc',
        link = 'none',
        offset = 0,
    }
    local results = {}
    repeat
        local result = util.smw.query(query, frame)
        local length = #result
        query.offset = query.offset + length
        for i = 1, length do
            results[#results + 1] = result[i]
        end
    until length < 1000
--    mw.logObject(results)
    local out = {}
    local last_minor_version, current_list
    for i = 1, #results do
        local result = results[i]
        local date = result['Has release date']
        local version = result['Is version']
        local patch_version = string_format('%s.%s.%s',
            result['Has major version part'], result['Has minor version part'], result['Has patch version part'])
        if patch_version ~= last_minor_version then
            if current_list ~= nil then
                out[#out + 1] = tostring(current_list)
            end
            out[#out + 1] = string_format('===Version %s===', patch_version)
            current_list = mw_html.create('ul')
        end
        current_list:tag('li'):wikitext(string_format('%s – [[Version %s]]', date, version))
        -- save the last list
        if i == #results and current_list ~= nil then
            out[#out + 1] = tostring(current_list)
        end
        last_minor_version = patch_version
    end
    return table_concat(out, '\n')
end
-----
return p