Модуль:Трансключэньне
Дакумэнтацыю да гэтага модуля можна стварыць у Модуль:Трансключэньне/Дакумэнтацыя
-- Модуль:Трансключэньне — рухавічок уключэньня шаблёнаў агульнага прызначэньня
-- Дакумэнтацыя і арыгінальная вэрсія: https://en.wikipedia.org/wiki/Module:Transcluder
-- Аўтары: Удзельнік:Sophivorus, Удзельнік:Certes & іншыя
-- Ліцэнзія: CC-BY-SA-3.0
local p = {}
-- Дапаможная функцыя для праверкі ісьцінных і фальшывых значэньняў
-- @зрабіць неяк інтэрнацыяналізаваць
local function truthy(value)
if not value or value == '' or value == 0 or value == '0' or value == 'мана' or value == 'не' or value == 'no' then
return false
end
return true
end
-- Дапаможная функцыя для супадзеньня ў сьпісе рэгулярных выразаў
-- Прыклад: match pre..list[1]..post or pre..list[2]..post or ...
local function matchAny(text, pre, list, post, init)
local match = {}
for i = 1, #list do
match = { mw.ustring.match(text, pre .. list[i] .. post, init) }
if match[1] then return unpack(match) end
end
return nil
end
-- Падобная да matchAny, але для спасылак Катэгорыя/Файл зь меншымі запамарокамі
local function matchAnyLink(text, list)
local match
for _, v in ipairs(list) do
match = string.match(text, '%[%[%s*' .. v .. '%s*:.*%]%]')
if match then break end
end
return match
end
-- Дапаможная функцыя для вылучэньня радку, які будзе выкарыстоўвацца ў рэгулярных выразах
local function escapeString(str)
return string.gsub(str, '[%^%$%(%)%.%[%]%*%+%-%?%%]', '%%%0')
end
-- Дапаможная функцыя для выразаньня радку з тэксту
local function removeString(text, str)
local pattern = escapeString(str)
if #pattern > 9999 then -- радкі, даўжэйшыя за 10000 байтаў, нельга выкарыстоўваць у рэг. выразах
pattern = escapeString(mw.ustring.sub(str, 1, 999)) .. '.-' .. escapeString(mw.ustring.sub(str, -999))
end
return string.gsub(text, pattern, '')
end
-- Дапаможная функцыя для пераўтварэньня сьпісу лікаў ці дыяпазонаў, аддзеленых
-- коскамі, у сьпіс лягічных значэньняў
-- @param flags сьпіс лікаў ці дыяпазонаў, аддзеленых коскамі, напрыклад '1,3-5'
-- @return перавод з цэлых да лягічных, напрыклад {1=true,2=false,3=true,4=true,5=true}
-- @return Boolean пазначае, ці трэба лічыць сьцяжкі чорным сьпісам, ці не
local function parseFlags(value)
local flags = {}
local blacklist = false
if not value then return nil, false end
if type(value) == 'number' then
if value < 0 then
value = -value
blacklist = true
end
flags = { [value] = true }
elseif type(value) == 'string' then
if string.sub(value, 1, 1) == '-' then
blacklist = true
value = string.sub(value, 2)
end
local ranges = mw.text.split(value, ',') -- split ranges: '1,3-5' to {'1','3-5'}
for _, range in pairs(ranges) do
range = mw.text.trim(range)
local min, max = mw.ustring.match(range, '^(%d+)%s*[-–—]%s*(%d+)$') -- '3-5' to min=3 max=5
if not max then min, max = string.match(range, '^((%d+))$') end -- '1' to min=1 max=1
if max then
for i = min, max do flags[i] = true end
else
flags[range] = true -- if we reach this point, the string had the form 'a,b,c' rather than '1,2,3'
end
end
-- List has the form { [1] = false, [2] = true, ['c'] = false }
-- Convert it to { [1] = true, [2] = true, ['c'] = true }
-- But if ANY value is set to false, treat the list as a blacklist
elseif type(value) == 'table' then
for i, v in pairs(value) do
if v == false then blacklist = true end
flags[i] = true
end
end
return flags, blacklist
end
-- Дапаможная функцыя для праверкі, ці адпавядае значэньне любому з дадзеных сьцяжкоў
local function matchFlag(value, flags)
if not value then return false end
value = tostring(value)
local lang = mw.language.getContentLanguage()
local lcvalue = lang:lcfirst(value)
local ucvalue = lang:ucfirst(value)
for flag in pairs(flags) do
if value == tostring(flag)
or lcvalue == flag
or ucvalue == flag
or ( not tonumber(flag) and mw.ustring.match(value, flag) ) then
return true
end
end
end
-- Дапаможная функцыя to convert template arguments into an array of options fit for get()
local function parseArgs(frame)
local args = {}
for key, value in pairs(frame:getParent().args) do args[key] = value end
for key, value in pairs(frame.args) do args[key] = value end -- args from Lua calls have priority over parent args from template
return args
end
-- Error handling function
-- Throws a Lua error or returns an empty string if error reporting is disabled
local function throwError(key, value)
local TNT = require('Модуль:TNT')
local ok, message = pcall(TNT.format, 'I18n/Модуль:Трансключэньне.tab', 'error-' .. key, value)
if not ok then message = key end
error(message, 2)
end
-- Функцыя апрацоўкі памылак
-- Вяртае прыдатную для вікі памылку або пусты радок, калі паведамленьні пра памылкі адключаныя
local function getError(key, value)
local TNT = require('Модуль:TNT')
local ok, message = pcall(TNT.format, 'I18n/Модуль:Трансключэньне.tab', 'error-' .. key, value)
if not ok then message = key end
message = mw.html.create('div'):addClass('error'):wikitext(message)
return message
end
-- Дапаможная функцыя для атрыманьня лякалізаванай назвы прасторы і ўсіх ейных сынонімаў
-- @param name Кананічная назва прасторы, напрыклад 'Файл'
-- @return Лякальная назва прасторы і ўсе сынонімы, напрыклад {'Файл','Выява','File','Image'}
local function getNamespaces(name)
local namespaces = mw.clone(mw.site.namespaces[name].aliases) -- Clone because https://en.wikipedia.org/w/index.php?diff=1056921358
table.insert(namespaces, mw.site.namespaces[name].name)
table.insert(namespaces, mw.site.namespaces[name].canonicalName)
return namespaces
end
-- Атрымлівае вікітэкст старонкі, пераходзячы па перанакіраваньнях
-- Дадаткова вяртае назву старонкі альбо назву мэтавай старонкі, калі перайшлі па перанакіраваньні, а калі старонкі не знайшлі, тады false
-- Для старонак файлаў вяртае зьмест старонкі апісаньня файлу
local function getText(page, noFollow)
local title = mw.title.new(page)
if not title then return false, false end
local target = title.redirectTarget
if target and not noFollow then title = target end
local text = title:getContent()
if not text then return false, title.prefixedText end
-- Remove <noinclude> tags
text = string.gsub(text, '<[Nn][Oo][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>.-</[Nn][Oo][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>', '') -- remove noinclude bits
-- Keep <onlyinclude> tags
if string.find(text, 'onlyinclude') then -- avoid expensive search if possible
text = text
:gsub('</onlyinclude>.-<onlyinclude>', '') -- remove text between onlyinclude sections
:gsub('^.-<onlyinclude>', '') -- remove text before first onlyinclude section
:gsub('</onlyinclude>.*', '') -- remove text after last onlyinclude section
end
return text, title.prefixedText
end
-- Атрымлівае запытаныя файлы з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param flags Дыяпазон файлаў для вяртаньня, напрыклад 2 або '1,3-5'. Каб вярнуць усе файлы, прапусьціце яго.
-- @return Пасьлядоўнасьць радкоў зь вікітэкстам запытаных файлаў.
-- @return Арыгінальны вікітэкст мінус запытаныя файлы.
local function getFiles(text, flags)
local files = {}
local flags, blacklist = parseFlags(flags)
local fileNamespaces = getNamespaces('Файл')
local name
local count = 0
for file in string.gmatch(text, '%b[]') do
if matchAnyLink(file, fileNamespaces) then
name = string.match(file, '%[%[[^:]-:([^]|]+)')
count = count + 1
if not blacklist and ( not flags or flags[count] or matchFlag(name, flags) )
or blacklist and flags and not flags[count] and not matchFlag(name, flags) then
table.insert(files, file)
else
text = removeString(text, file)
end
end
end
return files, text
end
-- Атрымлівае запытаныя табліцы з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param flags Дыяпазон табліц для вяртаньня, напрыклад 2 або '1,3-5'. Каб вярнуць усе табліцы, прапусьціце яго.
-- @return Пасьлядоўнасьць радкоў зь вікітэкстам запытаных табліц.
-- @return Арыгінальны вікітэкст мінус запытаныя табліцы.
local function getTables(text, flags)
local tables = {}
local flags, blacklist = parseFlags(flags)
local id
local count = 0
for t in string.gmatch('\n' .. text, '\n%b{}') do
if string.sub(t, 1, 3) == '\n{|' then
id = string.match(t, '\n{|[^\n]-id%s*=%s*["\']?([^"\'\n]+)["\']?[^\n]*\n')
count = count + 1
if not blacklist and ( not flags or flags[count] or flags[id] )
or blacklist and flags and not flags[count] and not flags[id] then
table.insert(tables, t)
else
text = removeString(text, t)
end
end
end
return tables, text
end
-- Атрымлівае запытаныя шаблёны з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param flags Дыяпазон шаблёнаў для вяртаньня, напрыклад 2 or '1,3-5'. Каб вярнуць усе шаблёны, прапусьціце яго.
-- @return Пасьлядоўнасьць радкоў зь вікітэкстам запытаных шаблёнаў.
-- @return Арыгінальны вікітэкст мінус запытаныя шаблёны.
local function getTemplates(text, flags)
local templates = {}
local flags, blacklist = parseFlags(flags)
local name
local count = 0
for template in string.gmatch(text, '{%b{}}') do
if string.sub(template, 1, 3) ~= '{{#' then -- skip parser functions like #if
name = mw.text.trim( string.match(template, '{{([^}|\n]+)') or "" ) -- get the template name
if name ~= "" then
count = count + 1
if not blacklist and ( not flags or flags[count] or matchFlag(name, flags) )
or blacklist and flags and not flags[count] and not matchFlag(name, flags) then
table.insert(templates, template)
else
text = removeString(text, template)
end
end
end
end
return templates, text
end
-- Атрымлівае запытаныя парамэтры шаблёну з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param flags Дыяпазон парамэтраў для вяртаньня, напрыклад 2 or '1,3-5'. Каб вярнуць усе парамэтры, прапусьціце яго.
-- @return Супастаўленьне назвы парамэтру і значэньня, НЕ Ў АРЫГІНАЛЬНЫМ ПАРАДКУ
-- @return Арыгінальны вікітэкст мінус запытаныя шаблёны.
-- @return Парадак, у якім разабраныя парамэтры.
local function getParameters(text, flags)
local parameters, parameterOrder = {}, {}
local flags, blacklist = parseFlags(flags)
local params, count, parts, key, value
for template in string.gmatch(text, '{%b{}}') do
params = string.match(template, '{{[^|}]-|(.*)}}')
if params then
count = 0
-- Часова замяніць вэртыкальныя рыскі ў падшаблёнах і спасылках, каб не заблытацца
for subtemplate in string.gmatch(params, '{%b{}}') do
params = string.gsub(params, escapeString(subtemplate), string.gsub(subtemplate, ".", {["%"]="%%", ["|"]="@@:@@", ["="]="@@_@@"}) )
end
for link in string.gmatch(params, '%b[]') do
params = string.gsub(params, escapeString(link), string.gsub(link, ".", {["%"]="%%", ["|"]="@@:@@", ["="]="@@_@@"}) )
end
for parameter in mw.text.gsplit(params, '|') do
parts = mw.text.split(parameter, '=')
key = mw.text.trim(parts[1])
if #parts == 1 then
value = key
count = count + 1
key = count
else
value = mw.text.trim(table.concat(parts, '=', 2))
end
value = string.gsub(string.gsub(value, '@@:@@', '|'), '@@_@@', '=')
if not blacklist and ( not flags or matchFlag(key, flags) )
or blacklist and flags and not matchFlag(key, flags) then
table.insert(parameterOrder, key)
parameters[key] = value
else
text = removeString(text, parameter)
end
end
end
end
return parameters, text, parameterOrder
end
-- Атрымлівае запытаныя сьпісы з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param flags Дыяпазон сьпісаў для вяртаньня, напрыклад 2 or '1,3-5'. Каб вярнуць усе сьпісы, прапусьціце яго.
-- @return Пасьлядоўнасьць радкоў зь вікітэкстам запытаных сьпісаў.
-- @return Арыгінальны вікітэкст мінус запытаныя сьпісы.
local function getLists(text, flags)
local lists = {}
local flags, blacklist = parseFlags(flags)
local count = 0
for list in string.gmatch('\n' .. text .. '\n\n', '\n([*#].-)\n[^*#]') do
count = count + 1
if not blacklist and ( not flags or flags[count] )
or blacklist and flags and not flags[count] then
table.insert(lists, list)
else
text = removeString(text, list)
end
end
return lists, text
end
-- Атрымлівае запытаныя параграфы з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param flags Дыяпазон параграфаў для вяртаньня, напрыклад 2 or '1,3-5'. Каб вярнуць усе параграфы, прапусьціце яго.
-- @return Пасьлядоўнасьць радкоў зь вікітэкстам запытаных параграфаў.
-- @return Арыгінальны вікітэкст мінус запытаныя параграфы.
local function getParagraphs(text, flags)
local paragraphs = {}
local flags, blacklist = parseFlags(flags)
-- Выдаліць не-параграфы
local elements
local temp = '\n' .. text .. '\n'
elements, temp = getLists(temp, 0) -- выдаліць сьпісы
elements, temp = getFiles(temp, 0) -- выдаліць файлы
temp = mw.text.trim((temp
:gsub('\n%b{} *\n', '\n%0\n') -- дадаць пропусты між табліцамі і блёкавымі шаблёнамі
:gsub('\n%b{} *\n', '\n') -- выдаліць табліцы і блёкавыя шаблёны
:gsub('\n==+[^=]+==+ *\n', '\n') -- выдаліць назвы разьдзелаў
))
-- Лічым, што рэшта — параграф
local count = 0
for paragraph in mw.text.gsplit(temp, '\n\n+') do
if mw.text.trim(paragraph) ~= '' then
count = count + 1
if not blacklist and ( not flags or flags[count] )
or blacklist and flags and not flags[count] then
table.insert(paragraphs, paragraph)
else
text = removeString(text, paragraph)
end
end
end
return paragraphs, text
end
-- Атрымлівае запытаныя катэгорыі з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param flags Дыяпазон катэгорый для вяртаньня, напрыклад 2 or '1,3-5'. Каб вярнуць усе катэгорыі, прапусьціце яго.
-- @return Пасьлядоўнасьць радкоў зь вікітэкстам запытаных катэгорый.
-- @return Арыгінальны вікітэкст мінус запытаныя катэгорыі.
local function getCategories(text, flags)
local categories = {}
local flags, blacklist = parseFlags(flags)
local categoryNamespaces = getNamespaces('Катэгорыя')
local name
local count = 0
for category in string.gmatch(text, '%b[]') do
if matchAnyLink(category, categoryNamespaces) then
name = string.match(category, '%[%[[^:]-:([^]|]+)')
count = count + 1
if not blacklist and ( not flags or flags[count] or matchFlag(name, flags) )
or blacklist and flags and not flags[count] and not matchFlag(name, flags) then
table.insert(categories, category)
else
text = removeString(text, category)
end
end
end
return categories, text
end
-- Атрымлівае запытаныя крыніцы з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param flags Дыяпазон крыніц для вяртаньня, напрыклад 2 or '1,3-5'. Каб вярнуць усе крыніцы, прапусьціце яго.
-- @return Пасьлядоўнасьць радкоў зь вікітэкстам запытаных крыніцаў.
-- @return Арыгінальны вікітэкст мінус запытаныя крыніцы.
local function getReferences(text, flags)
local references = {}
-- Remove all references, including citations, when 0 references are requested
-- This is kind of hacky but currently necessary because the rest of the code
-- doesn't remove citations like <ref name="Foo" /> if Foo is defined elsewhere
if flags and not truthy(flags) then
text = string.gsub(text, '<%s*[Rr][Ee][Ff][^>/]*>.-<%s*/%s*[Rr][Ee][Ff]%s*>', '')
text = string.gsub(text, '<%s*[Rr][Ee][Ff][^>/]*/%s*>', '')
return references, text
end
local flags, blacklist = parseFlags(flags)
local name
local count = 0
for reference in string.gmatch(text, '<%s*[Rr][Ee][Ff][^>/]*>.-<%s*/%s*[Rr][Ee][Ff]%s*>') do
name = string.match(reference, '<%s*[Rr][Ee][Ff][^>]*name%s*=%s*["\']?([^"\'>/]+)["\']?[^>]*%s*>')
count = count + 1
if not blacklist and ( not flags or flags[count] or matchFlag(name, flags) )
or blacklist and flags and not flags[count] and not matchFlag(name, flags) then
table.insert(references, reference)
else
text = removeString(text, reference)
if name then
for citation in string.gmatch(text, '<%s*[Rr][Ee][Ff][^>]*name%s*=%s*["\']?' .. escapeString(name) .. '["\']?[^/>]*/%s*>') do
text = removeString(text, citation)
end
end
end
end
return references, text
end
-- Атрымлівае першы разьдзел з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @return Вікітэкст першага разьдзелу.
local function getLead(text)
text = string.gsub('\n' .. text, '\n==.*', '')
text = mw.text.trim(text)
if not text then return throwError('пустыя-ўводзіны') end
return text
end
-- Атрымлівае запытаныя разьдзелы з дадзенага вікітэксту.
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param flags Дыяпазон разьдзелаў для вяртаньня, напрыклад 2 or '1,3-5'. Каб вярнуць усе разьдзелы, прапусьціце яго.
-- @return Пасьлядоўнасьць радкоў зь вікітэкстам запытаных разьдзелаў.
-- @return Арыгінальны вікітэкст мінус запытаныя разьдзелы.
local function getSections(text, flags)
local sections = {}
local flags, blacklist = parseFlags(flags)
local count = 0
local prefix, section, suffix
for title in string.gmatch('\n' .. text .. '\n==', '\n==+%s*([^=]+)%s*==+') do
count = count + 1
prefix, section, suffix = string.match('\n' .. text .. '\n==', '\n()==+%s*' .. escapeString(title) .. '%s*==+(.-)()\n==')
if not blacklist and ( not flags or flags[count] or matchFlag(title, flags) )
or blacklist and flags and not flags[count] and not matchFlag(title, flags) then
sections[title] = section
else
text = string.sub(text, 1, prefix) .. string.sub(text, suffix)
text = string.gsub(text, '\n?==$', '') -- remove the trailing \n==
end
end
return sections, text
end
-- Атрымлівае запытаны разьдзел ці цэтлік <section> з дадзенага вікітэксту (разам з падразьдзеламі).
-- @param text Абавязковы. Вікітэкст для разбору.
-- @param section Абавязковы. Назва разьдзелу, які трэба ўзяць (у вікітэксьце), напрыклад „Мінуўшчына“ ці „Гісторыя [[Атэны|Атэнаў]]“.
-- @return Wikitext of the requested section.
local function getSection(text, section)
section = mw.text.trim(section)
local escapedSection = escapeString(section)
-- Найперш праверым, ці адпавядае назва разьдзелу цэтліку <разьдзел>
if string.find(text, '<%s*[Рр]азьдзел%s+пачатак%s*=%s*["\']?%s*' .. escapedSection .. '%s*["\']?%s*/>') then -- па магчымасьці ўнікаем рэсурсаёмкага пошуку
text = mw.text.trim((text
:gsub('<%s*[Рр]азьдзел%s+канец=%s*["\']?%s*'.. escapedSection ..'%s*["\']?%s*/>.-<%s*[Рр]азьдзел%s+пачатак%s*=%s*["\']?%s*' .. escapedSection .. '%s*["\']?%s*/>', '') -- выдаліць тэкст унутры цэтлікаў разьдзелаў
:gsub('^.-<%s*[Рр]азьдзел%s+пачатак%s*=%s*["\']?%s*' .. escapedSection .. '%s*["\']?%s*/>', '') -- выдаліць тэкст перад першым цэтлікам разьдзелу
:gsub('<%s*[Рр]азьдзел%s+канец=%s*["\']?%s*'.. escapedSection ..'%s*["\']?%s*/>.*', '') -- выдаліць тэкст пасьля апошняга цэтліка разьдзелу
))
if text == '' then return throwError('пусты-цэтлік-разьдзелу', section) end
return text
end
local level, text = string.match('\n' .. text .. '\n', '\n(==+)%s*' .. escapedSection .. '%s*==.-\n(.*)')
if not text then return throwError('разьдзел-ня-знойдзены', section) end
local nextSection = '\n==' .. string.rep('=?', #level - 2) .. '[^=].*'
text = string.gsub(text, nextSection, '') -- выдаліць далейшыя разьдзелы з загалоўкамі таго ж ці вышэйшага ўзроўню
text = mw.text.trim(text)
if text == '' then return throwError('пусты-разьдзел', section) end
return text
end
-- Replace the first call to each reference defined outside of the text for the full reference, to prevent undefined references
-- Then prefix the page title to the reference names to prevent conflicts
-- that is, replace <ref name="Foo"> for <ref name="Title of the article Foo">
-- and also <ref name="Foo" /> for <ref name="Title of the article Foo" />
-- also remove reference groups: <ref name="Foo" group="Bar"> for <ref name="Title of the article Foo">
-- and <ref group="Bar"> for <ref>
-- @todo The current regex may fail in cases with both kinds of quotes, like <ref name="Darwin's book">
local function fixReferences(text, page, full)
if not full then full = getText(page) end
local refNames = {}
local refName
local refBody
local position = 1
while position < mw.ustring.len(text) do
refName, position = mw.ustring.match(text, '<%s*[Rr][Ee][Ff][^>]*name%s*=%s*["\']?([^"\'>]+)["\']?[^>]*/%s*>()', position)
if refName then
refName = mw.text.trim(refName)
if not refNames[refName] then -- make sure we process each ref name only once
table.insert(refNames, refName)
refName = escapeString(refName)
refBody = mw.ustring.match(text, '<%s*[Rr][Ee][Ff][^>]*name%s*=%s*["\']?%s*' .. refName .. '%s*["\']?[^>/]*>.-<%s*/%s*[Rr][Ee][Ff]%s*>')
if not refBody then -- the ref body is not in the excerpt
refBody = mw.ustring.match(full, '<%s*[Rr][Ee][Ff][^>]*name%s*=%s*["\']?%s*' .. refName .. '%s*["\']?[^/>]*>.-<%s*/%s*[Rr][Ee][Ff]%s*>')
if refBody then -- the ref body was found elsewhere
text = mw.ustring.gsub(text, '<%s*[Rr][Ee][Ff][^>]*name%s*=%s*["\']?%s*' .. refName .. '%s*["\']?[^>]*/?%s*>', mw.ustring.gsub(refBody, '%%', '%%%%'), 1)
end
end
end
else
position = mw.ustring.len(text)
end
end
page = string.gsub(page, '"', '') -- remove any quotation marks from the page title
text = mw.ustring.gsub(text, '<%s*[Rr][Ee][Ff][^>]*name%s*=%s*["\']?([^"\'>/]+)["\']?[^>/]*(/?)%s*>', '<ref name="' .. page .. ' %1"%2>')
text = mw.ustring.gsub(text, '<%s*[Rr][Ee][Ff]%s*group%s*=%s*["\']?[^"\'>/]+["\']%s*>', '<ref>')
return text
end
-- Replace the bold title or synonym near the start of the page by a link to the page
local function linkBold(text, page)
local lang = mw.language.getContentLanguage()
local position = mw.ustring.find(text, "'''" .. lang:ucfirst(page) .. "'''", 1, true) -- look for "'''Foo''' is..." (uc) or "A '''foo''' is..." (lc)
or mw.ustring.find(text, "'''" .. lang:lcfirst(page) .. "'''", 1, true) -- plain search: special characters in page represent themselves
if position then
local length = mw.ustring.len(page)
text = mw.ustring.sub(text, 1, position + 2) .. "[[" .. mw.ustring.sub(text, position + 3, position + length + 2) .. "]]" .. mw.ustring.sub(text, position + length + 3, -1) -- link it
else -- look for anything unlinked in bold, assumed to be a synonym of the title (e.g. a person's birth name)
text = mw.ustring.gsub(text, "()'''(.-'*)'''", function(a, b)
if not mw.ustring.find(b, "%[") and not mw.ustring.find(b, "%{") then -- if not wikilinked or some weird template
return "'''[[" .. page .. "|" .. b .. "]]'''" -- replace '''Foo''' by '''[[page|Foo]]'''
else
return nil -- instruct gsub to make no change
end
end, 1) -- "end" here terminates the anonymous replacement function(a, b) passed to gsub
end
return text
end
-- Remove non-free files.
-- @param text Required. Wikitext to clean.
-- @return Clean wikitext.
local function removeNonFreeFiles(text)
local fileNamespaces = getNamespaces('Файл')
local fileName
local fileDescription
local frame = mw.getCurrentFrame()
for file in string.gmatch(text, '%b[]') do
if matchAnyLink(file, fileNamespaces) then
fileName = 'Файл:' .. string.match(file, '%[%[[^:]-:([^]|]+)')
fileDescription, fileName = getText(fileName)
if fileName then
if not fileDescription or fileDescription == '' then
fileDescription = frame:preprocess('{{' .. fileName .. '}}') -- try Commons
end
if fileDescription and string.match(fileDescription, '[Nn]on%-free') then
text = removeString(text, file)
end
end
end
end
return text
end
-- Remove any self links
local function removeSelfLinks(text)
local lang = mw.language.getContentLanguage()
local page = escapeString(mw.title.getCurrentTitle().prefixedText)
local ucpage = lang:ucfirst(page)
local lcpage = lang:lcfirst(page)
text = text
:gsub('%[%[(' .. ucpage .. ')%]%]', '%1')
:gsub('%[%[(' .. lcpage .. ')%]%]', '%1')
:gsub('%[%[' .. ucpage .. '|([^]]+)%]%]', '%1')
:gsub('%[%[' .. lcpage .. '|([^]]+)%]%]', '%1')
return text
end
-- Remove all wikilinks
local function removeLinks(text)
text = text
:gsub('%[%[[^%]|]+|([^]]+)%]%]', '%1')
:gsub('%[%[([^]]+)%]%]', '%1')
:gsub('%[[^ ]+ ([^]]+)%]', '%1')
:gsub('%[([^]]+)%]', '%1')
return text
end
-- Remove HTML comments
local function removeComments(text)
text = string.gsub(text, '<!%-%-.-%-%->', '')
return text
end
-- Remove behavior switches, such as __NOTOC__
local function removeBehaviorSwitches(text)
text = string.gsub(text, '__[A-ZА-Я]+__', '')
return text
end
-- Remove bold text
local function removeBold(text)
text = string.gsub(text, "'''", '')
return text
end
-- Асноўная функцыя для модуляў
local function get(page, options)
if not options then options = {} end
-- Праверыць, што старонка існуе
if not page then return throwError('няма-старонкі') end
page = mw.text.trim(page)
if page == '' then return throwError('няма-старонкі') end
local page, hash, section = string.match(page, '([^#]+)(#?)(.*)')
local text, temp = getText(page, options.noFollow)
if not temp then return throwError('хібная-назва', page) end
page = temp
if not text then return throwError('няма-старонкі', page) end
local full = text -- захаваць поўны тэкст для fixReferences ніжэй
-- Узяць патрэбны разьдзел
if truthy(section) then
text = getSection(text, section)
elseif truthy(hash) then
text = getLead(text)
end
-- Захаваць толькі запытаныя элемэнты
local elements
if options.only then
if options.only == 'sections' then elements = getSections(text, options.sections) end
if options.only == 'lists' then elements = getLists(text, options.lists) end
if options.only == 'files' then elements = getFiles(text, options.files) end
if options.only == 'tables' then elements = getTables(text, options.tables) end
if options.only == 'templates' then elements = getTemplates(text, options.templates) end
if options.only == 'parameters' then elements = getParameters(text, options.parameters) end
if options.only == 'paragraphs' then elements = getParagraphs(text, options.paragraphs) end
if options.only == 'categories' then elements = getCategories(text, options.categories) end
if options.only == 'references' then elements = getReferences(text, options.references) end
text = ''
if elements then
for key, element in pairs(elements) do
text = text .. '\n' .. element .. '\n'
end
end
end
-- Адфільтраваць запытаныя элемэнты
if options.sections and options.only ~= 'sections' then elements, text = getSections(text, options.sections) end
if options.lists and options.only ~= 'lists' then elements, text = getLists(text, options.lists) end
if options.files and options.only ~= 'files' then elements, text = getFiles(text, options.files) end
if options.tables and options.only ~= 'tables' then elements, text = getTables(text, options.tables) end
if options.templates and options.only ~= 'templates' then elements, text = getTemplates(text, options.templates) end
if options.parameters and options.only ~= 'parameters' then elements, text = getParameters(text, options.parameters) end
if options.paragraphs and options.only ~= 'paragraphs' then elements, text = getParagraphs(text, options.paragraphs) end
if options.categories and options.only ~= 'categories' then elements, text = getCategories(text, options.categories) end
if options.references and options.only ~= 'references' then elements, text = getReferences(text, options.references) end
-- Розныя налады
if truthy(options.fixReferences) then text = fixReferences(text, page, full) end
if truthy(options.linkBold) and not truthy(section) then text = linkBold(text, page) end
if truthy(options.noBold) then text = removeBold(text) end
if truthy(options.noLinks) then text = removeLinks(text) end
if truthy(options.noSelfLinks) then text = removeSelfLinks(text) end
if truthy(options.noNonFreeFiles) then text = removeNonFreeFiles(text) end
if truthy(options.noBehaviorSwitches) then text = removeBehaviorSwitches(text) end
if truthy(options.noComments) then text = removeComments(text) end
-- Выдаліць шматкротныя пераводы радкоў, якія засталіся пасьля выдаленьня элемэнтаў
text = string.gsub(text, '\n\n\n+', '\n\n')
text = mw.text.trim(text)
return text
end
-- Асноўная функцыя выкліку для шаблёнаў
local function main(frame)
local args = parseArgs(frame)
local page = args[1]
local ok, text = pcall(get, page, args)
if not ok then return getError(text) end
return frame:preprocess(text)
end
-- Пункт уваходу для шаблёнаў
function p.main(frame) return main(frame) end
-- Пункт уваходу для модуляў
function p.get(page, options) return get(page, options) end
function p.getText(page, noFollow) return getText(page, noFollow) end
function p.getLead(text) return getLead(text) end
function p.getSection(text, section) return getSection(text, section) end
function p.getSections(text, flags) return getSections(text, flags) end
function p.getParagraphs(text, flags) return getParagraphs(text, flags) end
function p.getParameters(text, flags) return getParameters(text, flags) end
function p.getCategories(text, flags) return getCategories(text, flags) end
function p.getReferences(text, flags) return getReferences(text, flags) end
function p.getTemplates(text, flags) return getTemplates(text, flags) end
function p.getTables(text, flags) return getTables(text, flags) end
function p.getLists(text, flags) return getLists(text, flags) end
function p.getFiles(text, flags) return getFiles(text, flags) end
function p.getError(message, value) return getError(message, value) end
-- Expose handy methods
function p.truthy(value) return truthy(value) end
function p.parseArgs(frame) return parseArgs(frame) end
function p.matchAny(text, pre, list, post, init) return matchAny(text, pre, list, post, init) end
function p.matchFlag(value, flags) return matchFlag(value, flags) end
function p.getNamespaces(name) return getNamespaces(name) end
function p.removeBold(text) return removeBold(text) end
function p.removeLinks(text) return removeLinks(text) end
function p.removeSelfLinks(text) return removeSelfLinks(text) end
function p.removeNonFreeFiles(text) return removeNonFreeFiles(text) end
function p.removeBehaviorSwitches(text) return removeBehaviorSwitches(text) end
function p.removeComments(text) return removeComments(text) end
return p