-- Inflection-docs v0.8.3
-- 2015-07-06
-- This parameter `lang` should be changed when move source code to another wiktionary
-- It is used to get translations from corresponding i18n-module
local lang = 'ru'
local export = {}
local u = require("Module:utils")
local wu = require("Module:wiki-utils")
local du = require("Module:inflection-docs-utils")
local i18n = mw.loadData("Module:inflection-docs/i18n/" .. lang)
local data
local affixes
local conditions
local classes
local var_changes
local affixes_changes
local args_values
local condition_affixes
local condition_flags
-- TODO: move this function to inflection-docs-utils
local function classes_order(t, key_1, key_2)
if key_1 == nil then
return true
elseif key_2 == nil then
return false
end
local order_class_names = du.get_ordered_classes(conditions)
local key_1_index = 999
local key_2_index = 999
for i, order_class_name in pairs(order_class_names) do
if key_1:match('^' .. order_class_name) then
key_1_index = i
end
if key_2:match('^' .. order_class_name) then
key_2_index = i
end
end
if key_1_index ~= key_2_index then
return key_1_index < key_2_index
end
return key_1 < key_2
end
-- Function to load corresponding data-module
local function load_data(frame)
local data_name = frame.args['type']
if data_name == '' then
return 'Error in module [[Module:inflection-docs|inflection-docs]]: Name of data-module is absent.'
end
return mw.loadData("Module:inflection/data/" .. data_name);
end
-- Section "Template"
local function gen_template_name()
local r = string.format('=== %s ===\n', i18n.TEMPLATE_HEADER)
r = r .. string.format('{{%s|%s}}\n\n', i18n.TEMPLATE_TEMPLATE, data['template'])
return r
end
-- Section "Affixes in 'affixes'"
local function gen_affixes()
local r = ''
r = r .. string.format('==== %s ====\n', i18n.AFFIXES_SUBHEADER:format('<code>affixes</code>'))
r = r .. '{| ' .. wu.table_class() .. '\n'
r = r .. string.format('! %s || %s || %s \n', i18n.NAME, i18n.VALUE, i18n.CHANGES)
r = r .. '|-\n'
for affix_key, affix_value in u.spairs(affixes, case_order) do
changes = du.get_changes(affixes_changes, affix_key, wu.span_blue)
_anchor = wu.anchor('var', affix_key) .. ' '
r = r .. '| ' .. wu.link('var '..affix_key, wu.code_blue(affix_key)) .. '\n'
r = r .. '| align=center | '
if changes == '' then -- we need this because if column 'Changes' is empty then anchor on empty cell is working in a wrong way.
r = r .. _anchor
end
r = r .. '"' .. wu.span_blue(affix_value) .. '"\n'
r = r .. '|| '
if changes then -- if column 'Changes' is not empty then anchor should be on it.
r = r .. _anchor
end
r = r .. changes .. '\n'
r = r .. '|-\n'
end
r = r .. '|}\n\n'
return r
end
local function gen_condition_affixes()
local r = ''
r = r .. string.format('==== %s ====\n', i18n.AFFIXES_SUBHEADER:format('<code>conditions</code>'))
r = r .. '{| ' .. wu.table_class() .. '\n'
r = r .. string.format('! %s || %s \n', i18n.NAME, i18n.POSSIBLE_VALUES)
r = r .. '|-\n'
for affix_key, affix_value in u.spairs(condition_affixes, case_order) do
r = r .. '| ' .. wu.link('var '..affix_key, wu.code_blue(affix_key)) .. '\n'
r = r .. '|| ' .. wu.anchor('var', affix_key) .. ' ' .. du.get_changes(condition_affixes, affix_key, wu.span_blue) .. '\n'
r = r .. '|-\n'
end
r = r .. '|}\n\n'
return r
end
local function gen_condition_flags()
local r = ''
r = r .. string.format('==== %s ====\n', i18n.FLAGS_HEADER:format('<code>conditions</code>'))
r = r .. '{| ' .. wu.table_class() .. '\n'
r = r .. string.format('! %s || %s \n', i18n.NAME, i18n.POSSIBLE_VALUES)
r = r .. '|-\n'
for key, value in u.spairs(condition_flags) do
r = r .. '| ' .. wu.link('var '..key, wu.code_blue(key)) .. '\n'
r = r .. '|| ' .. wu.anchor('var', key) .. ' ' .. du.get_changes(condition_flags, key, wu.span_blue) .. '\n'
r = r .. '|-\n'
end
r = r .. '|}\n\n'
return r
end
local function gen_arguments()
local r = ''
r = r .. string.format('==== %s ====\n', i18n.ARGUMENTS_HEADER)
r = r .. '{| ' .. wu.table_class() .. '\n'
r = r .. string.format('! %s || %s \n', i18n.NAME, i18n.POSSIBLE_VALUES)
r = r .. '|-\n'
for key, value in u.spairs(args_values) do
r = r .. '| ' .. wu.link('arg '..key, wu.code_purple(key)) .. '\n'
r = r .. '|| ' .. wu.anchor('arg', key) .. ' ' .. du.get_changes(args_values, key, wu.span_purple) .. '\n'
r = r .. '|-\n'
end
r = r .. '|}\n\n'
return r
end
-- Section "Condtitions"
local function gen_conditions()
-- TODO section names or groups in conditions
local r = ''
r = r .. string.format('==== %s ====\n', i18n.CONDITIONS_HEADER)
r = r .. '{| ' .. wu.table_class() .. '\n'
r = r .. string.format('! № || %s || %s \n', i18n.CONDITIONS, i18n.ACTIONS)
r = r .. '|-\n'
for i, condition in pairs(conditions) do
local if_count = 0
local then_count = 0
local is_section = false
local is_subsection = false
local has_comment = false
local description_count = 0
for param_name, param_value in pairs(condition) do
if param_name == 'verdict' or param_name == 'actions' then
then_count = then_count + 1
elseif param_name == 'section' then
is_section = true
description_count = description_count + 1
elseif param_name == 'subsection' then
is_subsection = true
description_count = description_count + 1
elseif param_name == 'comment' then
has_comment = true
description_count = description_count + 1
else
if_count = if_count + 1
end
end
local has_conditions = (if_count > 0 or then_count > 0)
local has_descriptions = (description_count > 0)
local valign = ''
if if_count > 0 or true then -- temp
valign = "valign='top' "
end
if is_section then
r = r .. "| colspan='3' |\n"
r = r .. '|-\n'
end
local rowspan = ''
if has_conditions and has_descriptions then
rowspan = "rowspan='" .. (description_count + 1) .. "' "
end
r = r .. "| align='center' valign='top' " .. rowspan .. "| " .. wu.anchor('condition', i) .. ' ' .. wu.link('condition '..i, wu.span_green('#' .. i)) .. '\n'
if is_section then
r = r .. '| colspan=2 | ' .. wu.anchor('condition', i) .. ' ' .. wu.bold(i18n.SECTION .. ': ' .. wu.span_darkblue(condition['section'])) .. '\n'
r = r .. '|-\n'
end
if is_subsection then
r = r .. '| colspan=2 | ' .. wu.anchor('condition', i) .. ' ' .. wu.bold(i18n.SUBSECTION .. ': ') .. wu.span_darkblue(condition['subsection']) .. '\n'
r = r .. '|-\n'
end
if has_comment then
r = r .. '| colspan=2 | ' .. wu.anchor('condition', i) .. ' ' .. wu.italic(wu.bold(i18n.COMMENT .. ': ') .. wu.span_darkblue(condition['comment'])) .. '\n'
r = r .. '|-\n'
end
if has_conditions then
r = r .. '| ' .. valign .. '| ' .. wu.anchor('condition', i) .. ' '
if if_count > 0 then
r = r .. "'''" .. i18n.IF .. "'''"
if if_count == 2 then
r = r .. wu.span_silver(string.format(" ''(%s)''", i18n.APPLY_BOTH))
elseif if_count > 2 then
r = r .. wu.span_silver(string.format(" ''(%s)''", i18n.APPLY_ALL))
end
r = r .. '\n'
else
r = r .. wu.span_gray(string.format("''%s''", i18n.APPLY_ALWAYS)) .. '\n'
end
for param_name, param_value in pairs(condition) do
if param_name == 'verdict' or param_name == 'actions' then
-- skip
elseif param_name == 'section' or param_name == 'subsection' or param_name == 'comment' then
-- TODO
elseif param_name == 'last' then
r = r .. string.format('* %s: ', i18n.ENDS_WITH) .. du.join_values(param_value, wu.span_blue) .. '\n'
elseif param_name == 'last_NOT' then
r = r .. string.format("* %s: ", i18n.DOESNT_END_WITH) .. du.join_values(param_value, wu.span_blue) .. '\n'
elseif param_name == 'pre_last' then
r = r .. string.format("* %s: ", i18n.PRELAST_LETTER) .. du.join_values(param_value, wu.span_blue) .. '\n'
elseif param_name == 'pre_last_NOT' then
r = r .. string.format("* %s: ", i18n.PRELAST_LETTER_NOT) .. du.join_values(param_value, wu.span_blue) .. '\n'
elseif param_name:match("^arg") ~= nil or param_name:match("^var") ~= nil then
local NOT = false
local var_name
if param_name:match("_NOT$") ~= nil then
NOT = true
param_name = param_name:sub(1, -5)
end
if param_name == 'arg' or param_name == 'var' then -- arg = {'<name>', <values>}
var_name = param_value[1]
param_value = param_value[2]
else
var_name = param_name:sub(5) -- arg_<name> = <values>
param_name = param_name:sub(1, 3)
end
if param_name == 'arg' then
r = r .. '* ' .. i18n.SENT_ARGUMENT .. ' ' .. wu.link('arg '..var_name, wu.code_purple(var_name)) .. ' '
if NOT then
r = r .. i18n.ARG_NOT_EQUAL .. ' '
else
r = r .. i18n.ARG_EQUAL .. ' '
end
r = r .. du.join_values(param_value, wu.span_purple) .. '\n'
elseif param_name == 'var' then
r = r .. '* ' .. i18n.VAR .. ' ' .. wu.link('var '..var_name, wu.code_blue(var_name)) .. ' '
if NOT then
r = r .. i18n.VAR_NOT_EQUAL .. ' '
else
r = r .. i18n.VAR_EQUAL .. ' '
end
r = r .. du.join_values(param_value, wu.span_blue) .. '\n'
end
else
r = r .. '* ' .. param_name .. ' = ' .. du.join_values(param_value, wu.span_blue) .. '\n'
end
end
r = r .. "| valign='top' | "
if if_count > 0 then
r = r .. "'''" .. i18n.THEN .. "'''"
end
r = r .. '\n'
if condition['actions'] then
actions = condition['actions']
for j, action_params in pairs(actions) do
if action_params[1] == 'set' then
local var_name = action_params[2]
local var_value = du.get_action_value(action_params[3])
r = r .. '* ' .. i18n.SET .. ' ' .. wu.link('var '..var_name, wu.code_blue(var_name)) .. ' ' .. i18n.SET_TO .. ' "' .. wu.span_blue(var_value) .. '"\n'
else
r = r .. "* " .. i18n.ACTION .. " '''<code style='color: purple'>" .. action_params[1] .. "</code>''' (" .. action_params[2] .. ")\n"
end
end
end
if condition['verdict'] then
verdict = condition['verdict']
class_name = verdict['class_name']
r = r .. '* ' .. i18n.ADD_CLASS .. ' ' .. wu.link(i18n.CLASS..' '..class_name, wu.code_olive_bold(class_name)) .. "\n"
end
r = r .. '|-\n'
end
end
r = r .. '|}\n\n'
return r
end
-- Section "Classes"
local function gen_classes()
local form_keys = du.get_form_keys(classes)
local r = ''
r = string.format("=== %s '''<code>classes</code>''' %s ===\n", i18n.SECTION, i18n.CLASSES_HEADER_DESC)
for class_name, forms in u.spairs(classes, classes_order) do
r = r .. '==== ' .. i18n.CLASS .. ' ' .. wu.code_olive_bold(class_name) .. ' ====\n'
r = r .. '{| ' .. wu.table_class() .. '\n'
r = r .. string.format('! %s || %s \n', i18n.FORM, i18n.VALUE)
r = r .. '|-\n'
for form_key, form_value in u.spairs(forms, du.case_order) do
form_value = form_value:gsub("%>([^<]+)%<", '> + "' .. wu.span_blue('%1') .. '" + <')
form_value = form_value:gsub("%>([^<]+)$", '> + "' .. wu.span_blue('%1') .. '"')
form_value = form_value:gsub("%>%<", '> + <')
form_value = form_value:gsub("%<base%>", wu.code_green('base'))
for affix_key, affix_value in pairs(affixes) do
form_value = form_value:gsub("%<" .. affix_key .. "%>", wu.link('var '..affix_key, wu.code_blue(affix_key)))
end
for affix_key, affix_value in pairs(condition_affixes) do
form_value = form_value:gsub("%<" .. affix_key .. "%>", wu.link('var '..affix_key, wu.code_blue(affix_key)))
end
for key, value in pairs(condition_flags) do
form_value = form_value:gsub("%<" .. key .. "%>", wu.link('var '..key, wu.code_blue(key)))
end
for i, key in pairs(form_keys) do
form_value = form_value:gsub("%<" .. key .. "%>", wu.link('form '..key, wu.code_maroon(key)))
end
style = ''
if form_value == '—' or form_value == '-' then
style = ' align=center '
end
r = r .. '| ' .. wu.anchor('form', form_key) .. ' ' .. wu.link('form '..form_key, wu.code_maroon(form_key)) .. '\n'
r = r .. '|' .. style .. '| ' .. form_value .. '\n'
r = r .. '|-\n'
end
r = r .. '|}\n\n'
end
return r
end
local function gen_utils()
local utils = data['utils']
-- TODO
return ''
end
local function gen_notes()
local r = string.format('=== %s ===\n', i18n.NOTES_HEADER)
r = r .. '* ' .. i18n.NOTE_SENTENCE_PART1 .. ' ' .. wu.code_blue(i18n.NOTE_VAR) .. ', ' .. wu.code_purple(i18n.NOTE_ARG) .. ', ' .. wu.span_green('#1') .. ', ' .. wu.code_maroon(i18n.NOTE_FORM)
r = r .. i18n.NOTE_SENTENCE_PART2
return r
end
-- Main function to call from template
function export.get(frame)
data = load_data(frame)
affixes = data['affixes']
conditions = data['conditions']
classes = data['classes']
var_changes = du.gen_var_changes(conditions)
affixes_changes = du.gen_affixes_changes(var_changes, affixes)
local condition_vars = du.gen_condition_var_changes(var_changes, affixes)
condition_affixes = condition_vars[1]
condition_flags = condition_vars[2]
args_values = du.gen_args_values(conditions)
local result = ''
result = result .. gen_template_name()
result = result .. string.format('=== %s ===\n', i18n.AFFIXES_HEADER)
result = result .. gen_affixes()
result = result .. gen_condition_affixes()
result = result .. "=== " .. i18n.SECTION .. " '''<code>conditions</code>''' " .. i18n.CONDITIONS_HEADER_DESC .. " ===\n"
result = result .. gen_condition_flags()
result = result .. gen_arguments()
result = result .. gen_conditions()
result = result .. gen_classes()
result = result .. gen_utils()
result = result .. gen_notes()
return frame:preprocess(result)
end
return export
-- TODO: в "actions": base.replace(/k$/, 'g')
-- TODO: === Секция <code>tests</code> <span style='font-weight: normal'>''(тестовые примеры)''</span> ===
-- TODO: если секция пуста, то не отображать заголовок!!!
-- TODO: шаблон {{inflection-docs}} и автоматическое определение названия дата-модуля