Модуль:WDFormat: различия между версиями
Буквица>The Fox Bot м Защитил страницу Модуль:WDFormat: критический шаблон или модуль: согласно Служебная:Постоянная ссылка/143835923 ([Редактирование=только автоподтверждённые] (бессрочно) [Переименование=только автоподтверждённые] (бессрочно)) |
Karaby (обсуждение | вклад) м 1 версия импортирована |
(нет различий)
| |
Текущая версия от 15:36, 27 июля 2025
Модуль предназначен для форматирования набора данных, полученных из Викиданных посредством модуля WDBackend или заданных вручную. Форматирование может осуществляться в произвольной форме, как в строчку, так и в табличном виде.
Конечное представление информации задаётся профилем, который описывает, какими тегами оформлять данные, группы полей и отдельные поля, а также какие преобразования над данными необходимо сделать.
Использование
Модуль является библиотечным и предназначен для использования в других модулях. Данный модуль не предназначен для использования в статьях или других шаблонах напрямую через вызов #invoke.
Требуемое форматирование описывается профилем, представляющим собой таблицу Lua. Профиль описывает представление отдельных полей, то есть то, как они должны отображаться. Недостающий функционал реализуется указанием в профиле собственных функций, принимающих определённый набор аргументов и возвращающих определённый результат.
Для форматирования профиля в совокупности с передаваемым набором данных необходимо использовать функцию format(). В качестве результата возвращается отформатированный викитекст.
Для примера использования см. модуль Модуль:CiteGost.
Формат профиля в общем виде
{
-- Корневой тег:
tag = {
name = 'Имя тега',
classes = { 'class1', 'class2', ... },
attr = { атрибут1='значение1', атрибут2='значение2', ... },
tag = Вложенный тег,
},
-- Группы:
-- Начало 1-й группы:
{
-- Тег группы:
tag = {
name = 'Имя тега',
classes = { 'class1', 'class2', ... },
attr = { атрибут1='значение1', атрибут2='значение2', ... },
css = { свойство1='значение1', свойство2='значение2', ... },
tag = Вложенный тег
},
ensureEnds = 'Символ/текст, которым должно заканчиваться предыдущее поле',
delimiter = 'Разделитель, добавляемый по отношению к предыдущему полю',
childEnsureEnds = 'Символ/текст, которым должны заканчиваться поля группы',
childDelimiter = 'Разделитель полей в группе',
-- Дочерние элементы текущей группы по факту продолжают предыдущие элементы (влияет на повышение первой буквы до заглавной):
passthrough = true,
prefix = 'Текст до начала группы',
-- Поля группы (подгруппы):
-- 1-е поле группы:
{
-- Тег поля:
tag = {
name = 'Имя тега',
classes = { 'class1', 'class2', ... },
attr = { атрибут1='значение1', атрибут2='значение2', ... },
tag = Вложенный тег
css = { свойство1='значение1', свойство2='значение2', ... },
},
ensureEnds = 'Символ/текст, которым должен заканчиваться предшествующий текст',
delimiter = 'Разделитель, отделяющий текущий элемент от предыдущего',
-- Функция, разрешающая отображение поля:
cond = функция,
prefix = 'Текст до поля',
field = 'Название поля',
-- Менять ли первую букву поля на заглавную
capitalize = true/false
urlMaskProp = 'P-идентификатор свойства, отвечающего за маску ссылки',
-- Функции, через которые поле будет отформатировано:
format = { функция1, функция2, ... },
suffix = 'Текст после поля',
},
-- Второе поле:
{
value = 'Отображаемое значение',
},
-- Остальные группы:
...
suffix = 'Текст в конце группы',
},
-- Остальные группы:
...
ensureEnds = 'Окончение форматированных данных, например, точка.'
}
Функции форматирования полей
Форматирование поля задаётся через команду format с указанием функции форматирования, принимающей определённый набор аргументов. Доступны следующие встроенные функции:
numericalRanges— форматирование диапазона чисел (корректирует знак диапазона);dash— оформление тире в тексте;unit— получение единицы измерения у элемента Викиданных;abbr— получить сокращённое обозначение (есть ограничения) у элемента Викиданных;short— получить короткое название у элемента Викиданных;abbrWithHint— получить сокращённое обозначение (есть ограничения) у элемента Викиданных с расшифровкой в подсказке;date— форматирование даты;quantity— форматирование количества с указанной в нём единицей измерения;entity— получить значение идентификатора элемента Викиданных;wikilink— оформить поле Викиссылкой, если это возможно;wikisource— оформить поле ссылкой на Викитеку, если в элементе Викиданных указана соответствующая статья;link— оформить поле внешней ссылкой, если это возможно;wikidata— добавление к полю надстрочной ссылки на элемент Викиданных, если хотя бы в одном языковом разделе есть статья по теме;wikidataLink— оформить поле ссылкой на элемент Викиданных, который с полем связан.forceWikidataLink— оформить поле ссылкой на элемент Викиданных, который с полем связан. Формирует ссылку, даже если ранее по тексту ссылка на такой элемент была дана.
Внесение изменений
При исправлении ошибки, пожалуйста, сначала добавьте тест, который будет проваливаться из-за обнаруженной ошибки, и только затем вносите исправление. При внесении исправления проверьте, чтобы все тесты проходили. Вносить исправление можно только, если оно не ломает другие тесты.
Добавление нового функционала рекомендуется делать у себя в песочнице, скопировав в неё модуль. В правке копирования необходимо указать тот факт, что делается копирование, и сделать ссылку на оригинальный модуль в виде викитекста. При добавлении нового функционала сначала желательно добавить тест на этот функционал, затем добавить сам функционал, убедившись, что все тесты при этом проходят.
Тесты
[mark.svg|20px|link=|alt=] 3 тестов провалилось.
| Название | Ожидается | Фактически | |
|---|---|---|---|
| [check.svg|15px|link=|alt=✔] | test_format_array | ||
| [check.svg|15px|link=|alt=✔] | test_format_arrayCapitalize | ||
| [check.svg|15px|link=|alt=✔] | test_format_arrayForceCapitalize | ||
| [check.svg|15px|link=|alt=✔] | test_format_capitalize | ||
| [check.svg|15px|link=|alt=✔] | test_format_conflicts | ||
| [check.svg|15px|link=|alt=✔] | test_format_conflicts_recursive | ||
| [check.svg|15px|link=|alt=✔] | test_format_date | ||
| [check.svg|15px|link=|alt=✔] | test_format_delimiter_function | ||
| [check.svg|15px|link=|alt=✔] | test_format_depends | ||
| [check.svg|15px|link=|alt=✔] | test_format_depends_fieldPath | ||
| [check.svg|15px|link=|alt=✔] | test_format_depends_recursive | ||
| [check.svg|15px|link=|alt=✔] | test_format_ensureEndsAndDelimiter | ||
| [check.svg|15px|link=|alt=✔] | test_format_fieldPath | ||
| [check.svg|15px|link=|alt=✔] | test_format_group_childDelimiter_and_childEnsureEnds | ||
| [check.svg|15px|link=|alt=✔] | test_format_group_passthrough | ||
| [check.svg|15px|link=|alt=✔] | test_format_group_prefix_with_delimiter | ||
| [check.svg|15px|link=|alt=✔] | test_format_group_prefix_with_delimiter_inside_another_group | ||
| [check.svg|15px|link=|alt=✔] | test_format_groups_delimiter | ||
| [check.svg|15px|link=|alt=✔] | test_format_innerTags | ||
| [check.svg|15px|link=|alt=✔] | test_format_isStatic_hidden | ||
| [check.svg|15px|link=|alt=✔] | test_format_isStatic_hidden_in_array | ||
| [check.svg|15px|link=|alt=✔] | test_format_isStatic_hidden_in_array_in_additional_group | ||
| [check.svg|15px|link=|alt=✔] | test_format_isStatic_visible | ||
| [check.svg|15px|link=|alt=✔] | test_format_link | ||
| [mark.svg|20px|link=|alt=] | test_format_linkOrder | <span>[[s:ГОСТ Р 7.0.5—2008|ГОСТ Р 7.0.5—2008]]</span> | <span>[http://example.com <b><s>(nil)</s></b>]</span> |
| [check.svg|15px|link=|alt=✔] | test_format_nested_array | ||
| [check.svg|15px|link=|alt=✔] | test_format_oneField | ||
| [check.svg|15px|link=|alt=✔] | test_format_person | ||
| [check.svg|15px|link=|alt=✔] | test_format_person_multipleNames | ||
| [check.svg|15px|link=|alt=✔] | test_format_prefixAndSuffix | ||
| [check.svg|15px|link=|alt=✔] | test_format_recurseGroups | ||
| [check.svg|15px|link=|alt=✔] | test_format_rootTag | ||
| [check.svg|15px|link=|alt=✔] | test_format_squareBrackets | ||
| [check.svg|15px|link=|alt=✔] | test_format_tableTag | ||
| [mark.svg|20px|link=|alt=] | test_format_wikilink | <span>[[Почка]]</span> | <span><b><s>(nil)</s></b></span> |
| [mark.svg|20px|link=|alt=] | test_format_wikisource | <span>[[s:ГОСТ Р 7.0.5—2008|ГОСТ Р 7.0.5—2008]]</span> | <span><b><s>(nil)</s></b></span> |
В качестве интеграционных тестов использованы тесты модуля, который работает на основе текущего модуля.
| Статьи (0/5) | ||||
|---|---|---|---|---|
| Тест | Ожидается | Фактически | Разница | |
| ❌ | Научная статья 1{{Источник информации|Q73118986
|ref = Casotti, Lindberg, Braun
}}
| '"`[^<]+Casotti G%. %Functional morphology of the avian medullary cone% : [англ%.] : [%арх%.% 17 марта 2022] / G%. Casotti, K%. K%. Lindberg, E%. J%. Braun // American journal of physiology%. Regulatory, integrative and comparative physiology%[%[d:Q2201819|[d]%]%]%. — 2000, 1 November%. — Vol%. 279, iss%. 5%. — P%. R1722—30%. — %[%[Международный стандартный сериальный номер|ISSN%]%] %[https://[^ ]+ %w+-%w+%], %[https://[^ ]+ %w+-%w+%]%. — %[%[Цифровой идентификатор объекта|doi%]%]:%10.1152/ajpregu.2000.279.5.r1722%%. — %[%[PMID%]%] %11049855%%. — %[%[Викиданные|WD%]%] %[%[d:Q73118986|Q73118986%]%]%. | < > <span class="citation" id="CITEREFCasotti, Lindberg, Braun"><b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD [[d:Q73118986|Q73118986]]. | |
| ❌ | Научная статья 2{{Источник информации|Q92544321
|ref = Abdalla
}}
| Abdalla M%. A%.%[%[d:Q118210006|[d]%]%] %Anatomical features in the kidney involved in water conservation through urine concentration in dromedaries %(Camelus dromedarius%)% : [англ%.] : [%арх%.% 26 июля 2022] // Heliyon%[%[d:Q27727019|[d]%]%]%. — 2020, 2 January%. — Vol%. 6, iss%. 1%. — Article e03139%. — %[%[Международный стандартный сериальный номер|ISSN%]%] %[https://[^ ]+ %w+-%w+%]%. — %[%[Цифровой идентификатор объекта|doi%]%]:%10%.1016/j%.heliyon%.2019%.e03139%%. — %[%[PMID%]%] %31922050%%. — %[%[Викиданные|WD%]%] %[%[d:Q92544321|Q92544321%]%]%. | < id="CITEREFAbdalla > id="CITEREFAbdalla"><b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD [[d:Q92544321|Q92544321]]. | |
| ❌ | Научная статья 3{{Источник информации|Q59330138
|ref = Munn, Peters, Stern, et al.
}}
| %Systematic review or scoping review%? Guidance for authors when choosing between a systematic or scoping review approach% : [англ%.] / Z. Munn%[%[d:Q56167095|[d]%]%], M%. Peters%[%[d:Q57790662|[d]%]%], C. Stern %[et al.%] // BMC Medical Research Methodology%[%[d:Q15752152|[d]%]%]%. — 2018, 19 November%. — Vol%. 18, iss. 1%. — P%. 143%. — %[%[Международный стандартный сериальный номер|ISSN%]%] %[https://[^ ]+ %w+-%w+%]%. — %[%[Цифровой идентификатор объекта|doi%]%]:%10.1186/s12874%-018%-0611%-x%%. — %[%[PMID%]%] %30453902%%. — %[%[Викиданные|WD%]%] %[%[d:Q59330138|Q59330138%]%]%. | < al. > al."><b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD [[d:Q59330138|Q59330138]]. | |
| ❌ | Заданная вручную статья через qid издания{{Источник информации
|авторы = M. A. Abdalla
|ссылка = https://www.sciencedirect.com/science/article/pii/S2405844019367982
|заглавие = Anatomical features in the kidney involved in water conservation through urine concentration in dromedaries (Camelus dromedarius)
|язык = en
|qid издания = Q27727019
|статья = e03139
|дата = 2020-01-02
|том = 6
|выпуск = 1
|doi = 10.1016/J.HELIYON.2019.E03139
|pmid = 31922050
|ref = Abdalla
}}
| Abdalla M%. A%. %Anatomical features in the kidney involved in water conservation through urine concentration in dromedaries %(Camelus dromedarius%)% : [англ%.] // Heliyon%[%[d:Q27727019|[d]%]%]%. — 2020, 2 January%. — Vol%. 6, iss%. 1%. — Article e03139%. — %[%[Международный стандартный сериальный номер|ISSN%]%] %[https://[^ ]+ %w+-%w+%]%. — %[%[Цифровой идентификатор объекта|doi%]%]:%10%.1016/j%.heliyon%.2019%.e03139%%. — %[%[PMID%]%] %31922050%%. | Ошибка Lua на строке 206: attempt to concatenate local 'abbr' (a nil value). | < <s > <strong class="error"><span class="scribunto-error mw-scribunto-error-ee5e90fb">Ошибка Lua на строке 206: attempt to concatenate local 'abbr' (a nil value).</span></strong> |
| ❌ | Научная статья (у журнала не должно быть авторов){{Источник информации|Q24187606
|ref = Sutter, Saraswat, Driel
}}
| An I%. M%. De Sutter%. %Antihistamines for the common cold% : [англ%.] / An I%. M%. De Sutter, Avadhesh Saraswat, Mieke L%. van Driel%[%[d:Q48943509|[d]%]%] // Cochrane Database of Systematic Reviews%[%[d:Q15750361|[d]%]%]%. — 2015, 29 November%. — %[%[Международный стандартный сериальный номер|ISSN%]%] %[https://[^ ]+ %w+-%w+%], %[https://[^ ]+ %w+-%w+%]%. — %[%[Цифровой идентификатор объекта|doi%]%]:%10%.1002/14651858%.cd009345%.pub2%%. — %[%[PMID%]%] %26615034%%. — %[%[Викиданные|WD%]%] %[%[d:Q24187606|Q24187606%]%]%. | < Driel > Driel"><b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD [[d:Q24187606|Q24187606]]. | |
| Книги (0/12) | ||||
|---|---|---|---|---|
| Тест | Ожидается | Фактически | Разница | |
| ❌ | Глава книги{{Источник информации
|qid издания = Q114595502
|ссылка на издание = https://www.google.ru/books/edition/Seldin_and_Giebisch_s_The_Kidney/w5nEg7VLEQ4C?hl=en&gbpv=1&pg=610
|заглавие = Chapter 20 — Structural Organization of the Mammalian Kidney
|ссылка = https://www.sciencedirect.com/science/article/pii/B9780123814623000203
|авторы = W. Kriz, B. Kaissling
|том = 1
|страницы = 595-691
|ref = Kriz, Kaissling
}}
| Kriz W. Chapter 20 — Structural Organization of the Mammalian Kidney : [англ.] / W. Kriz, B. Kaissling // Seldin and Giebisch's The Kidney : Physiology and pathophysiology : in 2 vols. / Ed.: R. J. Alpern [et al.]. — Fifth edition. — Amsterdam : Academic Press, 2012, 31 December. — Vol. 1. — P. 595—691. — ISBN 978-0-12-381463-0, 978-0-12-381462-3. — WD Q114595502. | Kriz W. Chapter 20 — Structural Organization of the Mammalian KidneyЯзык? / W. Kriz, B. Kaissling // | < Kaissling > Kaissling"><i>Kriz W.</i> [https://www.sciencedirect.com/science/article/pii/B9780123814623000203 Chapter 20 — Structural Organization of the Mammalian Kidney]<sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup> / W. Kriz, B. Kaissling // [https://www.google.ru/books/edition/Seldin_and_Giebisch_s_The_Kidney/w5nEg7VLEQ4C?hl=en&gbpv=1&pg=610 <b><s>(nil)</s></b>]. (<span class="error">Издание?</span>). — 1. — 595—691. — WD |
| ❌ | Перевод книги с русского на английский{{Источник информации|Q114676884
|ref = Sagan
}}
| %[%[Саган, Карл|Саган К%.%]%] %[%[Мир, полный демонов: Наука — как свеча во тьме|Мир, полный демонов%]%] : Наука — как свеча во тьме = The Demon%-Haunted World : Science as a Candle in the Dark : Пер%. с англ%. / Пер%.: %[%[Сумм, Любовь Борисовна|Л[юбовь %. ]+Сумм%]%]; ред%.: Артур Кляницкий%. — 5%-е изд%. — %[%[Москва|М%.%]%] : %[%[Альпина нон%-фикшн%]%], 2019%. — 538 с%. — %[%[Международный стандартный книжный номер|ISBN%]%] %[%[Служебная:Источники_книг/978%-5%-91671%-874%-4|978%-5%-91671%-874%-4%]%]%. — %[%[Викиданные|WD%]%] %[%[d:Q114676884|Q114676884%]%]%. | < id="CITEREFSagan > id="CITEREFSagan"><b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD [[d:Q114676884|Q114676884]]. | |
| ❌ | Книга с указанным типом работы{{Источник информации|Q114831437
|ref = Веракса, Веракса
}}
| Веракса Н. Е. Познавательное развитие в дошкольном возрасте : учебное пособие / Н. Е. Веракса, А. Н. Веракса. — М. : МОЗАИКА-СИНТЕЗ, 2012. — 336 с. — ISBN 978-5-4315-0097-8. — WD Q114831437. | < Веракса > Веракса"><b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD | |
| ❌ | Книга с указанной серией{{Источник информации|Q115189432
|заглавие тома = Животные
|ref = Красная книга РФ, т. «Животные»
}}
| Красная книга Российской Федерации. Т. «Животные». — 2-е издание. — М. : ФГБУ «ВНИИ Экология», 2021. — 1128 с. — (Красная книга Российской Федерации). — ISBN 978-5-6047425-0-1. — WD Q115189432. | < «Животные» > «Животные»"><b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — Животные. — WD | |
| ❌ | Книга по qid издания и qid темы{{Источник информации
|qid издания = Q98103166
|qid темы = Q58184
|ref = Наточин
}}
| Юрий Викторович Наточин. Нефрон : [арх. 14 апреля 2023] // Знания : интернет-энциклопедия / Гл. ред.: С. Кравец. — 2023, 17 января. | < id="CITEREFНаточин > id="CITEREFНаточин"><b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup> // <b><s>(nil)</s></b><sup class="noprint">[[d:Q98103166|[d]]]</sup>. — WD [[d:Q98103166|Q98103166]]. | |
| ❌ | Книга по qid издания и qid темы на английском{{Источник информации
|qid издания = Q5375741
|qid темы = Q58184
|дата обновления = 2022-08-22
|дата обращения = 2022-10-23
|ref = Nephron, Britannica
}}
| The Editors of Encyclopaedia Britannica. Nephron : [англ.] : [арх. 2 июня 2022] // Encyclopædia Britannica : online encyclopedia. — Дата обновления: 22 августа 2022. — Дата обращения: 23 октября 2022. | < < > <b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup> // <b><s>(nil)</s></b><sup class="noprint">[[d:Q5375741|[d]]]</sup>. — Дата обновления: 22 августа 2022. — Дата обращения: 23 октября 2022. — WD [[d:Q5375741|Q5375741]]. | |
| ❌ | С указанием иллюстраторов{{Источник информации|Q115634662
|ref = Clement, Davis, Harris
}}
| Clement P.[d] Finches and Sparrows : [англ.] / Illus.: A. Harris, J. Davis. — 1st edition. — 1993, 21 November. — 500 p. — ISBN 978-0-691-03424-9. — WD Q115634662. | < Harris > Harris"><b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD | |
| ❌ | Том через qid{{Источник информации|Q115676233
}}
| %Jubb, Kennedy & Palmer's Pathology of Domestic Animals% : [англ%.]%. In 3 vols%. Vol%. 2 / Ed%.: M%. G[rant%.]+ Maxie%. — Elsevier Health Sciences, 2015, 14 August%. — 782 p%. — %[%[Международный стандартный книжный номер|ISBN%]%] %[%[Служебная:Источники_книг/978%-0%-7020%-5318%-4|978%-0%-7020%-5318%-4%]%]%. — %[%[Викиданные|WD%]%] %[%[d:Q115676233|Q115676233%]%]%. | < > <b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD [[d:Q115676233|Q115676233]]. | |
| ❌ | Том через qid с ручным заданием частного заглавия{{Источник информации|Q115926218
|заглавие тома = Full text
}}
| Lefever Ernest W. United Nations peacekeeping in the Congo: 1960-1964 : an analysis of political, executive and military control : [англ.]. In 4 vols. Vol. 2. Full text / Ernest W. Lefever, Wynfred Joshua. — Washington : Brookings Institution, 1966, 30 June. — 454 p. — OCLC 489825. — WD Q115926218. | < < > <b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — Full text. — WD | |
| ❌ | Глава, у которой есть автор, из книги, у которой указан редактор{{Источник информации
|авторы = Marc R. Hammerman
|заглавие = Chapter 37 - Xenotransplantation in the Kidney: A Historical Perspective
|ссылка = https://www.sciencedirect.com/science/article/abs/pii/B9780128001028000370
|страницы = 507-519
|doi = 10.1016/B978-0-12-800102-8.00037-0
|qid издания = Q118531989
}}
| Hammerman Marc R. Chapter 37 — Xenotransplantation in the Kidney: A Historical Perspective : [англ.] // Kidney Development, Disease, Repair and Regeneration[d] / Ed.: Melissa H. Little[d]. — Academic Press, 2016. — P. 507—519. — ISBN 978-0-12-800102-8. — doi:10.1016/b978-0-12-800102-8.00037-0. — WD Q118531989. | Hammerman Marc R. Chapter 37 — Xenotransplantation in the Kidney: A Historical PerspectiveЯзык? // | < > <sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup> // <b><s>(nil)</s></b><sup class="noprint">[[d:Q118531989|[d]]]</sup>. — 507—519. — doi:10.1016/b978-0-12-800102-8.00037-0. — WD |
| ❌ | С указанием главного редактора{{Источник информации|Q118220282
|ref = БРЭ
}}
| Большая российская энциклопедия : в 35 т. / Гл. ред.: Ю. С. Осипов. — М. : Большая российская энциклопедия, 2004—2017. — WD Q118220282. | < > <b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD | |
| ❌ | Ручное задание информации с серией{{Источник информации|Q118220282|авторы=Ulla C. Kopp|заглавие=Neural Control of Renal Function|ссылка=https://www.ncbi.nlm.nih.gov/books/NBK57113/|оригинал=Neural Control of Renal Function|место=San Rafael|издатель=Morgan & Claypool Life Sciences|дата=2011-08-20|серия=Integrated Systems Physiology: from Molecule to Function to Disease|pmid=21850765|язык=en|qid=Q121112788|офлайн=1}}
| Kopp Ulla C. Neural Control of Renal Function : [англ.]. — San Rafael : Morgan & Claypool Life Sciences, 2011, 20 August. — (Integrated Systems Physiology: from Molecule to Function to Disease). — PMID 21850765. — WD Q121112788. | Ошибка Lua на строке 206: attempt to concatenate local 'abbr' (a nil value). | < <s > <strong class="error"><span class="scribunto-error mw-scribunto-error-ee5e90fb">Ошибка Lua на строке 206: attempt to concatenate local 'abbr' (a nil value).</span></strong> |
| Выпуски (0/4) | ||||
|---|---|---|---|---|
| Тест | Ожидается | Фактически | Разница | |
| ❌ | Выпуск журнала{{Источник информации|Q36350107}}
| WikiJournal of Medicine : [англ%.]%. Iss%. 1%. — WikiJournal User Group%[%[d:Q28953974|[d]%]%]%. — Vol%. 4%. — %[%[Международный стандартный сериальный номер|ISSN%]%] %[https://[^ ]+ %w+-%w+%], %[https://[^ ]+ %w+-%w+%]. — %[%[Викиданные|WD%]%] %[%[d:Q36350107|Q36350107%]%]%. | < > <b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD [[d:Q36350107|Q36350107]]. | |
| ❌ | Выпуск журнала с названием{{Источник информации|Q29908205}}
| %The Art Newspaper% : [англ%.]%. Iss%. 289%. Visitor Figures 2016%. — 2017, April%. — %[%[Международный стандартный сериальный номер|ISSN%]%] %[https://[^ ]+ %w+-%w+%]%. — %[%[Викиданные|WD%]%]& | < > <b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD [[d:Q29908205|Q29908205]].</span> | |
| ❌ | Статья из выпуска журнала, оформленная через qid издания, в котором указан выпуск{{Источник информации
|qid издания = Q36350107
|заглавие = The Hippocampus
|ссылка = https://en.wikiversity.org/wiki/WikiJournal_of_Medicine/The_Hippocampus
}}
| %The Hippocampus% : [англ%.] // %[%[s:WikiJournal of Medicine|WikiJournal of Medicine%]%] : scientific journal%. — Vol%. 4, iss%. 1%. — %[%[Международный стандартный сериальный номер|ISSN%]%] %[https://[^ ]+ %w+-%w+%], %[https://[^ ]+ %w+-%w+%]%. — %[%[Викиданные|WD%]%] %[%[d:Q36350107|Q36350107%]%]%. | The HippocampusЯзык? // | < > [https://en.wikiversity.org/wiki/WikiJournal_of_Medicine/The_Hippocampus The Hippocampus]<sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup> // <b><s>(nil)</s></b><sup class="noprint">[[d:Q36350107|[d]]]</sup>. — WD [[d:Q36350107|Q36350107]]. |
| ❌ | Раздел из выпуска журнала по qid издания (у выпуска есть название){{Источник информации
|заглавие = Top Ten Thematic
|страницы = 7
|qid издания = Q29908205
}}
| Top Ten Thematic : [англ%.] // %[%[The Art Newspaper%]%]%. — Iss%. 289 : Visitor Figures 2016%. — P%. 7%. — %[%[Международный стандартный сериальный номер|ISSN%]%] %[https://[^ ]+ %w+-%w+%]%. — %[%[Викиданные|WD%]%] %[%[d:Q29908205|Q29908205%]%]%. | Top Ten ThematicЯзык? // | < Thematic > Thematic<sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup> // <b><s>(nil)</s></b><sup class="noprint">[[d:Q29908205|[d]]]</sup>. — 7. — WD [[d:Q29908205|Q29908205]]. |
| Медиа (0/2) | ||||
|---|---|---|---|---|
| Тест | Ожидается | Фактически | Разница | |
| ❌ | Видеозапись на youtube{{Источник информации
|заглавие = Деятельность ВОЗ по научно-техническому анализу и прогнозированию в области здравоохранения
|qid издателя = Q7817
|id = 1m_4Y6pHmUw
|qid издания = Q866
|язык = ru
|дата = 2022-07-08
|дата обращения = 2022-11-22
|ref = ВОЗ
}}
| Деятельность ВОЗ по научно-техническому анализу и прогнозированию в области здравоохранения [видеозапись] // YouTube. — ВОЗ, 2022, 8 июля. — Дата обращения: 22 ноября 2022. | Деятельность ВОЗ по научно-техническому анализу и прогнозированию в области здравоохранения // | < > Деятельность ВОЗ по научно-техническому анализу и прогнозированию в области здравоохранения // <b><s>(nil)</s></b><sup class="noprint">[[d:Q866|[d]]]</sup>. — <b><s>(nil)</s></b><sup class="noprint">[[d:Q7817|[d]]]</sup>, |
| ❌ | Аудиозапись на Яндекс.Музыке{{Источник информации
|авторы = Ж. Н. Меренкова
|заглавие = Анемии при беременности
|ссылка = https://music.yandex.ru/album/10142231/track/70882375?activeTab=track-list
|тип = профессиональный медицинский подкаст
|qid издания = Q4537983
|издатель = Специализированное издательство «Медицинская литература»
|язык = ru
|дата = 2020-09-04
|ref = Меренкова
}}
| Меренкова Ж. Н. Анемии при беременности [аудиоконтент] : профессиональный медицинский подкаст // Яндекс Музыка. — Специализированное издательство «Медицинская литература», 2020, 4 сентября. | Меренкова Ж. Н. Анемии при беременности : профессиональный медицинский подкаст // | < > : профессиональный медицинский подкаст // <b><s>(nil)</s></b><sup class="noprint">[[d:Q4537983|[d]]]</sup>. — Специализированное издательство «Медицинская литература», 2020, <span class="nowrap">4 сентября</span>. — WD [[d:Q4537983|Q4537983]]. |
| Язык (0/1) | ||||
|---|---|---|---|---|
| Тест | Ожидается | Фактически | Разница | |
| ❌ | На двух языках{{Источник информации|Q101483459}}
| Whitlam J.[d] Harper Collins Portuguese dictionary : English-Portuguese, Portuguese-English : [англ., португ.] / J. Whitlam, Vitória Davies[d], M. Harland[d]. — Glasgow : HarperCollins UK[d], 1991. — OCLC 370343862. — WD Q101483459. | < < > <b><s>(nil)</s></b><sup class="error" title="Не указан язык (или языки, если их несколько) источника информации.">Язык?</sup>. — WD | |
| Подстановка (0/2) | ||||
|---|---|---|---|---|
| Тест | Ожидается | Фактически | Разница | |
| ❌ | Подстановка полей из Викиданных{{Источник информации|Q115962047
|forceSubst = 1
}}
| {{Источник информации|авторы=В. Г. Олифер, Н. А. Олифер|заглавие=Компьютерные сети. Принципы, технологии, протоколы[d]|редакция=4-е изд.|место=Санкт-Петербург|издатель=Питер|дата=2014-11-30|страниц=944|серия=Серия «Учебник для вузов»|isbn=978-5-496-00004-8|язык=ru|qid=Q115962047|офлайн=1}} | {{Источник информации|заглавие= | < информации| > информации|заглавие=<b><s>(nil)</s></b><sup class="noprint">[[d:Q115962047|[d]]]</sup> |
| ❌ | Подстановка полей источника, который на английском языке{{Источник информации|Q116814927
|forceSubst = 1
}}
| {{Источник информации|авторы=P. Talantov, Ravil Niyazov, Галина Михайловна Вирясова[d], Margarita Dranitsyna, Ilya Yasny|заглавие=Unapproved clinical trials in Russia: exception or norm?|ссылка=https://bmcmedethics.biomedcentral.com/articles/10.1186/s12910-021-00617-3%7Cстатус ссылки=открытый доступ|архивная ссылка=http://web.archive.org/web/20210426035711/https://bmcmedethics.biomedcentral.com/articles/10.1186/s12910-021-00617-3%7Cдата архивирования=2021-07-20|издание=BMC Medical Ethics[d]|язык издания=en|тип издания=scientific journal|издатель=BioMed Central, Springer Science+Business Media|дата=2021-04-20|том=22|выпуск=1|статья=46|doi=10.1186/S12910-021-00617-3|pmid=33879151|issn=1472-6939|язык=en|qid=Q116814927|офлайн=1}} | {{Источник информации|заглавие= | < информации| > информации|заглавие=<b><s>(nil)</s></b><sup class="noprint">[[d:Q116814927|[d]]]</sup>|язык=ru |
| Предупреждения и ошибки (2/4) | ||||
|---|---|---|---|---|
| Тест | Ожидается | Фактически | Разница | |
| ❌ | Выдача ошибки об отсутствии ссылки, если задана архивная ссылка{{Источник информации
|заглавие = Запись с архивной ссылкой, но без основной
|архивная ссылка = https://www.webcitation.org/lalalala?url=https://lalalala.local
|дата архивирования = 2023-08-21
|язык = en
|издание = Тесты
|архивная ссылка на издание = https://www.webcitation.org/lalalala?url=https://lalalala.local
|дата архивирования издания = 2023-08-21
}}
| Запись с архивной ссылкой, но без основной : [англ.] : [арх. 21 августа 2023] // Тесты [арх. 21 августа 2023]. — (Указана архивная ссылка, но не указана основная. Указана архивная ссылка на издание, но не указана основная.). | Ошибка Lua на строке 206: attempt to concatenate local 'abbr' (a nil value). | < <s > <strong class="error"><span class="scribunto-error mw-scribunto-error-ee5e90fb">Ошибка Lua на строке 206: attempt to concatenate local 'abbr' (a nil value).</span></strong> |
| ❌ | Выдача ошибки об отсутствии даты архивирования{{Источник информации
|заглавие = Запись с архивной ссылкой, но без даты архивирования
|архивная ссылка = https://www.webcitation.org/lalalala?url=https://lalalala.local
|ссылка = https://lalalala.local
|язык = en
|издание = Тесты
|архивная ссылка на издание = https://www.webcitation.org/lalalala?url=https://lalalala.local
|ссылка на издание = https://lalalala.local
}}
| Запись с архивной ссылкой, но без даты архивирования : [англ.] // Тесты. — (Указана архивная ссылка, но не указана дата архивирования. Указана архивная ссылка на издание, но не указана дата архивирования.). | Ошибка Lua на строке 206: attempt to concatenate local 'abbr' (a nil value). | < <s > <strong class="error"><span class="scribunto-error mw-scribunto-error-ee5e90fb">Ошибка Lua на строке 206: attempt to concatenate local 'abbr' (a nil value).</span></strong> |
План разработки
План работ:
|
См. также
- WDBackend — модуль получения информации из Викиданных по задаваемой схеме.
- WDSource — модуль получения информации об источнике из соответствующего элемента Викиданных.
require('strict')
local p = {}
local NS_MODULE = 828 --: https://www.mediawiki.org/wiki/Extension_default_namespaces
local moduleNamespace = mw.site.namespaces[NS_MODULE].name
local wikidata = require(moduleNamespace .. ':WDCommon')
local function dump(obj, level)
if type(obj) ~= 'table' then
if type(obj) == 'string' then
return "'" .. obj .. "'"
else
return tostring(obj)
end
end
if not level then
level = 0
end
local indent = string.rep(' ', level)
local s = '{'
local isFirst = true
for i, v in pairs(obj) do
if not isFirst then
s = s .. ','
end
s = s .. '\n'
local currIndent = string.rep(' ', level + 4)
s = s .. currIndent
if type(i) == 'string' then
s = s .. i .. ' = '
end
s = s .. dump(v, level + 4)
isFirst = false
end
s = s .. '\n' .. indent .. '}'
return s
end
local Formatter = {
profile = nil,
processField = {},
}
-- Transforms tag table hierarchy to mediawiki html container representation.
-- Returns deepest child.
function Formatter:tagToContainer(tag, parentContainer, source)
if not tag or not tag.name then
return parentContainer
end
local container = parentContainer
while tag do
if container then
container = container:tag(tag.name)
else
container = mw.html.create(tag.name)
end
if tag.classes then
for _, currClass in ipairs(tag.classes) do
container:addClass(currClass)
end
end
if tag.attr then
for attr, value in pairs(tag.attr) do
if type(value) == 'function' then
value = value(source)
end
container:attr(attr, value)
end
end
if tag.css then
for key, value in pairs(tag.css) do
container:css(key, value)
end
end
tag = tag.tag
end
return container
end
function Formatter:new(profile, source, langCode, params)
local obj = {}
setmetatable(obj, self)
self.__index = self
self.profile = profile
self.source = source
self.lang = langCode
self.params = params
self.state = {
empty = true,
linkedEntities = {},
}
self.lastAddedText = ''
self.container = mw.html.create()
assert(self.profile.tag ~= nil, 'Not root container found. Use tag profile field.')
return obj
end
function Formatter.processField.numericalRanges(source, processedData, result)
local defaultLangObj = mw.getContentLanguage()
local defaultLang = defaultLangObj:getCode()
local rangeSign
if defaultLang == 'ru' then
rangeSign = '—'
elseif defaultLang == 'ko' then
rangeSign = '~'
else
rangeSign = '–'
end
result.wikitext = mw.ustring.gsub(result.wikitext, '-', rangeSign)
end
function Formatter.processField.squareBrackets(source, processedData, result)
result.text = '[' .. result.text .. ']'
result.wikitext = '[' .. result.wikitext .. ']'
end
function Formatter.processField.nowiki(source, processedData, result)
result.wikitext = mw.text.nowiki(result.wikitext)
end
function Formatter.processField.dash(source, processedData, result)
local defaultLangObj = mw.getContentLanguage()
local defaultLang = defaultLangObj:getCode()
local dashSign
if defaultLang == 'ru' then
dashSign = ' — '
end
result.wikitext = mw.ustring.gsub(result.wikitext, ' %- ', dashSign)
result.text = mw.ustring.gsub(result.text, ' %- ', dashSign)
end
function Formatter.processField.unit(source, processedData, result, state)
local entity = processedData.fieldTable.entity
if not entity then
return
end
local unit = wikidata.unit(entity, processedData.langCode)
if (unit and state.groupEmpty and processedData.capitalize) or processedData.forceCapitalize then
unit = mw.ustring.gsub(unit, '^%l', mw.ustring.upper)
end
result.text = unit
result.wikitext = unit
end
function Formatter.processField.abbr(source, processedData, result, state)
local entity = processedData.fieldTable.entity
if not entity or processedData.fieldTable.exact then
return
end
local abbr, _, ok = wikidata.abbrBiblio(entity, processedData.langCode)
if (abbr and state.groupEmpty and processedData.capitalize) or processedData.forceCapitalize then
abbr = mw.ustring.gsub(abbr, '^%l', mw.ustring.upper)
end
if abbr and ok then
abbr = mw.ustring.gsub(abbr, ' ', ' ')
end
result.text = abbr
result.wikitext = abbr
end
function Formatter.processField.short(source, processedData, result, state)
local entity = processedData.fieldTable.entity
if not entity or processedData.fieldTable.exact then
return
end
local short = wikidata.short(entity, processedData.langCode)
if (short and state.groupEmpty and processedData.capitalize) or processedData.forceCapitalize then
short = mw.ustring.gsub(short, '^%l', mw.ustring.upper)
end
if not short then
return
end
result.text = short
result.wikitext = short
end
function Formatter.processField.abbrWithHint(source, processedData, result, state)
local entity = processedData.fieldTable.entity
if not entity or processedData.fieldTable.exact then
return
end
local abbr, _, ok = wikidata.abbrBiblio(entity, processedData.langCode)
if (abbr and state.groupEmpty and processedData.capitalize) or processedData.forceCapitalize then
abbr = mw.ustring.gsub(abbr, '^%l', mw.ustring.upper)
end
if abbr and ok then
abbr = mw.ustring.gsub(abbr, ' ', ' ')
end
if result.text ~= abbr then
result.wikitext = '<abbr title="' .. result.wikitext .. '">' .. abbr .. '</abbr>'
result.text = abbr
end
end
function Formatter.processField.date(source, processedData, result)
if type(processedData.fieldTable.value) ~= 'table' then
return
end
local langObj = mw.getLanguage(processedData.langCode)
result.text = langObj:formatDate('j xg Y', processedData.fieldTable.value.timestamp)
result.wikitext = result.text
end
function Formatter.processField.dateISO(source, processedData, result)
if type(processedData.fieldTable.value) ~= 'table' then
return
end
local langObj = mw.getLanguage(processedData.langCode)
result.text = langObj:formatDate('Y-m-d', processedData.fieldTable.value.timestamp)
result.wikitext = result.text
end
function Formatter.processField.uriScheme(source, processedData, result)
local entity = processedData.fieldTable.entity
if not entity then
return
end
result.text = wikidata.uriScheme(entity)
result.wikitext = result.text
end
function Formatter.processField.quantity(source, processedData, result)
local fieldTable = processedData.fieldTable
if not fieldTable.unitEntity then
return
end
local unit = wikidata.unit(fieldTable.unitEntity, processedData.langCode)
if unit then
result.text = result.text .. ' ' .. unit
result.wikitext = result.wikitext .. ' ' .. unit
end
end
local function nameFromFieldTable(nameTable)
local value = nameTable.value
local ok = true
if not value then
local label = mw.wikibase.getLabel(nameTable.entity)
if label then
value = mw.wikibase.getLabel(nameTable.entity) .. '<sup>[[d:' .. nameTable.entity .. '|?]]</sup>'
else
value = '?' .. '<sup>[[d:' .. nameTable.entity .. '|?]]</sup>'
end
ok = false
end
return value, ok
end
local function nameToInitial(nameTable)
local value = nameTable.value
local ok
if not value then
local label = mw.wikibase.getLabel(nameTable.entity)
if label then
value = label .. '<sup>[[d:' .. nameTable.entity .. '|?]]</sup>'
else
value = '?' .. '<sup>[[d:' .. nameTable.entity .. '|?]]</sup>'
end
ok = false
else
value = mw.ustring.sub(value, 1, 1) .. '.'
ok = true
end
return value, ok
end
local function namesToInitial(nameTables)
local value, ok
if table.getn(nameTables) == 0 then
value, ok = nameToInitial(nameTables)
else
value = ''
ok = true
for i, nameTable in ipairs(nameTables) do
if i > 1 then
value = value .. ' '
end
local currValue, currOk = nameToInitial(nameTable)
value = value .. currValue
ok = ok and currOk
end
end
return value, ok
end
function Formatter.processField.person(source, processedData, result)
-- currently supports only names with givenName and pathronym/mathronym,
-- middle names are not supported if they are a part of givenName
local fieldTable = processedData.fieldTable
local name
if fieldTable.exact then
name = result.text
if name:match(',') then
name = name:gsub('([^,]+), *(.+)', '%2 %1')
result.text = name
result.wikitext = name
end
return
end
if fieldTable.components and fieldTable.components.familyName and fieldTable.components.givenName then
local ok
name, ok = namesToInitial(fieldTable.components.givenName)
if fieldTable.components.ancestorName then
local ancestorName, ancestorNameOk = namesToInitial(fieldTable.components.ancestorName)
name = name .. ' ' .. ancestorName
ok = ok and ancestorNameOk
end
local familyName, familyNameOk = nameFromFieldTable(fieldTable.components.familyName)
name = name .. ' ' .. familyName
ok = ok and familyNameOk
if not ok then
result.linked = true
end
else
local entity = processedData.fieldTable.entity
if entity then
name = wikidata.abbr(entity, processedData.langCode)
else
name = processedData.value
end
if not name then
name = mw.wikibase.getLabel(entity) .. '<sup>[[d:' .. entity .. '|?]]</sup>'
end
end
result.text = name
result.wikitext = result.text
end
function Formatter.processField.personReversed(source, processedData, result)
-- currently supports only names with givenName and pathronym/mathronym,
-- middle names are not supported if they are a part of givenName
local fieldTable = processedData.fieldTable
local name
if fieldTable.exact then
name = result.text
if not name:match(',') then
local initials, familyName = mw.ustring.match(name, '^(.+%.) ([^%. ]+)$')
if not initials or not familyName then
return
end
name = familyName .. ', ' .. initials
result.text = name
result.wikitext = name
end
return
end
if fieldTable.components and fieldTable.components.familyName and fieldTable.components.givenName then
local ok
local familyName, ok = nameFromFieldTable(fieldTable.components.familyName)
local givenName, givenNameOk = namesToInitial(fieldTable.components.givenName)
ok = ok and givenNameOk
name = familyName .. ', ' .. givenName
if fieldTable.components.ancestorName then
local ancestorName, ancestorNameOk = namesToInitial(fieldTable.components.ancestorName)
ok = ok and ancestorNameOk
name = name .. ' ' .. ancestorName
end
if not ok then
result.linked = true
end
else
local entity = processedData.fieldTable.entity
if entity then
name = wikidata.abbr(entity, processedData.langCode)
else
return
end
if not name then
name = mw.wikibase.getLabel(entity) .. '<sup>[[d:' .. entity .. '|?]]</sup>'
end
end
result.text = name
result.wikitext = result.text
end
function Formatter.processField.personReversedNoComma(source, processedData, result)
-- currently supports only names with givenName and pathronym/mathronym,
-- middle names are not supported if they are a part of givenName
local fieldTable = processedData.fieldTable
local name
if fieldTable.exact then
name = result.text
if name:match(',') then
name = name:gsub('([^,]+), *(.+)', '%2 %1')
result.text = name
result.wikitext = name
else
local initials, familyName = mw.ustring.match(name, '^(.+%.) ([^%. ]+)$')
if not initials or not familyName then
return
end
name = familyName .. ' ' .. initials
result.text = name
result.wikitext = name
end
return
end
if fieldTable.exact then
name = result.text
if name:match(',') then
name = name:gsub('([^,]+), *(.+)', '%2 %1')
result.text = name
result.wikitext = name
end
return
end
if fieldTable.components and fieldTable.components.familyName and fieldTable.components.givenName then
local ok
local familyName, ok = nameFromFieldTable(fieldTable.components.familyName)
local givenName, givenNameOk = namesToInitial(fieldTable.components.givenName)
ok = ok and givenNameOk
name = familyName .. ' ' .. givenName
if fieldTable.components.ancestorName then
local ancestorName, ancestorNameOk = namesToInitial(fieldTable.components.ancestorName)
ok = ok and ancestorNameOk
name = name .. ' ' .. ancestorName
end
if not ok then
result.linked = true
end
else
local entity = processedData.fieldTable.entity
if entity then
name = wikidata.abbr(entity, processedData.langCode)
else
return
end
if not name then
name = mw.wikibase.getLabel(entity) .. '<sup>[[d:' .. entity .. '|?]]</sup>'
end
end
result.text = name
result.wikitext = result.text
end
function Formatter.processField.lowercase(source, processedData, result)
result.text = mw.ustring.lower(result.text)
result.wikitext = mw.ustring.lower(result.wikitext)
end
function Formatter.processField.wikisource(source, processedData, result)
if result.linked then
return
end
local entity = processedData.fieldTable.entity
if not entity then
return
end
local title = mw.wikibase.getSitelink(entity, processedData.langCode .. 'wikisource')
if not title then
return
end
result.wikitext = '[[s:' .. title .. '|' .. result.text .. ']]'
result.linked = true
end
function Formatter.processField.wikiversity(source, processedData, result)
if result.linked then
return
end
local entity = processedData.fieldTable.entity
if not entity then
return
end
local title = mw.wikibase.getSitelink(entity, processedData.langCode .. 'wikiversity')
if not title then
return
end
result.wikitext = '[[s:' .. title .. '|' .. result.text .. ']]'
result.linked = true
end
function Formatter.processField.wikibooks(source, processedData, result)
if result.linked then
return
end
local entity = processedData.fieldTable.entity
if not entity then
return
end
local title = mw.wikibase.getSitelink(entity, processedData.langCode .. 'wikibooks')
if not title then
return
end
result.wikitext = '[[s:' .. title .. '|' .. result.text .. ']]'
result.linked = true
end
function Formatter.processField.link(source, processedData, result)
if result.linked or not processedData.url then
return
end
result.wikitext = '[' .. processedData.url .. ' ' .. result.wikitext .. ']'
result.linked = true
end
function Formatter.processField.safeLink(source, processedData, result)
if result.linked or not processedData.url then
return
end
if mw.ustring.match(result.wikitext, '%[') then
return
end
result.wikitext = '[' .. processedData.url .. ' ' .. result.wikitext .. ']'
result.linked = true
end
function Formatter.processField.wikilink(source, processedData, result)
if result.linked then
return
end
if processedData.wikilink then
result.wikitext = '[[' .. processedData.wikilink .. '|' .. result.wikitext .. ']]'
return
end
local entity = processedData.fieldTable.entity
if not entity then
return
end
if result.state.linkedEntities[entity] then
return
end
local wikitext
wikitext, entity = wikidata.base.wikilink(entity, result.wikitext)
if result.state.linkedEntities[entity] or not entity then
return
end
result.wikitext = wikitext
result.state.linkedEntities[entity] = true
result.linked = true
end
function Formatter.processField.resolveWikilink(source, processedData, result)
if result.linked then
return
end
if processedData.wikilink then
result.wikitext = '[[' .. processedData.wikilink .. '|' .. result.wikitext .. ']]'
return
end
local entity = processedData.fieldTable.entity
if not entity then
return
end
if result.state.linkedEntities[entity] then
return
end
local wikitext
wikitext, entity = wikidata.base.wikilink(entity, result.wikitext)
if not entity then
entity = wikidata.base.resolveParent(processedData.fieldTable.entity)
if not entity then
return
end
wikitext, entity = wikidata.base.wikilink(entity, result.wikitext)
end
if not entity or result.state.linkedEntities[entity] then
return
end
result.wikitext = wikitext
result.state.linkedEntities[entity] = true
result.linked = true
end
function Formatter.processField.valuableWikidata(source, processedData, result)
if result.linked then
return
end
local entity = processedData.fieldTable.entity
if not entity or result.state.linkedEntities[entity] then
return
end
local entityObj = mw.wikibase.getEntity(entity)
if entityObj.sitelinks then
result.wikitext = result.wikitext .. '<sup>[[d:' .. entity .. '|[d]]]</sup>'
result.state.linkedEntities[entity] = true
result.linked = true
end
end
function Formatter.processField.wikidata(source, processedData, result)
if result.linked then
return
end
local entity = processedData.fieldTable.entity
if not entity or result.state.linkedEntities[entity] then
return
end
result.wikitext = result.wikitext .. '<sup class="noprint">[[d:' .. entity .. '|[d]]]</sup>'
result.state.linkedEntities[entity] = true
result.linked = true
end
function Formatter.processField.forceWikidata(source, processedData, result)
local entity = processedData.fieldTable.entity
if not entity then
return
end
result.wikitext = result.wikitext .. '<sup>[[d:' .. entity .. '|[d]]]</sup>'
result.state.linkedEntities[entity] = true
result.linked = true
end
function Formatter.processField.wikidataLink(source, processedData, result)
if result.linked then
return
end
local entity = processedData.fieldTable.entity
if not entity then
return
end
result.wikitext = '[[d:' .. entity .. '|' .. result.wikitext .. ']]'
result.linked = true
end
function Formatter.processField.forceWikidataLink(source, processedData, result)
local entity = processedData.fieldTable.entity
if not entity then
return
end
result.wikitext = '[[d:' .. entity .. '|' .. result.wikitext .. ']]'
result.linked = true
end
function Formatter.processField.entity(source, processedData, result)
local entity = processedData.fieldTable.entity
if not entity then
return
end
result.text = entity
result.wikitext = entity
end
local function fieldTableByPath(source, path)
if type(path) == 'table' then
local currField = nil
local currFieldComponents = source
for _, currFieldName in ipairs(path) do
if type(currFieldName) == 'string' then
if not currFieldComponents then
return nil
end
currField = currFieldComponents[currFieldName]
else
currField = currField[currFieldName]
end
if not currField then
return nil
end
currFieldComponents = currField.components
end
return currField
end
return source[path]
end
local function fieldValueByPath(source, path)
local t = fieldTableByPath(source, path)
if not t then
return nil
end
if type(path) == 'table' and path.sub then
if not t.value then
return nil
end
return t.value[path.sub]
end
return t.value
end
local function urlFromMaskByPart(part, source, fieldValue, langCode)
if part.urlMaskProp then
local urlMask = wikidata.urlMask(part.urlMaskProp, langCode)
if urlMask then
return urlMask:gsub('%$1', fieldValue)
end
elseif part.urlField then
local urlTable = source[part.urlField]
if urlTable then
if type(urlTable) == 'table' then
return urlTable.value
else
return urlTable
end
end
end
return nil
end
local function wikilinkFromMaskByPart(part, source, fieldValue)
if part.wikilinkMask then
return part.wikilinkMask:gsub('%$1', fieldValue)
end
return nil
end
function Formatter:forceLangByPart(part, source)
local langCode
if not part.forceLang then
langCode = self.lang
end
if langCode then
return langCode
elseif part.forceLang == 'fallback' then
langCode = 'en'
elseif part.forceLang == 'default' or not part.forceLang then
local defaultLangObj = mw.getContentLanguage()
local defaultLang = defaultLangObj:getCode()
langCode = defaultLang
else
langCode = part.forceLang
end
return langCode
end
-- Format field with all neccessary data supplied by arguments.
function Formatter:formatField(source, part, fieldTable, fieldValue, state)
local processedData = {
field = part.field,
wikilink = wikilinkFromMaskByPart(part, source, fieldValue),
langCode = self:forceLangByPart(part, source),
fieldTable = fieldTable,
capitalize = (part.capitalize or (part.capitalize == nil)) and (state.index == 1),
forceCapitalize = (part.capitalize == true and state.index == 1),
}
processedData.url = urlFromMaskByPart(part, source, fieldValue, processedData.langCode)
local value = fieldValue
local linked = false
if fieldTable.entity and (processedData.langCode ~= self.lang or not value) then
if processedData.langCode then
value = mw.wikibase.getLabelByLang(fieldTable.entity, processedData.langCode)
if not value then
value = mw.wikibase.getLabel(fieldTable.entity)
if value then
value = value .. '<sup>[[d:' .. fieldTable.entity .. '|?]]</sup>'
linked = true
end
end
else
value = mw.wikibase.getLabel(fieldTable.entity)
end
end
if value and type(value) == 'string' then
if (state.groupEmpty and processedData.capitalize) or processedData.forceCapitalize then
value = mw.ustring.gsub(value, '^%l', mw.ustring.upper)
end
end
if type(value) == 'table' then
value = dump(value)
elseif value == nil then
value = '<b><s>(nil)</s></b>'
end
processedData.value = value
local result = {
wikitext = value,
text = value,
state = state,
linked = linked,
}
if not part.format then
state.groupEmpty = false
return result
end
for _, formatFunc in ipairs(part.format) do
formatFunc(source, processedData, result, state)
end
state.groupEmpty = false
return result
end
-- Used if fieldTable contains array.
function Formatter:formatFieldAsArray(source, part, fieldTable, state)
local text = ''
local wikitext = ''
local count = table.getn(fieldTable)
local cutCount = 0
if part.limits and count > part.limits.max then
cutCount = count - part.limits.cutTo
count = part.limits.cutTo
end
local delimiter = part.itemsDelimiter
if not delimiter then
delimiter = ', '
end
for i=1, count do
state.index = i
local currFieldTable = fieldTable[i]
local currResult = self:formatField(source, part, currFieldTable, currFieldTable.value, state)
wikitext = wikitext .. currResult.wikitext
text = text .. currResult.text
if i < count then
text = text .. delimiter
wikitext = wikitext .. delimiter
end
end
if cutCount > 0 then
local cutText = ''
for i=count + 1, count + cutCount do
state.index = i
local currFieldTable = fieldTable[i]
local currResult = self:formatField(source, part, currFieldTable, currFieldTable.value, state)
cutText = cutText .. currResult.text
if i < count + cutCount then
cutText = cutText .. delimiter
end
end
local processedData = {
field = part.field,
langCode = self:forceLangByPart(part, source),
fieldTable = fieldTable,
}
local othersText, othersWikitext = part.limits.replaceBy(source, processedData, cutText)
text = text .. othersText
wikitext = wikitext .. othersWikitext
end
return text, wikitext
end
local function fieldTableAndValueByPart(source, part)
if part.entity or part.value then
return { entity = part.entity, value = part.value }, part.value
else
return fieldTableByPath(source, part.field), fieldValueByPath(source, part.field)
end
end
-- Formats the field and returns resulting text.
function Formatter:formatFieldComponents(source, part, state)
local fieldTable, fieldValue = fieldTableAndValueByPart(source, part)
if type(fieldTable) ~= 'table' then
error('Field ' .. dump(part.field) .. ' is not a table. Its type is ' .. type(fieldTable))
end
local text
local wikitext
if table.getn(fieldTable) > 0 then
text, wikitext = self:formatFieldAsArray(source, part, fieldTable, state)
else
state.index = 1
local result = self:formatField(source, part, fieldTable, fieldValue, state)
text = result.text
wikitext = result.wikitext
end
return { text = text, wikitext = wikitext }
end
-- Format single field by its data.
function Formatter:commonFormatField(part, parentContainer, source)
local result = self:formatFieldComponents(source, part, self.state)
parentContainer:wikitext(result.wikitext)
self.lastAddedText = result.text
self.state.empty = false
end
function Formatter:ensureEndsWith(endsText, parentContainer)
if self.lastAddedText and endsText then
local len = mw.ustring.len(endsText)
if mw.ustring.sub(self.lastAddedText, -len) ~= endsText then
parentContainer:wikitext(endsText)
end
end
end
function Formatter:ensureEndsAndAddDelimiter(group, part, parentContainer, groupEmpty, source)
if self.state.empty or self.state.delimiterAdded then
return
end
local delimiter = part.delimiter
local endsText = part.ensureEnds
if (delimiter == nil or groupEmpty) and not part.forceDelimiter then
if group.childDelimiter or group.childEnsureEnds then
delimiter = group.childDelimiter
endsText = group.childEnsureEnds
end
end
if not delimiter and not endsText then
return
end
self:ensureEndsWith(endsText, parentContainer)
if type(delimiter) == 'function' then
delimiter = delimiter(source)
end
parentContainer:wikitext(delimiter)
self.state.delimiterAdded = true
end
-- Checks whether the field is set in the source.
local function fieldExists(source, path)
local t = fieldTableByPath(source, path)
if not t then
return false
end
if type(path) == 'table' and path.sub then
if not t.value then
return false
end
return (t.value[path.sub] ~= nil)
end
return true
end
local fieldConflicts, fieldDepends
fieldConflicts = function(conflicts, source)
if not conflicts then
return false
end
if type(conflicts) == 'table' and not conflicts.isPath then
for _, currField in ipairs(conflicts) do
if type(currField) == 'string' or currField.isPath then
if fieldExists(source, currField) then
return true
end
else
if fieldDepends(currField, source) then
return true
end
end
end
else
return fieldExists(source, conflicts)
end
return false
end
fieldDepends = function(depends, source)
if not depends then
return true
end
if type(depends) == 'table' and not depends.isPath then
for _, currField in ipairs(depends) do
if type(currField) == 'string' or currField.isPath then
if not fieldExists(source, currField) then
return false
end
else
if not fieldConflicts(currField, source) then
return false
end
end
end
else
return fieldExists(source, depends)
end
return true
end
-- Look-a-head for groups by data row that can be displayed within
-- specified group. For the single field returns true if it can be displayed.
function Formatter:groupRowIsAvailable(group, childGroups, localSource)
if table.getn(childGroups) > 0 then
local found = false
for _, subGroup in ipairs(childGroups) do
if not subGroup.isStatic then
if self:groupIsAvailable(subGroup, localSource) then
found = true
break
end
end
end
if group.cond and not group.cond(localSource, self.params) then
return false
end
return found
end
if not fieldExists(localSource, group.field) and not group.entity and group.value == nil then
return false
end
-- TODO: тест на удаление этого условия
if group.cond and not group.cond(localSource, self.params) then
return false
end
return true
end
-- Look-a-head for groups and data that can be displayed within specified group.
-- For the single field returns true if it can be displayed.
function Formatter:groupIsAvailable(group, source)
if fieldConflicts(group.conflicts, source) then
return false
end
if not fieldDepends(group.depends, source) then
return false
end
local childGroups = group.groups or group
local hasChildGroups = (table.getn(childGroups) > 0)
local localSource
if hasChildGroups and group.field then
localSource = source[group.field]
else
localSource = source
end
if not localSource then
error(tostring(group.field))
end
if table.getn(localSource) > 0 then
local found = false
if childGroups then
for _, row in ipairs(localSource) do
if not group.cond or group.cond(row, self.params) then
for _, subGroup in ipairs(childGroups) do
if not subGroup.isStatic then
if self:groupIsAvailable(subGroup, row) then
found = true
break
end
end
end
end
if found then
break
end
end
else
if not group.entity and group.value == nil then
for _, row in ipairs(localSource) do
if fieldExists(row, group.field) then
found = true
break
end
end
end
end
return found
end
return self:groupRowIsAvailable(group, childGroups, source)
end
-- Formats the group and puts it into the parentContainer.
function Formatter:formatGroup(parentGroup, group, parentContainer, source)
if not self:groupIsAvailable(group, source) then
return
end
local state = self.state
local groupEmpty = state.groupEmpty
local childGroups = group.groups or group
local hasChildGroups = (table.getn(childGroups) > 0)
if hasChildGroups and not group.passthrough then
state.groupEmpty = true
end
local localSource
if group.field and hasChildGroups then
localSource = source[group.field]
else
localSource = source
end
local prefix = group.prefix
if parentContainer then
self:ensureEndsAndAddDelimiter(parentGroup, group, parentContainer, state.groupEmpty, localSource)
end
if prefix and parentContainer then
parentContainer:wikitext(prefix)
self.lastAddedText = self.lastAddedText .. prefix
end
local groupContainer
if hasChildGroups then
if table.getn(localSource) > 0 then
groupContainer = parentContainer
for _, row in ipairs(localSource) do
if not group.cond or group.cond(row, self.params) then
if self:groupRowIsAvailable(group, childGroups, row) then
local currContainer = self:tagToContainer(group.tag, groupContainer, source) or parentContainer
for _, part in ipairs(childGroups) do
self:formatGroup(group, part, currContainer, row)
end
end
end
end
else
groupContainer = self:tagToContainer(group.tag, parentContainer, source) or parentContainer
for _, part in ipairs(childGroups) do
self:formatGroup(group, part, groupContainer, localSource)
end
end
else
groupContainer = self:tagToContainer(group.tag, parentContainer, source) or parentContainer
self:commonFormatField(group, groupContainer, localSource)
self.state.delimiterAdded = false
end
if not state.groupEmpty then
local suffix = group.suffix
if suffix and parentContainer then
parentContainer:wikitext(suffix)
self.lastAddedText = self.lastAddedText .. suffix
end
end
return groupContainer
end
function Formatter:format()
local rootContainer = self:formatGroup(nil, self.profile, self.container, self.source)
self:ensureEndsWith(self.profile.ensureEnds, rootContainer)
end
function Formatter:getAsText()
return tostring(self.container:allDone())
end
function p.format(profile, source, langCode, params)
-- Temporary solution for backward compatibility
if type(langCode) == 'table' then
params = langCode
langCode = 'ru'
end
if not langCode and source.langCode then
langCode = source.langCode.value
end
local f = Formatter:new(profile, source, langCode, params)
f:format()
return f:getAsText()
end
p.f = Formatter.processField
return p