diff --git a/README.md b/README.md index a62beeb..8ca86d5 100644 --- a/README.md +++ b/README.md @@ -144,15 +144,15 @@ - [ ] deprecated - [ ] readOnly - [ ] writeOnly -- [ ] oneOf -- [ ] anyOf -- [ ] allOf +- [x] oneOf +- [x] anyOf +- [x] allOf - [ ] not ## Ближайшие планы - [ ] Добавить возможность валидации по URL спецификации. -- [ ] Добавить обработку конструкций `allOf`, `anyOf`, `oneOf`, `not`. +- [x] Добавить обработку конструкций `allOf`, `anyOf`, `oneOf`, `not`. - [ ] Добавить поддержку свойства `format` для числовых типов. - [ ] Добавить валидацию формата `binary` для строк. - [ ] Добавить поддержку свойств `readOnly`, `writeOnly`. diff --git "a/src/cf/DataProcessors/\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\237\320\260\320\272\320\265\321\202\320\276\320\262/Ext/ObjectModule.bsl" "b/src/cf/DataProcessors/\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\237\320\260\320\272\320\265\321\202\320\276\320\262/Ext/ObjectModule.bsl" index abfa8cf..38c613f 100644 --- "a/src/cf/DataProcessors/\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\237\320\260\320\272\320\265\321\202\320\276\320\262/Ext/ObjectModule.bsl" +++ "b/src/cf/DataProcessors/\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\237\320\260\320\272\320\265\321\202\320\276\320\262/Ext/ObjectModule.bsl" @@ -38,90 +38,43 @@ #Область СлужебныеПроцедурыИФункции Процедура ПроверитьСвойствоПоСхеме(Данные, ТекущийКонтекст, - РазрешеныДопСвойства = Истина, - СхемаДопСвойств = Неопределено) + ОписаниеДополнительныхСвойств = Истина) ПроверяемаяСхема = ПолучитьПроверяемуюСхему(Данные.Ключ, ТекущийКонтекст); Если ПроверяемаяСхема = Неопределено Тогда // Это доп.свойство - Если Не РазрешеныДопСвойства Тогда - // Доп.свойства нельзя, но схему не нашли. Зафиксируем ошибку. - ТекстОшибки = СтрШаблон("Не удалось найти свойство <%1> в схеме данных.", Данные.Ключ); - Ошибки.Добавить(ТекстОшибки); - Возврат; - КонецЕсли; - Если Не ЗначениеЗаполнено(СхемаДопСвойств) Тогда + ПроверяемаяСхема = ПолучитьСхемуДополнительныхСвойств(ОписаниеДополнительныхСвойств, Данные.Ключ); + + Если Не ЗначениеЗаполнено(ПроверяемаяСхема) Тогда Возврат; КонецЕсли; - ПроверяемаяСхема = СхемаДопСвойств; - КонецЕсли; - - Если ЭтоСложнаяСхема(ПроверяемаяСхема) Тогда - ОбработатьСложнуюСхему(Данные, ПроверяемаяСхема); - Иначе - ВалидироватьДанныеПоСхеме(Данные, ПроверяемаяСхема); КонецЕсли; + ВыполнитьВалидациюДанных(Данные, ПроверяемаяСхема); КонецПроцедуры -Функция ПолучитьПроверяемуюСхему(ИмяСхемы, ТекущийКонтекст) - ПроверяемаяСхема = ТекущийКонтекст.Получить(ИмяСхемы); +Функция ПолучитьСхемуДополнительныхСвойств(ОписаниеДополнительныхСвойств, ИмяСвойства) - Если ПроверяемаяСхема = Неопределено Тогда - // Если у нас на вход неопределено, значит такая схема не найдена. - // Это нормально, в случае если это неизвестное свойство. просто больше ничего не делаем - Возврат ПроверяемаяСхема; + Если ОписаниеДополнительныхСвойств = Ложь Тогда + // Доп.свойства нельзя, но схему не нашли. Зафиксируем ошибку. + ТекстОшибки = СтрШаблон("Не удалось найти свойство <%1> в схеме данных.", ИмяСвойства); + Ошибки.Добавить(ТекстОшибки); + Возврат Неопределено; КонецЕсли; - - ПроверяемаяСхема = РазыменоватьСхему(ПроверяемаяСхема); - - Возврат ПроверяемаяСхема; -КонецФункции -// Функция - Разыменовать схему -// Обрабатывает переданную схему. -// Получает необходимую схему по ссылке, если это требуется. -// Параметры: -// ПроверяемаяСхема - Соответствие - Схема которую требуется разыменовать -// -// Возвращаемое значение: -// Соответствие - Разыменованое соответствие -// -Функция РазыменоватьСхему(ПроверяемаяСхема) - РазыменованнаяСхема = ПроверяемаяСхема; - Если РазыменованнаяСхема = Неопределено Тогда - // Если у нас на вход неопределено, значит такая схема не найдена. - // Это нормально, в случае если это неизвестное свойство. просто больше ничего не делаем - Возврат РазыменованнаяСхема; - КонецЕсли; - - СсылкаНаСхему = РазыменованнаяСхема.Получить("$ref"); - - Если ЗначениеЗаполнено(СсылкаНаСхему) Тогда - РазыменованнаяСхема = ВалидаторПакетовПовтИсп.СхемаПоСтроковомуПути(СсылкаНаСхему, Спецификация); + Если ОписаниеДополнительныхСвойств = Истина Тогда + Возврат Неопределено; КонецЕсли; - - Возврат РазыменованнаяСхема; -КонецФункции -// Функция - Это сложная схема -// -// Параметры: -// ПроверяемаяСхема - Соответствие - Описание проверяемой схемы -// -// Возвращаемое значение: -// Булево - Истина, если схема использует сложные конструкции -// -Функция ЭтоСложнаяСхема(ПроверяемаяСхема) - ЭтоOneOf = Не ПроверяемаяСхема.Получить("oneOf") = Неопределено; - ЭтоAllOf = Не ПроверяемаяСхема.Получить("allOf") = Неопределено; - ЭтоAnyOf = Не ПроверяемаяСхема.Получить("anyOf") = Неопределено; - - Возврат ЭтоOneOf Или ЭтоAllOf Или ЭтоAnyOf; + Возврат РазыменоватьСхему(ОписаниеДополнительныхСвойств); КонецФункции -Процедура ОбработатьСложнуюСхему(Данные, ПроверяемаяСхема) - Ошибки.Добавить("Работу с allOf, anyOf, oneOf пока не завезли."); +Процедура ВыполнитьВалидациюДанных(Данные, ПроверяемаяСхема) + Если ЭтоСложнаяСхема(ПроверяемаяСхема) Тогда + ОбработатьСложнуюСхему(Данные, ПроверяемаяСхема); + Иначе + ВалидироватьДанныеПоСхеме(Данные, ПроверяемаяСхема); + КонецЕсли; КонецПроцедуры Процедура ВалидироватьДанныеПоСхеме(Данные, ПроверяемаяСхема) @@ -164,6 +117,96 @@ КонецЕсли; КонецПроцедуры +#Область РаботаСоСложнымиСхемами +Процедура ОбработатьСложнуюСхему(Данные, ПроверяемаяСхема) + // Для работы сложных схем, нам понадобятся промежуточные результаты валидации. + // Закэшируем накопленные ошибки, а после выполнения проверок вернем их на место. + КэшОшибок = Новый Массив; + ДополнитьМассив(КэшОшибок, Ошибки); + Если ЕстьСвойство("oneOf", ПроверяемаяСхема) Тогда + ОбработатьСвойствоOneOf(Данные, ПроверяемаяСхема.Получить("oneOf")); + ИначеЕсли ЕстьСвойство("anyOf", ПроверяемаяСхема) Тогда + ОбработатьСвойствоAnyOf(Данные, ПроверяемаяСхема.Получить("anyOf")); + ИначеЕсли ЕстьСвойство("allOf", ПроверяемаяСхема) Тогда + ОбработатьСвойствоAllOf(Данные, ПроверяемаяСхема.Получить("allOf")); + Иначе + // Тут такого быть категорически не должно! Это ошибка валидатора. + ВызватьИсключение "Ошибка при разборе схемы! Не найдено ни одного из свойств oneOf, anyOf, allOf."; + КонецЕсли; + + ДополнитьМассив(Ошибки, КэшОшибок); +КонецПроцедуры + +Процедура ОбработатьСвойствоOneOf(Данные, МассивПроверяемыхСхем) + МассивИндексовСхемПрошедшихВалидацию = Новый Массив; + ПромежуточныйКэшОшибок = Новый Массив; + Для Индекс = 0 По МассивПроверяемыхСхем.ВГраница() Цикл + ПроверяемаяСхема = РазыменоватьСхему(МассивПроверяемыхСхем[Индекс]); + Ошибки = Новый Массив; + ВыполнитьВалидациюДанных(Данные, ПроверяемаяСхема); + Если Ошибки.Количество() = 0 Тогда + МассивИндексовСхемПрошедшихВалидацию.Добавить(Индекс); + КонецЕсли; + Если МассивИндексовСхемПрошедшихВалидацию.Количество() > 1 Тогда + // Уже была успешная валидация по схеме, а значит это ошибка oneOf + ТекстОшибки = СтрШаблон("%1 Объект должен соответствовать только одной схеме. Индексы валидных схем <%2>", + ШаблонБазовойОшибки, СтрСоединить(МассивИндексовСхемПрошедшихВалидацию, ";")); + Ошибки.Добавить(ТекстОшибки); + Возврат; + КонецЕсли; + + ДополнитьМассив(ПромежуточныйКэшОшибок, Ошибки); + КонецЦикла; + + Если МассивИндексовСхемПрошедшихВалидацию.Количество() = 0 Тогда + + ТекстОшибки = СтрШаблон("%1 Объект должен соответствовать хотя бы одной схеме.", + ШаблонБазовойОшибки); + Ошибки.Добавить(ТекстОшибки); + ДополнитьМассив(Ошибки, ПромежуточныйКэшОшибок); + Возврат; + КонецЕсли; + // Ровно одна схема прошла валидацию. Очистим массив ошибок, т.к. все ок. :) + Ошибки = Новый Массив; + +КонецПроцедуры + +Процедура ОбработатьСвойствоAnyOf(Данные, МассивПроверяемыхСхем) + ПромежуточныйКэшОшибок = Новый Массив; + Для Индекс = 0 По МассивПроверяемыхСхем.ВГраница() Цикл + ПроверяемаяСхема = РазыменоватьСхему(МассивПроверяемыхСхем[Индекс]); + Ошибки = Новый Массив; + ВыполнитьВалидациюДанных(Данные, ПроверяемаяСхема); + Если Ошибки.Количество() = 0 Тогда + Возврат; + КонецЕсли; + ДополнитьМассив(ПромежуточныйКэшОшибок, Ошибки); + КонецЦикла; + + Ошибки = Новый Массив; + ТекстОшибки = СтрШаблон("%1 Объект должен соответствовать хотя бы одной схеме.", + ШаблонБазовойОшибки); + Ошибки.Добавить(ТекстОшибки); + ДополнитьМассив(Ошибки, ПромежуточныйКэшОшибок); + +КонецПроцедуры + +Процедура ОбработатьСвойствоAllOf(Данные, МассивПроверяемыхСхем) + Ошибки = Новый Массив; + Для Индекс = 0 По МассивПроверяемыхСхем.ВГраница() Цикл + ПроверяемаяСхема = РазыменоватьСхему(МассивПроверяемыхСхем[Индекс]); + + ВыполнитьВалидациюДанных(Данные, ПроверяемаяСхема); + КонецЦикла; + + Если Ошибки.Количество() > 0 Тогда + ТекстОшибки = СтрШаблон("%1 Объект должен соответствовать всем схемам.", + ШаблонБазовойОшибки); + Ошибки.Добавить(ТекстОшибки); + КонецЕсли; +КонецПроцедуры +#КонецОбласти + #Область ВалидацияСтроки Процедура ВалидироватьСтроку(Данные, ПроверяемаяСхема) @@ -211,7 +254,7 @@ ИначеЕсли ФорматЗначения = "date" Тогда ПроверитьДату(ЗначениеСвойства, ЧастиДаты.Дата); ИначеЕсли ФорматЗначения = "date-time" Тогда - ПроверитьДату(ЗначениеСвойства, ЧастиДаты.ДатаВремя);; + ПроверитьДату(ЗначениеСвойства, ЧастиДаты.ДатаВремя); ИначеЕсли ФорматЗначения = "email" Тогда Паттерн = "^((?!\.)[\w\-_.]*[^.])(@\w+)(\.\w+(\.\w+)?[^.\W])$"; ИначеЕсли ФорматЗначения = "uuid" Тогда @@ -442,7 +485,7 @@ #КонецОбласти #Область ВалидацияОбъекта -Процедура ВалидироватьОбъект(Данные, ПроверяемаяСхема) +Процедура ВалидироватьОбъект(Данные, ПроверяемаяСхема) // BSLLS:Typo-off ОписаниеТипа = Новый ОписаниеТипов("Структура,Соответствие"); ЗначениеСвойства = Данные.Значение; @@ -454,11 +497,7 @@ ПроверитьКоличествоСвойств(ЗначениеСвойства, ПроверяемаяСхема); - ДополнительныеСвойства = ПроверяемаяСхема.Получить("additionalProperties"); - РазрешеныДополнительныеСвойства = Не ДополнительныеСвойства = Ложь; - Если ТипЗнч(ДополнительныеСвойства) = Тип("Соответствие") Тогда - СхемаДопСвойств = РазыменоватьСхему(ДополнительныеСвойства); - КонецЕсли; + ОписаниеДополнительныхСвойств = ПроверяемаяСхема.Получить("additionalProperties"); СписокСвойств = ПроверяемаяСхема.Получить("properties"); Если СписокСвойств = Неопределено Тогда @@ -467,7 +506,7 @@ СписокСвойств = Новый Соответствие; КонецЕсли; Для Каждого Свойство Из ЗначениеСвойства Цикл - ПроверитьСвойствоПоСхеме(Свойство, СписокСвойств, РазрешеныДополнительныеСвойства, СхемаДопСвойств); + ПроверитьСвойствоПоСхеме(Свойство, СписокСвойств, ОписаниеДополнительныхСвойств); КонецЦикла; КонецПроцедуры @@ -532,7 +571,7 @@ КонецПроцедуры Процедура УстановитьШаблонБазовойОшибки(Имя, Описание) - Представление = СтрШаблон("<%1>",Имя); + Представление = СтрШаблон("<%1>", Имя); Если ЗначениеЗаполнено(Описание) Тогда Представление = СтрШаблон("<%1>(%2)", Имя, Описание); @@ -544,15 +583,12 @@ Функция ТипЗначенияСоответствуетОписанию(ЗначениеСвойства, ОписаниеТипа) ПриведенноеЗначениеСвойства = ОписаниеТипа.ПривестиЗначение(ЗначениеСвойства); - Если ПриведенноеЗначениеСвойства = ЗначениеСвойства Тогда - // после приведения все совпадает. А значит тип подходит под схему. - Возврат Истина; - КонецЕсли; - + ОжидаемыйТип = ТипЗнч(ПриведенноеЗначениеСвойства); ФактическийТип = ТипЗнч(ЗначениеСвойства); РазличаютсяТипы = ОжидаемыйТип <> ФактическийТип; + Если РазличаютсяТипы Тогда ПредставлениеОжидаемыхТипов = СтрСоединить(ОписаниеТипа.Типы(), "; "); ТекстОшибки = @@ -564,6 +600,11 @@ Возврат Ложь; КонецЕсли; + Если ПриведенноеЗначениеСвойства = ЗначениеСвойства Тогда + // после приведения все совпадает. А значит тип подходит под схему. + Возврат Истина; + КонецЕсли; + // Если мы здесь, значит отличаются Квалификаторы Если ФактическийТип = Тип("Дата") Тогда ИнкрементКвалификатора = СтрШаблон("Некорректный формат даты. Ожидается <%1>", @@ -574,7 +615,7 @@ ИначеЕсли ФактическийТип = Тип("Число") Тогда ИнкрементКвалификатора = "Некорректный формат значения, число должно быть целым."; Иначе - //Тут мы никогда не окажемся. + // Тут мы никогда не окажемся. ВызватьИсключение "При обработке схемы возникла исключительная ситуация!"; КонецЕсли; @@ -634,5 +675,64 @@ КонецПроцедуры -#КонецОбласти +Функция ПолучитьПроверяемуюСхему(ИмяСхемы, ТекущийКонтекст) + ПроверяемаяСхема = ТекущийКонтекст.Получить(ИмяСхемы); + + Если ПроверяемаяСхема = Неопределено Тогда + // Если у нас на вход неопределено, значит такая схема не найдена. + // Это нормально, в случае если это неизвестное свойство. просто больше ничего не делаем + Возврат ПроверяемаяСхема; + КонецЕсли; + + ПроверяемаяСхема = РазыменоватьСхему(ПроверяемаяСхема); + + Возврат ПроверяемаяСхема; +КонецФункции +// Функция - Разыменовать схему +// Обрабатывает переданную схему. +// Получает необходимую схему по ссылке, если это требуется. +// Параметры: +// ПроверяемаяСхема - Соответствие - Схема которую требуется разыменовать +// +// Возвращаемое значение: +// Соответствие - Разыменованое соответствие +// +Функция РазыменоватьСхему(ПроверяемаяСхема) Экспорт + РазыменованнаяСхема = ПроверяемаяСхема; + Если РазыменованнаяСхема = Неопределено Тогда + // Если у нас на вход неопределено, значит такая схема не найдена. + // Это нормально, в случае если это неизвестное свойство. просто больше ничего не делаем + Возврат РазыменованнаяСхема; + КонецЕсли; + + СсылкаНаСхему = РазыменованнаяСхема.Получить("$ref"); + + Если ЗначениеЗаполнено(СсылкаНаСхему) Тогда + РазыменованнаяСхема = ВалидаторПакетовПовтИсп.СхемаПоСтроковомуПути(СсылкаНаСхему, Спецификация); + КонецЕсли; + + Возврат РазыменованнаяСхема; +КонецФункции + +// Функция - Это сложная схема +// +// Параметры: +// ПроверяемаяСхема - Соответствие - Описание проверяемой схемы +// +// Возвращаемое значение: +// Булево - Истина, если схема использует сложные конструкции +// +Функция ЭтоСложнаяСхема(ПроверяемаяСхема) Экспорт + ЭтоOneOf = ЕстьСвойство("oneOf", ПроверяемаяСхема); + ЭтоAllOf = ЕстьСвойство("allOf", ПроверяемаяСхема); + ЭтоAnyOf = ЕстьСвойство("anyOf", ПроверяемаяСхема); + + Возврат ЭтоOneOf Или ЭтоAllOf Или ЭтоAnyOf; +КонецФункции + +Функция ЕстьСвойство(ИмяСвойства, ПроверяемаяСхема) + Возврат Не ПроверяемаяСхема.Получить(ИмяСвойства) = Неопределено; +КонецФункции + +#КонецОбласти diff --git "a/src/cf/DataProcessors/\320\237\321\200\320\270\320\274\320\265\321\200\320\240\320\260\320\261\320\276\321\202\321\213\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\260/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form.xml" "b/src/cf/DataProcessors/\320\237\321\200\320\270\320\274\320\265\321\200\320\240\320\260\320\261\320\276\321\202\321\213\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\260/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form.xml" index d538b04..e0f7890 100644 --- "a/src/cf/DataProcessors/\320\237\321\200\320\270\320\274\320\265\321\200\320\240\320\260\320\261\320\276\321\202\321\213\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\260/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form.xml" +++ "b/src/cf/DataProcessors/\320\237\321\200\320\270\320\274\320\265\321\200\320\240\320\260\320\261\320\276\321\202\321\213\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\260/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form.xml" @@ -32,22 +32,49 @@ false - - Переключатель - None - Tumbler - + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Группа элементы управления</v8:content> + </v8:item> + + ru - БЛ='Валидный JSON'; БИ='Невалидный JSON' + Группа элементы управления - - - - - ПереключательПриИзменении - - + + None + false + + + + Переключатель + None + Tumbler + + + ru + БЛ='Валидный JSON'; БИ='Невалидный JSON' + + + + + + ПереключательПриИзменении + + + + ИмяСхемы + true + true + true + + + + + <v8:item> @@ -69,11 +96,17 @@ <DataPath>Объект.JsonДляПроверки</DataPath> <ContextMenu name="JsonДляПроверкиКонтекстноеМеню" id="16"/> <ExtendedTooltip name="JsonДляПроверкиРасширеннаяПодсказка" id="3"/> + <Events> + <Event name="OnChange">JsonДляПроверкиПриИзменении</Event> + </Events> </TextDocumentField> <TextDocumentField name="СхемаOpenApi" id="6"> <DataPath>Объект.СхемаOpenApi</DataPath> <ContextMenu name="СхемаOpenApiКонтекстноеМеню" id="7"/> <ExtendedTooltip name="СхемаOpenApiРасширеннаяПодсказка" id="8"/> + <Events> + <Event name="OnChange">СхемаOpenApiПриИзменении</Event> + </Events> </TextDocumentField> </ChildItems> </UsualGroup> @@ -98,6 +131,21 @@ <v8:Type>xs:boolean</v8:Type> </Type> </Attribute> + <Attribute name="ИмяСхемы" id="24"> + <Title> + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Имя схемы</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + diff --git "a/src/cf/DataProcessors/\320\237\321\200\320\270\320\274\320\265\321\200\320\240\320\260\320\261\320\276\321\202\321\213\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\260/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form/Module.bsl" "b/src/cf/DataProcessors/\320\237\321\200\320\270\320\274\320\265\321\200\320\240\320\260\320\261\320\276\321\202\321\213\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\260/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form/Module.bsl" index 75d486d..e963535 100644 --- "a/src/cf/DataProcessors/\320\237\321\200\320\270\320\274\320\265\321\200\320\240\320\260\320\261\320\276\321\202\321\213\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\260/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form/Module.bsl" +++ "b/src/cf/DataProcessors/\320\237\321\200\320\270\320\274\320\265\321\200\320\240\320\260\320\261\320\276\321\202\321\213\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\260/Forms/\320\244\320\276\321\200\320\274\320\260/Ext/Form/Module.bsl" @@ -4,7 +4,7 @@ Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) Объект.СхемаOpenApi = Обработки.ПримерРаботыВалидатора.ПолучитьМакет("OpenApi").ПолучитьТекст(); ЗагрузитьJsonДляПроверки(); - + ЗаполнитьСписокВыбораИмяСхемПакета(); КонецПроцедуры #КонецОбласти @@ -13,19 +13,32 @@ Процедура ПереключательПриИзменении(Элемент) ЗагрузитьJsonДляПроверки(); КонецПроцедуры + +&НаКлиенте +Процедура СхемаOpenApiПриИзменении(Элемент) // BSLLS:LatinAndCyrillicSymbolInWord-off + ЗаполнитьСписокВыбораИмяСхемПакета(); +КонецПроцедуры #КонецОбласти #Область ОбработчикиКомандФормы &НаКлиенте Процедура Валидировать(Команда) + Если Не ЗначениеЗаполнено(ИмяСхемы) Тогда + Сообщение = Новый СообщениеПользователю; + Сообщение.Текст = "Необходимо выбрать имя схемы!"; + Сообщение.ПутьКДанным = "ИмяСхемы"; + Сообщение.Сообщить(); + Возврат; + + КонецЕсли; ВалидироватьНаСервере(); КонецПроцедуры #КонецОбласти #Область СлужебныеПроцедурыИФункции &НаСервере -Процедура ВалидироватьНаСервере() +Процедура ВалидироватьНаСервере() // BSLLS:Typo-off МодельДанных = ВалидаторПакетовПовтИсп.JsonВОбъект(Объект.JsonДляПроверки); - МассивОшибок = ВалидаторПакетов.Валидировать(МодельДанных, "complex_object", Объект.СхемаOpenApi); + МассивОшибок = ВалидаторПакетов.Валидировать(МодельДанных, ИмяСхемы, Объект.СхемаOpenApi); Если МассивОшибок.количество() = 0 Тогда Сообщить("Валидация прошла успешно!"); @@ -47,4 +60,17 @@ Объект.JsonДляПроверки = Обработки.ПримерРаботыВалидатора.ПолучитьМакет(ИмяМакета).ПолучитьТекст(); КонецПроцедуры +&НаСервере +Процедура ЗаполнитьСписокВыбораИмяСхемПакета() + МассивИмен = Новый Массив; + Если ЗначениеЗаполнено(Объект.СхемаOpenApi) Тогда + Схемы = ВалидаторПакетовПовтИсп.СхемыДанныхСпецификации(Объект.СхемаOpenApi); + Для Каждого ЭлементСоответствия Из Схемы Цикл + МассивИмен.Добавить(ЭлементСоответствия.Ключ); + КонецЦикла; + + КонецЕсли; + + Элементы.ИмяСхемы.СписокВыбора.ЗагрузитьЗначения(МассивИмен); +КонецПроцедуры #КонецОбласти diff --git "a/src/cfe/YAXUNIT/CommonModules/\320\236\320\234_\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\237\320\260\320\272\320\265\321\202\320\276\320\262/Ext/Module.bsl" "b/src/cfe/YAXUNIT/CommonModules/\320\236\320\234_\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\237\320\260\320\272\320\265\321\202\320\276\320\262/Ext/Module.bsl" index 9c08edb..eb1dcb1 100644 --- "a/src/cfe/YAXUNIT/CommonModules/\320\236\320\234_\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\237\320\260\320\272\320\265\321\202\320\276\320\262/Ext/Module.bsl" +++ "b/src/cfe/YAXUNIT/CommonModules/\320\236\320\234_\320\222\320\260\320\273\320\270\320\264\320\260\321\202\320\276\321\200\320\237\320\260\320\272\320\265\321\202\320\276\320\262/Ext/Module.bsl" @@ -60,6 +60,10 @@ .ДобавитьТест("УспешнаяВалидацияЦелогоЧисла") .ДобавитьТест("УспешнаяВалидацияБулева") .ДобавитьТест("УспешнаяВложенногоСложногоОбъекта") + .ДобавитьТест("УспешнаяВалидацияAllOf") + .ДобавитьТест("УспешнаяВалидацияOneOf") + .ДобавитьТест("УспешнаяВалидацияAnyOf") + .ДобавитьТест("УспешнаяВалидацияСложногоОбъекта") .ДобавитьТестовыйНабор("НегативныеТесты") .ДобавитьТест("Ошибка_ВалидацияОбъекта") .ДобавитьТест("Ошибка_ВалидацияМассива") @@ -67,7 +71,12 @@ .ДобавитьТест("Ошибка_ВалидацияЧисла") .ДобавитьТест("Ошибка_ВалидацияЦелогоЧисла") .ДобавитьТест("Ошибка_ВалидацияБулева") - + .ДобавитьТестовыйНабор("СложныеСхемы") + .ДобавитьТест("Ошибка_allOf") + .ДобавитьТест("Ошибка_oneOf") + .ДобавитьТест("Ошибка_anyOf") + .ДобавитьТест("Ошибка_ВалидацияСложногоОбъекта") + КонецПроцедуры #Область События @@ -589,6 +598,116 @@ .ИмеетДлинуБольше(0) .Содержит(ЮТест.Предикат() // Значение по условиям .СодержитСтрокуПоШаблону("Передан тип <.*>. Список допустимых типов: <Булево>")) +КонецПроцедуры + +Процедура Ошибка_oneOf() Экспорт + ОбъектПроверки = Новый Структура("type, valueA, valueB", "A", "Example", 123); + ИмяСхемы = "OneOf"; + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлинуБольше(0) + .Содержит(ЮТест.Предикат() // Значение по условиям + .СодержитСтрокуПоШаблону(" Объект должен соответствовать только одной схеме. Индексы валидных схем <0;1>")) + +КонецПроцедуры + +Процедура УспешнаяВалидацияOneOf() Экспорт + + ИмяСхемы = "OneOf"; + ОбъектПроверки = Новый Структура("type, valueA", "A", "Example"); + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлину(0); + + ОбъектПроверки = Новый Структура("type, valueB", "B", 123); + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлину(0) + +КонецПроцедуры + +Процедура Ошибка_anyOf() Экспорт + ОбъектПроверки = Новый Структура("fieldC", true); + ИмяСхемы = "AnyOf"; + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлинуБольше(0) + .Содержит(ЮТест.Предикат() // Значение по условиям + .СодержитСтрокуПоШаблону(" Объект должен соответствовать хотя бы одной схеме.")) + +КонецПроцедуры + +Процедура УспешнаяВалидацияAnyOf() Экспорт + + ИмяСхемы = "AnyOf"; + ОбъектПроверки = Новый Структура("fieldA", "Some text"); + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлину(0); + + ОбъектПроверки = Новый Структура("fieldB", 42); + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлину(0); + + ОбъектПроверки = Новый Структура("fieldA, fieldB","Some text", 42); + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлину(0); +КонецПроцедуры + +Процедура Ошибка_AllOf() Экспорт + ОбъектПроверки = Новый Структура("commonField", "Some text"); + ИмяСхемы = "AllOf"; + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлинуБольше(0) + .Содержит(ЮТест.Предикат() // Значение по условиям + .СодержитСтрокуПоШаблону(" Объект должен соответствовать всем схемам.")) + .Содержит(ЮТест.Предикат() // Значение по условиям + .СодержитСтрокуПоШаблону("Отсутствует обязательное свойство ")) + +КонецПроцедуры + +Процедура УспешнаяВалидацияAllOf() Экспорт + + ИмяСхемы = "AllOf"; + ОбъектПроверки = Новый Структура("commonField, additionalField", "Some text", 42); + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлину(0); +КонецПроцедуры + +Процедура УспешнаяВалидацияСложногоОбъекта() Экспорт + + ИмяСхемы = "ComplexValidation"; + ОбъектПроверки = Новый Структура("id, typeA, valueA, status", "101", "example", 42, "active"); + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлину(0); +КонецПроцедуры + +Процедура Ошибка_ВалидацияСложногоОбъекта() Экспорт + ИмяСхемы = "ComplexValidation"; + ОбъектПроверки = Новый Структура("id, typeA, valueA", "101", "example", 42); + МассивОшибок = Валидировать(ОбъектПроверки, ИмяСхемы); + + ЮТест.ОжидаетЧто(МассивОшибок) + .ИмеетДлинуБольше(0) + .Содержит(ЮТест.Предикат() // Значение по условиям + .СодержитСтрокуПоШаблону(" Объект должен соответствовать всем схемам.")) + .Содержит(ЮТест.Предикат() // Значение по условиям + .СодержитСтрокуПоШаблону("Отсутствует обязательное свойство ")) КонецПроцедуры #КонецОбласти diff --git a/tests/fixtures/schema.json b/tests/fixtures/schema.json index ee54c9e..1f951c8 100644 --- a/tests/fixtures/schema.json +++ b/tests/fixtures/schema.json @@ -20,9 +20,9 @@ "simple_boolean": { "type": "boolean" }, - "array":{ + "array": { "type": "array", - "items":{ + "items": { "type": "string" } }, @@ -39,15 +39,15 @@ "required": { "type": "string" }, - "nested_object":{ + "nested_object": { "$ref": "#/components/schemas/object" }, - "nested_array":{ + "nested_array": { "$ref": "#/components/schemas/array" } } }, - "strings":{ + "strings": { "type": "object", "properties": { "string": { @@ -107,63 +107,63 @@ } } }, - "numbers":{ + "numbers": { "type": "object", "properties": { - "number":{ + "number": { "type": "number" }, - "integer":{ + "integer": { "type": "integer" }, - "minmax":{ - "type":"number", + "minmax": { + "type": "number", "minimum": 1, "maximum": 10 }, - "exclusiveminmax":{ + "exclusiveminmax": { "type": "number", "minimum": 1, "maximum": 10, "exclusiveMinimum": true, "exclusiveMaximum": true }, - "multipleOf":{ + "multipleOf": { "type": "number", "multipleOf": 10 } } }, - "arrays":{ + "arrays": { "type": "object", "properties": { - "simple_array":{ + "simple_array": { "type": "array" }, - "unique":{ + "unique": { "type": "array", "uniqueItems": true }, - "minmax":{ + "minmax": { "type": "array", "minItems": 2, "maxItems": 3 }, - "strict_type":{ + "strict_type": { "type": "array", - "items":{ + "items": { "type": "string" } } } }, - "objects":{ + "objects": { "type": "object", "properties": { - "object":{ + "object": { "type": "object" }, - "required":{ + "required": { "type": "object", "required": [ "required" @@ -174,12 +174,12 @@ } } }, - "minmax":{ + "minmax": { "type": "object", "minProperties": 2, "maxProperties": 3 }, - "additional_false":{ + "additional_false": { "type": "object", "properties": { "normal": { @@ -188,7 +188,7 @@ }, "additionalProperties": false }, - "additional_true":{ + "additional_true": { "type": "object", "properties": { "normal": { @@ -197,7 +197,7 @@ }, "additionalProperties": true }, - "additional_empty":{ + "additional_empty": { "type": "object", "properties": { "normal": { @@ -206,7 +206,7 @@ }, "additionalProperties": {} }, - "additional_object":{ + "additional_object": { "type": "object", "properties": { "normal": { @@ -217,7 +217,7 @@ "type": "string" } }, - "additional_ref":{ + "additional_ref": { "type": "object", "properties": { "normal": { @@ -229,6 +229,154 @@ } } } + }, + "OneOf": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "valueA": { + "type": "string" + } + }, + "required": [ + "valueA" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "valueB": { + "type": "number" + } + }, + "required": [ + "valueB" + ] + } + ] + }, + "AnyOf": { + "anyOf": [ + { + "type": "object", + "properties": { + "fieldA": { + "type": "string" + } + }, + "additionalProperties": { + "type": "number" + } + }, + { + "type": "object", + "properties": { + "fieldB": { + "type": "number" + } + }, + "additionalProperties": { + "type": "string" + } + } + ] + }, + "AllOf": { + "allOf": [ + { + "type": "object", + "required": [ + "commonField" + ], + "properties": { + "commonField": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "additionalField" + ], + "properties": { + "additionalField": { + "type": "number" + } + } + } + ] + }, + "ComplexValidation": { + "allOf": [ + { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ] + }, + { + "allOf": [ + { + "anyOf": [ + { + "type": "object", + "properties": { + "typeA": { + "type": "string" + }, + "valueA": { + "type": "number" + } + }, + "required": [ + "typeA", + "valueA" + ] + }, + { + "type": "object", + "properties": { + "typeB": { + "type": "string" + }, + "valueB": { + "type": "number" + } + }, + "required": [ + "typeB", + "valueB" + ] + } + ] + }, + { + "type": "object", + "properties": { + "status": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + ] + } + ] } } }