İçeriğe atla

Modül:Docbunto/renderer

Deltarune Wiki sitesinden

Doclet renderer for Docbunto taglet data.

Documentation

Package function

renderer(data, frame, modname) (function)
Doclet renderer for Docbunto taglet data.
Parameters:
  • data Taglet documentation data. (table)
  • frame Scribunto frame object. (Frame)
  • modname Module page name. (string)
Returns: Wikitext documentation output. (string)

Private items

type_reference(item) (function • local)
Doclet type reference preprocessor. Formats types with links to the Lua reference manual.
Parameter: item Item documentation data. (table)
render_item(stream, item, modname) (function • local)
Doclet item renderer.
Parameters:
  • stream Wikitext documentation stream. (table)
  • item Item documentation data. (table)
  • modname Module page name. (string)
render_tag(stream, name, tag) (function • local)
Doclet tag renderer.
Parameters:
  • stream Wikitext documentation stream. (table)
  • name Item tag name. (string)
  • tag Item tag data. (table)
function_name(item) (function • local)
Doclet function preprocessor. Formats item name as a function call with top-level arguments.
Parameter: item Item documentation data. (table)
variable_prefix(item) (function • local)
Doclet parameter/field subitem preprocessor. Indents and wraps variable prefix with code tag.
Parameter: item Item documentation data. (table)
usage_highlight(item) (function • local)
Doclet usage subitem preprocessor. Formats usage example with <syntaxhighlight> tag.
Parameter: item Item documentation data. (table)
error_line(item) (function • local)
Doclet error subitem preprocessor. Formats line numbers ({#}) in error tag values.
Parameter: item Item documentation data. (table)
--- Doclet renderer for Docbunto taglet data.
--  @script             renderer
--  @author             [[dev:User:8nml]]
--  @author             [[wikipedia:User:Awesome Aasim]]
--  @param              {table} data Taglet documentation data.
--  @param              {Frame} frame Scribunto frame object.
--  @param              {string} modname Module page name.
--  @return             {string} Wikitext documentation output.
require('strict')

--  Module dependencies.
local references = mw.loadData('Module:Docbunto/references')
local dtags = mw.loadData('Module:Docbunto/tags')

--  Docbunto private logic.

local function get_tag_name(tag, num)
	if tag == 'error' then
		if num == 1 then
			return 'Error'
		else
			return 'Errors'
		end
	elseif tag == 'field' then
		if num == 1 then
			return 'Field'
		else
			return 'Fields'
		end
	elseif tag == 'fixme' then
		if num == 1 then
			return 'Bug'
		else
			return 'Bugs'
		end
	elseif tag == 'note' then
		if num == 1 then
			return 'Note'
		else
			return 'Notes'
		end
	elseif tag == 'param' then
		if num == 1 then
			return 'Parameter'
		else
			return 'Parameters'
		end
	elseif tag == 'return' then
		return 'Returns'
	elseif tag == 'see' then
		return 'See also'
	elseif tag == 'todo' then
		return 'TODO'
	elseif tag == 'usage' then
		return 'Usage'
	elseif tag == 'warning' then
		if num == 1 then
			return 'Warning'
		else
			return 'Warnings'
		end
	end
end

--- Doclet type reference preprocessor.
--  Formats types with links to the [[mw:Extension:Scribunto/Lua reference manual|Lua reference manual]].
--  @function           type_reference
--  @param              {table} item Item documentation data.
--  @local
local function type_reference(item)
	if item.value and item.value:match('^%S+') == '<code>...</code>' then
		item.value = item.value:gsub('^(%S+)', mw.text.tag{
			name = 'code',
			content = '[[mw:Extension:Scribunto/Lua reference manual#varargs|...]]'
		})
	end

	if not item.type then
		return
	end

	item.type = item.type:gsub(' ', '\26')
	local space_ptn = '[;|][%s\26]*'
	local types, t = mw.text.split(item.type, space_ptn)
	local spaces = {}
	for space in item.type:gmatch(space_ptn) do
		table.insert(spaces, space)
	end

	for index, type in ipairs(types) do
		t = types[index]
		local data = references.types[type]
		local name = data and data.name or t
		if data then
			types[index] = '[[' .. data.link .. '|' .. name .. ']]'
		elseif not t:find('^line') and not dtags._generic_tags[t] then
			types[index] = '[[#' .. t .. '|' .. name .. ']]'
		end
	end

	for index, space in ipairs(spaces) do
		types[index] = types[index] .. space
	end

	item.type = table.concat(types)
	if item.alias then
		mw.log(item.type)
	end
	item.type = item.type:gsub('\26', ' ')
end

--- Doclet item renderer.
--  @function           render_item
--  @param              {table} stream Wikitext documentation stream.
--  @param              {table} item Item documentation data.
--  @param              {string} modname Module page name.
--  @local
local function render_item(stream, item, modname)
	local item_id = item.alias or item.name
	local item_name = item.alias or item.name

	type_reference(item)

	local item_type = item.type

	for _, name in ipairs(dtags._subtype_hierarchy) do
		if item.tags[name] then
			item_type = item_type .. '&nbsp;• ' .. name
		end
	end
	item_type = ' (' .. item_type .. ')'

	if modname == mw.title.getCurrentTitle().fullText then
		stream:wikitext(';[[#L-' .. item.lineno .. '|<code id="' .. item_id .. '">' ..  item_name .. '</code>]]' .. item_type):newline()
	else
		stream:wikitext(';[[' .. modname .. '#L-' .. item.lineno .. '|<code id="' .. item_id .. '">' ..  item_name .. '</code>]]' .. item_type):newline()
	end
	if (#(item.summary or '') + #item.description) ~= 0 then
		local separator = #(item.summary or '') ~= 0 and #item.description ~= 0
			and (item.description:find('^[{:#*]+%s+') and '\n' or ' ')
			or  ''
		local intro = (item.summary or '') .. separator .. item.description
		stream:wikitext(':' .. intro:gsub('\n([{:#*])', '\n:%1'):gsub('\n\n([^=])', '\n:%1')):newline()
	end
end

--- Doclet tag renderer.
--  @function           render_tag
--  @param              {table} stream Wikitext documentation stream.
--  @param              {string} name Item tag name.
--  @param              {table} tag Item tag data.
--  @local
local function render_tag(stream, name, tag)
	if tag.value then
		type_reference(tag)
		local tag_name = get_tag_name(name, 1)
		stream:wikitext(':<b>' ..  tag_name .. '</b>: ' .. mw.text.trim(tag.value):gsub('\n([{:#*])', '\n:%1'))

		if tag.value:find('\n[{:#*]') and (tag.type or (tag.modifiers or {})['opt']) then
			stream:newline():wikitext(':')
		end
		if tag.type and (tag.modifiers or {})['opt'] then
			stream:wikitext(' (' .. tag.type .. '; optional)')
		elseif tag.type then
			stream:wikitext(' (' .. tag.type .. ')')
		elseif (tag.modifiers or {})['opt'] then
			stream:wikitext(' (optional)')
		end

		stream:newline()

	else
		local tag_name = get_tag_name(name, #tag)
		stream:wikitext(':<b>' .. tag_name .. '</b>: '):newline()

		for _, tag_el in ipairs(tag) do
			type_reference(tag_el)
			stream:wikitext(':*' .. tag_el.value:gsub('\n([{:#*])', '\n:*%1'))

			if tag_el.value:find('\n[{:#*]') and (tag_el.type or (tag_el.modifiers or {})['opt']) then
				stream:newline():wikitext(':*' .. (tag_el.value:match('^[*:]+') or ''))
			end

			if tag_el.type and (tag_el.modifiers or {})['opt'] then
				stream:wikitext(' (' .. tag_el.type .. '; optional)')
			elseif tag_el.type then
				stream:wikitext(' (' .. tag_el.type .. ')')
			elseif (tag_el.modifiers or {})['opt'] then
				stream:wikitext(' (optional)')
			end

			stream:newline()
		end
	end
end

--- Doclet function preprocessor.
--  Formats item name as a function call with top-level arguments.
--  @function           function_name
--  @param              {table} item Item documentation data.
--  @local
local function function_name(item)
	local target = item.alias and 'alias' or 'name'

	item[target] = item[target] .. '('

	if
		item.tags['param'] and
		item.tags['param'].value and
		not item.tags['param'].value:find('^[%w_]+[.[]')
	then
		if (item.tags['param'].modifiers or {})['opt'] then
			item[target] = item[target] .. '<span style="opacity: 0.65;">'
		end

		item[target] = item[target] .. item.tags['param'].value:match('^(%S+)')

		if (item.tags['param'].modifiers or {})['opt'] then
			item[target] = item[target] .. '</span>'
		end

	elseif item.tags['param'] then
		for index, tag in ipairs(item.tags['param']) do
			if not tag.value:find('^[%w_]+[.[]') then
				if (tag.modifiers or {})['opt'] then
					item[target] = item[target] .. '<span style="opacity: 0.65;">'
				end

				item[target] = item[target] .. (index > 1 and ', ' or '') .. tag.value:match('^(%S+)')

				if (tag.modifiers or {})['opt'] then
					item[target] = item[target] .. '</span>'
				end
			end
		end
	end

	item[target] = item[target] .. ')'
	return item
end

--- Doclet parameter/field subitem preprocessor.
--  Indents and wraps variable prefix with <code>code</code> tag.
--  @function           variable_prefix
--  @param              {table} item Item documentation data.
--  @local
local function variable_prefix(item)
	local indent_level, indentation

	if item.value then
		indent_level = item.value:match('^%S+') == '...'
			and 0
			or  select(2, item.value:match('^%S+'):gsub('[.[]', ''))
		indentation = ('*'):rep(indent_level)
		item.value = indentation .. item.value:gsub('^(%S+)', '<code>%1</code>')

	elseif item then
		for _, item_el in ipairs(item) do
			variable_prefix(item_el)
		end
	end
	return item
end

--- Doclet usage subitem preprocessor.
--  Formats usage example with <code>&lt;syntaxhighlight></code> tag.
--  @function           usage_highlight
--  @param              {table} item Item documentation data.
--  @local
local function usage_highlight(item)
	if item.value then
		item.value = mw.text.trim(item.value)
		item.value =
			'<syntaxhighlight lang="lua"'.. (item.value:find('\n') and '' or ' inline') ..'>' ..
				item.value ..
			'</syntaxhighlight>'

	elseif item then
		for _, item_el in ipairs(item) do
			usage_highlight(item_el)
		end
	end
	return item
end

--- Doclet error subitem preprocessor.
--  Formats line numbers (<code>{#}</code>) in error tag values.
--  @function           error_line
--  @param              {table} item Item documentation data.
local function error_line(item)
	if item.name then
		local line

		for mod in pairs(item.modifiers or {}) do
			if mod:find('^%d+$') then line = mod end
		end

		if line then
			if item.type then
				item.type = item.type .. '; line ' .. line
			else
				item.type = 'line ' .. line
			end
		end

	elseif item then
		for _, item_el in ipairs(item) do
			error_line(item_el)
		end
	end
	return item
end

--  Docbunto package items.

return function(data, frame, modname)
	local documentation = mw.html.create()
	local namespace = '^' .. mw.site.namespaces[828].name .. ':'
	local codepage = data.filename:gsub(namespace, '')

	-- Documentation lede.
	if (#(data.summary or '') + #data.description) ~= 0 then
		local separator = #data.summary ~= 0 and #data.description ~= 0
			and (data.description:find('^[{|!}:#*=]+[%s-}]+') and '\n\n' or ' ')
			or  ''
		local intro = (data.summary or '') .. separator .. data.description
		intro = frame:preprocess(intro:gsub('^(' .. codepage .. ')', '<b>%1</b>'))
		documentation:wikitext(intro):newline():newline()
	end

	-- Start code documentation.
	local codedoc = mw.html.create()
	local function_module = data.tags['param'] or data.tags['return']
	local header_type =
		documentation.type == 'classmod'
			and 'Package class'
		or  function_module
			and 'Package function'
			or  'Package items'
	if (function_module or #data.items ~= 0) then
		codedoc:wikitext('== Documentation =='):newline()
		codedoc:wikitext('=== ' .. header_type .. ' ==='):newline()
	end

	-- Function module support.
	if function_module then
		data.type = 'function'
		data.description = ''
		render_item(codedoc, function_name(data), modname)

		if data.tags['param'] then
			render_tag(codedoc, 'param', variable_prefix(data.tags['param']))
		end
		if data.tags['error'] then
			render_tag(codedoc, 'error', error_line(data.tags['error']))
		end
		if data.tags['return'] then
			render_tag(codedoc, 'return', data.tags['return'])
		end
	end

	-- Render documentation items.
	local other_header = false
	local private_header = false
	local inaccessible
	for _, item in ipairs(data.items) do
		inaccessible = item.tags['local'] or item.tags['private']
		if
			not other_header and item.type ~= 'section' and item.type ~= 'type' and
			not item.export and not item.hierarchy and not inaccessible
		then
			codedoc:wikitext('=== Other items ==='):newline()
			other_header = true
		end
		if not private_header and inaccessible then
			codedoc:wikitext('=== Private items ==='):newline()
			private_header = true
		end

		if item.type == 'section' then
			codedoc:wikitext('=== ' .. mw.ustring.gsub(item.summary or item.alias or item.name, '[.։。।෴۔።]$', '') .. ' ==='):newline()
			if #item.description ~= 0 then
				codedoc:wikitext(item.description):newline()
			end

		elseif item.type == 'type' then
			codedoc:wikitext('=== <code>' .. (item.alias or item.name) .. '</code> ==='):newline()
			if (#(item.summary or '') + #item.description) ~= 0 then
				local separator = #(item.summary or '') ~= 0 and #item.description ~= 0
					and (item.description:find('^[{:#*=]+[%s-}]+') and '\n\n' or ' ')
					or  ''
				codedoc:wikitext((item.summary or '') .. separator .. item.description):newline()
			end

		elseif item.type == 'function' then
			render_item(codedoc, function_name(item), modname)
			if item.tags['param'] then
				render_tag(codedoc, 'param', variable_prefix(item.tags['param']))
			end
			if item.tags['error'] then
				render_tag(codedoc, 'error', error_line(item.tags['error']))
			end
			if item.tags['return'] then
				render_tag(codedoc, 'return', item.tags['return'])
			end

		elseif
			item.type == 'table' or
			item.type ~= nil and (
				item.type:find('^member') or
				item.type:find('^variable')
			) and (item.alias or item.name)
		then
			render_item(codedoc, item, modname)
			if item.tags['field'] then
				render_tag(codedoc, 'field', variable_prefix(item.tags['field']))
			end
		end

		if item.type ~= 'section' and item.type ~= 'type' then
			if item.tags['note'] then
				render_tag(codedoc, 'note', item.tags['note'])
			end
			if item.tags['warning'] then
				render_tag(codedoc, 'warning', item.tags['warning'])
			end
			if item.tags['fixme'] then
				render_tag(codedoc, 'fixme', item.tags['fixme'])
			end
			if item.tags['todo'] then
				render_tag(codedoc, 'todo', item.tags['todo'])
			end
			if item.tags['usage'] then
				render_tag(codedoc, 'usage', usage_highlight(item.tags['usage']))
			end
			if item.tags['see'] then
				render_tag(codedoc, 'see', item.tags['see'])
			end
		end
	end

	-- Render module-level annotations.
	local header_text
	for _, tag_name in ipairs{'warning', 'fixme', 'note', 'todo', 'see'} do
		if data.tags[tag_name] then
			header_text =  get_tag_name(tag_name, data.tags[tag_name].value and 1 or 2)
			header_text = '== ' .. header_text .. ' =='
			codedoc:newline():wikitext(header_text):newline()
			if data.tags[tag_name].value then
				codedoc:wikitext(data.tags[tag_name].value):newline()
			else
				for _, tag_el in ipairs(data.tags[tag_name]) do
					codedoc:wikitext('* ' .. tag_el.value):newline()
				end
			end
		end
	end

	-- Code documentation formatting.
	codedoc = frame:preprocess(tostring(codedoc))

	documentation:wikitext(codedoc)
	return tostring(documentation)
end
Konu ekle