cIhuV>XwiZ5H8f{cDUkz$dSW4kZ=cDekK>
zACzgXDy+?piQru|lzpcP-bJ#nIby()OKB>7E><>A2i
z(eobBQxUZY$fX1JO7`)JIaszt{yUqQ!SsTX&aW*_9Gai**zLQEFFJ2!{n?$*--W5%
zaEh9DDc{RKBQfi43M&Hb8=-@DIKl@V<6{48g=-0nT~LvIU`t)2a6G*tDJ7RQ>-rEF
z_0{*wchK$Guj;}$tEL#lBHPBoFm7BiFY`N7TV#04mF=%{ex9oNDjQ=}Zh
zvbIl*tN4V}oc(~>nH}#*pR?+2xHRNLsv3Oj5rx8>FOuB#PJRs
zTUgE(4q;b4=2JAE=HXQ|pV9au=z{C~Z*K1@nn-i$GMWf?{0WpaSPdghpmAM!2V602
zgokc*5^m+nM=Gkh8wM$;rD!6JvO3cWa^?LMasmw(Wpj=(Z%pnCNF;10k@)pFS5El#
zN<5G8+n+e7YwX)4g+jx7=5qzmittp`WZrvxFWm
zwQyWTL?wrUL>S!DUCAvHr;!d8_|bzWQh&LV7kZ~J-2eap
literal 0
HcmV?d00001
diff --git a/packagedef b/packagedef
new file mode 100644
index 0000000..729e246
--- /dev/null
+++ b/packagedef
@@ -0,0 +1,19 @@
+ПутКПараметрам = ОбъединитьПути(ТекущийСценарий().Каталог, "src", "Модули", "ПараметрыПриложения.os");
+Параметры = ЗагрузитьСценарий(ПутКПараметрам);
+
+Описание.Имя(Параметры.ИмяПриложения())
+ .Версия(Параметры.Версия())
+ .Автор("")
+ .АдресАвтора("")
+ .Описание("Отправка замечаний edt в отчет для сонара")
+ .ВерсияСреды("1.7.0")
+ .ВключитьФайл("src")
+ .ВключитьФайл("doc")
+ .ВключитьФайл("tasks")
+ .ВключитьФайл("custom-rules.json")
+ .ЗависитОт("logos")
+ .ЗависитОт("cli")
+ .ЗависитОт("fs")
+ .ЗависитОт("v8metadata-reader")
+ .ИсполняемыйФайл("src/main.os")
+ ;
diff --git a/src/main.os b/src/main.os
new file mode 100644
index 0000000..99f49e0
--- /dev/null
+++ b/src/main.os
@@ -0,0 +1,61 @@
+#Использовать "."
+#Использовать cli
+
+Перем Лог;
+
+Процедура ВыполнитьПриложение()
+
+ Приложение = Новый КонсольноеПриложение(ПараметрыПриложения.ИмяПриложения(),
+ "Приложение для работы с файлами ошибок статических анализаторов",
+ ЭтотОбъект);
+
+ Приложение.Версия("version", ПараметрыПриложения.Версия());
+
+ Приложение.Опция("v verbose", Ложь, "Вывод отладочной информация в процессе выполнения")
+ .Флаговый();
+
+ Приложение.Опция("f file", "", "Путь к внешнему файлу-коллектору замечаний")
+ .ТСтрока();
+
+ Приложение.ДобавитьКоманду("parse", "Создание отчета",
+ Новый КомандаПарсерОтчетаЕДТ);
+
+ Приложение.ДобавитьКоманду("publish", "Удаление из выбранного файла правил служебных блоков,
+ | результирующий файл готов для загрузки в сонар",
+ Новый КомандаПубликацияПравил);
+
+ Приложение.Запустить(АргументыКоманднойСтроки);
+
+КонецПроцедуры
+
+Процедура ПередВыполнениемКоманды(Знач Команда) Экспорт
+
+ ОтладкаВключена = Команда.ЗначениеОпции("verbose");
+
+ ПараметрыПриложения.УстановитьРежимОтладки(ОтладкаВключена);
+
+ ВнешнийФайлОписаний = Команда.ЗначениеОпции("file");
+
+ Если ЗначениеЗаполнено(ВнешнийФайлОписаний) Тогда
+ Файл = Новый Файл(ВнешнийФайлОписаний);
+ Если НЕ (Файл.Существует() И Файл.ЭтоФайл()) Тогда
+ Лог.КритичнаяОшибка("Файл %1 недоступен", ВнешнийФайлОписаний);
+ КонецЕсли;
+ КонецЕсли;
+
+ ПараметрыПриложения.УстановитьКонтекстСохранения(ВнешнийФайлОписаний);
+
+КонецПроцедуры
+
+Лог = ПараметрыПриложения.Лог();
+
+Попытка
+
+ ВыполнитьПриложение();
+
+Исключение
+
+ Лог.КритичнаяОшибка(ОписаниеОшибки());
+ ЗавершитьРаботу(1);
+
+КонецПопытки;
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262BSL.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262BSL.os"
new file mode 100644
index 0000000..a624388
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262BSL.os"
@@ -0,0 +1,136 @@
+#Использовать fs
+
+#Область ОписаниеПеременных
+
+// Содержит формируемый отчет в формате BSL LS
+Перем Отчет;
+
+// Переменная для логирования
+Перем Лог;
+
+#КонецОбласти
+
+#Область ПрограммныйИнтерфейс
+
+// Создает новое пустое замечание для файла и пополняет коллекци замечаний.
+//
+// Параметры:
+// Путь - Строка - Путь к bsl файлу для регистрации нового замечания
+//
+// Возвращаемое значение:
+// Структура - Все поля описаны в файле diagnostic.json
+//
+Функция НовыйЗамечаниеДляОбъекта(Путь) Экспорт
+
+ // СырыеДанныеСтрокой() - промежуточный слой для хранения замечаний. Ключ для регистрации - имя файла.
+ РазделЗамечанияДляФайла = Отчет[СырыеДанныеСтрокой()].Получить(Путь);
+
+ Если РазделЗамечанияДляФайла = Неопределено Тогда
+
+ Отчет[СырыеДанныеСтрокой()].Вставить(Путь, Новый Структура("diagnostics", Новый Массив));
+
+ КонецЕсли;
+
+ Замечание = Замечание();
+
+ Отчет[СырыеДанныеСтрокой()][Путь].diagnostics.Добавить(Замечание);
+
+ Возврат Замечание;
+
+КонецФункции
+
+// Записывает отчет в файл, если путь не передан, отчет запишется в текущий каталог запуска
+//
+// Параметры:
+// Путь - Строка - Путь к файлу, куда будет записан отчет в формате BSL LS
+//
+Процедура ЗаписатьОтчет(Путь = Неопределено) Экспорт
+
+ Если Путь = Неопределено Тогда
+ Путь = ОбъединитьПути(ТекущийКаталог(), "edt-bsl-report.json");
+ КонецЕсли;
+
+ ЗаписьJSON = Новый ЗаписьJSON;
+ ЗаписьJSON.ОткрытьФайл(Путь, "UTF-8", , Новый ПараметрыЗаписиJSON(, Символы.Таб));
+
+ ИзменитьСтруктуруОтчета();
+
+ ЗаписатьJSON(ЗаписьJSON, Отчет);
+ ЗаписьJSON.Закрыть();
+
+ Лог.Информация("Записан файл %1", Путь);
+
+КонецПроцедуры
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+Процедура ИзменитьСтруктуруОтчета()
+
+ Для Каждого ОбъектЗамечаний Из Отчет[СырыеДанныеСтрокой()] Цикл
+
+ Замечание = Новый Соответствие;
+ Замечание.Вставить("path", ОбъектЗамечаний.Ключ);
+ Замечание.Вставить("diagnostics", ОбъектЗамечаний.Значение.diagnostics);
+ Отчет["fileinfos"].Добавить(Замечание);
+
+ КонецЦикла;
+
+ Отчет.Удалить(СырыеДанныеСтрокой());
+
+КонецПроцедуры
+
+Функция СырыеДанныеСтрокой()
+
+ Возврат "fileinfos_dirty";
+
+КонецФункции
+
+Функция ПрочитатьОбъект(ПутьКФайлу, ВСоответствие = Истина)
+
+ ЧтениеJSON = Новый ЧтениеJSON;
+ ЧтениеJSON.ОткрытьФайл(ПутьКФайлу, "UTF-8");
+
+ Объект = ПрочитатьJSON(ЧтениеJSON, ВСоответствие);
+ ЧтениеJSON.Закрыть();
+
+ Возврат Объект;
+
+КонецФункции
+
+Функция ШаблонОтчет()
+
+ Возврат ОбъединитьПути(ТекущийСценарий().Каталог, "..", Ресурсы(), "report.json");
+
+КонецФункции
+
+Функция ШаблонЗамечания()
+
+ Возврат ОбъединитьПути(ТекущийСценарий().Каталог, "..", Ресурсы(), "diagnostic.json");
+
+КонецФункции
+
+Функция Ресурсы()
+
+ Возврат "Ресурсы";
+
+КонецФункции
+
+Функция Замечание()
+
+ Возврат ПрочитатьОбъект(ШаблонЗамечания(), Ложь);
+
+КонецФункции
+
+Процедура ПриСозданииОбъекта()
+
+ Отчет = ПрочитатьОбъект(ШаблонОтчет());
+
+ Отчет["date"] = Формат(ТекущаяУниверсальнаяДата(), "ДФ='yyyy-MM-dd HH:mm:ss'");
+
+КонецПроцедуры
+
+#КонецОбласти
+
+Лог = ПараметрыПриложения.Лог();
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\202\321\207\320\265\321\202\320\260\320\225\320\224\320\242.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\202\321\207\320\265\321\202\320\260\320\225\320\224\320\242.os"
new file mode 100644
index 0000000..4cffc64
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\202\321\207\320\265\321\202\320\260\320\225\320\224\320\242.os"
@@ -0,0 +1,69 @@
+Процедура ОписаниеКоманды(Команда) Экспорт
+
+ Команда.Аргумент("PATH", "", "Файл с отчетом")
+ .ТСтрока();
+
+ Команда.Аргумент("WORKDIR", "", "Корень репозитория или проектной области")
+ .ТСтрока();
+
+ Команда.Аргумент("PROJECTS", Новый Массив, "Список проектов, которые были переданы в ЕДТ для анализа")
+ .ТМассивСтрок();
+
+ Команда.Аргумент("OUT", "", "Путь к файлу отчета в формате BSL LS")
+ .ТСтрока();
+
+ Команда.Опция("nixPath", Истина, "Использовать пути как в линукс системах")
+ .ТБулево();
+
+КонецПроцедуры
+
+Процедура ПередВыполнениемКоманды(Знач Команда) Экспорт
+
+ Лог = ПараметрыПриложения.Лог();
+
+ БылиОшибки = Ложь;
+
+ ФайлДляОбработки = Новый Файл(Команда.ЗначениеАргумента("PATH"));
+
+ Если НЕ (ФайлДляОбработки.Существует() И ФайлДляОбработки.ЭтоФайл()) Тогда
+ Лог.Ошибка("Не найден файл %1", Команда.ЗначениеАргумента("PATH"));
+ БылиОшибки = Истина;
+ КонецЕсли;
+
+ Репозиторий = Новый Файл(Команда.ЗначениеАргумента("WORKDIR"));
+
+ Если НЕ (Репозиторий.Существует() И Репозиторий.ЭтоКаталог()) Тогда
+ Лог.Ошибка("Не найден корневой каталог проектов %1", Команда.ЗначениеАргумента("WORKDIR"));
+ БылиОшибки = Истина;
+ КонецЕсли;
+
+ Проекты = Команда.ЗначениеАргумента("PROJECTS");
+
+ Для Каждого Проект Из Проекты Цикл
+
+ ДиректорияПроекта = Новый Файл(ОбъединитьПути(Команда.ЗначениеАргумента("WORKDIR"), Проект));
+
+ Если НЕ (ДиректорияПроекта.Существует() И ДиректорияПроекта.ЭтоКаталог()) Тогда
+ Лог.Ошибка("Не найден корневой каталог проекта %1 в %2", Проект, Команда.ЗначениеАргумента("WORKDIR"));
+ БылиОшибки = Истина;
+ КонецЕсли;
+
+ КонецЦикла;
+
+ Если БылиОшибки Тогда
+ ВызватьИсключение "Продолжение работы невозможно";
+ КонецЕсли;
+
+КонецПроцедуры
+
+Процедура ВыполнитьКоманду(Знач Команда) Экспорт
+
+ ФайлДляОбработки = Команда.ЗначениеАргумента("PATH");
+ Репозиторий = Команда.ЗначениеАргумента("WORKDIR");
+ Проекты = Команда.ЗначениеАргумента("PROJECTS");
+ ФайлРезультата = Команда.ЗначениеАргумента("OUT");
+ ПутиКакВЛинукс = Команда.ЗначениеОпции("nixPath");
+
+ ПарсерОшибок.Прочитать(ФайлДляОбработки, Репозиторий, Проекты, ФайлРезультата, ПутиКакВЛинукс);
+
+КонецПроцедуры
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\321\203\320\261\320\273\320\270\320\272\320\260\321\206\320\270\321\217\320\237\321\200\320\260\320\262\320\270\320\273.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\321\203\320\261\320\273\320\270\320\272\320\260\321\206\320\270\321\217\320\237\321\200\320\260\320\262\320\270\320\273.os"
new file mode 100644
index 0000000..b0109f4
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\321\203\320\261\320\273\320\270\320\272\320\260\321\206\320\270\321\217\320\237\321\200\320\260\320\262\320\270\320\273.os"
@@ -0,0 +1,14 @@
+Процедура ОписаниеКоманды(Команда) Экспорт
+
+ Команда.Аргумент("OUT", "", "Путь к файлу отчета в формате BSL LS")
+ .ТСтрока();
+
+КонецПроцедуры
+
+Процедура ВыполнитьКоманду(Знач Команда) Экспорт
+
+ ФайлРезультата = Команда.ЗначениеАргумента("OUT");
+ ХранилищеПравил = Новый ХранилищеПравил;
+ ХранилищеПравил.Опубликовать(ФайлРезультата);
+
+КонецПроцедуры
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\237\321\200\320\260\320\262\320\270\320\273.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\237\321\200\320\260\320\262\320\270\320\273.os"
new file mode 100644
index 0000000..456af81
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\237\321\200\320\260\320\262\320\270\320\273.os"
@@ -0,0 +1,145 @@
+#Область ОписаниеПеременных
+
+// Хранилище правилы
+Перем Правила;
+#КонецОбласти
+
+#Область ПрограммныйИнтерфейс
+
+// Ищет в коллекции правил элемент по имени правила
+//
+// Параметры:
+// Код - Строка - Код правила - нормализованная строка пригодная быть в качестве кода либо сам код из ЕДТ
+//
+// Возвращаемое значение:
+// Структура - Структура с описанием правила (подробнее см НовыйПравило)
+//
+Функция НайтиПоКоду (Код) Экспорт
+
+ Возврат Правила.ПоКоду.Получить(Код);
+
+КонецФункции
+
+// Считает количество добавленных правил
+//
+// Возвращаемое значение:
+// Число - количество правил, сохраненных в файле с описанием правил
+//
+Функция Количество() Экспорт
+
+ Возврат Правила.ПоКоду.Количество();
+
+КонецФункции
+
+// Добавляет новые правила в хранилище правил
+//
+// Параметры:
+// МассивДобавлений - <Массив> - Массив с новыми правилами, которые будут записаны в итоговый файл
+//
+Процедура Дополнить(МассивДобавлений) Экспорт
+
+ Объект = ПравилаКакОбъект();
+
+ Для Каждого Добавление Из МассивДобавлений Цикл
+
+ Объект.Rules.Добавить(Добавление.Значение);
+
+ КонецЦикла;
+
+ ЗаписатьОбъект(ПараметрыПриложения.ПолучитьКонтекст(), Объект);
+
+КонецПроцедуры
+
+// Обрабатывает хранилище правил во внутреннем формате и создает файл, пригодный для экспорта в SQ
+//
+// Параметры:
+// Путь - Строка - Путь к файлу результата.
+//
+Процедура Опубликовать(Путь) Экспорт
+
+ Объект = ПравилаКакОбъект();
+
+ МаксимальнаяДлиннаИмениПравила = 198;
+ Для Каждого Правило Из Объект.Rules Цикл
+ // InternalCode используется для внутреннего сопоставления и для SQ будет являться лишним атрибутом
+ Правило.Удалить("InternalCode");
+
+ Если СтрДлина(Правило.Name) >= 198 Тогда
+
+ Правило.Description = Правило.Name;
+ Правило.Name = Лев(Правило.Name, 198);
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+ ЗаписатьОбъект(Путь, Объект);
+
+КонецПроцедуры
+
+// Создает базовое описание нового правила по замечанию, которое нашло ЕДТ.
+//
+// Параметры:
+// ВнутреннийКод - Строка - Код из ЕДТ или нормализованное имя правила
+// Имя - Строка - Имя правила
+// Тип - ТипыЗамечаний - Тип замечания (см ТипыЗамечаний)
+// Критичность - КритичностьЗамечаний- Критичность замечания (см КритичностьЗамечаний)
+//
+// Возвращаемое значение:
+// Структура- Описание нового правила
+//
+Функция НовыйПравило(ВнутреннийКод, Имя, Тип, Критичность) Экспорт
+
+ Правило = Новый Структура;
+ Правило.Вставить("Code", "");
+ Правило.Вставить("InternalCode", ВнутреннийКод);
+ Правило.Вставить("Name", Имя);
+ Правило.Вставить("Description", "Отсутствует");
+ Правило.Вставить("Type", Тип);
+ Правило.Вставить("Severity", Критичность);
+ Правило.Вставить("Active", true);
+ Правило.Вставить("EffortMinutes", 3);
+
+ Возврат Правило;
+
+КонецФункции
+
+#КонецОбласти
+
+Процедура ЗаписатьОбъект(ПутьКФайлу, ОбъектЗаписи)
+
+ ЗаписьJSON = Новый ЗаписьJSON;
+ ЗаписьJSON.ОткрытьФайл(ПутьКФайлу, "UTF-8", , Новый ПараметрыЗаписиJSON(, Символы.Таб));
+ ЗаписатьJSON(ЗаписьJSON, ОбъектЗаписи);
+ ЗаписьJSON.Закрыть();
+
+КонецПроцедуры
+
+Функция ПрочитатьОбъект(ИмяФайла)
+
+ ЧтениеJSON = Новый ЧтениеJSON;
+ ЧтениеJSON.ОткрытьФайл(ИмяФайла, "UTF-8");
+ Объект = ПрочитатьJSON(ЧтениеJSON, Ложь);
+ ЧтениеJSON.Закрыть();
+ Возврат Объект;
+
+КонецФункции
+
+Функция ПравилаКакОбъект()
+
+ Возврат ПрочитатьОбъект(ПараметрыПриложения.ПолучитьКонтекст());
+
+КонецФункции
+
+Процедура ПриСозданииОбъекта()
+
+ Объект = ПравилаКакОбъект();
+ ПоКоду = Новый Соответствие();
+
+ Для Каждого Правило Из Объект.Rules Цикл
+ ПоКоду.Вставить(Правило.InternalCode, Правило);
+ КонецЦикла;
+
+ Правила = Новый Структура("ПоКоду", ПоКоду);
+
+КонецПроцедуры
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os"
new file mode 100644
index 0000000..04e0c8f
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os"
@@ -0,0 +1,155 @@
+#Использовать v8metadata-reader
+#Использовать fs
+
+#Область ОписаниеПеременных
+
+#КонецОбласти
+
+#Область ПрограммныйИнтерфейс
+
+// Нормализует пути, заменяя раздетилель пути на тот, который используется на SQ
+//
+// Параметры:
+// Путь - Строка - любой путь на ФС
+// КакВЛинукс - Булево - Использовать разделитель пути как в линукс
+//
+// Возвращаемое значение:
+// Строка - Нормализованный путь
+//
+Функция НормализованыйПуть(Путь, КакВЛинукс = Истина) Экспорт
+
+ КонечныйПуть = "";
+
+ Если КакВЛинукс Тогда
+ КонечныйПуть = СтрЗаменить(Путь, "\", "/");
+ Иначе
+ КонечныйПуть = СтрЗаменить(Путь, "/", "\");
+ КонецЕсли;
+
+ Возврат КонечныйПуть;
+
+КонецФункции
+
+// Нормализует пути, заменяя раздетилель пути на тот, который используется на SQ
+//
+// Параметры:
+// Файл - Файл - Объект типа
+// КакВЛинукс - Булево - Использовать разделитель пути как в линукс
+//
+// Возвращаемое значение:
+// Строка - Нормализованный путь
+//
+Функция НормализованныйПутьФайла(Файл, КакВЛинукс = Истина) Экспорт
+
+ Возврат НормализованыйПуть(Файл.ПолноеИмя, КакВЛинукс);
+
+КонецФункции
+
+// Определяет путь на ФС по которому находится объект метаданных
+//
+// Параметры:
+// Генератор - v8metadata-reader.Путь1СПоМетаданным - Объект класса для поиска пути
+// ОбъектМетаданных - Строка - Представление объекта метаданных
+//
+// Возвращаемое значение:
+// Строка - Путь к объекту конфигурации на ФС
+//
+Функция ПутьКОбъектуКонфигурации(Генератор, ОбъектМетаданных) Экспорт
+
+ Возврат Генератор.Путь(ОбъектМетаданных);
+
+КонецФункции
+
+// Возвращает нормализованный путь на ФС к объекту конфигурации
+//
+// Параметры:
+// Генератор - v8metadata-reader.Путь1СПоМетаданным - Объект класса для поиска пути
+// Объект - Строка - Представление объекта метаданных
+// КакВЛинукс - Булево - Использовать пути как в линукс
+//
+// Возвращаемое значение:
+// Строка - Нормализованный путь к объекту конфигурации на ФС
+//
+Функция НормализованныйПутьКОбъектуКонфигурации(Генератор, Объект, КакВЛинукс = Истина) Экспорт
+
+ Возврат НормализованыйПуть(ПутьКОбъектуКонфигурации(Генератор, Объект), КакВЛинукс);
+
+КонецФункции
+
+// Проверяет существует ли путь на ФС к модулю объекта конфигурации, если путь не существует
+// ищет верхнеуровневые модули.
+//
+// Параметры:
+// Генератор - v8metadata-reader.Путь1СПоМетаданным - Объект класса для поиска пути
+// Объект - Строка - Представление объекта метаданных
+//
+// Возвращаемое значение:
+// Строка - Путь к модулю объекта конфигурации либо к модулю переопределенного объекта
+//
+Функция ПодобратьМодуль(Генератор, Знач Объект) Экспорт
+
+ Переопределение = "";
+ Шаблон = "%1.%2";
+ ТипыМодулей = Новый Массив;
+ ТипыМодулей.Добавить(СтрШаблон(Шаблон, Объект, "Модуль"));
+ ТипыМодулей.Добавить(СтрШаблон(Шаблон, Объект, "МодульОбъекта"));
+ ТипыМодулей.Добавить(СтрШаблон(Шаблон, Объект, "МодульМенеджера"));
+ ТипыМодулей.Добавить(СтрШаблон(Шаблон, Объект, "МодульНабораЗаписей"));
+ ТипыМодулей.Добавить(СтрШаблон(Шаблон, Объект, "МодульКоманды"));
+ ТипыМодулей.Добавить(СтрШаблон(Шаблон, Объект, "МодульМенеджераЗначения"));
+ ТипыМодулей.Добавить(МодульПриложенияСтрокой());
+ ТипыМодулей.Добавить(МодульОбычногоПриложенияСтрокой());
+ ТипыМодулей.Добавить(МодульСеансаСтрокой());
+
+ Для Каждого ТипМодуля Из ТипыМодулей Цикл
+
+ Если МожноИспользоватьВЗамечаниях(Генератор, ТипМодуля) Тогда
+ Переопределение = ТипМодуля;
+ Прервать;
+ КонецЕсли;
+
+ КонецЦикла;
+
+ Возврат Переопределение;
+
+КонецФункции
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+Функция МодульПриложенияСтрокой()
+
+ Возврат "Конфигурация.МодульУправляемогоПриложения";
+
+КонецФункции
+
+Функция МодульОбычногоПриложенияСтрокой()
+
+ Возврат "Конфигурация.МодульОбычногоПриложения";
+
+КонецФункции
+
+Функция МодульСеансаСтрокой()
+
+ Возврат "Конфигурация.МодульСеанса";
+
+КонецФункции
+
+Функция МожноИспользоватьВЗамечаниях(Знач Генератор, Знач Объект)
+
+ Результат = Истина;
+
+ Путь = НормализованныйПутьКОбъектуКонфигурации(Генератор, Объект);
+
+ Если НЕ ЗначениеЗаполнено(Путь) ИЛИ НЕ ФС.ФайлСуществует(Путь) Тогда
+ Результат = Ложь;
+ КонецЕсли;
+
+ Возврат Результат;
+
+КонецФункции
+
+#КонецОбласти
+
+Лог = ПараметрыПриложения.Лог();
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\321\200\320\270\321\202\320\270\321\207\320\275\320\276\321\201\321\202\321\214\320\227\320\260\320\274\320\265\321\207\320\260\320\275\320\270\320\271.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\321\200\320\270\321\202\320\270\321\207\320\275\320\276\321\201\321\202\321\214\320\227\320\260\320\274\320\265\321\207\320\260\320\275\320\270\320\271.os"
new file mode 100644
index 0000000..6b08f62
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\321\200\320\270\321\202\320\270\321\207\320\275\320\276\321\201\321\202\321\214\320\227\320\260\320\274\320\265\321\207\320\260\320\275\320\270\320\271.os"
@@ -0,0 +1,55 @@
+#Область ОписаниеПеременных
+
+Перем Информационное Экспорт;
+Перем Незначительное Экспорт;
+Перем Важное Экспорт;
+Перем Критическое Экспорт;
+Перем Блокирующее Экспорт;
+
+#КонецОбласти
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Сопоставляет уровень критичности из отчета ЕДТ и уровень критичности правила для сонара
+//
+// Параметры:
+// Критичность - Строка - Уровень критичности замечания из ЕДТ
+//
+// Возвращаемое значение:
+// Строка - Уровень критичности для правила в BSL LS
+//
+Функция Определить(Критичность) Экспорт
+
+ Если Критичность = "Тривиальная" Тогда
+
+ Возврат Информационное;
+
+ ИначеЕсли Критичность = "Незначительная" Тогда
+
+ Возврат Незначительное;
+
+ ИначеЕсли Критичность = "Значительная" Тогда
+
+ Возврат Важное;
+
+ ИначеЕсли Критичность = "Критическая" Тогда
+
+ Возврат Критическое;
+
+ ИначеЕсли Критичность = "Ошибка конфигурации" Тогда
+
+ Возврат Важное;
+
+ Иначе
+
+ Возврат Незначительное;
+
+ КонецЕсли;
+
+КонецФункции
+
+Информационное = "INFO";
+Незначительное = "MINOR";
+Важное = "MAJOR";
+Критическое = "CRITICAL";
+Блокирующее = "BLOCKER";
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os"
new file mode 100644
index 0000000..e5ac8da
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os"
@@ -0,0 +1,119 @@
+#Использовать logos
+
+#Область ОписаниеПеременных
+
+Перем Лог;
+
+Перем Контекст;
+
+#КонецОбласти
+
+#Область ПрограммныйИнтерфейс
+
+// Возвращает объект лог для фиксации сообщений
+//
+// Возвращаемое значение:
+// logos.Лог - объект типа
+//
+Функция Лог() Экспорт
+
+ Если Лог = Неопределено Тогда
+ Лог = Логирование.ПолучитьЛог(ИмяЛогаПриложения());
+ КонецЕсли;
+
+ Возврат Лог;
+
+КонецФункции
+
+// Устанавливает место, откуда будут читаться старые замечания и записываться новые.
+//
+// Параметры:
+// ПутьКФайлу - Строка - Путь к внешнему файлу правил
+//
+Процедура УстановитьКонтекстСохранения(Знач ПутьКФайлу) Экспорт
+
+ Если ЗначениеЗаполнено(ПутьКФайлу) Тогда
+ Контекст = ПутьКФайлу;
+
+ Иначе
+ Контекст = ЛокальныйКонтекст();
+ КонецЕсли;
+
+ Лог().Информация("Установлен контекст сохранения замечаний %1", Контекст);
+
+КонецПроцедуры
+
+// Устанавливает способ сохранения замечаний и возвращает выбранный контекст
+//
+// Возвращаемое значение:
+// Строка - контекст для работы с сохранением правил
+//
+Функция ПолучитьКонтекст() Экспорт
+
+ Если Контекст = Неопределено Тогда
+ УстановитьКонтекстСохранения(Неопределено);
+ КонецЕсли;
+
+ Возврат Контекст;
+
+КонецФункции
+
+// Путь к локальному файлу с сохраненными правилами
+//
+// Возвращаемое значение:
+// Строка - Путь к файлу
+//
+Функция ЛокальныйКонтекст() Экспорт
+
+ Возврат ОбъединитьПути(ТекущийСценарий().Каталог, "../..", "custom-rules.json");
+
+КонецФункции
+
+// Возвращает имя лога приложения
+//
+// Возвращаемое значение:
+// Строка - Имя лога
+//
+Функция ИмяЛогаПриложения() Экспорт
+ Возврат "oscript.app." + ИмяПриложения();
+КонецФункции
+
+// Возвращает имя приложения
+//
+// Возвращаемое значение:
+// Строка - Имя приложения
+//
+Функция ИмяПриложения() Экспорт
+
+ Возврат "edt-ripper";
+
+КонецФункции
+
+// Версия приложения
+//
+// Возвращаемое значение:
+// Строка - Строка с версией приложения
+//
+Функция Версия() Экспорт
+
+ Возврат "0.7";
+
+КонецФункции
+
+// Устанавливает режим отладки для логирования приложения
+//
+// Параметры:
+// РежимОтладки - Булево - Если Истина отладка включается, если ложь - выключается
+//
+Процедура УстановитьРежимОтладки(Знач РежимОтладки) Экспорт
+
+ Если РежимОтладки Тогда
+
+ Лог().УстановитьУровень(УровниЛога.Отладка);
+ Лог.Отладка("Установлен уровень логов ОТЛАДКА");
+
+ КонецЕсли;
+
+КонецПроцедуры
+
+#КонецОбласти
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os"
new file mode 100644
index 0000000..6d02dfc
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os"
@@ -0,0 +1,245 @@
+#Область ОписаниеПеременных
+
+Перем КешПрочитанныхФайлов;
+Перем Лог;
+
+#КонецОбласти
+
+#Область ПрограммныйИнтерфейс
+
+// Разбирает отчет из ЕДТ и формирует отчет в формате bsl ls
+//
+// Параметры:
+// Файл - Строка - Путь к файлу, результату работы ЕДТ
+// ПутьКРепозиторию - Строка - Путь к репозиторию с проектами
+// СписокПроектов - Массив - Список проектов в репозитории
+// ФайлРезультата - Строка - Файл, куда будет записан отчет
+// ПутиКакВЛинукс - Строка - Использовать пути как в линукс в отчете
+//
+Процедура Прочитать(Файл, ПутьКРепозиторию, СписокПроектов, ФайлРезультата, ПутиКакВЛинукс) Экспорт
+
+ Чтение = Новый ЧтениеТекста;
+ Чтение.Открыть(Файл, "UTF-8", , , Ложь);
+
+ Строка = Чтение.ПрочитатьСтроку();
+ Отчет = Новый ГенераторОтчетовBSL();
+
+ ВыражениеУбратьКавычки = Новый РегулярноеВыражение("(\s*[:\[][\S\s]+)");
+ ВыражениеУбратьКавычки2 = Новый РегулярноеВыражение("(\s\([\S\s]+?\))");
+ ВыражениеУбратьКавычки3 = Новый РегулярноеВыражение("(\s*(?>""'|[""'])[\S\s]*?(?>'""|['""]))");
+
+ МассивДобавлений = Новый Соответствие;
+ ХранилищеПравил = Новый ХранилищеПравил;
+
+ // проверка EDT могла быть запущена по мультипроектам с одним файлом результата(напр. конфа + расширения)
+ ГенераторыПутей = ИнициализироватьГенераторы(ПутьКРепозиторию, СписокПроектов);
+
+ Пока Строка <> Неопределено Цикл
+
+ СыроеЗамечание = РазобратьЗамечаниеВСтруктуру(Строка);
+
+ Если СтрНачинаетсяС(СыроеЗамечание.Сообщение, "[BSL LS]") Тогда
+ Строка = Чтение.ПрочитатьСтроку();
+ Продолжить;
+ КонецЕсли;
+
+ ГенераторПутей = ГенераторыПутей.Получить(СыроеЗамечание.Проект);
+
+ Если ГенераторПутей = Неопределено Тогда
+ //Выкинуть в лог?
+ ВызватьИсключение "Неизвестный проект " + СыроеЗамечание.Проект + "Невозможно подобрать путь";
+ КонецЕсли;
+
+ Позиция = НайтиПозициюВСтрокеЗамечания(СыроеЗамечание.Позиция);
+
+ МетаданныеЗамечания = "";
+ ЗамечаниеПеренесено = Ложь;
+
+ Если Позиция = Неопределено Тогда // это не модуль
+
+ МетаданныеЗамечания = Конфигурация.ПодобратьМодуль(ГенераторПутей, СыроеЗамечание.Объект);
+ ЗамечаниеПеренесено = Истина;
+
+ Иначе
+ МетаданныеЗамечания = СыроеЗамечание.Объект;
+ КонецЕсли;
+
+ ОбъектЗамечания = Конфигурация.НормализованныйПутьКОбъектуКонфигурации(ГенераторПутей, МетаданныеЗамечания, ПутиКакВЛинукс);
+
+ Если ЗамечаниеПеренесено Тогда
+ Позиция = ПолучитьЗначимуюСтроку(ОбъектЗамечания);
+ КонецЕсли;
+
+ Замечание = Отчет.НовыйЗамечаниеДляОбъекта(ОбъектЗамечания);
+
+ //Описание замечания берется из выхлопа EDT
+ Замечание.message = ?(ЗамечаниеПеренесено, СыроеЗамечание.РасширенноеСообщение, СыроеЗамечание.Сообщение);
+
+ // Диапазон срабатывания - позиция вычисленная ранее
+ Замечание.range.start.line = Позиция - 1;
+ Замечание.range.start.character = 0;
+ Замечание.range.end.line = Позиция - 1;
+ Замечание.range.end.character = 1;
+
+ // Определение кода события. Изначально если присутствует берется из EDT.
+ // Отсутствующий код берется из файла правил сонар.
+ КодПравила = СыроеЗамечание.Код;
+
+ Имя = ВыражениеУбратьКавычки.Заменить(СыроеЗамечание.Сообщение, "");
+ Имя = ВыражениеУбратьКавычки3.Заменить(Имя, "");
+ Имя = СокрЛП(ВыражениеУбратьКавычки2.Заменить(Имя, ""));;
+
+ Код = НайтиСоздатьПравило(ХранилищеПравил, КодПравила, Имя,СыроеЗамечание.Тип, СыроеЗамечание, МассивДобавлений);
+
+ Замечание.code = Код;
+
+ Строка = Чтение.ПрочитатьСтроку();
+ КонецЦикла;
+ Чтение.Закрыть();
+
+ Добавлено = МассивДобавлений.Количество();
+ Если Добавлено Тогда
+ ХранилищеПравил.Дополнить(МассивДобавлений);
+ КонецЕсли;
+
+ Отчет.ЗаписатьОтчет(ФайлРезультата);
+
+КонецПроцедуры
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+Функция НайтиСоздатьПравило(ХранилищеПравил, КодПравила, Имя, Тип, Важность, МассивДобавлений)
+
+ СтрокаПоиска = "";
+ Если ЗначениеЗаполнено(КодПравила) Тогда
+ СтрокаПоиска = КодПравила;
+ Иначе
+ СтрокаПоиска = Имя;
+ КонецЕсли;
+
+ Правило = ХранилищеПравил.НайтиПоКоду(СтрокаПоиска);
+
+ ПравилоОтсутствуетВХранилище = Правило = Неопределено;
+ НовоеПравило = МассивДобавлений.Получить(СтрокаПоиска);
+
+ Если НовоеПравило <> Неопределено Тогда
+
+ Возврат НовоеПравило.Code;
+
+ ИначеЕсли ПравилоОтсутствуетВХранилище Тогда
+
+ НовоеПравило = ХранилищеПравил.НовыйПравило(СтрокаПоиска, Имя, ТипыЗамечаний.Определить(Тип), КритичностьЗамечаний.Определить(Важность));
+ НовоеПравило.Code = "EDT" + "-" + (ХранилищеПравил.Количество() + МассивДобавлений.Количество() + 1);
+ МассивДобавлений.Вставить(СтрокаПоиска, НовоеПравило);
+
+ Возврат НовоеПравило.Code;
+
+ Иначе
+ Возврат Правило.Code;
+ КонецЕсли;
+
+КонецФункции
+
+Функция ИнициализироватьГенераторы(Репо, Проекты)
+
+ Генераторы = Новый Соответствие();
+
+ Для Каждого Проект Из Проекты Цикл
+
+ Путь = ОбъединитьПути(Репо, Проект, "src");
+ ПараметрыПриложения.Лог().Отладка("Использован путь проекта %1", Путь);
+ Генераторы.Вставить(Проект, Новый Путь1СПоМетаданным(Путь));
+ КонецЦикла;
+
+ Возврат Генераторы;
+
+КонецФункции
+
+Функция НайтиПозициюВСтрокеЗамечания(Позиция)
+
+ НайденаяПозиция = Неопределено;
+
+ Если ЗначениеЗаполнено(Позиция) Тогда
+
+ Попытка
+ НайденаяПозиция = Число(СтрЗаменить(Позиция, "строка ", ""));
+ Исключение
+ Попытка
+ НайденаяПозиция = Число(СтрЗаменить(Позиция, "line ", ""));
+ Исключение
+ НайденаяПозиция = Неопределено;
+ КонецПопытки;
+ КонецПопытки;
+ КонецЕсли;
+
+ Возврат НайденаяПозиция;
+
+КонецФункции
+
+Функция ПолучитьЗначимуюСтроку(ПутьКФайлу)
+
+ Если КешПрочитанныхФайлов.Получить(ПутьКФайлу) = Неопределено Тогда
+ ЗначимаяСтрока = ЗначимаяСтрокаФайла(ПутьКФайлу);
+ КешПрочитанныхФайлов.Вставить(ПутьКФайлу, ЗначимаяСтрока);
+ Возврат ЗначимаяСтрока;
+ Иначе;
+ Возврат КешПрочитанныхФайлов.Получить(ПутьКФайлу)
+ КонецЕсли;
+
+КонецФункции
+
+Функция ЗначимаяСтрокаФайла(ПутьКФайлу)
+ ЗначимаяСтрока = 0;
+ Текст = Новый ЧтениеТекста();
+
+ Попытка
+
+ Текст.Открыть(ПутьКФайлу);
+ Строка = Текст.ПрочитатьСтроку();
+
+ Пока Строка <> Неопределено Цикл
+
+ Если НЕ ПустаяСтрока(Строка) Тогда
+ Прервать;
+ КонецЕсли;
+
+ ЗначимаяСтрока = ЗначимаяСтрока + 1;
+ Строка = Текст.ПрочитатьСтроку();
+ КонецЦикла;
+
+ Исключение
+ Текст.Закрыть();
+ КонецПопытки;
+
+ Текст.Закрыть();
+
+ ЗначимаяСтрока = ЗначимаяСтрока + 1;
+
+ Возврат ЗначимаяСтрока;
+
+КонецФункции
+
+Функция РазобратьЗамечаниеВСтруктуру(Строка)
+
+ ОписаниеЗамечания = СтрРазделить(Строка, Символы.Таб, Истина);
+ Замечание = Новый Структура;
+ Замечание.Вставить("Дата", ОписаниеЗамечания[0]);
+ Замечание.Вставить("Важность", ОписаниеЗамечания[1]);
+ Замечание.Вставить("Тип", ОписаниеЗамечания[2]);
+ Замечание.Вставить("Проект", ОписаниеЗамечания[3]);
+ Замечание.Вставить("Код", ОписаниеЗамечания[4]);
+ Замечание.Вставить("Объект", ОписаниеЗамечания[5]);
+ Замечание.Вставить("Позиция", ОписаниеЗамечания[6]);
+ Замечание.Вставить("Сообщение", ОписаниеЗамечания[7]);
+ Замечание.Вставить("РасширенноеСообщение", ОписаниеЗамечания[5] + "->" + ОписаниеЗамечания[7]);
+
+ Возврат Замечание;
+
+КонецФункции;
+
+#КонецОбласти
+
+КешПрочитанныхФайлов = Новый Соответствие();
+Лог = ПараметрыПриложения.Лог();
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\227\320\260\320\274\320\265\321\207\320\260\320\275\320\270\320\271.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\227\320\260\320\274\320\265\321\207\320\260\320\275\320\270\320\271.os"
new file mode 100644
index 0000000..d61e4ab
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\227\320\260\320\274\320\265\321\207\320\260\320\275\320\270\320\271.os"
@@ -0,0 +1,55 @@
+Перем Ошибка Экспорт;
+Перем ДефектКода Экспорт;
+Перем Уязвимость Экспорт;
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Сопоставляет тип замечания из отчета ЕДТ и тип замечания для правила сонара
+//
+// Параметры:
+// ТипЗамечания - Строка - Тип замечания из ЕДТ
+//
+// Возвращаемое значение:
+// Строка - Подобраный тип замечания для правила в BSL LS
+//
+Функция Определить(ТипЗамечания) Экспорт
+
+ Если ТипЗамечания = "Производительность" Тогда
+
+ Возврат Ошибка;
+
+ ИначеЕсли ТипЗамечания = "Переносимость" Тогда
+
+ Возврат ДефектКода;
+
+ ИначеЕсли ТипЗамечания = "Предупреждение" Тогда
+
+ Возврат ДефектКода;
+
+ ИначеЕсли ТипЗамечания = "Ошибка конфигурации" Тогда
+
+ Возврат Ошибка;
+
+ ИначеЕсли ТипЗамечания = "Стандарты кодирования" Тогда
+
+ Возврат ДефектКода;
+
+ ИначеЕсли ТипЗамечания = "Безопасность" Тогда
+
+ Возврат Уязвимость;
+
+ ИначеЕсли ТипЗамечания = "Стандарты разработки интерфейсов" Тогда
+
+ Возврат Ошибка;
+
+ Иначе
+
+ Возврат ДефектКода;
+
+ КонецЕсли;
+
+КонецФункции
+
+Ошибка = "BUG";
+ДефектКода = "CODE_SMELL";
+Уязвимость = "VULNERABILITY";
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os"
new file mode 100644
index 0000000..9ba95ef
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os"
@@ -0,0 +1,106 @@
+#Область ПрограммныйИнтерфейс
+
+// Читает json файл и преобразует его в объект
+//
+// Параметры:
+// ПутьКФайлу - Строка - Путь к файлу, который будет прочитан
+// ВСоответствие - Булево - От значения параметра зависит в какой тип будет происходить чтение
+//
+// Возвращаемое значение:
+// Соответствие,Структура - Объект из json файла
+//
+Функция ПрочитатьОбъект(ПутьКФайлу, ВСоответствие = Истина) Экспорт
+ ЧтениеJSON = Новый ЧтениеJSON;
+ ЧтениеJSON.ОткрытьФайл(ПутьКФайлу, "UTF-8");
+ Объект = ПрочитатьJSON(ЧтениеJSON, ВСоответствие);
+ ЧтениеJSON.Закрыть();
+ Возврат Объект;
+КонецФункции
+
+// Записывает произвольный объект в json файл
+//
+// Параметры:
+// ПутьКФайлу - Строка - Путь json файлу
+// ОбъектЗаписи - Объект - Объект для серриализации
+//
+Процедура ЗаписатьОбъект(ПутьКФайлу, ОбъектЗаписи) Экспорт
+ ЗаписьJSON = Новый ЗаписьJSON;
+ ЗаписьJSON.ОткрытьФайл(ПутьКФайлу, "UTF-8", , Новый ПараметрыЗаписиJSON(, Символы.Таб));
+ ЗаписатьJSON(ЗаписьJSON, ОбъектЗаписи);
+ ЗаписьJSON.Закрыть();
+
+КонецПроцедуры
+
+// Находит шаблон для отчета
+//
+// Возвращаемое значение:
+// Строка - путь к файлу с шаблоном отчета
+//
+Функция РесурсОтчет() Экспорт
+
+ Возврат ОбъединитьПути(Ресурсы(), "report.json");
+
+КонецФункции
+
+// Находит шаблон замечания
+//
+// Возвращаемое значение:
+// Строка - Путь к шаблону замечания
+//
+Функция РесурсЗамечание() Экспорт
+
+ Возврат ОбъединитьПути(Ресурсы(), "diagnostic.json");
+
+КонецФункции
+
+#КонецОбласти
+
+#Область СлужебныйПрограммныйИнтерфейс
+
+// Находит путь к каталогу с ресурсами
+//
+// Возвращаемое значение:
+// Строка - путь к каталогу с ресурсами
+//
+Функция Ресурсы() Экспорт
+
+ Возврат ОбъединитьПути(КаталогИсходников(), ДиректорияРесурсов());
+
+КонецФункции
+
+// Находит путь к каталогу исходных файлов программы
+//
+// Возвращаемое значение:
+// Строка - Каталог исходных файлов программы
+//
+Функция КаталогИсходников() Экспорт
+ Возврат ОбъединитьПути(ТекущийСценарий().Каталог, "..");
+КонецФункции
+
+// Находит путь к корневому каталогу программы
+//
+// Возвращаемое значение:
+// Строка - Путь к корневому каталогу программы
+//
+Функция КаталогПрограммы() Экспорт
+ Возврат ОбъединитьПути(КаталогИсходников(), "..");
+КонецФункции
+
+// Находит внутренний файл правил
+//
+// Возвращаемое значение:
+// Строка - Путь к внутреннему файлу правил
+//
+Функция ФайлПравилПрограммы() Экспорт
+ Возврат ОбъединитьПути(КаталогПрограммы(), "custom-rules.json");
+КонецФункции
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+Функция ДиректорияРесурсов()
+ Возврат "Ресурсы";
+КонецФункции
+
+#КонецОбласти
diff --git "a/src/\320\240\320\265\321\201\321\203\321\200\321\201\321\213/diagnostic.json" "b/src/\320\240\320\265\321\201\321\203\321\200\321\201\321\213/diagnostic.json"
new file mode 100644
index 0000000..c32b6ab
--- /dev/null
+++ "b/src/\320\240\320\265\321\201\321\203\321\200\321\201\321\213/diagnostic.json"
@@ -0,0 +1,17 @@
+{
+ "range": {
+ "start": {
+ "line": 0,
+ "character": 0
+ },
+ "end": {
+ "line": 0,
+ "character": 0
+ }
+ },
+ "severity": "Information",
+ "code": "",
+ "source": "edt-rules",
+ "message": "",
+ "relatedInformation": null
+}
\ No newline at end of file
diff --git "a/src/\320\240\320\265\321\201\321\203\321\200\321\201\321\213/fileinfo.json" "b/src/\320\240\320\265\321\201\321\203\321\200\321\201\321\213/fileinfo.json"
new file mode 100644
index 0000000..0a9e7b1
--- /dev/null
+++ "b/src/\320\240\320\265\321\201\321\203\321\200\321\201\321\213/fileinfo.json"
@@ -0,0 +1,4 @@
+{
+ "diagnostics": [
+ ]
+}
\ No newline at end of file
diff --git "a/src/\320\240\320\265\321\201\321\203\321\200\321\201\321\213/report.json" "b/src/\320\240\320\265\321\201\321\203\321\200\321\201\321\213/report.json"
new file mode 100644
index 0000000..34964a1
--- /dev/null
+++ "b/src/\320\240\320\265\321\201\321\203\321\200\321\201\321\213/report.json"
@@ -0,0 +1,8 @@
+{
+ "date": "",
+ "fileinfos": [
+ ],
+ "fileinfos_dirty": {
+
+ }
+}
\ No newline at end of file
diff --git a/tasks/test.os b/tasks/test.os
new file mode 100644
index 0000000..10059c3
--- /dev/null
+++ b/tasks/test.os
@@ -0,0 +1,82 @@
+#Использовать 1bdd
+#Использовать 1testrunner
+#Использовать fs
+
+Функция ПрогнатьТесты()
+
+ Тестер = Новый Тестер;
+ Тестер.УстановитьФорматЛогФайла(Тестер.ФорматыЛогФайла().GenericExec);
+
+ ПутьКТестам = "tests";
+ ПутьКОтчетуJUnit = "out";
+
+ ФС.ОбеспечитьПустойКаталог(ПутьКОтчетуJUnit);
+
+ РезультатТестирования = Тестер.ТестироватьКаталог(
+ Новый Файл(ПутьКТестам),
+ Новый Файл(ПутьКОтчетуJUnit)
+ );
+
+ Успешно = РезультатТестирования = 0;
+
+ Возврат Успешно;
+КонецФункции // ПрогнатьТесты()
+
+Функция ПрогнатьФичи()
+
+ ПутьОтчетаJUnit = ОбъединитьПути(ТекущийКаталог(), "out", "bdd-log.xml");
+
+ КаталогФич = ОбъединитьПути(".", "features");
+
+ Файл_КаталогФич = Новый Файл(КаталогФич);
+
+ ИсполнительБДД = Новый ИсполнительБДД;
+ РезультатыВыполнения = ИсполнительБДД.ВыполнитьФичу(Файл_КаталогФич, Файл_КаталогФич);
+ ИтоговыйРезультатВыполнения = ИсполнительБДД.ПолучитьИтоговыйСтатусВыполнения(РезультатыВыполнения);
+
+ СтатусВыполнения = ИсполнительБДД.ВозможныеСтатусыВыполнения().НеВыполнялся;
+ Если РезультатыВыполнения.Строки.Количество() > 0 Тогда
+
+ СтатусВыполнения = ИсполнительБДД.ПолучитьИтоговыйСтатусВыполнения(РезультатыВыполнения);
+
+ КонецЕсли;
+
+ ГенераторОтчетаJUnit = Новый ГенераторОтчетаJUnit;
+ ГенераторОтчетаJUnit.Сформировать(РезультатыВыполнения, СтатусВыполнения, ПутьОтчетаJUnit);
+
+ Сообщить(СтрШаблон("Результат прогона фич <%1>
+ |", ИтоговыйРезультатВыполнения));
+
+ Возврат ИтоговыйРезультатВыполнения <> ИсполнительБДД.ВозможныеСтатусыВыполнения().Сломался;
+КонецФункции // ПрогнатьФичи()
+
+// основной код
+
+ТекКаталог = ТекущийКаталог();
+
+Попытка
+ ТестыПрошли = ПрогнатьТесты();
+Исключение
+ ТестыПрошли = Ложь;
+ Сообщить(СтрШаблон("Тесты через 1testrunner выполнены неудачно
+ |%1", ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
+КонецПопытки;
+
+УстановитьТекущийКаталог(ТекКаталог);
+
+Попытка
+ ФичиПрошли = ПрогнатьФичи();
+Исключение
+ ФичиПрошли = Ложь;
+ Сообщить(СтрШаблон("Тесты поведения через 1bdd выполнены неудачно
+ |%1", ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
+КонецПопытки;
+
+Если Не ТестыПрошли Или Не ФичиПрошли Тогда
+ ВызватьИсключение "Тестирование завершилось неудачно!";
+Иначе
+ Сообщить(СтрШаблон("Результат прогона тестов <%1>
+ |", ТестыПрошли));
+ Сообщить(СтрШаблон("Результат прогона основных фич <%1>
+ |", ФичиПрошли));
+КонецЕсли;
diff --git "a/tests/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262.os" "b/tests/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262.os"
new file mode 100644
index 0000000..dc542b9
--- /dev/null
+++ "b/tests/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262.os"
@@ -0,0 +1,57 @@
+#Использовать asserts
+#Использовать logos
+#Использовать tempfiles
+#Использовать "../src"
+
+Перем юТест;
+Перем Лог;
+Перем МенеджерВременныхФайлов;
+
+// Основная точка входа
+Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт
+
+ ПередЗапускомТестов();
+
+ юТест = ЮнитТестирование;
+
+ ВсеТесты = Новый Массив;
+
+ ВсеТесты.Добавить("Тест_ГенераторОтчетов");
+
+ Возврат ВсеТесты;
+
+КонецФункции
+
+Процедура ПередЗапускомТестов()
+
+ Попытка
+ ВремТестер = Новый Тестер;
+ Лог = Логирование.ПолучитьЛог(ВремТестер.ИмяЛога());
+ Исключение
+ Лог = Логирование.ПолучитьЛог("Test");
+ КонецПопытки;
+
+КонецПроцедуры
+
+Процедура ПередЗапускомТеста() Экспорт
+
+ ПараметрыПриложения.УстановитьРежимОтладки();
+
+ МенеджерВременныхФайлов = Новый МенеджерВременныхФайлов;
+
+КонецПроцедуры
+
+
+Процедура ПослеЗапускаТеста() Экспорт
+
+ МенеджерВременныхФайлов.Удалить();
+ МенеджерВременныхФайлов = Неопределено;
+
+КонецПроцедуры
+
+Процедура Тест_ГенераторОтчетов() Экспорт
+
+ Отчет = Новый ГенераторОтчетовBSL();
+
+ Ожидаем.Что(ЗначениеЗаполнено(Отчет.Получить("date"))).ЭтоИстина();
+КонецПроцедуры
diff --git "a/tests/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" "b/tests/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os"
new file mode 100644
index 0000000..e69de29
diff --git "a/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" "b/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os"
new file mode 100644
index 0000000..cd61648
--- /dev/null
+++ "b/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os"
@@ -0,0 +1,72 @@
+#Использовать asserts
+#Использовать logos
+#Использовать tempfiles
+#Использовать fs
+#Использовать "../src"
+
+Перем юТест;
+Перем Лог;
+Перем МенеджерВременныхФайлов;
+
+// Основная точка входа
+Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт
+
+ ПередЗапускомТестов();
+
+ юТест = ЮнитТестирование;
+
+ ВсеТесты = Новый Массив;
+
+ ВсеТесты.Добавить("Тест_ПолучениеРесурсов");
+ ВсеТесты.Добавить("Тест_СериализацияИДесериализация");
+
+ Возврат ВсеТесты;
+
+КонецФункции
+
+Процедура ПередЗапускомТестов()
+
+ Попытка
+ ВремТестер = Новый Тестер;
+ Лог = Логирование.ПолучитьЛог(ВремТестер.ИмяЛога());
+ Исключение
+ Лог = Логирование.ПолучитьЛог("Test");
+ КонецПопытки;
+
+КонецПроцедуры
+
+Процедура ПередЗапускомТеста() Экспорт
+
+ ПараметрыПриложения.УстановитьРежимОтладки();
+
+ МенеджерВременныхФайлов = Новый МенеджерВременныхФайлов;
+
+КонецПроцедуры
+
+Процедура ПослеЗапускаТеста() Экспорт
+
+ МенеджерВременныхФайлов.Удалить();
+ МенеджерВременныхФайлов = Неопределено;
+
+КонецПроцедуры
+
+Процедура Тест_ПолучениеРесурсов() Экспорт
+
+ Файл = Новый Файл(ФайловыеОперации.Ресурсы());
+
+ Ожидаем.Что(Файл.Существует(), "Директории не существует").ЭтоИстина();
+ Ожидаем.Что(Файл.ЭтоКаталог(), "Не является директорией").ЭтоИстина();
+ Ожидаем.Что(НайтиФайлы(ФайловыеОперации.Ресурсы(), "*.json").Количество(), "Изменилось количество ресурсов").Равно(4);
+
+КонецПроцедуры
+
+Процедура Тест_СериализацияИДесериализация() Экспорт
+
+ ПутьКФайлу = МенеджерВременныхФайлов.СоздатьФайл("test.json");
+
+ Объект = ФайловыеОперации.ПрочитатьОбъект(ФайловыеОперации.РесурсОтчет(), Истина);
+ Ожидаем.Что(ТипЗнч(Объект), "Типы не совпали").Равно(Тип("Соответствие"));
+
+ ФайловыеОперации.ЗаписатьОбъект(ПутьКФайлу, Объект);
+
+КонецПроцедуры
diff --git "a/tests/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\237\321\200\320\260\320\262\320\270\320\273.os" "b/tests/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\237\321\200\320\260\320\262\320\270\320\273.os"
new file mode 100644
index 0000000..e69de29
diff --git a/v8config.json b/v8config.json
new file mode 100644
index 0000000..000735c
--- /dev/null
+++ b/v8config.json
@@ -0,0 +1,23 @@
+{
+ "Precommt4onecСценарии": {
+ "ИспользоватьСценарииРепозитория": false,
+ "КаталогЛокальныхСценариев": "",
+ "ГлобальныеСценарии": [
+ "ЗапретИспользованияПерейти.os",
+ "УдалениеЛишнихПустыхСтрок.os",
+ "ПроверкаДублейПроцедурИФункций.os",
+ "ДобавлениеПробеловПередКлючевымиСловами.os",
+ "ПроверкаКорректностиИнструкцийПрепроцессора.os",
+ "ПроверкаКорректностиОбластей.os",
+ "ИсправлениеНеКаноническогоНаписания.os",
+ "УдалениеЛишнихКонцевыхПробелов.os"
+ ],
+ "ОтключенныеСценарии": [],
+ "НастройкиСценариев": {
+ "СортировкаДереваМетаданных": {
+ "УчитываяПрефикс": ""
+ }
+ },
+ "Проекты": {}
+ }
+}
\ No newline at end of file
From d83f33c7efa43ff8368f7818d6d451fbd8e551ae Mon Sep 17 00:00:00 2001
From: Valery Maximov
Date: Fri, 30 Sep 2022 09:52:30 +0300
Subject: [PATCH 2/2] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B2=D1=8B=D0=B9=20?=
=?UTF-8?q?=D0=BF=D1=83=D0=B1=D0=BB=D0=B8=D1=87=D0=BD=D1=8B=D0=B9=20=D1=80?=
=?UTF-8?q?=D0=B5=D0=BB=D0=B8=D0=B7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 3 ++-
edt-ripper-0.7.ospx | Bin 21416 -> 0 bytes
installlocalhost.bat | 12 ++++++++++++
...\320\266\320\265\320\275\320\270\321\217.os" | 2 +-
4 files changed, 15 insertions(+), 2 deletions(-)
delete mode 100644 edt-ripper-0.7.ospx
create mode 100644 installlocalhost.bat
diff --git a/.gitignore b/.gitignore
index 20b3621..b52e27e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.vscode/launch.json
edt-validate-results
edt-validate-results-en
-out.json
\ No newline at end of file
+out.json
+*.ospx
diff --git a/edt-ripper-0.7.ospx b/edt-ripper-0.7.ospx
deleted file mode 100644
index 78770c8a47e9ea2d06d35906425388b8c1b8eaec..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 21416
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
diff --git a/installlocalhost.bat b/installlocalhost.bat
new file mode 100644
index 0000000..fb6f30a
--- /dev/null
+++ b/installlocalhost.bat
@@ -0,0 +1,12 @@
+@echo off
+call del "*.ospx"
+
+for /f %%i in ('"oscript -version"') do set result=%%i
+
+if %result%==1.0.19.105 (
+ call opm build . -mf ./packagedef -out .
+) else (
+ call opm build -m ./packagedef -o .
+)
+
+call opm install -f *.ospx
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os"
index e5ac8da..ac505a8 100644
--- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os"
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os"
@@ -96,7 +96,7 @@
//
Функция Версия() Экспорт
- Возврат "0.7";
+ Возврат "22.09";
КонецФункции