Для документации этого модуля может быть создана страница Модуль:Предмет/doc

local p = {}
local getArgs = require('Module:Arguments').getArgs

-- Ленивая обёртка для #invoke и preprocess с кэшированием
local function makeInvoker(frame)
    local cache = {}
    return function(module, method, sub, extra, id)
        local key = table.concat({module, method, sub or "", extra or "", id or ""}, "|")
        if not cache[key] then
            local invokeStr = string.format("{{#invoke:%s|%s|%s|%s|%s}}", module, method, sub or "", extra or "", id or "")
            cache[key] = frame:preprocess(invokeStr)
        end
        return cache[key]
    end
end

-- Форматирование изображения
local function formatImage(file, size)
    return string.format("[[Файл:%s|%s|link=]]", file, size)
end

-- Разрешение аргумента
local function resolveArg(input, defaultValue)
    if input == nil then return defaultValue end
    return input == "" and "" or input
end

-- Обёртка для создания вики-ссылки
local function wrapLink(text, target)
    return text == "" and "" or string.format("[[%s|%s]]", target, text)
end

function p.main(frame)
    -- Один вызов getArgs
    local argsRaw = getArgs(frame, { trim = false, removeBlanks = false })
    -- Простые args
    local args = {}
    for k, v in pairs(argsRaw) do if v ~= "" then args[k] = v end end

    -- Параметры
    local id         = args[1] or ""
    local size       = args.size or "32px"
    local prefix     = args[2] or ""
    local repositoryMode = argsRaw.repository ~= nil
    local wrapperMode    = argsRaw.wrapper   ~= nil
    local vertical       = argsRaw.vertical  ~= nil

    -- Ленивая генерация invoke/preprocess
    local invokeLP = makeInvoker(frame)

    -- Функции для получения данных по требованию
    local function getItemStack()
        return invokeLP("Prototypes/Хранилище/Предмет", "main", "framing|stack", id)
    end
    local function getItemContained()
        return invokeLP("Prototypes/Хранилище/Предмет", "main", "framing|contained", id)
    end
    local function getItemSlot()
        return invokeLP("Prototypes/Хранилище/Предмет", "main", "framing|slot", id)
    end
    local function getItemChem()
        local chem = invokeLP("Prototypes/Хранилище/Предмет", "main", "chem", id)
        return frame:preprocess(string.format("{{СollapsibleMenu|color=#3e7c82|%s}}", chem))
    end
    local function getItemName()
        return invokeLP("Entity Lookup", "getname", id)
    end

    -- Собираем части результата
    local parts = {}

    -- Изображение
    local rawImage = argsRaw.image or argsRaw.img
    local image = rawImage == nil and formatImage(id..".png", size)
        or (rawImage ~= "" and formatImage(rawImage, size) or "")
    if argsRaw.imageTooltip then
        image = frame:preprocess(string.format(
            "{{#invoke:Entity Lookup|createimagetooltip|Файл:%s.png|%s|Мета=%s,link=}}",
            id, id, size
        ))
    end

    -- Метка и ссылка
    local rawLabel = argsRaw.label or argsRaw.l
    local label = rawLabel == nil and getItemName() or resolveArg(rawLabel, getItemName())
    local rawLink  = argsRaw.link
    local labelOut = rawLink ~= nil
        and wrapLink(label, rawLink == "" and getItemName() or rawLink)
        or label

    -- Репозиторий (только в режиме)
    local repoStr = ""
    if repositoryMode then
        repoStr = table.concat({ getItemContained(), getItemSlot(), getItemChem() }, " ")
    end

    -- Вертикальное или горизонтальное
    if vertical then
        table.insert(parts, string.format(
            "<span style='display:inline-flex;flex-direction:column;align-items:center;'>%s<b>%s</b></span>",
            image, labelOut
        ))
        table.insert(parts, getItemStack())
        table.insert(parts, prefix)
    else
        table.insert(parts, string.format(
            "<span style='display:inline-block;'>%s%s</span>", image, repoStr
        ))
        table.insert(parts, labelOut)
        table.insert(parts, getItemStack())
        table.insert(parts, prefix)
    end

    local result = table.concat(parts, " ")

    -- Обёртка LinkCard
    if wrapperMode then
        local pixel = size:match("(%d+)")
        local linkParam = rawLink and (rawLink == "" and getItemName() or rawLink) or ""
        local sideStyle = vertical and "" or "|SideStyle=1"
        local card = string.format(
            "{{LinkCard|name=%s %s %s|pin=%s|image-full=%s|pixel=%s|link=%s%s}}",
            labelOut, getItemStack(), prefix, repoStr, image, pixel, linkParam, sideStyle
        )
        return frame:preprocess(card)
    end

    -- Финальный вывод одним preprocess
    return frame:preprocess(string.format("<span>%s</span>", result))
end

return p