Module:Tdoc

From Disney•Pixar CARS Wiki
Jump to navigation Jump to search
local p = {}
--------------------
local split = table.concat
local push = table.insert
--------------------
local mwTitle = mw.title.getCurrentTitle()
local pagename = mwTitle.text
local fullpagename = mwTitle.prefixedText
------------
local getArgs = require( 'Module:Arguments' ).getArgs
local wiki = require( 'Module:WikitextUtils' )
local HtmlRawElement = wiki.rawElementt
local QuotesStr = wiki.QuotesStr
local makeWikilink = wiki.makeWikilink
--------------------
--
-- "params" relation makes this difficult to return cleanly
local defaultSkeletonFields = {}
--
-- "ingroup" tag for behavior switches
local funcGroup = ''
--
-- Module: Tdoc - template documentation generator
--------------------
local tagList = mw.loadData( 'Module:Tdoc/tags' )
-- 
--------------------
local docTypeClasses = {
	['Template'] = {
		title = 'Template',
		format = 'Template:FuncName',
	},
	['Parser functions'] = {
		title = 'Hook',
		category = 'Parser function hooks',
		format = 'FuncName',
	},
	['Parser extension tags'] = {
		title = 'Tag',
		category = 'Parser extension tags',
		format = '<FuncName>',
	},
}

-- /*
--  * @return string Current running version of Lua on this server.
--  * @see https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#_VERSION
--  */
function p.getLuaVersion()
    return _VERSION
end

-- /**
-- * @param int ns // namespace number
-- * @param string page // full page name
-- * @return bool, array // default cat or ingroup, type config
-- */
--------------------
function getTypeInfo( ns, page )
	if ns == 10 then
        return false, docTypeClasses['Template']
	elseif ns == 12 then --help
        return true, docTypeClasses[page]
    end
end

-- /**
-- * @param string arg // tag + value pair to split
-- * @return string, string // tag name, tag value
-- */
--------------------
function splitTagKey( arg )
    return string.match( arg, '^@(%S+)%s+(.+)' )
end

-- /**
-- * make a simple <dl> list w/ CSS class and full title
-- * 
-- * @param string part // wikitext variable to retrieve
-- * @param string class // CSS class name
-- * @param string content // content string to process
-- * @return string // formatted HTML element
-- */
function makeDlList( tag, class, content, title )
    return HtmlRawElement( 'dl', { ['class'] = ( class or '' ) .. tag },
	   HtmlRawElement( 'dt', {}, title )
	.. HtmlRawElement( 'dd', {}, content )
	)
end

-- /**
-- * prepend sub-headers for each of the main {{tdoc}} fields.
-- * 
-- * @param string tag // name of tag group to process
-- * @param array content // instances of the respective tag
-- * @return string // formatted HTML element
-- */
function makeSubSection( tag, content, ns )
	if string.match( tag, "^user%d" ) then
		local tempContentFormat
		if content[1] == 'Accepted values' then
			tempContentFormat = content[2]
		else
			tempContentFormat = SyntaxHighlight( 'text', content[2] )
		end
    	return makeDlList( tag, '', tempContentFormat, content[1] )
    end
    local tagCheck = tagList[tag]
    local class = nil
    if tagCheck ~= nil then
        class = tagCheck.format
        title = tagCheck.title
    end
    if class == 'section' then
		return makeDlList( tag, 'section ', split ( content, '<br/>' ), title )
    elseif class == 'params' then
        return makeDlList( tag, '', makeParamsRows( tag, content ), title )
    elseif class == 'comment' then
        return makeDlList( tag, '', split ( content ), title )
	elseif class == nil then
        return HtmlRawElement( 'p', {}, content )
	elseif class == 'transclude' and ns == 10 then
		local categories = {}
		for i, item in ipairs( content ) do
			funcGroup = item --save outside
		    push( categories, '[[Category:' .. item .. ' templates]]' )
		end
		return split( categories )
	else return ''
	end
end

