Модуль:Wikifier: различия между версиями
Перейти к навигации
Перейти к поиску
м (typo) |
(продолжу потом) |
||
Строка 55: | Строка 55: | ||
end) * quote | end) * quote | ||
end -- local function quoted (quote) | end -- local function quoted (quote) | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
-- These function is used in both partial parsing JavaScript and applying wikifier transformations: | -- These function is used in both partial parsing JavaScript and applying wikifier transformations: | ||
Строка 87: | Строка 81: | ||
-- These JavaScript functions are allowed in wikifying rules and are reimplemented in Lua: | -- These JavaScript functions are allowed in wikifying rules and are reimplemented in Lua: | ||
− | local | + | local allowed = { |
r = preg_replace, | r = preg_replace, | ||
hide = hide, | hide = hide, | ||
Строка 115: | Строка 109: | ||
} | } | ||
− | local s | + | local s = P's' |
− | local transform = P { ' | + | local transform = P { 'trans', |
− | + | trans = s * spaces * equals * spaces * V'call' * spaces * ';' * Cp (), | |
− | * ( spaces * | + | call = V'func' * spaces * open |
+ | * ( spaces * V'arg' * ( spaces * comma * spaces * V'arg' ) ^ 0 ) | ||
* spaces * close / function (func, ...) | * spaces * close / function (func, ...) | ||
+ | mw.log 'In call rule.' | ||
local args = {...} | local args = {...} | ||
return function (string) | return function (string) | ||
− | return func (string, unpack ( | + | local substituted = {} |
+ | for i, arg in ipairs (args) do | ||
+ | substituted [i] = arg == 's' and string or arg | ||
+ | end | ||
+ | return func (string, unpack (substituted)) | ||
end | end | ||
end, | end, | ||
Строка 129: | Строка 129: | ||
-- Only allowed functions: | -- Only allowed functions: | ||
local choice = never | local choice = never | ||
− | for name, func in pairs ( | + | mw.log 'In func rule' |
+ | for name, func in pairs (allowed) do | ||
+ | mw.log ('In func rule. name = ' .. tostring (name)) | ||
choice = choice + P (name) * Cc (func) | choice = choice + P (name) * Cc (func) | ||
end | end | ||
return choice | return choice | ||
end)(), | end)(), | ||
− | arg = V'call' + | + | arg = V's' + V'call' + V'string' + V'regex' + V'func', |
+ | s = C (s), | ||
+ | string = quoted'"' + quoted"'", | ||
+ | regex = slash * ((escape * slash + any - slash) ^ 1 / function (pattern) | ||
+ | local sanitised = rex.gsub (pattern, '\\\\u([0-9A-F]{2,4})', '\\x{%1}', nil, convert_flags'ig') | ||
+ | return sanitised | ||
+ | end) * slash * C (S'gim' ^ 0) | ||
} | } | ||
− | local transform_anywhere = P{ transform | + | local transform_anywhere = P{ transform + 1 * V(1) } |
+ | local wikifier = 'Gadget-wikifier.js' | ||
+ | local code = tostring (mw.message.new (wikifier)) | ||
-- Iterate over wikifier code yielding processing functions: | -- Iterate over wikifier code yielding processing functions: | ||
− | local function | + | local transforms = (function (code) |
-- Remove comments: | -- Remove comments: | ||
local code = preg_replace (code, '//.*$', 'mg', '') | local code = preg_replace (code, '//.*$', 'mg', '') | ||
Строка 152: | Строка 162: | ||
end | end | ||
end) | end) | ||
− | end -- local function | + | end) (code) --local transforms = (function (code) |
− | + | local function wikify (text, page, start, finish) | |
− | |||
− | |||
− | local function wikify (text | ||
local counter = 1 | local counter = 1 | ||
− | for func in transforms | + | for func in transforms do |
if (not start or counter >= start) and (not finish or counter <= finish) then | if (not start or counter >= start) and (not finish or counter <= finish) then | ||
text = func (text, page) | text = func (text, page) | ||
Строка 198: | Строка 205: | ||
return wikify ( | return wikify ( | ||
frame.args [1] or frame.args.text, | frame.args [1] or frame.args.text, | ||
− | |||
frame:callParserFunction ('FULLPAGENAME', ''), | frame:callParserFunction ('FULLPAGENAME', ''), | ||
tonumber (frame.args.start), | tonumber (frame.args.start), | ||
Строка 207: | Строка 213: | ||
return wikify ( | return wikify ( | ||
test, | test, | ||
− | |||
frame:callParserFunction ('FULLPAGENAME', ''), | frame:callParserFunction ('FULLPAGENAME', ''), | ||
tonumber (frame.args.start), | tonumber (frame.args.start), | ||
tonumber (frame.args.finish) | tonumber (frame.args.finish) | ||
) | ) | ||
+ | end, | ||
+ | test2 = function () | ||
+ | return wikify (test, code, '') | ||
end | end | ||
} -- return | } -- return |
Версия от 12:48, 1 сентября 2023
Страница тестирования викификатора.
Окройте страницу в режиме редактирования и нажмите кнопку викификации. Не сохраняйте викифицированный текст.
Экранирование шаблонов
{{nobr|}}
Обработка невикифицированного HTML
Часть 1
Текст со сноской [1]. Ещё текст с другой[2] сноской.
Абзац <p>, не закрытый надлежащим образом и содержащий текст "в кавычках, и даже "во вложенных кавычках"". Текст в «лапках».
И ещё один абзац, на сей раз закрытый.
Интернализация ссылок на источники
Примечания
[1] Текст первой сноски. [2] Текст второй сноски.
--[[
Модуль для викификации текста на стороне сервера.
Использует правила, определённые в MediaWiki:Gadget-wikifier.js.
--]]
-- Dependencies:
local concat = table.concat
local wrap, yield = coroutine.wrap, coroutine.yield
local string = mw.ustring or string
local sub, gsub, match, char = string.sub, string.gsub, string.match, string.char
local decode = mw.uri.decode
local lpeg, rex = lpeg, rex_pcre
local P, C, Cc, Cp, S, V = lpeg.P, lpeg.C, lpeg.Cc, lpeg.Cp, lpeg.S, lpeg.V
local any, never, spaces, escape, slash = P(1), P(0), lpeg.locale ().space ^ 0, P'\\', P'/'
local open, close, comma, equals = P'(', P')', P',', P'='
local ask = mw.smw.ask
-- Локаль:
local function convert_flags (flags)
local flags = flags .. 'u'
-- pcre.h:
local values = {
i = 0x0001
, m = 0x0002
, s = 0x0004
, x = 0x0008
, A = 0x0010
, D = 0x0020
, X = 0x0040
-- , ? = 0x0080 PCRENOTBOL
-- , ? = 0x0100 PCRENOTEOL
, U = 0x0200
, u = 0x0800
}
local converted = 0
if flags then
for flag, value in pairs (values) do
if match (flags, flag) then
converted = converted + value
end
end
end
return converted
end -- local function convert_flags (flags)
-- This pattern matches a JavaScript string and converts it to Lua string:
local function quoted (quote)
return P (quote) * ((any - quote + escape * quote) ^ 0 / function (str)
local sanitised = gsub (str, '\\x([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]?[0-9a-fA-F]?)', function (code)
return string.char (tonumber ('0x' .. code))
end)
sanitised = gsub (sanitised, '\\n', '\n')
sanitised = gsub (sanitised, '$(%d+)', '%%%1')
return sanitised
end) * quote
end -- local function quoted (quote)
-- These function is used in both partial parsing JavaScript and applying wikifier transformations:
local function preg_replace (string, pattern, flags, replacement)
local replacement = type (replacement) == 'string' and gsub (replacement or '', '$(%d)', '%%1') or replacement
return rex.gsub (string, pattern, replacement, nil, convert_flags (flags))
end -- local function preg_replace (string, pattern, flags, replacement)
-- Generate two functions allowed in wikifier with pseudo-static variables (hidden upvalues):
local hide, restore = (function ()
local hidden = {}
return function (string, pattern, flags)
return preg_replace (string, pattern, flags, function (found)
local no = #hidden + 1
hidden [no] = found
return '\x01' .. tostring (no) .. '\x02'
end)
end, function (text)
for i = #hidden, 1, -1 do
text = gsub (text, '\x01' .. tostring (i) .. '\x02', hidden [i])
end
hidden = {}
return text;
end
end) ()
-- These JavaScript functions are allowed in wikifying rules and are reimplemented in Lua:
local allowed = {
r = preg_replace,
hide = hide,
hideTags = function (string, ...)
local tags = concat ({...}, '|')
local pattern = '<(' .. tags .. ')( [^>]+)?>[\\s\\S]+?<\\/\\1>'
return hide (string, pattern, 'giu')
end,
restore = restore,
wikifyInternalLinks = function (_, __, page, alias)
return '[[' .. decode (page) .. '|' .. alias .. ']]';
end,
internalise = function (url, alias)
local property = 'URL источника'
local pages = ask { '[[' .. property .. '::' .. url ..']]', '?#-', limit = 1 }
if pages then
local page = pages [1] [1]
if not (context and page == context) then
return '[[' .. pages [1] [1] .. '|' .. alias .. ']]'
end
end
return '[' .. url .. ' ' .. alias .. ']'
end,
char = function (_, s)
return char (tonumber (sub (s, -4), 16))
end
}
local s = P's'
local transform = P { 'trans',
trans = s * spaces * equals * spaces * V'call' * spaces * ';' * Cp (),
call = V'func' * spaces * open
* ( spaces * V'arg' * ( spaces * comma * spaces * V'arg' ) ^ 0 )
* spaces * close / function (func, ...)
mw.log 'In call rule.'
local args = {...}
return function (string)
local substituted = {}
for i, arg in ipairs (args) do
substituted [i] = arg == 's' and string or arg
end
return func (string, unpack (substituted))
end
end,
func = (function()
-- Only allowed functions:
local choice = never
mw.log 'In func rule'
for name, func in pairs (allowed) do
mw.log ('In func rule. name = ' .. tostring (name))
choice = choice + P (name) * Cc (func)
end
return choice
end)(),
arg = V's' + V'call' + V'string' + V'regex' + V'func',
s = C (s),
string = quoted'"' + quoted"'",
regex = slash * ((escape * slash + any - slash) ^ 1 / function (pattern)
local sanitised = rex.gsub (pattern, '\\\\u([0-9A-F]{2,4})', '\\x{%1}', nil, convert_flags'ig')
return sanitised
end) * slash * C (S'gim' ^ 0)
}
local transform_anywhere = P{ transform + 1 * V(1) }
local wikifier = 'Gadget-wikifier.js'
local code = tostring (mw.message.new (wikifier))
-- Iterate over wikifier code yielding processing functions:
local transforms = (function (code)
-- Remove comments:
local code = preg_replace (code, '//.*$', 'mg', '')
code = preg_replace (code, '/\\*.*?\\*/', 'g', '')
return wrap (function ()
local pos = 1
while pos <= #code do
local func
func, pos = transform_anywhere:match (code, pos)
yield (func)
end
end)
end) (code) --local transforms = (function (code)
local function wikify (text, page, start, finish)
local counter = 1
for func in transforms do
if (not start or counter >= start) and (not finish or counter <= finish) then
text = func (text, page)
if #text == 0 then
return '<span class="error">Text became empty at rule #' .. tostring (counter) .. '</span>\n'
end
end
counter = counter + 1
end
return text
end -- local function wikify (text, code)
local test = [==[
Страница тестирования [[MediaWiki:Gadget-wikifier.js|викификатора]].
Окройте страницу в режиме редактирования и нажмите кнопку викификации. Не сохраняйте викифицированный текст.
== Экранирование шаблонов ==
{{nobr|[[Category:All]]}}
== Обработка невикифицированного HTML ==
<h3>Часть 1</h3>
Текст со сноской [1]. Ещё текст с другой[2] сноской.
<p>Абзац <p>, не закрытый надлежащим образом и содержащий текст "в кавычках, и даже "во вложенных кавычках"". Текст в «лапках».
<p>И ещё один абзац, на сей раз закрытый.</p>
== Интернализация ссылок на источники ==
* [http://www.hist.msu.ru/ER/Etext/apr1906.htm должна интернализоваться],
* [http://www.hist.msu.ru/ER/Etext/apr1906.html не должна интернализоваться],
<h2>Примечания</h2>
[1] Текст первой сноски.
[2] Текст второй сноски.
]==]
return {
run = function (frame)
return wikify (
frame.args [1] or frame.args.text,
frame:callParserFunction ('FULLPAGENAME', ''),
tonumber (frame.args.start),
tonumber (frame.args.finish)
)
end,
test = function (frame)
return wikify (
test,
frame:callParserFunction ('FULLPAGENAME', ''),
tonumber (frame.args.start),
tonumber (frame.args.finish)
)
end,
test2 = function ()
return wikify (test, code, '')
end
} -- return