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

local p = {}

-- Извлечение аргументов вызова
local function getArgs(frame)
    local args = {}
    if frame.getParent then
        local parent = frame:getParent()
        if parent and parent.args then
            for k, v in pairs(parent.args) do args[k] = v end
        end
    end
    if frame.args then
        for k, v in pairs(frame.args) do args[k] = v end
    end
    return args
end

-- Умная загрузка JSON с автоматическим перебором вариантов названий
local function loadData(args)
    local dataParam = args['данные'] or args[1]
    if not dataParam or dataParam == '' then
        error('Не указано имя базы данных или страница JSON (параметр 1 или |данные=)')
    end
    
    local candidates = {}
    if mw.ustring.find(dataParam, ':') or mw.ustring.find(dataParam, '%.json$') then
        table.insert(candidates, dataParam)
    else
        table.insert(candidates, 'Шаблон:Интерактивная схема ' .. dataParam .. ' метрополитена/data.json')
        table.insert(candidates, 'Шаблон:Интерактивная схема ' .. dataParam .. '/data.json')
        table.insert(candidates, 'Шаблон:' .. dataParam .. '/data.json')
        table.insert(candidates, dataParam .. '/data.json')
        table.insert(candidates, dataParam)
    end
    
    for _, dataPageTitle in ipairs(candidates) do
        -- Попытка быстрой загрузки встроенным парсером JSON
        local success, jsonData = pcall(mw.loadJsonData, dataPageTitle)
        if success and jsonData then
            return jsonData
        end
        
        -- Попытка ручной загрузки текста страницы
        local titleObj = mw.title.new(dataPageTitle)
        if titleObj and titleObj.exists then
            local rawText = titleObj:getContent()
            if rawText and rawText ~= '' then
                rawText = mw.ustring.gsub(rawText, '<noinclude>.-</noinclude>', '')
                rawText = mw.ustring.gsub(rawText, '<!--.-?-->', '')
                rawText = mw.text.trim(rawText)
                
                local decodeSuccess, decodedData = pcall(mw.text.jsonDecode, rawText)
                if decodeSuccess and decodedData then
                    return decodedData
                else
                    error('Ошибка в синтаксисе JSON на странице [[' .. dataPageTitle .. ']]!')
                end
            end
        end
    end
    
    error('Страница данных не найдена. Проверены следующие пути:\n* [[' .. table.concat(candidates, ']]\n* [[') .. ']]')
end

-- Генерация только ImageMap карты
function p.map(frame)
    local args = getArgs(frame)
    local jsonData = loadData(args)
    
    local file = args['файл'] or args['изображение'] or jsonData.file or 'Схема_Муроморского_метрополитена.png'
    local width = args['ширина'] or jsonData.width or '850px'
    local alt = args['alt'] or args['название'] or jsonData.title or 'Схема скоростного транспорта'
    local defaultRadius = args['радиус'] or jsonData.defaultRadius or '16'
    
    local mapText = 'Файл:' .. file .. '|' .. width .. '|center|alt=' .. alt .. '\n'
    mapText = mapText .. '# Автоматически сформированная разметка станций\n'
    
    if jsonData.lines then
        for _, line in ipairs(jsonData.lines) do
            -- Зона плашки линии (если задан box)
            if line.box and line.article then
                mapText = mapText .. 'rect ' .. line.box .. ' [[' .. line.article .. '|' .. (line.name or line.article) .. ']]\n'
            end
            
            -- Дополнительные полигоны линии
            if line.shapes then
                for _, shape in ipairs(line.shapes) do
                    mapText = mapText .. shape .. '\n'
                end
            end
            
            -- Станции линии
            if line.stations then
                for _, st in ipairs(line.stations) do
                    if st.coords and st.article then
                        local r = st.radius or defaultRadius
                        mapText = mapText .. 'circle ' .. st.coords .. ' ' .. r .. ' [[' .. st.article .. '|' .. (st.name or st.article) .. ']]\n'
                    end
                end
            end
        end
    end
    
    -- Дополнительные объекты (вокзалы, ж/д платформы и т.д.)
    local extras = {'Вокзалы', 'Ж/д станции', 'Терминалы', 'Аэропорты'}
    for _, key in ipairs(extras) do
        if jsonData[key] then
            for _, item in ipairs(jsonData[key]) do
                if item[1] and item[2] then
                    mapText = mapText .. 'circle ' .. item[2] .. ' ' .. defaultRadius .. ' ' .. item[1] .. '\n'
                end
            end
        end
    end
    
    mapText = mapText .. 'desc none\n'
    
    return frame:preprocess('{{#tag:imagemap|' .. mapText .. '}}')
end

return p