Claude Skill

1c-bsp-api

Справочник программного интерфейса Библиотеки стандартных подсистем (БСП) 1С - какие общие модули существуют, какие у них экспортные методы, сигнатуры, типы параметров, контексты выполнения и переопределяемые обработчики. Используй когда пишешь код на конфигурации с БСП и нужно у

LLM Mart · 0 points · 12 views 30 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download Desko77-claude-code-skills-1c-skills_1c-bsp-api-ac33656.zip · 183 KB
Part of desko77/claude-code-skills-1c — 48 skills

Install

skills CLI npx skills add https://github.com/Desko77/claude-code-skills-1c/tree/main/skills/1c-bsp-api
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install desko77-claude-code-skills-1c@llmmart
Git git clone https://github.com/Desko77/claude-code-skills-1c.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole desko77/claude-code-skills-1c collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Справочник API БСП

Офлайн-справочник по программному интерфейсу БСП: 2624 метода в 284 модулях, 71 подсистема, версии 3.1.11 и 3.2.1. Собран из двух источников одновременно - структура и сигнатуры из документации, модули и экспортность из самой библиотеки. Каждая версия документации сведена со своим дистрибутивом, поэтому различия между версиями видны, а не усреднены.

Назначение написано нами: одна строка у каждого из 284 модулей и у 440 методов ядра. Описательный текст документации ИТС в справочник не переносится.

Справочник больше мегабайта, в контекст целиком не грузится. Он спрашивается по месту.

Главное правило

Не пиши вызов метода БСП, не проверив его. Имена в БСП длинные и составные, поэтому правдоподобная выдумка выглядит как настоящее имя. Классические несуществующие: ФайловаяСистемаКлиентСервер, JSONСтрокой, Пользователи.СсылкаТекущегоПользователя.

python skills/1c-bsp-api/scripts/bsp-api.py check ФайловаяСистемаКлиентСервер.ПолучитьФайл

Код возврата 1, если вызова нет. При промахе инструмент подсказывает похожие имена - и по модулю, и по методу.

Как устроена библиотека

Суффикс имени модуля - это контекст выполнения, а не тематика. Один механизм разложен по нескольким модулям, и выбор между ними определяется тем, откуда идет вызов:

Суффикс Где исполняется Пример
без суффикса или Сервер сервер, толстый клиент, внешнее соединение ОбщегоНазначения
Клиент тонкий и толстый клиент ОбщегоНазначенияКлиент
КлиентСервер и там, и там ОбщегоНазначенияКлиентСервер
ВызовСервера сервер, вызывается с клиента напрямую ОбщегоНазначенияВызовСервера

Отсюда частая ошибка: серверный метод вызывают из клиентского кода. Контекст каждого метода есть в справочнике, отбор - ключом --av (S сервер, T тонкий, F толстый, E внешнее соединение, C вызов сервера).

Три вида модулей по назначению:

  • Обычные - публичный интерфейс, их и вызывают: ОбщегоНазначения, Пользователи, УправлениеПечатью.
  • Переопределяемый - точки расширения. Их не вызывают, в них ПИШУТ: обработчик вызывает библиотека, а тело пишет внедряющая конфигурация. Таких методов 372.
  • Служебный - внутренняя реализация библиотеки. В программный интерфейс не входит ни один служебный метод, и вызывать их нельзя: они меняются между версиями без объявления.

Еще два суффикса встречаются реже: ПовтИсп - модуль с повторным использованием возвращаемых значений, Локализация - национальная специфика.

Часть интерфейса объявлена не в общих модулях. Обмен данными опубликован модулями объектов обработок (Обработка.УниверсальныйОбменДаннымиXML, Обработка.КонвертацияОбъектовXDTO). В справочнике они есть наравне с общими модулями.

Запросы

B=skills/1c-bsp-api/scripts/bsp-api.py

python $B find печать                      # поиск по имени, модулю, подсистеме, назначению
python $B find "реквизит объект"           # ищутся все слова запроса сразу, не подстрока
python $B find файл --av T                 # только то, что доступно на тонком клиенте
python $B show ОбщегоНазначения.ЗначениеРеквизитаОбъекта   # карточка метода
python $B show ЗначениеРеквизитаОбъекта    # все модули, где есть метод с таким именем
python $B module Пользователи              # состав модуля целиком
python $B modules контакт                  # какие вообще есть модули
python $B subsystem печать                 # модули и механизмы подсистемы
python $B overrides обновлен               # переопределяемые обработчики под задачу
python $B check Пользователи.ТекущийПользователь
python $B stats                            # что вообще в справочнике

Общие ключи отбора: --av, --sub <подсистема>, --version 3.2.1, --limit N.

Как читать выдачу

Строка вида ОбщегоНазначения.ЗначениеРеквизитаОбъекта SFE - это модуль, метод и контексты.

Пометка [?] означает, что модуль выведен, а не подтвержден. Документация БСП называет механизм, а не модуль, поэтому у части методов модуль восстановлен по примеру вызова или по совпадению контекстов. В карточке (show) последняя строка всегда говорит, откуда взято имя модуля. Метод с пометкой перед использованием стоит сверить с конфигурацией проекта.

Пометка стоит у 117 методов из 2624, это около четырех процентов. Еще у 37 модуль определить не удалось вовсе - они собраны под именем ?. Это не значит, что метода нет: значит, одно и то же имя объявлено в нескольких модулях, и документация не говорит, о каком из них статья.

Пометка [!] означает, что между версиями метод изменился. Карточка тогда содержит строку "ВНИМАНИЕ, в <версия> иначе" с прежней сигнатурой. Таких методов 27, и часть изменений ломающие: ОбщегоНазначения.ВыполнитьМетодКонфигурации из процедуры стал функцией, а у ДобавитьПоказатель новый параметр вставлен не в конец, а первым. Код, написанный по новой сигнатуре, на старой версии передаст аргументы не туда и об этом не сообщит.

Частые ошибки

  • Выдуманный модуль. Проверять check, а не полагаться на память.
  • Серверный метод в клиентском коде. Смотреть контексты; для клиента почти всегда есть парный модуль с суффиксом Клиент.
  • Вызов служебного модуля. Если в имени есть Служебный - это не интерфейс.
  • Попытка вызвать переопределяемый обработчик. В него пишут тело, а не вызывают его.
  • Метод из другой версии. У каждой записи указано, в каких версиях БСП она есть. Метод, помеченный только 3.2.1, на 3.1.11 не существует. А метод с пометкой [!] существует в обеих, но вызывается по-разному - смотреть карточку до того, как писать вызов.
  • Расчет на то, что у метода тот же набор параметров, что был раньше. Сигнатура в справочнике полная, включая значения по умолчанию - брать оттуда.

Границы

Справочник знает ИМЕНА, СИГНАТУРЫ и КОНТЕКСТЫ, а назначение - строкой, написанной нами. Развернутого описания в нем нет: текст документации ИТС лицензионный и сюда не переносится. Строка назначения есть у каждого модуля, но у методов пока только у ядра - базовых модулей ОбщегоНазначения*, длительных операций, пользователей, строковых функций, файловой системы и журнала регистрации. Когда нужно понять механизм глубже, а не форму вызова - идти в документацию ИТС по подсистеме, которую покажет subsystem.

Не покрыты: HTTP-сервисы и веб-сервисы библиотеки, макеты, роли, права, состав метаданных подсистем. Только программный интерфейс кода.

Сборка справочника

Готовый справочник лежит в references/bsp-api.jsonl и обновлять его нужно только при переходе на новую версию БСП. Пересборка требует двух источников, оба лицензионные и в репозиторий не входят: скрапа документации с ИТС и дистрибутива библиотеки.

python -m v8unpack -E 1Cv8.cf E:\bsp\3_2_1 --temp E:\bsp\_tmp     # распаковать дистрибутив
python skills/1c-bsp-api/scripts/bsp-build.py \
    --docs "3.1.11=E:\scrape\bsp3111doc" --docs "3.2.1=E:\scrape\bsp321doc" \
    --lib "3.1.11=E:\bsp\3_1_11" --lib "3.2.1=E:\bsp\3_2_1" \
    --purposes skills/1c-bsp-api/references/purposes.json \
    --out skills/1c-bsp-api/references/bsp-api.jsonl \
    --map skills/1c-bsp-api/references/subsystem-map.md

Формулировки назначения ведутся отдельно, в references/purposes.json: раздел modules и раздел methods с ключами вида Модуль.Метод. При сборке они подмешиваются в справочник, а имена, которых в нем нет, генератор называет в отчете - это ловит и опечатку, и формулировку к методу, которого в этой версии уже не существует.

Ключи --docs и --lib указываются по одному на версию и связываются префиксом. Связывать обязательно: если сшивать документацию 3.1.11 с библиотекой 3.2.1, методы, убранные в новой версии, будут объявлены несуществующими. Библиотека без префикса версии берется для всех.

Брать надо 1Cv8.cf - чистую библиотеку, а не 1Cv8_demo.cf: демонстрационная конфигурация несет объекты, которых в поставке нет. Распаковка идет без платформы и Конфигуратора.

Скрипты на Python, PowerShell-порта нет: сборка нужна редко, а поиск идет по готовому файлу.

