Merge branch 'dev'

This commit is contained in:
Nick Shirokov
2026-02-10 13:31:23 +03:00
10 changed files with 2851 additions and 188 deletions
+71 -169
View File
@@ -1,7 +1,7 @@
---
name: role-compile
description: Создание роли 1С — метаданные и Rights.xml из описания прав
argument-hint: <RoleName> <RolesDir>
argument-hint: <JsonPath> <RolesDir>
allowed-tools:
- Bash
- Read
@@ -9,199 +9,101 @@ allowed-tools:
- Glob
---
# /role-compile — создание роли 1С
# /role-compile — генерация роли 1С из JSON DSL
Создаёт файлы роли (метаданные + Rights.xml) по описанию прав. Скрипта нет — агент генерирует XML по шаблонам ниже.
Принимает JSON-определение роли → генерирует `Roles/Имя.xml` (метаданные) и `Roles/Имя/Ext/Rights.xml` (права). UUID автоматически.
## Использование
## Параметры и команда
```
/role-compile <RoleName> <RolesDir>
| Параметр | Описание |
|----------|----------|
| `JsonPath` | Путь к JSON-определению роли |
| `RolesDir` | Каталог `Roles/` в исходниках конфигурации |
```powershell
powershell.exe -NoProfile -File .claude\skills\role-compile\scripts\role-compile.ps1 -JsonPath "<json>" -OutputDir "<RolesDir>"
```
- **RoleName** — программное имя роли
- **RolesDir** — каталог `Roles/` в исходниках конфигурации
`<Role>ИмяРоли</Role>` автоматически добавляется в `<ChildObjects>` файла `Configuration.xml` (ожидается в parent от `RolesDir`).
## Файловая структура и регистрация
## JSON DSL
```
Roles/
ИмяРоли.xml ← метаданные (uuid, имя, синоним)
ИмяРоли/
Ext/
Rights.xml ← определение прав
### Структура
```json
{ "name": "ИмяРоли", "synonym": "Отображаемое имя", "objects": [...], "templates": [...] }
```
В `Configuration.xml` добавить `<Role>ИмяРоли</Role>` в секцию `<ChildObjects>`.
Необязательные: `comment` (""), `setForNewObjects` (false), `setForAttributesByDefault` (true), `independentRightsOfChildObjects` (false).
## Шаблон метаданных: Roles/ИмяРоли.xml
### Shorthand-строки и объектная форма
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses"
xmlns:v8="http://v8.1c.ru/8.1/data/core"
xmlns:xr="http://v8.1c.ru/8.3/xcf/readable"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.17">
<Role uuid="GENERATE-UUID-HERE">
<Properties>
<Name>ИмяРоли</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Отображаемое имя роли</v8:content>
</v8:item>
</Synonym>
<Comment/>
</Properties>
</Role>
</MetaDataObject>
```json
"objects": [
"Catalog.Номенклатура: @view",
"Document.Реализация: @edit",
"DataProcessor.Загрузка: @view",
"InformationRegister.Цены: Read, Update",
{ "name": "Document.Продажа", "preset": "view", "rights": {"Delete": false}, "rls": {"Read": "#Шаблон(\"\")"} }
]
```
**UUID:** `powershell.exe -Command "[guid]::NewGuid().ToString()"`
- Shorthand: `"Тип.Имя: @пресет"` или `"Тип.Имя: Право1, Право2"`
- Объектная форма: `preset` + `rights` (переопределения) + `rls` (ограничения)
## Шаблон прав: Roles/ИмяРоли/Ext/Rights.xml
### Пресеты
```xml
<?xml version="1.0" encoding="UTF-8"?>
<Rights xmlns="http://v8.1c.ru/8.2/roles"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="Rights" version="2.17">
<setForNewObjects>false</setForNewObjects>
<setForAttributesByDefault>true</setForAttributesByDefault>
<independentRightsOfChildObjects>false</independentRightsOfChildObjects>
<!-- блоки <object> -->
</Rights>
| Пресет | Действие |
|--------|----------|
| `@view` | Просмотр — Read, View (+InputByString для справочников/документов; Use+View для обработок/отчётов) |
| `@edit` | Полное редактирование — CRUD + Interactive* + Posting (документы) |
`@` обязателен в shorthand. В объектной форме — `"preset": "view"` без `@`.
Для сервисов (WebService, HTTPService, IntegrationService) пресеты не определены — используй явные права: `"WebService.Имя: Use"`.
### Русские синонимы
Поддерживаются русские типы (`Справочник`→Catalog, `Документ`→Document) и права (`Чтение`→Read, `Просмотр`→View). Смешивание допустимо: `"Справочник.Контрагенты: Чтение, View"`.
### Шаблоны RLS
```json
"templates": [{"name": "ДляОбъекта(Мод)", "condition": "ГДЕ Организация = &ТекОрг"}]
```
NB: namespace `http://v8.1c.ru/8.2/roles` (исторически 8.2, не 8.3).
Ссылка в `rls`: `"#ДляОбъекта(\"\")"`. Символ `&` автоматически экранируется в XML.
## Формат блока прав
## Примеры
```xml
<object>
<name>Catalog.Номенклатура</name>
<right><name>Read</name><value>true</value></right>
<right><name>View</name><value>true</value></right>
</object>
### Простая роль
```json
{
"name": "ЧтениеНоменклатуры", "synonym": "Чтение номенклатуры",
"objects": ["Catalog.Номенклатура: @view", "Catalog.Контрагенты: @view", "DataProcessor.Загрузка: @view"]
}
```
Имя объекта — dot-нотация: `ТипОбъекта.Имя[.ТипВложенного.ИмяВложенного]`.
### Роль с RLS
## Практические наборы прав
### Catalog / ExchangePlan
| Набор | Права |
|-------|-------|
| Чтение | Read, View, InputByString |
| Полные | Read, Insert, Update, Delete, View, Edit, InputByString, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark |
### Document
| Набор | Права |
|-------|-------|
| Чтение | Read, View, InputByString |
| Полные | Read, Insert, Update, Delete, View, Edit, InputByString, Posting, UndoPosting, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark, InteractivePosting, InteractivePostingRegular, InteractiveUndoPosting, InteractiveChangeOfPosted |
### InformationRegister / AccumulationRegister / AccountingRegister
| Набор | Права |
|-------|-------|
| Чтение | Read, View |
| Полные | Read, Update, View, Edit |
TotalsControl — только для управления итогами, обычно не нужно.
### Простые типы
| Тип | Права |
|-----|-------|
| `DataProcessor` / `Report` | Use, View |
| `Constant` | Read, Update, View, Edit (чтение: Read, View) |
| `CommonForm` / `CommonCommand` / `Subsystem` / `FilterCriterion` | View |
| `DocumentJournal` | Read, View |
| `Sequence` | Read, Update |
| `SessionParameter` | Get (+ Set если пишет) |
| `CommonAttribute` | View (+ Edit если редактирует) |
| `WebService` / `HTTPService` / `IntegrationService` | Use |
| `CalculationRegister` | Read, View |
### Редкие ссылочные типы
| Тип | Особенности (относительно Catalog) |
|-----|-------|
| `ChartOfAccounts`, `ChartOfCharacteristicTypes`, `ChartOfCalculationTypes` | + Predefined-права (InteractiveDeletePredefinedData и др.) |
| `BusinessProcess` | + Start, InteractiveStart, InteractiveActivate |
| `Task` | + Execute, InteractiveExecute, InteractiveActivate |
### Типы БЕЗ прав в ролях
Enum, FunctionalOption, DefinedType, CommonModule, CommonPicture, CommonTemplate — не фигурируют в Rights.xml.
### Вложенные объекты (права: View, Edit)
```
Catalog.Контрагенты.Attribute.ИНН
Document.Реализация.StandardAttribute.Posted
Document.Реализация.TabularSection.Товары
InformationRegister.Цены.Dimension.Номенклатура
InformationRegister.Цены.Resource.Цена
Catalog.Контрагенты.Command.ОткрытьКарточку ← только View
Task.Задача.AddressingAttribute.Исполнитель
```json
{
"name": "ЧтениеДокументовПоОрганизации",
"synonym": "Чтение документов (ограничение по организации)",
"objects": [
"Catalog.Организации: @view",
{"name": "Document.РеализацияТоваровУслуг", "preset": "view", "rls": {"Read": "#ДляОбъекта(\"\")"}}
],
"templates": [{"name": "ДляОбъекта(Модификатор)", "condition": "ГДЕ Организация = &ТекущаяОрганизация"}]
}
```
Используются для точечного запрета: `<value>false</value>` на конкретный реквизит.
Подробные таблицы пресетов, русских синонимов и дополнительные примеры — в `dsl-reference.md`.
### Configuration
## Верификация
Объект: `Configuration.ИмяКонфигурации`. Ключевые права: Administration, DataAdministration, ThinClient, WebClient, ThickClient, MobileClient, ExternalConnection, Output, SaveUserData, InteractiveOpenExtDataProcessors, InteractiveOpenExtReports, MainWindowModeNormal, MainWindowModeWorkplace, MainWindowModeEmbeddedWorkplace, MainWindowModeFullscreenWorkplace, MainWindowModeKiosk, AnalyticsSystemClient.
> DataHistory-права (ReadDataHistory, UpdateDataHistory и др.) существуют у Catalog, Document, Register, Constant — но используются крайне редко, в типовых ролях практически не встречаются.
## RLS (ограничения на уровне записей)
Внутрь `<right>`, после `<value>`. Применяется к Read, Update, Insert, Delete.
```xml
<right>
<name>Read</name>
<value>true</value>
<restrictionByCondition>
<condition>#ИмяШаблона("Параметр1", "Параметр2")</condition>
</restrictionByCondition>
</right>
```
Шаблоны — в конце Rights.xml, после всех `<object>`:
```xml
<restrictionTemplate>
<name>ИмяШаблона(Параметр1, Параметр2)</name>
<condition>Текст шаблона</condition>
</restrictionTemplate>
/role-validate <RightsPath> [MetadataPath] — проверка корректности XML, прав, RLS
/role-info <RightsPath> — визуальная сводка структуры
```
`&` в условии → `&amp;`. Типичные шаблоны: ДляОбъекта, ПоЗначениям, ДляРегистра.
## Пример: роль для регламентного задания
```xml
<object>
<name>Catalog.Валюты</name>
<right><name>Read</name><value>true</value></right>
</object>
<object>
<name>InformationRegister.КурсыВалют</name>
<right><name>Read</name><value>true</value></right>
<right><name>Update</name><value>true</value></right>
</object>
<object>
<name>Constant.ОсновнаяВалюта</name>
<right><name>Read</name><value>true</value></right>
</object>
```
Фоновые задания не требуют Interactive/View/Edit-прав и прав конфигурации (ThinClient, WebClient и др.) — только программные (Read, Insert, Update, Delete, Posting).
@@ -0,0 +1,313 @@
# Role DSL — полная справка
Подробная справка по JSON DSL для `/role-compile`. Компактное описание — в [SKILL.md](SKILL.md).
## Структура верхнего уровня
```json
{
"name": "ИмяРоли",
"synonym": "Отображаемое имя роли",
"comment": "",
"setForNewObjects": false,
"setForAttributesByDefault": true,
"independentRightsOfChildObjects": false,
"objects": [ ... ],
"templates": [ ... ]
}
```
- `name` — программное имя роли (обязательно)
- `synonym` — отображаемое имя (по умолчанию = name)
- `comment` — комментарий (по умолчанию пусто)
- Глобальные флаги — по умолчанию `false`, `true`, `false`
## Объекты: два формата
Массив `objects` принимает строки (shorthand) и объекты (полная форма).
### Строковый shorthand
```
"ОбъектМетаданных: @пресет"
"ОбъектМетаданных: Право1, Право2"
```
Примеры:
```json
"objects": [
"Catalog.Номенклатура: @view",
"Document.Реализация: @edit",
"InformationRegister.Цены: Read, Update",
"DataProcessor.Загрузка: @view"
]
```
### Объектная форма (для RLS и переопределений)
```json
{
"name": "Document.Реализация",
"preset": "view",
"rights": { "Delete": false },
"rls": { "Read": "#ДляОбъекта(\"\")" }
}
```
- `preset` — базовый набор прав (`"view"`, `"edit"`)
- `rights` — переопределения: dict `{"Right": true/false}` или массив `["Right1", "Right2"]`
- `rls` — RLS-ограничения: `{"ИмяПрава": "текст условия"}`
## Пресеты — подробные таблицы
Пресеты обозначаются `@` в строковом формате. В объектной форме ключ `preset` без `@`.
### `@view` — просмотр
| Тип объекта | Права |
|-------------|-------|
| Catalog, ExchangePlan, Document, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes, BusinessProcess, Task | Read, View, InputByString |
| InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, Constant, DocumentJournal | Read, View |
| Sequence | Read |
| CommonForm, CommonCommand, Subsystem, FilterCriterion, CommonAttribute | View |
| DataProcessor, Report | Use, View |
| SessionParameter | Get |
| Configuration | ThinClient, WebClient, Output, SaveUserData, MainWindowModeNormal |
### `@edit` — полное редактирование
| Тип объекта | Права |
|-------------|-------|
| Catalog, ExchangePlan, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes | Read, Insert, Update, Delete, View, Edit, InputByString, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark |
| Document | Read, Insert, Update, Delete, View, Edit, InputByString, Posting, UndoPosting, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark, InteractivePosting, InteractivePostingRegular, InteractiveUndoPosting, InteractiveChangeOfPosted |
| BusinessProcess | Read, Insert, Update, Delete, View, Edit, InputByString, Start, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark, InteractiveActivate, InteractiveStart |
| Task | Read, Insert, Update, Delete, View, Edit, InputByString, Execute, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark, InteractiveActivate, InteractiveExecute |
| InformationRegister, AccumulationRegister, AccountingRegister, Constant | Read, Update, View, Edit |
| DocumentJournal | Read, View |
| Sequence | Read, Update |
| SessionParameter | Get, Set |
| CommonAttribute | View, Edit |
Для сервисов (WebService, HTTPService, IntegrationService) пресеты не определены — используй явные права: `"WebService.Имя: Use"`.
Если пресет не определён для типа объекта — предупреждение с подсказкой доступных.
## Русские синонимы
Скрипт автоматически транслирует русские имена в английские. Можно смешивать: `"Справочник.Контрагенты: Чтение, View"` — работает.
### Типы объектов
| Русский | English |
|---------|---------|
| `Справочник` | Catalog |
| `Документ` | Document |
| `РегистрСведений` | InformationRegister |
| `РегистрНакопления` | AccumulationRegister |
| `РегистрБухгалтерии` | AccountingRegister |
| `РегистрРасчета` | CalculationRegister |
| `Константа` | Constant |
| `ПланСчетов` | ChartOfAccounts |
| `ПланВидовХарактеристик` | ChartOfCharacteristicTypes |
| `ПланВидовРасчета` | ChartOfCalculationTypes |
| `ПланОбмена` | ExchangePlan |
| `БизнесПроцесс` | BusinessProcess |
| `Задача` | Task |
| `Обработка` | DataProcessor |
| `Отчет` | Report |
| `ОбщаяФорма` | CommonForm |
| `ОбщаяКоманда` | CommonCommand |
| `Подсистема` | Subsystem |
| `КритерийОтбора` | FilterCriterion |
| `ЖурналДокументов` | DocumentJournal |
| `Последовательность` | Sequence |
| `ВебСервис` | WebService |
| `HTTPСервис` | HTTPService |
| `СервисИнтеграции` | IntegrationService |
| `ПараметрСеанса` | SessionParameter |
| `ОбщийРеквизит` | CommonAttribute |
| `Конфигурация` | Configuration |
| `Перечисление` | Enum |
### Вложенные типы
| Русский | English |
|---------|---------|
| `Реквизит` | Attribute |
| `СтандартныйРеквизит` | StandardAttribute |
| `ТабличнаяЧасть` | TabularSection |
| `Измерение` | Dimension |
| `Ресурс` | Resource |
| `Команда` | Command |
| `РеквизитАдресации` | AddressingAttribute |
### Права (основные)
| Русский | English |
|---------|---------|
| `Чтение` | Read |
| `Добавление` | Insert |
| `Изменение` | Update |
| `Удаление` | Delete |
| `Просмотр` | View |
| `Редактирование` | Edit |
| `ВводПоСтроке` | InputByString |
| `Проведение` | Posting |
| `ОтменаПроведения` | UndoPosting |
| `Использование` | Use |
| `Получение` | Get |
| `Установка` | Set |
| `Старт` | Start |
| `Выполнение` | Execute |
| `УправлениеИтогами` | TotalsControl |
### Права (интерактивные)
| Русский | English |
|---------|---------|
| `ИнтерактивноеДобавление` | InteractiveInsert |
| `ИнтерактивнаяПометкаУдаления` | InteractiveSetDeletionMark |
| `ИнтерактивноеСнятиеПометкиУдаления` | InteractiveClearDeletionMark |
| `ИнтерактивноеУдаление` | InteractiveDelete |
| `ИнтерактивноеУдалениеПомеченных` | InteractiveDeleteMarked |
| `ИнтерактивноеПроведение` | InteractivePosting |
| `ИнтерактивноеПроведениеНеоперативное` | InteractivePostingRegular |
| `ИнтерактивнаяОтменаПроведения` | InteractiveUndoPosting |
| `ИнтерактивноеИзменениеПроведенных` | InteractiveChangeOfPosted |
| `ИнтерактивныйСтарт` | InteractiveStart |
| `ИнтерактивнаяАктивация` | InteractiveActivate |
| `ИнтерактивноеВыполнение` | InteractiveExecute |
### Права (конфигурация)
| Русский | English |
|---------|---------|
| `Администрирование` | Administration |
| `АдминистрированиеДанных` | DataAdministration |
| `ТонкийКлиент` | ThinClient |
| `ТолстыйКлиент` | ThickClient |
| `ВебКлиент` | WebClient |
| `МобильныйКлиент` | MobileClient |
| `ВнешнееСоединение` | ExternalConnection |
| `Вывод` | Output |
| `СохранениеДанныхПользователя` | SaveUserData |
## Типы объектов без прав в ролях
Следующие типы 1С **не могут** иметь права в ролях (не добавляются в `objects`):
| Тип | Причина |
|-----|---------|
| Enum (Перечисление) | Права наследуются от конфигурации, явное назначение невозможно |
| CommonModule (ОбщийМодуль) | Не имеет собственных прав в роли |
| DefinedType (ОпределяемыйТип) | Тип данных, не объект прав |
| CommonPicture (ОбщаяКартинка) | Ресурс, не объект прав |
| CommonTemplate (ОбщийМакет) | Ресурс, не объект прав |
| Language (Язык) | Конфигурационный элемент |
| FunctionalOption (ФункциональнаяОпция) | Не объект прав |
| FunctionalOptionsParameter | Не объект прав |
| EventSubscription (ПодпискаНаСобытие) | Не объект прав |
| ScheduledJob (РегламентноеЗадание) | Не объект прав |
| StyleItem (ЭлементСтиля) | Ресурс оформления |
## Шаблоны ограничений (RLS templates)
```json
"templates": [
{
"name": "ДляОбъекта(Модификатор)",
"condition": "// текст шаблона\nГДЕ 1=1\n&Модификатор"
}
]
```
- `&` в условии автоматически экранируется в `&amp;` в XML
- Ссылка на шаблон в `rls`: `"#ИмяШаблона(\"параметры\")"` — начинается с `#`
- Параметры шаблона можно передавать пустыми: `#ДляОбъекта("")`
## Примеры
### 1. Простая роль (только пресеты)
```json
{
"name": "ЧтениеНоменклатуры",
"synonym": "Чтение номенклатуры",
"objects": [
"Catalog.Номенклатура: @view",
"Catalog.Контрагенты: @view",
"DataProcessor.Загрузка: @view"
]
}
```
### 2. Роль для регламентного задания
```json
{
"name": "ОбновлениеЦен",
"synonym": "Обновление цен номенклатуры",
"objects": [
"Catalog.Номенклатура: Read",
"Catalog.Валюты: Read",
"InformationRegister.ЦеныНоменклатуры: Read, Update",
"Constant.ОсновнаяВалюта: Read"
]
}
```
### 3. Роль с RLS
```json
{
"name": "ЧтениеДокументовПоОрганизации",
"synonym": "Чтение документов (ограничение по организации)",
"objects": [
"Catalog.Организации: @view",
{
"name": "Document.РеализацияТоваровУслуг",
"preset": "view",
"rls": {
"Read": "#ДляОбъекта(\"\")"
}
}
],
"templates": [
{
"name": "ДляОбъекта(Модификатор)",
"condition": "ГДЕ Организация = &ТекущаяОрганизация"
}
]
}
```
### 4. Роль с русскими синонимами
```json
{
"name": "ПросмотрДанных",
"synonym": "Просмотр данных",
"objects": [
"Справочник.Контрагенты: @view",
"Документ.Реализация: Чтение, Просмотр",
"РегистрСведений.Цены: @edit",
"Обработка.ЗагрузкаДанных: @view"
]
}
```
### 5. Роль с переопределением прав из пресета
```json
{
"name": "ОграниченноеРедактирование",
"synonym": "Редактирование без удаления",
"objects": [
{
"name": "Catalog.Контрагенты",
"preset": "edit",
"rights": { "Delete": false }
}
]
}
```
@@ -0,0 +1,713 @@
param(
[Parameter(Mandatory)]
[string]$JsonPath,
[Parameter(Mandatory)]
[string]$OutputDir
)
$ErrorActionPreference = "Stop"
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# --- 1. Load and validate JSON ---
if (-not (Test-Path $JsonPath)) {
Write-Error "File not found: $JsonPath"
exit 1
}
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
$def = $json | ConvertFrom-Json
if (-not $def.name) {
Write-Error "JSON must have 'name' field (role programmatic name)"
exit 1
}
$roleName = "$($def.name)"
$synonym = if ($def.synonym) { "$($def.synonym)" } else { $roleName }
$comment = if ($def.comment) { "$($def.comment)" } else { "" }
# --- 2. XML helpers ---
$script:xmlBuf = $null
function X {
param([string]$text)
$script:xmlBuf.AppendLine($text) | Out-Null
}
function Esc-Xml {
param([string]$s)
return $s.Replace('&','&amp;').Replace('<','&lt;').Replace('>','&gt;').Replace('"','&quot;')
}
# --- 3. Russian synonyms → canonical English names ---
$script:typeAliases = @{
"Справочник" = "Catalog"
"Документ" = "Document"
"РегистрСведений" = "InformationRegister"
"РегистрНакопления" = "AccumulationRegister"
"РегистрБухгалтерии" = "AccountingRegister"
"РегистрРасчета" = "CalculationRegister"
"Константа" = "Constant"
"ПланСчетов" = "ChartOfAccounts"
"ПланВидовХарактеристик" = "ChartOfCharacteristicTypes"
"ПланВидовРасчета" = "ChartOfCalculationTypes"
"ПланОбмена" = "ExchangePlan"
"БизнесПроцесс" = "BusinessProcess"
"Задача" = "Task"
"Обработка" = "DataProcessor"
"Отчет" = "Report"
"ОбщаяФорма" = "CommonForm"
"ОбщаяКоманда" = "CommonCommand"
"Подсистема" = "Subsystem"
"КритерийОтбора" = "FilterCriterion"
"ЖурналДокументов" = "DocumentJournal"
"Последовательность" = "Sequence"
"ВебСервис" = "WebService"
"HTTPСервис" = "HTTPService"
"СервисИнтеграции" = "IntegrationService"
"ПараметрСеанса" = "SessionParameter"
"ОбщийРеквизит" = "CommonAttribute"
"Конфигурация" = "Configuration"
"Перечисление" = "Enum"
# Nested
"Реквизит" = "Attribute"
"СтандартныйРеквизит" = "StandardAttribute"
"ТабличнаяЧасть" = "TabularSection"
"Измерение" = "Dimension"
"Ресурс" = "Resource"
"Команда" = "Command"
"РеквизитАдресации" = "AddressingAttribute"
}
$script:rightAliases = @{
"Чтение" = "Read"
"Добавление" = "Insert"
"Изменение" = "Update"
"Удаление" = "Delete"
"Просмотр" = "View"
"Редактирование" = "Edit"
"ВводПоСтроке" = "InputByString"
"Проведение" = "Posting"
"ОтменаПроведения" = "UndoPosting"
"ИнтерактивноеДобавление" = "InteractiveInsert"
"ИнтерактивнаяПометкаУдаления" = "InteractiveSetDeletionMark"
"ИнтерактивноеСнятиеПометкиУдаления" = "InteractiveClearDeletionMark"
"ИнтерактивноеУдаление" = "InteractiveDelete"
"ИнтерактивноеУдалениеПомеченных" = "InteractiveDeleteMarked"
"ИнтерактивноеПроведение" = "InteractivePosting"
"ИнтерактивноеПроведениеНеоперативное" = "InteractivePostingRegular"
"ИнтерактивнаяОтменаПроведения" = "InteractiveUndoPosting"
"ИнтерактивноеИзменениеПроведенных" = "InteractiveChangeOfPosted"
"Использование" = "Use"
"Получение" = "Get"
"Установка" = "Set"
"Старт" = "Start"
"ИнтерактивныйСтарт" = "InteractiveStart"
"ИнтерактивнаяАктивация" = "InteractiveActivate"
"Выполнение" = "Execute"
"ИнтерактивноеВыполнение" = "InteractiveExecute"
"УправлениеИтогами" = "TotalsControl"
"Администрирование" = "Administration"
"АдминистрированиеДанных" = "DataAdministration"
"ТонкийКлиент" = "ThinClient"
"ВебКлиент" = "WebClient"
"ТолстыйКлиент" = "ThickClient"
"ВнешнееСоединение" = "ExternalConnection"
"Вывод" = "Output"
"СохранениеДанныхПользователя" = "SaveUserData"
"МобильныйКлиент" = "MobileClient"
}
# Translate Russian object name to English (e.g. "Справочник.Контрагенты" → "Catalog.Контрагенты")
function Translate-ObjectName {
param([string]$name)
$parts = $name.Split(".")
$result = @()
foreach ($p in $parts) {
if ($script:typeAliases.ContainsKey($p)) {
$result += $script:typeAliases[$p]
} else {
$result += $p
}
}
return $result -join "."
}
# Translate Russian right name to English (e.g. "Чтение" → "Read")
function Translate-RightName {
param([string]$name)
if ($script:rightAliases.ContainsKey($name)) {
return $script:rightAliases[$name]
}
return $name
}
# --- 4. Known rights per object type (source: docs/1c-role-spec.md) ---
$script:knownRights = @{
"Configuration" = @(
"Administration","DataAdministration","UpdateDataBaseConfiguration",
"ConfigurationExtensionsAdministration","ActiveUsers","EventLog","ExclusiveMode",
"ThinClient","ThickClient","WebClient","MobileClient","ExternalConnection",
"Automation","Output","SaveUserData","TechnicalSpecialistMode",
"InteractiveOpenExtDataProcessors","InteractiveOpenExtReports",
"AnalyticsSystemClient","CollaborationSystemInfoBaseRegistration",
"MainWindowModeNormal","MainWindowModeWorkplace",
"MainWindowModeEmbeddedWorkplace","MainWindowModeFullscreenWorkplace","MainWindowModeKiosk"
)
"Catalog" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveDeleteMarked",
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"Document" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"Posting","UndoPosting",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveDeleteMarked",
"InteractivePosting","InteractivePostingRegular","InteractiveUndoPosting",
"InteractiveChangeOfPosted",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"InformationRegister" = @(
"Read","Update","View","Edit","TotalsControl",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"AccumulationRegister" = @("Read","Update","View","Edit","TotalsControl")
"AccountingRegister" = @("Read","Update","View","Edit","TotalsControl")
"CalculationRegister" = @("Read","View")
"Constant" = @(
"Read","Update","View","Edit",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"ChartOfAccounts" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete",
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
"ReadDataHistory","ReadDataHistoryOfMissingData",
"UpdateDataHistory","UpdateDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment"
)
"ChartOfCharacteristicTypes" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveDeleteMarked",
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"ReadDataHistoryOfMissingData","UpdateDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"ChartOfCalculationTypes" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete",
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData"
)
"ExchangePlan" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveDeleteMarked",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"ReadDataHistoryOfMissingData","UpdateDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"BusinessProcess" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"Start","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveActivate","InteractiveStart"
)
"Task" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"Execute","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveActivate","InteractiveExecute"
)
"DataProcessor" = @("Use","View")
"Report" = @("Use","View")
"CommonForm" = @("View")
"CommonCommand" = @("View")
"Subsystem" = @("View")
"FilterCriterion" = @("View")
"DocumentJournal" = @("Read","View")
"Sequence" = @("Read","Update")
"WebService" = @("Use")
"HTTPService" = @("Use")
"IntegrationService" = @("Use")
"SessionParameter" = @("Get","Set")
"CommonAttribute" = @("View","Edit")
}
# Nested objects: Attribute, StandardAttribute, TabularSection, Dimension, Resource, AddressingAttribute
$script:nestedRights = @("View","Edit")
$script:commandRights = @("View")
# --- 4. Presets (@view, @edit) ---
$script:presets = @{
"view" = @{
"Catalog" = @("Read","View","InputByString")
"ExchangePlan" = @("Read","View","InputByString")
"Document" = @("Read","View","InputByString")
"ChartOfAccounts" = @("Read","View","InputByString")
"ChartOfCharacteristicTypes" = @("Read","View","InputByString")
"ChartOfCalculationTypes" = @("Read","View","InputByString")
"BusinessProcess" = @("Read","View","InputByString")
"Task" = @("Read","View","InputByString")
"InformationRegister" = @("Read","View")
"AccumulationRegister" = @("Read","View")
"AccountingRegister" = @("Read","View")
"CalculationRegister" = @("Read","View")
"Constant" = @("Read","View")
"DocumentJournal" = @("Read","View")
"Sequence" = @("Read")
"CommonForm" = @("View")
"CommonCommand" = @("View")
"Subsystem" = @("View")
"FilterCriterion" = @("View")
"SessionParameter" = @("Get")
"CommonAttribute" = @("View")
"DataProcessor" = @("Use","View")
"Report" = @("Use","View")
"Configuration" = @("ThinClient","WebClient","Output","SaveUserData","MainWindowModeNormal")
}
"edit" = @{
"Catalog" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
"ExchangePlan" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
"Document" = @("Read","Insert","Update","Delete","View","Edit","InputByString","Posting","UndoPosting","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark","InteractivePosting","InteractivePostingRegular","InteractiveUndoPosting","InteractiveChangeOfPosted")
"ChartOfAccounts" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
"ChartOfCharacteristicTypes" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
"ChartOfCalculationTypes" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
"BusinessProcess" = @("Read","Insert","Update","Delete","View","Edit","InputByString","Start","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark","InteractiveActivate","InteractiveStart")
"Task" = @("Read","Insert","Update","Delete","View","Edit","InputByString","Execute","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark","InteractiveActivate","InteractiveExecute")
"InformationRegister" = @("Read","Update","View","Edit")
"AccumulationRegister" = @("Read","Update","View","Edit")
"AccountingRegister" = @("Read","Update","View","Edit")
"Constant" = @("Read","Update","View","Edit")
"DocumentJournal" = @("Read","View")
"Sequence" = @("Read","Update")
"SessionParameter" = @("Get","Set")
"CommonAttribute" = @("View","Edit")
}
}
# --- 5. Helpers ---
function Get-ObjectType {
param([string]$objectName)
$dotIdx = $objectName.IndexOf(".")
if ($dotIdx -lt 0) { return $objectName }
return $objectName.Substring(0, $dotIdx)
}
function Is-NestedObject {
param([string]$objectName)
return ($objectName.Split(".").Count -ge 3)
}
function Resolve-Preset {
param([string]$objectType, [string]$presetName)
$preset = $presetName.TrimStart('@')
if (-not $script:presets.ContainsKey($preset)) {
Write-Warning "Unknown preset '@$preset'. Known: @view, @edit"
return @()
}
$typeMap = $script:presets[$preset]
if (-not $typeMap.ContainsKey($objectType)) {
$available = @()
foreach ($k in $script:presets.Keys) {
if ($script:presets[$k].ContainsKey($objectType)) {
$available += "@$k"
}
}
$availStr = if ($available.Count -gt 0) { $available -join ", " } else { "none" }
Write-Warning "Preset '@$preset' not defined for type '$objectType'. Available: $availStr"
return @()
}
return @($typeMap[$objectType])
}
function Validate-RightName {
param([string]$objectName, [string]$rightName)
$objectType = Get-ObjectType $objectName
if (Is-NestedObject $objectName) {
if ($objectName -match '\.Command\.') {
if ($rightName -notin $script:commandRights) {
Write-Warning "${objectName}: '$rightName' not valid for commands (only: View)"
return $false
}
} else {
if ($rightName -notin $script:nestedRights) {
Write-Warning "${objectName}: '$rightName' not valid for nested objects (only: View, Edit)"
return $false
}
}
return $true
}
if (-not $script:knownRights.ContainsKey($objectType)) {
Write-Warning "${objectName}: unknown object type '$objectType'"
return $true
}
$validRights = $script:knownRights[$objectType]
if ($rightName -notin $validRights) {
$suggestions = @($validRights | Where-Object {
$_ -like "*$rightName*" -or $rightName -like "*$_*"
})
$sugStr = if ($suggestions.Count -gt 0) { " Did you mean: $($suggestions -join ', ')?" } else { "" }
Write-Warning "${objectName}: unknown right '$rightName'.$sugStr"
return $false
}
return $true
}
# --- 6. Parse object entries ---
function Parse-ObjectEntry {
param($entry)
# --- String shorthand ---
if ($entry -is [string]) {
$colonIdx = $entry.IndexOf(':')
if ($colonIdx -lt 0) {
Write-Warning "Invalid string '$entry' -- expected 'Object.Name: @preset' or 'Object.Name: Right1, Right2'"
return $null
}
$objName = Translate-ObjectName ($entry.Substring(0, $colonIdx).Trim())
$rightsStr = $entry.Substring($colonIdx + 1).Trim()
$objectType = Get-ObjectType $objName
if ($rightsStr.StartsWith('@')) {
$rightNames = @(Resolve-Preset -objectType $objectType -presetName $rightsStr)
} else {
$rightNames = @($rightsStr -split ',\s*' | ForEach-Object { Translate-RightName $_.Trim() } | Where-Object { $_ })
foreach ($r in $rightNames) {
Validate-RightName -objectName $objName -rightName $r | Out-Null
}
}
$rights = @()
foreach ($r in $rightNames) {
$rights += ,@{Name=$r; Value="true"; Condition=$null}
}
return @{ Name = $objName; Rights = $rights }
}
# --- Object form ---
$objName = Translate-ObjectName "$($entry.name)"
if (-not $objName) {
Write-Warning "Object entry missing 'name' field"
return $null
}
$objectType = Get-ObjectType $objName
$rightsMap = [ordered]@{}
# 1) Start with preset
if ($entry.preset) {
$presetRights = @(Resolve-Preset -objectType $objectType -presetName "$($entry.preset)")
foreach ($r in $presetRights) {
$rightsMap[$r] = @{Value="true"; Condition=$null}
}
}
# 2) Apply explicit rights
if ($entry.rights) {
if ($entry.rights -is [array]) {
foreach ($r in $entry.rights) {
$rName = Translate-RightName "$r"
Validate-RightName -objectName $objName -rightName $rName | Out-Null
$rightsMap[$rName] = @{Value="true"; Condition=$null}
}
} else {
foreach ($p in $entry.rights.PSObject.Properties) {
$rName = Translate-RightName $p.Name
Validate-RightName -objectName $objName -rightName $rName | Out-Null
$boolVal = $p.Value
if ($boolVal -eq $true -or "$boolVal" -eq "True") {
$rightsMap[$rName] = @{Value="true"; Condition=$null}
} else {
$rightsMap[$rName] = @{Value="false"; Condition=$null}
}
}
}
}
# 3) Apply RLS conditions
if ($entry.rls) {
foreach ($p in $entry.rls.PSObject.Properties) {
$rlsRight = Translate-RightName $p.Name
if ($rightsMap.Contains($rlsRight)) {
$rightsMap[$rlsRight].Condition = "$($p.Value)"
} else {
Write-Warning "${objName}: RLS for '$rlsRight' but this right is not in the rights list"
}
}
}
# Convert to array
$rights = @()
foreach ($k in $rightsMap.Keys) {
$rights += ,@{
Name = $k
Value = $rightsMap[$k].Value
Condition = $rightsMap[$k].Condition
}
}
return @{ Name = $objName; Rights = $rights }
}
# --- 7. Parse all object entries ---
$parsedObjects = @()
if ($def.objects) {
foreach ($entry in $def.objects) {
$parsed = Parse-ObjectEntry -entry $entry
if ($parsed) {
$parsedObjects += ,$parsed
}
}
}
# --- 8. Generate UUID ---
$uuid = [guid]::NewGuid().ToString()
# --- 9. Emit metadata XML (Roles/Name.xml) ---
$script:xmlBuf = New-Object System.Text.StringBuilder 4096
X '<?xml version="1.0" encoding="UTF-8"?>'
X '<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses"'
X ' xmlns:app="http://v8.1c.ru/8.2/managed-application/core"'
X ' xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config"'
X ' xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi"'
X ' xmlns:ent="http://v8.1c.ru/8.1/data/enterprise"'
X ' xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform"'
X ' xmlns:style="http://v8.1c.ru/8.1/data/ui/style"'
X ' xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system"'
X ' xmlns:v8="http://v8.1c.ru/8.1/data/core"'
X ' xmlns:v8ui="http://v8.1c.ru/8.1/data/ui"'
X ' xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web"'
X ' xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows"'
X ' xmlns:xen="http://v8.1c.ru/8.3/xcf/enums"'
X ' xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef"'
X ' xmlns:xr="http://v8.1c.ru/8.3/xcf/readable"'
X ' xmlns:xs="http://www.w3.org/2001/XMLSchema"'
X ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
X ' version="2.17">'
X " <Role uuid=`"$uuid`">"
X ' <Properties>'
X " <Name>$roleName</Name>"
X ' <Synonym>'
X ' <v8:item>'
X ' <v8:lang>ru</v8:lang>'
X " <v8:content>$(Esc-Xml $synonym)</v8:content>"
X ' </v8:item>'
X ' </Synonym>'
if ($comment) {
X " <Comment>$(Esc-Xml $comment)</Comment>"
} else {
X ' <Comment/>'
}
X ' </Properties>'
X ' </Role>'
X '</MetaDataObject>'
$metadataXml = $script:xmlBuf.ToString()
# --- 10. Emit Rights XML (Roles/Name/Ext/Rights.xml) ---
$script:xmlBuf = New-Object System.Text.StringBuilder 8192
X '<?xml version="1.0" encoding="UTF-8"?>'
X '<Rights xmlns="http://v8.1c.ru/8.2/roles"'
X ' xmlns:xs="http://www.w3.org/2001/XMLSchema"'
X ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
X ' xsi:type="Rights" version="2.17">'
# Global flags (defaults match typical 1C roles)
$sfno = if ($null -ne $def.setForNewObjects) { "$($def.setForNewObjects)".ToLower() } else { "false" }
$sfab = if ($null -ne $def.setForAttributesByDefault) { "$($def.setForAttributesByDefault)".ToLower() } else { "true" }
$irco = if ($null -ne $def.independentRightsOfChildObjects) { "$($def.independentRightsOfChildObjects)".ToLower() } else { "false" }
X " <setForNewObjects>$sfno</setForNewObjects>"
X " <setForAttributesByDefault>$sfab</setForAttributesByDefault>"
X " <independentRightsOfChildObjects>$irco</independentRightsOfChildObjects>"
# Object blocks
$totalRights = 0
foreach ($obj in $parsedObjects) {
X ' <object>'
X " <name>$($obj.Name)</name>"
foreach ($right in $obj.Rights) {
X ' <right>'
X " <name>$($right.Name)</name>"
X " <value>$($right.Value)</value>"
if ($right.Condition) {
X ' <restrictionByCondition>'
X " <condition>$(Esc-Xml $right.Condition)</condition>"
X ' </restrictionByCondition>'
}
X ' </right>'
$totalRights++
}
X ' </object>'
}
# RLS restriction templates
$templateCount = 0
if ($def.templates) {
foreach ($tpl in $def.templates) {
X ' <restrictionTemplate>'
X " <name>$(Esc-Xml "$($tpl.name)")</name>"
X " <condition>$(Esc-Xml "$($tpl.condition)")</condition>"
X ' </restrictionTemplate>'
$templateCount++
}
}
X '</Rights>'
$rightsXml = $script:xmlBuf.ToString()
# --- 11. Write output files ---
$outDir = if ([System.IO.Path]::IsPathRooted($OutputDir)) {
$OutputDir
} else {
Join-Path (Get-Location) $OutputDir
}
# Metadata: OutputDir/RoleName.xml
$metadataPath = Join-Path $outDir "$roleName.xml"
if (-not (Test-Path $outDir)) {
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
}
# Rights: OutputDir/RoleName/Ext/Rights.xml
$roleSubDir = Join-Path $outDir $roleName
$extDir = Join-Path $roleSubDir "Ext"
$rightsPath = Join-Path $extDir "Rights.xml"
if (-not (Test-Path $extDir)) {
New-Item -ItemType Directory -Path $extDir -Force | Out-Null
}
$enc = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($metadataPath, $metadataXml, $enc)
[System.IO.File]::WriteAllText($rightsPath, $rightsXml, $enc)
# --- 12. Register in Configuration.xml ---
$configDir = Split-Path $outDir -Parent
$configXmlPath = Join-Path $configDir "Configuration.xml"
$regResult = $null
if (Test-Path $configXmlPath) {
$configDoc = New-Object System.Xml.XmlDocument
$configDoc.PreserveWhitespace = $true
$configDoc.Load($configXmlPath)
$nsMgr = New-Object System.Xml.XmlNamespaceManager($configDoc.NameTable)
$nsMgr.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses")
$childObjects = $configDoc.SelectSingleNode("//md:Configuration/md:ChildObjects", $nsMgr)
if ($childObjects) {
$existing = $childObjects.SelectNodes("md:Role", $nsMgr)
$alreadyExists = $false
foreach ($r in $existing) {
if ($r.InnerText -eq $roleName) {
$alreadyExists = $true
break
}
}
if ($alreadyExists) {
$regResult = "already"
} else {
$roleElem = $configDoc.CreateElement("Role", "http://v8.1c.ru/8.3/MDClasses")
$roleElem.InnerText = $roleName
if ($existing.Count -gt 0) {
# Insert after last existing <Role>
$lastRole = $existing[$existing.Count - 1]
$newWs = $configDoc.CreateWhitespace("`n`t`t`t")
$childObjects.InsertAfter($newWs, $lastRole) | Out-Null
$childObjects.InsertAfter($roleElem, $newWs) | Out-Null
} else {
# No existing roles — insert before closing whitespace
$lastChild = $childObjects.LastChild
if ($lastChild.NodeType -eq [System.Xml.XmlNodeType]::Whitespace) {
$newWs = $configDoc.CreateWhitespace("`n`t`t`t")
$childObjects.InsertBefore($newWs, $lastChild) | Out-Null
$childObjects.InsertBefore($roleElem, $lastChild) | Out-Null
} else {
$childObjects.AppendChild($configDoc.CreateWhitespace("`n`t`t`t")) | Out-Null
$childObjects.AppendChild($roleElem) | Out-Null
$childObjects.AppendChild($configDoc.CreateWhitespace("`n`t`t")) | Out-Null
}
}
# Save
$cfgSettings = New-Object System.Xml.XmlWriterSettings
$cfgSettings.Encoding = New-Object System.Text.UTF8Encoding($true)
$cfgSettings.Indent = $false
$stream = New-Object System.IO.FileStream($configXmlPath, [System.IO.FileMode]::Create)
$writer = [System.Xml.XmlWriter]::Create($stream, $cfgSettings)
$configDoc.Save($writer)
$writer.Close()
$stream.Close()
$regResult = "added"
}
} else {
$regResult = "no-childobj"
}
} else {
$regResult = "no-config"
}
# --- 13. Summary ---
Write-Host "[OK] Role '$roleName' compiled"
Write-Host " UUID: $uuid"
Write-Host " Metadata: $metadataPath"
Write-Host " Rights: $rightsPath"
Write-Host " Objects: $($parsedObjects.Count), Rights: $totalRights, Templates: $templateCount"
switch ($regResult) {
"added" { Write-Host " Configuration.xml: <Role>$roleName</Role> added to ChildObjects" }
"already" { Write-Host " Configuration.xml: <Role>$roleName</Role> already registered" }
"no-childobj" { Write-Warning "Configuration.xml found but <ChildObjects> not found" }
"no-config" { Write-Warning "Configuration.xml not found at $configXmlPath — register manually" }
}
@@ -7,6 +7,7 @@
)
$ErrorActionPreference = 'Stop'
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# --- Output helper (always collect, paginate at the end) ---
$script:lines = @()
+105
View File
@@ -0,0 +1,105 @@
---
name: role-validate
description: Валидация структурной корректности роли 1С (Rights.xml) — формат, права, RLS, шаблоны
argument-hint: <RightsPath>
allowed-tools:
- Bash
- Read
---
# /role-validate — валидация роли 1С
Проверяет корректность `Rights.xml` роли: формат XML, namespace, глобальные флаги, типы объектов, имена прав, RLS-ограничения, шаблоны. Опционально проверяет метаданные роли (UUID, имя, синоним).
## Использование
```
/role-validate <RightsPath> [MetadataPath]
```
## Запуск скрипта
```powershell
powershell.exe -NoProfile -File .claude\skills\role-validate\scripts\role-validate.ps1 -RightsPath <path> [-MetadataPath <path>] [-OutFile <output.txt>]
```
### Параметры
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-RightsPath` | да | Путь к `Rights.xml` роли |
| `-MetadataPath` | нет | Путь к метаданным роли (`Roles/ИмяРоли.xml`) |
| `-OutFile` | нет | Записать результат в файл (UTF-8 BOM). Без этого — вывод в консоль |
**Важно:** Для кириллических путей используй `-OutFile` и читай результат через Read tool.
## Проверки
### Rights.xml
1. XML well-formed — парсинг без ошибок
2. Корневой элемент `<Rights>` с namespace `http://v8.1c.ru/8.2/roles`
3. Три глобальных флага: `setForNewObjects`, `setForAttributesByDefault`, `independentRightsOfChildObjects`
4. Для каждого `<object>`:
- `<name>` не пуст
- Тип объекта распознан (Catalog, Document, InformationRegister и т.д.)
- Каждое `<right>` имеет `<name>` и `<value>` (`true`/`false`)
- Имя права валидно для данного типа объекта (с подсказкой при опечатке)
5. Вложенные объекты (3+ сегмента через `.`): допустимы только View, Edit (или Use для IntegrationServiceChannel)
6. RLS `<restrictionByCondition>`: `<condition>` не пуст
7. Шаблоны `<restrictionTemplate>`: `<name>` и `<condition>` не пусты
### Метаданные (опционально)
- Элемент `<Role>` найден
- UUID в корректном формате
- `<Name>` не пуст
- `<Synonym>` присутствует
## Формат вывода
```
Validating: Roles/МояРоль/Ext/Rights.xml
OK XML well-formed
OK Root element: <Rights> with correct namespace
OK 3 global flags present
WARN Document.Реализация: unknown right 'Rea'. Did you mean: Read?
OK 12 objects, 45 rights
OK 2 RLS restrictions
OK 1 templates: ДляОбъекта
OK Metadata: UUID valid (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
OK Metadata: Name = МояРоль
OK Metadata: Synonym present
---
Result: 0 error(s), 1 warning(s)
```
### Уровни сообщений
| Маркер | Значение |
|--------|----------|
| `OK` | Проверка пройдена |
| `WARN` | Предупреждение (неизвестный тип объекта, подозрительное имя права) |
| `ERR` | Ошибка (невалидный XML, отсутствие обязательных элементов) |
Код возврата: `0` — без ошибок, `1` — есть ошибки.
## Примеры
### Только Rights.xml
```
/role-validate upload/acc_8.3.20/Roles/БазовыеПраваБП/Ext/Rights.xml
```
### С проверкой метаданных
```
/role-validate Roles/МояРоль/Ext/Rights.xml Roles/МояРоль.xml
```
### Верификация после /role-compile
```
/role-compile role.json Roles/
/role-validate Roles/МояРоль/Ext/Rights.xml Roles/МояРоль.xml
```
@@ -0,0 +1,472 @@
param(
[Parameter(Mandatory)]
[string]$RightsPath,
[string]$MetadataPath,
[string]$OutFile
)
$ErrorActionPreference = "Stop"
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# --- 1. Known rights per object type ---
$script:knownRights = @{
"Configuration" = @(
"Administration","DataAdministration","UpdateDataBaseConfiguration",
"ConfigurationExtensionsAdministration","ActiveUsers","EventLog","ExclusiveMode",
"ThinClient","ThickClient","WebClient","MobileClient","ExternalConnection",
"Automation","Output","SaveUserData","TechnicalSpecialistMode",
"InteractiveOpenExtDataProcessors","InteractiveOpenExtReports",
"AnalyticsSystemClient","CollaborationSystemInfoBaseRegistration",
"MainWindowModeNormal","MainWindowModeWorkplace",
"MainWindowModeEmbeddedWorkplace","MainWindowModeFullscreenWorkplace","MainWindowModeKiosk"
)
"Catalog" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveDeleteMarked",
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"Document" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"Posting","UndoPosting",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveDeleteMarked",
"InteractivePosting","InteractivePostingRegular","InteractiveUndoPosting",
"InteractiveChangeOfPosted",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"InformationRegister" = @(
"Read","Update","View","Edit","TotalsControl",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"AccumulationRegister" = @("Read","Update","View","Edit","TotalsControl")
"AccountingRegister" = @("Read","Update","View","Edit","TotalsControl")
"CalculationRegister" = @("Read","View")
"Constant" = @(
"Read","Update","View","Edit",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"ChartOfAccounts" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete",
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
"ReadDataHistory","ReadDataHistoryOfMissingData",
"UpdateDataHistory","UpdateDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment"
)
"ChartOfCharacteristicTypes" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveDeleteMarked",
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"ReadDataHistoryOfMissingData","UpdateDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"ChartOfCalculationTypes" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete",
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData"
)
"ExchangePlan" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveDeleteMarked",
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
"ReadDataHistoryOfMissingData","UpdateDataHistoryOfMissingData",
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
)
"BusinessProcess" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"Start","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveActivate","InteractiveStart"
)
"Task" = @(
"Read","Insert","Update","Delete","View","Edit","InputByString",
"Execute","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
"InteractiveDelete","InteractiveActivate","InteractiveExecute"
)
"DataProcessor" = @("Use","View")
"Report" = @("Use","View")
"CommonForm" = @("View")
"CommonCommand" = @("View")
"Subsystem" = @("View")
"FilterCriterion" = @("View")
"DocumentJournal" = @("Read","View")
"Sequence" = @("Read","Update")
"WebService" = @("Use")
"HTTPService" = @("Use")
"IntegrationService" = @("Use")
"SessionParameter" = @("Get","Set")
"CommonAttribute" = @("View","Edit")
}
$script:nestedRights = @("View","Edit")
$script:channelRights = @("Use")
$script:commandRights = @("View")
# --- 2. Output helpers ---
$script:lines = @()
$script:errors = 0
$script:warnings = 0
function Out-OK {
param([string]$msg)
$script:lines += " OK $msg"
}
function Out-WARN {
param([string]$msg)
$script:warnings++
$script:lines += " WARN $msg"
}
function Out-ERR {
param([string]$msg)
$script:errors++
$script:lines += " ERR $msg"
}
function Get-ObjectType {
param([string]$name)
$dotIdx = $name.IndexOf(".")
if ($dotIdx -lt 0) { return $name }
return $name.Substring(0, $dotIdx)
}
function Is-NestedObject {
param([string]$name)
return ($name.Split(".").Count -ge 3)
}
function Find-Similar {
param([string]$needle, [string[]]$haystack)
$result = @($haystack | Where-Object {
$_ -like "*$needle*" -or $needle -like "*$_*"
})
if ($result.Count -gt 3) { $result = $result[0..2] }
return $result
}
# --- 3. Validate Rights.xml ---
$script:lines += "Validating: $RightsPath"
if (-not (Test-Path $RightsPath)) {
Out-ERR "File not found: $RightsPath"
$script:lines += "---"
$script:lines += "Result: $($script:errors) error(s), $($script:warnings) warning(s)"
$output = $script:lines -join "`n"
if ($OutFile) {
$enc = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($OutFile, $output, $enc)
} else {
Write-Host $output
}
exit 1
}
# 3a. Parse XML
try {
[xml]$xml = Get-Content -Path $RightsPath -Encoding UTF8
Out-OK "XML well-formed"
} catch {
Out-ERR "XML parse error: $($_.Exception.Message)"
$script:lines += "---"
$script:lines += "Result: $($script:errors) error(s), $($script:warnings) warning(s)"
$output = $script:lines -join "`n"
if ($OutFile) {
$enc = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($OutFile, $output, $enc)
} else {
Write-Host $output
}
exit 1
}
$root = $xml.DocumentElement
$rightsNs = "http://v8.1c.ru/8.2/roles"
# 3b. Check root element
if ($root.LocalName -ne "Rights") {
Out-ERR "Root element is '$($root.LocalName)', expected 'Rights'"
} elseif ($root.NamespaceURI -ne $rightsNs) {
Out-WARN "Namespace is '$($root.NamespaceURI)', expected '$rightsNs'"
} else {
Out-OK "Root element: <Rights> with correct namespace"
}
# 3c. Global flags
$flagNames = @("setForNewObjects","setForAttributesByDefault","independentRightsOfChildObjects")
$flagsFound = 0
foreach ($fn in $flagNames) {
$node = $root.GetElementsByTagName($fn, $rightsNs)
if ($node.Count -gt 0) {
$val = $node[0].InnerText
if ($val -ne "true" -and $val -ne "false") {
Out-WARN "$fn = '$val' (expected 'true' or 'false')"
}
$flagsFound++
} else {
Out-WARN "Missing global flag: $fn"
}
}
if ($flagsFound -eq 3) {
Out-OK "3 global flags present"
}
# 3d. Objects
$objects = $root.GetElementsByTagName("object", $rightsNs)
$objCount = $objects.Count
$rightCount = 0
$rlsCount = 0
foreach ($obj in $objects) {
$objName = ""
foreach ($child in $obj.ChildNodes) {
if ($child.LocalName -eq "name") {
$objName = $child.InnerText
break
}
}
if (-not $objName) {
Out-ERR "Object without <name>"
continue
}
$objectType = Get-ObjectType $objName
$isNested = Is-NestedObject $objName
# Check object type is known
if (-not $isNested -and -not $script:knownRights.ContainsKey($objectType)) {
Out-WARN "${objName}: unknown object type '$objectType'"
}
# Check rights
foreach ($child in $obj.ChildNodes) {
if ($child.LocalName -ne "right") { continue }
$rName = ""
$rValue = ""
$hasRLS = $false
foreach ($rc in $child.ChildNodes) {
if ($rc.LocalName -eq "name") { $rName = $rc.InnerText }
if ($rc.LocalName -eq "value") { $rValue = $rc.InnerText }
if ($rc.LocalName -eq "restrictionByCondition") {
$hasRLS = $true
$rlsCount++
# Check condition not empty
$condNode = $null
foreach ($rcc in $rc.ChildNodes) {
if ($rcc.LocalName -eq "condition") { $condNode = $rcc }
}
if (-not $condNode -or -not $condNode.InnerText) {
Out-WARN "${objName}: RLS condition for '$rName' is empty"
}
}
}
if (-not $rName) {
Out-ERR "${objName}: <right> without <name>"
continue
}
if ($rValue -ne "true" -and $rValue -ne "false") {
Out-ERR "${objName}: right '$rName' has invalid value '$rValue'"
continue
}
$rightCount++
# Validate right name
if ($isNested) {
if ($objName -match '\.Command\.') {
if ($rName -notin $script:commandRights) {
Out-WARN "${objName}: '$rName' not valid for commands (only: View)"
}
} elseif ($objName -match '\.IntegrationServiceChannel\.') {
if ($rName -notin $script:channelRights) {
Out-WARN "${objName}: '$rName' not valid for channels (only: Use)"
}
} else {
if ($rName -notin $script:nestedRights) {
Out-WARN "${objName}: '$rName' not valid for nested objects (only: View, Edit)"
}
}
} elseif ($script:knownRights.ContainsKey($objectType)) {
$validRights = $script:knownRights[$objectType]
if ($rName -notin $validRights) {
$similar = Find-Similar -needle $rName -haystack $validRights
$sugStr = if ($similar.Count -gt 0) { " Did you mean: $($similar -join ', ')?" } else { "" }
Out-WARN "${objName}: unknown right '$rName'.$sugStr"
}
}
}
}
Out-OK "$objCount objects, $rightCount rights"
if ($rlsCount -gt 0) {
Out-OK "$rlsCount RLS restrictions"
}
# 3e. Templates
$templates = $root.GetElementsByTagName("restrictionTemplate", $rightsNs)
if ($templates.Count -gt 0) {
$tplNames = @()
foreach ($tpl in $templates) {
$tName = ""
$tCond = ""
foreach ($child in $tpl.ChildNodes) {
if ($child.LocalName -eq "name") { $tName = $child.InnerText }
if ($child.LocalName -eq "condition") { $tCond = $child.InnerText }
}
if (-not $tName) {
Out-WARN "Restriction template without <name>"
} else {
$parenIdx = $tName.IndexOf("(")
$shortName = if ($parenIdx -gt 0) { $tName.Substring(0, $parenIdx) } else { $tName }
$tplNames += $shortName
}
if (-not $tCond) {
Out-WARN "Template '$tName': empty <condition>"
}
}
Out-OK "$($templates.Count) templates: $($tplNames -join ', ')"
}
# --- 4. Validate metadata (optional) ---
if ($MetadataPath) {
$script:lines += ""
if (-not (Test-Path $MetadataPath)) {
Out-ERR "Metadata file not found: $MetadataPath"
} else {
try {
[xml]$metaXml = Get-Content -Path $MetadataPath -Encoding UTF8
$roleNode = $metaXml.DocumentElement.SelectSingleNode("//*[local-name()='Role']")
if (-not $roleNode) {
Out-ERR "Metadata: <Role> element not found"
} else {
$uuid = $roleNode.GetAttribute("uuid")
if ($uuid -match '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$') {
Out-OK "Metadata: UUID valid ($uuid)"
} else {
Out-ERR "Metadata: invalid UUID format '$uuid'"
}
$nameNode = $roleNode.SelectSingleNode(".//*[local-name()='Name']")
if ($nameNode -and $nameNode.InnerText) {
Out-OK "Metadata: Name = $($nameNode.InnerText)"
} else {
Out-ERR "Metadata: <Name> is empty or missing"
}
$synNode = $roleNode.SelectSingleNode(".//*[local-name()='Synonym']")
if ($synNode -and $synNode.InnerXml) {
Out-OK "Metadata: Synonym present"
} else {
Out-WARN "Metadata: <Synonym> is empty"
}
}
} catch {
Out-ERR "Metadata XML parse error: $($_.Exception.Message)"
}
}
}
# --- 5. Check registration in Configuration.xml ---
# Infer paths: RightsPath = .../Roles/Name/Ext/Rights.xml
$extDir2 = Split-Path (Resolve-Path $RightsPath).Path -Parent
$roleDir2 = Split-Path $extDir2 -Parent
$rolesDir2 = Split-Path $roleDir2 -Parent
$configDir2 = Split-Path $rolesDir2 -Parent
$configXmlPath2 = Join-Path $configDir2 "Configuration.xml"
$inferredRoleName = Split-Path $roleDir2 -Leaf
# Use metadata name if available
if ($MetadataPath -and (Test-Path $MetadataPath)) {
try {
[xml]$metaXml2 = Get-Content -Path $MetadataPath -Encoding UTF8
$nameNode2 = $metaXml2.DocumentElement.SelectSingleNode("//*[local-name()='Role']//*[local-name()='Name']")
if ($nameNode2 -and $nameNode2.InnerText) {
$inferredRoleName = $nameNode2.InnerText
}
} catch { }
}
if (Test-Path $configXmlPath2) {
$script:lines += ""
try {
[xml]$cfgXml = Get-Content -Path $configXmlPath2 -Encoding UTF8
$cfgNs = New-Object System.Xml.XmlNamespaceManager($cfgXml.NameTable)
$cfgNs.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses")
$childObj = $cfgXml.SelectSingleNode("//md:Configuration/md:ChildObjects", $cfgNs)
if ($childObj) {
$roleNodes = $childObj.SelectNodes("md:Role", $cfgNs)
$found = $false
foreach ($rn in $roleNodes) {
if ($rn.InnerText -eq $inferredRoleName) {
$found = $true
break
}
}
if ($found) {
Out-OK "Configuration.xml: <Role>$inferredRoleName</Role> registered"
} else {
Out-WARN "Configuration.xml: <Role>$inferredRoleName</Role> NOT found in ChildObjects"
}
}
} catch {
Out-WARN "Configuration.xml: parse error — $($_.Exception.Message)"
}
}
# --- 6. Summary ---
$script:lines += "---"
$script:lines += "Result: $($script:errors) error(s), $($script:warnings) warning(s)"
$output = $script:lines -join "`n"
if ($OutFile) {
$outPath = if ([System.IO.Path]::IsPathRooted($OutFile)) { $OutFile } else { Join-Path (Get-Location) $OutFile }
$outDir = [System.IO.Path]::GetDirectoryName($outPath)
if (-not (Test-Path $outDir)) {
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
}
$enc = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($outPath, $output, $enc)
Write-Host "[OK] Validation result written to: $outPath"
} else {
Write-Host $output
}
if ($script:errors -gt 0) { exit 1 } else { exit 0 }
+4 -2
View File
@@ -22,7 +22,7 @@
| Внешние обработки (EPF) | 10 навыков `/epf-*` | Создание, модификация, сборка обработок из XML-исходников | [Подробнее](docs/epf-guide.md) |
| Табличный документ (MXL) | 4 навыка `/mxl-*` | Анализ, создание, компиляция макетов печатных форм | [Подробнее](docs/mxl-guide.md) |
| Управляемые формы (Form) | 6 навыков `/form-*` | Создание, анализ, генерация, модификация, валидация управляемых форм | [Подробнее](docs/form-guide.md) |
| Роли (Role) | 2 навыка `/role-*` | Анализ прав роли, создание роли из описания | [Подробнее](docs/role-guide.md) |
| Роли (Role) | 3 навыка `/role-*` | Анализ прав роли, создание из JSON DSL, валидация | [Подробнее](docs/role-guide.md) |
| Утилиты | `/img-grid` | Наложение сетки на изображение для определения пропорций колонок | — |
## Требования
@@ -40,6 +40,7 @@
- [MXL DSL](docs/mxl-dsl-spec.md) — JSON-формат описания макета для `/mxl-compile` и `/mxl-decompile`
- [Form DSL](docs/form-dsl-spec.md) — JSON-формат описания формы для `/form-compile`
- [Роли (Rights.xml)](docs/1c-role-spec.md) — XML-формат прав роли, типы объектов, RLS
- [Role DSL](docs/role-dsl-spec.md) — JSON-формат описания ролей для `/role-compile`
## Структура репозитория
@@ -66,7 +67,8 @@
├── form-edit/ # Добавление элементов в форму
├── form-patterns/ # Справочник паттернов компоновки форм
├── role-info/ # Анализ прав роли
├── role-compile/ # Создание роли из описания
├── role-compile/ # Создание роли из JSON DSL
├── role-validate/ # Валидация роли
└── img-grid/ # Сетка для анализа изображений
docs/
├── epf-guide.md # Гайд: внешние обработки
+957
View File
@@ -0,0 +1,957 @@
# Спецификация XML-формата схемы компоновки данных 1С (DCS)
Спецификация формата `DataCompositionSchema` — макетов типа «Схема компоновки данных» в конфигурации 1С:Предприятие 8.3.
Составлена на основе анализа 930 схем конфигурации «Бухгалтерия предприятия 3.0.180» (платформа 8.3.24).
---
## 0. Файловая структура
### Два файла на каждую схему
```
<Объект>/Templates/
ИмяМакета.xml ← метаданные (UUID, имя, TemplateType)
ИмяМакета/
Ext/
Template.xml ← тело схемы (DataCompositionSchema)
```
Типичные имена макетов: `ОсновнаяСхемаКомпоновкиДанных`, `СхемаКомпоновкиДанных`, произвольные.
### Метаданные макета — шаблон
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses"
xmlns:v8="http://v8.1c.ru/8.1/data/core"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.17">
<Template uuid="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX">
<Properties>
<Name>ОсновнаяСхемаКомпоновкиДанных</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основная схема компоновки данных</v8:content>
</v8:item>
</Synonym>
<Comment/>
<TemplateType>DataCompositionSchema</TemplateType>
</Properties>
</Template>
</MetaDataObject>
```
Значение `TemplateType` для DCS всегда: **`DataCompositionSchema`**.
### Где встречаются DCS-макеты
| Тип объекта метаданных | Частота | Примечание |
|---|---|---|
| Reports (Отчёты) | ~420 | Основное место — каждый отчёт СКД |
| DataProcessors (Обработки) | ~11 | Обработки с отчётными функциями |
| Enums (Перечисления) | ~20 | Дополнительные ссылки |
| Catalogs (Справочники) | ~5 | Запросы к справочным данным |
| DocumentJournals | ~4 | Журналы документов |
| CommonTemplates | ~3 | Общие макеты |
| InformationRegisters | ~2 | Регистры сведений |
| Documents (Документы) | ~1 | Редко |
---
## 1. Пространства имён
Корневой элемент — `<DataCompositionSchema>`.
```xml
<DataCompositionSchema
xmlns="http://v8.1c.ru/8.1/data-composition-system/schema"
xmlns:dcscom="http://v8.1c.ru/8.1/data-composition-system/common"
xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core"
xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings"
xmlns:v8="http://v8.1c.ru/8.1/data/core"
xmlns:v8ui="http://v8.1c.ru/8.1/data/ui"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
```
| Префикс | URI | Назначение |
|---|---|---|
| *(default)* | `.../data-composition-system/schema` | Элементы схемы (dataSource, dataSet, field, parameter, ...) |
| `dcscom` | `.../data-composition-system/common` | Общие типы СКД (dimension, account, role, ...) |
| `dcscor` | `.../data-composition-system/core` | Ядро СКД (Field, SettingsParameterValue, ChoiceParameterLinks, ...) |
| `dcsset` | `.../data-composition-system/settings` | Настройки варианта (selection, filter, order, group, ...) |
| `v8` | `.../data/core` | Типы данных ядра (LocalStringType, Type, StandardPeriod, ...) |
| `v8ui` | `.../data/ui` | UI-типы (HorizontalAlign, ...) |
| `xs` | `.../XMLSchema` | Стандартные XSD-типы (string, dateTime, boolean, decimal, ...) |
| `xsi` | `.../XMLSchema-instance` | Атрибуты экземпляра (xsi:type, xsi:nil) |
Дополнительные пространства имён (появляются в `settingsVariant`):
| Префикс | URI | Где |
|---|---|---|
| `style` | `http://v8.1c.ru/8.1/data/ui/style` | В settings — стили оформления |
| `sys` | `http://v8.1c.ru/8.1/data/ui/fonts/system` | В settings — системные шрифты |
| `web` | `http://v8.1c.ru/8.1/data/ui/colors/web` | В settings — веб-цвета |
| `win` | `http://v8.1c.ru/8.1/data/ui/colors/windows` | В settings — цвета Windows |
---
## 2. Общая структура DataCompositionSchema
Элементы верхнего уровня (порядок фиксирован):
```
DataCompositionSchema
├── dataSource* — источники данных (раздел 3)
├── dataSet* — наборы данных (раздел 4)
├── dataSetLink* — связи между наборами (раздел 5)
├── calculatedField* — вычисляемые поля (раздел 6)
├── totalField* — итоговые поля (раздел 7)
├── parameter* — параметры схемы (раздел 8)
├── template* — макеты областей (раздел 9)
├── groupTemplate* — привязки макетов группировок (раздел 10)
├── settingsVariant* — варианты настроек (раздел 11)
```
`*` — 0..N элементов.
Минимальная DCS содержит: 1 dataSource + 1 dataSet + 1 settingsVariant.
---
## 3. Источники данных (dataSource)
```xml
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
```
| Элемент | Обязат. | Описание |
|---|---|---|
| `name` | да | Уникальное имя, на которое ссылаются наборы данных |
| `dataSourceType` | да | Тип: `Local` (текущая информационная база) или `External` (внешний) |
В подавляющем большинстве случаев — один источник `Local`. Имя произвольное: `ИсточникДанных1`, `ИнформационнаяБаза` и т.п.
---
## 4. Наборы данных (dataSet)
Тип набора определяется атрибутом `xsi:type`. Три типа:
### 4.1. DataSetQuery — запрос
Самый распространённый тип. Содержит SQL-подобный запрос на языке 1С.
```xml
<dataSet xsi:type="DataSetQuery">
<name>НаборДанных1</name>
<field xsi:type="DataSetFieldField">...</field> <!-- 0..N полей -->
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ ... ИЗ ...</query>
<autoFillFields>false</autoFillFields> <!-- опционально -->
</dataSet>
```
| Элемент | Обязат. | Описание |
|---|---|---|
| `name` | да | Уникальное имя набора |
| `field` | нет | Описания полей (раздел 4.4) |
| `dataSource` | да | Ссылка на имя dataSource |
| `query` | да | Текст запроса на языке 1С (XML-экранирование: `&amp;` для `&`, `&gt;` для `>`) |
| `autoFillFields` | нет | `false` — отключить автозаполнение полей из запроса (по умолчанию `true`) |
#### Особенности запросов в DCS
- Параметры: `&ИмяПараметра` (в XML: `&amp;ИмяПараметра`)
- Авторазметка полей в фигурных скобках: `{ВЫБРАТЬ ...}`, `{ГДЕ ...}`, `{ЛЕВОЕ СОЕДИНЕНИЕ ...}` — позволяют СКД автоматически модифицировать запрос
- Пакетные запросы: несколько запросов через `; ////////////////`
- Временные таблицы: `ПОМЕСТИТЬ ИмяВТ`, `ИНДЕКСИРОВАТЬ ПО`
### 4.2. DataSetObject — объект
Данные берутся из программно заполненной таблицы значений.
```xml
<dataSet xsi:type="DataSetObject">
<name>НаборДанных1</name>
<field xsi:type="DataSetFieldField">...</field>
<dataSource>ИсточникДанных1</dataSource>
<objectName>ТаблицаПроверки</objectName>
</dataSet>
```
| Элемент | Обязат. | Описание |
|---|---|---|
| `objectName` | да | Имя объекта (таблицы значений), передаваемого программно |
### 4.3. DataSetUnion — объединение
Объединяет поля из нескольких наборов. Сам не содержит запросов — объединяет подчинённые наборы.
```xml
<dataSet xsi:type="DataSetUnion">
<name>РасчетНалога</name>
<field xsi:type="DataSetFieldField">...</field> <!-- агрегированные поля -->
<item xsi:type="DataSetQuery"> <!-- вложенные наборы -->
<name>ДанныеПоСтоимости</name>
...
</item>
<item xsi:type="DataSetQuery">
<name>ДанныеПоКадастру</name>
...
</item>
</dataSet>
```
| Элемент | Обязат. | Описание |
|---|---|---|
| `field` | нет | Поля объединения (описывают результирующие колонки) |
| `item` | да | Вложенные наборы (DataSetQuery или другие) |
### 4.4. Поля набора данных (field)
Каждое поле — элемент `<field xsi:type="DataSetFieldField">`:
```xml
<field xsi:type="DataSetFieldField">
<dataPath>ОстаточнаяСтоимость</dataPath>
<field>ОстаточнаяСтоимость</field>
<title xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Остаточная стоимость</v8:content>
</v8:item>
</title>
<useRestriction>
<condition>true</condition>
</useRestriction>
<role>
<dcscom:dimension>true</dcscom:dimension>
</role>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>11</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
<appearance>
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
<dcscor:parameter>Формат</dcscor:parameter>
<dcscor:value xsi:type="xs:string">ЧДЦ=2</dcscor:value>
</dcscor:item>
</appearance>
<inputParameters>...</inputParameters>
<presentationExpression>...</presentationExpression>
</field>
```
#### Элементы поля
| Элемент | Обязат. | Описание |
|---|---|---|
| `dataPath` | да | Путь к данным (имя поля в результате СКД). Через точку — реквизиты: `Номенклатура.Артикул` |
| `field` | да | Имя поля в запросе (может отличаться от dataPath) |
| `title` | нет | Локализованный заголовок (`v8:LocalStringType`) |
| `useRestriction` | нет | Ограничения использования поля (раздел 4.5) |
| `attributeUseRestriction` | нет | Ограничения использования реквизитов поля (раздел 4.5) |
| `role` | нет | Роль поля в СКД (раздел 4.6) |
| `valueType` | нет | Тип значения поля (раздел 4.7) |
| `appearance` | нет | Оформление — список параметров `dcscor:item` (раздел 4.8) |
| `inputParameters` | нет | Параметры ввода / связи параметров выбора (раздел 4.9) |
| `presentationExpression` | нет | Выражение для формирования представления (на языке 1С) |
### 4.5. Ограничения использования поля (useRestriction / attributeUseRestriction)
```xml
<useRestriction>
<field>true</field> <!-- запрет использования как поле в выборке -->
<condition>true</condition> <!-- запрет в условиях отбора -->
<group>true</group> <!-- запрет в группировках -->
<order>true</order> <!-- запрет в сортировке -->
</useRestriction>
```
Каждый подэлемент — `true`/`false` (по умолчанию `false` = разрешено). Можно указывать подмножество.
`attributeUseRestriction` — аналогичная структура, применяется к реквизитам (дочерним полям) поля.
### 4.6. Роли полей (role)
```xml
<role>
<dcscom:dimension>true</dcscom:dimension> <!-- поле — измерение -->
<dcscom:account>true</dcscom:account> <!-- поле — счёт -->
<dcscom:accountTypeExpression>Счет.Вид</dcscom:accountTypeExpression> <!-- выражение типа счёта -->
</role>
```
| Подэлемент | Описание |
|---|---|
| `dcscom:dimension` | Поле является измерением (`true`/`false`) |
| `dcscom:account` | Поле является счётом |
| `dcscom:accountTypeExpression` | Выражение для определения типа счёта |
| `dcscom:balance` | Поле является остатком |
| `dcscom:balanceGroup` | Группа остатка |
| `dcscom:period` | Поле — период |
### 4.7. Тип значения (valueType)
```xml
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>11</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
```
Типы: `xs:string`, `xs:dateTime`, `xs:decimal`, `xs:boolean`, ссылочные (`d4p1:CatalogRef.Номенклатура`).
Квалификаторы:
- `v8:StringQualifiers``v8:Length`, `v8:AllowedLength` (Fixed/Variable)
- `v8:DateQualifiers``v8:DateFractions` (Date/Time/DateTime)
- `v8:NumberQualifiers``v8:Digits`, `v8:FractionDigits`, `v8:AllowedSign` (Any/Nonnegative)
### 4.8. Оформление полей (appearance)
Список параметров оформления:
```xml
<appearance>
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
<dcscor:parameter>Формат</dcscor:parameter>
<dcscor:value xsi:type="xs:string">ЧДЦ=2</dcscor:value>
</dcscor:item>
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
<dcscor:parameter>ГоризонтальноеПоложение</dcscor:parameter>
<dcscor:value xsi:type="v8ui:HorizontalAlign">Center</dcscor:value>
</dcscor:item>
</appearance>
```
Типичные параметры оформления:
| Параметр | Тип значения | Пример |
|---|---|---|
| `Формат` | `xs:string` | `ЧДЦ=2`, `ЧГ=0`, `ЧН=0`, `ДФ=dd.MM.yyyy`, `Л=ru; ДФ=ММММ` |
| `ГоризонтальноеПоложение` | `v8ui:HorizontalAlign` | `Left`, `Center`, `Right` |
### 4.9. Параметры ввода (inputParameters)
Связи параметров выбора для интерактивных полей:
```xml
<inputParameters>
<dcscor:item>
<dcscor:parameter>СвязиПараметровВыбора</dcscor:parameter>
<dcscor:value xsi:type="dcscor:ChoiceParameterLinks">
<dcscor:item>
<dcscor:choiceParameter>Отбор.Владелец</dcscor:choiceParameter>
<dcscor:value>Организация</dcscor:value>
<dcscor:mode xmlns:d8p1="http://v8.1c.ru/8.1/data/enterprise"
xsi:type="d8p1:LinkedValueChangeMode">Clear</dcscor:mode>
</dcscor:item>
</dcscor:value>
</dcscor:item>
</inputParameters>
```
Используется для каскадных зависимостей в пользовательских настройках (например, подразделение зависит от организации).
---
## 5. Связи между наборами данных (dataSetLink)
Позволяют передавать параметры из одного набора в другой:
```xml
<dataSetLink>
<sourceDataSet>Периоды</sourceDataSet>
<destinationDataSet>ДанныеТ13</destinationDataSet>
<sourceExpression>НачалоМесяца</sourceExpression>
<destinationExpression>Месяц</destinationExpression>
<parameter>НачалоМесяца</parameter>
<parameterListAllowed>false</parameterListAllowed>
</dataSetLink>
```
| Элемент | Обязат. | Описание |
|---|---|---|
| `sourceDataSet` | да | Имя набора-источника |
| `destinationDataSet` | да | Имя целевого набора |
| `sourceExpression` | да | Выражение из источника (поле или формула) |
| `destinationExpression` | да | Выражение для сопоставления в целевом наборе |
| `parameter` | нет | Имя параметра для передачи значения |
| `parameterListAllowed` | нет | Допустим ли список значений (`true`/`false`) |
---
## 6. Вычисляемые поля (calculatedField)
Поля, вычисляемые выражением на языке 1С (не из запроса):
```xml
<calculatedField>
<dataPath>УИД</dataPath>
<expression>БухгалтерскиеОтчеты.ПолучитьУИДСсылкиСтрокой(Номенклатура)</expression>
<title xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Уникальный идентификатор</v8:content>
</v8:item>
</title>
<useRestriction>
<condition>true</condition>
<group>true</group>
<order>true</order>
</useRestriction>
</calculatedField>
```
| Элемент | Обязат. | Описание |
|---|---|---|
| `dataPath` | да | Путь к полю в результате |
| `expression` | да | Выражение на языке 1С (может вызывать методы общих модулей) |
| `title` | нет | Локализованный заголовок |
| `useRestriction` | нет | Ограничения использования (аналогично полям) |
| `valueType` | нет | Тип значения |
| `appearance` | нет | Оформление |
---
## 7. Итоговые поля (totalField)
Агрегатные функции для подведения итогов:
```xml
<totalField>
<dataPath>Количество</dataPath>
<expression>Сумма(Количество)</expression>
</totalField>
<totalField>
<dataPath>Цена</dataPath>
<expression>Максимум(Цена)</expression>
</totalField>
```
| Элемент | Обязат. | Описание |
|---|---|---|
| `dataPath` | да | Путь к полю |
| `expression` | да | Агрегатная функция: `Сумма(...)`, `Количество(...)`, `Максимум(...)`, `Минимум(...)`, `Среднее(...)` |
| `group` | нет | Для какой группировки считать итоги |
---
## 8. Параметры схемы (parameter)
Параметры, доступные для задания пользователем или программно:
```xml
<parameter>
<name>Период</name>
<title xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Период</v8:content>
</v8:item>
</title>
<valueType>
<v8:Type>v8:StandardPeriod</v8:Type>
</valueType>
<value xsi:type="v8:StandardPeriod">
<v8:variant xsi:type="v8:StandardPeriodVariant">LastMonth</v8:variant>
</value>
<useRestriction>false</useRestriction>
<expression>&amp;Период.ДатаНачала</expression>
<availableAsField>false</availableAsField>
<use>Always</use>
</parameter>
```
| Элемент | Обязат. | Описание |
|---|---|---|
| `name` | да | Имя параметра (используется в запросах как `&ИмяПараметра`) |
| `title` | нет | Локализованный заголовок |
| `valueType` | нет | Тип значения (раздел 4.7) |
| `value` | нет | Значение по умолчанию |
| `useRestriction` | нет | `true` — параметр скрыт от пользователя, `false` — доступен |
| `expression` | нет | Выражение для автоматического вычисления (например, `&Период.ДатаНачала`) |
| `availableAsField` | нет | `false` — параметр недоступен как поле в отчёте |
| `use` | нет | Режим: `Always` (всегда), `Auto` (автоматически) |
### Типы значений параметров
| Тип | XML-тип | Пример value |
|---|---|---|
| Дата | `xs:dateTime` | `0001-01-01T00:00:00` |
| Строка | `xs:string` | `Т13` |
| Стандартный период | `v8:StandardPeriod` | `<v8:variant>LastMonth</v8:variant>` |
| Ссылка | `d4p1:CatalogRef.ИмяСправочника` | `xsi:nil="true"` |
| null | — | `xsi:nil="true"` |
Стандартные варианты периодов (`v8:StandardPeriodVariant`): `Custom`, `Today`, `ThisWeek`, `ThisMonth`, `ThisQuarter`, `ThisYear`, `LastMonth`, `LastQuarter`, `LastYear` и др.
---
## 9. Макеты областей (template)
Пользовательские шаблоны вывода (макеты ячеек):
```xml
<template>
<name>Макет1</name>
<template xmlns:dcsat="http://v8.1c.ru/8.1/data-composition-system/area-template"
xsi:type="dcsat:AreaTemplate">
<dcsat:item xsi:type="dcsat:TableRow">
<dcsat:tableCell>
<dcsat:item xsi:type="dcsat:Field">
<dcsat:value xsi:type="dcscor:Parameter">ТипЦены</dcsat:value>
</dcsat:item>
</dcsat:tableCell>
</dcsat:item>
</template>
<parameter xmlns:dcsat="http://v8.1c.ru/8.1/data-composition-system/area-template"
xsi:type="dcsat:ExpressionAreaTemplateParameter">
<dcsat:name>ТипЦены</dcsat:name>
<dcsat:expression>Представление(ТипЦен)</dcsat:expression>
</parameter>
</template>
```
Пространство имён `dcsat`: `http://v8.1c.ru/8.1/data-composition-system/area-template`.
| Элемент | Описание |
|---|---|
| `name` | Имя макета (ссылаются groupTemplate) |
| `template` (вложенный) | Описание строк/ячеек (`dcsat:AreaTemplate`) |
| `parameter` | Параметры макета (`dcsat:ExpressionAreaTemplateParameter`) — выражения для подстановки |
---
## 10. Привязки макетов группировок (groupTemplate)
Связывают группировку с пользовательским макетом:
```xml
<groupTemplate>
<groupField>ТипЦен</groupField>
<templateType>Header</templateType>
<template>Макет1</template>
</groupTemplate>
```
| Элемент | Описание |
|---|---|
| `groupField` | Имя поля группировки |
| `templateType` | Тип: `Header` (заголовок), `Footer` (подвал), `Overall` (общий) |
| `template` | Ссылка на имя template из раздела 9 |
---
## 11. Варианты настроек (settingsVariant)
Каждый вариант — именованная конфигурация отчёта. Отчёт может иметь несколько вариантов.
```xml
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной вариант отчёта</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="..." xmlns:sys="..." xmlns:web="..." xmlns:win="...">
<!-- содержимое настроек -->
</dcsset:settings>
</settingsVariant>
```
### 11.1. Структура settings
```
dcsset:settings
├── dcsset:selection — выбранные поля (раздел 11.2)
├── dcsset:filter — отборы (раздел 11.3)
├── dcsset:order — сортировка (раздел 11.4)
├── dcsset:conditionalAppearance — условное оформление (раздел 11.5)
├── dcsset:outputParameters — параметры вывода (раздел 11.6)
├── dcsset:dataParameters — значения параметров данных (раздел 11.7)
├── dcsset:item* — элементы структуры (раздел 11.8)
```
### 11.2. Выборка полей (selection)
```xml
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemField">
<dcsset:field>ТипОбъекта</dcsset:field>
<dcsset:lwsTitle> <!-- опциональный заголовок -->
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Наименование</v8:content>
</v8:item>
</dcsset:lwsTitle>
</dcsset:item>
<dcsset:item xsi:type="dcsset:SelectedItemAuto"/> <!-- авто-выбор -->
</dcsset:selection>
```
Типы элементов выборки:
- `dcsset:SelectedItemField` — конкретное поле (элемент `dcsset:field`)
- `dcsset:SelectedItemAuto` — автоматический подбор полей
### 11.3. Отборы (filter)
```xml
<dcsset:filter>
<dcsset:item xsi:type="dcsset:FilterItemComparison">
<dcsset:use>false</dcsset:use> <!-- включён/выключен -->
<dcsset:left xsi:type="dcscor:Field">Организация</dcsset:left>
<dcsset:comparisonType>Equal</dcsset:comparisonType>
<dcsset:right xsi:type="xs:boolean">false</dcsset:right>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Описание фильтра</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:viewMode>Normal</dcsset:viewMode>
<dcsset:userSettingID>GUID</dcsset:userSettingID>
</dcsset:item>
</dcsset:filter>
```
Типы элементов фильтра:
- `dcsset:FilterItemComparison` — сравнение поля с значением
- `dcsset:FilterItemGroup` — группа условий (И/ИЛИ)
Типы сравнения (`comparisonType`):
| Значение | Описание |
|---|---|
| `Equal` | Равно |
| `NotEqual` | Не равно |
| `Greater` | Больше |
| `GreaterOrEqual` | Больше или равно |
| `Less` | Меньше |
| `LessOrEqual` | Меньше или равно |
| `InList` | В списке |
| `NotInList` | Не в списке |
| `InHierarchy` | В иерархии |
| `InListByHierarchy` | В списке по иерархии |
| `Contains` | Содержит |
| `NotContains` | Не содержит |
| `BeginsWith` | Начинается с |
| `NotBeginsWith` | Не начинается с |
| `Filled` | Заполнено |
| `NotFilled` | Не заполнено |
Значение правой части (`right`) — может содержать списки:
```xml
<dcsset:right xsi:type="v8:ValueListType">
<v8:valueType/>
<v8:lastId xsi:type="xs:decimal">-1</v8:lastId>
</dcsset:right>
```
### 11.4. Сортировка (order)
```xml
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemField">
<dcsset:field>РазмерДанных</dcsset:field>
<dcsset:orderType>Desc</dcsset:orderType>
</dcsset:item>
<dcsset:item xsi:type="dcsset:OrderItemAuto"/>
</dcsset:order>
```
Типы элементов сортировки:
- `dcsset:OrderItemField` — по полю (`dcsset:field` + `dcsset:orderType`: `Asc`/`Desc`)
- `dcsset:OrderItemAuto` — автоматическая сортировка
### 11.5. Условное оформление (conditionalAppearance)
```xml
<dcsset:conditionalAppearance>
<dcsset:item>
<dcsset:selection>
<dcsset:item>
<dcsset:field>ИмяПоля</dcsset:field>
</dcsset:item>
</dcsset:selection>
<dcsset:filter>
<dcsset:item xsi:type="dcsset:FilterItemComparison">
<dcsset:left xsi:type="dcscor:Field">ИмяПоля</dcsset:left>
<dcsset:comparisonType>Equal</dcsset:comparisonType>
<dcsset:right xsi:type="xs:decimal">0</dcsset:right>
</dcsset:item>
</dcsset:filter>
<dcsset:appearance>
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
<dcscor:parameter>Текст</dcscor:parameter>
<dcscor:value xsi:type="xs:string"/>
</dcscor:item>
</dcsset:appearance>
</dcsset:item>
</dcsset:conditionalAppearance>
```
### 11.6. Параметры вывода (outputParameters)
```xml
<dcsset:outputParameters>
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
<dcscor:use>false</dcscor:use> <!-- опционально -->
<dcscor:parameter>Заголовок</dcscor:parameter>
<dcscor:value xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Текст заголовка</v8:content>
</v8:item>
</dcscor:value>
</dcscor:item>
</dcsset:outputParameters>
```
Типичные параметры вывода:
| Параметр | Тип значения | Описание |
|---|---|---|
| `Заголовок` | `v8:LocalStringType` | Заголовок отчёта |
| `МакетОформления` | `xs:string` | Имя макета оформления: `ОформлениеОтчетовЧерноБелый`, `Зеленый` и др. |
| `РасположениеПолейГруппировки` | `dcsset:DataCompositionGroupFieldsPlacement` | `Together`, `Separately`, `SeparatelyAndInGroups` |
| `РасположениеРеквизитов` | `dcsset:DataCompositionAttributesPlacement` | `Together`, `Separately`, `SeparatelyAndInGroups` |
| `ГоризонтальноеРасположениеОбщихИтогов` | `dcscor:DataCompositionTotalPlacement` | `None`, `Begin`, `End`, `Auto` |
| `ВертикальноеРасположениеОбщихИтогов` | `dcscor:DataCompositionTotalPlacement` | `None`, `Begin`, `End`, `Auto` |
| `ВыводитьЗаголовок` | `dcsset:DataCompositionTextOutputType` | `Auto`, `DontOutput`, `Output` |
| `ВыводитьПараметрыДанных` | `dcsset:DataCompositionTextOutputType` | То же |
| `ВыводитьОтбор` | `dcsset:DataCompositionTextOutputType` | То же |
### 11.7. Параметры данных (dataParameters)
Значения параметров схемы в конкретном варианте:
```xml
<dcsset:dataParameters>
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
<dcscor:use>false</dcscor:use>
<dcscor:parameter>Период</dcscor:parameter>
<dcscor:value xsi:type="v8:StandardPeriod">
<v8:variant xsi:type="v8:StandardPeriodVariant">LastMonth</v8:variant>
</dcscor:value>
<dcsset:viewMode>Normal</dcsset:viewMode>
<dcsset:userSettingID>GUID</dcsset:userSettingID>
</dcscor:item>
</dcsset:dataParameters>
```
| Элемент | Описание |
|---|---|
| `dcscor:use` | `true`/`false` — использовать значение или нет |
| `dcscor:parameter` | Имя параметра из раздела 8 |
| `dcscor:value` | Значение параметра |
| `dcsset:viewMode` | Режим отображения: `Normal`, `QuickAccess`, `Inaccessible` |
| `dcsset:userSettingID` | GUID пользовательской настройки |
### 11.8. Элементы структуры (structure items)
Структура отчёта — иерархия группировок, таблиц, диаграмм.
#### StructureItemGroup — группировка
```xml
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:name>Группировка</dcsset:name>
<dcsset:groupItems>
<dcsset:item xsi:type="dcsset:GroupItemField">
<dcsset:field>Организация</dcsset:field>
<dcsset:groupType>Items</dcsset:groupType>
<dcsset:periodAdditionType>None</dcsset:periodAdditionType>
<dcsset:periodAdditionBegin xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionBegin>
<dcsset:periodAdditionEnd xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionEnd>
</dcsset:item>
</dcsset:groupItems>
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto"/>
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto"/>
</dcsset:selection>
<dcsset:outputParameters>...</dcsset:outputParameters>
<dcsset:item xsi:type="dcsset:StructureItemGroup"> <!-- вложенная группировка -->
...
</dcsset:item>
</dcsset:item>
```
Типы группировки (`groupType`): `Items`, `Hierarchy`, `HierarchyOnly`.
Типы дополнения периодом (`periodAdditionType`): `None`, `Year`, `HalfYear`, `Quarter`, `Month`, `TenDays`, `Week`, `Day`.
Пустая группировка (без `groupItems`) = детальные записи.
#### StructureItemTable — таблица (кросс-таблица)
```xml
<dcsset:item xsi:type="dcsset:StructureItemTable">
<dcsset:name>Таблица</dcsset:name>
<dcsset:column> <!-- группировки колонок -->
<dcsset:groupItems>...</dcsset:groupItems>
<dcsset:order>...</dcsset:order>
<dcsset:selection>...</dcsset:selection>
</dcsset:column>
<dcsset:row> <!-- группировки строк -->
<dcsset:name>Группировка</dcsset:name>
<dcsset:groupItems>...</dcsset:groupItems>
<dcsset:order>...</dcsset:order>
<dcsset:selection>...</dcsset:selection>
</dcsset:row>
</dcsset:item>
```
#### StructureItemChart — диаграмма
```xml
<dcsset:item xsi:type="dcsset:StructureItemChart">
<dcsset:point> <!-- точки (ось X) -->
<dcsset:groupItems>...</dcsset:groupItems>
<dcsset:order>...</dcsset:order>
<dcsset:selection>...</dcsset:selection>
</dcsset:point>
<dcsset:series> <!-- серии (необязательно) -->
<dcsset:groupItems>...</dcsset:groupItems>
...
</dcsset:series>
<dcsset:selection> <!-- значения для отображения -->
<dcsset:item xsi:type="dcsset:SelectedItemField">
<dcsset:field>РазмерДанных</dcsset:field>
</dcsset:item>
</dcsset:selection>
<dcsset:outputParameters>...</dcsset:outputParameters>
</dcsset:item>
```
---
## 12. Типы данных — сводка
### v8:LocalStringType — локализованная строка
```xml
<title xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Текст на русском</v8:content>
</v8:item>
</title>
```
Также можно задать как простую строку: `xsi:type="xs:string"`.
### dcscor:SettingsParameterValue — параметр настройки
```xml
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
<dcscor:use>true</dcscor:use> <!-- опционально -->
<dcscor:parameter>ИмяПараметра</dcscor:parameter>
<dcscor:value xsi:type="ТипЗначения">Значение</dcscor:value>
</dcscor:item>
```
### dcscor:Field — ссылка на поле
```xml
<dcsset:left xsi:type="dcscor:Field">ИмяПоля</dcsset:left>
```
---
## 13. Полный минимальный пример
Простая DCS: один запрос, два поля, один итог, один вариант:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<DataCompositionSchema xmlns="http://v8.1c.ru/8.1/data-composition-system/schema"
xmlns:dcscom="http://v8.1c.ru/8.1/data-composition-system/common"
xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core"
xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings"
xmlns:v8="http://v8.1c.ru/8.1/data/core"
xmlns:v8ui="http://v8.1c.ru/8.1/data/ui"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>НаборДанных1</name>
<field xsi:type="DataSetFieldField">
<dataPath>Наименование</dataPath>
<field>Наименование</field>
<title xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Наименование</v8:content>
</v8:item>
</title>
</field>
<field xsi:type="DataSetFieldField">
<dataPath>Количество</dataPath>
<field>Количество</field>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ
Номенклатура.Наименование КАК Наименование,
КОЛИЧЕСТВО(1) КАК Количество
ИЗ
Справочник.Номенклатура КАК Номенклатура
СГРУППИРОВАТЬ ПО
Номенклатура.Наименование</query>
</dataSet>
<totalField>
<dataPath>Количество</dataPath>
<expression>Сумма(Количество)</expression>
</totalField>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style"
xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system"
xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web"
xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemField">
<dcsset:field>Наименование</dcsset:field>
</dcsset:item>
<dcsset:item xsi:type="dcsset:SelectedItemField">
<dcsset:field>Количество</dcsset:field>
</dcsset:item>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto"/>
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto"/>
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
```
+112
View File
@@ -0,0 +1,112 @@
# Спецификация Role JSON DSL
Формат JSON для описания ролей 1С, используемый навыком `/role-compile`.
## Обзор
Role JSON DSL — компактный JSON-формат, транслируемый скриптом в XML-файлы роли 1С:Предприятия (метаданные + Rights.xml). Поддерживает пресеты прав, русские синонимы типов и прав, шаблоны ограничений (RLS).
## Корневой объект
| Поле | Тип | Обяз. | По умолчанию | Описание |
|------|-----|:-----:|:------------:|----------|
| `name` | string | да | — | Программное имя роли |
| `synonym` | string | нет | = name | Отображаемое имя |
| `comment` | string | нет | `""` | Комментарий |
| `setForNewObjects` | bool | нет | `false` | Устанавливать для новых объектов |
| `setForAttributesByDefault` | bool | нет | `true` | Устанавливать для реквизитов по умолчанию |
| `independentRightsOfChildObjects` | bool | нет | `false` | Независимые права подчинённых объектов |
| `objects` | array | нет | `[]` | Массив объектов метаданных с правами |
| `templates` | array | нет | `[]` | Шаблоны ограничений (RLS) |
## Элементы `objects`
Массив принимает два формата, которые можно смешивать.
### Строковый shorthand
```
"Тип.Имя: @пресет"
"Тип.Имя: Право1, Право2"
```
Тип — английский (Catalog) или русский (Справочник). Права — английские (Read) или русские (Чтение).
### Объектная форма
| Поле | Тип | Обяз. | Описание |
|------|-----|:-----:|----------|
| `name` | string | да | Полное имя объекта: `Тип.Имя` |
| `preset` | string | нет | Пресет: `"view"`, `"edit"` (без `@`) |
| `rights` | object\|array | нет | Переопределения: `{"Right": bool}` или `["Right1", "Right2"]` |
| `rls` | object | нет | RLS: `{"ИмяПрава": "текст условия или #шаблон"}` |
При наличии `preset` + `rights` — сначала применяется пресет, затем `rights` переопределяют отдельные права.
## Пресеты
Три встроенных пресета определяют набор прав в зависимости от типа объекта:
| Пресет | Назначение |
|--------|------------|
| `view` | Просмотр: Read, View (+InputByString для справочников/документов; Use+View для обработок/отчётов) |
| `edit` | Полное редактирование: CRUD + Interactive* + Posting (документы) |
Подробные таблицы прав для каждого типа объекта — в `.claude/skills/role-compile/dsl-reference.md`.
## Шаблоны ограничений (RLS)
Элементы массива `templates`:
| Поле | Тип | Описание |
|------|-----|----------|
| `name` | string | Имя шаблона с параметрами: `"ДляОбъекта(Модификатор)"` |
| `condition` | string | Текст условия. `&` экранируется в `&amp;` автоматически |
Ссылка на шаблон в `rls`: `"#ИмяШаблона(\"параметры\")"` — начинается с `#`.
## Русские синонимы
DSL принимает русские имена типов и прав, транслируя их в английские. Полные таблицы соответствий — в `.claude/skills/role-compile/dsl-reference.md`.
Примеры: `Справочник` → Catalog, `Документ` → Document, `Чтение` → Read, `Просмотр` → View.
## Пример
```json
{
"name": "МенеджерПродаж",
"synonym": "Менеджер продаж",
"objects": [
"Document.РеализацияТоваровУслуг: @edit",
"Catalog.Контрагенты: @view",
"Catalog.Номенклатура: @view",
{
"name": "Document.ЗаказКлиента",
"preset": "view",
"rls": { "Read": "#ДляОбъекта(\"\")" }
}
],
"templates": [
{
"name": "ДляОбъекта(Модификатор)",
"condition": "ГДЕ Организация = &ТекущаяОрганизация"
}
]
}
```
## Генерируемые файлы
```
Roles/
ИмяРоли.xml # Метаданные (UUID, синоним, флаги)
ИмяРоли/
└── Ext/
└── Rights.xml # Права доступа (объекты, права, RLS)
```
## См. также
- [Роли (Rights.xml)](1c-role-spec.md) — XML-формат прав роли, типы объектов, RLS
- [Гайд по ролям](role-guide.md) — сценарии использования, рабочий цикл
+103 -17
View File
@@ -1,13 +1,72 @@
# Роли (Role)
Навыки группы `/role-*` позволяют анализировать и создавать роли 1С — XML-файлы прав доступа (Rights.xml) и метаданных.
Навыки группы `/role-*` позволяют анализировать, создавать и проверять роли 1С — XML-файлы прав доступа (Rights.xml) и метаданных.
## Навыки
| Навык | Параметры | Описание |
|-------|-----------|----------|
| `/role-info` | `<RightsPath>` | Компактная сводка прав: объекты по типам, только разрешённые, RLS, шаблоны |
| `/role-compile` | `<RoleName> <RolesDir>` | Создание роли: метаданные + Rights.xml по описанию прав |
| `/role-compile` | `<JsonPath> <RolesDir>` | Генерация роли из JSON DSL: метаданные + Rights.xml, UUID автоматически |
| `/role-validate` | `<RightsPath> [MetadataPath]` | Валидация структурной корректности: XML, namespace, права, RLS, шаблоны |
## Рабочий цикл
```
Описание прав (текст) → JSON DSL → /role-compile → XML-исходники → /role-validate
→ /role-info
```
1. Claude формирует JSON-определение роли (с пресетами или явными правами)
2. `/role-compile` генерирует `Roles/ИмяРоли.xml` + `Roles/ИмяРоли/Ext/Rights.xml`
3. `/role-validate` проверяет корректность сгенерированного XML
4. `/role-info` выводит компактную сводку для визуальной проверки
## JSON DSL — компактный формат
Роли описываются в JSON с двумя уровнями детализации:
### Строковый shorthand (простые роли)
```json
{
"name": "ЧтениеНоменклатуры",
"synonym": "Чтение номенклатуры",
"objects": [
"Catalog.Номенклатура: @view",
"Catalog.Контрагенты: @view",
"DataProcessor.Загрузка: @view"
]
}
```
Формат строки: `Тип.Имя: @пресет` или `Тип.Имя: Право1, Право2`.
### Объектная форма (RLS, переопределения)
```json
{
"name": "Document.Реализация",
"preset": "view",
"rights": { "Delete": false },
"rls": { "Read": "#ДляОбъекта(\"\")" }
}
```
Форматы можно смешивать в одном массиве `objects`.
### Пресеты
| Пресет | Действие |
|--------|----------|
| `@view` | Просмотр: Read, View (+InputByString для справочников/документов; Use+View для обработок/отчётов) |
| `@edit` | Полное редактирование: CRUD + Interactive* + Posting (для документов) |
`@` обязателен в строковом shorthand. В объектной форме — ключ `preset` без `@`.
### Русские синонимы
Скрипт принимает русские имена типов и прав: `Справочник` → Catalog, `Чтение` → Read, `Проведение` → Posting и т.д. Полный список — в [спецификации Role DSL](role-dsl-spec.md).
## Сценарии использования
@@ -22,15 +81,6 @@ Claude вызовет `/role-info`, получит компактную свод
- где есть ограничения RLS
- какие шаблоны ограничений используются
### Создание роли для регламентного задания
```
> Проанализируй модуль регламентного задания ОбновлениеКурсовВалют
> и создай роль с минимальными правами для его выполнения
```
Claude проанализирует код, определит используемые объекты метаданных, и вызовет `/role-compile` для создания роли с нужными правами (Read, Update, Posting и т.д.).
### Создание роли по описанию
```
@@ -41,11 +91,46 @@ Claude проанализирует код, определит использу
> - Регистр ЦеныНоменклатуры: чтение
```
Рабочий цикл:
1. Claude генерирует `Roles/МенеджерПродаж.xml` (метаданные с UUID)
2. Claude генерирует `Roles/МенеджерПродаж/Ext/Rights.xml` (права)
3. Регистрирует роль в `Configuration.xml` (`<ChildObjects>`)
4. Проверяет результат через `/role-info`
Claude сформирует JSON с пресетами:
```json
{
"name": "МенеджерПродаж",
"synonym": "Менеджер продаж",
"objects": [
"Document.РеализацияТоваровУслуг: @edit",
"Catalog.Контрагенты: @view",
"Catalog.Номенклатура: @view",
"InformationRegister.ЦеныНоменклатуры: @view"
]
}
```
И вызовет `/role-compile``/role-validate``/role-info`.
### Создание роли для регламентного задания
```
> Проанализируй модуль регламентного задания ОбновлениеКурсовВалют
> и создай роль с минимальными правами для его выполнения
```
Claude проанализирует код, определит используемые объекты, создаст JSON с точечными правами (без пресетов — только нужные права), и скомпилирует роль.
### Создание роли с RLS
```
> Создай роль для чтения документов с ограничением по организации
```
Claude использует объектную форму JSON с шаблонами ограничений.
### Проверка существующей роли
```
> Проверь корректность роли Roles/МояРоль/Ext/Rights.xml
```
Claude вызовет `/role-validate` и покажет результат: ошибки (невалидный XML, отсутствующие элементы) и предупреждения (неизвестные типы объектов, подозрительные имена прав с подсказками).
## Структура файлов роли
@@ -66,4 +151,5 @@ Roles/
## Спецификация
Полная спецификация формата: [1c-role-spec.md](1c-role-spec.md) — типы объектов, права, RLS, шаблоны ограничений, версии формата.
- [1c-role-spec.md](1c-role-spec.md) — XML-формат прав роли, типы объектов, RLS, шаблоны ограничений
- [role-dsl-spec.md](role-dsl-spec.md) — JSON DSL для описания ролей (формат входных данных `/role-compile`)