-- /**
-- * Process parameters for 'param', 'throws' tags
-- * 
-- * @param string key // tag name
-- * @returns string // HTML table output
-- */
function makeParamsRows( key, rows )
	local tag = tagList[key]
	local subParams = tag.subparams
	local pattern = { '^' }
    for i = 1, #subParams do
        push( pattern, '(%S+)%s+' )
    end
    pattern = split( pattern, '' ) .. '(.+)'
	local paramRows = {}
	for r, row in ipairs( rows ) do
    ------
    --temp. replacement for concat issue
    if key == 'param' then
        row = { string.match( row, '^(%S+)%s+(%S+)%s+(.+)' ) }
    elseif key == 'throws' then
    	row = { string.match( row, '^(%S+)%s+(.+)' ) }
    end
    ------
		local paramCells = {}
		for f, field in ipairs( subParams ) do
		    local value = row[f]
		    if key == 'param' and field == 'name' then
		    	local param, default = string.match( value, '(%S+)¦(%S+)' )
		    	value = param or value
		    	local rawName = string.gsub( value, '%$', '' )
		        push( defaultSkeletonFields,
		        	'|' .. rawName .. '=' .. ( default or '' ) )
		    end			
			paramCells[f] = HtmlRawElement( 'td', {
				['class'] = 'param' .. field,
		    }, value or 'null' )
		end
		paramRows[r] = HtmlRawElement( 'tr', {}, split( paramCells ) )
	end
	return HtmlRawElement( 'table', {
		['class'] = tag.key or key,
	}, split( paramRows ) )
end

-- /**
--  * @param object frame
--  */
function p.Main( frame )
	local ogTitle = getArgs( frame ).title
    local parentTitle = mw.title.new( ogTitle )
    thisPageUsing = {}
    thisPageOrder = {}
    for keyName, _ in pairs( tagList ) do
        thisPageUsing[keyName] = {}
    end
    local args = getArgs( frame:getParent(), {
    	removeBlanks = false
    } )
    for i, arg in ipairs( args ) do
    	if string.match( arg, '%S+' ) then
        	local tagName, tagContent = splitTagKey( arg )
        	if tagName == nil then
        		local fullblock = "plaintext" .. tonumber(i)
        		thisPageUsing['fullblock'] = arg
        	    push( thisPageOrder, 'fullblock' )
        	elseif tagName == 'par' then
        		local customKeyName = "user" .. tostring( i )
        		local _, tagUserContent = splitTagKey( args[i + 1] )
        		-- maybe loop til != nil
        		thisPageUsing[customKeyName] = { tagContent, tagUserContent }
        		push( thisPageOrder, customKeyName )
        		args[i + 1] = '' -- nil will break
        	elseif tagList[tagName] ~= nil then
        	    if next( thisPageUsing[tagName] ) == nil then
        		    push( thisPageOrder, tagName )
        	    end
        	    push( thisPageUsing[tagName], tagContent )        	
        	end
        end
    end
    for i, key in ipairs( thisPageOrder ) do
   	    thisPageOrder[i] = makeSubSection( key, thisPageUsing[key], parentTitle.namespace )
    end
    local out = p.outputContainer( frame, thisPageOrder, parentTitle )
    return frame:preprocess( out )
end


function upperCheck( name )
	--probably gets treated as template
	--maybe just ingroups
	local out = mw.getCurrentFrame()
	local funcCall = string.upper( name )
	local funcTest = out:preprocess( '{{' .. funcCall .. '}}' )
    if mw.ustring.find( funcTest, 'Template' ) == nil then
	-- ~= out:preprocess( '[[Template:' .. funcCall .. ']]' ) then
	    return true
	end
	------
--  local varGroups = { 'Page names', 'Statistics' }
--  for i, groupName in ipairs( varGroups ) do
--      if group == groupName then return true end
--  end
end

function printSkelParams( params )
    return '\n' .. split( params, '\n' ) .. '\n'
end

function makeSkeleton( funcType, funcName )
	if funcType == 'Template' then
	    skelParams = printSkelParams( defaultSkeletonFields )
	elseif funcType == 'Hook' then
		if upperCheck( funcName ) == true then
		    funcName = string.upper( funcName )
		else
		    funcName = '#' .. funcName .. ':'
		    if #defaultSkeletonFields then
		    	local firstParam = string.gsub( defaultSkeletonFields[1], '|', ' ' )
		    	table.remove( defaultSkeletonFields, 1 )
		    	skelParams = firstParam .. printSkelParams( defaultSkeletonFields )
		    end
		end
	end
    return HtmlRawElement( 'pre', {},
    	'{{' .. funcName .. ( skelParams or '' ) .. '}}'
    )
end

