Claude Skill

1c-meta-compile

Создать объект метаданных 1С. Используй когда пользователь просит создать или добавить справочник, документ, регистр, перечисление, константу, общий модуль, обработку, отчёт и др.

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

Full trust report

Download Desko77-claude-code-skills-1c-skills_1c-meta-compile-ac33656.zip · 101 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-meta-compile
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

/meta-compile - генерация объектов метаданных из JSON DSL

Принимает JSON-определение объекта метаданных → генерирует XML + модули в структуре выгрузки конфигурации + регистрирует в Configuration.xml.

Порядок работы

  1. Составь JSON по синтаксису и примерам ниже → запиши во временный файл
  2. Запусти скрипт meta-compile
  3. Если нужно изменить созданный объект - /meta-edit
  4. Если нужно проверить - /meta-validate

Команда

powershell.exe -NoProfile -File skills/1c-meta-compile/scripts/meta-compile.ps1 -JsonPath "<json>" -OutputDir "<ConfigDir>"
Параметр Описание
JsonPath Путь к JSON-файлу (один объект {...} или массив [{...}, ...])
OutputDir Корень выгрузки конфигурации (где Configuration.xml, Catalogs/, Documents/ и т.д.)

JSON DSL

Общая структура

{ "type": "Catalog", "name": "Номенклатура", ...свойства типа... }

type и name - обязательные. synonym генерируется из name автоматически (CamelCase → слова через пробел). Можно задать явно: "synonym": "Мой синоним".

Shorthand реквизитов

Используется в attributes, dimensions, resources, tabularSections:

"ИмяРеквизита"                    → String(10) по умолчанию
"ИмяРеквизита: Тип"               → с типом
"ИмяРеквизита: Тип | req, index"  → с флагами

Типы: String(100), Number(15,2), Boolean, Date, DateTime, CatalogRef.Xxx, DocumentRef.Xxx, EnumRef.Xxx, DefinedType.Xxx и др. ссылочные.

Составной тип: "Значение: String + Number(15,2) + CatalogRef.Контрагенты".

Флаги: req, index, indexAdditional, nonneg, master, mainFilter, denyIncomplete, useInTotals.

Свойства по типам

Примеров и shorthand-синтаксиса выше достаточно для типовых задач. Если нужны свойства типа, не показанные в примерах, и их допустимые значения - см. reference-файл:

  • reference/types-basic.md - Catalog, Document, Enum, Constant, DefinedType, Report, DataProcessor
  • reference/types-registers.md - InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes
  • reference/types-process.md - BusinessProcess, Task, ExchangePlan, CommonModule, ScheduledJob, EventSubscription, DocumentJournal
  • reference/types-web.md - HTTPService, WebService
  • reference/types-config.md - CommonAttribute, CommonCommand, CommandGroup, CommonForm, CommonTemplate, CommonPicture, FilterCriterion, Sequence, DocumentNumerator, SessionParameter, SettingsStorage, FunctionalOption, FunctionalOptionsParameter, WSReference

Эта инструкция и reference-файлы - полная документация для генерации. Не ищи примеры XML в выгрузках конфигураций.

Примеры паттернов DSL

Минимальный объект

{ "type": "Catalog", "name": "Валюты" }

С реквизитами

{
  "type": "Catalog", "name": "Организации",
  "descriptionLength": 100,
  "attributes": ["ИНН: String(12)", "КПП: String(9)", "Директор: CatalogRef.ФизическиеЛица"]
}

С табличной частью

{
  "type": "Document", "name": "ПриходнаяНакладная",
  "registerRecords": ["AccumulationRegister.ОстаткиТоваров"],
  "attributes": ["Организация: CatalogRef.Организации", "Контрагент: CatalogRef.Контрагенты"],
  "tabularSections": { "Товары": ["Номенклатура: CatalogRef.Номенклатура", "Количество: Number(15,3)", "Цена: Number(15,2)"] }
}

Табличная часть задается списком колонок либо объектом, если нужен свой синоним:

"tabularSections": {
  "Товары": { "synonym": "Строки заказа", "attributes": ["Номенклатура: CatalogRef.Номенклатура"] }
}

Поддержаны ключи attributes, synonym и comment. Любой другой ключ навык не применит и скажет об этом предупреждением - молча он их больше не проглатывает.

Регистровый паттерн (измерения + ресурсы)

{
  "type": "InformationRegister", "name": "КурсыВалют", "periodicity": "Day",
  "dimensions": ["Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete"],
  "resources": ["Курс: Number(15,4)", "Кратность: Number(10,0)"]
}

Batch - несколько объектов в одном файле

