<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://androman.pro/wp-content/themes/androman/assets/feed.xsl?ver=0.9.4" type="text/xsl"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Frontend &#8212; ANDROMAN.PRO</title>
	<atom:link href="https://androman.pro/category/frontend/feed/" rel="self" type="application/rss+xml" />
	<link>https://androman.pro</link>
	<description>Независимый 1С-архитектор и AI-автоматизация корпоративных процессов: аудит, PoC на реальных данных, проверка качества и внедрение. · build 0.9.4</description>
	<lastBuildDate>Tue, 05 May 2026 11:57:41 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>highlight.js для 1С: мытарства, баг и npm-пакет</title>
		<link>https://androman.pro/2026/05/02/test-1c-highlight/</link>
					<comments>https://androman.pro/2026/05/02/test-1c-highlight/#respond</comments>
		
		<dc:creator><![CDATA[Androman.pro]]></dc:creator>
		<pubDate>Fri, 01 May 2026 21:00:00 +0000</pubDate>
				<category><![CDATA[Frontend]]></category>
		<category><![CDATA[лаборатория]]></category>
		<guid isPermaLink="false">https://androman.pro/2026/05/02/test-1c-highlight/</guid>

					<description><![CDATA[Подключил highlight.js к блогу — и Функция осталась серой. КонецФункции тоже. Если/Тогда/Пока светятся, а объявление функции — нет. Пять минут разобраться «почему» превратились в несколько часов. Дизайн, не баг В hljs у языков помимо ключевых слов есть пары «открыть / закрыть блок» — то, что обозначает начало и конец именованной области кода. В грамматике 1c [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Подключил <a href="https://highlightjs.org/">highlight.js</a> к блогу — и <code>Функция</code> осталась серой. <code>КонецФункции</code> тоже. <code>Если</code>/<code>Тогда</code>/<code>Пока</code> светятся, а объявление функции — нет. Пять минут разобраться «почему» превратились в несколько часов.</p>
<h2>Дизайн, не баг</h2>
<p>В hljs у языков помимо ключевых слов есть пары «открыть / закрыть блок» — то, что обозначает начало и конец именованной области кода. В грамматике <code>1c</code> такими парами объявлены <code>Функция</code>/<code>КонецФункции</code> и <code>Процедура</code>/<code>КонецПроцедуры</code>. Они не получают класс <code>hljs-keyword</code> — им достаётся другая роль, и раскрашиваются иначе (или не раскрашиваются вовсе).</p>
<p><code>Знач</code> — модификатор параметра — просто отсутствует в списке ключевых слов грамматики. Вообще. Можно было написать пост-процессор на пять строк и закрыть тему. Но пока копался в исходниках, нашёл кое-что интереснее.</p>
<h2>Английский BSL — нулевая подсветка</h2>
<p>Грамматика <code>1c</code> для hljs написана только под русский синтаксис. Если у кого-то конфигурация с английской локализацией — <code>Function</code>, <code>EndFunction</code>, <code>If</code>, <code>Then</code> и всё остальное рендерится как простой текст. Совсем, без единого цвета.</p>
<p>Это неочевидно: большинство 1С-разработчиков работают с русским синтаксисом, и проблема просто не всплывала. Но международные команды встречаются. Значит фикс должен быть двуязычным.</p>
<h2>Что взял из atom-language-1c-bsl</h2>
<p>Нашёл <a href="https://github.com/1c-syntax/atom-language-1c-bsl">atom-language-1c-bsl</a> — грамматику для Atom от того же сообщества. Три вещи пошли прямо в патч:</p>
<p><strong>Регистронезависимость.</strong> BSL не чувствителен к регистру (<code>если = ЕСЛИ = Если</code>), а JavaScript <code>\b</code> работает только с ASCII и ломается на кириллице. Поэтому явные символьные классы для границ слов и флаг <code>gi</code> вместо просто <code>g</code>.</p>
<p><strong>Литералы.</strong> <code>Истина</code>, <code>Ложь</code>, <code>Неопределено</code> (и EN-аналоги) не получают <code>hljs-literal</code> нативно — добавил отдельным проходом.</p>
<p><strong>Аннотации.</strong> <code>&amp;НаСервере</code>, <code>&amp;AtClient</code> и подобные рендерились как обычный текст. Регулярное выражение <code>&amp;[a-zA-Zа-яёА-ЯЁ_][…]</code> закрыло это одним проходом.</p>
<h2>Баг — чей он вообще?</h2>
<p>В теме уже жил отдельный патч для подсветки обращений через точку — <code>Запрос.Текст</code>, <code>Объект.Реквизит</code>. Патч писал ИИ. Я проверил что работает — закрыл задачу.</p>
<p>Оказалось: он обходит все текстовые узлы, включая внутри строковых литералов. В тексте запроса <code>"ОстаткиИОбороты.Номенклатура"</code> — <code>Номенклатура</code> подсвечивалась как свойство объекта, хотя это просто часть строки.</p>
<p>Когда нашёл — спросил себя: а чья это недоработка? ИИ написал код с ошибкой. Но я не проверил граничный случай со строками-запросами и спокойно закрыл задачу. Нашёл до прода — уже хорошо.</p>
<p>Фикс — три строки: перед обработкой текстового узла проверять предков на класс <code>hljs-string</code>. Если есть — пропускать.</p>
<h2>Про примеры кода</h2>
<p>Демо-страница нужна была с реалистичными примерами — запрос с виртуальной таблицей, серверная процедура, HTTP. Попросил ИИ сгенерить. Подсветка сработала, выглядело хорошо — поехали.</p>
<p>Потом посмотрел внимательнее: <code>Справочники.Склады.НайтиПоНаименованию("Главный")</code>. <code>Сообщить(Выборка.Номенклатура.Наименование)</code> в цикле — отдельный запрос к БД на каждой строке. <code>ОбщегоНазначенияСервер</code> — модуля с таким именем в БСП нет. Голый <code>ПодробноеПредставлениеОшибки()</code> — устаревший глобальный метод с 8.3.17+.</p>
<p>Пришлось попросить переделать по правилам. Получилось — но не без напоминания)</p>
<hr />
<h2>Запрос с виртуальной таблицей</h2>
<pre><code class="language-1c">Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    ОстаткиИОбороты.Номенклатура КАК Номенклатура,
|    ОстаткиИОбороты.Номенклатура.Наименование КАК НоменклатураНаименование,
|    ОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,
|    ОстаткиИОбороты.КоличествоКонечныйОстаток  КАК КонечныйОстаток,
|    ОстаткиИОбороты.КоличествоПриход КАК Приход,
|    ОстаткиИОбороты.КоличествоРасход КАК Расход
|ИЗ
|    РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(
|        &amp;НачалоПериода, &amp;КонецПериода, Авто, Движения,
|        Склад = &amp;Склад) КАК ОстаткиИОбороты
|ГДЕ
|    ОстаткиИОбороты.КоличествоКонечныйОстаток &lt;&gt; 0";

Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ТекущаяДата()));
Запрос.УстановитьПараметр("КонецПериода",  КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("Склад",         Склад); // передавать ссылкой, не искать по имени

Результат = Запрос.Выполнить();
Если НЕ Результат.Пустой() Тогда
    Выборка = Результат.Выбрать();
    Пока Выборка.Следующий() Цикл
        ОбщегоНазначения.СообщитьПользователю(СтрШаблон(
            "%1, остаток: %2",
            Выборка.НоменклатураНаименование,
            Формат(Выборка.КонечныйОстаток, "ЧДЦ=3")));
    КонецЦикла;
КонецЕсли;</code></pre>
<h2>Серверная процедура с обработкой исключения</h2>
<pre><code class="language-1c">&amp;НаСервере
Процедура ПровестиДокументНаСервере(Объект, Отказ)
    Попытка
        НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Регистратор.Установить(Объект.Ссылка);

        Для Каждого СтрокаТЧ Из Объект.Товары Цикл
            Движение = НаборЗаписей.Добавить();
            Движение.ВидДвижения  = ВидДвиженияНакопления.Расход;
            Движение.Период       = Объект.Дата;
            Движение.Номенклатура = СтрокаТЧ.Номенклатура;
            Движение.Склад        = Объект.Склад;
            Движение.Количество   = СтрокаТЧ.Количество;
        КонецЦикла;

        НаборЗаписей.Записать();
    Исключение
        ОбщегоНазначения.СообщитьПользователю(
            ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),
            ,,,, Отказ);
    КонецПопытки;