Files (claude-code-skills-1c)
  • evals
    • evals.json 6 KB
      {
        "skill_name": "1c-bsp-api",
        "_": "Поведенческие кейсы. Гоняются через tools/run_skill_evals.py: фаза RED без скила, фаза GREEN со скилом. Поля expect и forbid - регулярные выражения по тексту ответа, checks_bsl включает сверку вызовов в блоках BSL с офлайн-справочником БСП. Все имена модулей и методов в кейсах проверены по самому справочнику.",
        "evals": [
          {
            "id": "invented-module-refused",
            "prompt": "На конфигурации с БСП мне нужно получить файл с диска. Коллега советует вызвать ФайловаяСистемаКлиентСервер.ПолучитьФайл. Напиши, как это правильно сделать, и покажи код на BSL.",
            "expected_output": "Агент сообщает, что общего модуля ФайловаяСистемаКлиентСервер в БСП нет, вместо выдумывания сигнатуры несуществующего метода.",
            "expectations": [
              "Прямо сказано, что модуля ФайловаяСистемаКлиентСервер не существует",
              "Не приведена выдуманная сигнатура ПолучитьФайл у этого модуля"
            ],
            "expect": [
              "ФайловаяСистемаКлиентСервер"
            ],
            "forbid": [
              "ФайловаяСистемаКлиентСервер\\s*\\.\\s*ПолучитьФайл\\s*\\("
            ],
            "checks_bsl": true
          },
          {
            "id": "current-user-thin-client",
            "prompt": "Напиши обработчик команды формы на BSL: в клиентской процедуре с директивой НаКлиенте нужно показать имя текущего пользователя. Конфигурация с БСП, работаем в тонком клиенте.",
            "expected_output": "Использован ПользователиКлиент.ТекущийПользователь, доступный на тонком клиенте, а не серверный модуль Пользователи.",
            "expectations": [
              "Клиентский код обращается к модулю с суффиксом Клиент",
              "Серверный модуль Пользователи не вызывается напрямую из НаКлиенте"
            ],
            "expect": [
              "ПользователиКлиент\\s*\\.\\s*ТекущийПользователь"
            ],
            "checks_bsl": true
          },
          {
            "id": "overridable-is-implemented-not-called",
            "prompt": "На конфигурации с БСП нужно выполнить свой код сразу после обновления информационной базы на новую версию. Покажи на BSL, куда его поместить.",
            "expected_output": "Указан переопределяемый обработчик ОбновлениеИнформационнойБазыПереопределяемый.ПослеОбновленияИнформационнойБазы как точка реализации, а не как вызов из прикладного кода.",
            "expectations": [
              "Назван модуль ОбновлениеИнформационнойБазыПереопределяемый",
              "Сказано, что обработчик реализуют, а не вызывают"
            ],
            "expect": [
              "ОбновлениеИнформационнойБазыПереопределяемый"
            ],
            "checks_bsl": true
          },
          {
            "id": "message-bound-to-field",
            "prompt": "Напиши на BSL серверную проверку заполнения реквизита Контрагент в модуле объекта документа. Если реквизит пуст, покажи пользователю сообщение, привязанное к полю, и установи Отказ. Конфигурация с БСП.",
            "expected_output": "Использован ОбщегоНазначения.СообщитьПользователю с привязкой к полю и параметром Отказ, а не конструктор платформы.",
            "expectations": [
              "Вызван ОбщегоНазначения.СообщитьПользователю",
              "Передано поле и Отказ",
              "Не использован Новый СообщениеПользователю"
            ],
            "expect": [
              "ОбщегоНазначения\\s*\\.\\s*СообщитьПользователю\\s*\\(",
              "Отказ"
            ],
            "forbid": [
              "Новый\\s+СообщениеПользователю"
            ],
            "checks_bsl": true
          },
          {
            "id": "invented-current-user-property",
            "prompt": "Конфигурация с БСП. Нужна ссылка на элемент справочника Пользователи для текущего сеанса на сервере. Покажи вызов на BSL.",
            "expected_output": "Использована функция Пользователи.ТекущийПользователь. Несуществующая Пользователи.СсылкаТекущегоПользователя не появляется.",
            "expectations": [
              "Вызвана существующая функция модуля Пользователи",
              "Не выдумано имя СсылкаТекущегоПользователя"
            ],
            "expect": [
              "Пользователи\\s*\\.\\s*ТекущийПользователь"
            ],
            "forbid": [
              "СсылкаТекущегоПользователя"
            ],
            "checks_bsl": true
          }
        ]
      }
      
  • references
    • bsp-api.jsonl 1.7 MB · in bundle
    • purposes.json 141.6 KB
      {
        "_": "Формулировки назначения своими словами. Единственная часть справочника, написанная нами, а не выведенная из источников. Раздел modules отвечает на вопрос куда идти, раздел methods - что взять.",
        "modules": {
          "?": "Метод документирован, но однозначно определить его модуль не удалось: одно и то же имя объявлено в нескольких модулях. Смотреть подсистему и механизм в карточке",
          "АвтономнаяРабота": "Автономное рабочее место: работа без постоянной связи с основной базой и синхронизация при подключении",
          "АдминистрированиеКластера": "Управление кластером серверов из кода: сеансы и соединения информационной базы, блокировка сеансов и регламентных заданий, профили безопасности",
          "АдресныйКлассификатор": "Государственный адресный реестр: загруженные регионы, поиск адресных объектов, коды и наименования, проверка адреса по классификатору",
          "АдресныйКлассификаторКлиент": "Клиентская часть адресного классификатора: загрузка и выбор адресных объектов",
          "БизнесПроцессыИЗадачиКлиент": "Клиентская часть бизнес-процессов и задач: команды работы с процессами и задачами на форме",
          "БизнесПроцессыИЗадачиКлиентПереопределяемый": "Клиентская точка расширения бизнес-процессов",
          "БизнесПроцессыИЗадачиКлиентСервер": "Общие правила работы с бизнес-процессами и задачами",
          "БизнесПроцессыИЗадачиПереопределяемый": "Точка расширения бизнес-процессов: свои объекты адресации, свои правила заполнения задач",
          "БизнесПроцессыИЗадачиСервер": "Бизнес-процессы и задачи: создание и старт процессов, адресация и исполнители задач, отложенный старт, выполнение задач",
          "БлокировкаРаботыСВнешнимиРесурсамиПереопределяемый": "Точка расширения блокировки работы с внешними ресурсами в копии базы",
          "ВариантыОтчетов": "Варианты отчетов и их размещение в интерфейсе: регистрация вариантов, настройка размещения по подсистемам, пользовательские варианты",
          "ВариантыОтчетовКлиент": "Клиентская часть вариантов отчетов: открытие и настройка варианта",
          "ВариантыОтчетовКлиентСервер": "Общие имена и правила работы с вариантами отчетов",
          "ВариантыОтчетовПереопределяемый": "Точка расширения вариантов отчетов: свои варианты и их размещение",
          "ВерсионированиеОбъектов": "История изменений объектов: хранение версий, сравнение версий, отчет по изменениям",
          "ВерсионированиеОбъектовКлиент": "Клиентская часть версионирования: открытие истории изменений объекта",
          "ВерсионированиеОбъектовПереопределяемый": "Точка расширения версионирования: какие объекты версионировать и как",
          "ВерсионированиеОбъектовСобытия": "Обработчики подписок на события, записывающие версию объекта при изменении",
          "Взаимодействия": "Письма, звонки, встречи и планируемые взаимодействия с контактами",
          "ВзаимодействияКлиент": "Клиентская часть взаимодействий: создание и просмотр писем, звонков и встреч",
          "ВзаимодействияКлиентСервер": "Общие правила работы с взаимодействиями",
          "ВзаимодействияКлиентСерверПереопределяемый": "Точка расширения взаимодействий, общая для клиента и сервера",
          "ВзаимодействияЛокализация": "Национальная специфика взаимодействий",
          "ВзаимодействияПереопределяемый": "Точка расширения взаимодействий: свои виды контактов",
          "ВнешниеКомпонентыКлиент": "Подключение и установка внешних компонент на рабочем месте",
          "ВнешниеКомпонентыКлиентЛокализация": "Национальная специфика внешних компонент на клиенте",
          "ВнешниеКомпонентыСервер": "Хранение и выдача внешних компонент с сервера",
          "ВнешниеПользователи": "Внешние пользователи - контрагенты, партнеры, физические лица, работающие в программе через отдельный вид учетных записей",
          "ВнешниеПользователиКлиент": "Клиентская часть работы с внешними пользователями",
          "ВыгрузкаОбъектовВФайлы": "Выгрузка объектов конфигурации в файлы для последующей загрузки",
          "ГенерацияШтрихкода": "Формирование изображений штрихкодов и QR-кодов",
          "ГрафикиРаботы": "Графики работы организации: рабочее время по дням, расчет длительности с учетом графика",
          "ГрупповоеИзменениеОбъектовКлиент": "Клиентская часть группового изменения объектов",
          "ГрупповоеИзменениеОбъектовПереопределяемый": "Точка расширения группового изменения: какие объекты и реквизиты доступны",
          "ДатыЗапретаИзменения": "Запрет изменения данных до указанной даты: проверка при записи, разделы и объекты запрета",
          "ДатыЗапретаИзмененияПереопределяемый": "Точка расширения дат запрета: свои разделы запрета",
          "ДлительныеОперации": "Выполнение долгих действий в фоновом задании: запуск процедуры или функции в фоне, ожидание результата, сообщение о ходе выполнения, выполнение в несколько потоков",
          "ДлительныеОперацииКлиент": "Клиентская часть длительных операций: ожидание завершения фонового задания и показ хода выполнения пользователю",
          "ДополнительныеОтчетыИОбработки": "Дополнительные отчеты и обработки, подключаемые пользователем: регистрация, права, назначение объектам, запуск",
          "ДополнительныеОтчетыИОбработкиКлиент": "Клиентская часть дополнительных отчетов и обработок: выполнение команд",
          "ДополнительныеОтчетыИОбработкиКлиентПереопределяемый": "Клиентская точка расширения дополнительных отчетов и обработок",
          "ДополнительныеОтчетыИОбработкиКлиентСервер": "Общие имена видов, типов команд и форм для дополнительных отчетов и обработок",
          "ДополнительныеОтчетыИОбработкиПереопределяемый": "Точка расширения дополнительных отчетов и обработок",
          "ЖурналРегистрации": "Запись событий в журнал регистрации и чтение журнала на сервере",
          "ЖурналРегистрацииКлиент": "Запись клиентских событий в журнал регистрации",
          "ЗагрузкаДанныхИзФайла": "Загрузка табличных данных из файла в объекты конфигурации: разбор, сопоставление колонок, запись",
          "ЗагрузкаДанныхИзФайлаКлиент": "Клиентская часть загрузки данных из файла",
          "ЗагрузкаДанныхИзФайлаКлиентСервер": "Общие правила разбора загружаемых данных",
          "ЗагрузкаДанныхИзФайлаПереопределяемый": "Точка расширения загрузки из файла: свои объекты-приемники",
          "ЗаметкиПользователя": "Личные заметки пользователя к объектам и разделам",
          "ЗаполнениеОбъектовПереопределяемый": "Точка расширения команд заполнения объектов",
          "ЗапретРедактированияРеквизитовОбъектов": "Запрет правки ключевых реквизитов после проведения или использования объекта",
          "ЗапретРедактированияРеквизитовОбъектовКлиент": "Клиентская часть запрета редактирования реквизитов: разблокировка на форме",
          "ЗапретРедактированияРеквизитовОбъектовПереопределяемый": "Точка расширения запрета редактирования: свои запрещенные реквизиты",
          "ЗащитаПерсональныхДанных": "Учет доступа к персональным данным и их уничтожение: журнал событий доступа, встраивание в формы объектов",
          "ЗащитаПерсональныхДанныхКлиент": "Клиентская часть защиты персональных данных",
          "ЗащитаПерсональныхДанныхПереопределяемый": "Точка расширения защиты персональных данных: свои объекты с персональными данными",
          "ЗаявлениеНаСертификатПереопределяемый": "Точка расширения заявлений на выпуск сертификата",
          "ИнтеграцияПодсистемБСП": "Связывает подсистемы БСП между собой и с встраивающей конфигурацией: объявление состава подсистем и условные вызовы между ними",
          "ИнтерфейсODataПереопределяемый": "Точка расширения интерфейса OData: состав публикуемых объектов",
          "ИнформацияПриЗапускеПереопределяемый": "Точка расширения информационных сообщений при запуске программы",
          "КалендарныеГрафики": "Производственный календарь и календарные графики: рабочие и нерабочие дни, сдвиг даты на рабочие дни, ближайшая рабочая дата",
          "КалендарныеГрафикиЛокализация": "Национальная специфика производственного календаря",
          "КалендарныеГрафикиПереопределяемый": "Точка расширения календарных графиков: свои производственные календари",
          "КонструкторФормул": "Конструктор выражений над данными объекта: сбор доступных полей, проверка и вычисление формулы",
          "КонструкторФормулКлиент": "Клиентская часть конструктора формул: открытие конструктора и правка выражения",
          "КонтрольВеденияУчета": "Проверки корректности данных: запуск проверок, регистрация проблем, отчет по найденным проблемам",
          "КонтрольВеденияУчетаКлиент": "Клиентская часть контроля ведения учета: открытие отчета по проблемам",
          "КонтрольВеденияУчетаПереопределяемый": "Точка расширения контроля учета: свои виды проверок",
          "КонтрольРаботыПользователей": "Отчеты о действиях пользователей по данным журнала регистрации",
          "МашиночитаемыеДоверенностиФНС": "Машиночитаемые доверенности ФНС: формирование, подписание, регистрация и проверка",
          "МашиночитаемыеДоверенностиФНСКлиент": "Клиентская часть машиночитаемых доверенностей",
          "МашиночитаемыеДоверенностиФНСКлиентПереопределяемый": "Клиентская точка расширения машиночитаемых доверенностей",
          "МашиночитаемыеДоверенностиФНСПереопределяемый": "Точка расширения машиночитаемых доверенностей",
          "МультиязычностьКлиент": "Клиентская часть многоязычности",
          "МультиязычностьКлиентСервер": "Общие правила работы с многоязычными данными на клиенте и сервере",
          "МультиязычностьПереопределяемый": "Точка расширения многоязычности: свои языки и свои многоязычные реквизиты",
          "МультиязычностьСервер": "Многоязычные данные: реквизиты на разных языках, подстановка языка в запросы и представления",
          "НапоминанияПользователя": "Напоминания пользователю о событиях и объектах: создание, перенос, отключение",
          "НапоминанияПользователяКлиент": "Клиентская часть напоминаний: показ и откладывание напоминания",
          "НапоминанияПользователяКлиентСервер": "Общие правила расчета времени напоминания",
          "НапоминанияПользователяПереопределяемый": "Точка расширения напоминаний: свои источники событий",
          "НастройкаПорядкаЭлементов": "Ручной порядок элементов в списках: перемещение вверх и вниз, реквизит упорядочивания",
          "НастройкиПрограммыПереопределяемый": "Точка расширения формы настроек программы: свои разделы и элементы настроек",
          "ОбменДаннымиXDTOСервер": "Универсальный формат обмена: отправка и получение данных, инициализация обмена, поиск правил конвертации, протокол",
          "ОбменДаннымиВМоделиСервиса": "Обмен данными в модели сервиса: особенности синхронизации между областями данных",
          "ОбменДаннымиВМоделиСервисаПереопределяемый": "Точка расширения обмена в модели сервиса",
          "ОбменДаннымиВнешнееСоединение": "Обмен через внешнее соединение с другой информационной базой",
          "ОбменДаннымиВызовСервера": "Функции обмена данными, вызываемые с клиента напрямую",
          "ОбменДаннымиКлиент": "Клиентская часть синхронизации данных: команды запуска обмена и просмотра результатов",
          "ОбменДаннымиПереопределяемый": "Точка расширения обмена данными: свои планы обмена, свои правила регистрации и конвертации",
          "ОбменДаннымиРегистрацияСервер": "Регистрация изменений объектов для узлов обмена на стороне сервера",
          "ОбменДаннымиСервер": "Синхронизация данных между информационными базами: настройки узлов и подключений, запуск и мониторинг обмена, регистрация изменений",
          "ОбменДаннымиСобытия": "Обработчики событий правил регистрации и конвертации при обмене данными",
          "ОбновлениеИнформационнойБазы": "Механизм обновления данных при переходе на новую версию: регистрация обработчиков обновления, порционная обработка ссылок и наборов записей, отложенное обновление, отметки об обработанных данных, начальное заполнение",
          "ОбновлениеИнформационнойБазыКлиентПереопределяемый": "Клиентские точки расширения обновления: что показать пользователю до и после перехода на новую версию",
          "ОбновлениеИнформационнойБазыПереопределяемый": "Точка расширения обновления: здесь конфигурация объявляет свои обработчики обновления и порядок их выполнения",
          "ОбновлениеКонфигурации": "Обновление конфигурации из файла или с сервиса обновлений",
          "ОбновлениеКонфигурацииКлиент": "Клиентская часть обновления конфигурации: помощник и перезапуск",
          "Обработка.КонвертацияОбъектовXDTO (модуль объекта)": "Конвертация объектов по правилам формата XDTO при обмене данными",
          "Обработка.КонвертацияОбъектовИнформационныхБаз (модуль объекта)": "Конвертация объектов при обмене между информационными базами: выгрузка, загрузка, правила",
          "Обработка.РегистрацияИзмененийДляОбменаДанными (модуль объекта)": "Регистрация и снятие регистрации изменений объектов для узлов обмена",
          "Обработка.ТранспортСообщенийОбменаESB1C (модуль менеджера)": "Транспорт сообщений обмена через шину 1С:Шина",
          "Обработка.УниверсальныйОбменДаннымиXML (модуль объекта)": "Универсальный обмен данными XML: выгрузка и загрузка по правилам обмена, разбор сообщения, счетчики и протокол. В дистрибутиве 3.2.1 обработки уже нет",
          "Обсуждения": "Обсуждения и сообщения через систему взаимодействия",
          "ОбсужденияКлиент": "Клиентская часть обсуждений",
          "ОбсужденияЛокализация": "Национальная специфика обсуждений",
          "ОбщегоНазначения": "Базовый серверный модуль библиотеки: чтение реквизитов объектов без чтения самих объектов, работа с метаданными и ссылками, свойства сеанса и окружения, выполнение стороннего кода в безопасном режиме, хранилища настроек, обращения в интернет",
          "ОбщегоНазначенияКлиент": "Базовые клиентские операции: свойства сеанса на стороне клиента, оповещения об изменении объектов, подключение внешних компонент, типовые диалоги подтверждения и правки текста, резервное копирование",
          "ОбщегоНазначенияКлиентПереопределяемый": "Клиентские точки расширения ядра: свои действия при старте и завершении работы, обработка навигационных ссылок",
          "ОбщегоНазначенияКлиентСервер": "Базовые операции, доступные и на клиенте: коллекции и структуры, разбор и сборка путей и имен файлов, отборы динамических списков, сообщения пользователю, проверка адресов электронной почты",
          "ОбщегоНазначенияПереопределяемый": "Точки расширения ядра: подключение своих подсистем к общим механизмам, свои параметры работы программы, переименования объектов метаданных при обновлении",
          "ОрганизацииПереопределяемый": "Точка расширения организаций: свои источники сведений об организации",
          "ОрганизацииСервер": "Сведения об организациях: реквизиты, ответственные лица, обособленные подразделения, индивидуальные предприниматели",
          "ОтправкаSMS": "Отправка SMS через настроенного оператора: текст, получатели, статус доставки",
          "ОтправкаSMSКлиент": "Клиентская часть отправки SMS",
          "ОтправкаSMSКлиентПереопределяемый": "Клиентская точка расширения отправки SMS",
          "ОтправкаSMSПереопределяемый": "Точка расширения отправки SMS: свой оператор",
          "ОтчетОДвиженияхДокументаПереопределяемый": "Точка расширения отчета о движениях документа",
          "ОтчетыКлиент": "Клиентская часть общих механизмов отчетов",
          "ОтчетыКлиентПереопределяемый": "Клиентская точка расширения форм отчетов",
          "ОтчетыКлиентСервер": "Общие для клиента и сервера правила работы с настройками отчетов",
          "ОтчетыПереопределяемый": "Точка расширения общих механизмов отчетов",
          "ОтчетыСервер": "Общие механизмы отчетов: настройки компоновки, параметры формирования, расширения форм отчетов",
          "ОценкаПроизводительности": "Замеры времени ключевых операций и выгрузка результатов для анализа",
          "ОценкаПроизводительностиКлиент": "Клиентская часть замеров: начало и завершение замера ключевой операции",
          "ПереводТекстаНаДругиеЯзыки": "Перевод текста через внешний сервис перевода",
          "ПереводТекстаНаДругиеЯзыкиЛокализация": "Национальная специфика перевода текста",
          "ПодключаемыеКоманды": "Команды, добавляемые к формам объектов другими подсистемами: сбор состава команд и их размещение",
          "ПодключаемыеКомандыКлиент": "Клиентская часть подключаемых команд: выполнение команды на форме",
          "ПодключаемыеКомандыКлиентСервер": "Общие правила работы с подключаемыми командами",
          "ПодключаемыеКомандыПереопределяемый": "Точка расширения подключаемых команд: свои команды для форм объектов",
          "ПодсистемыКонфигурацииПереопределяемый": "Точка расширения списка подсистем конфигурации, видимых библиотеке",
          "ПоискИУдалениеДублей": "Поиск дублей элементов справочников и их замена на выбранный оригинал",
          "ПоискИУдалениеДублейКлиент": "Клиентская часть поиска дублей",
          "ПоискИУдалениеДублейПереопределяемый": "Точка расширения поиска дублей: свои правила сравнения",
          "ПолнотекстовыйПоискКлиент": "Клиентская часть полнотекстового поиска",
          "ПолнотекстовыйПоискСервер": "Полнотекстовый поиск по данным: обновление индекса и выполнение поиска",
          "ПолнотекстовыйПоискСерверПереопределяемый": "Точка расширения полнотекстового поиска",
          "ПолучениеФайловИзИнтернета": "Загрузка файлов по HTTP и FTP: прокси, таймауты, проверка доступности ресурса",
          "ПолучениеФайловИзИнтернетаКлиент": "Клиентская часть загрузки файлов из интернета",
          "ПолучениеФайловИзИнтернетаКлиентСервер": "Общие для клиента и сервера параметры загрузки файлов из интернета",
          "ПолучениеФайловИзИнтернетаЛокализация": "Национальная специфика загрузки файлов из интернета",
          "Пользователи": "Пользователи программы и пользователи информационной базы: текущий пользователь, права и роли, полнота прав, служебные пользователи, связь элемента справочника с учетной записью ИБ",
          "ПользователиКлиент": "Клиентская часть работы с пользователями: сведения о текущем пользователе на клиенте",
          "ПользователиПереопределяемый": "Точка расширения подсистемы пользователей: свои роли, свои действия при создании и изменении пользователя",
          "ПрефиксацияОбъектовКлиентСервер": "Разбор и сборка номеров с префиксом на клиенте и сервере",
          "ПрефиксацияОбъектовКлиентСерверПереопределяемый": "Точка расширения префиксации: свои правила формирования номера",
          "ПрефиксацияОбъектовПереопределяемый": "Точка расширения префиксации: свои правила формирования префикса",
          "ПрефиксацияОбъектовСобытия": "Обработчики подписок на события, подставляющие префикс в номер или код объекта при записи",
          "ПроверкаЛегальностиПолученияОбновленияКлиент": "Клиентская часть проверки легальности получения обновления",
          "ПроверкаЛегальностиПолученияОбновленияПереопределяемый": "Точка расширения проверки легальности обновления",
          "РаботаВБезопасномРежиме": "Профили безопасности: запросы на использование внешних ресурсов - файлов, интернета, COM, внешних компонент, - и выполнение кода с этими разрешениями",
          "РаботаВБезопасномРежимеКлиент": "Клиентская часть профилей безопасности: интерактивное подтверждение запросов на внешние ресурсы",
          "РаботаВБезопасномРежимеКлиентПереопределяемый": "Клиентская точка расширения профилей безопасности",
          "РаботаВБезопасномРежимеПереопределяемый": "Точка расширения профилей безопасности: свои разрешения на внешние ресурсы",
          "РаботаВМоделиСервисаБСП": "Особенности работы библиотеки в модели сервиса: разделение данных и области",
          "РаботаСАдресами": "Разбор и сборка адресов: представление адреса, его поля, соответствие структуре адреса РФ",
          "РаботаСАдресамиКлиентСервер": "Общие для клиента и сервера правила работы со структурой адреса",
          "РаботаСБанками": "Классификатор банков: поиск по БИК и корсчету, загрузка классификатора",
          "РаботаСБанкамиКлиент": "Клиентская часть работы с классификатором банков",
          "РаботаСБанкамиПереопределяемый": "Точка расширения классификатора банков",
          "РаботаСКурсамиВалют": "Курсы валют: загрузка с сервиса, пересчет сумм, курс на дату",
          "РаботаСКурсамиВалютКлиентЛокализация": "Национальная специфика курсов валют на клиенте",
          "РаботаСКурсамиВалютКлиентСервер": "Пересчет сумм по курсу на клиенте и сервере",
          "РаботаСКурсамиВалютЛокализация": "Национальная специфика загрузки и применения курсов валют",
          "РаботаСКурсамиВалютПереопределяемый": "Точка расширения курсов валют: свой источник курсов",
          "РаботаСПочтовымиСообщениями": "Отправка и получение электронной почты: учетные записи, отправка писем, загрузка входящих",
          "РаботаСПочтовымиСообщениямиКлиент": "Клиентская часть работы с почтой: формы отправки писем",
          "РаботаСПочтовымиСообщениямиКлиентПереопределяемый": "Клиентская точка расширения работы с почтой",
          "РаботаСПочтовымиСообщениямиЛокализация": "Национальная специфика работы с почтой",
          "РаботаСПочтовымиСообщениямиПереопределяемый": "Точка расширения работы с почтой",
          "РаботаСФайлами": "Присоединенные файлы объектов: создание, чтение, изменение и версии файлов, хранение в базе или на диске, блокировка на редактирование",
          "РаботаСФайламиКлиент": "Клиентская часть работы с присоединенными файлами: команды открытия и редактирования, сканирование, обмен файлами с рабочим местом",
          "РаботаСФайламиКлиентПереопределяемый": "Клиентская точка расширения работы с присоединенными файлами",
          "РаботаСФайламиКлиентСервер": "Общие для клиента и сервера правила работы с присоединенными файлами: разбор имен, проверка расширений, параметры сканирования",
          "РаботаСФайламиЛокализация": "Национальная специфика работы с присоединенными файлами",
          "РаботаСФайламиПереопределяемый": "Точка расширения присоединенных файлов: свои правила хранения и обработки файлов объектов",
          "РассылкаОтчетов": "Рассылка отчетов по расписанию: состав рассылки, получатели, формирование и отправка",
          "РассылкаОтчетовКлиентПереопределяемый": "Клиентская точка расширения рассылки отчетов",
          "РассылкаОтчетовПереопределяемый": "Точка расширения рассылки отчетов",
          "РегистрСведений.НеудаленныеОбъекты (модуль менеджера)": "Объекты, которые не удалось удалить из-за ссылок на них",
          "РегистрСведений.СнимкиОтчетов (модуль менеджера)": "Хранение и чтение сохраненных результатов отчетов",
          "РегламентированныеДанныеКлиентСервер": "Общие правила работы с регламентированными сведениями на клиенте и сервере",
          "РегламентныеЗаданияПереопределяемый": "Точка расширения регламентных заданий: свои задания и их расписания",
          "РегламентныеЗаданияСервер": "Регламентные и фоновые задания: расписание, включение и выключение, выполнение с учетом модели сервиса",
          "РезервноеКопированиеИБКлиент": "Клиентская часть резервного копирования информационной базы",
          "РезервноеКопированиеИБКлиентПереопределяемый": "Клиентская точка расширения резервного копирования",
          "СерверныеОповещения": "Оповещения, инициированные сервером и доставляемые на открытые сеансы пользователей",
          "СерверныеОповещенияКлиент": "Прием серверных оповещений на клиенте и реакция на них",
          "СервисКриптографииDSSПереопределяемый": "Точка расширения сервиса криптографии DSS",
          "СервисМобильнойПодписи": "Подписание документов через сервис мобильной подписи",
          "СервисМобильнойПодписиКлиент": "Клиентская часть сервиса мобильной подписи",
          "СервисМобильнойПодписиКлиентСервер": "Общие правила работы с сервисом мобильной подписи",
          "СервисМобильнойПодписиПереопределяемый": "Точка расширения сервиса мобильной подписи",
          "СклонениеПредставленийОбъектов": "Склонение наименований и ФИО по падежам на сервере",
          "СклонениеПредставленийОбъектовКлиент": "Клиентская часть склонения представлений",
          "СклонениеПредставленийОбъектовКлиентСервер": "Общие правила склонения на клиенте и сервере",
          "СнимкиОтчетов": "Сохраненные результаты отчетов и работа с ними",
          "СоединенияИБ": "Завершение работы пользователей: блокировка новых сеансов, отключение активных соединений",
          "СоединенияИБКлиент": "Клиентская часть завершения работы пользователей: предупреждение о скором отключении",
          "СоединенияИБПереопределяемый": "Точка расширения завершения работы пользователей",
          "СозданиеНаОсновании": "Команды создания объектов на основании других объектов",
          "СозданиеНаОснованииПереопределяемый": "Точка расширения создания на основании: свои команды ввода на основании",
          "СообщенияАдминистрированиеОбменаДаннымиКонтрольИнтерфейс": "Программный интерфейс сообщений контроля администрирования обмена в модели сервиса",
          "СообщенияАдминистрированиеОбменаДаннымиКонтрольОбработчикСообщения_2_1_2_1": "Обработчик сообщений контроля администрирования обмена, версия протокола 2.1.2.1",
          "СообщенияАдминистрированиеОбменаДаннымиУправлениеИнтерфейс": "Программный интерфейс сообщений управления администрированием обмена в модели сервиса",
          "СообщенияАдминистрированиеОбменаДаннымиУправлениеОбработчикСообщения_2_1_2_1": "Обработчик сообщений управления администрированием обмена, версия протокола 2.1.2.1",
          "СообщенияАдминистрированиеОбменаДаннымиУправлениеОбработчикСообщения_3_0_1_1": "Обработчик сообщений управления администрированием обмена, версия протокола 3.0.1.1",
          "СообщенияАдминистрированиеОбменаДаннымиУправлениеТрансляция_2_1_2_1": "Трансляция сообщений управления администрированием обмена между версиями протокола",
          "СообщенияКонтрольДополнительныхОтчетовИОбработокОбработчикТрансляции_1_0_0_1": "Трансляция сообщений контроля дополнительных отчетов и обработок между версиями протокола",
          "СообщенияОбменаДаннымиКонтрольИнтерфейс": "Программный интерфейс сообщений контроля обмена данными в модели сервиса",
          "СообщенияОбменаДаннымиКонтрольОбработчикСообщения_2_1_2_1": "Обработчик сообщений контроля обмена данными, версия протокола 2.1.2.1",
          "СообщенияОбменаДаннымиОбработчикСообщения": "Обработчик входящих сообщений обмена данными в модели сервиса",
          "СообщенияОбменаДаннымиУправлениеИнтерфейс": "Программный интерфейс сообщений управления обменом данными в модели сервиса",
          "СообщенияОбменаДаннымиУправлениеОбработчикСообщения_2_1_2_1": "Обработчик сообщений управления обменом данными, версия протокола 2.1.2.1",
          "СообщенияОбменаДаннымиУправлениеОбработчикСообщения_3_0_1_1": "Обработчик сообщений управления обменом данными, версия протокола 3.0.1.1",
          "СообщенияОбменаДаннымиУправлениеОбработчикТрансляции_2_1_2_1": "Трансляция сообщений управления обменом между версиями протокола",
          "СообщенияУправленияДОИООбработчикСообщения_1_0_1_1": "Обработчик сообщений управления дополнительными отчетами и обработками, версия протокола 1.0.1.1",
          "СообщенияУправленияДОИООбработчикСообщения_1_0_1_2": "Обработчик сообщений управления дополнительными отчетами и обработками, версия протокола 1.0.1.2",
          "СообщенияУправленияДополнительнымиОтчетамиИОбработкамиИнтерфейс": "Программный интерфейс сообщений управления дополнительными отчетами и обработками в модели сервиса",
          "СтандартныеПодсистемыКлиент": "Обработка событий приложения на клиенте: старт, завершение, обработка ошибок, действия при открытии форм",
          "СтандартныеПодсистемыКлиентСервер": "Общие для клиента и сервера параметры встраивания библиотеки",
          "СтандартныеПодсистемыКлиентСерверЛокализация": "Национальная специфика служебного слоя, общая для клиента и сервера",
          "СтандартныеПодсистемыСервер": "Служебный слой встраивания библиотеки: обработка событий приложения на сервере, параметры работы программы, поддержка форм",
          "СтандартныеПодсистемыСерверЛокализация": "Национальная специфика служебного слоя библиотеки на сервере",
          "СтроковыеФункции": "Серверные операции над строками, которым нужен доступ к базе",
          "СтроковыеФункцииКлиент": "Клиентские операции над строками",
          "СтроковыеФункцииКлиентСервер": "Разбор и сборка строк без обращения к базе: разделение и склейка, форматированные строки, числа прописью, извлечение текста из HTML, сравнение версий",
          "СтроковыеФункцииКлиентСерверЛокализация": "Национальная специфика строковых функций",
          "СтроковыеФункцииКлиентСерверРФ": "Строковые функции, специфичные для РФ",
          "СтруктураПодчиненностиПереопределяемый": "Точка расширения отчета о структуре подчиненности документов",
          "ТекущиеДелаКлиент": "Клиентская часть текущих дел: переход по делу",
          "ТекущиеДелаПереопределяемый": "Точка расширения текущих дел: свои дела на начальной странице",
          "ТекущиеДелаСервер": "Начальная страница с текущими делами: состав дел, счетчики, обновление",
          "ТранспортСообщенийОбмена": "Доставка сообщений обмена: файл, каталог, почта, FTP, веб-сервис и прочие способы передачи",
          "ТранспортСообщенийОбменаПереопределяемый": "Точка расширения транспорта сообщений: свой способ доставки",
          "УдалениеПомеченныхОбъектов": "Удаление помеченных на удаление объектов с контролем ссылочной целостности",
          "УдалениеПомеченныхОбъектовКлиент": "Клиентская часть удаления помеченных объектов",
          "УдалениеПомеченныхОбъектовПереопределяемый": "Точка расширения удаления помеченных объектов",
          "УправлениеДоступом": "Ограничение доступа на уровне записей и полей: группы доступа, профили, значения и наборы значений доступа, включение и выключение ограничений, настройка форм под права",
          "УправлениеДоступомПереопределяемый": "Точка расширения управления доступом: свои виды доступа, свои наборы значений доступа для объектов конфигурации",
          "УправлениеКолонтитулами": "Колонтитулы печатных форм и отчетов",
          "УправлениеКонтактнойИнформацией": "Адреса, телефоны, почта и прочая контактная информация объектов: чтение и запись, виды контактной информации, проверка и разбор адресов, классификатор стран мира",
          "УправлениеКонтактнойИнформациейКлиент": "Клиентская часть контактной информации: ввод и редактирование на форме, команды перехода по адресу и почте",
          "УправлениеКонтактнойИнформациейКлиентЛокализация": "Национальная специфика контактной информации на клиенте",
          "УправлениеКонтактнойИнформациейКлиентСервер": "Общие для клиента и сервера правила разбора и представления контактной информации",
          "УправлениеКонтактнойИнформациейКлиентСерверЛокализация": "Национальная специфика контактной информации, общая для клиента и сервера",
          "УправлениеКонтактнойИнформациейЛокализация": "Национальная специфика контактной информации на сервере",
          "УправлениеКонтактнойИнформациейПереопределяемый": "Точка расширения контактной информации: свои виды контактной информации и правила их обработки",
          "УправлениеПечатью": "Печать документов: формирование печатных форм, их состав и параметры, макеты в форматах офисных документов, отправка на принтер и сохранение",
          "УправлениеПечатьюКлиент": "Клиентская часть печати: выполнение команд печати, предварительный просмотр, работа с офисными документами на стороне клиента",
          "УправлениеПечатьюКлиентПереопределяемый": "Клиентская точка расширения печати: свои действия при выполнении команд печати",
          "УправлениеПечатьюМультиязычностьПереопределяемый": "Точка расширения многоязычности печатных форм",
          "УправлениеПечатьюПереопределяемый": "Точка расширения печати: свои печатные формы, свои команды печати, подмена макетов",
          "УправлениеПечатьюРФ": "Печатные формы, специфичные для РФ",
          "УправлениеСвойствами": "Дополнительные реквизиты и сведения: наборы свойств объекта, чтение и запись значений, вывод на форму",
          "УправлениеСвойствамиКлиент": "Клиентская часть дополнительных реквизитов и сведений: правка значений на форме",
          "УправлениеСвойствамиПереопределяемый": "Точка расширения дополнительных свойств: свои наборы свойств для объектов",
          "УчетОригиналовПервичныхДокументов": "Состояния оригиналов первичных документов: получен, подписан, отправлен, и отражение состояний в списках",
          "УчетОригиналовПервичныхДокументовКлиент": "Клиентская часть учета оригиналов: команды смены состояния на форме",
          "УчетОригиналовПервичныхДокументовКлиентПереопределяемый": "Клиентская точка расширения учета оригиналов первичных документов",
          "УчетОригиналовПервичныхДокументовПереопределяемый": "Точка расширения учета оригиналов первичных документов",
          "ФайловаяСистема": "Файлы и каталоги на стороне сервера: временные файлы, каталоги, безопасное создание и удаление",
          "ФайловаяСистемаКлиент": "Файлы на рабочем месте пользователя: выбор, загрузка и сохранение файлов, запуск внешних приложений, работа с временным хранилищем",
          "ФизическиеЛицаКлиентСервер": "Разбор и сборка ФИО физических лиц на клиенте и сервере",
          "ФизическиеЛицаКлиентСерверЛокализация": "Национальная специфика работы с ФИО",
          "ЦентрМониторинга": "Отправка обезличенной статистики использования программы в центр мониторинга 1С",
          "ЦентрМониторингаКлиент": "Клиентская часть центра мониторинга: запрос согласия пользователя",
          "ЦентрМониторингаПереопределяемый": "Точка расширения центра мониторинга: свои показатели",
          "ШаблоныСообщений": "Шаблоны писем и сообщений: подстановка данных объекта в текст, формирование сообщения по шаблону, вложения",
          "ШаблоныСообщенийКлиент": "Клиентская часть шаблонов сообщений: выбор шаблона и правка сообщения",
          "ШаблоныСообщенийКлиентСервер": "Общие правила разбора шаблонов сообщений",
          "ШаблоныСообщенийПереопределяемый": "Точка расширения шаблонов сообщений: свои источники данных для подстановки",
          "ШаблоныСообщенийСервер": "Серверные операции над шаблонами сообщений",
          "ЭлектроннаяПодпись": "Электронная подпись и шифрование на сервере: подписание данных, проверка подписи, сертификаты и их свойства, криптопровайдеры",
          "ЭлектроннаяПодписьКлиент": "Клиентская часть электронной подписи: интерактивное подписание и проверка, добавление сертификата, установка расширения криптографии",
          "ЭлектроннаяПодписьКлиентЛокализация": "Национальная специфика электронной подписи на клиенте",
          "ЭлектроннаяПодписьКлиентПереопределяемый": "Клиентская точка расширения электронной подписи",
          "ЭлектроннаяПодписьКлиентСервер": "Общие для клиента и сервера правила работы с 
    • subsystem-map.md 22.5 KB
      # Карта подсистем БСП
      
      Собрано генератором из версий: 3.1.11, 3.2.1. Правка вручную бессмысленна - файл перезаписывается при пересборке справочника.
      
      Имя подсистемы в документации и имя модуля в коде совпадают не всегда: механизм печати живет в `УправлениеПечатью`, свойства - в `УправлениеСвойствами`, а базовая функциональность - в `ОбщегоНазначения`. Поэтому модуль ищется по этой таблице, а не по названию подсистемы.
      
      Цифра в скобках - сколько методов подсистемы объявлено в этом модуле.
      
      | Подсистема | Программный интерфейс | Точки расширения |
      |---|---|---|
      | Базовая функциональность | `ОбщегоНазначения` (192), `ОбщегоНазначенияКлиентСервер` (83), `ОбщегоНазначенияКлиент` (54), `АдминистрированиеКластера` (45), `СтандартныеПодсистемыКлиент` (27), `СтроковыеФункцииКлиентСервер` (23), `ФайловаяСистемаКлиент` (19), `СтандартныеПодсистемыСервер` (18), `РегламентныеЗаданияСервер` (16), `ДлительныеОперации` (13), и еще 19 | `ОбщегоНазначенияПереопределяемый` (21), `ОбщегоНазначенияКлиентПереопределяемый` (12), `МультиязычностьПереопределяемый` (1), `ПодсистемыКонфигурацииПереопределяемый` (1) |
      | Обмен данными | `Обработка.УниверсальныйОбменДаннымиXML (модуль объекта)` (50), `ОбменДаннымиСервер` (43), `ОбменДаннымиXDTOСервер` (33), `Обработка.КонвертацияОбъектовИнформационныхБаз (модуль объекта)` (17), `ОбменДаннымиКлиент` (15), `ОбменДаннымиСобытия` (15), `Обработка.РегистрацияИзмененийДляОбменаДанными (модуль объекта)` (5), `ОбменДаннымиВнешнееСоединение` (3), `ОбменДаннымиВызовСервера` (1), `Обработка.КонвертацияОбъектовXDTO (модуль объекта)` (1) | `ОбменДаннымиПереопределяемый` (14) |
      | Электронная подпись | `ЭлектроннаяПодписьКлиентЛокализация` (43), `ЭлектроннаяПодписьКлиент` (38), `ЭлектроннаяПодпись` (32), `ЭлектроннаяПодписьЛокализация` (31), `ЭлектроннаяПодписьКлиентСерверЛокализация` (22), `ЭлектроннаяПодписьКлиентСервер` (5) | `ЭлектроннаяПодписьПереопределяемый` (6), `ЗаявлениеНаСертификатПереопределяемый` (4), `ЭлектроннаяПодписьКлиентПереопределяемый` (4) |
      | Контактная информация | `УправлениеКонтактнойИнформацией` (66), `УправлениеКонтактнойИнформациейКлиент` (26), `УправлениеКонтактнойИнформациейЛокализация` (15), `РаботаСАдресами` (10), `УправлениеКонтактнойИнформациейКлиентСервер` (6), `УправлениеКонтактнойИнформациейКлиентЛокализация` (3), `РаботаСАдресамиКлиентСервер` (2), `УправлениеКонтактнойИнформациейКлиентСерверЛокализация` (1) | `УправлениеКонтактнойИнформациейПереопределяемый` (5) |
      | Обмен данными в модели сервиса | `СообщенияОбменаДаннымиКонтрольИнтерфейс` (17), `СообщенияАдминистрированиеОбменаДаннымиУправлениеИнтерфейс` (15), `ОбменДаннымиВМоделиСервиса` (14), `СообщенияАдминистрированиеОбменаДаннымиКонтрольИнтерфейс` (14), `СообщенияОбменаДаннымиУправлениеИнтерфейс` (11), `СообщенияАдминистрированиеОбменаДаннымиУправлениеТрансляция_2_1_2_1` (6), `СообщенияОбменаДаннымиУправлениеОбработчикТрансляции_2_1_2_1` (6), `АвтономнаяРабота` (5), `СообщенияАдминистрированиеОбменаДаннымиКонтрольОбработчикСообщения_2_1_2_1` (4), `СообщенияАдминистрированиеОбменаДаннымиУправлениеОбработчикСообщения_2_1_2_1` (4), и еще 5 | `ОбменДаннымиВМоделиСервисаПереопределяемый` (2) |
      | Обновление версии ИБ | `ОбновлениеИнформационнойБазы` (72) | `ОбновлениеИнформационнойБазыПереопределяемый` (13), `ОбновлениеИнформационнойБазыКлиентПереопределяемый` (2) |
      | Работа с файлами | `РаботаСФайламиКлиент` (39), `РаботаСФайлами` (29), `РаботаСФайламиКлиентСервер` (4), `РаботаСФайламиЛокализация` (2) | `РаботаСФайламиПереопределяемый` (11), `РаботаСФайламиКлиентПереопределяемый` (2) |
      | Печать | `УправлениеПечатью` (36), `УправлениеПечатьюКлиент` (12), `УправлениеПечатьюРФ` (1) | `УправлениеПечатьюПереопределяемый` (16), `УправлениеПечатьюКлиентПереопределяемый` (4), `УправлениеПечатьюМультиязычностьПереопределяемый` (1) |
      | Бизнес-процессы и задачи | `БизнесПроцессыИЗадачиСервер` (36), `БизнесПроцессыИЗадачиКлиент` (19), `БизнесПроцессыИЗадачиКлиентСервер` (2) | `БизнесПроцессыИЗадачиПереопределяемый` (10), `БизнесПроцессыИЗадачиКлиентПереопределяемый` (1) |
      | Пользователи | `Пользователи` (41), `ВнешниеПользователи` (7), `ПользователиКлиент` (4), `ВнешниеПользователиКлиент` (1) | `ПользователиПереопределяемый` (11) |
      | Варианты отчетов | `ВариантыОтчетов` (15), `ОтчетыСервер` (7), `СнимкиОтчетов` (5), `ВариантыОтчетовКлиент` (3), `РегистрСведений.СнимкиОтчетов (модуль менеджера)` (3), `ВариантыОтчетовКлиентСервер` (1), `ОтчетыКлиент` (1), `ОтчетыКлиентСервер` (1), `УправлениеКолонтитулами` (1) | `ОтчетыКлиентПереопределяемый` (9), `ВариантыОтчетовПереопределяемый` (6), `ОтчетыПереопределяемый` (4) |
      | Управление доступом | `УправлениеДоступом` (40) | `УправлениеДоступомПереопределяемый` (11) |
      | Свойства | `УправлениеСвойствами` (36), `УправлениеСвойствамиКлиент` (6) | `УправлениеСвойствамиПереопределяемый` (6) |
      | Шаблоны сообщений | `ШаблоныСообщений` (20), `ШаблоныСообщенийКлиент` (4), `ШаблоныСообщенийКлиентСервер` (4), `ШаблоныСообщенийСервер` (1) | `ШаблоныСообщенийПереопределяемый` (8) |
      | Транспорт сообщений обмена | `ТранспортСообщенийОбмена` (24), `ИнтеграцияПодсистемБСП` (1), `Обработка.ТранспортСообщенийОбменаESB1C (модуль менеджера)` (1), `УправлениеПечатью` (1) | `ТранспортСообщенийОбменаПереопределяемый` (5) |
      | Учет оригиналов первичных документов | `УчетОригиналовПервичныхДокументов` (17), `УчетОригиналовПервичныхДокументовКлиент` (12) | `УчетОригиналовПервичныхДокументовПереопределяемый` (6), `УчетОригиналовПервичныхДокументовКлиентПереопределяемый` (2) |
      | Организации | `ОрганизацииСервер` (18) | `ОрганизацииПереопределяемый` (16) |
      | Дополнительные отчеты и обработки | `ДополнительныеОтчетыИОбработкиКлиентСервер` (16), `ДополнительныеОтчетыИОбработки` (10), `ДополнительныеОтчетыИОбработкиКлиент` (4) | `ДополнительныеОтчетыИОбработкиПереопределяемый` (2), `ДополнительныеОтчетыИОбработкиКлиентПереопределяемый` (1) |
      | Контроль ведения учета | `КонтрольВеденияУчета` (22), `КонтрольВеденияУчетаКлиент` (3) | `КонтрольВеденияУчетаПереопределяемый` (5) |
      | Машиночитаемые доверенности | `МашиночитаемыеДоверенностиФНС` (9), `МашиночитаемыеДоверенностиФНСКлиент` (5) | `МашиночитаемыеДоверенностиФНСПереопределяемый` (9), `МашиночитаемыеДоверенностиФНСКлиентПереопределяемый` (7) |
      | Защита персональных данных | `ЗащитаПерсональныхДанных` (15), `ЗащитаПерсональныхДанныхКлиент` (4) | `ЗащитаПерсональныхДанныхПереопределяемый` (10) |
      | Работа с почтовыми сообщениями | `РаботаСПочтовымиСообщениями` (16), `РаботаСПочтовымиСообщениямиКлиент` (4), `РаботаСПочтовымиСообщениямиЛокализация` (4) | `РаботаСПочтовымиСообщениямиПереопределяемый` (4), `РаботаСПочтовымиСообщениямиКлиентПереопределяемый` (1) |
      | Взаимодействия | `Взаимодействия` (12), `ВзаимодействияКлиент` (7), `ВзаимодействияЛокализация` (3), `ВзаимодействияКлиентСервер` (1) | `ВзаимодействияПереопределяемый` (3), `ВзаимодействияКлиентСерверПереопределяемый` (2) |
      | Профили безопасности | `РаботаВБезопасномРежиме` (15), `РаботаВБезопасномРежимеКлиент` (3) | `РаботаВБезопасномРежимеПереопределяемый` (8), `РаботаВБезопасномРежимеКлиентПереопределяемый` (1) |
      | Дополнительные отчеты и обработки в модели сервиса | `СообщенияУправленияДополнительнымиОтчетамиИОбработкамиИнтерфейс` (12), `СообщенияКонтрольДополнительныхОтчетовИОбработокОбработчикТрансляции_1_0_0_1` (6), `СообщенияУправленияДОИООбработчикСообщения_1_0_1_1` (4), `СообщенияУправленияДОИООбработчикСообщения_1_0_1_2` (4) | - |
      | Конструктор формул | `КонструкторФормул` (14), `КонструкторФормулКлиент` (8) | - |
      | Валюты | `РаботаСКурсамиВалютЛокализация` (10), `РаботаСКурсамиВалют` (6), `РаботаСКурсамиВалютКлиентЛокализация` (1), `РаботаСКурсамиВалютКлиентСервер` (1) | `РаботаСКурсамиВалютПереопределяемый` (2) |
      | Даты запрета изменения | `ДатыЗапретаИзменения` (15) | `ДатыЗапретаИзмененияПереопределяемый` (6) |
      | Напоминания пользователя | `НапоминанияПользователя` (9), `НапоминанияПользователяКлиент` (9), `НапоминанияПользователяКлиентСервер` (1) | `НапоминанияПользователяПереопределяемый` (2) |
      | Подключаемые команды | `ПодключаемыеКоманды` (5), `ПодключаемыеКомандыКлиент` (5), `ПодключаемыеКомандыКлиентСервер` (1), `СозданиеНаОсновании` (1) | `СозданиеНаОснованииПереопределяемый` (4), `ПодключаемыеКомандыПереопределяемый` (3), `ЗаполнениеОбъектовПереопределяемый` (2) |
      | Версионирование объектов | `ВерсионированиеОбъектов` (7), `ВерсионированиеОбъектовКлиент` (5), `ВерсионированиеОбъектовСобытия` (2) | `ВерсионированиеОбъектовПереопределяемый` (6) |
      | Оценка производительности | `ОценкаПроизводительностиКлиент` (11), `ОценкаПроизводительности` (9) | - |
      | Префиксация объектов | `ПрефиксацияОбъектовСобытия` (10), `ПрефиксацияОбъектовКлиентСервер` (5) | `ПрефиксацияОбъектовПереопределяемый` (3), `ПрефиксацияОбъектовКлиентСерверПереопределяемый` (1) |
      | Рассылка отчетов | `РассылкаОтчетов` (8) | `РассылкаОтчетовПереопределяемый` (8), `РассылкаОтчетовКлиентПереопределяемый` (3) |
      | Удаление помеченных объектов | `УдалениеПомеченныхОбъектов` (7), `УдалениеПомеченныхОбъектовКлиент` (7), `РегистрСведений.НеудаленныеОбъекты (модуль менеджера)` (2) | `УдалениеПомеченныхОбъектовПереопределяемый` (3) |
      | Обсуждения | `Обсуждения` (12), `ОбсужденияКлиент` (3), `ОбсужденияЛокализация` (2) | - |
      | Адресный классификатор | `АдресныйКлассификатор` (14), `АдресныйКлассификаторКлиент` (2) | - |
      | Календарные графики | `КалендарныеГрафики` (10), `КалендарныеГрафикиЛокализация` (1) | `КалендарныеГрафикиПереопределяемый` (4) |
      | Центр мониторинга | `ЦентрМониторинга` (10), `ЦентрМониторингаКлиент` (3) | `ЦентрМониторингаПереопределяемый` (2) |
      | Внешние компоненты | `ВнешниеКомпонентыКлиент` (8), `ВнешниеКомпонентыСервер` (3), `ВнешниеКомпонентыКлиентЛокализация` (2) | - |
      | Сервис мобильной подписи | `СервисМобильнойПодписи` (6), `СервисМобильнойПодписиКлиент` (3), `СервисМобильнойПодписиКлиентСервер` (1) | `СервисМобильнойПодписиПереопределяемый` (3) |
      | Текущие дела | `ТекущиеДелаСервер` (7), `ТекущиеДелаКлиент` (1) | `ТекущиеДелаПереопределяемый` (5) |
      | Завершение работы пользователей | `СоединенияИБ` (8), `СоединенияИБКлиент` (3) | `СоединенияИБПереопределяемый` (1) |
      | Загрузка данных из файла | `ЗагрузкаДанныхИзФайла` (6), `ЗагрузкаДанныхИзФайлаКлиентСервер` (3), `ЗагрузкаДанныхИзФайлаКлиент` (2) | `ЗагрузкаДанныхИзФайлаПереопределяемый` (1) |
      | Отправка SMS | `ОтправкаSMS` (4), `ОтправкаSMSКлиент` (2) | `ОтправкаSMSПереопределяемый` (4), `ОтправкаSMSКлиентПереопределяемый` (2) |
      | Поиск и удаление дублей | `ПоискИУдалениеДублей` (4), `ПоискИУдалениеДублейКлиент` (3) | `ПоискИУдалениеДублейПереопределяемый` (5) |
      | Получение файлов из Интернета | `ПолучениеФайловИзИнтернета` (7), `ПолучениеФайловИзИнтернетаКлиент` (2), `ПолучениеФайловИзИнтернетаЛокализация` (2), `ПолучениеФайловИзИнтернетаКлиентСервер` (1) | - |
      | Запрет редактирования реквизитов объектов | `ЗапретРедактированияРеквизитовОбъектовКлиент` (5), `ЗапретРедактированияРеквизитовОбъектов` (3) | `ЗапретРедактированияРеквизитовОбъектовПереопределяемый` (2) |
      | Склонение представлений объектов | `СклонениеПредставленийОбъектов` (7), `СклонениеПредставленийОбъектовКлиент` (2), `СклонениеПредставленийОбъектовКлиентСервер` (1) | - |
      | Настройки программы | - | `НастройкиПрограммыПереопределяемый` (8) |
      | Полнотекстовый поиск | `ПолнотекстовыйПоискСервер` (4), `ПолнотекстовыйПоискКлиент` (3) | `ПолнотекстовыйПоискСерверПереопределяемый` (1) |
      | Банки | `РаботаСБанками` (2), `РаботаСБанкамиКлиент` (1) | `РаботаСБанкамиПереопределяемый` (3) |
      | Графики работы | `ГрафикиРаботы` (6) | - |
      | Перевод текста | `ПереводТекстаНаДругиеЯзыки` (4), `ПереводТекстаНаДругиеЯзыкиЛокализация` (1) | - |
      | Групповое изменение объектов | `ГрупповоеИзменениеОбъектовКлиент` (1) | `ГрупповоеИзменениеОбъектовПереопределяемый` (3) |
      | Контроль работы пользователей | `КонтрольРаботыПользователей` (4) | - |
      | Обновление конфигурации | `ОбновлениеКонфигурацииКлиент` (3), `ОбновлениеКонфигурации` (1) | - |
      | Регламентные задания | - | `БлокировкаРаботыСВнешнимиРесурсамиПереопределяемый` (2), `РегламентныеЗаданияПереопределяемый` (2) |
      | Электронная подпись сервиса DSS | - | `СервисКриптографииDSSПереопределяемый` (4) |
      | Генерация штрихкода | `ГенерацияШтрихкода` (2), `УправлениеПечатью` (1) | - |
      | Настройка порядка элементов | `НастройкаПорядкаЭлементов` (3) | - |
      | Отчет о движениях документа | - | `ОтчетОДвиженияхДокументаПереопределяемый` (3) |
      | Регистрация | `ОбменДаннымиРегистрацияСервер` (3) | - |
      | Структура подчиненности | - | `СтруктураПодчиненностиПереопределяемый` (3) |
      | Базовая функциональность в модели сервиса | `РаботаВМоделиСервисаБСП` (2) | - |
      | Заметки пользователя | `ЗаметкиПользователя` (2) | - |
      | Проверка легальности получения обновления | `ПроверкаЛегальностиПолученияОбновленияКлиент` (1) | `ПроверкаЛегальностиПолученияОбновленияПереопределяемый` (1) |
      | Резервное копирование ИБ | `РезервноеКопированиеИБКлиент` (1) | `РезервноеКопированиеИБКлиентПереопределяемый` (1) |
      | Выгрузка объектов в файлы | `ВыгрузкаОбъектовВФайлы` (1) | - |
      | Интерфейс OData | - | `ИнтерфейсODataПереопределяемый` (1) |
      | Информация при запуске | - | `ИнформацияПриЗапускеПереопределяемый` (1) |
      
  • scripts
    • bsp-api.py 16 KB
      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      """Поиск по справочнику API БСП.
      
      Справочник больше мегабайта и в контекст целиком не грузится - он спрашивается по месту.
      
        bsp-api.py find <текст>            поиск по имени метода, модулю, подсистеме, механизму
        bsp-api.py show <Модуль.Метод>     полная карточка метода
        bsp-api.py show <Метод>            все методы с таким именем, в каких модулях
        bsp-api.py module <Модуль>         состав модуля
        bsp-api.py modules [<текст>]       перечень модулей
        bsp-api.py subsystem <текст>       модули и механизмы подсистемы
        bsp-api.py overrides <текст>       переопределяемые обработчики
        bsp-api.py check <Модуль.Метод>    существует ли такой вызов; код возврата 1, если нет
      
      Отборы: --av S|T|F|E|C (контекст), --sub <подсистема>, --version <версия>, --limit N.
      """
      import argparse
      import io
      import json
      import os
      import re
      import sys
      
      AV_LONG = {'S': 'Сервер', 'C': 'Вызов сервера', 'T': 'Тонкий клиент',
                 'F': 'Толстый клиент', 'E': 'Внешнее соединение'}
      SRC_LONG = {
          'L': 'модуль назван в документации',
          'P': 'модуль из примера вызова, подтвержден реализацией',
          'PA': 'модуль из примера вызова плюс контексты выполнения',
          'A': 'модуль выбран по контекстам выполнения',
          'AP': 'контексты выполнения плюс пример вызова',
          'O': 'модуль объекта или менеджера',
          'OS': 'модуль объекта, выбран по подсистеме',
          'P?': 'модуль назван в примере, но в дистрибутиве этой версии такого метода нет',
          '?': 'модуль не определен однозначно',
      }
      DB = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'references', 'bsp-api.jsonl')
      
      
      def read_reference(path):
          if not os.path.exists(path):
              raise SystemExit('справочник не найден: %s\nсобрать: scripts/bsp-build.py --help' % path)
          with io.open(path, encoding='utf-8') as fh:
              header = json.loads(fh.readline())
              return header, [json.loads(line) for line in fh if line.strip()]
      
      
      def av_text(code):
          return ', '.join(AV_LONG.get(c, c) for c in code) or 'не указана'
      
      
      def matches(rec, words):
          """Совпадение по ВСЕМ словам запроса, а не по непрерывной подстроке.
      
          Запрос обычно описывает задачу ("реквизит объекта", "фоновое задание"), а слова из него
          в записи разнесены по имени, механизму и формулировке назначения. Поиск подстроки целиком
          такие запросы просто не находит.
          """
          hay = ' '.join(filter(None, [rec['n'], rec['m'], rec.get('sub'),
                                       rec.get('grp'), rec.get('o'), rec.get('sig')])).lower()
          return all(w in hay for w in words)
      
      
      def keep(rec, args):
          if args.av and not all(c in rec.get('av', '') for c in args.av.upper()):
              return False
          if args.sub and args.sub.lower() not in (rec.get('sub') or '').lower():
              return False
          if args.version and args.version not in rec.get('v', []):
              return False
          return True
      
      
      def line_of(rec):
          star = '' if rec['src'] in ('L', 'P', 'PA', 'O') else ' [?]'
          ver = ' [!]' if rec.get('was') else ''
          purpose = ('  - ' + rec['o']) if rec.get('o') else ''
          return '%s.%s%s%s   %s%s' % (rec['m'], rec['n'], star, ver, rec.get('av', ''), purpose)
      
      
      def card(rec, header):
          out = []
          out.append('%s.%s' % (rec['m'], rec['n']))
          if rec.get('o'):
              out.append('  %s' % rec['o'])
          out.append('  %s' % rec['sig'])
          out.append('  контексты: %s' % av_text(rec.get('av', '')))
          if rec.get('p'):
              out.append('  параметры:')
              for p in rec['p']:
                  bits = [p['n']]
                  if p.get('t'):
                      bits.append(p['t'])
                  if p.get('d'):
                      bits.append('по умолчанию ' + p['d'])
                  if p.get('byval'):
                      bits.append('Знач')
                  out.append('    %s' % ' - '.join(bits))
          if rec.get('ret'):
              out.append('  возвращает: %s' % rec['ret'])
          out.append('  подсистема: %s%s' % (rec['sub'],
                                             ', механизм ' + rec['grp'] if rec.get('grp') else ''))
          out.append('  раздел: %s' % ('переопределяемый обработчик' if rec['sec'] == 'П'
                                       else 'программный интерфейс'))
          out.append('  версии: %s' % ', '.join(rec.get('v', [])))
          for ver, delta in (rec.get('was') or {}).items():
              bits = []
              if delta.get('sig'):
                  bits.append('сигнатура была: %s' % delta['sig'])
              if delta.get('k'):
                  bits.append('была %s' % ('функцией' if delta['k'] == 'Ф' else 'процедурой'))
              if delta.get('ret'):
                  bits.append('возвращала %s' % delta['ret'])
              if delta.get('av'):
                  bits.append('контексты были: %s' % av_text(delta['av']))
              if delta.get('sub'):
                  bits.append('подсистема была: %s' % delta['sub'])
              out.append('  ВНИМАНИЕ, в %s иначе - %s' % (ver, '; '.join(bits)))
          mod = header['modules'].get(rec['m'])
          if mod:
              extra = ', повторное использование %s' % mod['reuse'] if mod.get('reuse') else ''
              out.append('  модуль: %s, методов %d%s' % (mod['kind'], mod.get('total', 0), extra))
              if mod.get('o'):
                  out.append('  назначение модуля: %s' % mod['o'])
          out.append('  источник: %s' % SRC_LONG.get(rec['src'], rec['src']))
          return '\n'.join(out)
      
      
      def main():
          # Вывод справочника - кириллица. Без явного переключения потока печать падает
          # с UnicodeEncodeError везде, где консоль не в UTF-8: сборочный агент, чужая локаль.
          sys.stdout.reconfigure(encoding='utf-8')
          sys.stderr.reconfigure(encoding='utf-8')
          ap = argparse.ArgumentParser(description=__doc__,
                                       formatter_class=argparse.RawDescriptionHelpFormatter)
          ap.add_argument('command', choices=['find', 'show', 'module', 'modules', 'subsystem',
                                              'overrides', 'check', 'stats'])
          ap.add_argument('query', nargs='?', default='')
          ap.add_argument('--db', default=DB)
          ap.add_argument('--av', help='отбор по контексту: S сервер, T тонкий, F толстый, E внешнее, C вызов сервера')
          ap.add_argument('--sub', help='отбор по подсистеме')
          ap.add_argument('--version', help='отбор по версии БСП')
          ap.add_argument('--limit', type=int, default=40)
          args = ap.parse_args()
      
          header, recs = read_reference(args.db)
          q = args.query.strip()
          ql = q.lower()
      
          if args.command == 'stats':
              print('версии: %s' % ', '.join(header['versions']))
              print('модулей: %d, методов: %d' % (len(header['modules']), len(recs)))
              subs = {}
              for r in recs:
                  subs[r['sub']] = subs.get(r['sub'], 0) + 1
              for k in sorted(subs, key=lambda x: -subs[x])[:20]:
                  print('   %5d  %s' % (subs[k], k))
              return 0
      
          if args.command == 'check':
              if '.' not in q:
                  raise SystemExit('check ждет Модуль.Метод')
              mod, name = q.rsplit('.', 1)
              hit = [r for r in recs if r['m'].lower() == mod.lower() and r['n'].lower() == name.lower()]
              # Отбор по версии обязан действовать и здесь. Иначе на проекте с БСП 3.1.11 проверка
              # подтвердит метод, появившийся только в 3.2.1, - то есть сделает ровно обратное тому,
              # ради чего ее зовут.
              if hit and args.version:
                  wrong = [r for r in hit if args.version not in r.get('v', [])]
                  hit = [r for r in hit if args.version in r.get('v', [])]
                  if not hit and wrong:
                      print('%s - в версии %s НЕ СУЩЕСТВУЕТ; есть в: %s'
                            % (q, args.version,
                               ', '.join(sorted(set(v for r in wrong for v in r.get('v', []))))))
                      return 1
              if hit:
                  print('%s.%s - есть, %s' % (hit[0]['m'], hit[0]['n'], hit[0]['sig']))
                  # Существует - еще не значит "вызывай": устаревший метод по виду
                  # не отличается от действующего. Код возврата не меняем, метод
                  # существует; предупреждение читает человек либо валидатор.
                  dep = hit[0].get('dep')
                  if dep:
                      print('  ВНИМАНИЕ: устаревший, вместо него %s' % dep)
                  return 0
              same = [r for r in recs if r['n'].lower() == name.lower()]
              print('%s - НЕ НАЙДЕН в справочнике БСП' % q)
              if same:
                  print('метод с таким именем есть в: %s' % ', '.join(sorted({r['m'] for r in same})))
              near = [r for r in recs if r['m'].lower() == mod.lower()]
              if near and not same:
                  print('модуль есть, метода нет. Похожие имена в модуле: %s'
                        % ', '.join(sorted(r['n'] for r in near
                                           if name.lower()[:5] in r['n'].lower())[:8]))
              elif not near:
                  mods = sorted(m for m in header['modules'] if mod.lower()[:6] in m.lower())
                  if mods:
                      print('модуля нет. Похожие: %s' % ', '.join(mods[:8]))
              return 1
      
          if args.command == 'modules':
              rows = [(m, v) for m, v in header['modules'].items() if not q or ql in m.lower()]
              rows.sort(key=lambda x: -x[1].get('total', 0))
              for m, v in rows[:args.limit]:
                  print('%-52s %-4s методов %4d' % (m, v.get('av', ''), v.get('total', 0)))
                  if v.get('o'):
                      print('    %s' % v['o'])
              print('-- всего %d' % len(rows))
              return 0
      
          if args.command == 'module':
              rows = [r for r in recs if r['m'].lower() == ql]
              if not rows:
                  # Частичное совпадение с НЕСКОЛЬКИМИ модулями склеивать нельзя: состав окажется
                  # сборным, а шапка - от одного из них, и клиент-серверные методы припишутся клиенту.
                  near = sorted({r['m'] for r in recs if ql in r['m'].lower()})
                  if len(near) > 1:
                      print('уточните модуль, подходит %d: %s' % (len(near), ', '.join(near[:12])))
                      return 1
                  rows = [r for r in recs if ql in r['m'].lower()]
              if not rows:
                  print('модуль не найден: %s' % q)
                  return 1
              rows = [r for r in rows if keep(r, args)]
              if not rows:
                  print('модуль есть, но под отбор ничего не подходит')
                  return 1
              info = header['modules'].get(rows[0]['m'], {})
              print('%s - %s, контексты: %s' % (rows[0]['m'], info.get('kind', ''),
                                                av_text(info.get('av', ''))))
              if info.get('o'):
                  print('   %s' % info['o'])
              for r in sorted(rows, key=lambda x: x['n'])[:args.limit]:
                  print('   %s %s' % ('Ф' if r['k'] == 'Ф' else 'П', r['sig']))
              print('-- методов %d' % len(rows))
              return 0
      
          if args.command == 'subsystem':
              rows = [r for r in recs if (r.get('sub') or '').lower() == ql]
              if not rows:
                  # "Обмен данными" подходит и к "Обмен данными в модели сервиса": склеив их, получим
                  # чужие модули и счетчик от двух подсистем под именем одной.
                  near = sorted({r['sub'] for r in recs if ql in (r.get('sub') or '').lower()})
                  if len(near) > 1:
                      print('уточните подсистему, подходит %d: %s' % (len(near), '; '.join(near)))
                      return 1
                  rows = [r for r in recs if ql in (r.get('sub') or '').lower()]
              if not rows:
                  print('подсистема не найдена: %s' % q)
                  return 1
              rows = [r for r in rows if keep(r, args)]
              if not rows:
                  print('подсистема есть, но под отбор ничего не подходит')
                  return 1
              mods, groups = {}, {}
              for r in rows:
                  mods[r['m']] = mods.get(r['m'], 0) + 1
                  if r.get('grp'):
                      groups[r['grp']] = groups.get(r['grp'], 0) + 1
              print('подсистема: %s, методов %d' % (rows[0]['sub'], len(rows)))
              print('модули:')
              for m in sorted(mods, key=lambda x: -mods[x])[:args.limit]:
                  print('   %-50s %4d' % (m, mods[m]))
                  o = header['modules'].get(m, {}).get('o')
                  if o:
                      print('       %s' % o)
              if groups:
                  print('механизмы:')
                  for g in sorted(groups, key=lambda x: -groups[x])[:args.limit]:
                      print('   %-50s %4d' % (g, groups[g]))
              return 0
      
          if args.command == 'overrides':
              rows = [r for r in recs if r['sec'] == 'П'
                      and (not q or matches(r, [w for w in ql.split() if w]))]
              rows = [r for r in rows if keep(r, args)]
              for r in sorted(rows, key=lambda x: (x['m'], x['n']))[:args.limit]:
                  print(line_of(r))
              print('-- всего %d' % len(rows))
              return 0
      
          if args.command == 'show':
              if '.' in q:
                  mod, name = q.rsplit('.', 1)
                  rows = [r for r in recs if r['m'].lower() == mod.lower() and r['n'].lower() == name.lower()]
              else:
                  rows = [r for r in recs if r['n'].lower() == ql]
              rows = [r for r in rows if keep(r, args)]
              if not rows:
                  print('не найдено: %s' % q)
                  return 1
              print('\n\n'.join(card(r, header) for r in rows[:args.limit]))
              return 0
      
          words = [w for w in ql.split() if w]
          if not words:
              raise SystemExit('find ждет текст запроса')
          rows = [r for r in recs if matches(r, words) and keep(r, args)]
          # Сперва то, где запрос попал в само имя метода: имена в БСП говорящие, и точное попадание
          # почти всегда и есть искомое.
          rows.sort(key=lambda r: (0 if all(w in r['n'].lower() for w in words) else 1,
                                   len(r['n']), r['m'], r['n']))
          for r in rows[:args.limit]:
              print(line_of(r))
          if len(rows) > args.limit:
              print('-- показано %d из %d, уточните запрос или поднимите --limit' % (args.limit, len(rows)))
          else:
              print('-- всего %d' % len(rows))
          return 0
      
      
      if __name__ == '__main__':
          sys.exit(main())
      
    • bsp-build.py 34.3 KB
      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      """Сборка справочника API БСП: документация ИТС плюс реальная реализация библиотеки.
      
      Документация знает, ЧТО делает метод, но не знает, в каком общем модуле он лежит: крошки
      статьи называют механизм, а не модуль. Реализация знает модули и сигнатуры, но не знает, какая
      часть кода вынесена в публичный интерфейс. Справочник получается на стыке.
      
      Вход:
        --docs   <версия>=<каталог скрапа ИТС>   можно указать несколько раз
        --lib    <каталог, куда v8unpack развернул 1Cv8.cf>
        --out    <файл .jsonl>
      
      Скрап и дистрибутив библиотеки лицензионные и в репозиторий не кладутся. На выходе - только
      факты: имена, сигнатуры, типы, контексты выполнения, принадлежность подсистеме и версиям.
      
      Распаковать дистрибутив:  python -m v8unpack -E 1Cv8.cf <каталог> --temp <каталог-temp>
      """
      import argparse
      import collections
      import io
      import json
      import os
      import re
      import sys
      
      IDENT = r'[A-Za-z_А-яЁё][A-Za-z0-9_А-яЁё]*'
      
      # --- разбор страниц документации ------------------------------------------------------------
      SEC_RE = re.compile(r'^(Синтаксис|Параметры|Возвращаемое значение|Пример вызова|Пример реализации|'
                          r'Доступность|Расположение)\s*\n+```\n(.*?)```', re.S | re.M)
      SIGN_RE = re.compile(r'^\s*(?:(Асинх|Async)\s+)?(Процедура|Функция|Procedure|Function)\s+('
                           + IDENT + r')\s*\(', re.S)
      LOC_RE = re.compile(r'^[ \t]*Общий модуль\s+(' + IDENT + r')', re.M)
      PARAM_TYPE_RE = re.compile(r'\s{0,6}(' + IDENT + r')\s+-\s+([^-\n]{1,60}?)\s*(?:-|$)')
      
      # --- разбор кода ----------------------------------------------------------------------------
      # Литерал ИЛИ комментарий: что началось раньше, то и поглощает второе. Закрывающая кавычка
      # необязательна - незакрытый литерал гасит остаток файла.
      NOISE_RE = re.compile(r'"(?:[^"]|"")*"?|//[^\n]*')
      SIG_RE = re.compile(r'^[ \t]*(?:(Асинх|Async)[ \t]+)?(Процедура|Функция|Procedure|Function)[ \t]+('
                          + IDENT + r')[ \t]*\(', re.IGNORECASE | re.MULTILINE)
      TAIL_RE = re.compile(r'^\s*(Экспорт|Export)\b', re.IGNORECASE)
      
      # Позиции флагов в CommonModule.json (v8unpack), расшифрованы сверкой с XML-выгрузкой на 425
      # модулях с полным совпадением. Шестая позиция - не флаг, а ReturnValuesReuse.
      FLAG_POS = {0: 'ClientOrdinaryApplication', 1: 'Server', 2: 'ExternalConnection', 3: 'Privileged',
                  4: 'Global', 5: 'ClientManagedApplication', 7: 'ServerCall'}
      REUSE = {'0': None, '1': 'НаВремяВызова', '2': 'НаВремяСеанса'}
      
      AV_SHORT = {'Сервер': 'S', 'Вызов сервера': 'C', 'Тонкий клиент': 'T',
                  'Толстый клиент': 'F', 'Внешнее соединение': 'E'}
      # Источник имени модуля. Показывает, насколько запись факт, а не вывод: L - документация назвала
      # модуль сама; P - префикс из примера, подтвержденный реализацией; A - выбор по контекстам
      # выполнения; O - модуль объекта или менеджера; P? - имя названо документацией, но в дистрибутиве
      # этой версии такого метода нет (объект выведен из поставки либо документация отстала).
      SRC_CODE = {'Расположение': 'L', 'префикс подтвержден реализацией': 'P',
                  'префикс плюс доступность': 'PA', 'доступность': 'A',
                  'доступность плюс префикс': 'AP', 'модуль объекта или менеджера': 'O',
                  'модуль объекта, выбран по подсистеме': 'OS',
                  'префикс без подтверждения': 'P?'}
      
      KIND_RU = {
          'Catalog': 'Справочник', 'Document': 'Документ', 'DataProcessor': 'Обработка',
          'Report': 'Отчет', 'InformationRegister': 'РегистрСведений',
          'AccumulationRegister': 'РегистрНакопления', 'BusinessProcess': 'БизнесПроцесс',
          'ChartOfCharacteristicType': 'ПланВидовХарактеристик', 'Task': 'Задача',
          'ExchangePlan': 'ПланОбмена', 'Constant': 'Константа', 'DocumentJournal': 'ЖурналДокументов',
          'WebService': 'WebСервис', 'HTTPService': 'HTTPСервис', 'FilterCriterion': 'КритерийОтбора',
          'SettingsStorage': 'ХранилищеНастроек', 'CalculationRegister': 'РегистрРасчета',
          'AccountingRegister': 'РегистрБухгалтерии',
      }
      
      # Префиксы из примеров вызова, которые общими модулями не являются.
      NOT_A_MODULE_RE = re.compile(r'(Объект|Ссылка|Менеджер|Форма|Набор|Запись)$')
      
      # Менеджер объектов метаданных в примерах: Обработки.Имя, Отчеты.Имя и так далее.
      MANAGER_RU = {'Обработки': 'Обработка', 'Отчеты': 'Отчет', 'Справочники': 'Справочник',
                    'Документы': 'Документ', 'РегистрыСведений': 'РегистрСведений',
                    'РегистрыНакопления': 'РегистрНакопления', 'ПланыОбмена': 'ПланОбмена',
                    'БизнесПроцессы': 'БизнесПроцесс', 'Задачи': 'Задача',
                    'ЖурналыДокументов': 'ЖурналДокументов', 'Константы': 'Константа'}
      # Пример вида "ОбработкаОбъект = Обработки.Имя.Создать();" - дальше метод зовут через переменную,
      # и без этой связки настоящее имя обработки теряется.
      CREATE_RE = re.compile(r'(' + IDENT + r')\s*=\s*(' + '|'.join(MANAGER_RU) +
                             r')\.(' + IDENT + r')\s*\.\s*(?:Создать\w*)\s*\(')
      MANAGER_CALL_RE = re.compile(r'(' + '|'.join(MANAGER_RU) + r')\.(' + IDENT + r')\s*\.\s*%s\b')
      
      
      def blank_noise(text):
          """Гасит строковые литералы и комментарии за один проход, сохраняя длину и переводы строк."""
          def blank(m):
              s = m.group(0)
              if s[0] == '/':
                  return ' ' * len(s)
              closed = len(s) >= 2 and s[-1] == '"'
              inner = s[1:-1] if closed else s[1:]
              body = ' ' * len(inner) if '\n' not in inner \
                  else ''.join('\n' if c == '\n' else ' ' for c in inner)
              return '"' + body + ('"' if closed else '')
          return NOISE_RE.sub(blank, text)
      
      
      def exported_methods(text):
          """Экспортные методы модуля: имя, вид, сигнатура одной строкой."""
          src = blank_noise(text)
          out = []
          for m in SIG_RE.finditer(src):
              i, depth = m.end() - 1, 0
              while i < len(src):
                  if src[i] == '(':
                      depth += 1
                  elif src[i] == ')':
                      depth -= 1
                      if depth == 0:
                          break
                  i += 1
              if depth != 0:
                  continue
              if not TAIL_RE.match(src[i + 1:i + 240].lstrip('\r\n \t')):
                  continue
              out.append({'name': m.group(3), 'kind': m.group(2), 'async': bool(m.group(1)),
                          'signature': ' '.join(text[m.start():i + 1].split())})
          return out
      
      
      def read_module_text(path):
          if not os.path.exists(path):
              return ''
          return io.open(path, encoding='utf-8-sig', errors='replace', newline='').read()
      
      
      # --- сторона реализации ---------------------------------------------------------------------
      def parse_impl(root):
          """Контейнеры кода библиотеки: общие модули плюс модули объектов и менеджеров.
      
          Формы не берутся: их методы программным интерфейсом библиотеки не являются.
          """
          containers = {}
          base = os.path.join(root, 'CommonModule')
          if not os.path.isdir(base):
              raise SystemExit('в каталоге %s нет папки CommonModule - это не распакованный .cf' % root)
      
          for name in sorted(os.listdir(base)):
              d = os.path.join(base, name)
              jp = os.path.join(d, 'CommonModule.json')
              if not os.path.isdir(d) or not os.path.exists(jp):
                  continue
              meta = json.load(io.open(jp, encoding='utf-8'))
              flags, reuse = {}, None
              try:
                  tail = meta['header'][0][1][2:10]
                  if len(tail) >= 8 and all(isinstance(v, str) for v in tail):
                      flags = {n: tail[p] == '1' for p, n in FLAG_POS.items()}
                      reuse = REUSE.get(tail[6])
              except (KeyError, IndexError, TypeError):
                  pass
              av = []
              for flag, label in (('Server', 'Сервер'), ('ServerCall', 'Вызов сервера'),
                                  ('ClientManagedApplication', 'Тонкий клиент'),
                                  ('ClientOrdinaryApplication', 'Толстый клиент'),
                                  ('ExternalConnection', 'Внешнее соединение')):
                  if flags.get(flag):
                      av.append(label)
              containers[name] = {'kind': 'ОбщийМодуль', 'availability': av, 'reuse': reuse,
                                  'privileged': bool(flags.get('Privileged')),
                                  'methods': exported_methods(read_module_text(
                                      os.path.join(d, 'CommonModule.obj.bsl')))}
      
          for kind in sorted(os.listdir(root)):
              kd = os.path.join(root, kind)
              if kind == 'CommonModule' or not os.path.isdir(kd):
                  continue
              ru = KIND_RU.get(kind, kind)
              for obj in sorted(os.listdir(kd)):
                  od = os.path.join(kd, obj)
                  if not os.path.isdir(od):
                      continue
                  for suffix, label in ((kind + '.obj.bsl', 'модуль объекта'),
                                        (kind + '.mgr.bsl', 'модуль менеджера')):
                      ms = exported_methods(read_module_text(os.path.join(od, suffix)))
                      if not ms:
                          continue
                      containers['%s.%s (%s)' % (ru, obj, label)] = {
                          'kind': ru, 'availability': [], 'reuse': None, 'privileged': False,
                          'methods': ms}
          return containers
      
      
      # --- сторона документации -------------------------------------------------------------------
      def split_params(sig):
          """Параметры из сигнатуры: имя, передача по значению, значение по умолчанию."""
          i = sig.find('(')
          if i < 0:
              return []
          depth, j = 0, i
          while j < len(sig):
              if sig[j] == '(':
                  depth += 1
              elif sig[j] == ')':
                  depth -= 1
                  if depth == 0:
                      break
              j += 1
          # Запятая разделяет параметры только вне скобок И вне строкового литерала: у части методов
          # значение по умолчанию - это сама запятая, например Разделитель = ",".
          parts, depth, cur, in_str = [], 0, '', False
          for ch in sig[i + 1:j]:
              if in_str:
                  cur += ch
                  if ch == '"':
                      in_str = False
                  continue
              if ch == '"':
                  in_str = True
                  cur += ch
                  continue
              if ch in '([':
                  depth += 1
              elif ch in ')]':
                  depth -= 1
              if ch == ',' and depth == 0:
                  parts.append(cur)
                  cur = ''
              else:
                  cur += ch
          if cur.strip():
              parts.append(cur)
          out = []
          for p in parts:
              p = ' '.join(p.split())
              if not p:
                  continue
              byval = bool(re.match(r'(Знач|Val)\s+', p, re.I))
              rest = re.sub(r'^(Знач|Val)\s+', '', p, flags=re.I)
              name, _, dflt = rest.partition('=')
              out.append({'name': name.strip(), 'byval': byval,
                          'default': dflt.strip() or None})
          return out
      
      
      def parse_docs(root):
          """Страницы главы 4 - программного интерфейса."""
          meta = json.load(io.open(os.path.join(root, '_meta.json'), encoding='utf-8'))
          out = []
          for x in meta:
              b = x['breadcrumb']
              if len(b) < 4 or not b[1].startswith('Глава 4'):
                  continue
              p = os.path.join(root, 'markdown', x['filename_base'] + '.md')
              if not os.path.exists(p):
                  continue
              body = io.open(p, encoding='utf-8').read()
              body = body.split('---', 2)[2] if body.startswith('---') else body
              secs = {m.group(1): m.group(2).strip('\n') for m in SEC_RE.finditer(body)}
              if 'Синтаксис' not in secs:
                  continue
              ms = SIGN_RE.match(secs['Синтаксис'].strip())
              if not ms:
                  continue
              name = ms.group(3)
      
              module, source, cands = None, None, []
              if 'Расположение' in secs:
                  ml = LOC_RE.search(secs['Расположение'])
                  if ml:
                      module, source = ml.group(1), 'Расположение'
              if module is None:
                  # Метод могут звать прямо через менеджер: Обработки.Имя.Метод().
                  mc = MANAGER_CALL_RE.pattern % re.escape(name)
                  for mm in re.finditer(mc, body):
                      cands.append('%s.%s (модуль менеджера)' % (MANAGER_RU[mm.group(1)], mm.group(2)))
                  # Либо через переменную, которой присвоили Обработки.Имя.Создать().
                  created = {mm.group(1): '%s.%s (модуль объекта)' % (MANAGER_RU[mm.group(2)], mm.group(3))
                             for mm in CREATE_RE.finditer(body)}
                  pref = collections.Counter(
                      mm.group(1) for mm in
                      re.finditer(r'(' + IDENT + r')\.' + re.escape(name) + r'\b', body))
                  for p in pref:
                      if p in created:
                          cands.append(created[p])
                      elif not NOT_A_MODULE_RE.search(p):
                          cands.append(p)
                  cands = sorted(set(cands))
      
              types = {}
              for line in (secs.get('Параметры') or '').split('\n'):
                  m = PARAM_TYPE_RE.match(line)
                  if m:
                      types.setdefault(m.group(1), m.group(2).strip())
              params = split_params(' '.join(secs['Синтаксис'].split()))
              for pr in params:
                  pr['type'] = types.get(pr['name'])
      
              out.append({
                  'name': name,
                  'async': bool(ms.group(1)),
                  'kind': ms.group(2),
                  'subsystem': b[2],
                  'section': b[3],
                  'group': b[4] if len(b) > 5 else None,
                  'module': module,
                  'module_source': source,
                  'candidates': cands,
                  'availability': [s.strip() for s in secs.get('Доступность', '').split(',') if s.strip()],
                  'signature': ' '.join(secs['Синтаксис'].split()),
                  'params': params,
                  'returns': secs.get('Возвращаемое значение'),
              })
          return out
      
      
      # --- сшивка ---------------------------------------------------------------------------------
      def public_only(cands, section):
          """Отсев кандидатов, которые публичным интерфейсом быть не могут.
      
          Оба правила проверены сплошь: ни один документированный метод не лежит в служебном модуле,
          а раздел Переопределение ложится ровно в переопределяемые модули и никуда больше.
          """
          out = [c for c in cands if 'Служебн' not in c]
          if section == 'Переопределение':
              pick = [c for c in out if 'Переопределяем' in c]
          else:
              pick = [c for c in out if 'Переопределяем' not in c]
          return pick or out or list(cands)
      
      
      def resolve_module(doc, impl, by_name):
          """Модуль метода. Возвращает (модуль, источник) - источник показывает, насколько это факт."""
          owners = by_name.get(doc['name'].lower(), [])
          common = public_only([c for c in owners if impl[c]['kind'] == 'ОбщийМодуль'], doc['section'])
          other = sorted(set(c for c in owners if impl[c]['kind'] != 'ОбщийМодуль'))
          av = set(doc['availability'])
      
          if doc['module_source'] == 'Расположение':
              m = doc['module']
              return (m, 'Расположение') if m in impl else (m, 'Расположение (в реализации нет)')
      
          fixed = []
          for c in doc['candidates']:
              if c in impl:
                  fixed.append(c)
              elif c.startswith('Модуль') and c[6:] in impl:
                  fixed.append(c[6:])          # идиома ОбщегоНазначения.ОбщийМодуль("Имя")
      
          confirmed = sorted(set(c for c in fixed if c in common))
          if len(confirmed) == 1:
              return confirmed[0], 'префикс подтвержден реализацией'
          if len(confirmed) > 1:
              byav = [c for c in confirmed if set(impl[c]['availability']) == av]
              if len(byav) == 1:
                  return byav[0], 'префикс плюс доступность'
      
          if common:
              byav = [c for c in sorted(set(common)) if set(impl[c]['availability']) == av]
              if len(byav) == 1:
                  return byav[0], 'доступность'
              if len(byav) > 1:
                  inter = [c for c in byav if c in fixed]
                  if len(inter) == 1:
                      return inter[0], 'доступность плюс префикс'
                  return None, 'несколько общих модулей с одной доступностью'
              return None, 'доступность не совпала ни с одним общим модулем'
      
          if other:
              if len(other) == 1:
                  return other[0], 'модуль объекта или менеджера'
              sub = re.sub(r'[^A-Za-zА-яЁё]', '', doc['subsystem']).lower()[:10]
              near = [c for c in other if sub and sub in re.sub(r'[^A-Za-zА-яЁё]', '', c).lower()]
              if len(near) == 1:
                  return near[0], 'модуль объекта, выбран по подсистеме'
              return None, 'метод есть в %d модулях объектов' % len(other)
      
          if len(set(fixed)) == 1:
              return sorted(set(fixed))[0], 'префикс без подтверждения'
          # Последняя попытка: документация называет владельца, а в этой сборке библиотеки его нет.
          # Так бывает у обработок обмена, выведенных из поставки: имя из примера достоверно, а
          # проверить его нечем. Отдаем с явной пометкой, а не молчим.
          raw = sorted(set(c for c in doc['candidates'] if not NOT_A_MODULE_RE.search(c)))
          if len(raw) == 1:
              return raw[0], 'префикс без подтверждения'
          return None, 'метода нет в реализации'
      
      
      def version_deltas(by_ver, versions, base_rec):
          """Чем метод отличался в прежних версиях от того, что записано как основное.
      
          Записывать только последнюю версию нельзя: между 3.1.11 и 3.2.1 у части методов изменилась
          сигнатура, причем ломающе - процедура стала функцией, параметр вставлен НЕ в конец. Код,
          написанный по новой сигнатуре, на старой версии передаст аргументы не туда.
          """
          if len(by_ver) < 2:
              return None
          newest = [v for v in versions if v in by_ver][-1]
          out = {}
          for ver in versions:
              if ver not in by_ver or ver == newest:
                  continue
              d = by_ver[ver]
              delta = {}
              if d['signature'] != base_rec['sig']:
                  delta['sig'] = d['signature']
              av = ''.join(AV_SHORT.get(a, '?') for a in d['availability'])
              if av != base_rec['av']:
                  delta['av'] = av
              # Отличие по возврату записывается только когда ОБА типа названы. Отсутствие секции в
              # старой документации - это ее неполнота, а не смена контракта, и в отличия не идет.
              rt = return_type(d.get('returns'))
              if rt and base_rec.get('ret') and rt != base_rec['ret']:
                  delta['ret'] = rt
              kind = 'Ф' if d['kind'].lower().startswith(('функ', 'func')) else 'П'
              if kind != base_rec['k']:
                  delta['k'] = kind
              if d['subsystem'] != base_rec['sub']:
                  delta['sub'] = d['subsystem']
              if delta:
                  out[ver] = delta
          return out or None
      
      
      def return_type(raw):
          """Тип возвращаемого значения - первое слово секции."""
          if not raw:
              return None
          m = re.match(r'\s*см\.\s*(' + IDENT + r'(?:\.' + IDENT + r')*)', raw.strip(), re.I)
          if m:
              return 'см. ' + m.group(1)
          m = re.match(r'\s*(' + IDENT + r'(?:\.' + IDENT + r')*)', raw.strip())
          return m.group(1) if m else None
      
      
      def main():
          ap = argparse.ArgumentParser(description=__doc__,
                                       formatter_class=argparse.RawDescriptionHelpFormatter)
          ap.add_argument('--docs', action='append', required=True, metavar='ВЕРСИЯ=КАТАЛОГ',
                          help='скрап документации ИТС; можно указать несколько раз')
          ap.add_argument('--lib', action='append', required=True, metavar='[ВЕРСИЯ=]КАТАЛОГ',
                          help='каталог, куда v8unpack развернул 1Cv8.cf. С префиксом версии '
                               'привязывается к своей документации; без префикса берется для всех')
          ap.add_argument('--out', required=True, metavar='ФАЙЛ.jsonl')
          ap.add_argument('--map', metavar='ФАЙЛ.md',
                          help='заодно переписать карту подсистем')
          ap.add_argument('--purposes', metavar='ФАЙЛ.json',
                          help='свои однострочные формулировки назначения: "Модуль.Метод": "текст"')
          args = ap.parse_args()
      
          # Каждая версия документации сшивается со СВОЕЙ библиотекой. Иначе методы, убранные в новой
          # версии, объявляются несуществующими, а добавленные - неподтвержденными.
          libs, default_lib = {}, None
          for spec in args.lib:
              ver, sep, path = spec.partition('=')
              if not sep:
                  ver, path = None, spec
              impl = parse_impl(path)
              index = collections.defaultdict(list)
              for cid, c in impl.items():
                  for m in c['methods']:
                      index[m['name'].lower()].append(cid)
              sys.stderr.write('реализация %s: контейнеров %d, экспортных методов %d\n'
                               % (ver or 'общая', len(impl), sum(len(c['methods']) for c in impl.values())))
              if ver:
                  libs[ver] = (impl, index)
              else:
                  default_lib = (impl, index)
          # Библиотеку без префикса версии подставляем любой документации. Молча подставлять вместо нее
          # "самую свежую из указанных" нельзя: опечатка в версии тогда сведет документацию с чужой
          # реализацией и выдаст неверные модули и контексты - ровно то, ради чего версии и разводились.
      
          # Формулировки назначения - единственная часть справочника, написанная нами, а не выведенная
          # из источников. Два раздела: чем занят модуль и что делает метод.
          purposes, mod_purposes = {}, {}
          if args.purposes and os.path.exists(args.purposes):
              p = json.load(io.open(args.purposes, encoding='utf-8'))
              if isinstance(p, dict) and ('methods' in p or 'modules' in p):
                  purposes = p.get('methods') or {}
                  mod_purposes = p.get('modules') or {}
              else:
                  purposes = p
              sys.stderr.write('формулировки назначения: модулей %d, методов %d\n'
                               % (len(mod_purposes), len(purposes)))
      
          merged, seen, versions, per_version = {}, collections.defaultdict(set), [], {}
          stat = collections.Counter()
          for spec in args.docs:
              if '=' not in spec:
                  raise SystemExit('--docs ждет ВЕРСИЯ=КАТАЛОГ, получено: %s' % spec)
              ver, path = spec.split('=', 1)
              versions.append(ver)
              pair = libs.get(ver, default_lib)
              if pair is None:
                  raise SystemExit('для документации %s не указана библиотека: добавьте --lib "%s=<каталог>" '
                                   'либо --lib <каталог> без версии. Известны: %s'
                                   % (ver, ver, ', '.join(sorted(libs)) or 'ни одной'))
              impl, by_name = pair
              pages = parse_docs(path)
              for d in pages:
                  module, source = resolve_module(d, impl, by_name)
                  d['module'], d['module_source'] = module, source
                  stat[source] += 1
                  stat['всего'] += 1
                  key = (module or '?', d['name'])
                  seen[key].add(ver)
                  merged[key] = d
                  per_version.setdefault(key, {})[ver] = d
              sys.stderr.write('документация %s: методов %d\n' % (ver, len(pages)))
      
          resolved = sum(v for k, v in stat.items() if k in SRC_CODE)
          sys.stderr.write('сшивка: модуль определен у %d из %d (%.1f%%)\n'
                           % (resolved, stat['всего'], 100.0 * resolved / max(1, stat['всего'])))
          for k, v in stat.most_common():
              if k != 'всего' and k not in SRC_CODE:
                  sys.stderr.write('   не разрешено - %s: %d\n' % (k, v))
      
          used = sorted({k[0] for k in merged})
          header = {'_': 'справочник API БСП', 'versions': versions, 'modules': {}}
          # Свойства модуля берутся из самой поздней библиотеки, где он есть: модуль мог быть убран,
          # и тогда о нем знает только более ранняя.
          lookup = [libs[v][0] for v in reversed(versions) if v in libs]
          if default_lib is not None:
              lookup.append(default_lib[0])
          for cid in used:
              c = next((L[cid] for L in lookup if cid in L), None)
              header['modules'][cid] = {
                  'kind': c['kind'] if c else '?',
                  'av': ''.join(AV_SHORT.get(a, '?') for a in c['availability']) if c else '',
                  'reuse': c['reuse'] if c else None,
                  'total': len(c['methods']) if c else 0,
              }
              if mod_purposes.get(cid):
                  header['modules'][cid]['o'] = mod_purposes[cid]
          unknown = sorted(set(mod_purposes) - set(header['modules']))
          if unknown:
              sys.stderr.write('в формулировках есть модули, которых нет в справочнике: %s\n'
                               % ', '.join(unknown[:5]))
          unknown_m = sorted(set(purposes) - {'%s.%s' % k for k in merged})
          if unknown_m:
              sys.stderr.write('в формулировках есть методы, которых нет в справочнике: %d, например %s\n'
                               % (len(unknown_m), ', '.join(unknown_m[:3])))
      
          with io.open(args.out, 'w', encoding='utf-8', newline='\n') as fh:
              fh.write(json.dumps(header, ensure_ascii=False, sort_keys=False) + '\n')
              for (mod, name), d in sorted(merged.items()):
                  rec = {'m': mod, 'n': name,
                         'k': 'Ф' if d['kind'].lower().startswith(('функ', 'func')) else 'П',
                         'sig': d['signature'],
                         'av': ''.join(AV_SHORT.get(a, '?') for a in d['availability']),
                         'sub': d['subsystem'],
                         'sec': 'П' if d['section'] == 'Переопределение' else 'И',
                         'src': SRC_CODE.get(d['module_source'], '?'),
                         'v': sorted(seen[(mod, name)])}
                  if d['async']:
                      rec['async'] = True
                  if d['group']:
                      rec['grp'] = d['group']
                  params = []
                  for p in d['params']:
                      q = {'n': p['name']}
                      if p.get('type'):
                          q['t'] = p['type']
                      if p.get('default'):
                          q['d'] = p['default']
                      if p.get('byval'):
                          q['byval'] = True
                      params.append(q)
                  if params:
                      rec['p'] = params
                  rt = return_type(d.get('returns'))
                  if rt:
                      rec['ret'] = rt
                  pur = purposes.get(mod + '.' + name)
                  if pur:
                      rec['o'] = pur
                  was = version_deltas(per_version.get((mod, name), {}), versions, rec)
                  if was:
                      rec['was'] = was
                  fh.write(json.dumps(rec, ensure_ascii=False, sort_keys=False) + '\n')
      
          sys.stderr.write('записано: %s, методов %d, %.2f МБ\n'
                           % (args.out, len(merged), os.path.getsize(args.out) / 1048576.0))
      
          if args.map:
              write_subsystem_map(args.map, merged, versions)
              sys.stderr.write('записано: %s\n' % args.map)
      
      
      def write_subsystem_map(path, merged, versions):
          """Карта подсистем: какие модули в каждой и где ее точки расширения.
      
          Имя подсистемы в документации и имя модуля в коде совпадают далеко не всегда, а без карты
          приходится угадывать: механизм печати живет в УправлениеПечатью, а не в Печать.
          """
          by_sub = collections.defaultdict(lambda: collections.defaultdict(int))
          for (mod, name), d in merged.items():
              by_sub[d['subsystem']][mod] += 1
      
          lines = ['# Карта подсистем БСП', '',
                   'Собрано генератором из версий: %s. Правка вручную бессмысленна - файл '
                   'перезаписывается при пересборке справочника.' % ', '.join(versions), '',
                   'Имя подсистемы в документации и имя модуля в коде совпадают не всегда: механизм '
                   'печати живет в `УправлениеПечатью`, свойства - в `УправлениеСвойствами`, а базовая '
                   'функциональность - в `ОбщегоНазначения`. Поэтому модуль ищется по этой таблице, а не '
                   'по названию подсистемы.', '',
                   'Цифра в скобках - сколько методов подсистемы объявлено в этом модуле.', '',
                   '| Подсистема | Программный интерфейс | Точки расширения |', '|---|---|---|']
          for sub in sorted(by_sub, key=lambda s: (-sum(by_sub[s].values()), s)):
              mods = by_sub[sub]
              api = [m for m in mods if 'Переопределяем' not in m and m != '?']
              ext = [m for m in mods if 'Переопределяем' in m]
              api.sort(key=lambda m: (-mods[m], m))
              ext.sort(key=lambda m: (-mods[m], m))
              lines.append('| %s | %s | %s |' % (sub, map_cell(api, mods), map_cell(ext, mods)))
          lines.append('')
          with io.open(path, 'w', encoding='utf-8', newline='\n') as fh:
              fh.write('\n'.join(lines))
      
      
      def map_cell(mods, counts, top=10):
          """Ячейка карты. В крупных подсистемах модулей десятки, и целиком они превращают строку
          таблицы в простыню. Перечисляются те, где методов больше; остальные считаются, а полный
          состав дает scripts/bsp-api.py subsystem."""
          if not mods:
              return '-'
          head = ', '.join('`%s` (%d)' % (m, counts[m]) for m in mods[:top])
          rest = len(mods) - top
          return head + (', и еще %d' % rest if rest > 0 else '')
      
      
      if __name__ == '__main__':
          main()
      
  • SKILL.md 14.7 KB
    ---
    name: 1c-bsp-api
    description: "Справочник программного интерфейса Библиотеки стандартных подсистем (БСП) 1С - какие общие модули существуют, какие у них экспортные методы, сигнатуры, типы параметров, контексты выполнения и переопределяемые обработчики. Используй когда пишешь код на конфигурации с БСП и нужно узнать имя модуля или метода, его сигнатуру, серверный он или клиентский, какой переопределяемый обработчик реализовать под задачу; а также чтобы ПРОВЕРИТЬ вызов перед тем, как его написать: имя модуля БСП, отсутствующее в библиотеке, по виду не отличается от настоящего, поэтому вызов сверяется со справочником. Работает офлайн, платформа и EDT не нужны. НЕ для API самой платформы (там 1c-platform-docs) и НЕ для прикладных конфигураций ERP, ЗУП, БП"
    argument-hint: "find <текст> | show <Модуль.Метод> | check <Модуль.Метод> | module <Имя> | subsystem <Имя> | overrides <текст>"
    allowed-tools:
      - Bash
      - Read
    ---
    
    # Справочник API БСП
    
    Офлайн-справочник по программному интерфейсу БСП: 2624 метода в 284 модулях, 71 подсистема,
    версии 3.1.11 и 3.2.1. Собран из двух источников одновременно - структура и сигнатуры из
    документации, модули и экспортность из самой библиотеки. Каждая версия документации сведена со
    своим дистрибутивом, поэтому различия между версиями видны, а не усреднены.
    
    Назначение написано нами: одна строка у каждого из 284 модулей и у 440 методов ядра. Описательный
    текст документации ИТС в справочник не переносится.
    
    Справочник больше мегабайта, в контекст целиком не грузится. Он спрашивается по месту.
    
    ## Главное правило
    
    **Не пиши вызов метода БСП, не проверив его.** Имена в БСП длинные и составные, поэтому
    правдоподобная выдумка выглядит как настоящее имя. Классические несуществующие:
    `ФайловаяСистемаКлиентСервер`, `JSONСтрокой`, `Пользователи.СсылкаТекущегоПользователя`.
    
    ```bash
    python skills/1c-bsp-api/scripts/bsp-api.py check ФайловаяСистемаКлиентСервер.ПолучитьФайл
    ```
    
    Код возврата 1, если вызова нет. При промахе инструмент подсказывает похожие имена - и по
    модулю, и по методу.
    
    ## Как устроена библиотека
    
    **Суффикс имени модуля - это контекст выполнения, а не тематика.** Один механизм разложен по
    нескольким модулям, и выбор между ними определяется тем, откуда идет вызов:
    
    | Суффикс | Где исполняется | Пример |
    |---|---|---|
    | без суффикса или `Сервер` | сервер, толстый клиент, внешнее соединение | `ОбщегоНазначения` |
    | `Клиент` | тонкий и толстый клиент | `ОбщегоНазначенияКлиент` |
    | `КлиентСервер` | и там, и там | `ОбщегоНазначенияКлиентСервер` |
    | `ВызовСервера` | сервер, вызывается с клиента напрямую | `ОбщегоНазначенияВызовСервера` |
    
    Отсюда частая ошибка: серверный метод вызывают из клиентского кода. Контекст каждого метода есть
    в справочнике, отбор - ключом `--av` (`S` сервер, `T` тонкий, `F` толстый, `E` внешнее
    соединение, `C` вызов сервера).
    
    **Три вида модулей по назначению:**
    
    - **Обычные** - публичный интерфейс, их и вызывают: `ОбщегоНазначения`, `Пользователи`,
      `УправлениеПечатью`.
    - **`Переопределяемый`** - точки расширения. Их не вызывают, в них ПИШУТ: обработчик вызывает
      библиотека, а тело пишет внедряющая конфигурация. Таких методов 372.
    - **`Служебный`** - внутренняя реализация библиотеки. В программный интерфейс не входит ни один
      служебный метод, и вызывать их нельзя: они меняются между версиями без объявления.
    
    Еще два суффикса встречаются реже: `ПовтИсп` - модуль с повторным использованием возвращаемых
    значений, `Локализация` - национальная специфика.
    
    **Часть интерфейса объявлена не в общих модулях.** Обмен данными опубликован модулями объектов
    обработок (`Обработка.УниверсальныйОбменДаннымиXML`, `Обработка.КонвертацияОбъектовXDTO`).
    В справочнике они есть наравне с общими модулями.
    
    ## Запросы
    
    ```bash
    B=skills/1c-bsp-api/scripts/bsp-api.py
    
    python $B find печать                      # поиск по имени, модулю, подсистеме, назначению
    python $B find "реквизит объект"           # ищутся все слова запроса сразу, не подстрока
    python $B find файл --av T                 # только то, что доступно на тонком клиенте
    python $B show ОбщегоНазначения.ЗначениеРеквизитаОбъекта   # карточка метода
    python $B show ЗначениеРеквизитаОбъекта    # все модули, где есть метод с таким именем
    python $B module Пользователи              # состав модуля целиком
    python $B modules контакт                  # какие вообще есть модули
    python $B subsystem печать                 # модули и механизмы подсистемы
    python $B overrides обновлен               # переопределяемые обработчики под задачу
    python $B check Пользователи.ТекущийПользователь
    python $B stats                            # что вообще в справочнике
    ```
    
    Общие ключи отбора: `--av`, `--sub <подсистема>`, `--version 3.2.1`, `--limit N`.
    
    ## Как читать выдачу
    
    Строка вида `ОбщегоНазначения.ЗначениеРеквизитаОбъекта   SFE` - это модуль, метод и контексты.
    
    **Пометка `[?]` означает, что модуль выведен, а не подтвержден.** Документация БСП называет
    механизм, а не модуль, поэтому у части методов модуль восстановлен по примеру вызова или по
    совпадению контекстов. В карточке (`show`) последняя строка всегда говорит, откуда взято имя
    модуля. Метод с пометкой перед использованием стоит сверить с конфигурацией проекта.
    
    Пометка стоит у 117 методов из 2624, это около четырех процентов. Еще у 37 модуль определить
    не удалось вовсе - они собраны под именем `?`. Это не значит, что метода нет: значит, одно и то же
    имя объявлено в нескольких модулях, и документация не говорит, о каком из них статья.
    
    **Пометка `[!]` означает, что между версиями метод изменился.** Карточка тогда содержит строку
    "ВНИМАНИЕ, в <версия> иначе" с прежней сигнатурой. Таких методов 27, и часть изменений ломающие:
    `ОбщегоНазначения.ВыполнитьМетодКонфигурации` из процедуры стал функцией, а у
    `ДобавитьПоказатель` новый параметр вставлен не в конец, а первым. Код, написанный по новой
    сигнатуре, на старой версии передаст аргументы не туда и об этом не сообщит.
    
    ## Частые ошибки
    
    - **Выдуманный модуль.** Проверять `check`, а не полагаться на память.
    - **Серверный метод в клиентском коде.** Смотреть контексты; для клиента почти всегда есть
      парный модуль с суффиксом `Клиент`.
    - **Вызов служебного модуля.** Если в имени есть `Служебный` - это не интерфейс.
    - **Попытка вызвать переопределяемый обработчик.** В него пишут тело, а не вызывают его.
    - **Метод из другой версии.** У каждой записи указано, в каких версиях БСП она есть. Метод,
      помеченный только `3.2.1`, на 3.1.11 не существует. А метод с пометкой `[!]` существует в обеих,
      но вызывается по-разному - смотреть карточку до того, как писать вызов.
    - **Расчет на то, что у метода тот же набор параметров, что был раньше.** Сигнатура в
      справочнике полная, включая значения по умолчанию - брать оттуда.
    
    ## Границы
    
    Справочник знает ИМЕНА, СИГНАТУРЫ и КОНТЕКСТЫ, а назначение - строкой, написанной нами. Развернутого
    описания в нем нет: текст документации ИТС лицензионный и сюда не переносится. Строка назначения есть
    у каждого модуля, но у методов пока только у ядра - базовых модулей `ОбщегоНазначения*`, длительных
    операций, пользователей, строковых функций, файловой системы и журнала регистрации. Когда нужно
    понять механизм глубже, а не форму вызова - идти в документацию ИТС по подсистеме, которую покажет
    `subsystem`.
    
    Не покрыты: HTTP-сервисы и веб-сервисы библиотеки, макеты, роли, права, состав метаданных
    подсистем. Только программный интерфейс кода.
    
    ## Сборка справочника
    
    Готовый справочник лежит в `references/bsp-api.jsonl` и обновлять его нужно только при переходе
    на новую версию БСП. Пересборка требует двух источников, оба лицензионные и в репозиторий не
    входят: скрапа документации с ИТС и дистрибутива библиотеки.
    
    ```bash
    python -m v8unpack -E 1Cv8.cf E:\bsp\3_2_1 --temp E:\bsp\_tmp     # распаковать дистрибутив
    python skills/1c-bsp-api/scripts/bsp-build.py \
        --docs "3.1.11=E:\scrape\bsp3111doc" --docs "3.2.1=E:\scrape\bsp321doc" \
        --lib "3.1.11=E:\bsp\3_1_11" --lib "3.2.1=E:\bsp\3_2_1" \
        --purposes skills/1c-bsp-api/references/purposes.json \
        --out skills/1c-bsp-api/references/bsp-api.jsonl \
        --map skills/1c-bsp-api/references/subsystem-map.md
    ```
    
    Формулировки назначения ведутся отдельно, в `references/purposes.json`: раздел `modules` и раздел
    `methods` с ключами вида `Модуль.Метод`. При сборке они подмешиваются в справочник, а имена, которых
    в нем нет, генератор называет в отчете - это ловит и опечатку, и формулировку к методу, которого
    в этой версии уже не существует.
    
    Ключи `--docs` и `--lib` указываются по одному на версию и связываются префиксом. Связывать
    обязательно: если сшивать документацию 3.1.11 с библиотекой 3.2.1, методы, убранные в новой
    версии, будут объявлены несуществующими. Библиотека без префикса версии берется для всех.
    
    Брать надо `1Cv8.cf` - чистую библиотеку, а не `1Cv8_demo.cf`: демонстрационная конфигурация
    несет объекты, которых в поставке нет. Распаковка идет без платформы и Конфигуратора.
    
    Скрипты на Python, PowerShell-порта нет: сборка нужна редко, а поиск идет по готовому файлу.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related