# Module:Pagetype

---
-- --  
-- This meta-module which automatically detects namespaces, and allows --  
-- for a great deal of customisation. It can easily be ported to other --  
-- wikis by changing the values in the Module:Pagetype/config. --  
-- --  
---
-- Load config.  
local cfg = mw.loadData('Module:Pagetype/config')  

-- Load required modules.  
local yesno = require('Module:Yesno')  
local p = {}  

-- Look up a namespace argument in the args table.  
local function lookUpNamespaceArg(args, key)  
local arg = args[key]  
-- Convert "yes", "1" etc. to true, "no", "0" etc. to false, and leave  
-- other values the same.  
return yesno(arg, arg)  
end  

-- Append multiple values to an array  
local function appendMultiple(target, source)  
for _, value in ipairs(source) do  
table.insert(target, value)  
end  
end  

-- Get argument keys for a title's namespace  
local function getNamespaceArgKeys(title)  
local nsInfo = mw.site.namespaces[title.namespace]  
local customAliases = cfg.customNamespaceAliases[title.namespace] or {}  
local keys = {}  
if nsInfo.name ~= '' then  
table.insert(keys, nsInfo.name)  
end  
if nsInfo.canonicalName ~= nsInfo.name and nsInfo.canonicalName ~= '' then  
table.insert(keys, nsInfo.canonicalName)  
end  
appendMultiple(keys, nsInfo.aliases)  
appendMultiple(keys, customAliases)  
return keys  
end  

-- Get the argument for a title's namespace, if it was specified in the args table.  
local function getNamespaceArg(title, args)  
if title.isTalkPage then  
return lookUpNamespaceArg(args, cfg.talk)  
end  
for _, key in ipairs(getNamespaceArgKeys(title)) do  
local arg = lookUpNamespaceArg(args, mw.ustring.lower(key))  
if arg ~= nil then  
return arg  
end  
end  
return nil  
end  

-- Look up a page type specific to the title's namespace  
local function getExplicitPageType(title)  
if title.isTalkPage then  
return cfg.talkDefault  
else  
return cfg.pagetypes[title.namespace]  
end  
end  

-- Get a default page type that is not specific to the title's namespace  
local function getDefaultPageType(args)  
local other = lookUpNamespaceArg(args, cfg.other)  
if type(other) == 'string' then  
return other  
else  
return cfg.otherDefault  
end  
end  

local function detectRedirects(title, args)  
local redirect = lookUpNamespaceArg(args, cfg.redirect)  
if redirect == false then  
-- Don't detect redirects if they have been specifically disallowed.  
return nil  
end  

-- Allow custom values for redirects.  
if not title.isRedirect then  
return nil  
elseif type(redirect) == 'string' then  
return redirect  
else  
return cfg.redirectDefault  
end  
end  

local function capitalize(pageType)  
local first = mw.ustring.sub(pageType, 1, 1)  
local rest = mw.ustring.sub(pageType, 2)  
return mw.ustring.upper(first) .. rest  
end  

local function pluralize(pageType)  
if cfg.irregularPlurals[pageType] then  
return cfg.irregularPlurals[pageType]  
else  
return pageType .. cfg.plural -- often 's'  
end  
end  