КонецПроцедуры

&amp;НаСервереБезКонтекста
Функция ПолучитьОстатокНаСкладе(Номенклатура, Склад) Экспорт
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток
    |ИЗ
    |    РегистрНакопления.ТоварыНаСкладах.Остатки(
    |        , Номенклатура = &amp;Номенклатура И Склад = &amp;Склад) КАК Остатки";
    Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
    Запрос.УстановитьПараметр("Склад",        Склад);
    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        Возврат Выборка.КоличествоОстаток;
    КонецЕсли;
    Возврат 0;
КонецФункции</code></pre>
<h2>JSON-сериализация и HTTP-запрос</h2>
<pre><code class="language-1c">ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, " ", Истина);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);

Структура = Новый Структура;
Структура.Вставить("ШтрихКод",   "4607038302746");
Структура.Вставить("Количество", 5);
Структура.Вставить("Серия",      Строка(СерийныйНомер.УникальныйИдентификатор()));

ЗаписатьJSON(ЗаписьJSON, Структура);
JSONТекст = ЗаписьJSON.Закрыть();

HTTPСоединение = Новый HTTPСоединение("api.1c.ru", 443,,,, 30, Новый ЗащищенноеСоединениеOpenSSL());
HTTPЗапрос = Новый HTTPЗапрос("/v1/sync", Новый Соответствие);
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
HTTPЗапрос.УстановитьТелоИзСтроки(JSONТекст, "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);

Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Если Ответ.КодСостояния = 200 Тогда
    ЗаписьЖурналаРегистрации(
        НСтр("ru = 'Интеграция.Синхронизация'"),
        УровеньЖурналаРегистрации.Информация, , , Ответ.ПолучитьТелоКакСтроку());
Иначе
    ЗаписьЖурналаРегистрации(
        НСтр("ru = 'Интеграция.Синхронизация'"),
        УровеньЖурналаРегистрации.Ошибка, , , СтрШаблон(
            НСтр("ru = 'HTTP %1: %2'"),
            Ответ.КодСостояния,
            Ответ.ПолучитьТелоКакСтроку()));
КонецЕсли;</code></pre>
<h2>Заодно — bash, sql, json</h2>
<pre><code class="language-bash">#!/bin/bash
# Bulk-import 1C XML files into infobase
ibcmd="C:/Program Files/1cv8/8.3.27.1989/bin/ibcmd.exe"
db="F:/Bases/test"

for xml in F:/exports/*.xml; do
  echo "Importing $xml..."
  "$ibcmd" config import --db-path="$db" "$xml" || exit 1
done
echo "Done"</code></pre>
<pre><code class="language-sql">SELECT
    p.id,
    p.title,
    pm.meta_value AS reading_time,
    COUNT(c.id) AS comment_count
FROM wp_posts p
LEFT JOIN wp_postmeta pm ON pm.post_id = p.id AND pm.meta_key = '_reading_time'
LEFT JOIN wp_comments c  ON c.comment_post_ID = p.id AND c.comment_approved = '1'
WHERE p.post_status = 'publish' AND p.post_type = 'post'
GROUP BY p.id
ORDER BY p.post_date DESC
LIMIT 10;</code></pre>
<pre><code class="language-json">{
  "version": "0.6.18",
  "theme": "androman",
  "highlight": {
    "languages": ["1c", "bash", "sql", "json"],
    "theme": "github-dark",
    "version": "11.10.0"
  }
}</code></pre>
<h2>Итог</h2>
<p>Патч вышел как npm-пакет <a href="https://www.npmjs.com/package/highlightjs-1c-bsl"><code>highlightjs-1c-bsl</code></a>: три прохода — ключевые слова, литералы, аннотации. RU + EN. Регистронезависимо.</p>
<p>Живые примеры с обоими синтаксисами: <a href="https://andromanpro.github.io/highlightjs-1c-bsl/">andromanpro.github.io/highlightjs-1c-bsl</a></p>
<p>Исходники: <a href="https://github.com/andromanpro/highlightjs-1c-bsl">GitHub</a> · <a href="https://github.com/andromanpro/highlightjs-1c-bsl/blob/main/README.ru.md">README на русском</a> · <code>npm install highlightjs-1c-bsl</code></p>


<p style="margin-top:1em;font-family:monospace;font-size:0.9em;">→ <a href="https://androman.pro/2026/05/02/test-1c-highlight/">открыть на androman.pro</a></p>]]></content:encoded>
					
					<wfw:commentRss>https://androman.pro/2026/05/02/test-1c-highlight/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
