Module:ListUtils

Revision as of 13:44, 15 November 2025 by C (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:ListUtils/doc

-- Module:ListUtils
local p = {}

-- Helper: trim whitespace
local function trim(s)
    if not s then return '' end
    return (mw.ustring.gsub(s, '^%s*(.-)%s*$', '%1'))
end

-- Helper: is already a wikilink like [[Foo]] or [[Foo|Bar]]
local function isLinked(s)
    return mw.ustring.match(s, '%[%[') ~= nil
end

-- Helper: strip existing [[...]] to normalize before relinking
local function stripLinks(s)
    s = mw.ustring.gsub(s, '%[%[', '')
    s = mw.ustring.gsub(s, '%]%]', '')
    return s
end

-- Public: turn "A, B , [[C|X]] , D" into "[[A]], [[B]], [[C|X]], [[D]]"
function p.linkifyCommaList(frame)
    local raw = frame.args[1] or ''
    raw = trim(raw)
    if raw == '' then return '' end

    -- Split on commas (allowing messy spacing)
    local parts = mw.text.split(raw, ',')
    local out = {}
    local seen = {}

    for _, part in ipairs(parts) do
        local s = trim(part)
        if s ~= '' then
            -- Keep already-linked entries as-is
            if isLinked(s) then
                if not seen[s] then
                    table.insert(out, s)
                    seen[s] = true
                end
            else
                -- Normalize any accidental brackets then relink
                local plain = stripLinks(s)
                plain = trim(plain)
                -- Deduplicate by plain text
                if not seen[plain] then
                    table.insert(out, '[[' .. plain .. ']]')
                    seen[plain] = true
                end
            end
        end
    end

    return table.concat(out, ', ')
end

--------------------------------------------------------------------
-- Generic helper for comma lists → categories + SMW properties
--------------------------------------------------------------------

-- Internal helper: works on raw strings
local function catsAndPropsFromList(list, property, catNs)
    list = trim(list or '')
    if list == '' then
        return ''
    end

    catNs = catNs or 'Category'

    local parts = mw.text.split(list, ',')
    local out = {}
    local seen = {}

    for _, part in ipairs(parts) do
        local s = trim(part)
        if s ~= '' then
            -- Normalize to plain page name
            local plain = stripLinks(s)
            -- Handle links like [[Foo|Label]]
            plain = mw.ustring.match(plain, '([^|]+)') or plain
            plain = trim(plain)

            if plain ~= '' and not seen[plain] then
                -- Category link (optional if catNs ~= '')
                if catNs ~= '' then
                    table.insert(out, '[[' .. catNs .. ':' .. plain .. ']]')
                end
                -- Property annotation (hidden label so nothing shows)
                if property and property ~= '' then
                    table.insert(out, '[[' .. property .. '::' .. plain .. '| ]]')
                end
                seen[plain] = true
            end
        end
    end

    return table.concat(out, ' ')
end

-- Internal: props only
local function propsFromList(list, property)
    list = trim(list or '')
    if list == '' or not property or property == '' then
        return ''
    end

    local parts = mw.text.split(list, ',')
    local out = {}
    local seen = {}

    for _, part in ipairs(parts) do
        local s = trim(part)
        if s ~= '' then
            local plain = stripLinks(s)
            plain = mw.ustring.match(plain, '([^|]+)') or plain
            plain = trim(plain)

            if plain ~= '' and not seen[plain] then
                table.insert(out, '[[' .. property .. '::' .. plain .. '| ]]')
                seen[plain] = true
            end
        end
    end

    return table.concat(out, ' ')
end

-- Public: generic #invoke entry point
-- Examples:
-- {{#invoke:ListUtils|catsAndProps|Environment, Energy|HasVertical}}
-- {{#invoke:ListUtils|catsAndProps
--   | list = Environment, Energy
--   | property = HasVertical
--   | catns = Category
-- }}
function p.catsAndProps(frame)
    local list = frame.args.list or frame.args[1] or ''
    local property = frame.args.property or frame.args[2] or ''
    local catNs = frame.args.catns or frame.args.categoryNamespace or frame.args[3] or 'Category'

    return catsAndPropsFromList(list, property, catNs)
end

-- Public: props-only entry point
-- {{#invoke:ListUtils|propsOnly|A, B, C|HasThing}}
-- {{#invoke:ListUtils|propsOnly|list=A, B, C|property=HasThing}}
function p.propsOnly(frame)
    local list = frame.args.list or frame.args[1] or ''
    local property = frame.args.property or frame.args[2] or ''
    return propsFromList(list, property)
end

return p