local function parseContent(title, args, optionsList)  
if title.namespace==828 and title.subpageText~='doc' -- don't detect modules  
or not title.exists -- can't check unless page exists  
then  
return nil  
end  
local content = title:getContent  
if content == nil then  
return nil  
end  
local templates -- lazily evaluated  
for _, options in next, optionsList do  
local list, parameter, default, articleOnly = unpack(options, 1, 4)  
if not articleOnly or title.namespace==0 then -- only check for templates if we should...  
local out = lookUpNamespaceArg(args, parameter)  
if type(out) == "string" or (out ~= false and default) then -- ...and if we actually have anything to say about them  
if not templates then  
templates = {} -- do our delayed evaluation now that we are required to  
content = require('Module:Wikitext Parsing').PrepareText(content) -- disregard templates which do not have any affect  
for template in string.gmatch(content, "  
-- Find pages which do not exist  
local function nonExistent(title, args)  
local arg = lookUpNamespaceArg(args, cfg.ne)  
if arg == false then  
return nil  
end  
local exists = false  
if title.exists then -- not an article if it does not exist  
exists = true  
elseif title.namespace==8 and mw.message.new(title.text):exists then  
exists = true  
elseif title.namespace==6 and title.fileExists then  
exists = true  
end  
if not exists then  
if type(arg) == 'string' then  
return arg  
else  
return cfg.naDefault  
end  
end  
end  

-- Get page types for mainspaces pages with an explicit class specified  
local function getMainNamespaceClassPageType(title, args)  
local class = args[1]  
if type(class) == 'string' then -- Put in lower case so e.g. "na" and "NA" will both match  
class = mw.ustring.lower(class)  
end  
local arg = lookUpNamespaceArg(args, cfg.na)  
if arg == false then -- don't check for this class if it is specifically disallowed  
return nil  
end  
if cfg.naAliases[class] then  
if type(arg) == 'string' then  
return arg  
else  
return cfg.naDefault  
end  
else  
return nil  
end  
end  

-- Get page type specified by an explicit namespace argument.  
local function getNamespaceArgPageType(title, args)  
local namespaceArg = getNamespaceArg(title, args)  
if namespaceArg == true then  
-- Namespace has been explicitly enabled, so return the default for  
-- this namespace  
return getExplicitPageType(title)  
elseif namespaceArg == false then  
-- Namespace has been explicitly disabled  
return getDefaultPageType(args)  
elseif namespaceArg then  
-- This namespaces uses custom text  
return namespaceArg  
else  
return nil  
end  
end  

-- Get page type not specified or detected by other means  
local function getOtherPageType(title, args)  
-- Whether the title is in the set of default active namespaces which are looked up in cfg.pagetypes.  
local isInDefaultActiveNamespace = false  
local defaultNamespacesKey = args[cfg.defaultns]  
if defaultNamespacesKey == cfg.defaultnsAll then  
isInDefaultActiveNamespace = true  
else  
local defaultNamespaces  
if defaultNamespacesKey == cfg.defaultnsExtended then  
defaultNamespaces = cfg.extendedNamespaces  
elseif defaultNamespacesKey == cfg.defaultnsNone then  
defaultNamespaces = {}  
else  
defaultNamespaces = cfg.defaultNamespaces  
end  
isInDefaultActiveNamespace = defaultNamespaces[title.namespace]  
end  
if isInDefaultActiveNamespace then  
return getExplicitPageType(title)  
else  
return getDefaultPageType(args)  
end  
end  

function p._main(args)  
local title  
if args.page then  
title = mw.title.new(args.page)  
else  
title = mw.title.getCurrentTitle  
end  
if title and not yesno(args.talk, true) and args[cfg.defaultns] ~= cfg.defaultnsAll then  
title = title.subjectPageTitle  
end  
local pageType = detectRedirects(title, args)  
or nonExistent(title, args)  
or parseContent(title, args, {  
{'softredirect', cfg.softRedirect, cfg.softRedirectDefault},  
{'setindex', cfg.sia, cfg.siaDefault, true},  
{'disambiguation', cfg.dab, cfg.dabDefault, true},  
{'rfd', cfg.rfd, cfg.rfdDefault},  
})  
or (title.namespace == 0 and getMainNamespaceClassPageType(title, args))  
or getNamespaceArgPageType(title, args)  
or getOtherPageType(title, args)  
if yesno(args.plural, false) then  
pageType = pluralize(pageType)  
end  
if yesno(args.caps, false) then  
pageType = capitalize(pageType)  
end  
return pageType  
end  

function p.main  
local args = require('Module:Arguments').getArgs  
return p._main(args)  
end  

return p