diff --git a/packagedef b/packagedef index 2bc4f89..92b49a1 100644 --- a/packagedef +++ b/packagedef @@ -3,7 +3,7 @@ // Описание.Имя("oscript-yaml") - .Версия("0.2.0") + .Версия("0.3.0") .Автор("Egor Ivanov") .АдресАвтора("e.ivanov@1cdevelopers.ru") .Описание("Реализация Yaml") diff --git "a/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\241\320\265\321\200\320\270\320\260\320\273\320\270\320\267\320\260\321\202\320\276\321\200.os" "b/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\241\320\265\321\200\320\270\320\260\320\273\320\270\320\267\320\260\321\202\320\276\321\200.os" index 8837245..b09d25e 100644 --- "a/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\241\320\265\321\200\320\270\320\260\320\273\320\270\320\267\320\260\321\202\320\276\321\200.os" +++ "b/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\241\320\265\321\200\320\270\320\260\320\273\320\270\320\267\320\260\321\202\320\276\321\200.os" @@ -11,52 +11,70 @@ // Функция Сериализовать(Знач Значение, УровеньОтступа = 0) Экспорт - ТипЗначения = ТипЗнч(Значение); + Возврат СериализоватьЗначение(Значение, УровеньОтступа); + +КонецФункции + +Функция СериализоватьДокументы(Знач Документы) Экспорт + + Если ТипЗнч(Документы) <> Тип("Массив") Тогда + ВызватьИсключение "Для сериализации нескольких документов нужно передать массив документов"; + КонецЕсли; + Результат = ""; - // Если это корневой уровень, добавляем разделитель документа - Если УровеньОтступа = 0 Тогда - Результат = "---" + Символы.ПС; + Для Каждого Документ Из Документы Цикл + Результат = ДобавитьСтроку(Результат, "---" + Символы.ПС + СериализоватьЗначение(Документ, 0)); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +Функция СериализоватьЗначение(Знач Значение, УровеньОтступа) + + Если Значение = Неопределено Тогда + Возврат "null"; + КонецЕсли; + + ТипЗначения = ТипЗнч(Значение); + + Если ТипЗначения = Тип("Массив") Тогда + Возврат СериализоватьМассив(Значение, УровеньОтступа); + ИначеЕсли ЭтоТипОбъекта(ТипЗначения) Тогда + Возврат СериализоватьОбъект(Значение, УровеньОтступа); + ИначеЕсли ТипЗначения = Тип("Строка") И ЭтоМногострочнаяСтрока(Значение) Тогда + Возврат СериализоватьМногострочнуюСтроку(Значение, УровеньОтступа); + Иначе + Возврат СериализоватьСкаляр(Значение); + КонецЕсли; + +КонецФункции + +Функция СериализоватьСкаляр(Знач Значение) + + Если Значение = Неопределено Тогда + Возврат "null"; КонецЕсли; + ТипЗначения = ТипЗнч(Значение); + Если ТипЗначения = Тип("Строка") Тогда - Результат = Результат + СериализоватьСтроку(Значение); + Возврат СериализоватьСтроку(Значение); ИначеЕсли ТипЗначения = Тип("Число") Тогда - Результат = Результат + СериализоватьЧисло(Значение); + Возврат СериализоватьЧисло(Значение); ИначеЕсли ТипЗначения = Тип("Булево") Тогда - Результат = Результат + СериализоватьБулево(Значение); - ИначеЕсли ТипЗначения = Тип("Массив") Тогда - Результат = Результат + СериализоватьМассив(Значение, УровеньОтступа); - ИначеЕсли ТипЗначения = Тип("Структура") Или ТипЗначения = Тип("Соответствие") Тогда - Результат = Результат + СериализоватьОбъект(Значение, УровеньОтступа); - ИначеЕсли Значение = Неопределено Тогда - Результат = Результат + "null"; + Возврат СериализоватьБулево(Значение); ИначеЕсли ТипЗначения = Тип("Дата") Тогда - // Используем JSON писателя для корректной сериализации дат - ЗаписьJSON = Новый ЗаписьJSON; - ЗаписьJSON.УстановитьСтроку(); - ЗаписатьJSON(ЗаписьJSON, Значение); - Результат = Результат + ЗаписьJSON.Закрыть(); + Возврат СериализоватьJSON(Значение); Иначе - // Для неизвестных типов пытаемся использовать JSON сериализацию Попытка - ЗаписьJSON = Новый ЗаписьJSON; - ЗаписьJSON.УстановитьСтроку(); - ЗаписатьJSON(ЗаписьJSON, Значение); - Результат = Результат + ЗаписьJSON.Закрыть(); + Возврат СериализоватьJSON(Значение); Исключение - // Если JSON не справился, используем строковое представление - Результат = Результат + СериализоватьСтроку(Строка(Значение)); + Возврат СериализоватьСтроку(Строка(Значение)); КонецПопытки; КонецЕсли; - // Если это корневой уровень, добавляем разделитель конца документа - Если УровеньОтступа = 0 Тогда - Результат = Результат + Символы.ПС + "..."; - КонецЕсли; - - Возврат Результат; - КонецФункции // Сериализация строки @@ -69,55 +87,48 @@ // Функция СериализоватьСтроку(Значение) - // Если строка пустая Если Значение = "" Тогда Возврат """"""; КонецЕсли; - // Если строка содержит переносы строк, используем блочный стиль - Если СтрНайти(Значение, Символы.ПС) > 0 ИЛИ СтрНайти(Значение, Символы.ВК) > 0 Тогда - Возврат СериализоватьМногострочнуюСтроку(Значение); - КонецЕсли; - - // Проверяем, нужно ли заключать в кавычки Если ТребуетсяЗаключениеВКавычки(Значение) Тогда - // Используем JSON писателя для корректного экранирования строки - ЗаписьJSON = Новый ЗаписьJSON; - ЗаписьJSON.УстановитьСтроку(); - ЗаписатьJSON(ЗаписьJSON, Значение); - Возврат ЗаписьJSON.Закрыть(); + Возврат СериализоватьJSON(Значение); Иначе Возврат Значение; КонецЕсли; КонецФункции +Функция СериализоватьJSON(Значение) + + ЗаписьJSON = Новый ЗаписьJSON; + ЗаписьJSON.УстановитьСтроку(); + ЗаписатьJSON(ЗаписьJSON, Значение); + + Возврат ЗаписьJSON.Закрыть(); + +КонецФункции + // Сериализация многострочной строки // // Параметры: // Значение - Строка - многострочная строка для сериализации +// УровеньОтступа - Число - текущий уровень отступа // // Возвращаемое значение: // Строка - YAML представление многострочной строки // -Функция СериализоватьМногострочнуюСтроку(Значение) - - // Нормализуем переносы строк - НормализованноеЗначение = СтрЗаменить(Значение, Символы.ВК, Символы.ПС); - - // Разделяем на строки - Строки = СтрРазделить(НормализованноеЗначение, Символы.ПС, Ложь); +Функция СериализоватьМногострочнуюСтроку(Значение, УровеньОтступа) - // Используем блочный литеральный стиль | - Результат = "|" + Символы.ПС; + НормализованноеЗначение = НормализоватьПереносыСтрок(Значение); + Строки = СтрРазделить(НормализованноеЗначение, Символы.ПС, Истина); + ОтступСтроки = ПолучитьОтступ(УровеньОтступа + 1); - Для Каждого Строка Из Строки Цикл - Результат = Результат + " " + Строка + Символы.ПС; + Результат = "|"; + Для Каждого СтрокаЗначения Из Строки Цикл + Результат = Результат + Символы.ПС + ОтступСтроки + СтрокаЗначения; КонецЦикла; - // Убираем последний перенос строки - Результат = Лев(Результат, СтрДлина(Результат) - 1); - Возврат Результат; КонецФункции @@ -141,7 +152,7 @@ // Сериализация булевого значения // // Параметры: -// Значение - Булево - булевое значение для сериализации +// Значение - Булево - булевое значение // // Возвращаемое значение: // Строка - YAML представление булевого значения @@ -171,93 +182,60 @@ Результат = ""; Отступ = ПолучитьОтступ(УровеньОтступа); - ПервыйЭлемент = Истина; Для Каждого Элемент Из Массив Цикл - Если НЕ ПервыйЭлемент Тогда - Результат = Результат + Символы.ПС; - КонецЕсли; - ПервыйЭлемент = Ложь; - - ТипЭлемента = ТипЗнч(Элемент); - - // Для объектов и массивов используем специальную обработку - Если ТипЭлемента = Тип("Структура") ИЛИ ТипЭлемента = Тип("Соответствие") ИЛИ ТипЭлемента = Тип("Массив") Тогда - СериализованныйЭлемент = Сериализовать(Элемент, УровеньОтступа + 1); - Результат = Результат + ОбработатьМногострочныйЭлементМассива(СериализованныйЭлемент, Отступ, УровеньОтступа); - Иначе - // Простые значения (строки, числа, булево) - СериализованныйЭлемент = Сериализовать(Элемент, УровеньОтступа + 1); - Результат = Результат + Отступ + "- " + СериализованныйЭлемент; - КонецЕсли; - + Результат = ДобавитьСтроку(Результат, СериализоватьЭлементМассива(Элемент, Отступ, УровеньОтступа)); КонецЦикла; Возврат Результат; КонецФункции -// Обработка многострочного элемента в массиве -// -// Параметры: -// СериализованныйЭлемент - Строка - сериализованный элемент с переносами строк -// Отступ - Строка - базовый отступ для массива -// УровеньОтступа - Число - уровень отступа -// -// Возвращаемое значение: -// Строка - отформатированный элемент массива -// -Функция ОбработатьМногострочныйЭлементМассива(СериализованныйЭлемент, Отступ, УровеньОтступа) +Функция СериализоватьЭлементМассива(Знач Элемент, Отступ, УровеньОтступа) - МассивСтрок = СтрРазделить(СериализованныйЭлемент, Символы.ПС, Ложь); - ОжидаемыйОтступ = ПолучитьОтступ(УровеньОтступа + 1); + Если ЭтоПустаяКоллекция(Элемент) Или ЭтоСкалярДляСтроки(Элемент) Тогда + Возврат Отступ + "- " + СериализоватьСкалярИлиПустуюКоллекцию(Элемент); + КонецЕсли; - Результат = ""; - Для Инд = 0 По МассивСтрок.Количество() - 1 Цикл - СтрокаЭлемента = МассивСтрок[Инд]; - - Если Инд = 0 Тогда - // Первая строка - убираем ожидаемый отступ и добавляем "- " - СтрокаБезОтступа = УбратьОжидаемыйОтступ(СтрокаЭлемента, ОжидаемыйОтступ); - Результат = Результат + Отступ + "- " + СтрокаБезОтступа; - Иначе - // Остальные строки - заменяем ожидаемый отступ на отступ массива + 2 пробела - ОстатокСтроки = УбратьОжидаемыйОтступ(СтрокаЭлемента, ОжидаемыйОтступ); - Результат = Результат + Символы.ПС + Отступ + " " + ОстатокСтроки; - КонецЕсли; - КонецЦикла; + ТипЭлемента = ТипЗнч(Элемент); - Возврат Результат; + Если ТипЭлемента = Тип("Строка") Тогда + Возврат Отступ + "- " + СериализоватьМногострочнуюСтроку(Элемент, УровеньОтступа); + ИначеЕсли ЭтоТипОбъекта(ТипЭлемента) Тогда + Возврат СериализоватьОбъектВЭлементеМассива(Элемент, Отступ, УровеньОтступа); + ИначеЕсли ТипЭлемента = Тип("Массив") Тогда + Возврат Отступ + "-" + Символы.ПС + СериализоватьМассив(Элемент, УровеньОтступа + 1); + Иначе + Возврат Отступ + "- " + СериализоватьСкаляр(Элемент); + КонецЕсли; КонецФункции -// Убрать ожидаемый отступ из строки -// -// Параметры: -// СтрокаЭлемента - Строка - исходная строка -// ОжидаемыйОтступ - Строка - ожидаемый отступ для удаления -// -// Возвращаемое значение: -// Строка - строка без ожидаемого отступа -// -Функция УбратьОжидаемыйОтступ(СтрокаЭлемента, ОжидаемыйОтступ) +Функция СериализоватьОбъектВЭлементеМассива(Объект, Отступ, УровеньОтступа) - Если СтрНачинаетсяС(СтрокаЭлемента, ОжидаемыйОтступ) Тогда - Возврат Сред(СтрокаЭлемента, СтрДлина(ОжидаемыйОтступ) + 1); - Иначе - Возврат СокрЛП(СтрокаЭлемента); - КонецЕсли; + ОтступДочернегоОбъекта = ПолучитьОтступ(УровеньОтступа + 1); + СериализованныйОбъект = СериализоватьОбъект(Объект, УровеньОтступа + 1); + СтрокиОбъекта = СтрРазделить(СериализованныйОбъект, Символы.ПС, Истина); + + ПерваяСтрока = УбратьНачальныйОтступ(СтрокиОбъекта[0], ОтступДочернегоОбъекта); + Результат = Отступ + "- " + ПерваяСтрока; + + Для Индекс = 1 По СтрокиОбъекта.Количество() - 1 Цикл + Результат = Результат + Символы.ПС + СтрокиОбъекта[Индекс]; + КонецЦикла; + + Возврат Результат; КонецФункции // Сериализация объекта // // Параметры: -// Объект - Соответствие, Структура - соответствие для сериализации +// Объект - Соответствие, Структура - объект для сериализации // УровеньОтступа - Число - текущий уровень отступа // // Возвращаемое значение: -// Строка - YAML представление соответствия +// Строка - YAML представление объекта // Функция СериализоватьОбъект(Объект, УровеньОтступа = 0) @@ -267,41 +245,46 @@ Результат = ""; Отступ = ПолучитьОтступ(УровеньОтступа); - ПервыйЭлемент = Истина; Для Каждого КлючЗначение Из Объект Цикл - Если НЕ ПервыйЭлемент Тогда - Результат = Результат + Символы.ПС; - КонецЕсли; - ПервыйЭлемент = Ложь; - - Ключ = КлючЗначение.Ключ; + Ключ = СериализоватьКлюч(КлючЗначение.Ключ); Значение = КлючЗначение.Значение; - СериализованныйКлюч = СериализоватьКлюч(Ключ); - СериализованноеЗначение = Сериализовать(Значение, УровеньОтступа + 1); - - // Если значение содержит переносы строк (массив или сложный объект), - // то нужно размещать его на новой строке с правильными отступами - Если СтрНайти(СериализованноеЗначение, Символы.ПС) > 0 Тогда - // Сложное значение - размещаем на новой строке - // Но для многострочных строк с | добавляем пробел - Если СтрНачинаетсяС(СериализованноеЗначение, "|") Тогда - Результат = Результат + Отступ + СериализованныйКлюч + ": " + СериализованноеЗначение; - Иначе - // Для массивов и объектов - значение начинается с новой строки - Результат = Результат + Отступ + СериализованныйКлюч + ":" + Символы.ПС + СериализованноеЗначение; - КонецЕсли; - Иначе - // Простое значение - размещаем на той же строке - Результат = Результат + Отступ + СериализованныйКлюч + ": " + СериализованноеЗначение; - КонецЕсли; + Результат = ДобавитьСтроку(Результат, СериализоватьСвойствоОбъекта(Ключ, Значение, Отступ, УровеньОтступа)); КонецЦикла; Возврат Результат; КонецФункции +Функция СериализоватьСвойствоОбъекта(Ключ, Значение, Отступ, УровеньОтступа) + + Если ЭтоПустаяКоллекция(Значение) Или ЭтоСкалярДляСтроки(Значение) Тогда + Возврат Отступ + Ключ + ": " + СериализоватьСкалярИлиПустуюКоллекцию(Значение); + КонецЕсли; + + Если ТипЗнч(Значение) = Тип("Строка") Тогда + Возврат Отступ + Ключ + ": " + СериализоватьМногострочнуюСтроку(Значение, УровеньОтступа); + Иначе + Возврат Отступ + Ключ + ":" + Символы.ПС + СериализоватьЗначение(Значение, УровеньОтступа + 1); + КонецЕсли; + +КонецФункции + +Функция СериализоватьСкалярИлиПустуюКоллекцию(Знач Значение) + + Если ЭтоПустаяКоллекция(Значение) Тогда + Если ТипЗнч(Значение) = Тип("Массив") Тогда + Возврат "[]"; + Иначе + Возврат "{}"; + КонецЕсли; + Иначе + Возврат СериализоватьСкаляр(Значение); + КонецЕсли; + +КонецФункции + // Сериализация ключа // // Параметры: @@ -312,18 +295,83 @@ // Функция СериализоватьКлюч(Ключ) - ТипКлюча = ТипЗнч(Ключ); + Возврат СериализоватьСкаляр(Ключ); + +КонецФункции + +Функция ЭтоСкалярДляСтроки(Значение) + + Если Значение = Неопределено Тогда + Возврат Истина; + КонецЕсли; + + ТипЗначения = ТипЗнч(Значение); + + Если ТипЗначения = Тип("Массив") Или ЭтоТипОбъекта(ТипЗначения) Тогда + Возврат Ложь; + КонецЕсли; + + Если ТипЗначения = Тип("Строка") Тогда + Возврат НЕ ЭтоМногострочнаяСтрока(Значение); + КонецЕсли; + + Возврат Истина; + +КонецФункции + +Функция ЭтоПустаяКоллекция(Значение) + + Если Значение = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ТипЗначения = ТипЗнч(Значение); - Если ТипКлюча = Тип("Строка") Тогда - // Для ключей применяем те же правила, что и для строк - Возврат СериализоватьСтроку(Ключ); - ИначеЕсли ТипКлюча = Тип("Число") Тогда - Возврат СериализоватьЧисло(Ключ); - ИначеЕсли ТипКлюча = Тип("Булево") Тогда - Возврат СериализоватьБулево(Ключ); + Если ТипЗначения = Тип("Массив") Или ЭтоТипОбъекта(ТипЗначения) Тогда + Возврат Значение.Количество() = 0; Иначе - // Для других типов преобразуем в строку - Возврат СериализоватьСтроку(Строка(Ключ)); + Возврат Ложь; + КонецЕсли; + +КонецФункции + +Функция ЭтоТипОбъекта(ТипЗначения) + + Возврат ТипЗначения = Тип("Структура") Или ТипЗначения = Тип("Соответствие"); + +КонецФункции + +Функция ЭтоМногострочнаяСтрока(Значение) + + Возврат СтрНайти(Значение, Символы.ПС) > 0 Или СтрНайти(Значение, Символы.ВК) > 0; + +КонецФункции + +Функция НормализоватьПереносыСтрок(Значение) + + Результат = СтрЗаменить(Значение, Символы.ВК + Символы.ПС, Символы.ПС); + Результат = СтрЗаменить(Результат, Символы.ВК, Символы.ПС); + + Возврат Результат; + +КонецФункции + +Функция ДобавитьСтроку(Результат, Строка) + + Если Результат = "" Тогда + Возврат Строка; + Иначе + Возврат Результат + Символы.ПС + Строка; + КонецЕсли; + +КонецФункции + +Функция УбратьНачальныйОтступ(Строка, Отступ) + + Если СтрНачинаетсяС(Строка, Отступ) Тогда + Возврат Сред(Строка, СтрДлина(Отступ) + 1); + Иначе + Возврат СокрЛП(Строка); КонецЕсли; КонецФункции @@ -342,10 +390,9 @@ Возврат ""; КонецЕсли; - // Используем 2 пробела на каждый уровень отступа КоличествоПробелов = УровеньОтступа * 2; - Результат = ""; + Пока СтрДлина(Результат) < КоличествоПробелов Цикл Результат = Результат + " "; КонецЦикла; @@ -364,22 +411,16 @@ // Функция ЭтоЧисло(Значение) - Если Значение = "" Тогда - Возврат Ложь; - КонецЕсли; - - // Убираем пробелы по краям ОчищенноеЗначение = СокрЛП(Значение); - // Проверяем регулярным выражением на простое число - Если СтрДлина(ОчищенноеЗначение) = 0 Тогда + Если ОчищенноеЗначение = "" Тогда Возврат Ложь; КонецЕсли; - // Простая проверка: число может содержать цифры, знак в начале и одну точку РазрешенныеСимволы = "0123456789.-+"; КоличествоТочек = 0; КоличествоЗнаков = 0; + КоличествоЦифр = 0; Для Позиция = 1 По СтрДлина(ОчищенноеЗначение) Цикл Символ = Сред(ОчищенноеЗначение, Позиция, 1); @@ -388,21 +429,19 @@ Возврат Ложь; КонецЕсли; - Если Символ = "." Тогда + Если СтрНайти("0123456789", Символ) > 0 Тогда + КоличествоЦифр = КоличествоЦифр + 1; + ИначеЕсли Символ = "." Тогда КоличествоТочек = КоличествоТочек + 1; - КонецЕсли; - - Если Символ = "-" ИЛИ Символ = "+" Тогда + ИначеЕсли Символ = "-" Или Символ = "+" Тогда КоличествоЗнаков = КоличествоЗнаков + 1; - // Знак может быть только в начале Если Позиция > 1 Тогда Возврат Ложь; КонецЕсли; КонецЕсли; КонецЦикла; - // Не может быть больше одной точки или одного знака - Возврат КоличествоТочек <= 1 И КоличествоЗнаков <= 1; + Возврат КоличествоЦифр > 0 И КоличествоТочек <= 1 И КоличествоЗнаков <= 1; КонецФункции @@ -416,13 +455,11 @@ // Функция ТребуетсяЗаключениеВКавычки(Значение) - // Пустая строка должна быть в кавычках Если Значение = "" Тогда Возврат Истина; КонецЕсли; - // Строки, которые могут интерпретироваться как специальные значения YAML - // НО только если они точно совпадают + НижнийРегистр = НРег(СокрЛП(Значение)); СпециальныеЗначения = Новый Массив; СпециальныеЗначения.Добавить("true"); СпециальныеЗначения.Добавить("false"); @@ -433,35 +470,30 @@ СпециальныеЗначения.Добавить("on"); СпециальныеЗначения.Добавить("off"); - НижнийРегистр = НРег(СокрЛП(Значение)); Для Каждого СпециальноеЗначение Из СпециальныеЗначения Цикл Если НижнийРегистр = СпециальноеЗначение Тогда Возврат Истина; КонецЕсли; КонецЦикла; - // Проверяем, является ли строка числом Если ЭтоЧисло(Значение) Тогда - Возврат Истина; // Если это число, заключаем в кавычки + Возврат Истина; КонецЕсли; - // Проверяем специальные символы YAML СпециальныеСимволы = ":#@`|>{}[]!%&*"; - Для Инд = 1 По СтрДлина(СпециальныеСимволы) Цикл - Символ = Сред(СпециальныеСимволы, Инд, 1); + Для Индекс = 1 По СтрДлина(СпециальныеСимволы) Цикл + Символ = Сред(СпециальныеСимволы, Индекс, 1); Если СтрНайти(Значение, Символ) > 0 Тогда Возврат Истина; КонецЕсли; КонецЦикла; - // Проверяем, начинается ли с пробела или заканчивается пробелом - Если Лев(Значение, 1) = " " ИЛИ Прав(Значение, 1) = " " Тогда + Если Лев(Значение, 1) = " " Или Прав(Значение, 1) = " " Тогда Возврат Истина; КонецЕсли; - // Проверяем на наличие переносов строк, табов и кавычек - Если СтрНайти(Значение, Символы.ПС) > 0 ИЛИ СтрНайти(Значение, Символы.ВК) > 0 - ИЛИ СтрНайти(Значение, Символы.ВТаб) > 0 ИЛИ СтрНайти(Значение, """") > 0 Тогда + Если СтрНайти(Значение, Символы.ПС) > 0 Или СтрНайти(Значение, Символы.ВК) > 0 + Или СтрНайти(Значение, Символы.ВТаб) > 0 Или СтрНайти(Значение, """") > 0 Тогда Возврат Истина; КонецЕсли; diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\321\201\320\265\321\200Yaml.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\321\201\320\265\321\200Yaml.os" index 77a3fb8..714b6db 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\321\201\320\265\321\200Yaml.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\321\201\320\265\321\200Yaml.os" @@ -35,4 +35,18 @@ Возврат Сериализатор.Сериализовать(Значение); -КонецФункции \ No newline at end of file +КонецФункции + +// YAML сериализатор нескольких документов +// +// Параметры: +// Документы - Массив - документы, сериализуемые в один YAML-поток; +// +// Возвращаемое значение: +// Строка - Строка данных в формате YAML согласно содержимому входящих документов. +// +Функция ЗаписатьДокументыYaml(Знач Документы) Экспорт + + Возврат Сериализатор.СериализоватьДокументы(Документы); + +КонецФункции diff --git a/tests/serialization.os b/tests/serialization.os new file mode 100644 index 0000000..280f4b9 --- /dev/null +++ b/tests/serialization.os @@ -0,0 +1,441 @@ +#Использовать asserts +#Использовать ".." +#Использовать "." + +&ТестовыйНабор +Процедура ПриСозданииОбъекта() +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует базовые скаляры в соответствиях") +Процедура СериализуетБазовыеСкалярыВСоответствиях() Экспорт + Данные = Новый Соответствие(); + Данные.Вставить("name", "builder:latest"); + Данные.Вставить("count", 3); + Данные.Вставить("active", Истина); + Данные.Вставить("empty", ""); + Данные.Вставить("nothing", Неопределено); + + ОжидаемыйYaml = Строки( + "name: ""builder:latest""", + "count: 3", + "active: true", + "empty: """"", + "nothing: null"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует одноэлементные коллекции с новой строки") +Процедура СериализуетОдноэлементныеКоллекцииСНовойСтроки() Экспорт + Пайп = Новый Соответствие(); + + Стадии = Новый Массив(); + Стадии.Добавить("build"); + Пайп.Вставить("stages", Стадии); + + ВложенныйОбъект = Новый Соответствие(); + ВложенныйОбъект.Вставить("name", "builder:latest"); + Пайп.Вставить("image", ВложенныйОбъект); + + ОжидаемыйYaml = Строки( + "stages:", + " - build", + "image:", + " name: ""builder:latest"""); + + ПроверитьСериализацию(Пайп, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует массивы скаляров") +Процедура СериализуетМассивыСкаляров() Экспорт + Данные = Новый Соответствие(); + + Значения = Новый Массив(); + Значения.Добавить("build"); + Значения.Добавить("test"); + Значения.Добавить(10); + Значения.Добавить(Ложь); + Данные.Вставить("stages", Значения); + + ОжидаемыйYaml = Строки( + "stages:", + " - build", + " - test", + " - 10", + " - false"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует вложенные соответствия и массивы") +Процедура СериализуетВложенныеСоответствияИМассивы() Экспорт + Данные = Новый Соответствие(); + Задачи = Новый Массив(); + + Задача = Новый Соответствие(); + Задача.Вставить("name", "build"); + + Скрипт = Новый Массив(); + Скрипт.Добавить("opm install"); + Скрипт.Добавить("oneunit e"); + Задача.Вставить("script", Скрипт); + + Задачи.Добавить(Задача); + Данные.Вставить("jobs", Задачи); + + ОжидаемыйYaml = Строки( + "jobs:", + " - name: build", + " script:", + " - opm install", + " - oneunit e"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует пустые коллекции в flow-форме") +Процедура СериализуетПустыеКоллекцииВFlowФорме() Экспорт + Данные = Новый Соответствие(); + Данные.Вставить("emptyArray", Новый Массив()); + Данные.Вставить("emptyMap", Новый Соответствие()); + + ОжидаемыйYaml = Строки( + "emptyArray: []", + "emptyMap: {}"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует многострочные строки блоком") +Процедура СериализуетМногострочныеСтрокиБлоком() Экспорт + Данные = Новый Соответствие(); + Данные.Вставить("script", "line 1" + Символы.ПС + "line 2"); + + ОжидаемыйYaml = Строки( + "script: |", + " line 1", + " line 2"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует верхнеуровневый массив как один документ") +Процедура СериализуетВерхнеуровневыйМассивКакОдинДокумент() Экспорт + Данные = Новый Массив(); + Данные.Добавить("build"); + Данные.Добавить("test"); + + ОжидаемыйYaml = Строки( + "- build", + "- test"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует несколько документов с разделителями") +Процедура СериализуетНесколькоДокументовСРазделителями() Экспорт + Документы = Новый Массив(); + + ПервыйДокумент = Новый Соответствие(); + ПервыйДокумент.Вставить("name", "first"); + Документы.Добавить(ПервыйДокумент); + + ВторойДокумент = Новый Соответствие(); + ВторойДокумент.Вставить("name", "second"); + + Элементы = Новый Массив(); + Элементы.Добавить("one"); + ВторойДокумент.Вставить("items", Элементы); + Документы.Добавить(ВторойДокумент); + + ОжидаемыйYaml = Строки( + "---", + "name: first", + "---", + "name: second", + "items:", + " - one"); + + ПроверитьСериализациюДокументов(Документы, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует корневые скаляры") +Процедура СериализуетКорневыеСкаляры() Экспорт + ПроверитьСериализацию("true", """true"""); + ПроверитьСериализацию("123", """123"""); + ПроверитьСериализацию("plain", "plain"); + ПроверитьСериализацию(42, "42"); + ПроверитьСериализацию(Ложь, "false"); + ПроверитьСериализацию(Неопределено, "null"); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Заключает в кавычки строки с YAML-значимым содержимым") +Процедура ЗаключаетВКавычкиСтрокиСYamlЗначимымСодержимым() Экспорт + Данные = Новый Соответствие(); + Данные.Вставить("boolString", "false"); + Данные.Вставить("nullString", "null"); + Данные.Вставить("numberString", "00123"); + Данные.Вставить("withSpaces", " value "); + Данные.Вставить("withComment", "value # comment"); + Данные.Вставить("withColon", "repo/image:latest"); + + ОжидаемыйYaml = Строки( + "boolString: ""false""", + "nullString: ""null""", + "numberString: ""00123""", + "withSpaces: "" value """, + "withComment: ""value # comment""", + "withColon: ""repo/image:latest"""); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует структуру как соответствие") +Процедура СериализуетСтруктуруКакСоответствие() Экспорт + Данные = Новый Структура(); + Данные.Вставить("name", "app"); + Данные.Вставить("enabled", Истина); + Данные.Вставить("replicas", 2); + + ОжидаемыйYaml = Строки( + "name: app", + "enabled: true", + "replicas: 2"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует ключи требующие кавычек") +Процедура СериализуетКлючиТребующиеКавычек() Экспорт + Данные = Новый Соответствие(); + Данные.Вставить("image:name", "builder"); + Данные.Вставить("true", "string-key"); + Данные.Вставить(10, "number-key"); + + ОжидаемыйYaml = Строки( + """image:name"": builder", + """true"": string-key", + "10: number-key"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует вложенные массивы") +Процедура СериализуетВложенныеМассивы() Экспорт + Данные = Новый Соответствие(); + Матрица = Новый Массив(); + + СтрокаМатрицы = Новый Массив(); + СтрокаМатрицы.Добавить("linux"); + СтрокаМатрицы.Добавить("x64"); + Матрица.Добавить(СтрокаМатрицы); + + СтрокаМатрицы = Новый Массив(); + СтрокаМатрицы.Добавить("windows"); + СтрокаМатрицы.Добавить("x64"); + Матрица.Добавить(СтрокаМатрицы); + + Данные.Вставить("matrix", Матрица); + + ОжидаемыйYaml = Строки( + "matrix:", + " -", + " - linux", + " - x64", + " -", + " - windows", + " - x64"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует пустые коллекции внутри массива") +Процедура СериализуетПустыеКоллекцииВнутриМассива() Экспорт + Данные = Новый Соответствие(); + Элементы = Новый Массив(); + Элементы.Добавить(Новый Массив()); + Элементы.Добавить(Новый Соответствие()); + Данные.Вставить("items", Элементы); + + ОжидаемыйYaml = Строки( + "items:", + " - []", + " - {}"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует многострочные строки внутри массива") +Процедура СериализуетМногострочныеСтрокиВнутриМассива() Экспорт + Данные = Новый Соответствие(); + Скрипт = Новый Массив(); + Скрипт.Добавить("line 1" + Символы.ПС + "line 2"); + Скрипт.Добавить("done"); + Данные.Вставить("script", Скрипт); + + ОжидаемыйYaml = Строки( + "script:", + " - |", + " line 1", + " line 2", + " - done"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +&Тест +&Тег("serialization") +&ОтображаемоеИмя("Сериализует комплексный pipeline") +Процедура СериализуетКомплексныйPipeline() Экспорт + Данные = Новый Соответствие(); + + Стадии = Новый Массив(); + Стадии.Добавить("build"); + Стадии.Добавить("test"); + Данные.Вставить("stages", Стадии); + + Переменные = Новый Соответствие(); + Переменные.Вставить("IMAGE", "repo/image:latest"); + Переменные.Вставить("DEBUG", "false"); + Данные.Вставить("variables", Переменные); + + Задачи = Новый Массив(); + + Задача = Новый Соответствие(); + Задача.Вставить("name", "build"); + Задача.Вставить("stage", "build"); + + Скрипт = Новый Массив(); + Скрипт.Добавить("opm install"); + Скрипт.Добавить("oneunit e"); + Задача.Вставить("script", Скрипт); + + Артефакты = Новый Соответствие(); + Пути = Новый Массив(); + Пути.Добавить("out"); + Артефакты.Вставить("paths", Пути); + Задача.Вставить("artifacts", Артефакты); + + Задачи.Добавить(Задача); + Данные.Вставить("jobs", Задачи); + + ОжидаемыйYaml = Строки( + "stages:", + " - build", + " - test", + "variables:", + " IMAGE: ""repo/image:latest""", + " DEBUG: ""false""", + "jobs:", + " - name: build", + " stage: build", + " script:", + " - opm install", + " - oneunit e", + " artifacts:", + " paths:", + " - out"); + + ПроверитьСериализацию(Данные, ОжидаемыйYaml); +КонецПроцедуры + +Процедура ПроверитьСериализацию(Значение, ОжидаемыйYaml) + Парсер = ТестовыеУтилиты.СоздатьЭкземплярПарсера(); + ФактическийYaml = НормализоватьПереносы(Парсер.ЗаписатьYaml(Значение)); + + Ожидаем.Что(ФактическийYaml).Равно(ОжидаемыйYaml); +КонецПроцедуры + +Процедура ПроверитьСериализациюДокументов(Документы, ОжидаемыйYaml) + Парсер = ТестовыеУтилиты.СоздатьЭкземплярПарсера(); + ФактическийYaml = НормализоватьПереносы(Парсер.ЗаписатьДокументыYaml(Документы)); + + Ожидаем.Что(ФактическийYaml).Равно(ОжидаемыйYaml); +КонецПроцедуры + +Функция Строки( + Строка1, + Строка2 = Неопределено, + Строка3 = Неопределено, + Строка4 = Неопределено, + Строка5 = Неопределено, + Строка6 = Неопределено, + Строка7 = Неопределено, + Строка8 = Неопределено, + Строка9 = Неопределено, + Строка10 = Неопределено, + Строка11 = Неопределено, + Строка12 = Неопределено, + Строка13 = Неопределено, + Строка14 = Неопределено, + Строка15 = Неопределено, + Строка16 = Неопределено, + Строка17 = Неопределено, + Строка18 = Неопределено, + Строка19 = Неопределено, + Строка20 = Неопределено) + + Результат = Строка1; + СтрокиДляДобавления = Новый Массив(); + СтрокиДляДобавления.Добавить(Строка2); + СтрокиДляДобавления.Добавить(Строка3); + СтрокиДляДобавления.Добавить(Строка4); + СтрокиДляДобавления.Добавить(Строка5); + СтрокиДляДобавления.Добавить(Строка6); + СтрокиДляДобавления.Добавить(Строка7); + СтрокиДляДобавления.Добавить(Строка8); + СтрокиДляДобавления.Добавить(Строка9); + СтрокиДляДобавления.Добавить(Строка10); + СтрокиДляДобавления.Добавить(Строка11); + СтрокиДляДобавления.Добавить(Строка12); + СтрокиДляДобавления.Добавить(Строка13); + СтрокиДляДобавления.Добавить(Строка14); + СтрокиДляДобавления.Добавить(Строка15); + СтрокиДляДобавления.Добавить(Строка16); + СтрокиДляДобавления.Добавить(Строка17); + СтрокиДляДобавления.Добавить(Строка18); + СтрокиДляДобавления.Добавить(Строка19); + СтрокиДляДобавления.Добавить(Строка20); + + Для Каждого СтрокаДляДобавления Из СтрокиДляДобавления Цикл + Если СтрокаДляДобавления <> Неопределено Тогда + Результат = Результат + Символы.ПС + СтрокаДляДобавления; + КонецЕсли; + КонецЦикла; + + Возврат Результат; +КонецФункции + +Функция НормализоватьПереносы(Значение) + Возврат СтрЗаменить(Значение, Символы.ВК, Символы.ПС); +КонецФункции