diff --git a/.claude/skills/role-edit/scripts/role-edit.ps1 b/.claude/skills/role-edit/scripts/role-edit.ps1
index c29e86061..a1becdfbe 100644
--- a/.claude/skills/role-edit/scripts/role-edit.ps1
+++ b/.claude/skills/role-edit/scripts/role-edit.ps1
@@ -1,4 +1,4 @@
-# role-edit v1.5 — Edit existing 1C role rights in place
+# role-edit v1.6 — Edit existing 1C role rights in place
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
[CmdletBinding(PositionalBinding=$false)]
param(
@@ -1713,12 +1713,15 @@ function New-ObjectNode([string]$objName) {
return $nodes[0]
}
-# Узел без единого разрешающего права платформа не производит: остаточные запреты уходят с ним.
-function Remove-ObjectIfNoTrueRights($objNode) {
- if ((Get-TrueRightNames $objNode).Count -gt 0) { return $false }
+# Пустых узлов платформа не производит. Узел с одними запретами — производит (так закрывают
+# реквизит), поэтому смотрим на наличие прав вообще, а не только разрешающих.
+function Remove-ObjectIfEmpty($objNode) {
+ # @() на месте использования: return из функции разворачивает массив из одного элемента,
+ # и .Count у него $null — узел с единственным правом считался бы пустым.
+ if (@(Get-RightNodes $objNode).Count -gt 0) { return $false }
$name = Get-ObjectNodeName $objNode
Remove-NodeWithWhitespace $objNode
- Add-Note " ${name}: разрешающих прав не осталось — узел объекта удалён"
+ Add-Note " ${name}: прав не осталось — узел объекта удалён"
return $true
}
@@ -1852,7 +1855,7 @@ function Apply-SetRights($spec) {
$script:rightsDirty = $true
Add-Note " $($spec.Name): набор прав заменён"
if ($droppedRls -gt 0) { Add-Note "[WARN] $($spec.Name): снято ограничений RLS: $droppedRls" }
- Remove-ObjectIfNoTrueRights $objNode | Out-Null
+ Remove-ObjectIfEmpty $objNode | Out-Null
}
function Do-RemoveRights([string]$batchVal) {
@@ -1901,7 +1904,7 @@ function Apply-RemoveRights($spec) {
$note = " $($spec.Name): снято — $($removed -join ', ')"
if ($cascade.Count -gt 0) { $note += " (каскадом: $($cascade -join ', '))" }
Add-Note $note
- Remove-ObjectIfNoTrueRights $objNode | Out-Null
+ Remove-ObjectIfEmpty $objNode | Out-Null
}
function Do-DenyRights([string]$batchVal) {
@@ -1914,9 +1917,11 @@ function Do-DenyRights([string]$batchVal) {
function Apply-DenyRights($spec) {
$objNode = Find-ObjectNode $spec.Name
+ $created = $false
if (-not $objNode) {
$objNode = New-ObjectNode $spec.Name
Insert-ObjectNode $objNode $spec.Name
+ $created = $true
}
$toDeny = @()
foreach ($rightName in $spec.Rights) {
@@ -1943,6 +1948,7 @@ function Apply-DenyRights($spec) {
$script:rightsDirty = $true
}
if ($denied.Count -eq 0) {
+ if ($created) { Remove-NodeWithWhitespace $objNode }
$reason = if ($script:droppedByDefault -match [regex]::Escape($spec.Name)) { "запрет совпадает с умолчанием роли и платформой не хранится" } else { "права уже запрещены" }
Add-Note " $($spec.Name): $reason, изменений нет"
return
@@ -2031,7 +2037,7 @@ function Apply-SetRls($spec) {
# Строка без полей («прочие поля») идёт первой, строки с полями — после неё.
$refNode = $null
if ($spec.Fields.Count -eq 0) {
- foreach ($node in $existing) { if ((Get-RestrictionFields $node).Count -gt 0) { $refNode = $node; break } }
+ foreach ($node in $existing) { if (@(Get-RestrictionFields $node).Count -gt 0) { $refNode = $node; break } }
}
Insert-BeforeElement $rightNode $new $refNode $indent
$script:addCount++
@@ -2062,7 +2068,7 @@ function Apply-RemoveRls($spec) {
$removed = 0
foreach ($node in @($rightNode.SelectNodes("rt:restrictionByCondition", $script:ns))) {
# Адрес без скобок снимает все ограничения права, со скобками — строку с этим набором полей.
- if ($spec.Fields.Count -gt 0 -and -not (Test-SameFieldSet (Get-RestrictionFields $node) $spec.Fields)) { continue }
+ if (@($spec.Fields).Count -gt 0 -and -not (Test-SameFieldSet (Get-RestrictionFields $node) $spec.Fields)) { continue }
Remove-NodeWithWhitespace $node
$removed++
}
diff --git a/.claude/skills/role-edit/scripts/role-edit.py b/.claude/skills/role-edit/scripts/role-edit.py
index 9c4749680..3af839f3c 100644
--- a/.claude/skills/role-edit/scripts/role-edit.py
+++ b/.claude/skills/role-edit/scripts/role-edit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# role-edit v1.5 — Edit existing 1C role rights in place
+# role-edit v1.6 — Edit existing 1C role rights in place
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import json
@@ -1740,13 +1740,14 @@ class Editor:
ref = templates[0]
self.insert_child(self.root, new_el, ref, indent)
- # Узел без единого разрешающего права платформа не производит.
- def remove_object_if_no_true_rights(self, obj_node):
- if self.true_right_names(obj_node):
+ # Пустых узлов платформа не производит. Узел с одними запретами — производит (так закрывают
+ # реквизит), поэтому смотрим на наличие прав вообще, а не только разрешающих.
+ def remove_object_if_empty(self, obj_node):
+ if self.right_nodes(obj_node):
return
name = node_text(obj_node, "name")
self.remove_child(obj_node)
- self.note(f" {name}: разрешающих прав не осталось — узел объекта удалён")
+ self.note(f" {name}: прав не осталось — узел объекта удалён")
# --- Зависимости ---
@@ -1857,7 +1858,7 @@ class Editor:
self.note(f" {spec['Name']}: набор прав заменён")
if dropped_rls:
self.note(f"[WARN] {spec['Name']}: снято ограничений RLS: {dropped_rls}")
- self.remove_object_if_no_true_rights(obj_node)
+ self.remove_object_if_empty(obj_node)
def apply_remove_rights(self, spec):
obj_node = self.find_object(spec["Name"])
@@ -1894,13 +1895,15 @@ class Editor:
if cascade:
note += f" (каскадом: {', '.join(cascade)})"
self.note(note)
- self.remove_object_if_no_true_rights(obj_node)
+ self.remove_object_if_empty(obj_node)
def apply_deny_rights(self, spec):
obj_node = self.find_object(spec["Name"])
+ created = False
if obj_node is None:
obj_node = self.make_object(spec["Name"], self.child_indent(self.root))
self.insert_object_node(obj_node, spec["Name"])
+ created = True
to_deny = []
for right_name in spec["Rights"]:
to_deny.append(right_name)
@@ -1925,6 +1928,8 @@ class Editor:
denied.append(right_name)
self.rights_dirty = True
if not denied:
+ if created:
+ self.remove_child(obj_node)
reason = ("запрет совпадает с умолчанием роли и платформой не хранится"
if any(d.startswith(spec['Name'] + '.') for d in self.dropped_by_default)
else "права уже запрещены")
diff --git a/tests/skills/cases/role-edit/deny-dropped-no-empty-node.json b/tests/skills/cases/role-edit/deny-dropped-no-empty-node.json
new file mode 100644
index 000000000..0fb0576b0
--- /dev/null
+++ b/tests/skills/cases/role-edit/deny-dropped-no-empty-node.json
@@ -0,0 +1,23 @@
+{
+ "name": "Отброшенный запрет не оставляет пустой узел, когда файл меняет соседняя операция",
+ "setup": "fixture:role-base",
+ "params": {
+ "rolePath": "Roles/Менеджер"
+ },
+ "input": [
+ {
+ "operation": "deny-rights",
+ "value": "InformationRegister.Цены: Read"
+ },
+ {
+ "operation": "add-rights",
+ "value": "Catalog.Товары: Insert"
+ }
+ ],
+ "expect": {
+ "fileNotContains": {
+ "file": "Roles/Менеджер/Ext/Rights.xml",
+ "text": "InformationRegister.Цены"
+ }
+ }
+}
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Catalogs/Товары.xml b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Catalogs/Товары.xml
new file mode 100644
index 000000000..292de84c4
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Catalogs/Товары.xml
@@ -0,0 +1,137 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+ UUID-006
+ UUID-007
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+
+ Товары
+
+
+ ru
+ Товары
+
+
+
+ false
+ HierarchyFoldersAndItems
+ false
+ 2
+ true
+ true
+
+ ToItems
+ 9
+ 25
+ String
+ Variable
+ WholeCatalog
+ false
+ true
+ AsDescription
+
+ Auto
+ InDialog
+ false
+ BothWays
+
+ Catalog.Товары.StandardAttribute.Description
+ Catalog.Товары.StandardAttribute.Code
+
+ Begin
+ DontUse
+ Directly
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+ Managed
+ Use
+
+
+
+
+
+ Use
+ Auto
+ DontUse
+ false
+ false
+
+
+
+
+ Цена
+
+
+ ru
+ Цена
+
+
+
+
+ xs:decimal
+
+ 15
+ 2
+ Any
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ 0
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+ DontIndex
+ Use
+ Use
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Catalogs/Товары/Ext/ObjectModule.bsl b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Catalogs/Товары/Ext/ObjectModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Configuration.xml b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Configuration.xml
new file mode 100644
index 000000000..880e20b87
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Configuration.xml
@@ -0,0 +1,256 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+ UUID-006
+ UUID-007
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+ UUID-012
+ UUID-013
+
+
+ UUID-014
+ UUID-015
+
+
+
+ TestConfig
+
+
+ ru
+ TestConfig
+
+
+
+
+ Version8_3_24
+ ManagedApplication
+
+ PlatformApplication
+
+ Russian
+
+
+
+
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Biometrics
+ true
+
+
+ Location
+ false
+
+
+ BackgroundLocation
+ false
+
+
+ BluetoothPrinters
+ false
+
+
+ WiFiPrinters
+ false
+
+
+ Contacts
+ false
+
+
+ Calendars
+ false
+
+
+ PushNotifications
+ false
+
+
+ LocalNotifications
+ false
+
+
+ InAppPurchases
+ false
+
+
+ PersonalComputerFileExchange
+ false
+
+
+ Ads
+ false
+
+
+ NumberDialing
+ false
+
+
+ CallProcessing
+ false
+
+
+ CallLog
+ false
+
+
+ AutoSendSMS
+ false
+
+
+ ReceiveSMS
+ false
+
+
+ SMSLog
+ false
+
+
+ Camera
+ false
+
+
+ Microphone
+ false
+
+
+ MusicLibrary
+ false
+
+
+ PictureAndVideoLibraries
+ false
+
+
+ AudioPlaybackAndVibration
+ false
+
+
+ BackgroundAudioPlaybackAndVibration
+ false
+
+
+ InstallPackages
+ false
+
+
+ OSBackup
+ true
+
+
+ ApplicationUsageStatistics
+ false
+
+
+ BarcodeScanning
+ false
+
+
+ BackgroundAudioRecording
+ false
+
+
+ AllFilesAccess
+ false
+
+
+ Videoconferences
+ false
+
+
+ NFC
+ false
+
+
+ DocumentScanning
+ false
+
+
+ SpeechToText
+ false
+
+
+ Geofences
+ false
+
+
+ IncomingShareRequests
+ false
+
+
+ AllIncomingShareRequestsTypesProcessing
+ false
+
+
+
+
+
+ Normal
+
+
+ Language.Русский
+
+
+
+
+
+ Managed
+ NotAutoFree
+ DontUse
+ DontUse
+ TaxiEnableVersion8_2
+ DontUse
+ Version8_3_24
+
+
+
+ Русский
+ Менеджер
+ Товары
+ Заказ
+ Загрузка
+ Цены
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/DataProcessors/Загрузка.xml b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/DataProcessors/Загрузка.xml
new file mode 100644
index 000000000..fa5caaf26
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/DataProcessors/Загрузка.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+
+ Загрузка
+
+
+ ru
+ Загрузка
+
+
+
+ true
+
+
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/DataProcessors/Загрузка/Ext/ManagerModule.bsl b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/DataProcessors/Загрузка/Ext/ManagerModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/DataProcessors/Загрузка/Ext/ObjectModule.bsl b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/DataProcessors/Загрузка/Ext/ObjectModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Documents/Заказ.xml b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Documents/Заказ.xml
new file mode 100644
index 000000000..32fa05878
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Documents/Заказ.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+ UUID-006
+ UUID-007
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+
+ Заказ
+
+
+ ru
+ Заказ
+
+
+
+ true
+
+ String
+ 11
+ Variable
+ Year
+ true
+ true
+
+
+
+ Document.Заказ.StandardAttribute.Number
+
+ Use
+ Begin
+ DontUse
+ Directly
+
+
+
+
+
+
+ Allow
+ Deny
+ AutoDelete
+ WriteSelected
+ AutoFill
+
+ true
+ true
+ false
+
+ Managed
+ Use
+
+
+
+
+
+ Auto
+ DontUse
+ false
+ false
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Documents/Заказ/Ext/ObjectModule.bsl b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Documents/Заказ/Ext/ObjectModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Ext/ClientApplicationInterface.xml b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Ext/ClientApplicationInterface.xml
new file mode 100644
index 000000000..3c1161b2d
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Ext/ClientApplicationInterface.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ UUID-002
+
+
+
+
+ UUID-004
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/InformationRegisters/Цены.xml b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/InformationRegisters/Цены.xml
new file mode 100644
index 000000000..092bf1d11
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/InformationRegisters/Цены.xml
@@ -0,0 +1,261 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+ UUID-006
+ UUID-007
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+ UUID-012
+ UUID-013
+
+
+ UUID-014
+ UUID-015
+
+
+
+ Цены
+
+
+ ru
+ Цены
+
+
+
+ true
+ InDialog
+
+
+
+
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+ Nonperiodical
+ Independent
+ false
+ false
+ Managed
+ Use
+ false
+ false
+
+
+
+
+
+ DontUse
+ false
+ false
+
+
+
+
+ Цена
+
+
+ ru
+ Цена
+
+
+
+
+ xs:decimal
+
+ 15
+ 2
+ Any
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ 0
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+ DontIndex
+ Use
+ Use
+
+
+
+
+ Товар
+
+
+ ru
+ Товар
+
+
+
+
+ cfg:CatalogRef.Товары
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+ false
+ false
+ false
+ DontIndex
+ Use
+ Use
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/InformationRegisters/Цены/Ext/RecordSetModule.bsl b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/InformationRegisters/Цены/Ext/RecordSetModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Languages/Русский.xml b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Languages/Русский.xml
new file mode 100644
index 000000000..37c60d786
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Languages/Русский.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ Русский
+
+
+ ru
+ Русский
+
+
+
+ ru
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Roles/Менеджер.xml b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Roles/Менеджер.xml
new file mode 100644
index 000000000..001d4535b
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Roles/Менеджер.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ Менеджер
+
+
+ ru
+ Менеджер
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Roles/Менеджер/Ext/Rights.xml b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Roles/Менеджер/Ext/Rights.xml
new file mode 100644
index 000000000..a20e853c4
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/deny-dropped-no-empty-node/Roles/Менеджер/Ext/Rights.xml
@@ -0,0 +1,96 @@
+
+
+ false
+ true
+ false
+
+
+
+ ДляОбъекта(Мод)
+ ГДЕ Организация = &ТекОрг
+
+
\ No newline at end of file