function p.outputContainer( frame, thisPageOrder, parentTitle )
    local options = '[[Help:Template documentation|Help]]' --getTemplateStyles( args["TemplateStyles"] or '' )
    local baseCat, docClass = getTypeInfo( parentTitle.namespace, parentTitle.rootText )
    local funcName = mwTitle.subpageText
    local docHeader = subTable( { ['class'] = 'header-info-table' }, {
    	string.gsub( docClass.format, 'FuncName', funcName ),
    	HtmlRawElement( 'div', { ['class'] = 'prenomargin' },
    		makeSkeleton( docClass.title, funcName ) ),
 --   	'<div class="prenomargin"><pre>' .. skeleton .. '</pre></div>',    	
    	subTable( {}, { options } )
    })
    local usesQuery = frame:preprocess( '{{#dpl:'
    	.. '\n|uses=' .. fullpagename
        .. '\n|namespace=Template'
    	.. '\n|noresultsheader=empty'
    	.. '\n}}' )
    if usesQuery ~= 'empty' then
    	push( thisPageOrder, HtmlRawElement( 'p', {}, 'Used by ' .. usesQuery ) )
    end
    --------
    local boxParts = HtmlRawElement( 'div', {
    	['class'] = 'template-doc-header',
    	['id'] = docClass.title,
    }, docHeader )
    .. HtmlRawElement( 'div', { ['class'] = 'template-doc-body' }, split( thisPageOrder ) )
    if baseCat == true then
    	baseCat = docClass.category
    	baseCatLink = makeWikilink( 'Category:' .. baseCat, funcName )
    else
    	baseCatLink = ''
    end
    return TemplateStyles( 'Tdoc/styles.css' )
--    .. HtmlRawElement( 'h2', {}, docClass.title .. " Documentation" )
    .. HtmlRawElement( 'div', {
    	['class'] = 'template-doc',
    }, boxParts )
    .. baseCatLink
end


-- /**
-- * DynamicPageList parser function
-- * 
-- * @param array templateParams // [key]=value pairs for arguments
-- * @return string (non-parsed)
-- */
function DynamicPageList( title, templateParams )
	templateParams['format'] = title .. ' ,[[%PAGE%|%TITLE%]]&#44; ,,'
	for key, value in pairs( templateParams ) do
		push( templateParams, '|' .. key .. '=' .. value )
		templateParams[key] = nil
	end
	return '<p>' .. '{{#dpl:\n'
	.. split( templateParams, '\n' )
	.. '\n}}' .. '</p>'
end

-- /**
-- * add TemplateStyles sheets if existing
-- * 
-- * @param string src
-- * @return string
-- */
function getTemplateStyles( arg, value )
    if arg ~= nil then
    	if arg == '' then
            return TemplateStyles( fullpagename .. '/styles.css' )
    	else
    		return TemplateStyles( arg )
        end
    end
end

function TemplateStyles( src )
	return '<templatestyles src=' .. QuotesStr( src ) .. '/>'
end

function SyntaxHighlight( lang, code )
	return '<syntaxhighlight lang=' .. lang .. '>'
	.. code .. '</syntaxhighlight>'
end

-- /**
-- * Bread-and-butter table generator
-- * 
-- * @param array tableCells
-- * @return string
-- */
function makeRawTableRow( tableCells )
	for i, tableCell in ipairs( tableCells ) do
		tableCells[i] = HtmlRawElement( 'td', {}, tableCell )
	end
	return HtmlRawElement( 'tr', {}, split( tableCells ) )
end

function subTable( attribs, cells )
	return HtmlRawElement( 'table', attribs, makeRawTableRow( cells ) )
end

-- /*
-- return string // formatted doc table w/ tag names and description
-- */
function p.listTagDescriptions( frame )
	local docRows = { HtmlRawElement( 'tr', {},
        HtmlRawElement( 'th', {}, 'Tag Name' )
        .. HtmlRawElement( 'th', {}, 'Parameters' )
        .. HtmlRawElement( 'th', {}, 'Description' )
	)}
    local docOrder = { 'todo', 'var', 'see', 'source', 'ingroup', 'param',
        'return', 'throws', 'author' }
    for _, tagName in ipairs( docOrder ) do
    	local docCells = {}
    	local docTag = tagList[tagName]
    	docCells[1] = '<code>@' .. tagName .. '</code>'
    	docCells[2] = formatSubParams( docTag.subparams or { 'info' } )
    	docCells[3] = docTag.description
    	push( docRows, makeRawTableRow( docCells ) )
    end
    return frame:preprocess( HtmlRawElement( 'table', {
    	['class'] = 'wikitable',
    }, split( docRows ) ))
end

function formatSubParams( subParams )
--   if subParams ~= nil then
        local subParamsText = {}
        for i, subParam in ipairs( subParams ) do
    	    subParamsText[i] = '$' .. subParam
        end
        return split( subParamsText, ' ' )
--    end
end

return p