Module:Subpages

local _M = {};

function _M.clean(title)
    local string, mw_title = string, mw.title;
    title = title and string.gsub( title, '^%s*%[%[+[%s_]*([^%[%]|]+).-%]%]+%s*$', '%1' );
    if title == '' then
        return table.concat{ mw_title.getCurrentTitle().prefixedText, '/' };
    elseif string.sub( title, 1, 1) == '/' then
        return table.concat{ mw_title.getCurrentTitle().prefixedText, title };
    else
        return title;
    end
end

function _M.subpages(title, options)
    local title, options, query = _M.clean(title), options or {};
    
    query, title = pcall(mw.title.new, title, 0);
    if not query or not title then
        return ipairs({});
    elseif not options.ignoreNS and not mw.site.namespaces[title.namespace].hasSubpages then
        return ipairs({});
    end
    
    title = title.prefixedText;
    
    -- merge options
    query = {};
    options.ignoreNS = nil;
    options.stripprefix = 1;
    for k,v in pairs(options) do
        if v ~= nil then
            table.insert( query, table.concat{ k, '=', tostring(v) } );
        end
    end
    query = table.concat{ '{{special:prefixindex/', title, '|', table.concat( query, '|' ) };
    
    -- the pages
    local frame, expand = mw:getCurrentFrame(), mw.text.unstrip;
    local function get(name)
        return string.gmatch( expand( frame:preprocess( name ) ), '<a[^>]*>(.-)</a>' );
    end
    local pages = get(table.concat{ query, '}}' });
    local count = 0;
    
    return function(title, last)
        local query, get, page, decode = query, get, pages(), mw.text.decode;
        count = count+1;
        if page ~= nil then return decode(page), count; end
        if last == nil then return nil, count-1; end
        pages = get( table.concat{ query, '|from=', title, last, '}}' } );
        pages();
        page = pages();
        return (page and decode(page)), count
    end, title;
end

return _M