[
  { "type": "Enum", "name": "Статусы", "values": ["Новый", "Закрыт"] },
  { "type": "Catalog", "name": "Валюты" },
  { "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" }
]
Files (claude-code-skills-1c)
  • docs
    • meta-dsl-spec.md 39.1 KB
      # Meta DSL - спецификация JSON-формата для объектов метаданных 1С
      
      Версия: 2.1
      
      ## Обзор
      
      JSON DSL для описания объектов метаданных конфигурации 1С. Компактный формат компилируется в полноценный XML, совместимый с выгрузкой конфигурации 1С:Предприятие 8.3.
      
      Поддерживаемые типы (23): **Catalog**, **Document**, **Enum**, **Constant**, **InformationRegister**, **AccumulationRegister**, **AccountingRegister**, **CalculationRegister**, **ChartOfAccounts**, **ChartOfCharacteristicTypes**, **ChartOfCalculationTypes**, **BusinessProcess**, **Task**, **ExchangePlan**, **DocumentJournal**, **Report**, **DataProcessor**, **CommonModule**, **ScheduledJob**, **EventSubscription**, **HTTPService**, **WebService**, **DefinedType**.
      
      ---
      
      ## 1. Корневая структура
      
      ```json
      {
        "type": "Catalog",
        "name": "Номенклатура",
        "synonym": "авто из name",
        "comment": "",
        ...type-specific properties...,
        "attributes": [...],
        "tabularSections": {...}
      }
      ```
      
      | Поле | Тип | Обязательное | Описание |
      |------|-----|-------------|----------|
      | `type` | string | да | Тип объекта (см. §8) |
      | `name` | string | да | Имя объекта (идентификатор 1С) |
      | `synonym` | string | нет | Синоним; если не указан - авто из CamelCase (§2) |
      | `comment` | string | нет | Комментарий |
      
      Дополнительные поля зависят от типа (§7).
      
      ---
      
      ## 2. Автогенерация синонима (CamelCase → слова)
      
      Если `synonym` не указан, имя автоматически разбивается на слова:
      
      | Вход | Результат |
      |------|-----------|
      | `АвансовыйОтчет` | `Авансовый отчет` |
      | `ОсновнаяВалюта` | `Основная валюта` |
      | `НДС20` | `НДС20` |
      | `IncomingDocument` | `Incoming document` |
      
      Правила:
      - Граница на переходе `[а-яе][А-ЯЕ]` и `[a-z][A-Z]`
      - Первое слово сохраняет заглавную, остальные - строчные
      - Явный `synonym` перекрывает автогенерацию
      
      ---
      
      ## 3. Система типов
      
      Совместима с skd-compile.
      
      ### 3.1 Примитивные типы
      
      | DSL | XML |
      |-----|-----|
      | `String` или `String(100)` | `xs:string` + StringQualifiers |
      | `Number(15,2)` | `xs:decimal` + NumberQualifiers |
      | `Number(10,0,nonneg)` | `xs:decimal` + AllowedSign=Nonnegative |
      | `Boolean` | `xs:boolean` |
      | `Date` | `xs:dateTime` + DateFractions=Date |
      | `DateTime` | `xs:dateTime` + DateFractions=DateTime |
      
      ### 3.2 Ссылочные типы
      
      | DSL | XML |
      |-----|-----|
      | `CatalogRef.Xxx` | `cfg:CatalogRef.Xxx` |
      | `DocumentRef.Xxx` | `cfg:DocumentRef.Xxx` |
      | `EnumRef.Xxx` | `cfg:EnumRef.Xxx` |
      | `ChartOfAccountsRef.Xxx` | `cfg:ChartOfAccountsRef.Xxx` |
      | `ChartOfCharacteristicTypesRef.Xxx` | `cfg:ChartOfCharacteristicTypesRef.Xxx` |
      | `ChartOfCalculationTypesRef.Xxx` | `cfg:ChartOfCalculationTypesRef.Xxx` |
      | `ExchangePlanRef.Xxx` | `cfg:ExchangePlanRef.Xxx` |
      | `BusinessProcessRef.Xxx` | `cfg:BusinessProcessRef.Xxx` |
      | `TaskRef.Xxx` | `cfg:TaskRef.Xxx` |
      | `DefinedType.Xxx` | `cfg:DefinedType.Xxx` (через `v8:TypeSet`) |
      
      ### 3.3 Русские синонимы типов
      
      | Русский | Канонический |
      |---------|-------------|
      | `Строка(100)` | `String(100)` |
      | `Число(15,2)` | `Number(15,2)` |
      | `Булево` | `Boolean` |
      | `Дата` | `Date` |
      | `ДатаВремя` | `DateTime` |
      | `СправочникСсылка.Xxx` | `CatalogRef.Xxx` |
      | `ДокументСсылка.Xxx` | `DocumentRef.Xxx` |
      | `ПеречислениеСсылка.Xxx` | `EnumRef.Xxx` |
      | `ПланСчетовСсылка.Xxx` | `ChartOfAccountsRef.Xxx` |
      | `ПланВидовХарактеристикСсылка.Xxx` | `ChartOfCharacteristicTypesRef.Xxx` |
      | `ПланВидовРасчетаСсылка.Xxx` | `ChartOfCalculationTypesRef.Xxx` |
      | `ПланОбменаСсылка.Xxx` | `ExchangePlanRef.Xxx` |
      | `БизнесПроцессСсылка.Xxx` | `BusinessProcessRef.Xxx` |
      | `ЗадачаСсылка.Xxx` | `TaskRef.Xxx` |
      | `ОпределяемыйТип.Xxx` | `DefinedType.Xxx` |
      
      Регистронезависимые.
      
      ---
      
      ## 4. Сокращенная запись реквизитов
      
      ### 4.1 Строковая форма
      
      ```
      "ИмяРеквизита"                              → String(10) по умолчанию
      "ИмяРеквизита: Тип"                         → с типом
      "ИмяРеквизита: Тип | req, index"           → с флагами
      ```
      
      ### 4.2 Объектная форма
      
      ```json
      {
        "name": "Имя",
        "type": "String(100)",
        "synonym": "Мой синоним",
        "comment": "Комментарий",
        "fillChecking": "ShowError",
        "indexing": "Index"
      }
      ```
      
      Тип можно задать единой строкой (`"type": "String(100)"`) или раздельными полями:
      
      ```json
      { "name": "Имя", "type": "String", "length": 100 }
      { "name": "Сумма", "type": "Number", "length": 15, "precision": 2 }
      { "name": "Остаток", "type": "Number", "length": 15, "precision": 2, "nonneg": true }
      ```
      
      Раздельная форма эквивалентна `String(100)`, `Number(15,2)`, `Number(15,2,nonneg)`.
      Если `type` уже содержит скобки - `length`/`precision` игнорируются.
      
      ### 4.3 Флаги
      
      | Флаг | Действие | Применимость |
      |------|---------|-------------|
      | `req` | FillChecking = ShowError | attributes, dimensions, resources |
      | `index` | Indexing = Index | attributes, dimensions |
      | `indexAdditional` | Indexing = IndexWithAdditionalOrder | attributes |
      | `multiline` | MultiLine = true | attributes |
      | `nonneg` | MinValue = 0 (+ nonneg для Number) | attributes, resources |
      | `master` | Master = true | dimensions (РС) |
      | `mainFilter` | MainFilter = true | dimensions (РС) |
      | `denyIncomplete` | DenyIncompleteValues = true | dimensions |
      | `useInTotals` | UseInTotals = true | dimensions (РН) |
      
      Флаги разделяются запятой после `|`.
      
      ---
      
      ## 5. Табличные части
      
      Для типов с ChildObjects → TabularSection: Catalog, Document, ExchangePlan, ChartOfCharacteristicTypes, ChartOfCalculationTypes, BusinessProcess, Task, Report, DataProcessor, ChartOfAccounts.
      
      ```json
      "tabularSections": {
        "Товары": [
          "Номенклатура: CatalogRef.Номенклатура | req",
          "Количество: Number(10,3)",
          "Цена: Number(15,2)",
          "Сумма: Number(15,2)"
        ],
        "Услуги": [
          "Описание: String(200)"
        ]
      }
      ```
      
      Ключ - имя табличной части, значение - массив реквизитов (в строковой или объектной форме).
      
      Для Catalog добавляется `<Use>ForItem</Use>` в Properties табличной части. Для Document Use не применяется.
      
      ---
      
      ## 6. Значения перечислений
      
      Только для Enum.
      
      ```json
      "values": [
        "Приход",
        "Расход",
        { "name": "НДС20", "synonym": "НДС 20%" }
      ]
      ```
      
      Строка - имя (синоним авто из CamelCase). Объект - полная форма.
      
      ---
      
      ## 7. Свойства по типам
      
      ### 7.1 Catalog
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `hierarchical` | `false` | Hierarchical |
      | `hierarchyType` | `HierarchyFoldersAndItems` | HierarchyType |
      | `limitLevelCount` | `false` | LimitLevelCount |
      | `levelCount` | `2` | LevelCount |
      | `foldersOnTop` | `true` | FoldersOnTop |
      | `codeLength` | `9` | CodeLength |
      | `codeType` | `String` | CodeType |
      | `codeAllowedLength` | `Variable` | CodeAllowedLength |
      | `codeSeries` | `WholeCatalog` | CodeSeries |
      | `descriptionLength` | `25` | DescriptionLength |
      | `autonumbering` | `true` | Autonumbering |
      | `checkUnique` | `false` | CheckUnique |
      | `defaultPresentation` | `AsDescription` | DefaultPresentation |
      | `subordinationUse` | `ToItems` | SubordinationUse |
      | `quickChoice` | `true` | QuickChoice |
      | `choiceMode` | `BothWays` | ChoiceMode |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `owners` | `[]` | Owners |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      ### 7.2 Document
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `numberType` | `String` | NumberType |
      | `numberLength` | `11` | NumberLength |
      | `numberAllowedLength` | `Variable` | NumberAllowedLength |
      | `numberPeriodicity` | `Year` | NumberPeriodicity |
      | `checkUnique` | `true` | CheckUnique |
      | `autonumbering` | `true` | Autonumbering |
      | `posting` | `Allow` | Posting |
      | `realTimePosting` | `Deny` | RealTimePosting |
      | `registerRecordsDeletion` | `AutoDelete` | RegisterRecordsDeletion |
      | `registerRecordsWritingOnPost` | `WriteModified` | RegisterRecordsWritingOnPost |
      | `postInPrivilegedMode` | `true` | PostInPrivilegedMode |
      | `unpostInPrivilegedMode` | `true` | UnpostInPrivilegedMode |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `registerRecords` | `[]` | RegisterRecords |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      ### 7.3 Enum
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `values` | `[]` | → EnumValue в ChildObjects |
      
      Других настраиваемых свойств нет - все дефолтные.
      
      ### 7.4 Constant
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `valueType` | `String` | Type |
      | `length` | - | Длина строки (если valueType=String) |
      | `precision` | - | Точность числа (если valueType=Number) |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      
      `valueType` + `length`/`precision` работают аналогично раздельной форме типа (§4.2):
      `"valueType": "String", "length": 100` → `String(100)`.
      
      ### 7.5 InformationRegister
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `writeMode` | `Independent` | WriteMode |
      | `periodicity` | `Nonperiodical` | InformationRegisterPeriodicity |
      | `mainFilterOnPeriod` | авто* | MainFilterOnPeriod |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `dimensions` | `[]` | → Dimension в ChildObjects |
      | `resources` | `[]` | → Resource в ChildObjects |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      
      \* `mainFilterOnPeriod` = `true` если `periodicity` != `Nonperiodical`, иначе `false`.
      
      ### 7.6 AccumulationRegister
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `registerType` | `Balance` | RegisterType |
      | `enableTotalsSplitting` | `true` | EnableTotalsSplitting |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `dimensions` | `[]` | → Dimension в ChildObjects |
      | `resources` | `[]` | → Resource в ChildObjects |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      
      ### 7.7 DefinedType
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `valueTypes` | `[]` | Type (составной - массив `v8:Type`) |
      | `valueType` | - | Алиас для `valueTypes` (принимает строку или массив) |
      
      Без ChildObjects и модулей. Принимается как `valueTypes` (мн.ч.), так и `valueType` (ед.ч.).
      
      ```json
      { "type": "DefinedType", "name": "ДенежныеСредства", "valueTypes": ["CatalogRef.БанковскиеСчета", "CatalogRef.Кассы"] }
      { "type": "DefinedType", "name": "ФлагАктивности", "valueType": "Boolean" }
      ```
      
      ### 7.8 CommonModule
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `context` | - | Шорткат (см. ниже) |
      | `global` | `false` | Global |
      | `server` | `false` | Server |
      | `serverCall` | `false` | ServerCall |
      | `clientManagedApplication` | `false` | ClientManagedApplication |
      | `clientOrdinaryApplication` | `false` | ClientOrdinaryApplication |
      | `externalConnection` | `false` | ExternalConnection |
      | `privileged` | `false` | Privileged |
      | `returnValuesReuse` | `DontUse` | ReturnValuesReuse |
      
      Шорткаты `context`:
      - `"server"` → Server=true, ServerCall=true
      - `"client"` → ClientManagedApplication=true
      - `"serverClient"` → Server=true, ClientManagedApplication=true
      
      Модуль: `Ext/Module.bsl` (пустой).
      
      ```json
      { "type": "CommonModule", "name": "ОбменДаннымиСервер", "context": "server", "returnValuesReuse": "DuringRequest" }
      ```
      
      ### 7.9 ScheduledJob
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `methodName` | `""` | MethodName (авто-префикс `CommonModule.`) |
      | `description` | = synonym | Description |
      | `key` | `""` | Key |
      | `use` | `false` | Use |
      | `predefined` | `false` | Predefined |
      | `restartCountOnFailure` | `3` | RestartCountOnFailure |
      | `restartIntervalOnFailure` | `10` | RestartIntervalOnFailure |
      
      Без ChildObjects и модулей.
      
      Формат `methodName`: `"МодульСервер.Процедура"` - при компиляции авто-дополняется до `CommonModule.МодульСервер.Процедура`. Если уже содержит `CommonModule.` - оставляется как есть.
      
      ```json
      { "type": "ScheduledJob", "name": "ОбменДанными", "methodName": "ОбменДаннымиСервер.Выполнить", "use": true }
      ```
      
      ### 7.10 EventSubscription
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `source` | `[]` | Source (массив `v8:Type`, формат `cfg:XxxObject.Name`) |
      | `event` | `BeforeWrite` | Event |
      | `handler` | `""` | Handler (авто-префикс `CommonModule.`) |
      
      Без ChildObjects и модулей.
      
      Значения `event`: `BeforeWrite`, `OnWrite`, `BeforeDelete`, `OnReadAtServer`, `FillCheckProcessing` и др.
      
      Формат `handler`: `"МодульСервер.Процедура"` - при компиляции авто-дополняется до `CommonModule.МодульСервер.Процедура`. Если уже содержит `CommonModule.` - оставляется как есть.
      
      ```json
      { "type": "EventSubscription", "name": "ПередЗаписьюКонтрагента", "source": ["CatalogObject.Контрагенты"], "event": "BeforeWrite", "handler": "ОбщегоНазначенияСервер.ПередЗаписьюКонтрагента" }
      ```
      
      ### 7.11 Report
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `defaultForm` | `""` | DefaultForm |
      | `auxiliaryForm` | `""` | AuxiliaryForm |
      | `mainDataCompositionSchema` | `""` | MainDataCompositionSchema |
      | `defaultSettingsForm` | `""` | DefaultSettingsForm |
      | `auxiliarySettingsForm` | `""` | AuxiliarySettingsForm |
      | `defaultVariantForm` | `""` | DefaultVariantForm |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      Модули: `Ext/ObjectModule.bsl` (пустой).
      
      ```json
      { "type": "Report", "name": "ОстаткиТоваров", "attributes": ["НачалоПериода: Date", "КонецПериода: Date"] }
      ```
      
      ### 7.12 DataProcessor
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `defaultForm` | `""` | DefaultForm |
      | `auxiliaryForm` | `""` | AuxiliaryForm |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      Модули: `Ext/ObjectModule.bsl` (пустой).
      
      ```json
      { "type": "DataProcessor", "name": "ЗагрузкаДанных", "attributes": ["ПутьКФайлу: String(500)"] }
      ```
      
      ### 7.13 ExchangePlan
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `codeLength` | `9` | CodeLength |
      | `codeAllowedLength` | `Variable` | CodeAllowedLength |
      | `descriptionLength` | `100` | DescriptionLength |
      | `distributedInfoBase` | `false` | DistributedInfoBase |
      | `includeConfigurationExtensions` | `false` | IncludeConfigurationExtensions |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      Модули: `Ext/ObjectModule.bsl` (пустой).
      Дополнительно: `Ext/Content.xml` (пустой шаблон).
      
      ```json
      { "type": "ExchangePlan", "name": "ОбменССайтом", "attributes": ["АдресСервера: String(200)"] }
      ```
      
      ### 7.14 ChartOfCharacteristicTypes
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `codeLength` | `9` | CodeLength |
      | `codeType` | `String` | CodeType |
      | `codeAllowedLength` | `Variable` | CodeAllowedLength |
      | `descriptionLength` | `25` | DescriptionLength |
      | `autonumbering` | `true` | Autonumbering |
      | `checkUnique` | `false` | CheckUnique |
      | `characteristicExtValues` | `""` | CharacteristicExtValues |
      | `valueTypes` | авто* | Type (составной тип значений характеристик) |
      | `hierarchical` | `false` | Hierarchical |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      \* Если `valueTypes` не указан, по умолчанию: Boolean, String(100), Number(15,2), DateTime.
      
      Модули: `Ext/ObjectModule.bsl` (пустой).
      
      ```json
      {
        "type": "ChartOfCharacteristicTypes", "name": "ВидыСубконто",
        "valueTypes": ["CatalogRef.Номенклатура", "CatalogRef.Контрагенты", "Boolean", "String", "Number(15,2)"]
      }
      ```
      
      ### 7.15 DocumentJournal
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `defaultForm` | `""` | DefaultForm |
      | `auxiliaryForm` | `""` | AuxiliaryForm |
      | `registeredDocuments` | `[]` | RegisteredDocuments |
      | `columns` | `[]` | → Column в ChildObjects |
      
      Без модулей.
      
      DSL для `registeredDocuments` - массив строк `"Document.ИмяДокумента"` (или русский `"Документ.ИмяДокумента"`).
      
      DSL для `columns` (§12).
      
      ```json
      {
        "type": "DocumentJournal", "name": "Взаимодействия",
        "registeredDocuments": ["Document.Встреча", "Document.ТелефонныйЗвонок"],
        "columns": [{ "name": "Организация", "indexing": "Index", "references": ["Document.Встреча.Attribute.Организация"] }]
      }
      ```
      
      ### 7.16 ChartOfAccounts
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `extDimensionTypes` | `""` | ExtDimensionTypes (ссылка на ПВХ) |
      | `maxExtDimensionCount` | `3` | MaxExtDimensionCount |
      | `codeMask` | `""` | CodeMask |
      | `codeLength` | `8` | CodeLength |
      | `descriptionLength` | `120` | DescriptionLength |
      | `codeSeries` | `WholeChartOfAccounts` | CodeSeries |
      | `autoOrderByCode` | `true` | AutoOrderByCode |
      | `orderLength` | `5` | OrderLength |
      | `hierarchical` | `false` | Hierarchical |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `accountingFlags` | `[]` | → AccountingFlag в ChildObjects (§13) |
      | `extDimensionAccountingFlags` | `[]` | → ExtDimensionAccountingFlag в ChildObjects (§14) |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      Модули: `Ext/ObjectModule.bsl` (пустой).
      
      ```json
      {
        "type": "ChartOfAccounts", "name": "Хозрасчетный",
        "extDimensionTypes": "ChartOfCharacteristicTypes.ВидыСубконто", "maxExtDimensionCount": 3,
        "codeMask": "@@@.@@.@", "codeLength": 8,
        "accountingFlags": ["Валютный", "Количественный"],
        "extDimensionAccountingFlags": ["Суммовой", "Валютный"]
      }
      ```
      
      ### 7.17 AccountingRegister
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `chartOfAccounts` | `""` | ChartOfAccounts (ссылка на план счетов) |
      | `correspondence` | `false` | Correspondence |
      | `periodAdjustmentLength` | `0` | PeriodAdjustmentLength |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `dimensions` | `[]` | → Dimension в ChildObjects |
      | `resources` | `[]` | → Resource в ChildObjects |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      
      Модули: `Ext/RecordSetModule.bsl` (пустой).
      
      ```json
      {
        "type": "AccountingRegister", "name": "Хозрасчетный",
        "chartOfAccounts": "ChartOfAccounts.Хозрасчетный", "correspondence": true,
        "dimensions": ["Организация: CatalogRef.Организации"],
        "resources": ["Сумма: Number(15,2)"]
      }
      ```
      
      ### 7.18 ChartOfCalculationTypes
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `codeLength` | `9` | CodeLength |
      | `codeType` | `String` | CodeType |
      | `codeAllowedLength` | `Variable` | CodeAllowedLength |
      | `descriptionLength` | `25` | DescriptionLength |
      | `autonumbering` | `true` | Autonumbering |
      | `checkUnique` | `false` | CheckUnique |
      | `dependenceOnCalculationTypes` | `NotUsed` | DependenceOnCalculationTypes |
      | `baseCalculationTypes` | `[]` | BaseCalculationTypes |
      | `actionPeriodUse` | `false` | ActionPeriodUse |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      Значения `dependenceOnCalculationTypes`: `NotUsed`, `ExclusionAndDependence`, `ExclusionOnly`.
      
      Модули: `Ext/ObjectModule.bsl` (пустой).
      
      ```json
      {
        "type": "ChartOfCalculationTypes", "name": "Начисления",
        "dependenceOnCalculationTypes": "ExclusionAndDependence",
        "actionPeriodUse": true
      }
      ```
      
      ### 7.19 CalculationRegister
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `chartOfCalculationTypes` | `""` | ChartOfCalculationTypes (ссылка на ПВР) |
      | `periodicity` | `Month` | Periodicity |
      | `actionPeriod` | `false` | ActionPeriod |
      | `basePeriod` | `false` | BasePeriod |
      | `schedule` | `""` | Schedule (ссылка на РС графиков) |
      | `scheduleValue` | `""` | ScheduleValue |
      | `scheduleDate` | `""` | ScheduleDate |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `dimensions` | `[]` | → Dimension в ChildObjects |
      | `resources` | `[]` | → Resource в ChildObjects |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      
      Модули: `Ext/RecordSetModule.bsl` (пустой).
      
      ```json
      {
        "type": "CalculationRegister", "name": "Начисления",
        "chartOfCalculationTypes": "ChartOfCalculationTypes.Начисления",
        "periodicity": "Month", "actionPeriod": true, "basePeriod": true,
        "dimensions": ["Сотрудник: CatalogRef.Сотрудники"],
        "resources": ["Сумма: Number(15,2)", "Дни: Number(3,0)"]
      }
      ```
      
      ### 7.20 BusinessProcess
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `editType` | `InDialog` | EditType |
      | `numberType` | `String` | NumberType |
      | `numberLength` | `11` | NumberLength |
      | `numberAllowedLength` | `Variable` | NumberAllowedLength |
      | `checkUnique` | `true` | CheckUnique |
      | `autonumbering` | `true` | Autonumbering |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `task` | `""` | Task (ссылка на Task.XXX) |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      Модули: `Ext/ObjectModule.bsl` (пустой).
      Дополнительно: `Ext/Flowchart.xml` (заглушка карты маршрута).
      
      ```json
      { "type": "BusinessProcess", "name": "Задание", "task": "Task.ЗадачаИсполнителя", "attributes": ["Описание: String(200)"] }
      ```
      
      ### 7.21 Task
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `numberType` | `String` | NumberType |
      | `numberLength` | `14` | NumberLength |
      | `numberAllowedLength` | `Variable` | NumberAllowedLength |
      | `checkUnique` | `true` | CheckUnique |
      | `autonumbering` | `true` | Autonumbering |
      | `taskNumberAutoPrefix` | `BusinessProcessNumber` | TaskNumberAutoPrefix |
      | `descriptionLength` | `150` | DescriptionLength |
      | `addressing` | `""` | Addressing (ссылка на РС адресации) |
      | `mainAddressingAttribute` | `""` | MainAddressingAttribute |
      | `currentPerformer` | `""` | CurrentPerformer |
      | `dataLockControlMode` | `Automatic` | DataLockControlMode |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      | `addressingAttributes` | `[]` | → AddressingAttribute в ChildObjects (§15) |
      
      Модули: `Ext/ObjectModule.bsl` (пустой).
      
      ```json
      {
        "type": "Task", "name": "ЗадачаИсполнителя", "descriptionLength": 200,
        "addressing": "InformationRegister.АдресацияЗадач",
        "addressingAttributes": [{ "name": "Исполнитель", "type": "CatalogRef.Пользователи", "addressingDimension": "InformationRegister.АдресацияЗадач.Dimension.Исполнитель" }]
      }
      ```
      
      ### 7.22 HTTPService
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `rootURL` | = имя (lowercase) | RootURL |
      | `reuseSessions` | `DontUse` | ReuseSessions |
      | `sessionMaxAge` | `20` | SessionMaxAge |
      | `urlTemplates` | `{}` | → URLTemplate в ChildObjects (§16) |
      
      Модули: `Ext/Module.bsl` (пустой).
      
      ```json
      {
        "type": "HTTPService", "name": "API", "rootURL": "api",
        "urlTemplates": {
          "Users": { "template": "/v1/users", "methods": { "Get": "GET", "Create": "POST" } }
        }
      }
      ```
      
      ### 7.23 WebService
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `namespace` | `""` | Namespace |
      | `xdtoPackages` | `""` | XDTOPackages |
      | `reuseSessions` | `DontUse` | ReuseSessions |
      | `sessionMaxAge` | `20` | SessionMaxAge |
      | `operations` | `{}` | → Operation в ChildObjects (§17) |
      
      Модули: `Ext/Module.bsl` (пустой).
      
      ```json
      {
        "type": "WebService", "name": "DataExchange", "namespace": "http://www.1c.ru/DataExchange",
        "operations": {
          "TestConnection": {
            "returnType": "xs:boolean",
            "handler": "ПроверкаПодключения",
            "parameters": { "ErrorMessage": { "type": "xs:string", "direction": "Out" } }
          }
        }
      }
      ```
      
      ---
      
      ## 8. Русские синонимы типов объектов
      
      | Русский | Канонический |
      |---------|-------------|
      | `Справочник` | `Catalog` |
      | `Документ` | `Document` |
      | `Перечисление` | `Enum` |
      | `Константа` | `Constant` |
      | `РегистрСведений` | `InformationRegister` |
      | `РегистрНакопления` | `AccumulationRegister` |
      | `РегистрБухгалтерии` | `AccountingRegister` |
      | `РегистрРасчета` | `CalculationRegister` |
      | `ПланСчетов` | `ChartOfAccounts` |
      | `ПланВидовХарактеристик` | `ChartOfCharacteristicTypes` |
      | `ПланВидовРасчета` | `ChartOfCalculationTypes` |
      | `БизнесПроцесс` | `BusinessProcess` |
      | `Задача` | `Task` |
      | `ПланОбмена` | `ExchangePlan` |
      | `ЖурналДокументов` | `DocumentJournal` |
      | `Отчет` | `Report` |
      | `Обработка` | `DataProcessor` |
      | `ОбщийМодуль` | `CommonModule` |
      | `РегламентноеЗадание` | `ScheduledJob` |
      | `ПодпискаНаСобытие` | `EventSubscription` |
      | `HTTPСервис` | `HTTPService` |
      | `ВебСервис` | `WebService` |
      | `ОпределяемыйТип` | `DefinedType` |
      
      ---
      
      ## 9. RegisterRecords для документов
      
      ```json
      "registerRecords": [
        "AccumulationRegister.Продажи",
        "InformationRegister.Цены"
      ]
      ```
      
      Или с русскими синонимами: `"РегистрНакопления.Продажи"`.
      
      ---
      
      ## 10. Измерения и ресурсы регистров
      
      Синтаксис аналогичен реквизитам (§4), но с дополнительными флагами:
      
      ### Измерения (dimensions)
      
      ```json
      "dimensions": [
        "Организация: CatalogRef.Организации | master, mainFilter, denyIncomplete",
        "Номенклатура: CatalogRef.Номенклатура"
      ]
      ```
      
      ### Ресурсы (resources)
      
      ```json
      "resources": [
        "Количество: Number(15,3)",
        "Сумма: Number(15,2)"
      ]
      ```
      
      Флаг `useInTotals` - только для измерений AccumulationRegister (по умолчанию `true`).
      
      Применимо к: InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister.
      
      ---
      
      ## 11. Примеры
      
      ### Минимальные
      
      ```json
      { "type": "Catalog", "name": "Валюты" }
      ```
      
      ```json
      { "type": "Enum", "name": "Статусы", "values": ["Новый", "Закрыт"] }
      ```
      
      ```json
      { "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" }
      ```
      
      ### Справочник с реквизитами и табличной частью
      
      ```json
      {
        "type": "Catalog",
        "name": "Номенклатура",
        "codeLength": 11,
        "descriptionLength": 100,
        "hierarchical": true,
        "attributes": [
          "Артикул: String(25)",
          "ЕдиницаИзмерения: CatalogRef.ЕдиницыИзмерения | req",
          "ВидНоменклатуры: EnumRef.ВидыНоменклатуры",
          "Цена: Number(15,2)"
        ],
        "tabularSections": {
          "Штрихкоды": [
            "Штрихкод: String(200) | req, index"
          ]
        }
      }
      ```
      
      ### Документ с движениями
      
      ```json
      {
        "type": "Document",
        "name": "РеализацияТоваров",
        "posting": "Allow",
        "registerRecords": ["AccumulationRegister.Продажи"],
        "attributes": [
          "Организация: CatalogRef.Организации | req",
          "Контрагент: CatalogRef.Контрагенты | req",
          "Склад: CatalogRef.Склады"
        ],
        "tabularSections": {
          "Товары": [
            "Номенклатура: CatalogRef.Номенклатура | req",
            "Количество: Number(15,3)",
            "Цена: Number(15,2)",
            "Сумма: Number(15,2)"
          ]
        }
      }
      ```
      
      ### Регистр сведений с периодичностью
      
      ```json
      {
        "type": "InformationRegister",
        "name": "КурсыВалют",
        "periodicity": "Day",
        "dimensions": [
          "Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete"
        ],
        "resources": [
          "Курс: Number(15,4)",
          "Кратность: Number(10,0)"
        ]
      }
      ```
      
      ### Регистр накопления
      
      ```json
      {
        "type": "AccumulationRegister",
        "name": "ОстаткиТоваров",
        "registerType": "Balance",
        "dimensions": [
          "Номенклатура: CatalogRef.Номенклатура",
          "Склад: CatalogRef.Склады"
        ],
        "resources": [
          "Количество: Number(15,3)"
        ]
      }
      ```
      
      ### Определяемый тип
      
      ```json
      { "type": "DefinedType", "name": "ДенежныеСредства", "valueTypes": ["CatalogRef.БанковскиеСчета", "CatalogRef.Кассы"] }
      ```
      
      ### Общий модуль
      
      ```json
      { "type": "CommonModule", "name": "ОбменДаннымиСервер", "context": "server", "returnValuesReuse": "DuringRequest" }
      ```
      
      ### План обмена
      
      ```json
      { "type": "ExchangePlan", "name": "ОбменССайтом", "attributes": ["АдресСервера: String(200)"] }
      ```
      
      ### Журнал документов
      
      ```json
      {
        "type": "DocumentJournal", "name": "Взаимодействия",
        "registeredDocuments": ["Document.Встреча", "Document.ТелефонныйЗвонок"],
        "columns": [{ "name": "Организация", "indexing": "Index", "references": ["Document.Встреча.Attribute.Организация"] }]
      }
      ```
      
      ### План счетов
      
      ```json
      {
        "type": "ChartOfAccounts", "name": "Хозрасчетный",
        "extDimensionTypes": "ChartOfCharacteristicTypes.ВидыСубконто", "maxExtDimensionCount": 3,
        "codeMask": "@@@.@@.@", "codeLength": 8,
        "accountingFlags": ["Валютный", "Количественный"],
        "extDimensionAccountingFlags": ["Суммовой", "Валютный"]
      }
      ```
      
      ### HTTP-сервис
      
      ```json
      {
        "type": "HTTPService", "name": "API", "rootURL": "api",
        "urlTemplates": {
          "Users": { "template": "/v1/users", "methods": { "Get": "GET", "Create": "POST" } }
        }
      }
      ```
      
      ### Веб-сервис
      
      ```json
      {
        "type": "WebService", "name": "DataExchange", "namespace": "http://www.1c.ru/DataExchange",
        "operations": {
          "TestConnection": {
            "returnType": "xs:boolean",
            "handler": "ПроверкаПодключения",
            "parameters": { "ErrorMessage": { "type": "xs:string", "direction": "Out" } }
          }
        }
      }
      ```
      
      ### Бизнес-процесс
      
      ```json
      { "type": "BusinessProcess", "name": "Задание", "task": "Task.ЗадачаИсполнителя", "attributes": ["Описание: String(200)"] }
      ```
      
      ### Задача
      
      ```json
      {
        "type": "Task", "name": "ЗадачаИсполнителя", "descriptionLength": 200,
        "addressing": "InformationRegister.АдресацияЗадач",
        "addressingAttributes": [{ "name": "Исполнитель", "type": "CatalogRef.Пользователи" }]
      }
      ```
      
      ---
      
      ## 12. Графы журнала документов (columns)
      
      Только для DocumentJournal.
      
      ### Строковая форма
      
      ```json
      "columns": ["Организация", "Контрагент"]
      ```
      
      Создает графу без ссылок, без индексации.
      
      ### Объектная форма
      
      ```json
      "columns": [
        {
          "name": "Организация",
          "synonym": "Организация",
          "indexing": "Index",
          "references": [
            "Document.Встреча.Attribute.Организация",
            "Document.ТелефонныйЗвонок.Attribute.Организация"
          ]
        }
      ]
      ```
      
      | Поле | Умолчание | Описание |
      |------|----------|----------|
      | `name` | - | Имя графы (обязательное) |
      | `synonym` | авто | Синоним |
      | `indexing` | `DontIndex` | `DontIndex` / `Index` |
      | `references` | `[]` | Ссылки на реквизиты регистрируемых документов |
      
      ---
      
      ## 13. Признаки учета (accountingFlags)
      
      Только для ChartOfAccounts.
      
      ```json
      "accountingFlags": ["Валютный", "Количественный"]
      ```
      
      Массив имен. Каждый признак - Boolean-тип. Синоним авто из CamelCase.
      
      ---
      
      ## 14. Признаки учета субконто (extDimensionAccountingFlags)
      
      Только для ChartOfAccounts.
      
      ```json
      "extDimensionAccountingFlags": ["Суммовой", "Валютный"]
      ```
      
      Аналогично accountingFlags, но применяется к субконто (ExtDimensionTypes).
      
      ---
      
      ## 15. Реквизиты адресации (addressingAttributes)
      
      Только для Task.
      
      ### Строковая форма
      
      ```json
      "addressingAttributes": ["Исполнитель"]
      ```
      
      ### Объектная форма
      
      ```json
      "addressingAttributes": [
        {
          "name": "Исполнитель",
          "type": "CatalogRef.Пользователи",
          "addressingDimension": "InformationRegister.АдресацияЗадач.Dimension.Исполнитель"
        }
      ]
      ```
      
      | Поле | Умолчание | Описание |
      |------|----------|----------|
      | `name` | - | Имя реквизита (обязательное) |
      | `type` | `String` | Тип значения |
      | `synonym` | авто | Синоним |
      | `addressingDimension` | `""` | Ссылка на измерение регистра адресации |
      
      ---
      
      ## 16. URL-шаблоны HTTP-сервиса (urlTemplates)
      
      Только для HTTPService.
      
      ```json
      "urlTemplates": {
        "Users": {
          "template": "/v1/users",
          "methods": {
            "Get": "GET",
            "Create": "POST"
          }
        }
      }
      ```
      
      Ключ - имя шаблона. Значение - объект:
      
      | Поле | Умолчание | Описание |
      |------|----------|----------|
      | `template` | `/{name}` | URL-шаблон (строка) |
      | `methods` | `{}` | Имя метода → HTTP-метод (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`) |
      
      Обработчик метода авто: `{TemplateName}{MethodName}` (напр. `UsersGet`).
      
      Если значение - строка, интерпретируется как `template` без методов.
      
      ---
      
      ## 17. Операции веб-сервиса (operations)
      
      Только для WebService.
      
      ```json
      "operations": {
        "TestConnection": {
          "returnType": "xs:boolean",
          "handler": "ПроверкаПодключения",
          "nillable": false,
          "transactioned": false,
          "parameters": {
            "ErrorMessage": {
              "type": "xs:string",
              "nillable": true,
              "direction": "Out"
            }
          }
        }
      }
      ```
      
      Ключ - имя операции. Значение - объект:
      
      | Поле | Умолчание | Описание |
      |------|----------|----------|
      | `returnType` | `xs:string` | XDTO-тип возвращаемого значения |
      | `handler` | = имя операции | Имя процедуры-обработчика |
      | `nillable` | `false` | Может ли возвращать null |
      | `transactioned` | `false` | Выполняется в транзакции |
      | `parameters` | `{}` | Параметры операции |
      
      Если значение - строка, интерпретируется как `returnType`.
      
      ### Параметры операции
      
      | Поле | Умолчание | Описание |
      |------|----------|----------|
      | `type` | `xs:string` | XDTO-тип параметра |
      | `nillable` | `true` | Может ли быть null |
      | `direction` | `In` | Направление: `In` / `Out` / `InOut` |
      
      Если значение - строка, интерпретируется как `type`.
      
  • evals
    • evals.json 3.4 KB
      {
        "skill_name": "1c-meta-compile",
        "evals": [
          {
            "id": 1,
            "prompt": "Создай справочник Контрагенты с реквизитами ИНН (строка 12), КПП (строка 9), ЮридическийАдрес (строка 255). Выгрузка конфигурации в папке src/.",
            "expected_output": "В папке src/Catalogs/Контрагенты/ созданы XML-файлы (Catalog.xml, Ext/ObjectModule.bsl и др.), справочник зарегистрирован в src/Configuration.xml.",
            "expectations": [
              "Скрипт meta-compile.ps1 вызван с параметрами -JsonPath и -OutputDir",
              "Создана папка Catalogs/Контрагенты/ (или аналогичное имя)",
              "Файл Catalog.xml содержит элемент с именем Контрагенты",
              "Реквизит ИНН присутствует в XML-определении объекта",
              "Справочник добавлен в Configuration.xml"
            ]
          },
          {
            "id": 2,
            "prompt": "Добавь документ ПоступлениеТоваров с шапочными реквизитами Склад (ссылка на справочник Склады) и Контрагент (ссылка на справочник Контрагенты), и табличной частью Товары с реквизитами Номенклатура, Количество (число 15,3), Цена (число 15,2), Сумма (число 15,2). Выгрузка в D:/Config/src/.",
            "expected_output": "В D:/Config/src/Documents/ПоступлениеТоваров/ созданы файлы документа, включая XML с описанием табличной части Товары и реквизитами.",
            "expectations": [
              "Скрипт meta-compile.ps1 вызван с корректным путём к OutputDir",
              "Создана папка Documents/ПоступлениеТоваров/",
              "Document.xml содержит определение табличной части Товары",
              "Реквизиты Количество и Цена определены с числовым типом",
              "Документ зарегистрирован в Configuration.xml"
            ]
          },
          {
            "id": 3,
            "prompt": "Создай регистр сведений КурсыВалют с измерением Валюта (ссылка на справочник Валюты), измерением Период (дата) и ресурсом Курс (число 15,4). Без регистратора, периодичность — по позиции регистратора. Конфигурация в C:/Projects/Erp/src/.",
            "expected_output": "В C:/Projects/Erp/src/InformationRegisters/КурсыВалют/ созданы файлы регистра сведений.",
            "expectations": [
              "Скрипт meta-compile.ps1 вызван с типом объекта InformationRegister или регистр сведений",
              "Создана папка InformationRegisters/КурсыВалют/",
              "Измерение Валюта определено в XML-файле",
              "Ресурс Курс определён с числовым типом",
              "Регистр добавлен в Configuration.xml"
            ]
          }
        ]
      }
      
  • reference
    • types-basic.md 4.5 KB
      # Базовые типы: Catalog, Document, Enum, Constant, DefinedType, Report, DataProcessor
      
      ## Catalog
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `hierarchical` | `false` | Hierarchical |
      | `hierarchyType` | `HierarchyFoldersAndItems` | HierarchyType |
      | `limitLevelCount` | `false` | LimitLevelCount |
      | `levelCount` | `2` | LevelCount |
      | `foldersOnTop` | `true` | FoldersOnTop |
      | `codeLength` | `9` | CodeLength |
      | `codeType` | `String` | CodeType |
      | `codeAllowedLength` | `Variable` | CodeAllowedLength |
      | `codeSeries` | `WholeCatalog` | CodeSeries |
      | `descriptionLength` | `25` | DescriptionLength |
      | `autonumbering` | `true` | Autonumbering |
      | `checkUnique` | `false` | CheckUnique |
      | `defaultPresentation` | `AsDescription` | DefaultPresentation |
      | `subordinationUse` | `ToItems` | SubordinationUse |
      | `quickChoice` | `true` | QuickChoice |
      | `choiceMode` | `BothWays` | ChoiceMode |
      | `owners` | `[]` | Owners |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      ```json
      { "type": "Catalog", "name": "Организации", "attributes": ["ИНН: String(12)", "КПП: String(9)"] }
      ```
      
      ## Document
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `numberType` | `String` | NumberType |
      | `numberLength` | `11` | NumberLength |
      | `numberAllowedLength` | `Variable` | NumberAllowedLength |
      | `numberPeriodicity` | `Year` | NumberPeriodicity |
      | `checkUnique` | `true` | CheckUnique |
      | `autonumbering` | `true` | Autonumbering |
      | `posting` | `Allow` | Posting |
      | `realTimePosting` | `Deny` | RealTimePosting |
      | `registerRecordsDeletion` | `AutoDelete` | RegisterRecordsDeletion |
      | `registerRecordsWritingOnPost` | `WriteModified` | RegisterRecordsWritingOnPost |
      | `postInPrivilegedMode` | `true` | PostInPrivilegedMode |
      | `unpostInPrivilegedMode` | `true` | UnpostInPrivilegedMode |
      | `registerRecords` | `[]` | RegisterRecords |
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      RegisterRecords - массив строк: `"AccumulationRegister.Продажи"`, `"InformationRegister.Цены"`.
      
      ```json
      {
        "type": "Document", "name": "ПриходнаяНакладная",
        "registerRecords": ["AccumulationRegister.ОстаткиТоваров"],
        "attributes": ["Организация: CatalogRef.Организации", "Контрагент: CatalogRef.Контрагенты"],
        "tabularSections": { "Товары": ["Номенклатура: CatalogRef.Номенклатура", "Количество: Number(15,3)"] }
      }
      ```
      
      ## Enum
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `values` | `[]` | → EnumValue в ChildObjects |
      
      ```json
      { "type": "Enum", "name": "Статусы", "values": ["Новый", "ВРаботе", "Закрыт"] }
      ```
      
      ## Constant
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `valueType` | `String` | Type |
      
      `valueType` принимает shorthand типа: `"String(100)"`, `"Number(15,2)"`, `"Boolean"`, `"CatalogRef.Валюты"`.
      
      ```json
      { "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" }
      ```
      
      ## DefinedType
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `valueTypes` | `[]` | Type (составной тип) |
      | `valueType` | - | Алиас для `valueTypes` (строка или массив) |
      
      ```json
      { "type": "DefinedType", "name": "ДенежныеСредства", "valueTypes": ["CatalogRef.БанковскиеСчета", "CatalogRef.Кассы"] }
      { "type": "DefinedType", "name": "ФлагАктивности", "valueType": "Boolean" }
      ```
      
      ## Report
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      ```json
      { "type": "Report", "name": "ОстаткиТоваров" }
      ```
      
      ## DataProcessor
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `attributes` | `[]` | → Attribute в ChildObjects |
      | `tabularSections` | `{}` | → TabularSection в ChildObjects |
      
      ```json
      { "type": "DataProcessor", "name": "ЗагрузкаДанных", "attributes": ["ПутьКФайлу: String(500)"] }
      ```
      
    • types-config.md 8.5 KB
      # Конфигурационные объекты без собственных данных
      
      Объекты, которые не хранят свои таблицы, а настраивают поведение конфигурации: общие реквизиты,
      команды, формы, макеты, картинки, критерии отбора, последовательности, нумераторы, параметры сеанса,
      хранилища настроек, функциональные опции и WS-ссылки.
      
      Общее для всех: `name` обязателен, `synonym` по умолчанию выводится из имени, `comment` пишется как
      задан.
      
      ## Ссылки на метаданные
      
      Поля состава (`content`, `documents`, `use`, `documentMap`, `location` и подобные) принимают путь к
      метаданным на русском или английском вперемешку - вид объекта переводится, имя остается как написано:
      
      ```
      "Документ.РеализацияТоваров.Реквизит.Склад"  ->  Document.РеализацияТоваров.Attribute.Склад
      "РегистрСведений.Настройки.Измерение.Организация" -> InformationRegister.Настройки.Dimension.Организация
      ```
      
      Переводятся виды объектов (`Документ`, `Справочник`, `РегистрНакопления`, ...) и виды подчиненных
      элементов: `Реквизит` -> Attribute, `ТабличнаяЧасть` -> TabularSection, `Измерение` -> Dimension,
      `Ресурс` -> Resource, `Графа` -> Column, `ЗначениеПеречисления` -> EnumValue, `Форма` -> Form,
      `Макет` -> Template, `Команда` -> Command, `ПризнакУчета` -> AccountingFlag,
      `ПризнакУчетаСубконто` -> ExtDimensionAccountingFlag, `РеквизитАдресации` -> AddressingAttribute.
      
      ## CommonAttribute (Общий реквизит)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `valueType` | - | Type |
      | `content` | `[]` | Content |
      | `autoUse` | `DontUse` | AutoUse |
      | `indexing` | `DontIndex` | Indexing |
      | `fullTextSearch` | `Use` | FullTextSearch |
      | `dataHistory` | `Use` | DataHistory |
      
      `content` - массив, элемент строкой (`"Документ.РеализацияТоваров"`) или объектом
      `{ "metadata": "...", "use": "Use" }`. Без `use` подставляется `Use`.
      
      ```json
      {
        "type": "CommonAttribute", "name": "Организация",
        "valueType": "CatalogRef.Организации", "autoUse": "Use",
        "content": [ { "metadata": "Документ.РеализацияТоваров", "use": "Use" }, "Документ.ПоступлениеТоваров" ]
      }
      ```
      
      ## CommonCommand (Общая команда)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `group` | пусто | Group |
      | `commandParameterType` | пусто | CommandParameterType |
      | `parameterUseMode` | `Single` | ParameterUseMode |
      | `modifiesData` | `false` | ModifiesData |
      | `representation` | `Auto` | Representation |
      | `picture` | пусто | Picture |
      
      Модули: `Ext/CommandModule.bsl` (создается пустым, обработчик пишется отдельно).
      
      ## CommandGroup (Группа команд)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `representation` | `Auto` | Representation |
      | `category` | `FormCommandBar` | Category |
      | `picture` | пусто | Picture |
      
      `picture` - строка `"CommonPicture.Логотип"` либо объект
      `{ "src": "CommonPicture.Логотип", "loadTransparent": false }`.
      
      ## CommonForm (Общая форма)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `formType` | `Managed` | FormType |
      | `usePurposes` | `["PlatformApplication"]` | UsePurposes |
      | `useStandardCommands` | `false` | UseStandardCommands |
      
      Создает заготовку формы `Ext/Form.xml` (пустая командная панель и пустые элементы) и модуль
      `Ext/Form/Module.bsl`. Наполнение формы - навык `1c-form-compile`.
      
      ## CommonTemplate (Общий макет)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `templateType` | `SpreadsheetDocument` | TemplateType |
      
      Пишутся только метаданные макета. Содержимое макета - навыки `1c-mxl-compile` (табличный документ)
      и `1c-skd-compile` (схема компоновки).
      
      ## CommonPicture (Общая картинка)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `availabilityForChoice` | `false` | AvailabilityForChoice |
      | `availabilityForAppearance` | `false` | AvailabilityForAppearance |
      
      Файл самой картинки не создается - его кладут в `Ext/Picture` отдельно.
      
      ## FilterCriterion (Критерий отбора)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `valueType` | - | Type |
      | `useStandardCommands` | `true` | UseStandardCommands |
      | `content` | `[]` | Content |
      
      ## Sequence (Последовательность)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `documents` | `[]` | Documents |
      | `registerRecords` | `[]` | RegisterRecords |
      | `moveBoundaryOnPosting` | `DontMove` | MoveBoundaryOnPosting |
      | `dataLockControlMode` | `Managed` | DataLockControlMode |
      | `dimensions` | `[]` | → Dimension |
      
      Измерение: `{ "name": "...", "type": "CatalogRef.X", "documentMap": [...], "registerRecordsMap": [...] }`.
      `documentMap` перечисляет реквизиты документов, откуда берется значение измерения.
      
      ```json
      {
        "type": "Sequence", "name": "ВзаиморасчетыСКонтрагентами",
        "documents": ["Документ.ПоступлениеТоваров", "Document.РеализацияТоваров"],
        "dimensions": [{
          "name": "Организация", "type": "CatalogRef.Организации",
          "documentMap": ["Документ.ПоступлениеТоваров.Реквизит.Организация"]
        }]
      }
      ```
      
      ## DocumentNumerator (Нумератор документов)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `numberType` | `String` | NumberType |
      | `numberLength` | `9` | NumberLength |
      | `numberAllowedLength` | `Variable` | NumberAllowedLength |
      | `numberPeriodicity` | `Year` | NumberPeriodicity |
      | `checkUnique` | `true` | CheckUnique |
      
      ## SessionParameter (Параметр сеанса)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `valueType` | - | Type |
      
      Составной тип - через `+`: `"CatalogRef.Пользователи + CatalogRef.ВнешниеПользователи"`.
      
      ## SettingsStorage (Хранилище настроек)
      
      Своих полей нет: только имя, синоним и комментарий. Формы сохранения и загрузки остаются пустыми.
      
      ## FunctionalOption (Функциональная опция)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `location` | пусто | Location |
      | `privilegedGetMode` | `true` | PrivilegedGetMode |
      | `content` | `[]` | Content |
      
      `location` - где хранится значение опции: константа или реквизит
      (`"Constant.ВестиУчетПоСкладам"`).
      
      ## FunctionalOptionsParameter (Параметр функциональных опций)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `use` | `[]` | Use |
      
      `use` - измерения регистров, по которым параметризуется опция.
      
      ## WSReference (WS-ссылка)
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `locationURL` | пусто | LocationURL |
      
      Адрес WSDL. Сам WSDL не скачивается и не разбирается.
      
    • types-process.md 5.5 KB
      # Процессы и сервисные: BusinessProcess, Task, ExchangePlan, CommonModule, ScheduledJob, EventSubscription, DocumentJournal
      
      ## BusinessProcess
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `task` | `""` | Task (ссылка `Task.XXX`) |
      | `numberType` | `String` | NumberType |
      | `numberLength` | `11` | NumberLength |
      | `checkUnique` | `true` | CheckUnique |
      | `autonumbering` | `true` | Autonumbering |
      | `attributes` | `[]` | → Attribute |
      | `tabularSections` | `{}` | → TabularSection |
      
      Модули: `Ext/ObjectModule.bsl`, `Ext/Flowchart.xml`.
      
      ```json
      { "type": "BusinessProcess", "name": "Задание", "task": "Task.ЗадачаИсполнителя", "attributes": ["Описание: String(200)"] }
      ```
      
      ## Task
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `numberType` | `String` | NumberType |
      | `numberLength` | `14` | NumberLength |
      | `checkUnique` | `true` | CheckUnique |
      | `autonumbering` | `true` | Autonumbering |
      | `descriptionLength` | `150` | DescriptionLength |
      | `addressing` | `""` | Addressing (ссылка на РС адресации) |
      | `mainAddressingAttribute` | `""` | MainAddressingAttribute |
      | `currentPerformer` | `""` | CurrentPerformer |
      | `attributes` | `[]` | → Attribute |
      | `tabularSections` | `{}` | → TabularSection |
      | `addressingAttributes` | `[]` | → AddressingAttribute (shorthand или объект) |
      
      AddressingAttribute - shorthand `"Имя: Тип"` или объект `{ "name", "type", "addressingDimension" }`.
      
      ```json
      {
        "type": "Task", "name": "ЗадачаИсполнителя",
        "addressingAttributes": ["Исполнитель: CatalogRef.Пользователи"]
      }
      ```
      
      ## ExchangePlan
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `codeLength` | `9` | CodeLength |
      | `descriptionLength` | `100` | DescriptionLength |
      | `distributedInfoBase` | `false` | DistributedInfoBase |
      | `attributes` | `[]` | → Attribute |
      | `tabularSections` | `{}` | → TabularSection |
      
      Модули: `Ext/ObjectModule.bsl`, `Ext/Content.xml`.
      
      ```json
      { "type": "ExchangePlan", "name": "ОбменССайтом", "attributes": ["АдресСервера: String(200)"] }
      ```
      
      ## CommonModule
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `context` | - | Шорткат (см. ниже) |
      | `global` | `false` | Global |
      | `server` | `false` | Server |
      | `serverCall` | `false` | ServerCall |
      | `clientManagedApplication` | `false` | ClientManagedApplication |
      | `externalConnection` | `false` | ExternalConnection |
      | `privileged` | `false` | Privileged |
      | `returnValuesReuse` | `DontUse` | ReturnValuesReuse |
      
      Шорткаты `context`: `"server"` → Server+ServerCall, `"client"` → ClientManagedApplication, `"serverClient"` → Server+ClientManagedApplication.
      
      ```json
      { "type": "CommonModule", "name": "ОбщиеФункции", "context": "serverClient" }
      ```
      
      ## ScheduledJob
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `methodName` | `""` | MethodName |
      | `description` | = synonym | Description |
      | `use` | `false` | Use |
      | `predefined` | `false` | Predefined |
      | `restartCountOnFailure` | `3` | RestartCountOnFailure |
      | `restartIntervalOnFailure` | `10` | RestartIntervalOnFailure |
      
      Формат `methodName`: `"МодульСервер.Процедура"` - авто-дополняется до `CommonModule.МодульСервер.Процедура`.
      
      ```json
      { "type": "ScheduledJob", "name": "ОбменДанными", "methodName": "ОбменДаннымиСервер.Выполнить" }
      ```
      
      ## EventSubscription
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `source` | `[]` | Source (массив, формат `XxxObject.Name`) |
      | `event` | `BeforeWrite` | Event |
      | `handler` | `""` | Handler |
      
      Формат `handler`: `"МодульСервер.Процедура"` - авто-дополняется до `CommonModule.МодульСервер.Процедура`.
      
      Значения `event`: `BeforeWrite`, `OnWrite`, `BeforeDelete`, `OnReadAtServer`, `FillCheckProcessing`.
      
      Формат `source`: `"CatalogObject.Xxx"`, `"DocumentObject.Xxx"`.
      
      ```json
      { "type": "EventSubscription", "name": "ПередЗаписью", "source": ["CatalogObject.Контрагенты"], "event": "BeforeWrite", "handler": "ОбщиеФункции.ПередЗаписью" }
      ```
      
      ## DocumentJournal
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `registeredDocuments` | `[]` | RegisteredDocuments (массив `"Document.Xxx"`) |
      | `columns` | `[]` | → Column |
      
      Колонки - строка `"Имя"` или объект `{ "name", "synonym", "indexing": "Index"/"DontIndex", "references": ["Document.Xxx.Attribute.Yyy"] }`.
      
      ```json
      {
        "type": "DocumentJournal", "name": "Взаимодействия",
        "registeredDocuments": ["Document.Встреча", "Document.Звонок"],
        "columns": [{ "name": "Организация", "indexing": "Index", "references": ["Document.Встреча.Attribute.Организация"] }]
      }
      ```
      
      ## Зависимости
      
      - **ScheduledJob/EventSubscription** - процедура-обработчик должна существовать в модуле (экспортная)
      - **BusinessProcess** → `Task` (задача должна существовать)
      
    • types-registers.md 7.4 KB
      # Регистры и планы: InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes
      
      ## Измерения и ресурсы (общее)
      
      Синтаксис аналогичен реквизитам (shorthand `"Имя: Тип | флаги"`).
      
      Флаги измерений: `master`, `mainFilter`, `denyIncomplete`, `useInTotals` (AccumulationRegister only, default `true`).
      
      ```json
      "dimensions": ["Организация: CatalogRef.Организации | master, mainFilter, denyIncomplete"],
      "resources": ["Сумма: Number(15,2)"]
      ```
      
      ---
      
      ## InformationRegister
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `writeMode` | `Independent` | WriteMode |
      | `periodicity` | `Nonperiodical` | InformationRegisterPeriodicity |
      | `mainFilterOnPeriod` | авто* | MainFilterOnPeriod |
      | `dimensions` | `[]` | → Dimension |
      | `resources` | `[]` | → Resource |
      | `attributes` | `[]` | → Attribute |
      
      \* `mainFilterOnPeriod` = `true` если `periodicity` != `Nonperiodical`.
      
      ```json
      {
        "type": "InformationRegister", "name": "КурсыВалют", "periodicity": "Day",
        "dimensions": ["Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete"],
        "resources": ["Курс: Number(15,4)", "Кратность: Number(10,0)"]
      }
      ```
      
      ## AccumulationRegister
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `registerType` | `Balance` | RegisterType (`Balance` / `Turnovers`) |
      | `enableTotalsSplitting` | `true` | EnableTotalsSplitting |
      | `dimensions` | `[]` | → Dimension |
      | `resources` | `[]` | → Resource |
      | `attributes` | `[]` | → Attribute |
      
      ```json
      {
        "type": "AccumulationRegister", "name": "ОстаткиТоваров", "registerType": "Balance",
        "dimensions": ["Номенклатура: CatalogRef.Номенклатура"],
        "resources": ["Количество: Number(15,3)"]
      }
      ```
      
      ## AccountingRegister
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `chartOfAccounts` | `""` | ChartOfAccounts (**обязательная** ссылка на план счетов) |
      | `correspondence` | `false` | Correspondence |
      | `periodAdjustmentLength` | `0` | PeriodAdjustmentLength |
      | `dimensions` | `[]` | → Dimension |
      | `resources` | `[]` | → Resource |
      | `attributes` | `[]` | → Attribute |
      
      ```json
      {
        "type": "AccountingRegister", "name": "Хозрасчетный",
        "chartOfAccounts": "ChartOfAccounts.Хозрасчетный",
        "dimensions": ["Организация: CatalogRef.Организации"],
        "resources": ["Сумма: Number(15,2)"]
      }
      ```
      
      ## CalculationRegister
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `chartOfCalculationTypes` | `""` | ChartOfCalculationTypes (**обязательная** ссылка на ПВР) |
      | `periodicity` | `Month` | Periodicity |
      | `actionPeriod` | `false` | ActionPeriod |
      | `basePeriod` | `false` | BasePeriod |
      | `schedule` | `""` | Schedule (ссылка на РС графиков) |
      | `dimensions` | `[]` | → Dimension |
      | `resources` | `[]` | → Resource |
      | `attributes` | `[]` | → Attribute |
      
      ```json
      {
        "type": "CalculationRegister", "name": "Начисления",
        "chartOfCalculationTypes": "ChartOfCalculationTypes.Начисления",
        "periodicity": "Month",
        "dimensions": ["Сотрудник: CatalogRef.Сотрудники"],
        "resources": ["Сумма: Number(15,2)"]
      }
      ```
      
      ---
      
      ## ChartOfCharacteristicTypes
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `codeLength` | `9` | CodeLength |
      | `descriptionLength` | `25` | DescriptionLength |
      | `autonumbering` | `true` | Autonumbering |
      | `checkUnique` | `false` | CheckUnique |
      | `characteristicExtValues` | `""` | CharacteristicExtValues |
      | `valueTypes` | авто* | Type (составной тип значений характеристик) |
      | `hierarchical` | `false` | Hierarchical |
      | `attributes` | `[]` | → Attribute |
      | `tabularSections` | `{}` | → TabularSection |
      
      \* По умолчанию: Boolean, String(100), Number(15,2), DateTime.
      
      ```json
      {
        "type": "ChartOfCharacteristicTypes", "name": "ВидыСубконто",
        "valueTypes": ["CatalogRef.Номенклатура", "CatalogRef.Контрагенты", "Boolean", "String", "Number(15,2)"]
      }
      ```
      
      ## ChartOfAccounts
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `extDimensionTypes` | `""` | ExtDimensionTypes (ссылка на ПВХ) |
      | `maxExtDimensionCount` | `3` с ПВХ, иначе `0` | MaxExtDimensionCount |
      | `codeMask` | `""` | CodeMask |
      | `codeLength` | `8` | CodeLength |
      | `descriptionLength` | `120` | DescriptionLength |
      | `codeSeries` | `WholeChartOfAccounts` | CodeSeries |
      | `autoOrderByCode` | `true` | AutoOrderByCode |
      | `orderLength` | `5` | OrderLength |
      | `hierarchical` | `false` | Hierarchical |
      | `accountingFlags` | `[]` | → AccountingFlag (Boolean-тип, массив имен) |
      | `extDimensionAccountingFlags` | `[]` | → ExtDimensionAccountingFlag (Boolean-тип, массив имен) |
      | `attributes` | `[]` | → Attribute |
      | `tabularSections` | `{}` | → TabularSection |
      
      **Субконто идут парой.** Ненулевой `maxExtDimensionCount` без `extDimensionTypes` дает объект,
      который платформа отказывается грузить: "У плана счетов с количеством субконто не равным 0 должен
      быть установлен план видов характеристик". Поэтому без ссылки на ПВХ счетчик по умолчанию 0, а если
      выставить его руками - навык предупредит. План счетов без субконто законен, это просто другой план.
      
      ```json
      {
        "type": "ChartOfAccounts", "name": "Хозрасчетный",
        "extDimensionTypes": "ChartOfCharacteristicTypes.ВидыСубконто", "maxExtDimensionCount": 3,
        "codeLength": 8, "codeMask": "@@@.@@.@",
        "accountingFlags": ["Валютный", "Количественный"],
        "extDimensionAccountingFlags": ["Суммовой", "Валютный"]
      }
      ```
      
      ## ChartOfCalculationTypes
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `codeLength` | `9` | CodeLength |
      | `descriptionLength` | `25` | DescriptionLength |
      | `autonumbering` | `true` | Autonumbering |
      | `checkUnique` | `false` | CheckUnique |
      | `dependenceOnCalculationTypes` | `DontUse` | DependenceOnCalculationTypes |
      | `actionPeriodUse` | `false` | ActionPeriodUse |
      | `attributes` | `[]` | → Attribute |
      | `tabularSections` | `{}` | → TabularSection |
      
      `dependenceOnCalculationTypes`: `DontUse`, `OnActionPeriod`.
      
      ```json
      { "type": "ChartOfCalculationTypes", "name": "Начисления", "dependenceOnCalculationTypes": "OnActionPeriod" }
      ```
      
      ## Зависимости
      
      - **AccountingRegister** требует `ChartOfAccounts` (и документ-регистратор)
      - **CalculationRegister** требует `ChartOfCalculationTypes` (и документ-регистратор)
      - **ChartOfAccounts** ссылается на `ChartOfCharacteristicTypes` через `extDimensionTypes`
      
    • types-web.md 3.5 KB
      # Веб-сервисы: HTTPService, WebService
      
      ## HTTPService
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `rootURL` | `= name.toLower()` | RootURL |
      | `reuseSessions` | `DontUse` | ReuseSessions |
      | `sessionMaxAge` | `20` | SessionMaxAge |
      | `urlTemplates` | `{}` | → URLTemplate |
      
      Модули: `Ext/Module.bsl`.
      
      ### urlTemplates - вложенная структура
      
      `urlTemplates` - объект `{ "TemplateName": templateDef, ... }`.
      
      Каждый `templateDef`:
      - Строка - URL-шаблон: `"/v1/users"` (без методов)
      - Объект:
      
      | Поле | Умолчание | Описание |
      |------|----------|----------|
      | `template` | `"/templatename"` | URL-путь (с параметрами `{id}`) |
      | `methods` | `{}` | Методы: `{ "MethodName": "HTTPMethod" }` |
      
      Допустимые HTTPMethod: `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`, `CONNECT`, `TRACE`, `MERGE`.
      
      Обработчик метода генерируется автоматически: `{TemplateName}{MethodName}` - должен быть реализован в `Ext/Module.bsl`.
      
      ```json
      {
        "type": "HTTPService", "name": "API", "rootURL": "api",
        "urlTemplates": {
          "Users": {
            "template": "/v1/users/{id}",
            "methods": { "Get": "GET", "Create": "POST", "Update": "PUT", "Delete": "DELETE" }
          },
          "Health": "/health"
        }
      }
      ```
      
      ## WebService
      
      | Поле JSON | Умолчание | XML элемент |
      |-----------|----------|-------------|
      | `namespace` | `""` | Namespace (URI пространства имен WSDL) |
      | `xdtoPackages` | `""` | XDTOPackages |
      | `reuseSessions` | `DontUse` | ReuseSessions |
      | `sessionMaxAge` | `20` | SessionMaxAge |
      | `operations` | `{}` | → Operation |
      
      Модули: `Ext/Module.bsl`.
      
      ### operations - вложенная структура
      
      `operations` - объект `{ "OperationName": operationDef, ... }`.
      
      Каждый `operationDef`:
      - Строка - тип возврата: `"xs:boolean"` (параметров нет, обработчик = имя операции)
      - Объект:
      
      | Поле | Умолчание | Описание |
      |------|----------|----------|
      | `returnType` | `xs:string` | XDTO-тип возврата |
      | `nillable` | `false` | Может ли вернуть null |
      | `transactioned` | `false` | Выполнять в транзакции |
      | `handler` | `= operationName` | Имя процедуры в модуле |
      | `parameters` | `{}` | Параметры операции |
      
      ### parameters - параметры операции
      
      `parameters` - объект `{ "ParamName": paramDef, ... }`.
      
      Каждый `paramDef`:
      - Строка - XDTO-тип: `"xs:string"` (direction = In, nillable = true)
      - Объект:
      
      | Поле | Умолчание | Описание |
      |------|----------|----------|
      | `type` | `xs:string` | XDTO-тип параметра |
      | `nillable` | `true` | Может ли быть null |
      | `direction` | `In` | Направление: `In`, `Out`, `InOut` |
      
      Стандартные XDTO-типы: `xs:string`, `xs:boolean`, `xs:int`, `xs:long`, `xs:decimal`, `xs:dateTime`, `xs:base64Binary`.
      
      ```json
      {
        "type": "WebService", "name": "DataExchange",
        "namespace": "http://www.1c.ru/DataExchange",
        "operations": {
          "TestConnection": {
            "returnType": "xs:boolean",
            "handler": "ПроверкаПодключения",
            "parameters": {
              "ErrorMessage": { "type": "xs:string", "direction": "Out" }
            }
          },
          "GetVersion": "xs:string"
        }
      }
      ```
      
  • scripts
    • meta-compile.ps1 186.9 KB · in bundle
    • meta-compile.py 195.2 KB
      #!/usr/bin/env python3
      # meta-compile v1.10 - Compile 1C metadata object from JSON
      # Source: https://github.com/Desko77/claude-code-skills-1c
      
      import argparse
      import json
      import os
      import re
      import subprocess
      import sys
      import tempfile
      import uuid
      import xml.etree.ElementTree as ET
      
      # ============================================================
      # Support guard (Ext/ParentConfigurations.bin) - see docs/1c-support-state-spec.md
      # Blocks edits of vendor objects "на замке" / read-only configs. Trigger = bin
      # present; reaction from .v8-project.json editingAllowedCheck (deny|warn|off,
      # default deny). Never throws (except sys.exit on deny) - errors degrade to allow.
      # ============================================================
      
      def _sg_parse(xml_path):
          """Разбор XML средствами стандартной библиотеки.
      
          Свой, а не разбор скила: одни порты работают через lxml, другие XML не разбирают вовсе,
          и обращение к чужому имени попадало в общий except ниже - гард молча разрешал правку.
          """
          from xml.etree import ElementTree as _sg_et
          return _sg_et.parse(xml_path).getroot()
      
      
      def _sg_root_uuid(xml_path):
          if not os.path.isfile(xml_path):
              return None
          try:
              mx = _sg_parse(xml_path)
              for child in mx:
                  if isinstance(child.tag, str) and child.get("uuid"):
                      return child.get("uuid")
          except Exception:
              return None
          return None
      
      
      def _sg_is_external_root(xml_path):
          if not os.path.isfile(xml_path):
              return False
          try:
              mx = _sg_parse(xml_path)
              for child in mx:
                  if isinstance(child.tag, str):
                      return child.tag.split("}")[-1] in ("ExternalDataProcessor", "ExternalReport")
          except Exception:
              return False
          return False
      
      def _sg_find_v8project(start_dir):
          d = start_dir
          for _ in range(20):
              if not d:
                  break
              pj = os.path.join(d, ".v8-project.json")
              if os.path.isfile(pj):
                  return pj
              parent = os.path.dirname(d)
              if parent == d:
                  break
              d = parent
          return None
      
      
      def _sg_get_edit_mode(cfg_dir):
          try:
              pj = _sg_find_v8project(os.getcwd()) or _sg_find_v8project(cfg_dir)
              if not pj:
                  return "deny"
              proj = json.loads(open(pj, encoding="utf-8-sig").read())
              cfg_full = os.path.normcase(os.path.abspath(cfg_dir)).rstrip("\\/")
              for db in proj.get("databases", []):
                  src = db.get("configSrc")
                  if src:
                      src_full = os.path.normcase(os.path.abspath(src)).rstrip("\\/")
                      if cfg_full == src_full or cfg_full.startswith(src_full + os.sep):
                          if db.get("editingAllowedCheck"):
                              return db["editingAllowedCheck"]
              if proj.get("editingAllowedCheck"):
                  return proj["editingAllowedCheck"]
              return "deny"
          except Exception:
              return "deny"
      
      
      def assert_edit_allowed(target_path, require):
          try:
              rp = os.path.abspath(target_path)
              # Autonomous external object (EPF/ERF): never part of a config on support (issue #39).
              if _sg_is_external_root(rp):
                  return
              elem_uuid = _sg_root_uuid(rp)
              cfg_dir = None
              bin_path = None
              d = rp if os.path.isdir(rp) else os.path.dirname(rp)
              for _ in range(12):
                  if not d:
                      break
                  if _sg_is_external_root(d + ".xml"):
                      return
                  if not elem_uuid:
                      elem_uuid = _sg_root_uuid(d + ".xml")
                  if not cfg_dir:
                      cand = os.path.join(d, "Ext", "ParentConfigurations.bin")
                      if os.path.exists(cand) or os.path.exists(os.path.join(d, "Configuration.xml")):
                          cfg_dir = d
                          bin_path = cand
                  if elem_uuid and cfg_dir:
                      break
                  parent = os.path.dirname(d)
                  if parent == d:
                      break
                  d = parent
              if not elem_uuid and cfg_dir:
                  elem_uuid = _sg_root_uuid(os.path.join(cfg_dir, "Configuration.xml"))
              if not bin_path or not os.path.exists(bin_path):
                  return
              data = open(bin_path, "rb").read()
              if len(data) <= 32:
                  return
              if data[:3] == b"\xef\xbb\xbf":
                  data = data[3:]
              text = data.decode("utf-8", "replace")
              h = re.match(r"\{6,(\d+),(\d+),", text)
              if not h:
                  return
              g = int(h.group(1))
              k = int(h.group(2))
              if k == 0:
                  return
              best = None
              if elem_uuid:
                  for m in re.finditer(r"([0-2]),0," + re.escape(elem_uuid.lower()), text):
                      f1 = int(m.group(1))
                      if best is None or f1 < best:
                          best = f1
              blocked = False
              code = ""
              reason = ""
              if g == 1:
                  blocked = True
                  code = "capability-off"
                  reason = "возможность изменения конфигурации выключена (вся конфигурация read-only)"
              elif require == "removed":
                  if best is not None and best != 2:
                      blocked = True
                      code = "not-removed"
                      reason = "объект не снят с поддержки - удаление сломает обновления"
              else:
                  if best is not None and best == 0:
                      blocked = True
                      code = "locked"
                      reason = "объект на замке - редактирование сломает обновления"
              if not blocked:
                  return
              mode = _sg_get_edit_mode(cfg_dir)
              if mode == "off":
                  return
              if mode == "warn":
                  sys.stderr.write(f"[support-guard] ПРЕДУПРЕЖДЕНИЕ: {reason}. Цель: {rp}\n")
                  return
              head = "[support-guard] Редактирование отклонено: это объект типовой конфигурации на поддержке поставщика, прямое редактирование молча сломает будущие обновления."
              cfe = "Рекомендуемый путь: внести доработку в расширение (навыки cfe-borrow / cfe-patch-method) - состояние поддержки менять не нужно, обновления вендора сохраняются."
              off_note = "Снять проверку для этой базы: editingAllowedCheck = warn|off в .v8-project.json."
              if code == "capability-off":
                  state = f"Состояние: у всей конфигурации выключена возможность изменения (режим read-only 'из коробки') - поэтому объект '{rp}' редактировать нельзя."
                  fix = (
                      "Либо снять защиту явно (навык support-edit, два шага):\n"
                      f'  1. support-edit -Path "{cfg_dir}" -Capability on - включить возможность изменения (объекты пока остаются на замке);\n'
                      f'  2. support-edit -Path "{rp}" -Set editable - открыть этот объект для редактирования.\n'
                      "  Изменение применяется в базу полной загрузкой выгрузки и обходит механизм обновлений вендора."
                  )
              elif code == "not-removed":
                  state = f"Состояние: объект '{rp}' на поддержке (не снят с поддержки) - его удаление разорвет обновления вендора."
                  fix = (
                      "Либо сначала снять объект с поддержки, затем удалять:\n"
                      f'  support-edit -Path "{rp}" -Set off-support - объект уходит из-под обновлений, после этого удаление безопасно.'
                  )
              else:
                  state = f"Состояние: объект '{rp}' на замке (возможность изменения конфигурации включена, но сам объект не редактируется)."
                  fix = (
                      "Либо разрешить редактирование этого объекта (навык support-edit, выбрать одно):\n"
                      f'  support-edit -Path "{rp}" -Set editable - редактировать и дальше получать обновления вендора (возможны конфликты слияния);\n'
                      f'  support-edit -Path "{rp}" -Set off-support - снять с поддержки: обновления по объекту больше не приходят.'
                  )
              sys.stderr.write(head + "\n" + state + "\n" + cfe + "\n" + fix + "\n" + off_note + "\n")
              sys.exit(1)
          except SystemExit:
              raise
          except Exception:
              return
      # --- Конец общего блока гарда поддержки ---
      
      
      sys.stdout.reconfigure(encoding="utf-8")
      sys.stderr.reconfigure(encoding="utf-8")
      
      # ---------------------------------------------------------------------------
      # Inline utilities
      # ---------------------------------------------------------------------------
      
      def esc_xml(s):
          return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
      
      def new_uuid():
          return str(uuid.uuid4())
      
      def detect_file_eol(path):
          """Конец строки существующего файла; у нового - канонический CRLF."""
          try:
              with open(path, "rb") as fh:
                  data = fh.read()
          except OSError:
              return '\r\n'
          return '\r\n' if b'\r\n' in data or b'\n' not in data else '\n'
      
      
      def write_utf8_bom(path, content, eol='\r\n'):
          # Исходники 1С хранятся в CRLF: этого ждет Конфигуратор, и это закреплено в .gitattributes.
          # Сборка идет через '\n'.join, поэтому концы строк разворачиваются здесь, на записи.
          # Нормализация идемпотентна - смешанный текст тоже приходит к одному виду.
          # Правка существующего файла передает сюда его собственный eol: форсировать CRLF там
          # нельзя, иначе навык переписывает весь чужой файл ради одной добавленной строки.
          content = content.replace('\r\n', '\n').replace('\n', eol)
          with open(path, 'w', encoding='utf-8-sig', newline='') as f:
              f.write(content)
      
      # ---------------------------------------------------------------------------
      # XML builder (lines list)
      # ---------------------------------------------------------------------------
      
      lines = []
      
      def X(text):
          lines.append(text)
      
      def emit_mltext(indent, tag, text):
          if not text:
              X(f'{indent}<{tag}/>')
              return
          # Значение бывает строкой (тогда это русский вариант) и словарем { 'ru': ..., 'en': ... }.
          # Раньше словарь приводился к строке и уезжал в XML как есть, вместо перевода.
          if isinstance(text, dict):
              ml_items = [(str(lang), str(content)) for lang, content in text.items()]
          else:
              ml_items = [('ru', str(text))]
          X(f'{indent}<{tag}>')
          for lang, content in ml_items:
              X(f'{indent}\t<v8:item>')
              # Пустой язык платформа пишет одиночным тегом: пара с пустым содержимым не совпадает
              # с выгрузкой.
              if lang:
                  X(f'{indent}\t\t<v8:lang>{lang}</v8:lang>')
              else:
                  X(f'{indent}\t\t<v8:lang/>')
              X(f'{indent}\t\t<v8:content>{esc_xml(content)}</v8:content>')
              X(f'{indent}\t</v8:item>')
          X(f'{indent}</{tag}>')
      
      # ---------------------------------------------------------------------------
      # CamelCase splitter
      # ---------------------------------------------------------------------------
      
      def split_camel_case(name):
          if not name:
              return name
          result = re.sub(r'([а-яё])([А-ЯЁ])', r'\1 \2', name)
          result = re.sub(r'([a-z])([A-Z])', r'\1 \2', result)
          if len(result) > 1:
              tail = re.sub(r'(?<![А-ЯЁA-Z])([А-ЯЁA-Z])(?![А-ЯЁA-Z])',
                            lambda m: m.group(1).lower(), result[1:])
              result = result[0] + tail
          return result
      
      # ---------------------------------------------------------------------------
      # 1. Load and validate JSON
      # ---------------------------------------------------------------------------
      
      parser = argparse.ArgumentParser(allow_abbrev=False)
      parser.add_argument('-JsonPath', required=True)
      parser.add_argument('-OutputDir', required=True)
      args = parser.parse_args()
      
      json_path = args.JsonPath
      output_dir = args.OutputDir
      assert_edit_allowed(output_dir, "editable")
      
      if not os.path.isfile(json_path):
          print(f'File not found: {json_path}', file=sys.stderr)
          sys.exit(1)
      
      with open(json_path, 'r', encoding='utf-8-sig') as f:
          json_text = f.read()
      
      class LenientDict(dict):
          """Словарь, нечувствительный к регистру ключей - как PSObject в PowerShell.
      
          Нужен для прощающего ввода: DSL принимает и `codeLength`, и `CodeLength`. Вложенные словари
          оборачиваются тоже, иначе леность теряется на первом же уровне вложенности.
          """
      
          def __init__(self, data=None):
              super().__init__()
              for k, v in (data or {}).items():
                  self[k] = v
      
          @staticmethod
          def _wrap(v):
              if isinstance(v, dict):
                  return LenientDict(v)
              if isinstance(v, list):
                  return [LenientDict(x) if isinstance(x, dict) else x for x in v]
              return v
      
          def __setitem__(self, key, value):
              super().__setitem__(key, self._wrap(value))
      
          def _actual_key(self, key):
              if super().__contains__(key):
                  return key
              if isinstance(key, str):
                  low = key.lower()
                  for k in super().keys():
                      if isinstance(k, str) and k.lower() == low:
                          return k
              return None
      
          def __getitem__(self, key):
              k = self._actual_key(key)
              if k is None:
                  raise KeyError(key)
              return super().__getitem__(k)
      
          def __contains__(self, key):
              return self._actual_key(key) is not None
      
          def get(self, key, default=None):
              k = self._actual_key(key)
              return super().__getitem__(k) if k is not None else default
      
      
      def lenient(data):
          """JSON бывает объектом и массивом объектов - оборачиваем и то, и другое."""
          if isinstance(data, list):
              return [LenientDict(x) if isinstance(x, dict) else x for x in data]
          return LenientDict(data) if isinstance(data, dict) else data
      
      
      defn = lenient(json.loads(json_text))
      
      # --- Batch mode: JSON array of objects ---
      if isinstance(defn, list):
          batch_ok = 0
          batch_fail = 0
          for idx, item in enumerate(defn, 1):
              tmp_fd, tmp_path = tempfile.mkstemp(suffix='.json', prefix=f'meta-compile-batch-{idx}-')
              try:
                  with os.fdopen(tmp_fd, 'w', encoding='utf-8') as f:
                      json.dump(item, f, ensure_ascii=False, indent=2)
                  rc = subprocess.call([sys.executable, __file__, '-JsonPath', tmp_path, '-OutputDir', output_dir])
                  if rc == 0:
                      batch_ok += 1
                  else:
                      batch_fail += 1
              finally:
                  if os.path.exists(tmp_path):
                      os.unlink(tmp_path)
          print()
          print(f"=== Batch: {len(defn)} objects, {batch_ok} compiled, {batch_fail} failed ===")
          sys.exit(1 if batch_fail > 0 else 0)
      
      # Normalize field synonyms: accept "objectType" as alias for "type"
      if not defn.get('type') and defn.get('objectType'):
          defn['type'] = defn['objectType']
      
      # Object type synonyms (Russian -> English)
      object_type_synonyms = {
          'Справочник': 'Catalog',
          'Каталог': 'Catalog',
          'Документ': 'Document',
          'Перечисление': 'Enum',
          'Константа': 'Constant',
          'РегистрСведений': 'InformationRegister',
          'РегистрНакопления': 'AccumulationRegister',
          'РегистрБухгалтерии': 'AccountingRegister',
          'РегистрРасчёта': 'CalculationRegister',
          'РегистрРасчета': 'CalculationRegister',
          'ПланСчетов': 'ChartOfAccounts',
          'ПланВидовХарактеристик': 'ChartOfCharacteristicTypes',
          'ПланВидовРасчёта': 'ChartOfCalculationTypes',
          'ПланВидовРасчета': 'ChartOfCalculationTypes',
          'БизнесПроцесс': 'BusinessProcess',
          'Задача': 'Task',
          'ПланОбмена': 'ExchangePlan',
          'ЖурналДокументов': 'DocumentJournal',
          'Отчёт': 'Report',
          'Отчет': 'Report',
          'Обработка': 'DataProcessor',
          'ОбщийМодуль': 'CommonModule',
          'РегламентноеЗадание': 'ScheduledJob',
          'ПодпискаНаСобытие': 'EventSubscription',
          'HTTPСервис': 'HTTPService',
          'ВебСервис': 'WebService',
          'ОпределяемыйТип': 'DefinedType',
          'ОбщийРеквизит': 'CommonAttribute',
          'ОбщаяФорма': 'CommonForm',
          'ОбщаяКоманда': 'CommonCommand',
          'ГруппаКоманд': 'CommandGroup',
          'ОбщийМакет': 'CommonTemplate',
          'ОбщаяКартинка': 'CommonPicture',
          'КритерийОтбора': 'FilterCriterion',
          'Последовательность': 'Sequence',
          'НумераторДокументов': 'DocumentNumerator',
          'ПараметрСеанса': 'SessionParameter',
          'ХранилищеНастроек': 'SettingsStorage',
          'ФункциональнаяОпция': 'FunctionalOption',
          'ПараметрФункциональныхОпций': 'FunctionalOptionsParameter',
          'WSСсылка': 'WSReference',
      }
      
      # Enum property value synonyms - model often gets these slightly wrong
      enum_value_aliases = {
          # RegisterType (AccumulationRegister)
          'Balances': 'Balance', 'Остатки': 'Balance', 'Обороты': 'Turnovers',
          # WriteMode (InformationRegister)
          'RecordSubordinate': 'RecorderSubordinate', 'Subordinate': 'RecorderSubordinate',
          'ПодчинениеРегистратору': 'RecorderSubordinate', 'Независимый': 'Independent',
          # DependenceOnCalculationTypes (ChartOfCalculationTypes)
          'NotDependOnCalculationTypes': 'DontUse', 'NoDependence': 'DontUse', 'NotUsed': 'DontUse',
          'Depend': 'OnActionPeriod', 'ПоПериодуДействия': 'OnActionPeriod',
          # InformationRegisterPeriodicity
          'None': 'Nonperiodical', 'Daily': 'Day', 'Monthly': 'Month',
          'Quarterly': 'Quarter', 'Yearly': 'Year',
          'Непериодический': 'Nonperiodical', 'Секунда': 'Second', 'День': 'Day',
          'Месяц': 'Month', 'Квартал': 'Quarter', 'Год': 'Year',
          'ПозицияРегистратора': 'RecorderPosition',
          # DataLockControlMode
          'Автоматический': 'Automatic', 'Управляемый': 'Managed',
          # FullTextSearch
          'Использовать': 'Use', 'НеИспользовать': 'DontUse',
          # Posting
          'Разрешить': 'Allow', 'Запретить': 'Deny',
          # EditType
          'ВДиалоге': 'InDialog', 'ВСписке': 'InList', 'ОбаСпособа': 'BothWays',
          # DefaultPresentation
          'ВВидеНаименования': 'AsDescription', 'ВВидеКода': 'AsCode',
          # FillChecking
          'НеПроверять': 'DontCheck', 'Ошибка': 'ShowError', 'Предупреждение': 'ShowWarning',
          # Indexing
          'НеИндексировать': 'DontIndex', 'Индексировать': 'Index',
          'ИндексироватьСДопУпорядочиванием': 'IndexWithAdditionalOrder',
      }
      
      # Valid enum values per property (from meta-validate)
      valid_enum_values = {
          'RegisterType': ['Balance', 'Turnovers'],
          'WriteMode': ['Independent', 'RecorderSubordinate'],
          'InformationRegisterPeriodicity': ['Nonperiodical', 'Second', 'Day', 'Month', 'Quarter', 'Year', 'RecorderPosition'],
          'DependenceOnCalculationTypes': ['DontUse', 'OnActionPeriod'],
          'DataLockControlMode': ['Automatic', 'Managed'],
          'FullTextSearch': ['Use', 'DontUse'],
          'DataHistory': ['Use', 'DontUse'],
          'DefaultPresentation': ['AsDescription', 'AsCode'],
          'Posting': ['Allow', 'Deny'],
          'RealTimePosting': ['Allow', 'Deny'],
          'EditType': ['InDialog', 'InList', 'BothWays'],
          'HierarchyType': ['HierarchyFoldersAndItems', 'HierarchyItemsOnly'],
          'CodeType': ['String', 'Number'],
          'CodeAllowedLength': ['Variable', 'Fixed'],
          'NumberType': ['String', 'Number'],
          'NumberAllowedLength': ['Variable', 'Fixed'],
          'RegisterRecordsDeletion': ['AutoDelete', 'AutoDeleteOnUnpost', 'AutoDeleteOff'],
          'RegisterRecordsWritingOnPost': ['WriteModified', 'WriteSelected', 'WriteAll'],
          'ReturnValuesReuse': ['DontUse', 'DuringRequest', 'DuringSession'],
          'ReuseSessions': ['DontUse', 'Use', 'AutoUse'],
          'FillChecking': ['DontCheck', 'ShowError', 'ShowWarning'],
          'Indexing': ['DontIndex', 'Index', 'IndexWithAdditionalOrder'],
          'SubordinationUse': ['ToItems', 'ToFolders', 'ToFoldersAndItems'],
          'CodeSeries': ['WholeCatalog', 'WithinSubordination'],
          'ChoiceMode': ['BothWays', 'QuickChoice', 'FromForm'],
      }
      
      def normalize_enum_value(prop_name, value):
          # 1. Check alias dictionary - silent auto-correct. Поиск без учета регистра: хеш-таблица
          # PowerShell находит "обороты" по ключу "Обороты", словарь python - нет.
          alias = lookup_ci(enum_value_aliases, value)
          if alias is not None:
              return alias
          # 2. Case-insensitive match against valid values - silent
          valid = valid_enum_values.get(prop_name)
          if valid:
              for v in valid:
                  if v.lower() == value.lower():
                      return v
              # 3. Known property, unknown value - error with hint
              print(f"Invalid value '{value}' for property '{prop_name}'. Valid values: {', '.join(valid)}", file=sys.stderr)
              sys.exit(1)
          # 4. Unknown property - pass-through (no validation data)
          return value
      
      def get_enum_prop(prop_name, field_name, default):
          val = defn.get(field_name)
          raw = str(val) if val else default
          return normalize_enum_value(prop_name, raw)
      
      
      
      # Виды вложенных сущностей: русское имя -> английское. Дополняется синонимами типов объектов,
      # чтобы путь вида "Документ.Заказ.Реквизит.Сумма" приводился к английскому целиком.
      md_kind_synonyms = {
          'Реквизит': 'Attribute',
          'ТабличнаяЧасть': 'TabularSection',
          'Измерение': 'Dimension',
          'Ресурс': 'Resource',
          'Графа': 'Column',
          'ЗначениеПеречисления': 'EnumValue',
          'Форма': 'Form',
          'Макет': 'Template',
          'Команда': 'Command',
          'ПризнакУчета': 'AccountingFlag',
          'ПризнакУчетаСубконто': 'ExtDimensionAccountingFlag',
          'РеквизитАдресации': 'AddressingAttribute',
      }
      md_kind_synonyms.update(object_type_synonyms)
      
      
      def as_array(value):
          """Аналог @(...) в PowerShell: строка становится ОДНИМ элементом, а не списком символов.
      
          Через list() строковое значение рассыпалось посимвольно - например источник подписки
          "CatalogObject.Товары" выпускался как двадцать типов d5p1:C, d5p1:a, d5p1:t...
          """
          if value is None:
              return []
          if isinstance(value, (list, tuple)):
              return [v for v in value if v is not None]
          return [value]
      
      
      def resolve_md_path(path):
          """Приводит путь к метаданным к английским именам: русские идут на нечетных позициях."""
          if not path:
              return path
          parts = str(path).split('.')
          for idx in range(0, len(parts), 2):
              # Поиск без учета регистра: хеш-таблица PowerShell находит "документ" по ключу "Документ",
              # словарь python - нет, и русский вид сущности оставался непереведенным.
              syn = lookup_ci(md_kind_synonyms, parts[idx])
              if syn:
                  parts[idx] = syn
          return '.'.join(parts)
      
      
      def emit_comment(indent):
          if comment:
              X(f'{indent}<Comment>{esc_xml(comment)}</Comment>')
          else:
              X(f'{indent}<Comment/>')
      
      
      def emit_common_head(indent):
          """Голова свойств, одинаковая у всех типов: имя, синоним, комментарий."""
          X(f'{indent}<Name>{esc_xml(obj_name)}</Name>')
          emit_mltext(indent, 'Synonym', synonym)
          emit_comment(indent)
      
      
      def emit_md_ref_list(indent, tag, items):
          """Список ссылок: <xr:Item xsi:type="xr:MDObjectRef">Document.X</xr:Item>"""
          refs = [r for r in (items if isinstance(items, list) else ([items] if items else [])) if r]
          if not refs:
              X(f'{indent}<{tag}/>')
              return
          X(f'{indent}<{tag}>')
          for ref in refs:
              X(f'{indent}\t<xr:Item xsi:type="xr:MDObjectRef">{resolve_md_path(str(ref))}</xr:Item>')
          X(f'{indent}</{tag}>')
      
      
      def emit_picture_ref(indent, picture):
          """Картинка команды или группы: либо ссылка на общую картинку, либо пустой тег."""
          if not picture:
              X(f'{indent}<Picture/>')
              return
          src = picture if isinstance(picture, str) else picture.get('src')
          if not src:
              X(f'{indent}<Picture/>')
              return
          transparent = 'true' if (not isinstance(picture, str) and picture.get('loadTransparent') is True) else 'false'
          X(f'{indent}<Picture>')
          X(f'{indent}\t<xr:Ref>{resolve_md_path(str(src))}</xr:Ref>')
          X(f'{indent}\t<xr:LoadTransparent>{transparent}</xr:LoadTransparent>')
          X(f'{indent}</Picture>')
      
      
      if not defn.get('type'):
          print("JSON must have 'type' field", file=sys.stderr)
          sys.exit(1)
      
      def lookup_ci(table, key):
          """Поиск по словарю без учета регистра - хеш-таблица PowerShell ведет себя так же."""
          if key in table:
              return table[key]
          low = str(key).lower()
          for k, v in table.items():
              if str(k).lower() == low:
                  return v
          return None
      
      
      obj_type = str(defn['type'])
      _syn = lookup_ci(object_type_synonyms, obj_type)
      if _syn:
          obj_type = _syn
      
      valid_types = [
          'Catalog', 'Document', 'Enum', 'Constant', 'InformationRegister',
          'AccumulationRegister', 'AccountingRegister', 'CalculationRegister',
          'ChartOfAccounts', 'ChartOfCharacteristicTypes', 'ChartOfCalculationTypes',
          'BusinessProcess', 'Task', 'ExchangePlan', 'DocumentJournal',
          'Report', 'DataProcessor', 'CommonModule', 'ScheduledJob',
          'EventSubscription', 'HTTPService', 'WebService', 'DefinedType',
          'CommonAttribute', 'CommonCommand', 'CommandGroup', 'CommonForm', 'CommonTemplate',
          'CommonPicture', 'FilterCriterion', 'Sequence', 'DocumentNumerator',
          'SessionParameter', 'SettingsStorage', 'FunctionalOption',
          'FunctionalOptionsParameter', 'WSReference',
      ]
      # Сравнение регистронезависимое, как оператор -in в PowerShell, но имя типа затем приводится
      # к каноническому виду. Иначе "catalog" уходит в XML тегом <catalog>, а платформа на таком теге
      # не ругается - она МОЛЧА выбрасывает объект: "не является подчиненным для объекта
      # Configuration", код возврата 0, объекта в базе нет. Замерено на 8.3.27.
      _canonical = next((v for v in valid_types if v.lower() == obj_type.lower()), None)
      if _canonical is None:
          print(f"Unsupported type: {obj_type}. Valid: {', '.join(valid_types)}", file=sys.stderr)
          sys.exit(1)
      obj_type = _canonical
      
      if not defn.get('name'):
          print("JSON must have 'name' field", file=sys.stderr)
          sys.exit(1)
      
      obj_name = str(defn['name'])
      
      # Auto-synonym
      synonym = defn['synonym'] if defn.get('synonym') else split_camel_case(obj_name)
      comment = str(defn['comment']) if defn.get('comment') else ''
      
      # ---------------------------------------------------------------------------
      # 4. Type system
      # ---------------------------------------------------------------------------
      
      type_synonyms = {
          'число': 'Number',
          'строка': 'String',
          'булево': 'Boolean',
          'дата': 'Date',
          'датавремя': 'DateTime',
          'number': 'Number',
          'string': 'String',
          'boolean': 'Boolean',
          'date': 'Date',
          'datetime': 'DateTime',
          'bool': 'Boolean',
          # Reference synonyms (Russian, lowercase)
          'справочникссылка': 'CatalogRef',
          'документссылка': 'DocumentRef',
          'перечислениессылка': 'EnumRef',
          'плансчетовссылка': 'ChartOfAccountsRef',
          'планвидовхарактеристикссылка': 'ChartOfCharacteristicTypesRef',
          'планвидоврасчётассылка': 'ChartOfCalculationTypesRef',
          'планвидоврасчетассылка': 'ChartOfCalculationTypesRef',
          'планобменассылка': 'ExchangePlanRef',
          'бизнеспроцессссылка': 'BusinessProcessRef',
          'задачассылка': 'TaskRef',
          'определяемыйтип': 'DefinedType',
          'definedtype': 'DefinedType',
          # English lowercase ref synonyms
          'catalogref': 'CatalogRef',
          'documentref': 'DocumentRef',
          'enumref': 'EnumRef',
      }
      
      def resolve_type_str(type_str):
          if not type_str:
              return type_str
          # Тип, скопированный из выгрузки, несет префикс пространства имен: cfg:, d5p1:, d4p1:.
          # Срезается только префикс выгрузки конфигурации: схемные префиксы (v8:, xs:, v8ui:)
          # часть имени типа, и без них тип не разрешается.
          m_prefix = re.match(r'^(?:cfg|d\d+p\d+):(.+)$', type_str)
          if m_prefix:
              type_str = m_prefix.group(1)
          # Parameterized types: Number(15,2), Строка(100), etc.
          m = re.match(r'^([^(]+)\((.+)\)$', type_str)
          if m:
              base_name = m.group(1).strip()
              params = m.group(2)
              resolved = type_synonyms.get(base_name.lower())
              if resolved:
                  return f'{resolved}({params})'
              return type_str
          # Reference types: СправочникСсылка.Организации -> CatalogRef.Организации
          if '.' in type_str:
              dot_idx = type_str.index('.')
              prefix = type_str[:dot_idx]
              suffix = type_str[dot_idx:]  # includes the dot
              resolved = type_synonyms.get(prefix.lower())
              if resolved:
                  return f'{resolved}{suffix}'
              return type_str
          # Simple name lookup
          resolved = type_synonyms.get(type_str.lower())
          if resolved:
              return resolved
          return type_str
      
      def emit_type_content(indent, type_str, cfg_prefix=False):
          if not type_str:
              return
          # Составной тип платформа пишет блоками: сперва все типы, затем наборы типов, затем
          # квалификаторы по одному на вид - числовой, строковый, дата. Наш вывод шел парами
          # тип-квалификатор, и файл расходился с выгрузкой на каждом составном типе.
          if ' + ' in type_str:
              parts = [p.strip() for p in type_str.split('+')]
              type_lines, set_lines, quals = [], [], {}
              for part in parts:
                  start = len(lines)
                  emit_type_content(indent, part, cfg_prefix)
                  chunk = lines[start:]
                  del lines[start:]
                  open_kind = None
                  for line in chunk:
                      stripped = line.strip()
                      if open_kind:
                          quals[open_kind].append(line)
                          if stripped == f'</v8:{open_kind}>':
                              open_kind = None
                          continue
                      m_qual = re.match(r'<v8:(\w+Qualifiers)>', stripped)
                      if m_qual:
                          open_kind = m_qual.group(1)
                          quals.setdefault(open_kind, []).append(line)
                      elif stripped.startswith('<v8:TypeSet'):
                          set_lines.append(line)
                      elif stripped.startswith('<v8:Type'):
                          type_lines.append(line)
                      else:
                          type_lines.append(line)
              for line in type_lines + set_lines:
                  X(line)
              ordered = ['NumberQualifiers', 'StringQualifiers', 'DateQualifiers']
              for kind in ordered + [k for k in quals if k not in ordered]:
                  for line in quals.get(kind, []):
                      X(line)
              return
          type_str = resolve_type_str(type_str)
          # Boolean
          if type_str == 'Boolean':
              X(f'{indent}<v8:Type>xs:boolean</v8:Type>')
              return
          # String or String(N)
          m = re.match(r'^String(\((\d+)\))?$', type_str)
          if m:
              length = m.group(2) if m.group(2) else '10'
              X(f'{indent}<v8:Type>xs:string</v8:Type>')
              X(f'{indent}<v8:StringQualifiers>')
              X(f'{indent}\t<v8:Length>{length}</v8:Length>')
              X(f'{indent}\t<v8:AllowedLength>Variable</v8:AllowedLength>')
              X(f'{indent}</v8:StringQualifiers>')
              return
          # Number without params -> Number(10,0)
          if type_str == 'Number':
              X(f'{indent}<v8:Type>xs:decimal</v8:Type>')
              X(f'{indent}<v8:NumberQualifiers>')
              X(f'{indent}\t<v8:Digits>10</v8:Digits>')
              X(f'{indent}\t<v8:FractionDigits>0</v8:FractionDigits>')
              X(f'{indent}\t<v8:AllowedSign>Any</v8:AllowedSign>')
              X(f'{indent}</v8:NumberQualifiers>')
              return
      
          # Number(D,F) or Number(D,F,nonneg)
          m = re.match(r'^Number\((\d+),(\d+)(,nonneg)?\)$', type_str)
          if m:
              digits = m.group(1)
              fraction = m.group(2)
              sign = 'Nonnegative' if m.group(3) else 'Any'
              X(f'{indent}<v8:Type>xs:decimal</v8:Type>')
              X(f'{indent}<v8:NumberQualifiers>')
              X(f'{indent}\t<v8:Digits>{digits}</v8:Digits>')
              X(f'{indent}\t<v8:FractionDigits>{fraction}</v8:FractionDigits>')
              X(f'{indent}\t<v8:AllowedSign>{sign}</v8:AllowedSign>')
              X(f'{indent}</v8:NumberQualifiers>')
              return
          # Date / DateTime
          if type_str == 'Date':
              X(f'{indent}<v8:Type>xs:dateTime</v8:Type>')
              X(f'{indent}<v8:DateQualifiers>')
              X(f'{indent}\t<v8:DateFractions>Date</v8:DateFractions>')
              X(f'{indent}</v8:DateQualifiers>')
              return
          if type_str == 'DateTime':
              X(f'{indent}<v8:Type>xs:dateTime</v8:Type>')
              X(f'{indent}<v8:DateQualifiers>')
              X(f'{indent}\t<v8:DateFractions>DateTime</v8:DateFractions>')
              X(f'{indent}</v8:DateQualifiers>')
              return
          # DefinedType
          m = re.match(r'^DefinedType\.(.+)$', type_str)
          if m:
              dt_name = m.group(1)
              X(f'{indent}<v8:TypeSet>cfg:DefinedType.{dt_name}</v8:TypeSet>')
              return
          # ValueStorage
          if type_str == 'ValueStorage':
              X(f'{indent}<v8:Type>xs:base64Binary</v8:Type>')
              return
      
          # Reference types - use local xmlns declaration for 1C compatibility
          m = re.match(r'^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.(.+)$', type_str)
          if m:
              if cfg_prefix:
                  X(f'{indent}<v8:Type>cfg:{type_str}</v8:Type>')
              else:
                  X(f'{indent}<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:{type_str}</v8:Type>')
              return
          # Ссылочный тип без имени объекта - это НАБОР типов, а не тип: любой справочник,
          # любой документ. Платформа пишет его элементом TypeSet.
          if re.fullmatch(r'CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef', type_str):
              X(f'{indent}<v8:TypeSet>cfg:{type_str}</v8:TypeSet>')
              return
          # Fallback
          X(f'{indent}<v8:Type>{type_str}</v8:Type>')
      
      def emit_value_type(indent, type_str):
          # Измерения и ресурсы регистров платформа выгружает через объявленный в шапке префикс
          # cfg, а не локальным объявлением - замерено на эталоне регистра сведений.
          X(f'{indent}<Type>')
          emit_type_content(f'{indent}\t', type_str, cfg_prefix=True)
          X(f'{indent}</Type>')
      
      def emit_fill_value(indent, type_str):
          if not type_str:
              X(f'{indent}<FillValue xsi:nil="true"/>')
              return
          type_str = resolve_type_str(type_str)
          if type_str == 'Boolean':
              X(f'{indent}<FillValue xsi:type="xs:boolean">false</FillValue>')
              return
          if re.match(r'^String', type_str):
              X(f'{indent}<FillValue xsi:type="xs:string"/>')
              return
          if re.match(r'^Number', type_str):
              X(f'{indent}<FillValue xsi:type="xs:decimal">0</FillValue>')
              return
          if re.match(r'^(Date|DateTime)$', type_str):
              X(f'{indent}<FillValue xsi:nil="true"/>')
              return
          X(f'{indent}<FillValue xsi:nil="true"/>')
      
      # ---------------------------------------------------------------------------
      # 5. Attribute shorthand parser
      # ---------------------------------------------------------------------------
      
      def build_type_str(obj):
          t = str(obj.get('valueType') or obj.get('type') or '')
          if t and '(' not in t:
              if t == 'String' and obj.get('length'):
                  t = f"String({obj['length']})"
              elif t == 'Number' and obj.get('length'):
                  prec = obj.get('precision', 0)
                  nn = ',nonneg' if obj.get('nonneg') or obj.get('nonnegative') else ''
                  t = f"Number({obj['length']},{prec}{nn})"
          return t
      
      def parse_attribute_shorthand(val):
          if isinstance(val, str):
              parsed = {
                  'name': '',
                  'type': '',
                  'synonym': '',
                  'comment': '',
                  'flags': [],
                  'fillChecking': '',
                  'indexing': '',
              }
              parts = val.split('|', 1)
              main_part = parts[0].strip()
              if len(parts) > 1:
                  flag_str = parts[1].strip()
                  parsed['flags'] = [f.strip().lower() for f in flag_str.split(',') if f.strip()]
              colon_parts = main_part.split(':', 1)
              parsed['name'] = colon_parts[0].strip()
              if len(colon_parts) > 1:
                  parsed['type'] = colon_parts[1].strip()
              parsed['synonym'] = split_camel_case(parsed['name'])
              return parsed
          # Object form
          name = str(val.get('name', ''))
          return {
              'name': name,
              'type': build_type_str(val),
              'synonym': val['synonym'] if val.get('synonym') else split_camel_case(name),
              'comment': str(val['comment']) if val.get('comment') else '',
              'flags': list(val.get('flags', [])),
              'fillChecking': str(val['fillChecking']) if val.get('fillChecking') else '',
              'indexing': str(val['indexing']) if val.get('indexing') else '',
              'multiLine': True if val.get('multiLine') is True else False,
          }
      
      def parse_enum_value_shorthand(val):
          if isinstance(val, str):
              return {
                  'name': val,
                  'synonym': split_camel_case(val),
                  'comment': '',
              }
          name = str(val.get('name', ''))
          return {
              'name': name,
              'synonym': val['synonym'] if val.get('synonym') else split_camel_case(name),
              'comment': str(val['comment']) if val.get('comment') else '',
          }
      
      # ---------------------------------------------------------------------------
      # 6. GeneratedType categories
      # ---------------------------------------------------------------------------
      
      generated_types = {
          'Catalog': [
              {'prefix': 'CatalogObject', 'category': 'Object'},
              {'prefix': 'CatalogRef', 'category': 'Ref'},
              {'prefix': 'CatalogSelection', 'category': 'Selection'},
              {'prefix': 'CatalogList', 'category': 'List'},
              {'prefix': 'CatalogManager', 'category': 'Manager'},
          ],
          'Document': [
              {'prefix': 'DocumentObject', 'category': 'Object'},
              {'prefix': 'DocumentRef', 'category': 'Ref'},
              {'prefix': 'DocumentSelection', 'category': 'Selection'},
              {'prefix': 'DocumentList', 'category': 'List'},
              {'prefix': 'DocumentManager', 'category': 'Manager'},
          ],
          'Enum': [
              {'prefix': 'EnumRef', 'category': 'Ref'},
              {'prefix': 'EnumManager', 'category': 'Manager'},
              {'prefix': 'EnumList', 'category': 'List'},
          ],
          'Constant': [
              {'prefix': 'ConstantManager', 'category': 'Manager'},
              {'prefix': 'ConstantValueManager', 'category': 'ValueManager'},
              {'prefix': 'ConstantValueKey', 'category': 'ValueKey'},
          ],
          'InformationRegister': [
              {'prefix': 'InformationRegisterRecord', 'category': 'Record'},
              {'prefix': 'InformationRegisterManager', 'category': 'Manager'},
              {'prefix': 'InformationRegisterSelection', 'category': 'Selection'},
              {'prefix': 'InformationRegisterList', 'category': 'List'},
              {'prefix': 'InformationRegisterRecordSet', 'category': 'RecordSet'},
              {'prefix': 'InformationRegisterRecordKey', 'category': 'RecordKey'},
              {'prefix': 'InformationRegisterRecordManager', 'category': 'RecordManager'},
          ],
          'AccumulationRegister': [
              {'prefix': 'AccumulationRegisterRecord', 'category': 'Record'},
              {'prefix': 'AccumulationRegisterManager', 'category': 'Manager'},
              {'prefix': 'AccumulationRegisterSelection', 'category': 'Selection'},
              {'prefix': 'AccumulationRegisterList', 'category': 'List'},
              {'prefix': 'AccumulationRegisterRecordSet', 'category': 'RecordSet'},
              {'prefix': 'AccumulationRegisterRecordKey', 'category': 'RecordKey'},
          ],
          'AccountingRegister': [
              {'prefix': 'AccountingRegisterRecord', 'category': 'Record'},
              {'prefix': 'AccountingRegisterExtDimensions', 'category': 'ExtDimensions'},
              {'prefix': 'AccountingRegisterRecordSet', 'category': 'RecordSet'},
              {'prefix': 'AccountingRegisterRecordKey', 'category': 'RecordKey'},
              {'prefix': 'AccountingRegisterSelection', 'category': 'Selection'},
              {'prefix': 'AccountingRegisterList', 'category': 'List'},
              {'prefix': 'AccountingRegisterManager', 'category': 'Manager'},
          ],
          'CalculationRegister': [
              {'prefix': 'CalculationRegisterRecord', 'category': 'Record'},
              {'prefix': 'CalculationRegisterManager', 'category': 'Manager'},
              {'prefix': 'CalculationRegisterSelection', 'category': 'Selection'},
              {'prefix': 'CalculationRegisterList', 'category': 'List'},
              {'prefix': 'CalculationRegisterRecordSet', 'category': 'RecordSet'},
              {'prefix': 'CalculationRegisterRecordKey', 'category': 'RecordKey'},
              {'prefix': 'RecalculationsManager', 'category': 'Recalcs'},
          ],
          'ChartOfAccounts': [
              {'prefix': 'ChartOfAccountsObject', 'category': 'Object'},
              {'prefix': 'ChartOfAccountsRef', 'category': 'Ref'},
              {'prefix': 'ChartOfAccountsSelection', 'category': 'Selection'},
              {'prefix': 'ChartOfAccountsList', 'category': 'List'},
              {'prefix': 'ChartOfAccountsManager', 'category': 'Manager'},
              {'prefix': 'ChartOfAccountsExtDimensionTypes', 'category': 'ExtDimensionTypes'},
              {'prefix': 'ChartOfAccountsExtDimensionTypesRow', 'category': 'ExtDimensionTypesRow'},
          ],
          'ChartOfCharacteristicTypes': [
              {'prefix': 'ChartOfCharacteristicTypesObject', 'category': 'Object'},
              {'prefix': 'ChartOfCharacteristicTypesRef', 'category': 'Ref'},
              {'prefix': 'ChartOfCharacteristicTypesSelection', 'category': 'Selection'},
              {'prefix': 'ChartOfCharacteristicTypesList', 'category': 'List'},
              # Префикс именно "Characteristic", без имени типа: так пишет платформа. Замерено круговым
              # прогоном через 8.3.27 и подтверждено выгрузкой типовой конфигурации.
              {'prefix': 'Characteristic', 'category': 'Characteristic'},
              {'prefix': 'ChartOfCharacteristicTypesManager', 'category': 'Manager'},
          ],
          'ChartOfCalculationTypes': [
              {'prefix': 'ChartOfCalculationTypesObject', 'category': 'Object'},
              {'prefix': 'ChartOfCalculationTypesRef', 'category': 'Ref'},
              {'prefix': 'ChartOfCalculationTypesSelection', 'category': 'Selection'},
              {'prefix': 'ChartOfCalculationTypesList', 'category': 'List'},
              {'prefix': 'ChartOfCalculationTypesManager', 'category': 'Manager'},
              {'prefix': 'DisplacingCalculationTypes', 'category': 'DisplacingCalculationTypes'},
              {'prefix': 'DisplacingCalculationTypesRow', 'category': 'DisplacingCalculationTypesRow'},
              {'prefix': 'BaseCalculationTypes', 'category': 'BaseCalculationTypes'},
              {'prefix': 'BaseCalculationTypesRow', 'category': 'BaseCalculationTypesRow'},
              {'prefix': 'LeadingCalculationTypes', 'category': 'LeadingCalculationTypes'},
              {'prefix': 'LeadingCalculationTypesRow', 'category': 'LeadingCalculationTypesRow'},
          ],
          'BusinessProcess': [
              {'prefix': 'BusinessProcessObject', 'category': 'Object'},
              {'prefix': 'BusinessProcessRef', 'category': 'Ref'},
              {'prefix': 'BusinessProcessSelection', 'category': 'Selection'},
              {'prefix': 'BusinessProcessList', 'category': 'List'},
              {'prefix': 'BusinessProcessManager', 'category': 'Manager'},
              {'prefix': 'BusinessProcessRoutePointRef', 'category': 'RoutePointRef'},
          ],
          'Task': [
              {'prefix': 'TaskObject', 'category': 'Object'},
              {'prefix': 'TaskRef', 'category': 'Ref'},
              {'prefix': 'TaskSelection', 'category': 'Selection'},
              {'prefix': 'TaskList', 'category': 'List'},
              {'prefix': 'TaskManager', 'category': 'Manager'},
          ],
          'ExchangePlan': [
              {'prefix': 'ExchangePlanObject', 'category': 'Object'},
              {'prefix': 'ExchangePlanRef', 'category': 'Ref'},
              {'prefix': 'ExchangePlanSelection', 'category': 'Selection'},
              {'prefix': 'ExchangePlanList', 'category': 'List'},
              {'prefix': 'ExchangePlanManager', 'category': 'Manager'},
          ],
          'DefinedType': [
              {'prefix': 'DefinedType', 'category': 'DefinedType'},
          ],
          'FilterCriterion': [
              {'prefix': 'FilterCriterionManager', 'category': 'Manager'},
              {'prefix': 'FilterCriterionList', 'category': 'List'},
          ],
          'Sequence': [
              {'prefix': 'SequenceRecord', 'category': 'Record'},
              {'prefix': 'SequenceManager', 'category': 'Manager'},
              {'prefix': 'SequenceRecordSet', 'category': 'RecordSet'},
          ],
          'SettingsStorage': [
              {'prefix': 'SettingsStorageManager', 'category': 'Manager'},
          ],
          'WSReference': [
              {'prefix': 'WSReferenceManager', 'category': 'Manager'},
          ],
          'DocumentJournal': [
              {'prefix': 'DocumentJournalSelection', 'category': 'Selection'},
              {'prefix': 'DocumentJournalList', 'category': 'List'},
              {'prefix': 'DocumentJournalManager', 'category': 'Manager'},
          ],
          'Report': [
              {'prefix': 'ReportObject', 'category': 'Object'},
              {'prefix': 'ReportManager', 'category': 'Manager'},
          ],
          'DataProcessor': [
              {'prefix': 'DataProcessorObject', 'category': 'Object'},
              {'prefix': 'DataProcessorManager', 'category': 'Manager'},
          ],
      }
      
      def emit_internal_info(indent, object_type, object_name):
          types = generated_types.get(object_type)
          if not types:
              return
          X(f'{indent}<InternalInfo>')
          if object_type == 'ExchangePlan':
              X(f'{indent}\t<xr:ThisNode>{new_uuid()}</xr:ThisNode>')
          for gt in types:
              full_name = f"{gt['prefix']}.{object_name}"
              X(f'{indent}\t<xr:GeneratedType name="{full_name}" category="{gt["category"]}">')
              X(f'{indent}\t\t<xr:TypeId>{new_uuid()}</xr:TypeId>')
              X(f'{indent}\t\t<xr:ValueId>{new_uuid()}</xr:ValueId>')
              X(f'{indent}\t</xr:GeneratedType>')
          X(f'{indent}</InternalInfo>')
      
      # ---------------------------------------------------------------------------
      # 7. StandardAttributes
      # ---------------------------------------------------------------------------
      
      standard_attributes_by_type = {
          'Catalog': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'IsFolder', 'Owner', 'Parent', 'Description', 'Code'],
          'Document': ['Posted', 'Ref', 'DeletionMark', 'Date', 'Number'],
          'Enum': ['Order', 'Ref'],
          'InformationRegister': ['Active', 'LineNumber', 'Recorder', 'Period'],
          'AccumulationRegister': ['Active', 'LineNumber', 'Recorder', 'Period'],
          'AccountingRegister': ['Active', 'Period', 'Recorder', 'LineNumber', 'Account'],
          'CalculationRegister': ['RegistrationPeriod', 'ReversingEntry', 'Active', 'EndOfBasePeriod', 'BegOfBasePeriod', 'EndOfActionPeriod', 'BegOfActionPeriod', 'ActionPeriod', 'CalculationType', 'LineNumber', 'Recorder'],
          'ChartOfAccounts': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'Description', 'Code', 'Parent', 'Order', 'Type', 'OffBalance'],
          'ChartOfCharacteristicTypes': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'Description', 'Code', 'Parent', 'ValueType'],
          'ChartOfCalculationTypes': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'Description', 'Code', 'ActionPeriodIsBasic'],
          'BusinessProcess': ['Ref', 'DeletionMark', 'Date', 'Number', 'Started', 'Completed', 'HeadTask'],
          'Task': ['Ref', 'DeletionMark', 'Date', 'Number', 'Executed', 'Description', 'RoutePoint', 'BusinessProcess'],
          'ExchangePlan': ['Ref', 'DeletionMark', 'Code', 'Description', 'ThisNode', 'SentNo', 'ReceivedNo'],
          'DocumentJournal': ['Type', 'Ref', 'Date', 'Posted', 'DeletionMark', 'Number'],
      }
      
      # --- Команды объекта ---
      # Группа обязательна: без нее платформа не знает, где показывать команду. Секционные группы
      # командного интерфейса параметра команды не принимают.
      COMMAND_SECTION_GROUPS = (
          'NavigationPanelImportant', 'NavigationPanelOrdinary', 'NavigationPanelSeeAlso',
          'ActionsPanelImportant', 'ActionsPanelOrdinary', 'ActionsPanelSeeAlso', 'ActionsPanelCreate',
          'CommandBar', 'CommandStatusBar',
      )
      
      COMMAND_GROUP_SYNONYMS = {
          'панельнавигации.важное': 'NavigationPanelImportant',
          'панельнавигации.обычное': 'NavigationPanelOrdinary',
          'панельнавигации.смтакже': 'NavigationPanelSeeAlso',
          'панельдействий.важное': 'ActionsPanelImportant',
          'панельдействий.обычное': 'ActionsPanelOrdinary',
          'панельдействий.смтакже': 'ActionsPanelSeeAlso',
          'панельдействий.создать': 'ActionsPanelCreate',
          'панельдействий.сервис': 'ActionsPanelTools',
          'команднаяпанельформы.важное': 'FormCommandBarImportant',
          'команднаяпанельформы.обычное': 'FormCommandBarOrdinary',
          'команднаяпанельформы.смтакже': 'FormCommandBarSeeAlso',
          'команднаяпанельформы.создать': 'FormCommandBarCreate',
          'панельнавигацииформы.важное': 'FormNavigationPanelImportant',
          'панельнавигацииформы.обычное': 'FormNavigationPanelOrdinary',
          'панельнавигацииформы.перейти': 'FormNavigationPanelGoTo',
          'панельнавигацииформы.смтакже': 'FormNavigationPanelSeeAlso',
      }
      
      
      def resolve_command_group(group):
          """Группа задается предопределенным именем или ссылкой на собственную группу команд."""
          if not group:
              return ''
          key = re.sub(r'\s', '', group).lower()
          if key in COMMAND_GROUP_SYNONYMS:
              return COMMAND_GROUP_SYNONYMS[key]
          m = re.match(r'^(?:ГруппаКоманд|CommandGroup)\.(.+)$', group)
          if m:
              return 'CommandGroup.' + m.group(1)
          return group
      
      
      def emit_object_command(indent, cmd_name, cmd_def):
          group = resolve_command_group(str(cmd_def.get('group', '')))
          if not group:
              print("Ошибка: команде '" + cmd_name + "' не задана группа. "
                    "Укажите group, например FormCommandBarImportant", file=sys.stderr)
              sys.exit(1)
          param_type = str(cmd_def.get('commandParameterType', ''))
          if param_type and group in COMMAND_SECTION_GROUPS:
              print("Ошибка: у команды '" + cmd_name + "' параметр команды недоступен для группы "
                    + group + " - секционные группы командного интерфейса принимают команды без параметра",
                    file=sys.stderr)
              sys.exit(1)
      
          X(indent + '<Command uuid="' + new_uuid() + '">')
          i = indent + '\t\t'
          X(indent + '\t<Properties>')
          X(i + '<Name>' + esc_xml(cmd_name) + '</Name>')
          emit_mltext(i, 'Synonym', cmd_def.get('synonym') or split_camel_case(cmd_name))
          comment = str(cmd_def.get('comment', ''))
          X(i + '<Comment>' + esc_xml(comment) + '</Comment>' if comment else i + '<Comment/>')
          X(i + '<Group>' + group + '</Group>')
          if param_type:
              X(i + '<CommandParameterType>')
              emit_type_content(i + '\t', param_type, cfg_prefix=True)
              X(i + '</CommandParameterType>')
          else:
              X(i + '<CommandParameterType/>')
          X(i + '<ParameterUseMode>' + str(cmd_def.get('parameterUseMode', 'Single')) + '</ParameterUseMode>')
          X(i + '<ModifiesData>' + ('true' if cmd_def.get('modifiesData') is True else 'false') + '</ModifiesData>')
          X(i + '<Representation>' + str(cmd_def.get('representation', 'Auto')) + '</Representation>')
          if cmd_def.get('tooltip'):
              emit_mltext(i, 'ToolTip', cmd_def['tooltip'])
          else:
              X(i + '<ToolTip/>')
      
          # Картинка задается именем или объектом с прозрачным пикселем.
          picture = cmd_def.get('picture')
          if picture:
              pic_ref = picture if isinstance(picture, str) else str(picture.get('src', ''))
              X(i + '<Picture>')
              X(i + '\t<xr:Ref>' + esc_xml(pic_ref) + '</xr:Ref>')
              load_transparent = 'false' if cmd_def.get('loadTransparent') is False else 'true'
              X(i + '\t<xr:LoadTransparent>' + load_transparent + '</xr:LoadTransparent>')
              if not isinstance(picture, str) and picture.get('transparentPixel'):
                  pixel = picture['transparentPixel']
                  X(i + '\t<xr:TransparentPixel x="' + str(pixel.get('x', 0))
                    + '" y="' + str(pixel.get('y', 0)) + '"/>')
              X(i + '</Picture>')
          else:
              X(i + '<Picture/>')
          shortcut = str(cmd_def.get('shortcut', ''))
          X(i + '<Shortcut>' + esc_xml(shortcut) + '</Shortcut>' if shortcut else i + '<Shortcut/>')
          X(i + '<OnMainServerUnavalableBehavior>'
            + str(cmd_def.get('onMainServerUnavalableBehavior', 'Auto'))
            + '</OnMainServerUnavalableBehavior>')
          X(indent + '\t</Properties>')
          X(indent + '</Command>')
      
      
      def emit_standard_attribute(indent, attr_name, required=False):
          # Настройки приходят ключом standardAttributes: заданное свойство заменяет умолчание,
          # остальные печатаются как есть.
          cfg = (defn.get('standardAttributes') or {}).get(attr_name) or {}
      
          X(f'{indent}<xr:StandardAttribute name="{attr_name}">')
          X(f'{indent}\t<xr:LinkByType/>')
          # Владелец подчиненного справочника обязателен к заполнению - платформа выставляет это
          # сама. Владелец и родитель заполняются из значения заполнения.
          default_checking = 'ShowError' if attr_name == 'Owner' or required else 'DontCheck'
          fill_checking = (normalize_enum_value('FillChecking', str(cfg['fillChecking']))
                           if cfg.get('fillChecking') else default_checking)
          X(f'{indent}\t<xr:FillChecking>{fill_checking}</xr:FillChecking>')
          X(f'{indent}\t<xr:MultiLine>false</xr:MultiLine>')
          from_filling = 'true' if attr_name in ('Owner', 'Parent') else 'false'
          X(f'{indent}\t<xr:FillFromFillingValue>{from_filling}</xr:FillFromFillingValue>')
          X(f'{indent}\t<xr:CreateOnInput>Auto</xr:CreateOnInput>')
          # Свойство появилось в формате 2.18. У владельца справочника тип задан списком владельцев,
          # и приведение значений платформа запрещает.
          if float(format_version) >= 2.18:
              reduction = 'Deny' if attr_name == 'Owner' else 'TransformValues'
              X(f'{indent}\t<xr:TypeReductionMode>{reduction}</xr:TypeReductionMode>')
          X(f'{indent}\t<xr:MaxValue xsi:nil="true"/>')
          if cfg.get('tooltip'):
              emit_mltext(f'{indent}	', 'xr:ToolTip', cfg['tooltip'])
          else:
              X(f'{indent}	<xr:ToolTip/>')
          X(f'{indent}\t<xr:ExtendedEdit>false</xr:ExtendedEdit>')
          X(f'{indent}\t<xr:Format/>')
          X(f'{indent}\t<xr:ChoiceForm/>')
          X(f'{indent}\t<xr:QuickChoice>Auto</xr:QuickChoice>')
          X(f'{indent}\t<xr:ChoiceHistoryOnInput>Auto</xr:ChoiceHistoryOnInput>')
          X(f'{indent}\t<xr:EditFormat/>')
          X(f'{indent}\t<xr:PasswordMode>false</xr:PasswordMode>')
          X(f'{indent}\t<xr:DataHistory>Use</xr:DataHistory>')
          X(f'{indent}\t<xr:MarkNegatives>false</xr:MarkNegatives>')
          X(f'{indent}\t<xr:MinValue xsi:nil="true"/>')
          if cfg.get('synonym'):
              emit_mltext(f'{indent}	', 'xr:Synonym', cfg['synonym'])
          else:
              X(f'{indent}	<xr:Synonym/>')
          if cfg.get('comment'):
              X(f'{indent}	<
  • SKILL.md 6.1 KB
    ---
    name: 1c-meta-compile
    description: Создать объект метаданных 1С. Используй когда пользователь просит создать или добавить справочник, документ, регистр, перечисление, константу, общий модуль, обработку, отчет и др.
    argument-hint: <JsonPath> <OutputDir>
    allowed-tools:
      - Bash
      - Read
      - Write
      - Glob
    ---
    
    # /meta-compile - генерация объектов метаданных из JSON DSL
    
    Принимает JSON-определение объекта метаданных → генерирует XML + модули в структуре выгрузки конфигурации + регистрирует в Configuration.xml.
    
    ## Порядок работы
    
    1. Составь JSON по синтаксису и примерам ниже → запиши во временный файл
    2. Запусти скрипт meta-compile
    3. Если нужно изменить созданный объект - `/meta-edit`
    4. Если нужно проверить - `/meta-validate`
    
    ## Команда
    
    ```powershell
    powershell.exe -NoProfile -File skills/1c-meta-compile/scripts/meta-compile.ps1 -JsonPath "<json>" -OutputDir "<ConfigDir>"
    ```
    
    | Параметр | Описание |
    |----------|----------|
    | `JsonPath` | Путь к JSON-файлу (один объект `{...}` или массив `[{...}, ...]`) |
    | `OutputDir` | Корень выгрузки конфигурации (где `Configuration.xml`, `Catalogs/`, `Documents/` и т.д.) |
    
    ## JSON DSL
    
    ### Общая структура
    
    ```json
    { "type": "Catalog", "name": "Номенклатура", ...свойства типа... }
    ```
    
    `type` и `name` - обязательные. `synonym` генерируется из `name` автоматически (CamelCase → слова через пробел). Можно задать явно: `"synonym": "Мой синоним"`.
    
    ### Shorthand реквизитов
    
    Используется в `attributes`, `dimensions`, `resources`, `tabularSections`:
    
    ```
    "ИмяРеквизита"                    → String(10) по умолчанию
    "ИмяРеквизита: Тип"               → с типом
    "ИмяРеквизита: Тип | req, index"  → с флагами
    ```
    
    Типы: `String(100)`, `Number(15,2)`, `Boolean`, `Date`, `DateTime`, `CatalogRef.Xxx`, `DocumentRef.Xxx`, `EnumRef.Xxx`, `DefinedType.Xxx` и др. ссылочные.
    
    Составной тип: `"Значение: String + Number(15,2) + CatalogRef.Контрагенты"`.
    
    Флаги: `req`, `index`, `indexAdditional`, `nonneg`, `master`, `mainFilter`, `denyIncomplete`, `useInTotals`.
    
    ### Свойства по типам
    
    Примеров и shorthand-синтаксиса выше достаточно для типовых задач. Если нужны свойства типа, не показанные в примерах, и их допустимые значения - см. reference-файл:
    
    - `reference/types-basic.md` - Catalog, Document, Enum, Constant, DefinedType, Report, DataProcessor
    - `reference/types-registers.md` - InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes
    - `reference/types-process.md` - BusinessProcess, Task, ExchangePlan, CommonModule, ScheduledJob, EventSubscription, DocumentJournal
    - `reference/types-web.md` - HTTPService, WebService
    - `reference/types-config.md` - CommonAttribute, CommonCommand, CommandGroup, CommonForm, CommonTemplate, CommonPicture, FilterCriterion, Sequence, DocumentNumerator, SessionParameter, SettingsStorage, FunctionalOption, FunctionalOptionsParameter, WSReference
    
    Эта инструкция и reference-файлы - полная документация для генерации. Не ищи примеры XML в выгрузках конфигураций.
    
    ## Примеры паттернов DSL
    
    ### Минимальный объект
    
    ```json
    { "type": "Catalog", "name": "Валюты" }
    ```
    
    ### С реквизитами
    
    ```json
    {
      "type": "Catalog", "name": "Организации",
      "descriptionLength": 100,
      "attributes": ["ИНН: String(12)", "КПП: String(9)", "Директор: CatalogRef.ФизическиеЛица"]
    }
    ```
    
    ### С табличной частью
    
    ```json
    {
      "type": "Document", "name": "ПриходнаяНакладная",
      "registerRecords": ["AccumulationRegister.ОстаткиТоваров"],
      "attributes": ["Организация: CatalogRef.Организации", "Контрагент: CatalogRef.Контрагенты"],
      "tabularSections": { "Товары": ["Номенклатура: CatalogRef.Номенклатура", "Количество: Number(15,3)", "Цена: Number(15,2)"] }
    }
    ```
    
    Табличная часть задается списком колонок либо объектом, если нужен свой синоним:
    
    ```json
    "tabularSections": {
      "Товары": { "synonym": "Строки заказа", "attributes": ["Номенклатура: CatalogRef.Номенклатура"] }
    }
    ```
    
    Поддержаны ключи `attributes`, `synonym` и `comment`. Любой другой ключ навык не применит и скажет об
    этом предупреждением - молча он их больше не проглатывает.
    
    ### Регистровый паттерн (измерения + ресурсы)
    
    ```json
    {
      "type": "InformationRegister", "name": "КурсыВалют", "periodicity": "Day",
      "dimensions": ["Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete"],
      "resources": ["Курс: Number(15,4)", "Кратность: Number(10,0)"]
    }
    ```
    
    ### Batch - несколько объектов в одном файле
    
    ```json
    [
      { "type": "Enum", "name": "Статусы", "values": ["Новый", "Закрыт"] },
      { "type": "Catalog", "name": "Валюты" },
      { "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" }
    ]
    ```
    
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related