From 493f13c16644ca5c4e121645bc8722412e32095d Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Mon, 20 Jul 2026 12:48:08 +0400 Subject: [PATCH 1/7] =?UTF-8?q?=D0=BA=20#1532:=20=D0=9E=D1=82=D0=BA=D1=80?= =?UTF-8?q?=D1=8B=D1=82=D1=8C=D0=9F=D0=BE=D1=82=D0=BE=D0=BA=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=97=D0=B0=D0=BF=D0=B8=D1=81=D1=8CJSON?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Json/JSONWriter.cs | 189 ++++++++++-------- 1 file changed, 107 insertions(+), 82 deletions(-) diff --git a/src/OneScript.StandardLibrary/Json/JSONWriter.cs b/src/OneScript.StandardLibrary/Json/JSONWriter.cs index a31842fc2..09a7f7fa8 100644 --- a/src/OneScript.StandardLibrary/Json/JSONWriter.cs +++ b/src/OneScript.StandardLibrary/Json/JSONWriter.cs @@ -13,6 +13,7 @@ This Source Code Form is subject to the terms of the using OneScript.Commons; using OneScript.Contexts; using OneScript.Exceptions; +using OneScript.StandardLibrary.Binary; using OneScript.StandardLibrary.Text; using ScriptEngine.Machine; using ScriptEngine.Machine.Contexts; @@ -20,29 +21,27 @@ This Source Code Form is subject to the terms of the namespace OneScript.StandardLibrary.Json { /// - /// /// Предназначен для организации последовательной записи объектов и текстов JSON. /// [ContextClass("ЗаписьJSON", "JSONWriter")] - public class JSONWriter : AutoContext + public class JSONWriter : AutoContext, IDisposable { private const int INDENT_SIZE = 0; + private const string DEFAULT_ENCODING = "UTF-8"; private JSONWriterSettings _settings; private JsonTextWriter _writer; // Объект из библиотеки Newtonsoft для работы с форматом JSON StringWriter _stringWriter; + private bool _escapeNonAscii; public JSONWriter() { } - private bool _escapeNonAscii; - /// - /// - /// Возвращает true если для объекта чтения json был задан текст для парсинга. + /// Возвращает true если был открыт объект для записи. /// private bool IsOpen() { @@ -50,14 +49,19 @@ private bool IsOpen() } /// - /// - /// Возвращает true если для объекта чтения json был задан текст для парсинга. + /// Возвращает true если текст json выводится в строку. /// private bool IsOpenForString() { return _stringWriter != null; } + private void CheckWriter() + { + if (!IsOpen()) + throw NotOpenException(); + } + private void SetDefaultOptions() { _writer.Indentation = INDENT_SIZE; @@ -67,7 +71,13 @@ private void SetDefaultOptions() } private void SetOptions(JSONWriterSettings settings) - { + { + if (settings == null) + { + SetDefaultOptions(); + return; + } + _settings = settings; if (_settings.UseDoubleQuotes) _writer.QuoteChar = '\"'; @@ -223,7 +233,6 @@ public static JSONWriter Constructor() } /// - /// /// Определяет текущие параметры записи JSON. /// /// ПараметрыЗаписиJSON (JSONWriterSettings) @@ -234,9 +243,7 @@ public IValue Settings } - /// - /// /// Показывает, будет ли проводиться проверка правильности структуры записываемого JSON объекта. В случае обнаружение ошибки, будет сгенерировано исключение. Например: при попытке записать значение без имени вне массива или записать окончание объекта без начала. Установка данного свойства не имеет немедленного эффекта. Установленное значение свойства будет использовано только после открытия файла или установки строки. /// После создания объекта данное свойство имеет значение Истина. /// @@ -250,59 +257,39 @@ public bool ValidateStructure /// - /// - /// Завершает запись текста JSON. Если производилась запись в файл, то файл закрывается. - /// Если производилась запись в строку, то результирующая строка будет получена в качестве возвращаемого значения метода. - /// Если производилась запись в файл, то метод вернет пустую строку. + /// Завершает запись текста JSON. + /// Если производилась запись в строку, то метод вернет результирующую строку. + /// Если производилась запись в файл, то файл закрывается, а метод вернет пустую строку. /// - /// - /// - /// Значения данного типа содержат строку в формате Unicode произвольной длины. + /// Допускается повторное закрытие. Будет возвращена пустая строка. + /// Строка в формате Unicode [ContextMethod("Закрыть", "Close")] public string Close() { - string res = ""; - - if (IsOpenForString()) - { - res = _stringWriter.ToString(); - _stringWriter.Close(); - _stringWriter = null; - } - - if (_writer != null) - { - _writer.Close(); - _writer = null; - } - - return res; + var result = IsOpenForString() ? _stringWriter.ToString() : String.Empty; + + Dispose(); + + return result; } - /// - /// /// Выполняет запись произвольной строки в документ, при этом проверка структуры документа не выполняется. /// Если при использовании метода свойство ПроверятьСтруктуру установлено в значение Истина, то проверка структуры продолжается на следующем элементе. /// - /// /// /// Строка, записываемая в документ JSON. [ContextMethod("ЗаписатьБезОбработки", "WriteRaw")] public void WriteRaw(string stringValue) { - if (!IsOpen()) - throw NotOpenException(); - + CheckWriter(); _writer.WriteRaw(stringValue); } /// - /// /// Записывает значение свойства JSON. /// - /// /// /// Записываемое значение. Типы: Строка (String), Число (Number), Булево (Boolean), Неопределено (Undefined) /// @@ -310,9 +297,8 @@ public void WriteRaw(string stringValue) /// Значение по умолчанию: Ложь. [ContextMethod("ЗаписатьЗначение", "WriteValue")] public void WriteValue(IValue value, bool useFormatWithExponent = false) - { - if (!IsOpen()) - throw NotOpenException(); + { + CheckWriter(); var clrValue = value.UnwrapToClrObject(); switch (clrValue) @@ -354,78 +340,70 @@ public void WriteValue(IValue value, bool useFormatWithExponent = false) } /// - /// /// Записывает имя свойства JSON. /// - /// /// /// Имя свойства. [ContextMethod("ЗаписатьИмяСвойства", "WritePropertyName")] public void WritePropertyName(string propertyName) { + CheckWriter(); _writer.WritePropertyName(propertyName); } /// - /// /// Записывает конец массива JSON. /// - /// [ContextMethod("ЗаписатьКонецМассива", "WriteEndArray")] public void WriteEndArray() { + CheckWriter(); _writer.WriteEndArray(); } /// - /// /// Записывает конец объекта JSON. /// - /// [ContextMethod("ЗаписатьКонецОбъекта", "WriteEndObject")] public void WriteEndObject() { + CheckWriter(); _writer.WriteEndObject(); } /// - /// /// Записывает начало массива JSON. /// - /// [ContextMethod("ЗаписатьНачалоМассива", "WriteStartArray")] public void WriteStartArray() { + CheckWriter(); _writer.WriteStartArray(); } /// - /// /// Записывает начало объекта JSON. /// - /// [ContextMethod("ЗаписатьНачалоОбъекта", "WriteStartObject")] public void WriteStartObject() { + CheckWriter(); _writer.WriteStartObject(); } /// - /// /// Открывает файл для записи JSON. Позволяет указать тип кодировки, который будет использован для записи файла JSON, а также использование BOM. /// - /// /// /// Имя файла, в который будет записываться текст JSON. /// /// В качестве типа кодировки может быть указана одна из возможных кодировок текста. В этом случае файл будет записан в соответствующей кодировке. Если же в качестве параметра указана пустая строка или ничего не указано, то для записи файла будет использована кодировка UTF8. /// Поддерживаемые коды кодировок: - /// /// Значение по умолчанию: UTF-8. /// /// Определяет, будет ли добавлен маркер порядка байт (BOM) к результирующему файлу JSON. @@ -437,61 +415,108 @@ public void WriteStartObject() public void OpenFile(string fileName, string encoding = null, bool addBOM = false, JSONWriterSettings settings = null) { StreamWriter streamWriter; - + var textEncoding = TextEncodingEnum.GetEncodingByName(encoding ?? DEFAULT_ENCODING, addBOM); + try { - if (encoding != null) - streamWriter = FileOpener.OpenWriter(fileName, TextEncodingEnum.GetEncodingByName(encoding, addBOM)); - else - streamWriter = FileOpener.OpenWriter(fileName, TextEncodingEnum.GetEncodingByName("UTF-8", addBOM)); + streamWriter = FileOpener.OpenWriter(fileName, textEncoding); } catch (Exception e) { throw new RuntimeException(e.Message, e); } - if (IsOpen()) - Close(); - - _writer = new JsonTextWriter(streamWriter); - if (settings == null) - SetDefaultOptions(); - else - SetOptions(settings); + SetWriter(streamWriter, settings); + } - SetNewLineChars(streamWriter); + /// + /// Открывает поток для записи JSON. Позволяет указать тип кодировки, который будет использован для записи файла JSON, а также использование BOM. + /// + /// + /// Поток, в который будет записываться текст JSON. + /// + /// В качестве типа кодировки может быть указана одна из возможных кодировок текста. В этом случае файл будет записан в соответствующей кодировке. Если же в качестве параметра указана пустая строка или ничего не указано, то для записи файла будет использована кодировка UTF8. + /// Поддерживаемые коды кодировок: + /// Значение по умолчанию: UTF-8. + /// + /// Определяет, будет ли добавлен маркер порядка байт (BOM) к результирующему потоку JSON. + /// Внимание. Стандарт RFC7159 настоятельно рекомендует не добавлять маркер порядка байт (BOM) к документу JSON . + /// Значение по умолчанию: Ложь. + /// + /// Параметры, используемые при открытии потока для настройки записи в формате JSON. + [ContextMethod("ОткрытьПоток", "OpenStream")] + public void OpenStream(IStreamWrapper streamContext, string encoding = null, bool addBOM = false, JSONWriterSettings settings = null) + { + if (streamContext is null) + throw new ArgumentNullException(nameof(streamContext)); + + if (streamContext.IsReadOnly) + throw CannotWriteException(); + + var textEncoding = TextEncodingEnum.GetEncodingByName(encoding ?? DEFAULT_ENCODING, addBOM); + StreamWriter streamWriter = new(streamContext.GetUnderlyingStream(), textEncoding); + SetWriter(streamWriter, settings); } /// - /// /// Инициализирует объект для вывода результирующего JSON текста в строку. /// - /// /// /// Параметры, используемые при записи объекта JSON. /// По умолчанию, содержит ПараметрыЗаписиJSON, сгенерированные автоматически. [ContextMethod("УстановитьСтроку", "SetString")] public void SetString(JSONWriterSettings settings = null) { + _stringWriter = new StringWriter(); + SetWriter(_stringWriter, settings); + } + + private void SetWriter(TextWriter stream, JSONWriterSettings settings) + { if (IsOpen()) Close(); - _stringWriter = new StringWriter(); - _writer = new JsonTextWriter(_stringWriter); - if (settings == null) - SetDefaultOptions(); - else - SetOptions(settings); - SetNewLineChars(_stringWriter); + _writer = new JsonTextWriter(stream); + + SetOptions(settings); + SetNewLineChars(stream); + } + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing && _writer is not null) + { + _stringWriter?.Dispose(); + _stringWriter = null; + + _writer.Close(); + _writer = null; + } } + #endregion + RuntimeException NotOpenException() { return new RuntimeException(Locale.NStr ("ru='Приемник данных JSON не открыт';en='JSON data target is not opened'")); } + RuntimeException CannotWriteException() + { + return new("Попытка записи в поток не поддерживающий запись", + "Cannot write to a stream that does not support writing"); + } + RuntimeException TypeNotSupportedException(Type type) { return new RuntimeException(Locale.NStr From 5f656f709aa5c7874aa1b95e0c0d7847e9ef1ada Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Mon, 20 Jul 2026 13:47:25 +0400 Subject: [PATCH 2/7] =?UTF-8?q?=D0=BF=D0=BE=20=D0=B7=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=87=D0=B0=D0=BD=D0=B8=D1=8F=D0=BC:=20Flush=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B4=20=D0=B7=D0=B0=D0=BA=D1=80=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D0=B5=D0=BC,=20=D0=B7=D0=B0=D0=BA=D1=80=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=BE=D1=82=20=D1=83=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Json/JSONWriter.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/OneScript.StandardLibrary/Json/JSONWriter.cs b/src/OneScript.StandardLibrary/Json/JSONWriter.cs index 09a7f7fa8..5bf365894 100644 --- a/src/OneScript.StandardLibrary/Json/JSONWriter.cs +++ b/src/OneScript.StandardLibrary/Json/JSONWriter.cs @@ -266,9 +266,15 @@ public bool ValidateStructure [ContextMethod("Закрыть", "Close")] public string Close() { - var result = IsOpenForString() ? _stringWriter.ToString() : String.Empty; + var result = String.Empty; + if (_writer is not null) + { + _writer.Flush(); + if (IsOpenForString()) + result = _stringWriter.ToString(); - Dispose(); + Dispose(); + } return result; } @@ -426,6 +432,7 @@ public void OpenFile(string fileName, string encoding = null, bool addBOM = fals throw new RuntimeException(e.Message, e); } + Close(); SetWriter(streamWriter, settings); } @@ -453,6 +460,7 @@ public void OpenStream(IStreamWrapper streamContext, string encoding = null, boo if (streamContext.IsReadOnly) throw CannotWriteException(); + Close(); var textEncoding = TextEncodingEnum.GetEncodingByName(encoding ?? DEFAULT_ENCODING, addBOM); StreamWriter streamWriter = new(streamContext.GetUnderlyingStream(), textEncoding); SetWriter(streamWriter, settings); @@ -468,15 +476,14 @@ public void OpenStream(IStreamWrapper streamContext, string encoding = null, boo [ContextMethod("УстановитьСтроку", "SetString")] public void SetString(JSONWriterSettings settings = null) { + Close(); + _stringWriter = new StringWriter(); SetWriter(_stringWriter, settings); } private void SetWriter(TextWriter stream, JSONWriterSettings settings) { - if (IsOpen()) - Close(); - _writer = new JsonTextWriter(stream); SetOptions(settings); From b10fbdaae281fc428a49f8b98653bba3f35866cb Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Tue, 21 Jul 2026 16:28:29 +0400 Subject: [PATCH 3/7] =?UTF-8?q?=D0=BD=D0=B5=20=D0=B7=D0=B0=D0=BA=D1=80?= =?UTF-8?q?=D1=8B=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BF=D0=BE=D1=82=D0=BE=D0=BA?= =?UTF-8?q?=20+=D1=82=D0=B5=D1=81=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Json/JSONWriter.cs | 2 +- tests/json/test-json_writer.os | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/OneScript.StandardLibrary/Json/JSONWriter.cs b/src/OneScript.StandardLibrary/Json/JSONWriter.cs index 5bf365894..bfe8d0808 100644 --- a/src/OneScript.StandardLibrary/Json/JSONWriter.cs +++ b/src/OneScript.StandardLibrary/Json/JSONWriter.cs @@ -462,7 +462,7 @@ public void OpenStream(IStreamWrapper streamContext, string encoding = null, boo Close(); var textEncoding = TextEncodingEnum.GetEncodingByName(encoding ?? DEFAULT_ENCODING, addBOM); - StreamWriter streamWriter = new(streamContext.GetUnderlyingStream(), textEncoding); + StreamWriter streamWriter = new(streamContext.GetUnderlyingStream(), textEncoding, leaveOpen: true); SetWriter(streamWriter, settings); } diff --git a/tests/json/test-json_writer.os b/tests/json/test-json_writer.os index 927a7c186..7f355cf3c 100644 --- a/tests/json/test-json_writer.os +++ b/tests/json/test-json_writer.os @@ -18,6 +18,7 @@ СписокТестов.Добавить("Тест_Должен_СверитьХешСуммуСгенерированнойМетодомЗаписатьJSONСтруктурыСФиксированнымиКоллекциями"); СписокТестов.Добавить("Тест_Должен_ПроверитьПустуюСтрокуПриЗакрытии"); СписокТестов.Добавить("Тест_Должен_ПроверитьСохранениеУстановленнойСтроки"); + СписокТестов.Добавить("Тест_Должен_ПроверитьСохранениеПотокаПослеЗакрытия"); Возврат СписокТестов; КонецФункции @@ -207,3 +208,21 @@ Структура = Новый Структура(); ПопыткаЗаписатьЗначение(Структура); КонецПроцедуры + +Процедура Тест_Должен_ПроверитьСохранениеПотокаПослеЗакрытия() Экспорт + Поток = Новый ПотокВПамяти(64); + Поток.Записать(ПолучитьБуферДвоичныхДанныхИзСтроки("БДД"),0,2); + + ЗаписьJSON = Новый ЗаписьJSON; + ЗаписьJSON.ОткрытьПоток(Поток); + ЗаписьJSON.УстановитьСтроку(); + ЗаписьJSON.ЗаписатьБезОбработки("123"); + РезЗаписи = ЗаписьJSON.Закрыть(); + + Поток.Записать(ПолучитьБуферДвоичныхДанныхИзСтроки("БДД"),2,2); + РезПотока = Поток.ЗакрытьИПолучитьДвоичныеДанные(); + + юТест.ПроверитьРавенство("123", РезЗаписи); + юТест.ПроверитьРавенство("D0 91 D0 94", Строка(РезПотока)); +КонецПроцедуры + From 0c164525dadfd4b9d9eae9d9e78761d013b3abd4 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Tue, 21 Jul 2026 17:09:59 +0400 Subject: [PATCH 4/7] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=B8=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/json/test-json_writer.os | 47 ++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/tests/json/test-json_writer.os b/tests/json/test-json_writer.os index 7f355cf3c..739ce2492 100644 --- a/tests/json/test-json_writer.os +++ b/tests/json/test-json_writer.os @@ -18,7 +18,9 @@ СписокТестов.Добавить("Тест_Должен_СверитьХешСуммуСгенерированнойМетодомЗаписатьJSONСтруктурыСФиксированнымиКоллекциями"); СписокТестов.Добавить("Тест_Должен_ПроверитьПустуюСтрокуПриЗакрытии"); СписокТестов.Добавить("Тест_Должен_ПроверитьСохранениеУстановленнойСтроки"); + СписокТестов.Добавить("Тест_Должен_ПроверитьЗаписьВПоток"); СписокТестов.Добавить("Тест_Должен_ПроверитьСохранениеПотокаПослеЗакрытия"); + СписокТестов.Добавить("Тест_Должен_ПроверитьИсключениеНаПотокеТолькоДляЧтения"); Возврат СписокТестов; КонецФункции @@ -209,20 +211,55 @@ ПопыткаЗаписатьЗначение(Структура); КонецПроцедуры +Процедура Тест_Должен_ПроверитьЗаписьВПоток() Экспорт + Поток = Новый ПотокВПамяти(64); + + ЗаписьJSON = Новый ЗаписьJSON; + ЗаписьJSON.ОткрытьПоток(Поток); + ЗаписьJSON.ЗаписатьБезОбработки("123"); + РезЗаписи = ЗаписьJSON.Закрыть(); + РезПотока = Поток.ЗакрытьИПолучитьДвоичныеДанные(); + + юТест.ПроверитьРавенство("", РезЗаписи); + юТест.ПроверитьРавенство("31 32 33", Строка(РезПотока)); +КонецПроцедуры + + +// отличается от 1С Процедура Тест_Должен_ПроверитьСохранениеПотокаПослеЗакрытия() Экспорт Поток = Новый ПотокВПамяти(64); - Поток.Записать(ПолучитьБуферДвоичныхДанныхИзСтроки("БДД"),0,2); + Поток.Записать(ПолучитьБуферДвоичныхДанныхИзСтроки("01"),0,2); ЗаписьJSON = Новый ЗаписьJSON; ЗаписьJSON.ОткрытьПоток(Поток); + ЗаписьJSON.ЗаписатьБезОбработки("23"); ЗаписьJSON.УстановитьСтроку(); - ЗаписьJSON.ЗаписатьБезОбработки("123"); + ЗаписьJSON.ЗаписатьБезОбработки("45"); РезЗаписи = ЗаписьJSON.Закрыть(); - Поток.Записать(ПолучитьБуферДвоичныхДанныхИзСтроки("БДД"),2,2); + Поток.Записать(ПолучитьБуферДвоичныхДанныхИзСтроки("67"),0,2); РезПотока = Поток.ЗакрытьИПолучитьДвоичныеДанные(); - юТест.ПроверитьРавенство("123", РезЗаписи); - юТест.ПроверитьРавенство("D0 91 D0 94", Строка(РезПотока)); + юТест.ПроверитьРавенство("45", РезЗаписи); + юТест.ПроверитьРавенство("30 31 32 33 36 37", Строка(РезПотока)); КонецПроцедуры +// отличается от 1С +Процедура Тест_Должен_ПроверитьИсключениеНаПотокеТолькоДляЧтения() Экспорт + Поток = Новый ПотокВПамяти(64); + ПотокЧтения = Поток.ПолучитьПотокТолькоДляЧтения(); + + ЗаписьJSON = Новый ЗаписьJSON; + Попытка + ЗаписьJSON.ОткрытьПоток(ПотокЧтения); // OneScript падает здесь + Исключение + Возврат; + КонецПопытки; + + ЗаписьJSON.ЗаписатьБезОбработки("123"); // 1C падает здесь + ЗаписьJSON.Закрыть(); + + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + + From f4a1a41d11fe4b7682e82991fc19ef55bbe0a123 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Tue, 21 Jul 2026 18:11:38 +0400 Subject: [PATCH 5/7] =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=BE=20=D1=8D=D0=BA=D1=80=D0=B0=D0=BD=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B8=D0=BC=D0=BE=D0=BB=D0=BE?= =?UTF-8?q?=D0=B2=20+=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Json/JSONWriter.cs | 75 +++++-------------- tests/json/test-json_writer.os | 43 ++++++++++- 2 files changed, 58 insertions(+), 60 deletions(-) diff --git a/src/OneScript.StandardLibrary/Json/JSONWriter.cs b/src/OneScript.StandardLibrary/Json/JSONWriter.cs index bfe8d0808..62aa68873 100644 --- a/src/OneScript.StandardLibrary/Json/JSONWriter.cs +++ b/src/OneScript.StandardLibrary/Json/JSONWriter.cs @@ -130,62 +130,25 @@ string EscapeCharacters(string sval, bool EscapeSlash) for (var i = 0; i < length; i++) { char c = sval[i]; - string? escapedValue = null; - - if (EscapeSlash && c == '/') - { - escapedValue = "\\/"; - } - else if (_settings.EscapeAmpersand && c == '&') - { - escapedValue = "\\&"; - } - else if ((_settings.EscapeSingleQuotes || !_settings.UseDoubleQuotes) && c == '\'') - { - escapedValue = "\\u0027"; - } - else if (_settings.EscapeAngleBrackets && c == '<') - { - escapedValue = "\\u003C"; - } - else if (_settings.EscapeAngleBrackets && c == '>') - { - escapedValue = "\\u003E"; - } - else if (c == '\r') - { - escapedValue = "\\r"; - } - else if (c == '\n') - { - escapedValue = "\\n"; - } - else if (c == '\f') - { - escapedValue = "\\f"; - } - else if (c == '\"') - { - escapedValue = "\\\""; - } - else if (c == '\b') - { - escapedValue = "\\b"; - } - else if (c == '\t') - { - escapedValue = "\\t"; - } - else if (c == '\\') - { - escapedValue = "\\\\"; - } - - // Спец. символы: \u0000, \u0001, \u0002, ... , \u001e, \u001f; - else if ((int)c >= 0 && (int)c <= 31) - { - escapedValue = "\\u" + ((int)c).ToString("x4"); - } + string escapedValue = c switch + { + '/' when EscapeSlash => "\\/", + '\'' when (_settings.EscapeSingleQuotes || !_settings.UseDoubleQuotes) => "\\u0027", + '&' when _settings.EscapeAmpersand => "\\u0026", + '<' when _settings.EscapeAngleBrackets => "\\u003C", + '>' when _settings.EscapeAngleBrackets => "\\u003E", + '\x2028' when _settings.EscapeLineTerminators => "\\u2028", + '\x2029' when _settings.EscapeLineTerminators => "\\u2029", + '\r' => "\\r", + '\n' => "\\n", + '\f' => "\\f", + '\b' => "\\b", + '\t' => "\\t", + '\"' => "\\\"", + '\\' => "\\\\", + >= '\x00' and <= '\x1F' => "\\u" + ((int)c).ToString("x4"), + _ => null + }; if (escapedValue != null) { diff --git a/tests/json/test-json_writer.os b/tests/json/test-json_writer.os index 739ce2492..ea1f453ed 100644 --- a/tests/json/test-json_writer.os +++ b/tests/json/test-json_writer.os @@ -10,7 +10,9 @@ СписокТестов = Новый Массив; СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСоСпецСимволами"); - СписокТестов.Добавить("Тест_Должен_СверитьСтрокуЭкранированнымиКириллическимиСимволами"); + СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСЭкранированнымиКириллическимиСимволами"); + СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСЭкранированнымиСимволами_БезПараметров"); + СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСЭкранированнымиСимволами_СПараметрами"); СписокТестов.Добавить("Тест_Должен_ПроверитьИсключенияДляНедопустимыхТипов"); СписокТестов.Добавить("Тест_Должен_СверитьХешСуммуСгенерированнойСтрокиJSON"); @@ -66,7 +68,7 @@ КонецПроцедуры -Процедура Тест_Должен_СверитьСтрокуЭкранированнымиКириллическимиСимволами() Экспорт +Процедура Тест_Должен_СверитьСтрокуСЭкранированнымиКириллическимиСимволами() Экспорт ЗаписьJSON = Новый ЗаписьJSON; Параметры = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Windows, , , ЭкранированиеСимволовJSON.СимволыВнеASCII); @@ -89,6 +91,41 @@ КонецПроцедуры +Процедура Тест_Должен_СверитьСтрокуСЭкранированнымиСимволами_БезПараметров() Экспорт + ЗаписьJSON = Новый ЗаписьJSON; + ЗаписьJSON.УстановитьСтроку(); + + ЗаписьJSON.ЗаписатьЗначение("""\<&>/'"+Символ(13)+Символ(10)+Символ(12)+Символ(8)+Символ(9)); + Рез = ЗаписьJSON.Закрыть(); + + юТест.ПроверитьРавенство("""\""\\<&>/'\r\n\f\b\t""", Рез); + +КонецПроцедуры + +Процедура Тест_Должен_СверитьСтрокуСЭкранированнымиСимволами_СПараметрами() Экспорт + Параметры = Новый ПараметрыЗаписиJSON( + , // ПереносСтрок + , // СимволыОтступа + Ложь, // ИспользоватьДвойныеКавычки + ЭкранированиеСимволовJSON.Нет, // ЭкранированиеСимволов + Истина, // ЭкранироватьУгловыеСкобки + Истина, // ЭкранироватьРазделителиСтрок + Истина, // ЭкранироватьАмперсанд + Истина, // ЭкранироватьОдинарныеКавычки + Истина // ЭкранироватьСлеш + ); + + ЗаписьJSON = Новый ЗаписьJSON; + ЗаписьJSON.УстановитьСтроку(Параметры); + + ЗаписьJSON.ЗаписатьЗначение("""\<&>/'"+Символ(8232)+Символ(8233)); + Рез = ЗаписьJSON.Закрыть(); + + юТест.ПроверитьРавенство("'\""\\\u003C\u0026\u003E\/\u0027\u2028\u2029'", Рез); + +КонецПроцедуры + + Процедура Тест_Должен_СверитьХешСуммуСгенерированнойМетодомЗаписатьJSONСтруктурыСФиксированнымиКоллекциями() Экспорт Запись = Новый ЗаписьJson(); @@ -224,8 +261,6 @@ юТест.ПроверитьРавенство("31 32 33", Строка(РезПотока)); КонецПроцедуры - -// отличается от 1С Процедура Тест_Должен_ПроверитьСохранениеПотокаПослеЗакрытия() Экспорт Поток = Новый ПотокВПамяти(64); Поток.Записать(ПолучитьБуферДвоичныхДанныхИзСтроки("01"),0,2); From a029e305e31f2572781dd55bbab8a73ff3e5a507 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Wed, 22 Jul 2026 17:20:26 +0400 Subject: [PATCH 6/7] =?UTF-8?q?=D1=81=D0=B2=D0=BE=D0=B9=D1=81=D1=82=D0=B2?= =?UTF-8?q?=D0=BE=20=D0=9F=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D1=8B?= =?UTF-8?q?;=20=D0=9F=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D1=8B?= =?UTF-8?q?=D0=97=D0=B0=D0=BF=D0=B8=D1=81=D0=B8JSON=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D1=83=D0=BC=D0=BE=D0=BB=D1=87=D0=B0=D0=BD=D0=B8=D1=8E=20+?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Json/JSONWriter.cs | 25 +++++--- .../Json/JSONWriterSettings.cs | 8 +-- tests/json/test-json_writer.os | 61 +++++++++++++++---- 3 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/OneScript.StandardLibrary/Json/JSONWriter.cs b/src/OneScript.StandardLibrary/Json/JSONWriter.cs index 62aa68873..5c2b023f1 100644 --- a/src/OneScript.StandardLibrary/Json/JSONWriter.cs +++ b/src/OneScript.StandardLibrary/Json/JSONWriter.cs @@ -36,8 +36,8 @@ public class JSONWriter : AutoContext, IDisposable private bool _escapeNonAscii; public JSONWriter() - { - + { + _settings = new JSONWriterSettings(); } /// @@ -85,9 +85,17 @@ private void SetOptions(JSONWriterSettings settings) _writer.QuoteChar = '\''; } - _writer.IndentChar = !string.IsNullOrEmpty(_settings.PaddingSymbols) ? _settings.PaddingSymbols[0] : ' '; - _writer.Indentation = !string.IsNullOrEmpty(_settings.PaddingSymbols) ? 1 : INDENT_SIZE; - _writer.Formatting = Formatting.Indented; + if (string.IsNullOrEmpty(_settings.PaddingSymbols)) + { + _writer.IndentChar = ' '; + _writer.Indentation = INDENT_SIZE; + } + else + { + _writer.IndentChar = _settings.PaddingSymbols[0]; + _writer.Indentation = 1; + } + _writer.Formatting = Formatting.Indented; if (_settings.EscapeCharacters != JSONCharactersEscapeModeEnum.None) { @@ -189,6 +197,7 @@ void SetNewLineChars(TextWriter textWriter) } } } + [ScriptConstructor] public static JSONWriter Constructor() { @@ -200,11 +209,7 @@ public static JSONWriter Constructor() /// /// ПараметрыЗаписиJSON (JSONWriterSettings) [ContextProperty("Параметры", "Settings")] - public IValue Settings - { - get { throw new NotImplementedException(); } - - } + public IValue Settings => _settings; /// /// Показывает, будет ли проводиться проверка правильности структуры записываемого JSON объекта. В случае обнаружение ошибки, будет сгенерировано исключение. Например: при попытке записать значение без имени вне массива или записать окончание объекта без начала. Установка данного свойства не имеет немедленного эффекта. Установленное значение свойства будет использовано только после открытия файла или установки строки. diff --git a/src/OneScript.StandardLibrary/Json/JSONWriterSettings.cs b/src/OneScript.StandardLibrary/Json/JSONWriterSettings.cs index ba7825f2d..9df1e99dc 100644 --- a/src/OneScript.StandardLibrary/Json/JSONWriterSettings.cs +++ b/src/OneScript.StandardLibrary/Json/JSONWriterSettings.cs @@ -61,7 +61,7 @@ public JSONWriterSettings(JSONLineBreakEnum NewLines = JSONLineBreakEnum.Auto, s /// /// Определяет символы отступа, используемые при записи данных JSON. /// Применяется только, если значение ПереносСтрокJSON отлично от Нет. - /// Значение по умолчанию: " ". + /// Значение по умолчанию: "". /// /// Определяет, будут ли при записи имена свойств JSON записываться в двойных кавычках. /// Значение по умолчанию: Истина. @@ -86,8 +86,8 @@ public JSONWriterSettings(JSONLineBreakEnum NewLines = JSONLineBreakEnum.Auto, s /// Значение по умолчанию: Ложь. [ScriptConstructor(Name = "По описанию параметров записи")] public static JSONWriterSettings ParametrizedConstructor( - JSONLineBreakEnum newLines = JSONLineBreakEnum.None, - string paddingSymbols = null, + JSONLineBreakEnum newLines = JSONLineBreakEnum.Auto, + string paddingSymbols = "", bool useDoubleQuotes = true, JSONCharactersEscapeModeEnum escapeCharacters = JSONCharactersEscapeModeEnum.None, bool escapeAngleBrackets = false, @@ -147,7 +147,7 @@ public static JSONWriterSettings Constructor() /// /// Строка (String) [ContextProperty("СимволыОтступа", "PaddingSymbols")] - public string PaddingSymbols => _paddingSymbols; + public string PaddingSymbols => _paddingSymbols ?? string.Empty; /// diff --git a/tests/json/test-json_writer.os b/tests/json/test-json_writer.os index ea1f453ed..311a3145c 100644 --- a/tests/json/test-json_writer.os +++ b/tests/json/test-json_writer.os @@ -9,6 +9,8 @@ СписокТестов = Новый Массив; + СписокТестов.Добавить("Тест_Должен_ПроверитьПараметрыЗаписиJSONПоУмолчанию"); + СписокТестов.Добавить("Тест_Должен_ПроверитьУстановленныеПараметрыПоУмолчанию"); СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСоСпецСимволами"); СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСЭкранированнымиКириллическимиСимволами"); СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСЭкранированнымиСимволами_БезПараметров"); @@ -30,7 +32,10 @@ Процедура Тест_Должен_СверитьХешСуммуСгенерированнойСтрокиJSON() Экспорт Запись = Новый ЗаписьJson(); - Запись.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Windows)); + Параметры = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Windows); + юТест.ПроверитьРавенство(ПереносСтрокJSON.Windows, Параметры.ПереносСтрок, "ПереносСтрок.Windows"); + + Запись.УстановитьСтроку(Параметры); Запись.ЗаписатьНачалоОбъекта(); Запись.ЗаписатьИмяСвойства("firstName"); Запись.ЗаписатьЗначение("Иван"); @@ -60,7 +65,7 @@ Запись.ЗаписатьКонецОбъекта(); Текст = Запись.Закрыть(); - + Хеширование = Новый ХешированиеДанных(ХешФункция.CRC32); Хеширование.Добавить(Текст); @@ -70,24 +75,56 @@ Процедура Тест_Должен_СверитьСтрокуСЭкранированнымиКириллическимиСимволами() Экспорт -ЗаписьJSON = Новый ЗаписьJSON; -Параметры = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Windows, , , ЭкранированиеСимволовJSON.СимволыВнеASCII); - -ЗаписьJSON.УстановитьСтроку(Параметры); + ЗаписьJSON = Новый ЗаписьJSON; + Параметры = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Windows, , , ЭкранированиеСимволовJSON.СимволыВнеASCII); + + ЗаписьJSON.УстановитьСтроку(Параметры); -ЗаписатьJSON(ЗаписьJSON, "Символы кириллицы"); + ЗаписатьJSON(ЗаписьJSON, "Символы кириллицы"); -юТест.ПроверитьРавенство(ЗаписьJSON.Закрыть(), """\\u0421\\u0438\\u043c\\u0432\\u043e\\u043b\\u044b \\u043a\\u0438\\u0440\\u0438\\u043b\\u043b\\u0438\\u0446\\u044b"""); + юТест.ПроверитьРавенство(ЗаписьJSON.Закрыть(), """\\u0421\\u0438\\u043c\\u0432\\u043e\\u043b\\u044b \\u043a\\u0438\\u0440\\u0438\\u043b\\u043b\\u0438\\u0446\\u044b"""); КонецПроцедуры Процедура Тест_Должен_СверитьСтрокуСоСпецСимволами() Экспорт + + ЗаписьJSON = Новый ЗаписьJSON; + ЗаписьJSON.УстановитьСтроку(); + + ЗаписатьJSON(ЗаписьJSON, Символ(1) + Символ(31)); + юТест.ПроверитьРавенство(ЗаписьJSON.Закрыть(), """\u0001\u001f"""); + +КонецПроцедуры + +Процедура Тест_Должен_ПроверитьПараметрыЗаписиJSONПоУмолчанию() Экспорт + Параметры = Новый ПараметрыЗаписиJSON; + + юТест.ПроверитьРавенство(ПереносСтрокJSON.Авто, Параметры.ПереносСтрок, "ПереносСтрок"); + юТест.ПроверитьРавенство("", Параметры.СимволыОтступа, "СимволыОтступа"); + юТест.ПроверитьИстину(Параметры.ИспользоватьДвойныеКавычки, "ИспользоватьДвойныеКавычки"); + юТест.ПроверитьРавенство( ЭкранированиеСимволовJSON.Нет, Параметры.ЭкранированиеСимволов, "ЭкранированиеСимволов"); + юТест.ПроверитьЛожь(Параметры.ЭкранироватьУгловыеСкобки, "ЭкранироватьУгловыеСкобки"); + юТест.ПроверитьИстину(Параметры.ЭкранироватьРазделителиСтрок, "ЭкранироватьРазделителиСтрок"); + юТест.ПроверитьЛожь(Параметры.ЭкранироватьАмперсанд, "ЭкранироватьАмперсанд"); + юТест.ПроверитьЛожь(Параметры.ЭкранироватьОдинарныеКавычки, "ЭкранироватьОдинарныеКавычки"); + юТест.ПроверитьЛожь(Параметры.ЭкранироватьСлеш, "ЭкранироватьСлеш"); -ЗаписьJSON = Новый ЗаписьJSON; -ЗаписьJSON.УстановитьСтроку(); +КонецПроцедуры + +Процедура Тест_Должен_ПроверитьУстановленныеПараметрыПоУмолчанию() Экспорт + ЗаписьJSON = Новый ЗаписьJSON; + Параметры = ЗаписьJSON.Параметры; + ЗаписьJSON.Закрыть(); -ЗаписатьJSON(ЗаписьJSON, Символ(1) + Символ(31)); -юТест.ПроверитьРавенство(ЗаписьJSON.Закрыть(), """\u0001\u001f"""); + юТест.ПроверитьРавенство(ПереносСтрокJSON.Авто, Параметры.ПереносСтрок, "ПереносСтрок"); + юТест.ПроверитьРавенство("", Параметры.СимволыОтступа, "СимволыОтступа"); + юТест.ПроверитьИстину(Параметры.ИспользоватьДвойныеКавычки, "ИспользоватьДвойныеКавычки"); + юТест.ПроверитьРавенство( ЭкранированиеСимволовJSON.Нет, Параметры.ЭкранированиеСимволов, "ЭкранированиеСимволов"); + юТест.ПроверитьЛожь(Параметры.ЭкранироватьУгловыеСкобки, "ЭкранироватьУгловыеСкобки"); + юТест.ПроверитьИстину(Параметры.ЭкранироватьРазделителиСтрок, "ЭкранироватьРазделителиСтрок"); + юТест.ПроверитьЛожь(Параметры.ЭкранироватьАмперсанд, "ЭкранироватьАмперсанд"); + юТест.ПроверитьЛожь(Параметры.ЭкранироватьОдинарныеКавычки, "ЭкранироватьОдинарныеКавычки"); + юТест.ПроверитьЛожь(Параметры.ЭкранироватьСлеш, "ЭкранироватьСлеш"); КонецПроцедуры From 28013d02aa68cd4d331500e760da6e8f5428893a Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Thu, 23 Jul 2026 16:21:50 +0400 Subject: [PATCH 7/7] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=20=D0=AD=D0=BA=D1=80=D0=B0=D0=BD=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=D0=A1=D0=B8=D0=BC=D0=B2?= =?UTF-8?q?=D0=BE=D0=BB=D0=BE=D0=B2;=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=B8=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Json/JSONWriter.cs | 90 ++++++------------- .../Json/JSONWriterSettings.cs | 21 +---- tests/json/test-json_writer.os | 16 +++- 3 files changed, 45 insertions(+), 82 deletions(-) diff --git a/src/OneScript.StandardLibrary/Json/JSONWriter.cs b/src/OneScript.StandardLibrary/Json/JSONWriter.cs index 5c2b023f1..b85d72a43 100644 --- a/src/OneScript.StandardLibrary/Json/JSONWriter.cs +++ b/src/OneScript.StandardLibrary/Json/JSONWriter.cs @@ -33,7 +33,6 @@ public class JSONWriter : AutoContext, IDisposable private JsonTextWriter _writer; // Объект из библиотеки Newtonsoft для работы с форматом JSON StringWriter _stringWriter; - private bool _escapeNonAscii; public JSONWriter() { @@ -43,18 +42,12 @@ public JSONWriter() /// /// Возвращает true если был открыт объект для записи. /// - private bool IsOpen() - { - return _writer != null; - } + private bool IsOpen() => _writer != null; /// /// Возвращает true если текст json выводится в строку. /// - private bool IsOpenForString() - { - return _stringWriter != null; - } + private bool IsOpenForString() => _stringWriter != null; private void CheckWriter() { @@ -67,7 +60,6 @@ private void SetDefaultOptions() _writer.Indentation = INDENT_SIZE; _writer.Formatting = Formatting.Indented; _settings = new JSONWriterSettings(); - _escapeNonAscii = false; } private void SetOptions(JSONWriterSettings settings) @@ -79,11 +71,8 @@ private void SetOptions(JSONWriterSettings settings) } _settings = settings; - if (_settings.UseDoubleQuotes) - _writer.QuoteChar = '\"'; - else { - _writer.QuoteChar = '\''; - } + + _writer.QuoteChar = _settings.UseDoubleQuotes ? '"' : '\''; if (string.IsNullOrEmpty(_settings.PaddingSymbols)) { @@ -96,39 +85,9 @@ private void SetOptions(JSONWriterSettings settings) _writer.Indentation = 1; } _writer.Formatting = Formatting.Indented; - - if (_settings.EscapeCharacters != JSONCharactersEscapeModeEnum.None) - { - var jsonCharactersEscapeMode = _settings.EscapeCharacters; - if (jsonCharactersEscapeMode == JSONCharactersEscapeModeEnum.NotASCIISymbols) - { - _escapeNonAscii = true; - _writer.QuoteChar = '\"'; - _writer.StringEscapeHandling = StringEscapeHandling.EscapeNonAscii; - } - else if (jsonCharactersEscapeMode == JSONCharactersEscapeModeEnum.SymbolsNotInBMP) - throw new NotImplementedException(); - } } - void WriteStringValue(string val) - { - if (_settings.EscapeCharacters != JSONCharactersEscapeModeEnum.None && _escapeNonAscii) - { - StringWriter wr = new StringWriter(); - var jsonWriter = new JsonTextWriter(wr); - jsonWriter.QuoteChar = '\"'; - jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeNonAscii; - new JsonSerializer().Serialize(jsonWriter, val); - string str = wr.ToString(); - _writer.WriteRawValue(EscapeCharacters(str.Substring(1, str.Length - 2), false)); - - } - else - _writer.WriteRawValue(EscapeCharacters(val, _settings.EscapeSlash)); - } - - string EscapeCharacters(string sval, bool EscapeSlash) + string EscapeCharacters(string sval) { var sb = new StringBuilder(); @@ -140,7 +99,7 @@ string EscapeCharacters(string sval, bool EscapeSlash) char c = sval[i]; string escapedValue = c switch { - '/' when EscapeSlash => "\\/", + '/' when _settings.EscapeSlash => "\\/", '\'' when (_settings.EscapeSingleQuotes || !_settings.UseDoubleQuotes) => "\\u0027", '&' when _settings.EscapeAmpersand => "\\u0026", '<' when _settings.EscapeAngleBrackets => "\\u003C", @@ -154,7 +113,14 @@ string EscapeCharacters(string sval, bool EscapeSlash) '\t' => "\\t", '\"' => "\\\"", '\\' => "\\\\", - >= '\x00' and <= '\x1F' => "\\u" + ((int)c).ToString("x4"), + >= '\x00' and <= '\x1F' => "\\u" + ((int)c).ToString("X4"), + + >= '\xD800' and <= '\xDFFF' when _settings.EscapeCharacters == JSONCharactersEscapeModeEnum.SymbolsNotInBMP + => "\\u" + ((int)c).ToString("X4"), + + >= '\xFF' and <= '\xFFFF' when _settings.EscapeCharacters == JSONCharactersEscapeModeEnum.NotASCIISymbols + => "\\u" + ((int)c).ToString("X4"), + _ => null }; @@ -190,8 +156,8 @@ void SetNewLineChars(TextWriter textWriter) case JSONLineBreakEnum.Auto: textWriter.NewLine = "\r\n"; break; - default: - textWriter.NewLine = ""; //Нет + default: // JSONLineBreakEnum.None + textWriter.NewLine = ""; _writer.Formatting = Formatting.None; break; } @@ -212,15 +178,18 @@ public static JSONWriter Constructor() public IValue Settings => _settings; /// - /// Показывает, будет ли проводиться проверка правильности структуры записываемого JSON объекта. В случае обнаружение ошибки, будет сгенерировано исключение. Например: при попытке записать значение без имени вне массива или записать окончание объекта без начала. Установка данного свойства не имеет немедленного эффекта. Установленное значение свойства будет использовано только после открытия файла или установки строки. + /// Показывает, будет ли проводиться проверка правильности структуры записываемого JSON объекта. + /// В случае обнаружения ошибки, будет сгенерировано исключение. Например: при попытке записать значение без имени вне массива или записать окончание объекта без начала. + /// Установка данного свойства не имеет немедленного эффекта. Установленное значение свойства будет использовано только после открытия файла или установки строки. /// После создания объекта данное свойство имеет значение Истина. /// + /// Проверка структуры поддерживается частично. Попытка установки свойства в Ложь вызовет исключение /// Булево (Boolean) [ContextProperty("ПроверятьСтруктуру", "ValidateStructure")] public bool ValidateStructure { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } + get { return true; } + set { if(!value) throw new NotImplementedException(); } } @@ -228,6 +197,7 @@ public bool ValidateStructure /// Завершает запись текста JSON. /// Если производилась запись в строку, то метод вернет результирующую строку. /// Если производилась запись в файл, то файл закрывается, а метод вернет пустую строку. + /// Если производилась запись в поток, то поток остается открытым, а метод вернет пустую строку. /// /// Допускается повторное закрытие. Будет возвращена пустая строка. /// Строка в формате Unicode @@ -277,11 +247,11 @@ public void WriteValue(IValue value, bool useFormatWithExponent = false) var clrValue = value.UnwrapToClrObject(); switch (clrValue) { - case string v: - WriteStringValue(v); + case string v: + _writer.WriteRawValue(EscapeCharacters(v)); break; case decimal v: - if (v == Math.Round(v)) + if (v == Math.Truncate(v)) { Int64 i = Convert.ToInt64(v); if (useFormatWithExponent) @@ -482,8 +452,7 @@ protected virtual void Dispose(bool disposing) RuntimeException NotOpenException() { - return new RuntimeException(Locale.NStr - ("ru='Приемник данных JSON не открыт';en='JSON data target is not opened'")); + return new RuntimeException("Приемник данных JSON не открыт", "JSON data target is not opened"); } RuntimeException CannotWriteException() @@ -494,9 +463,8 @@ RuntimeException CannotWriteException() RuntimeException TypeNotSupportedException(Type type) { - return new RuntimeException(Locale.NStr - ($"ru='Запись значения типа {type} не поддерживается.'; en='Can not write value of type {type}'")); + return new RuntimeException($"Запись значения типа {type} не поддерживается", + $"Cannot write value of type {type}"); } - } } diff --git a/src/OneScript.StandardLibrary/Json/JSONWriterSettings.cs b/src/OneScript.StandardLibrary/Json/JSONWriterSettings.cs index 9df1e99dc..292bf3c90 100644 --- a/src/OneScript.StandardLibrary/Json/JSONWriterSettings.cs +++ b/src/OneScript.StandardLibrary/Json/JSONWriterSettings.cs @@ -11,7 +11,6 @@ This Source Code Form is subject to the terms of the namespace OneScript.StandardLibrary.Json { /// - /// /// Определяет набор параметров, используемых при записи JSON. /// [ContextClass("ПараметрыЗаписиJSON", "JSONWriterSettings")] @@ -51,10 +50,8 @@ public JSONWriterSettings(JSONLineBreakEnum NewLines = JSONLineBreakEnum.Auto, s /// - /// /// Создает объект параметров записи JSON. /// - /// /// /// Определяет способ переноса строк, который будет использован при записи данных JSON. /// Значение по умолчанию: Авто. @@ -107,11 +104,6 @@ public static JSONWriterSettings ParametrizedConstructor( escapeSlash); } - /// - /// - /// - /// - /// [ScriptConstructor] public static JSONWriterSettings Constructor() { @@ -119,7 +111,6 @@ public static JSONWriterSettings Constructor() } /// - /// /// Определяет использование двойных кавычек при записи свойств и значений JSON. /// После создания объекта данное свойство имеет значение Истина. /// @@ -129,7 +120,6 @@ public static JSONWriterSettings Constructor() /// - /// /// Управляет размещением начала и конца объектов и массивов, ключей и значений на новой строке. /// Также установка данного свойства в значение, отличное от Нет, добавляет пробел между именем свойства, двоеточием и значением. /// После создания объекта данное свойство имеет значение Авто. @@ -140,10 +130,9 @@ public static JSONWriterSettings Constructor() /// - /// /// Определяет символы отступа, используемые при записи документа JSON. /// Свойство не используется, если свойство ПереносСтрокJSON установлено в значение Нет. - /// После создания объекта данное свойство имеет значение - один пробельный символ. + /// После создания объекта данное свойство имеет значение - пустая строка. /// /// Строка (String) [ContextProperty("СимволыОтступа", "PaddingSymbols")] @@ -151,9 +140,8 @@ public static JSONWriterSettings Constructor() /// - /// /// Определяет способ экранирования символов при записи документа JSON. - /// После создания объекта данное свойство имеет значение СимволыВнеASCII. + /// После создания объекта данное свойство имеет значение Нет. /// /// ЭкранированиеСимволовJSON (JSONCharactersEscapeMode) [ContextProperty("ЭкранированиеСимволов", "EscapeCharacters")] @@ -161,7 +149,6 @@ public static JSONWriterSettings Constructor() /// - /// /// Определяет, будет ли экранироваться знак амперсанда при записи документа JSON. /// После создания объекта данное свойство имеет значение Ложь. /// @@ -171,7 +158,6 @@ public static JSONWriterSettings Constructor() /// - /// /// Определяет, будет ли экранирован знак одинарной кавычки при записи документа JSON. /// Имеет значение Истина, если ИспользоватьДвойныеКавычки установлен Ложь. /// После создания объекта данное свойство имеет значение Ложь @@ -182,7 +168,6 @@ public static JSONWriterSettings Constructor() /// - /// /// Определяет экранирование символов "U+2028" (разделитель строк) и "U+2029" (разделитель абзацев) для совместимости с JavaScript. /// После создания объекта данное свойство имеет значение Истина. /// @@ -192,7 +177,6 @@ public static JSONWriterSettings Constructor() /// - /// /// Определяет, будет ли экранироваться слеш (косая черта) при записи значения. /// После создания объекта данное свойство имеет значение Ложь. /// @@ -202,7 +186,6 @@ public static JSONWriterSettings Constructor() /// - /// /// Определяет, будут ли экранированы знаки угловых скобок при записи документа JSON. /// После создания объекта данное свойство имеет значение Ложь. /// diff --git a/tests/json/test-json_writer.os b/tests/json/test-json_writer.os index 311a3145c..d5c6bb1fd 100644 --- a/tests/json/test-json_writer.os +++ b/tests/json/test-json_writer.os @@ -12,6 +12,7 @@ СписокТестов.Добавить("Тест_Должен_ПроверитьПараметрыЗаписиJSONПоУмолчанию"); СписокТестов.Добавить("Тест_Должен_ПроверитьУстановленныеПараметрыПоУмолчанию"); СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСоСпецСимволами"); + СписокТестов.Добавить("Тест_Должен_СверитьСтрокуССимволамиВнеBMP"); СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСЭкранированнымиКириллическимиСимволами"); СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСЭкранированнымиСимволами_БезПараметров"); СписокТестов.Добавить("Тест_Должен_СверитьСтрокуСЭкранированнымиСимволами_СПараметрами"); @@ -82,7 +83,7 @@ ЗаписатьJSON(ЗаписьJSON, "Символы кириллицы"); - юТест.ПроверитьРавенство(ЗаписьJSON.Закрыть(), """\\u0421\\u0438\\u043c\\u0432\\u043e\\u043b\\u044b \\u043a\\u0438\\u0440\\u0438\\u043b\\u043b\\u0438\\u0446\\u044b"""); + юТест.ПроверитьРавенство(ЗаписьJSON.Закрыть(), """\u0421\u0438\u043C\u0432\u043E\u043B\u044B \u043A\u0438\u0440\u0438\u043B\u043B\u0438\u0446\u044B"""); КонецПроцедуры @@ -92,7 +93,18 @@ ЗаписьJSON.УстановитьСтроку(); ЗаписатьJSON(ЗаписьJSON, Символ(1) + Символ(31)); - юТест.ПроверитьРавенство(ЗаписьJSON.Закрыть(), """\u0001\u001f"""); + юТест.ПроверитьРавенство(ЗаписьJSON.Закрыть(), """\u0001\u001F"""); + +КонецПроцедуры + +Процедура Тест_Должен_СверитьСтрокуССимволамиВнеBMP() Экспорт + + ЗаписьJSON = Новый ЗаписьJSON; + Параметры = Новый ПараметрыЗаписиJSON(, , , ЭкранированиеСимволовJSON.СимволыВнеBMP); + ЗаписьJSON.УстановитьСтроку(Параметры); + + ЗаписатьJSON(ЗаписьJSON, "Ключ: "+Символ(55348)+Символ(56606)); + юТест.ПроверитьРавенство(ЗаписьJSON.Закрыть(), """Ключ: \uD834\uDD1E"""); КонецПроцедуры