From 121c9c8ad31dfab950416f6caf0f565851043291 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 13 Sep 2026 18:02:35 +0300 Subject: [PATCH] =?UTF-8?q?feat(role-compile):=20=D1=83=D1=81=D0=BB=D0=BE?= =?UTF-8?q?=D0=B2=D0=B8=D0=B5=20RLS=20=D0=B8=20=D1=82=D0=B5=D0=BB=D0=BE=20?= =?UTF-8?q?=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=D0=B0=20=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=B2=D0=B7=D1=8F=D1=82=D1=8C=20=D0=B8=D0=B7=20?= =?UTF-8?q?=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Симметрично role-edit: в значении пишется "@путь", текст приходит из файла. Условия типовых занимают десятки строк с кавычками внутри, и в JSON-строке это источник ошибок экранирования — теперь условие живёт отдельным файлом рядом с описанием роли. Работает в rls и в templates[].condition. Отсутствие файла — ошибка до записи, как и прочие ошибки описания прав. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FGkXwoXTuafcu1SXMsauFq --- .claude/skills/role-compile/SKILL.md | 7 + .../role-compile/scripts/role-compile.ps1 | 20 +- .../role-compile/scripts/role-compile.py | 22 +- .../role-compile/rls-condition-from-file.json | 37 +++ .../cases/role-compile/rls-usloviye.txt | 3 + .../Catalogs/Номенклатура.xml | 91 +++++++ .../Номенклатура/Ext/ObjectModule.bsl | 0 .../rls-condition-from-file/Configuration.xml | 254 ++++++++++++++++++ .../DataProcessors/Загрузка.xml | 32 +++ .../Загрузка/Ext/ManagerModule.bsl | 0 .../Загрузка/Ext/ObjectModule.bsl | 0 .../Ext/ClientApplicationInterface.xml | 18 ++ .../Languages/Русский.xml | 16 ++ .../Roles/РольИзФайла.xml | 15 ++ .../Roles/РольИзФайла/Ext/Rights.xml | 32 +++ .../rls-condition-from-file/rls-usloviye.txt | 3 + 16 files changed, 544 insertions(+), 6 deletions(-) create mode 100644 tests/skills/cases/role-compile/rls-condition-from-file.json create mode 100644 tests/skills/cases/role-compile/rls-usloviye.txt create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Catalogs/Номенклатура.xml create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Catalogs/Номенклатура/Ext/ObjectModule.bsl create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Configuration.xml create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/DataProcessors/Загрузка.xml create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/DataProcessors/Загрузка/Ext/ManagerModule.bsl create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/DataProcessors/Загрузка/Ext/ObjectModule.bsl create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Ext/ClientApplicationInterface.xml create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Languages/Русский.xml create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Roles/РольИзФайла.xml create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Roles/РольИзФайла/Ext/Rights.xml create mode 100644 tests/skills/cases/role-compile/snapshots/rls-condition-from-file/rls-usloviye.txt diff --git a/.claude/skills/role-compile/SKILL.md b/.claude/skills/role-compile/SKILL.md index 67ba38743..da0a9459e 100644 --- a/.claude/skills/role-compile/SKILL.md +++ b/.claude/skills/role-compile/SKILL.md @@ -91,6 +91,13 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/role-compile.ps1" - Ссылка в `rls`: `"#ДляОбъекта(\"\")"`. Символ `&` автоматически экранируется в XML. +Длинное условие держи в файле — в значении пишется `@путь` (путь от текущего каталога): + +```json +"objects": [{"name": "Document.Продажа", "preset": "view", "rls": {"Read": "@условие.txt"}}], +"templates": [{"name": "ДляОбъекта(Мод)", "condition": "@шаблон.txt"}] +``` + ## Примеры ### Простая роль diff --git a/.claude/skills/role-compile/scripts/role-compile.ps1 b/.claude/skills/role-compile/scripts/role-compile.ps1 index 6954b57bd..c5d6a7aa6 100644 --- a/.claude/skills/role-compile/scripts/role-compile.ps1 +++ b/.claude/skills/role-compile/scripts/role-compile.ps1 @@ -1,4 +1,4 @@ -# role-compile v1.39 — Compile 1C role from JSON +# role-compile v1.40 — Compile 1C role from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills [CmdletBinding(PositionalBinding=$false)] param( @@ -1072,6 +1072,20 @@ function Validate-RightName { return $true } +# "@путь" в значении условия — текст берётся из файла: условия RLS типовых занимают десятки +# строк с кавычками, и внутри JSON-строки это источник ошибок экранирования. Путь относительный — +# от текущего каталога, как в role-edit. +function Resolve-TextValue([string]$text) { + if (-not $text -or -not $text.StartsWith("@")) { return $text } + $valueFile = $text.Substring(1).Trim() + if (-not [System.IO.Path]::IsPathRooted($valueFile)) { $valueFile = Join-Path (Get-Location).Path $valueFile } + if (-not (Test-Path -LiteralPath $valueFile -PathType Leaf)) { + Add-ValidationError "Файл значения не найден: $valueFile" + return $text + } + return [System.IO.File]::ReadAllText($valueFile).Trim() +} + # --- 5a. Service roots: expand to leaves --- # Метаданные сервиса читаются один раз на имя: раскрытие и проверка заимствования @@ -1290,7 +1304,7 @@ function Parse-ObjectEntry { foreach ($p in $entry.rls.PSObject.Properties) { $rlsRight = Translate-RightName $p.Name if ($rightsMap.Contains($rlsRight)) { - $rightsMap[$rlsRight].Condition = "$($p.Value)" + $rightsMap[$rlsRight].Condition = Resolve-TextValue "$($p.Value)" } else { Write-Warning "${objName}: RLS for '$rlsRight' but this right is not in the rights list" } @@ -1478,7 +1492,7 @@ if ($def.templates) { foreach ($tpl in $def.templates) { X "`t" X "`t`t$(Esc-XmlText "$($tpl.name)")" - X "`t`t$(Esc-XmlText "$($tpl.condition)")" + X "`t`t$(Esc-XmlText (Resolve-TextValue "$($tpl.condition)"))" X "`t" $templateCount++ } diff --git a/.claude/skills/role-compile/scripts/role-compile.py b/.claude/skills/role-compile/scripts/role-compile.py index ad9917ea5..a67f3ab99 100644 --- a/.claude/skills/role-compile/scripts/role-compile.py +++ b/.claude/skills/role-compile/scripts/role-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# role-compile v1.39 — Compile 1C role from JSON +# role-compile v1.40 — Compile 1C role from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json @@ -1165,6 +1165,22 @@ def validate_right_name(object_name, right_name): return True +# "@путь" в значении условия — текст берётся из файла: условия RLS типовых занимают десятки +# строк с кавычками, и внутри JSON-строки это источник ошибок экранирования. Путь относительный — +# от текущего каталога, как в role-edit. +def resolve_text_value(text): + if not text or not text.startswith("@"): + return text + value_file = text[1:].strip() + if not os.path.isabs(value_file): + value_file = os.path.join(os.getcwd(), value_file) + if not os.path.isfile(value_file): + add_validation_error(f"Файл значения не найден: {value_file}") + return text + with open(value_file, encoding="utf-8-sig") as f: + return f.read().strip() + + MD_NS = 'http://v8.1c.ru/8.3/MDClasses' # Метаданные сервиса читаются один раз на имя: раскрытие и проверка заимствования @@ -1364,7 +1380,7 @@ def parse_object_entry(entry): for p_name, p_value in entry['rls'].items(): rls_right = translate_right_name(p_name) if rls_right in rights_map: - rights_map[rls_right]['Condition'] = str(p_value) + rights_map[rls_right]['Condition'] = resolve_text_value(str(p_value)) else: print(f"WARNING: {obj_name}: RLS for '{rls_right}' but this right is not in the rights list", file=sys.stderr) @@ -1724,7 +1740,7 @@ def main(): for tpl in defn['templates']: lines.append('\t') lines.append(f'\t\t{esc_xml_text(str(tpl["name"]))}') - lines.append(f'\t\t{esc_xml_text(str(tpl["condition"]))}') + lines.append(f'\t\t{esc_xml_text(resolve_text_value(str(tpl["condition"])))}') lines.append('\t') template_count += 1 diff --git a/tests/skills/cases/role-compile/rls-condition-from-file.json b/tests/skills/cases/role-compile/rls-condition-from-file.json new file mode 100644 index 000000000..a6760a2ed --- /dev/null +++ b/tests/skills/cases/role-compile/rls-condition-from-file.json @@ -0,0 +1,37 @@ +{ + "name": "Условие RLS и тело шаблона берутся из файла", + "setup": "fixture:view-preset-fx", + "cwd": "workDir", + "caseFiles": [ + "rls-usloviye.txt" + ], + "input": { + "name": "РольИзФайла", + "synonym": "Роль из файла", + "objects": [ + { + "name": "Catalog.Номенклатура", + "preset": "view", + "rls": { + "Read": "@rls-usloviye.txt" + } + } + ], + "templates": [ + { + "name": "ПоОрганизации(Мод)", + "condition": "@rls-usloviye.txt" + } + ] + }, + "validatePath": "Roles/РольИзФайла", + "expect": { + "fileContains": { + "file": "Roles/РольИзФайла/Ext/Rights.xml", + "text": [ + "ОграничениеПоОрганизации", + "restrictionTemplate" + ] + } + } +} diff --git a/tests/skills/cases/role-compile/rls-usloviye.txt b/tests/skills/cases/role-compile/rls-usloviye.txt new file mode 100644 index 000000000..eaef48d49 --- /dev/null +++ b/tests/skills/cases/role-compile/rls-usloviye.txt @@ -0,0 +1,3 @@ +#Если &ОграничениеПоОрганизации #Тогда + ГДЕ Организация = &ТекущаяОрганизация +#КонецЕсли \ No newline at end of file diff --git a/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Catalogs/Номенклатура.xml b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Catalogs/Номенклатура.xml new file mode 100644 index 000000000..0daed60e9 --- /dev/null +++ b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Catalogs/Номенклатура.xml @@ -0,0 +1,91 @@ + + + + + + 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 + + + + \ No newline at end of file diff --git a/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Catalogs/Номенклатура/Ext/ObjectModule.bsl b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Catalogs/Номенклатура/Ext/ObjectModule.bsl new file mode 100644 index 000000000..e69de29bb diff --git a/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Configuration.xml b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Configuration.xml new file mode 100644 index 000000000..cde3bcf92 --- /dev/null +++ b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Configuration.xml @@ -0,0 +1,254 @@ + + + + + + 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-compile/snapshots/rls-condition-from-file/DataProcessors/Загрузка.xml b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/DataProcessors/Загрузка.xml new file mode 100644 index 000000000..fa5caaf26 --- /dev/null +++ b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/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-compile/snapshots/rls-condition-from-file/DataProcessors/Загрузка/Ext/ManagerModule.bsl b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/DataProcessors/Загрузка/Ext/ManagerModule.bsl new file mode 100644 index 000000000..e69de29bb diff --git a/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/DataProcessors/Загрузка/Ext/ObjectModule.bsl b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/DataProcessors/Загрузка/Ext/ObjectModule.bsl new file mode 100644 index 000000000..e69de29bb diff --git a/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Ext/ClientApplicationInterface.xml b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Ext/ClientApplicationInterface.xml new file mode 100644 index 000000000..3c1161b2d --- /dev/null +++ b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Languages/Русский.xml b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Languages/Русский.xml new file mode 100644 index 000000000..37c60d786 --- /dev/null +++ b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Roles/РольИзФайла.xml b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Roles/РольИзФайла.xml new file mode 100644 index 000000000..5fe249406 --- /dev/null +++ b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Roles/РольИзФайла.xml @@ -0,0 +1,15 @@ + + + + + РольИзФайла + + + ru + Роль из файла + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Roles/РольИзФайла/Ext/Rights.xml b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Roles/РольИзФайла/Ext/Rights.xml new file mode 100644 index 000000000..3bd7e4c29 --- /dev/null +++ b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/Roles/РольИзФайла/Ext/Rights.xml @@ -0,0 +1,32 @@ + + + false + true + false + + Catalog.Номенклатура + + Read + true + + #Если &ОграничениеПоОрганизации #Тогда + ГДЕ Организация = &ТекущаяОрганизация +#КонецЕсли + + + + View + true + + + InputByString + true + + + + ПоОрганизации(Мод) + #Если &ОграничениеПоОрганизации #Тогда + ГДЕ Организация = &ТекущаяОрганизация +#КонецЕсли + + \ No newline at end of file diff --git a/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/rls-usloviye.txt b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/rls-usloviye.txt new file mode 100644 index 000000000..eaef48d49 --- /dev/null +++ b/tests/skills/cases/role-compile/snapshots/rls-condition-from-file/rls-usloviye.txt @@ -0,0 +1,3 @@ +#Если &ОграничениеПоОрганизации #Тогда + ГДЕ Организация = &ТекущаяОрганизация +#КонецЕсли \ No newline at end of file