diff --git a/.claude/skills/cfe-patch-method/SKILL.md b/.claude/skills/cfe-patch-method/SKILL.md index cbc0ea35..0e9ae6cc 100644 --- a/.claude/skills/cfe-patch-method/SKILL.md +++ b/.claude/skills/cfe-patch-method/SKILL.md @@ -1,7 +1,7 @@ --- name: cfe-patch-method -description: Генерация перехватчика метода в расширении 1С (CFE). Используй когда нужно перехватить метод заимствованного объекта — вставить код до, после или вместо оригинального -argument-hint: -ExtensionPath -ModulePath "Catalog.X.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before +description: Генерация перехватчика метода в расширении 1С (CFE). Используй когда нужно перехватить метод заимствованного объекта — вставить код до, после, вместо оригинального или изменить его тело (ИзменениеИКонтроль), а также актуализировать перехватчик после изменения оригинала +argument-hint: -ExtensionPath -ConfigPath -ModulePath "Catalog.X.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before allowed-tools: - Bash - Read @@ -10,22 +10,31 @@ allowed-tools: # /cfe-patch-method — Генерация перехватчика метода -Генерирует `.bsl` файл с декоратором перехвата для заимствованного объекта расширения. Создаёт файл или дописывает в существующий. +Читает оригинал метода из конфигурации-источника и генерирует `.bsl`-перехватчик заимствованного объекта: с правильной директивой контекста, полной сигнатурой, обрамляющими инструкциями препроцессора и областями. Для `ИзменениеИКонтроль` копирует всё тело оригинала. Создаёт файл модуля, дописывает в существующий или актуализирует уже заимствованный метод. ## Предусловие -Объект должен быть заимствован в расширение (`/cfe-borrow`). Скрипт читает `NamePrefix` из `Configuration.xml` расширения для формирования имени процедуры. +Объект должен быть заимствован в расширение (`/cfe-borrow`). Нужен доступ к исходникам базовой конфигурации (`-ConfigPath`) — оттуда читается оригинал метода. `NamePrefix` берётся из `Configuration.xml` расширения. + +### Авто-определение ConfigPath + +Если пользователь не указал `-ConfigPath` — попробуй определить автоматически: +1. Прочитай `.v8-project.json` из корня проекта +2. Разреши целевую базу (по имени, ветке или `default` — алгоритм из `/db-list`) +3. Если у базы есть поле `configSrc` — используй как `-ConfigPath` +4. Если `configSrc` нет — спроси у пользователя ## Параметры | Параметр | Описание | По умолчанию | |----------|----------|--------------| | `ExtensionPath` | Путь к расширению (обязат.) | — | -| `ModulePath` | Путь к модулю (обязат.) | — | +| `ConfigPath` | Путь к конфигурации-источнику | обязат., кроме случая, когда `ModulePath` — путь к файлу | +| `ModulePath` | Логическое имя (`Тип.Имя.Модуль`) **или** путь к файлу модуля `.bsl` (обязат.) | — | | `MethodName` | Имя перехватываемого метода (обязат.) | — | -| `InterceptorType` | `Before` / `After` / `ModificationAndControl` (обязат.) | — | -| `Context` | Директива контекста | `НаСервере` | -| `IsFunction` | Метод — функция (добавит `Возврат`) | false | +| `InterceptorType` | `Before` / `After` / `Instead` / `ModificationAndControl` (обязат.) | — | + +Директива контекста, `Процедура`/`Функция`, сигнатура и обрамление определяются из оригинала автоматически — вручную задавать не нужно. ## Формат ModulePath @@ -40,39 +49,66 @@ allowed-tools: Аналогично для Report, DataProcessor, InformationRegister и других типов. +Вместо логического имени в `ModulePath` можно передать **путь к файлу** модуля-источника `.bsl` — тогда `-ConfigPath` указывать не нужно (оригинал читается прямо из этого файла). Путь модуля расширения определяется от типовой папки в пути автоматически. + ## Типы перехвата | InterceptorType | Декоратор | Назначение | |-----------------|-----------|------------| | `Before` | `&Перед` | Код до вызова оригинального метода | | `After` | `&После` | Код после вызова оригинального метода | -| `ModificationAndControl` | `&ИзменениеИКонтроль` | Копия тела метода с маркерами `#Вставка`/`#Удаление` | +| `Instead` | `&Вместо` | Замена метода; в теле — скаффолд `ПродолжитьВызов(...)` | +| `ModificationAndControl` | `&ИзменениеИКонтроль` | Копия тела оригинала для правки маркерами `#Вставка`/`#Удаление` | + +`Before` и `After` применимы только к **процедурам**. Для **функций** доступны `Instead` и `ModificationAndControl`. + +## Что переносится из оригинала + +- **Директива контекста** (`&НаСервере`/`&НаКлиенте`/…) — как у оригинала. +- **Сигнатура** — полный список параметров (для `Instead` имена параметров подставляются в `ПродолжитьВызов`). +- **Обрамляющие `#Если … Тогда`** — наследуются от оригинала. +- **Области `#Область`** — метод помещается в ту же область (переиспользуется, если уже есть в модуле). +- Для `ModificationAndControl` — **всё тело** оригинала дословно; далее расставь маркеры `#Вставка`/`#КонецВставки` и `#Удаление`/`#КонецУдаления`. + +Имя процедуры перехватчика — `<Метод>`; при коллизии в модуле добавляется суффикс типа (`_Перед`/`_После`/`_Вместо`). + +## Актуализация (повторный вызов `ModificationAndControl`) + +Если для метода уже есть перехватчик `&ИзменениеИКонтроль`, повторный вызов **актуализирует** его по текущему оригиналу: + +- `[АКТУАЛЕН]` — оригинал не менялся, изменений нет; +- `[АКТУАЛИЗИРОВАН]` — тело обновлено по новому оригиналу, правки (`#Вставка`/`#Удаление`) перенесены автоматически; +- `[АКТУАЛИЗИРОВАН-ЧАСТИЧНО]` — часть правок не удалось разместить (изменился якорь). Они помечены `// [РЕСИНК-КОНФЛИКТ]` и не потеряны; для анализа выгружаются файлы-версии (`v1.bsl`, `v2.bsl`, `current.bsl`, `diff.txt`) — путь печатается в выводе. Проверь конфликтные блоки и размести вручную. + +Повторный вызов `Before`/`After`/`Instead` для уже перехваченного метода не создаёт дубль (`[ПРОПУЩЕН]`). ## Команда ```powershell -powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-patch-method.ps1" -ExtensionPath src -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before +powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-patch-method.ps1" -ExtensionPath src\cfe\ИмяРасширения -ConfigPath src\cf -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before ``` ## Примеры ```powershell -# Перехват &Перед на сервере -... -ExtensionPath src -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before +# Код перед записью +... -ExtensionPath src\cfe\ИмяРасширения -ConfigPath src\cf -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before -# Перехват &После на клиенте -... -ExtensionPath src -ModulePath "Document.Заказ.Form.ФормаДокумента" -MethodName "ПослеЗаписиНаСервере" -InterceptorType After -Context "НаКлиенте" +# Перехват После на форме +... -ExtensionPath src\cfe\ИмяРасширения -ConfigPath src\cf -ModulePath "Document.Заказ.Form.ФормаДокумента" -MethodName "ПослеЗаписиНаСервере" -InterceptorType After -# ИзменениеИКонтроль для функции -... -ExtensionPath src -ModulePath "CommonModule.ОбщийМодуль" -MethodName "ПолучитьДанные" -InterceptorType ModificationAndControl -IsFunction +# Замена функции (ПродолжитьВызов) +... -ExtensionPath src\cfe\ИмяРасширения -ConfigPath src\cf -ModulePath "CommonModule.ОбщийМодуль" -MethodName "ПолучитьДанные" -InterceptorType Instead + +# ИзменениеИКонтроль — копия тела для правки маркерами +... -ExtensionPath src\cfe\ИмяРасширения -ConfigPath src\cf -ModulePath "Document.РеализацияТоваров.ObjectModule" -MethodName "ОбработкаПроведения" -InterceptorType ModificationAndControl + +# ModulePath как путь к файлу модуля-источника (без -ConfigPath) +... -ExtensionPath src\cfe\ИмяРасширения -ModulePath "src\cf\CommonModules\ОбщийМодуль\Ext\Module.bsl" -MethodName "ПолучитьДанные" -InterceptorType Instead ``` -## Генерируемый код (Before) +## Верификация -```bsl -&НаСервере -&Перед("ПриЗаписи") -Процедура Расш1_ПриЗаписи() - // TODO: код перед вызовом оригинального метода -КонецПроцедуры +``` +/cfe-validate ``` diff --git a/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.ps1 b/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.ps1 index 96324c3b..4c083c93 100644 --- a/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.ps1 +++ b/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.ps1 @@ -1,9 +1,11 @@ -# cfe-patch-method v1.1 — Generate method interceptor for 1C extension (CFE) +# cfe-patch-method v2.0 — Source-aware method interceptor for 1C extension (CFE) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] [string]$ExtensionPath, + [string]$ConfigPath, + [Parameter(Mandatory)] [string]$ModulePath, @@ -11,53 +13,18 @@ param( [string]$MethodName, [Parameter(Mandatory)] - [ValidateSet("Before","After","ModificationAndControl")] - [string]$InterceptorType, - - [string]$Context = "НаСервере", - - [switch]$IsFunction + [ValidateSet("Before","After","Instead","ModificationAndControl")] + [string]$InterceptorType ) $ErrorActionPreference = "Stop" [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 -# --- Resolve extension path --- -if (-not [System.IO.Path]::IsPathRooted($ExtensionPath)) { - $ExtensionPath = Join-Path (Get-Location).Path $ExtensionPath -} -if (Test-Path $ExtensionPath -PathType Leaf) { - $ExtensionPath = Split-Path $ExtensionPath -Parent -} -$cfgFile = Join-Path $ExtensionPath "Configuration.xml" -if (-not (Test-Path $cfgFile)) { - Write-Error "Configuration.xml not found in: $ExtensionPath" - exit 1 -} +# ============================================================================ +# Helpers +# ============================================================================ -# --- Read NamePrefix from Configuration.xml --- -$cfgDoc = New-Object System.Xml.XmlDocument -$cfgDoc.PreserveWhitespace = $false -$cfgDoc.Load($cfgFile) - -$cfgNs = New-Object System.Xml.XmlNamespaceManager($cfgDoc.NameTable) -$cfgNs.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses") - -$propsNode = $cfgDoc.SelectSingleNode("//md:Configuration/md:Properties", $cfgNs) -$prefixNode = if ($propsNode) { $propsNode.SelectSingleNode("md:NamePrefix", $cfgNs) } else { $null } -$namePrefix = if ($prefixNode -and $prefixNode.InnerText) { $prefixNode.InnerText } else { "Расш_" } - -# --- Map ModulePath to file path --- -# ModulePath formats: -# Catalog.X.ObjectModule -> Catalogs/X/Ext/ObjectModule.bsl -# Catalog.X.ManagerModule -> Catalogs/X/Ext/ManagerModule.bsl -# Catalog.X.Form.Y -> Catalogs/X/Forms/Y/Ext/Form/Module.bsl -# CommonModule.X -> CommonModules/X/Ext/Module.bsl -# Document.X.ObjectModule -> Documents/X/Ext/ObjectModule.bsl -# Document.X.ManagerModule -> Documents/X/Ext/ManagerModule.bsl -# Document.X.Form.Y -> Documents/X/Forms/Y/Ext/Form/Module.bsl - -$typeDirMap = @{ +$script:typeDirMap = @{ "Catalog"="Catalogs"; "Document"="Documents"; "Enum"="Enums" "CommonModule"="CommonModules"; "Report"="Reports"; "DataProcessor"="DataProcessors" "ExchangePlan"="ExchangePlans"; "ChartOfAccounts"="ChartsOfAccounts" @@ -76,134 +43,715 @@ $typeDirMap = @{ "AccountingRegisters"="AccountingRegisters"; "CalculationRegisters"="CalculationRegisters" } -$parts = $ModulePath.Split(".") -if ($parts.Count -lt 2) { - Write-Error "Invalid ModulePath format: $ModulePath. Expected: Type.Name.Module or CommonModule.Name" - exit 1 +# InterceptorType -> Russian decorator keyword +$script:decoratorMap = @{ + "Before"="Перед"; "After"="После"; "Instead"="Вместо" + "ModificationAndControl"="ИзменениеИКонтроль" } -$objType = $parts[0] -$objName = $parts[1] - -if (-not $typeDirMap.ContainsKey($objType)) { - Write-Error "Unknown object type: $objType" - exit 1 -} -$dirName = $typeDirMap[$objType] - -$bslFile = $null -if ($objType -eq "CommonModule") { - # CommonModule.X -> CommonModules/X/Ext/Module.bsl - $bslFile = Join-Path (Join-Path (Join-Path (Join-Path $ExtensionPath $dirName) $objName) "Ext") "Module.bsl" -} elseif ($parts.Count -ge 4 -and $parts[2] -eq "Form") { - # Type.X.Form.Y -> Types/X/Forms/Y/Ext/Form/Module.bsl - $formName = $parts[3] - $bslFile = Join-Path (Join-Path (Join-Path (Join-Path (Join-Path (Join-Path (Join-Path $ExtensionPath $dirName) $objName) "Forms") $formName) "Ext") "Form") "Module.bsl" -} elseif ($parts.Count -ge 3) { - # Type.X.ObjectModule -> Types/X/Ext/ObjectModule.bsl - $moduleName = $parts[2] - $moduleFileName = switch ($moduleName) { - "ObjectModule" { "ObjectModule.bsl" } - "ManagerModule" { "ManagerModule.bsl" } - "RecordSetModule" { "RecordSetModule.bsl" } - "CommandModule" { "CommandModule.bsl" } - default { "$moduleName.bsl" } +# Compute relative .bsl path segments from ModulePath (used for both ext and src) +function Get-ModuleRelPath { + param([string]$modulePath) + $parts = $modulePath.Split(".") + if ($parts.Count -lt 2) { + throw "Invalid ModulePath format: $modulePath. Expected: Type.Name.Module, Type.Name.Form.FormName or CommonModule.Name" + } + $objType = $parts[0] + $objName = $parts[1] + if (-not $script:typeDirMap.ContainsKey($objType)) { + throw "Unknown object type: $objType" + } + $dirName = $script:typeDirMap[$objType] + + if ($objType -eq "CommonModule") { + return @($dirName, $objName, "Ext", "Module.bsl") + } elseif ($parts.Count -ge 4 -and $parts[2] -eq "Form") { + $formName = $parts[3] + return @($dirName, $objName, "Forms", $formName, "Ext", "Form", "Module.bsl") + } elseif ($parts.Count -ge 3) { + $moduleName = $parts[2] + $moduleFileName = switch ($moduleName) { + "ObjectModule" { "ObjectModule.bsl" } + "ManagerModule" { "ManagerModule.bsl" } + "RecordSetModule" { "RecordSetModule.bsl" } + "CommandModule" { "CommandModule.bsl" } + "ValueManagerModule" { "ValueManagerModule.bsl" } + default { "$moduleName.bsl" } + } + return @($dirName, $objName, "Ext", $moduleFileName) + } + throw "Invalid ModulePath format: $modulePath" +} + +# Extract relative module path segments from a filesystem path to a .bsl, +# anchored on a known type directory (Catalogs/Documents/CommonModules/...). +function Get-RelPartsFromFilePath { + param([string]$path) + $segs = ($path -replace '\\', '/').Split('/') | Where-Object { $_ -ne '' } + $anchors = $script:typeDirMap.Values | Select-Object -Unique + for ($i = 0; $i -lt $segs.Count; $i++) { + # case-sensitive: 1C type dirs are PascalCase (Catalogs/Documents/Tasks/…) + if ($anchors -ccontains $segs[$i]) { return $segs[$i..($segs.Count - 1)] } + } + return $null +} + +# Split text at top-level separator (respecting parens and string literals) +function Split-TopLevel { + param([string]$text, [char]$sep = ',') + $result = @() + $depth = 0; $inStr = $false + $sb = New-Object System.Text.StringBuilder + for ($i = 0; $i -lt $text.Length; $i++) { + $ch = $text[$i] + if ($inStr) { + [void]$sb.Append($ch) + if ($ch -eq '"') { $inStr = $false } + continue + } + if ($ch -eq '"') { $inStr = $true; [void]$sb.Append($ch); continue } + if ($ch -eq '(') { $depth++; [void]$sb.Append($ch); continue } + if ($ch -eq ')') { $depth--; [void]$sb.Append($ch); continue } + if ($ch -eq $sep -and $depth -eq 0) { $result += $sb.ToString(); $sb = New-Object System.Text.StringBuilder; continue } + [void]$sb.Append($ch) + } + $result += $sb.ToString() + return $result +} + +# Is a trimmed line a context-directive annotation? +function Test-ContextDirective { + param([string]$trimmed) + return $trimmed -match '^&(НаКлиенте|НаСервере|НаСервереБезКонтекста|НаКлиентеНаСервереБезКонтекста|НаКлиентеНаСервере)\s*$' +} + +# Read a method signature starting at declaration line; returns @{ ParamsText; EndLineIdx } +function Read-Signature { + param($lines, [int]$startIdx) + $depth = 0; $inStr = $false; $openFound = $false + $paramsSb = New-Object System.Text.StringBuilder + for ($li = $startIdx; $li -lt $lines.Count; $li++) { + $line = $lines[$li] + for ($ci = 0; $ci -lt $line.Length; $ci++) { + $ch = $line[$ci] + if ($inStr) { + if ($openFound) { [void]$paramsSb.Append($ch) } + if ($ch -eq '"') { $inStr = $false } + continue + } + if ($ch -eq '"') { $inStr = $true; if ($openFound) { [void]$paramsSb.Append($ch) }; continue } + if ($ch -eq '(') { + $depth++ + if (-not $openFound) { $openFound = $true } else { [void]$paramsSb.Append($ch) } + continue + } + if ($ch -eq ')') { + $depth-- + if ($depth -eq 0) { return @{ ParamsText = $paramsSb.ToString(); EndLineIdx = $li } } + [void]$paramsSb.Append($ch) + continue + } + if ($openFound) { [void]$paramsSb.Append($ch) } + } + if ($openFound -and $depth -ge 1) { [void]$paramsSb.Append("`r`n") } + } + return $null +} + +# Compute effective condition of the current branch of an #Если frame +function Get-EffectiveCondition { + param($frame) + $conds = $frame.Conds + $n = $conds.Count + if ($frame.InElse) { + $parts = @() + foreach ($c in $conds) { $parts += "НЕ ($c)" } + return ($parts -join " И ") + } + if ($n -eq 1) { return $conds[0] } + $parts = @() + for ($j = 0; $j -lt ($n - 1); $j++) { $parts += "НЕ ($($conds[$j]))" } + $parts += $conds[$n - 1] + return ($parts -join " И ") +} + +# Extract the enclosing wrapper chain (regions + preprocessor) at a target line. +# Returns array outer->inner of @{ Kind='region'|'if'; Name=..; Cond=.. } +function Get-EnclosingChain { + param($lines, [int]$targetIdx) + $stack = New-Object System.Collections.ArrayList + for ($i = 0; $i -lt $targetIdx; $i++) { + $t = $lines[$i].Trim() + if ($t -match '^#Область\s+(\S+)') { + [void]$stack.Add(@{ Kind = 'region'; Name = $Matches[1] }) + } elseif ($t -match '^#КонецОбласти') { + for ($k = $stack.Count - 1; $k -ge 0; $k--) { if ($stack[$k].Kind -eq 'region') { $stack.RemoveAt($k); break } } + } elseif ($t -match '^#Если\s+(.+?)\s+Тогда') { + [void]$stack.Add(@{ Kind = 'if'; Conds = @($Matches[1].Trim()); InElse = $false }) + } elseif ($t -match '^#ИначеЕсли\s+(.+?)\s+Тогда') { + for ($k = $stack.Count - 1; $k -ge 0; $k--) { if ($stack[$k].Kind -eq 'if') { $stack[$k].Conds += $Matches[1].Trim(); $stack[$k].InElse = $false; break } } + } elseif ($t -match '^#Иначе(\s|$)') { + for ($k = $stack.Count - 1; $k -ge 0; $k--) { if ($stack[$k].Kind -eq 'if') { $stack[$k].InElse = $true; break } } + } elseif ($t -match '^#КонецЕсли') { + for ($k = $stack.Count - 1; $k -ge 0; $k--) { if ($stack[$k].Kind -eq 'if') { $stack.RemoveAt($k); break } } + } + } + $chain = @() + foreach ($f in $stack) { + if ($f.Kind -eq 'region') { $chain += @{ Kind = 'region'; Name = $f.Name } } + else { $chain += @{ Kind = 'if'; Cond = (Get-EffectiveCondition $f) } } + } + return ,$chain +} + +# Extract a method from source .bsl lines. Returns $null if not found. +function Extract-Method { + param($lines, [string]$methodName) + $declRe = '^\s*(Асинх\s+)?(Процедура|Функция)\s+(' + [regex]::Escape($methodName) + ')\s*\(' + for ($i = 0; $i -lt $lines.Count; $i++) { + if ($lines[$i] -imatch $declRe) { + $isAsync = [bool]$Matches[1] + $keyword = $Matches[2] + $canonical = $Matches[3] + $isFunction = ($keyword -ieq "Функция") + + $sig = Read-Signature $lines $i + if (-not $sig) { throw "Не удалось разобрать сигнатуру метода '$methodName'" } + $sigEnd = $sig.EndLineIdx + $paramsText = $sig.ParamsText + + # Parameter names (for ПродолжитьВызов) + $paramNames = @() + if ($paramsText.Trim().Length -gt 0) { + foreach ($seg in (Split-TopLevel $paramsText)) { + $s = $seg.Trim() -replace '^Знач\s+', '' + if ($s -match '^([\w]+)') { $paramNames += $Matches[1] } + } + } + + # Body: from sigEnd+1 to matching Конец* + $endRe = if ($isFunction) { '^\s*КонецФункции\b' } else { '^\s*КонецПроцедуры\b' } + $bodyStart = $sigEnd + 1 + $bodyEnd = -1 + for ($j = $bodyStart; $j -lt $lines.Count; $j++) { + if ($lines[$j] -imatch $endRe) { $bodyEnd = $j; break } + } + if ($bodyEnd -lt 0) { throw "Не найден конец метода '$methodName'" } + $bodyLines = @() + for ($j = $bodyStart; $j -lt $bodyEnd; $j++) { $bodyLines += $lines[$j] } + + # Context directive (immediately above declaration) + $context = "" + if ($i -ge 1) { + $prev = $lines[$i - 1].Trim() + if (Test-ContextDirective $prev) { $context = $prev } + } + + # Enclosing chain (regions + preprocessor) + $chain = Get-EnclosingChain $lines $i + + return @{ + Canonical = $canonical + IsFunction = $isFunction + IsAsync = $isAsync + ParamsText = $paramsText + ParamNames = $paramNames + Context = $context + BodyLines = $bodyLines + Chain = $chain + DeclIdx = $i + SigEndIdx = $sigEnd + BodyEndIdx = $bodyEnd + } + } + } + return $null +} + +# Parse interceptors present in a module (type + method) +function Get-Interceptors { + param($lines) + $result = @() + for ($i = 0; $i -lt $lines.Count; $i++) { + $t = $lines[$i].Trim() + if ($t -match '^&(Перед|После|ИзменениеИКонтроль|Вместо)\("([^"]+)"\)') { + $result += @{ Type = $Matches[1]; Method = $Matches[2]; Line = $i } + } + } + return $result +} + +# Parse declared procedure/function names in a module +function Get-ProcNames { + param($lines) + $names = @() + foreach ($line in $lines) { + if ($line -imatch '^\s*(?:Асинх\s+)?(?:Процедура|Функция)\s+([\w]+)\s*\(') { $names += $Matches[1] } + } + return $names +} + +# ============================================================================ +# Build interceptor block (without enclosing wrappers) +# ============================================================================ +function Build-InterceptorCore { + param($method, [string]$interceptorType, [string]$interceptorName) + + $decoratorRu = $script:decoratorMap[$interceptorType] + $asyncPrefix = if ($method.IsAsync) { "Асинх " } else { "" } + $keyword = if ($method.IsFunction) { "Функция" } else { "Процедура" } + $endKeyword = if ($method.IsFunction) { "КонецФункции" } else { "КонецПроцедуры" } + + $lines = @() + if ($method.Context) { $lines += $method.Context } + $lines += "&$decoratorRu(`"$($method.Canonical)`")" + $lines += "$asyncPrefix$keyword $interceptorName($($method.ParamsText))" + + switch ($interceptorType) { + "Before" { + $lines += "`t// TODO: код перед вызовом оригинального метода" + } + "After" { + $lines += "`t// TODO: код после вызова оригинального метода" + } + "Instead" { + $namesJoined = ($method.ParamNames -join ", ") + if ($method.IsFunction) { + $lines += "`tРезультат = ПродолжитьВызов($namesJoined);" + $lines += "`t// TODO: доработать поведение" + $lines += "`tВозврат Результат;" + } else { + $lines += "`tПродолжитьВызов($namesJoined);" + $lines += "`t// TODO: доработать поведение" + } + } + "ModificationAndControl" { + foreach ($bl in $method.BodyLines) { $lines += $bl } + } + } + $lines += $endKeyword + return $lines +} + +# Wrap core with region/preprocessor lines, adding blank lines ("air") around +# each structural boundary. Empty chain -> core as-is. +function Build-WrappedBlock { + param($chainArr, $core) + $b = @() + foreach ($w in $chainArr) { + if ($w.Kind -eq 'region') { $b += "#Область $($w.Name)" } else { $b += "#Если $($w.Cond) Тогда" } + $b += "" + } + $b += $core + for ($c = $chainArr.Count - 1; $c -ge 0; $c--) { + $b += "" + if ($chainArr[$c].Kind -eq 'region') { $b += "#КонецОбласти" } else { $b += "#КонецЕсли" } + } + return $b +} + +# ============================================================================ +# Resync helpers (&ИзменениеИКонтроль) +# ============================================================================ + +function Get-Normalized { + param([string]$line) + return (($line -replace '\s+', ' ').Trim()) +} + +# Reconstruct v1 body and edit ops from a marked body +function Parse-MarkedBody { + param($bodyLines) + $v1 = @() # reconstructed original lines + $ops = @() # edit operations + $i = 0 + while ($i -lt $bodyLines.Count) { + $t = $bodyLines[$i].Trim() + if ($t -eq '#Вставка') { + $ins = @() + $i++ + while ($i -lt $bodyLines.Count -and $bodyLines[$i].Trim() -ne '#КонецВставки') { $ins += $bodyLines[$i]; $i++ } + $i++ # skip #КонецВставки + $ops += @{ Kind = 'insert'; After = ($v1.Count - 1); Lines = $ins } + } elseif ($t -eq '#Удаление') { + $startIdx = $v1.Count + $i++ + $del = @() + while ($i -lt $bodyLines.Count -and $bodyLines[$i].Trim() -ne '#КонецУдаления') { $del += $bodyLines[$i]; $v1 += $bodyLines[$i]; $i++ } + $i++ # skip #КонецУдаления + $ops += @{ Kind = 'delete'; Start = $startIdx; End = ($v1.Count - 1); Lines = $del } + } else { + $v1 += $bodyLines[$i] + $i++ + } + } + return @{ V1 = $v1; Ops = $ops } +} + +# Find unique normalized index of a line in v2; -1 if absent or ambiguous +function Find-UniqueIndex { + param($v2norm, [string]$key) + $found = -1 + for ($k = 0; $k -lt $v2norm.Count; $k++) { + if ($v2norm[$k] -eq $key) { + if ($found -ge 0) { return -1 } # ambiguous + $found = $k + } + } + return $found +} + +# Find unique contiguous run of normalized lines in v2; returns start index or -1 +function Find-UniqueRun { + param($v2norm, $keys) + if ($keys.Count -eq 0) { return -1 } + $found = -1 + for ($k = 0; $k -le ($v2norm.Count - $keys.Count); $k++) { + $match = $true + for ($m = 0; $m -lt $keys.Count; $m++) { + if ($v2norm[$k + $m] -ne $keys[$m]) { $match = $false; break } + } + if ($match) { + if ($found -ge 0) { return -1 } # ambiguous + $found = $k + } + } + return $found +} + +# ============================================================================ +# Main +# ============================================================================ + +# --- Resolve extension path --- +if (-not [System.IO.Path]::IsPathRooted($ExtensionPath)) { $ExtensionPath = Join-Path (Get-Location).Path $ExtensionPath } +if (Test-Path $ExtensionPath -PathType Leaf) { $ExtensionPath = Split-Path $ExtensionPath -Parent } +$cfgFile = Join-Path $ExtensionPath "Configuration.xml" +if (-not (Test-Path $cfgFile)) { Write-Error "Configuration.xml не найден в расширении: $ExtensionPath"; exit 1 } + +# --- Read NamePrefix --- +$cfgDoc = New-Object System.Xml.XmlDocument +$cfgDoc.PreserveWhitespace = $false +$cfgDoc.Load($cfgFile) +$cfgNs = New-Object System.Xml.XmlNamespaceManager($cfgDoc.NameTable) +$cfgNs.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses") +$propsNode = $cfgDoc.SelectSingleNode("//md:Configuration/md:Properties", $cfgNs) +$prefixNode = if ($propsNode) { $propsNode.SelectSingleNode("md:NamePrefix", $cfgNs) } else { $null } +$namePrefix = if ($prefixNode -and $prefixNode.InnerText) { $prefixNode.InnerText } else { "Расш_" } + +# --- Resolve module file paths (ModulePath = logical name OR path to a .bsl) --- +$hasConfigPath = -not [string]::IsNullOrEmpty($ConfigPath) +if ($hasConfigPath) { + if (-not [System.IO.Path]::IsPathRooted($ConfigPath)) { $ConfigPath = Join-Path (Get-Location).Path $ConfigPath } + if (Test-Path $ConfigPath -PathType Leaf) { $ConfigPath = Split-Path $ConfigPath -Parent } +} + +$isFilePath = ($ModulePath -match '[\\/]') -or ($ModulePath -match '\.bsl$') + +if ($isFilePath) { + # ModulePath is a filesystem path to the module .bsl + $mpAbs = if ([System.IO.Path]::IsPathRooted($ModulePath)) { $ModulePath } else { Join-Path (Get-Location).Path $ModulePath } + $relParts = Get-RelPartsFromFilePath $ModulePath + if (-not $relParts) { Write-Error "Не удалось определить объект по пути модуля: $ModulePath`n(нет распознаваемой типовой папки — Catalogs/Documents/CommonModules/…)"; exit 1 } + $extBsl = $ExtensionPath + foreach ($p in $relParts) { $extBsl = Join-Path $extBsl $p } + if ($hasConfigPath) { + $srcBsl = $ConfigPath + foreach ($p in $relParts) { $srcBsl = Join-Path $srcBsl $p } + } else { + # Guard: a path under the extension itself is not a valid source + $extRootAbs = [System.IO.Path]::GetFullPath($ExtensionPath).TrimEnd('\','/') + $mpFull = [System.IO.Path]::GetFullPath($mpAbs) + if ($mpFull.StartsWith($extRootAbs, [System.StringComparison]::OrdinalIgnoreCase)) { + Write-Error "Путь модуля указывает внутрь расширения, а не на источник. Укажите путь к модулю-источнику или -ConfigPath."; exit 1 + } + $srcBsl = $mpAbs } - $bslFile = Join-Path (Join-Path (Join-Path $ExtensionPath $dirName) $objName) (Join-Path "Ext" $moduleFileName) } else { - Write-Error "Invalid ModulePath format: $ModulePath. Expected: Type.Name.Module, Type.Name.Form.FormName, or CommonModule.Name" + # ModulePath is a logical name — ConfigPath required + if (-not $hasConfigPath) { Write-Error "Не указан -ConfigPath. Укажите путь к исходникам конфигурации или передайте путь к файлу модуля в -ModulePath."; exit 1 } + if (-not (Test-Path (Join-Path $ConfigPath "Configuration.xml"))) { Write-Error "Configuration.xml не найден в конфигурации-источнике: $ConfigPath"; exit 1 } + $relParts = Get-ModuleRelPath $ModulePath + $extBsl = $ExtensionPath + foreach ($p in $relParts) { $extBsl = Join-Path $extBsl $p } + $srcBsl = $ConfigPath + foreach ($p in $relParts) { $srcBsl = Join-Path $srcBsl $p } +} + +if (-not (Test-Path $srcBsl)) { Write-Error "Модуль-источник не найден: $srcBsl`n(проверьте ModulePath и ConfigPath)"; exit 1 } + +# --- Extract original method --- +$srcLines = [System.IO.File]::ReadAllLines($srcBsl, [System.Text.Encoding]::UTF8) +$method = Extract-Method $srcLines $MethodName +if (-not $method) { Write-Error "Метод '$MethodName' не найден в модуле-источнике: $srcBsl"; exit 1 } + +# --- Guard: functions cannot use Before/After --- +if ($method.IsFunction -and ($InterceptorType -eq "Before" -or $InterceptorType -eq "After")) { + Write-Error "Метод '$MethodName' — функция. Для функций доступны только Instead и ModificationAndControl (перехват &Перед/&После к функциям неприменим)." exit 1 } -# --- Map InterceptorType to decorator --- -$decorator = switch ($InterceptorType) { - "Before" { "&Перед" } - "After" { "&После" } - "ModificationAndControl" { "&ИзменениеИКонтроль" } -} +$decoratorRu = $script:decoratorMap[$InterceptorType] -# --- Map Context to annotation --- -$contextAnnotation = switch ($Context) { - "НаСервере" { "&НаСервере" } - "НаКлиенте" { "&НаКлиенте" } - "НаСервереБезКонтекста" { "&НаСервереБезКонтекста" } - default { "&$Context" } -} +# --- Read existing extension module (if any) --- +$extLines = @() +$extExists = Test-Path $extBsl +if ($extExists) { $extLines = @([System.IO.File]::ReadAllLines($extBsl, [System.Text.Encoding]::UTF8)) } -# --- Procedure name --- -$procName = "${namePrefix}${MethodName}" +$existingInterceptors = if ($extExists) { Get-Interceptors $extLines } else { @() } +$existingProcNames = if ($extExists) { Get-ProcNames $extLines } else { @() } -# --- Generate BSL code --- -$keyword = if ($IsFunction) { "Функция" } else { "Процедура" } -$endKeyword = if ($IsFunction) { "КонецФункции" } else { "КонецПроцедуры" } - -$bodyLines = @() -switch ($InterceptorType) { - "Before" { - $bodyLines += "`t// TODO: код перед вызовом оригинального метода" - } - "After" { - $bodyLines += "`t// TODO: код после вызова оригинального метода" - } - "ModificationAndControl" { - $bodyLines += "`t// Скопируйте тело оригинального метода и внесите изменения," - $bodyLines += "`t// используя маркеры #Удаление / #КонецУдаления и #Вставка / #КонецВставки" - } -} - -if ($IsFunction) { - $bodyLines += "`t" - $bodyLines += "`tВозврат Неопределено; // TODO: заменить на реальное возвращаемое значение" -} - -$bslCode = @() -$bslCode += "$contextAnnotation" -$bslCode += "${decorator}(`"$MethodName`")" -$bslCode += "$keyword ${procName}()" -$bslCode += $bodyLines -$bslCode += "$endKeyword" - -$bslText = ($bslCode -join "`r`n") + "`r`n" - -# --- Check form borrowing for .Form. paths --- -if ($parts.Count -ge 4 -and $parts[2] -eq "Form") { - $formName = $parts[3] - $dirName = $typeDirMap[$objType] - $formMetaFile = Join-Path (Join-Path (Join-Path (Join-Path $ExtensionPath $dirName) $objName) "Forms") "${formName}.xml" - $formXmlFile = Join-Path (Join-Path (Join-Path (Join-Path (Join-Path $ExtensionPath $dirName) $objName) "Forms") $formName) "Ext/Form.xml" - - if (-not (Test-Path $formMetaFile) -or -not (Test-Path $formXmlFile)) { - Write-Host "[WARN] Form '$formName' metadata or Form.xml not found in extension." - Write-Host " Run /cfe-borrow first:" - Write-Host " /cfe-borrow -ExtensionPath $ExtensionPath -ConfigPath -Object `"$objType.$objName.Form.$formName`"" - Write-Host "" - } -} - -# --- Check if file exists and append --- -$bslDir = Split-Path $bslFile -Parent -if (-not (Test-Path $bslDir)) { - New-Item -ItemType Directory -Path $bslDir -Force | Out-Null -} +# --- Does the same (method, type) already exist? --- +$dup = $existingInterceptors | Where-Object { $_.Type -eq $decoratorRu -and $_.Method -ieq $MethodName } | Select-Object -First 1 $enc = New-Object System.Text.UTF8Encoding($true) -if (Test-Path $bslFile) { - # Append to existing file - $existing = [System.IO.File]::ReadAllText($bslFile, $enc) - $separator = "`r`n" - if ($existing -and -not $existing.EndsWith("`n")) { - $separator = "`r`n`r`n" +if ($dup) { + if ($InterceptorType -ne "ModificationAndControl") { + Write-Host "[ПРОПУЩЕН] Перехватчик &$decoratorRu(`"$MethodName`") уже есть в модуле — дубль не создаётся." + Write-Host " Файл: $extBsl" + exit 0 } - $newContent = $existing + $separator + $bslText - [System.IO.File]::WriteAllText($bslFile, $newContent, $enc) - Write-Host "[OK] Добавлен перехватчик в существующий файл" -} else { - [System.IO.File]::WriteAllText($bslFile, $bslText, $enc) - Write-Host "[OK] Создан файл модуля" + # ---- RESYNC (&ИзменениеИКонтроль) ---- + # Locate existing block: decorator line -> signature -> body -> Конец* + $decLine = $dup.Line + # Interceptor procedure name from existing signature (line after decorator, skipping possible async) + $sigLineIdx = $decLine + 1 + if ($sigLineIdx -ge $extLines.Count -or $extLines[$sigLineIdx] -notmatch '^\s*(?:Асинх\s+)?(?:Процедура|Функция)\s+([\w]+)\s*\(') { + Write-Error "Не удалось найти сигнатуру существующего перехватчика &ИзменениеИКонтроль(`"$MethodName`")"; exit 1 + } + $existingName = $Matches[1] + $sig = Read-Signature $extLines $sigLineIdx + if (-not $sig) { Write-Error "Не удалось разобрать сигнатуру существующего перехватчика"; exit 1 } + $sigEnd = $sig.EndLineIdx + $isFunc = ($extLines[$sigLineIdx] -imatch '^\s*(?:Асинх\s+)?Функция\b') + $endRe = if ($isFunc) { '^\s*КонецФункции\b' } else { '^\s*КонецПроцедуры\b' } + $blockEnd = -1 + for ($j = $sigEnd + 1; $j -lt $extLines.Count; $j++) { if ($extLines[$j] -imatch $endRe) { $blockEnd = $j; break } } + if ($blockEnd -lt 0) { Write-Error "Не найден конец существующего перехватчика"; exit 1 } + + # marked body + $markedBody = @() + for ($j = $sigEnd + 1; $j -lt $blockEnd; $j++) { $markedBody += $extLines[$j] } + + # reconstruct v1, ops + $parsed = Parse-MarkedBody $markedBody + $v1 = $parsed.V1 + $ops = $parsed.Ops + $v2 = $method.BodyLines + + $v1norm = @($v1 | ForEach-Object { Get-Normalized $_ }) + $v2norm = @($v2 | ForEach-Object { Get-Normalized $_ }) + + # no drift? + if (($v1norm -join "`n") -eq ($v2norm -join "`n")) { + Write-Host "[АКТУАЛЕН] &ИзменениеИКонтроль(`"$MethodName`") — оригинал не менялся, изменений нет." + Write-Host " Файл: $extBsl" + exit 0 + } + + # transfer ops onto v2 + $insertTop = @() + $insertAfter = @{} # v2 index -> list of blocks (each = @{Lines=..}) + $delStart = @{} # v2 index -> $true + $delEnd = @{} + $disputed = @() + + foreach ($op in $ops) { + if ($op.Kind -eq 'insert') { + if ($op.After -lt 0) { $insertTop += ,$op.Lines; continue } + $anchorKey = $v1norm[$op.After] + $k = Find-UniqueIndex $v2norm $anchorKey + if ($k -ge 0) { + if (-not $insertAfter.ContainsKey($k)) { $insertAfter[$k] = @() } + $insertAfter[$k] += ,$op.Lines + } else { + $disputed += @{ Kind = 'insert'; Lines = $op.Lines } + } + } else { + $keys = @() + for ($m = $op.Start; $m -le $op.End; $m++) { $keys += $v1norm[$m] } + $p = Find-UniqueRun $v2norm $keys + if ($p -ge 0) { + $delStart[$p] = $true + $delEnd[$p + $keys.Count - 1] = $true + } else { + $disputed += @{ Kind = 'delete'; Lines = $op.Lines } + } + } + } + + # assemble new marked body + $newBody = @() + foreach ($blk in $insertTop) { + $newBody += "#Вставка"; foreach ($l in $blk) { $newBody += $l }; $newBody += "#КонецВставки" + } + for ($k = 0; $k -lt $v2.Count; $k++) { + if ($delStart.ContainsKey($k)) { $newBody += "#Удаление" } + $newBody += $v2[$k] + if ($delEnd.ContainsKey($k)) { $newBody += "#КонецУдаления" } + if ($insertAfter.ContainsKey($k)) { + foreach ($blk in $insertAfter[$k]) { + $newBody += "#Вставка"; foreach ($l in $blk) { $newBody += $l }; $newBody += "#КонецВставки" + } + } + } + # disputed blocks appended with conflict markers (never lost) + if ($disputed.Count -gt 0) { + $newBody += "`t// [РЕСИНК-КОНФЛИКТ] перенесите блоки ниже вручную — исходный якорь изменился в новой версии оригинала." + $newBody += "`t// Материалы для анализа см. в выводе команды (файлы v1/v2/current/diff)." + foreach ($d in $disputed) { + if ($d.Kind -eq 'insert') { + $newBody += "#Вставка"; foreach ($l in $d.Lines) { $newBody += $l }; $newBody += "#КонецВставки" + } else { + $newBody += "`t// [РЕСИНК-КОНФЛИКТ] не удалось найти для удаления:" + foreach ($l in $d.Lines) { $newBody += ("`t// " + $l.Trim()) } + } + } + } + + # rebuild block: keep context (from v2), decorator, signature with existing name and v2 params + $asyncPrefix = if ($method.IsAsync) { "Асинх " } else { "" } + $keyword = if ($method.IsFunction) { "Функция" } else { "Процедура" } + $endKeyword = if ($method.IsFunction) { "КонецФункции" } else { "КонецПроцедуры" } + $newBlock = @() + if ($method.Context) { $newBlock += $method.Context } + $newBlock += "&ИзменениеИКонтроль(`"$($method.Canonical)`")" + $newBlock += "$asyncPrefix$keyword $existingName($($method.ParamsText))" + $newBlock += $newBody + $newBlock += $endKeyword + + # block start includes preceding context directive line if present + $blockStart = $decLine + if ($decLine -ge 1 -and (Test-ContextDirective $extLines[$decLine - 1].Trim())) { $blockStart = $decLine - 1 } + + $out = @() + for ($j = 0; $j -lt $blockStart; $j++) { $out += $extLines[$j] } + foreach ($l in $newBlock) { $out += $l } + for ($j = $blockEnd + 1; $j -lt $extLines.Count; $j++) { $out += $extLines[$j] } + + [System.IO.File]::WriteAllText($extBsl, (($out -join "`r`n") + "`r`n"), $enc) + + if ($disputed.Count -gt 0) { + # write version files + $tmpRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("cfe-resync\" + ($ModulePath -replace '[\\/:*?"<>|]', '_') + "." + $MethodName) + if (-not (Test-Path $tmpRoot)) { New-Item -ItemType Directory -Path $tmpRoot -Force | Out-Null } + [System.IO.File]::WriteAllText((Join-Path $tmpRoot "v1.bsl"), (($v1 -join "`r`n") + "`r`n"), $enc) + [System.IO.File]::WriteAllText((Join-Path $tmpRoot "v2.bsl"), (($v2 -join "`r`n") + "`r`n"), $enc) + [System.IO.File]::WriteAllText((Join-Path $tmpRoot "current.bsl"), (($markedBody -join "`r`n") + "`r`n"), $enc) + $diff = @() + $diff += "--- v1 (что было скопировано) vs v2 (новый оригинал) ---" + foreach ($l in $v1) { if ($v2norm -notcontains (Get-Normalized $l)) { $diff += "- $l" } } + foreach ($l in $v2) { if ($v1norm -notcontains (Get-Normalized $l)) { $diff += "+ $l" } } + [System.IO.File]::WriteAllText((Join-Path $tmpRoot "diff.txt"), (($diff -join "`r`n") + "`r`n"), $enc) + + Write-Host "[АКТУАЛИЗИРОВАН-ЧАСТИЧНО] &ИзменениеИКонтроль(`"$MethodName`")" + Write-Host " Перенесено автоматически, конфликтов: $($disputed.Count) (помечены // [РЕСИНК-КОНФЛИКТ])" + Write-Host " Файлы-версии для анализа:" + Write-Host " $tmpRoot" + Write-Host " Проверьте конфликтные блоки и разместите их вручную." + } else { + Write-Host "[АКТУАЛИЗИРОВАН] &ИзменениеИКонтроль(`"$MethodName`") — тело обновлено по новому оригиналу, правки перенесены." + } + Write-Host " Файл: $extBsl" + exit 0 } -Write-Host " Файл: $bslFile" -Write-Host " Декоратор: $decorator(`"$MethodName`")" -Write-Host " Процедура: ${procName}()" -Write-Host " Контекст: $contextAnnotation" +# ============================================================================ +# New interceptor: compute name, build block, place (region-aware) +# ============================================================================ + +# Procedure name with collision handling +$candidate = "${namePrefix}$($method.Canonical)" +$taken = @($existingProcNames | ForEach-Object { $_.ToLower() }) +$interceptorName = $candidate +if ($taken -contains $candidate.ToLower()) { + if ($InterceptorType -eq "ModificationAndControl") { + $interceptorName = "${candidate}_ИзменениеИКонтроль" + } else { + $interceptorName = "${candidate}_$decoratorRu" + } +} + +$core = Build-InterceptorCore $method $InterceptorType $interceptorName + +# --- Region-aware placement --- +# Find innermost region in the source chain that already exists in the extension module. +$chain = $method.Chain +$reuseRegionIdx = -1 # index in chain of the region to reuse +$reuseLineIdx = -1 # line in extLines of its #Область +if ($extExists) { + for ($c = $chain.Count - 1; $c -ge 0; $c--) { + if ($chain[$c].Kind -eq 'region') { + $rname = $chain[$c].Name + for ($li = 0; $li -lt $extLines.Count; $li++) { + if ($extLines[$li].Trim() -match ('^#Область\s+' + [regex]::Escape($rname) + '\s*$')) { + $reuseRegionIdx = $c; $reuseLineIdx = $li; break + } + } + } + if ($reuseRegionIdx -ge 0) { break } + } +} + +if ($reuseRegionIdx -ge 0) { + # Insert inside the existing region, before its matching #КонецОбласти. + # Wrappers inner to the reused region are emitted around the method; outer are inherited. + $innerChain = @() + for ($c = $reuseRegionIdx + 1; $c -lt $chain.Count; $c++) { $innerChain += $chain[$c] } + + $block = Build-WrappedBlock $innerChain $core + + # find matching #КонецОбласти for the reused region + $depth = 0; $closeIdx = -1 + for ($li = $reuseLineIdx; $li -lt $extLines.Count; $li++) { + $t = $extLines[$li].Trim() + if ($t -match '^#Область\s') { $depth++ } + elseif ($t -match '^#КонецОбласти') { $depth--; if ($depth -eq 0) { $closeIdx = $li; break } } + } + if ($closeIdx -lt 0) { Write-Error "Не найден #КонецОбласти для региона (переиспользование)"; exit 1 } + + # strip trailing blank lines of the region content, then insert with air + $lastContent = $closeIdx - 1 + while ($lastContent -ge 0 -and $extLines[$lastContent].Trim() -eq "") { $lastContent-- } + $out = @() + for ($j = 0; $j -le $lastContent; $j++) { $out += $extLines[$j] } + $out += "" + foreach ($l in $block) { $out += $l } + $out += "" + for ($j = $closeIdx; $j -lt $extLines.Count; $j++) { $out += $extLines[$j] } + [System.IO.File]::WriteAllText($extBsl, (($out -join "`r`n") + "`r`n"), $enc) + $placement = "в существующий регион '$($chain[$reuseRegionIdx].Name)'" +} else { + # Build full wrapper chain (source order) and append (or create file). + $block = Build-WrappedBlock $chain $core + $blockText = ($block -join "`r`n") + "`r`n" + + $bslDir = Split-Path $extBsl -Parent + if (-not (Test-Path $bslDir)) { New-Item -ItemType Directory -Path $bslDir -Force | Out-Null } + + if ($extExists) { + $existing = [System.IO.File]::ReadAllText($extBsl, $enc) + if ([string]::IsNullOrWhiteSpace($existing)) { + # Borrowed-but-empty module (e.g. cfe-borrow form module) + [System.IO.File]::WriteAllText($extBsl, $blockText, $enc) + $placement = "заполнен модуль" + } else { + $sep = if ($existing.EndsWith("`n")) { "`r`n" } else { "`r`n`r`n" } + [System.IO.File]::WriteAllText($extBsl, ($existing + $sep + $blockText), $enc) + $placement = "дописан в модуль" + } + } else { + [System.IO.File]::WriteAllText($extBsl, $blockText, $enc) + $placement = "создан модуль" + } +} + +Write-Host "[OK] Перехватчик &$decoratorRu(`"$MethodName`") — $placement" +Write-Host " Файл: $extBsl" +Write-Host " Процедура: $interceptorName($($method.ParamsText -replace '\s+', ' '))" +if ($method.Context) { Write-Host " Контекст: $($method.Context)" } +if ($chain.Count -gt 0) { + $chainDesc = ($chain | ForEach-Object { if ($_.Kind -eq 'region') { "Область:$($_.Name)" } else { "Если:$($_.Cond)" } }) -join " > " + Write-Host " Обрамление: $chainDesc" +} diff --git a/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.py b/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.py index 5a1ac770..f8f33efb 100644 --- a/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.py +++ b/.claude/skills/cfe-patch-method/scripts/cfe-patch-method.py @@ -1,246 +1,776 @@ #!/usr/bin/env python3 -# cfe-patch-method v1.1 — Generate method interceptor for 1C extension (CFE) +# cfe-patch-method v2.0 — Source-aware method interceptor for 1C extension (CFE) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import os +import re import sys +import tempfile import xml.etree.ElementTree as ET +TYPE_DIR_MAP = { + "Catalog": "Catalogs", "Document": "Documents", "Enum": "Enums", + "CommonModule": "CommonModules", "Report": "Reports", "DataProcessor": "DataProcessors", + "ExchangePlan": "ExchangePlans", "ChartOfAccounts": "ChartsOfAccounts", + "ChartOfCharacteristicTypes": "ChartsOfCharacteristicTypes", + "ChartOfCalculationTypes": "ChartsOfCalculationTypes", + "BusinessProcess": "BusinessProcesses", "Task": "Tasks", + "InformationRegister": "InformationRegisters", "AccumulationRegister": "AccumulationRegisters", + "AccountingRegister": "AccountingRegisters", "CalculationRegister": "CalculationRegisters", +} +# accept plural forms too +for _v in list(TYPE_DIR_MAP.values()): + TYPE_DIR_MAP[_v] = _v -def main(): - sys.stdout.reconfigure(encoding="utf-8") - sys.stderr.reconfigure(encoding="utf-8") - parser = argparse.ArgumentParser( - description="Generate method interceptor for 1C extension (CFE)", - allow_abbrev=False, - ) - parser.add_argument("-ExtensionPath", required=True) - parser.add_argument("-ModulePath", required=True) - parser.add_argument("-MethodName", required=True) - parser.add_argument( - "-InterceptorType", - required=True, - choices=["Before", "After", "ModificationAndControl"], - ) - parser.add_argument("-Context", default="\u041d\u0430\u0421\u0435\u0440\u0432\u0435\u0440\u0435") # НаСервере - parser.add_argument("-IsFunction", action="store_true") - args = parser.parse_args() +# InterceptorType -> Russian decorator keyword +DECORATOR_MAP = { + "Before": "Перед", "After": "После", "Instead": "Вместо", + "ModificationAndControl": "ИзменениеИКонтроль", +} - extension_path = args.ExtensionPath - module_path = args.ModulePath - method_name = args.MethodName - interceptor_type = args.InterceptorType - context = args.Context - is_function = args.IsFunction +CONTEXT_RE = re.compile( + r'^&(НаКлиенте|НаСервере|НаСервереБезКонтекста|НаКлиентеНаСервереБезКонтекста|НаКлиентеНаСервере)\s*$' +) - # --- Resolve extension path --- - if not os.path.isabs(extension_path): - extension_path = os.path.join(os.getcwd(), extension_path) - if os.path.isfile(extension_path): - extension_path = os.path.dirname(extension_path) - - cfg_file = os.path.join(extension_path, "Configuration.xml") - if not os.path.isfile(cfg_file): - print(f"Configuration.xml not found in: {extension_path}", file=sys.stderr) - sys.exit(1) - - # --- Read NamePrefix from Configuration.xml --- - tree = ET.parse(cfg_file) - root = tree.getroot() - - ns = {"md": "http://v8.1c.ru/8.3/MDClasses"} - props_node = root.find(".//md:Configuration/md:Properties", ns) - name_prefix = "\u0420\u0430\u0441\u0448_" # Расш_ - if props_node is not None: - prefix_node = props_node.find("md:NamePrefix", ns) - if prefix_node is not None and prefix_node.text: - name_prefix = prefix_node.text - - # --- Map ModulePath to file path --- - # ModulePath formats: - # Catalog.X.ObjectModule -> Catalogs/X/Ext/ObjectModule.bsl - # Catalog.X.ManagerModule -> Catalogs/X/Ext/ManagerModule.bsl - # Catalog.X.Form.Y -> Catalogs/X/Forms/Y/Ext/Form/Module.bsl - # CommonModule.X -> CommonModules/X/Ext/Module.bsl - # Document.X.ObjectModule -> Documents/X/Ext/ObjectModule.bsl - # Document.X.ManagerModule -> Documents/X/Ext/ManagerModule.bsl - # Document.X.Form.Y -> Documents/X/Forms/Y/Ext/Form/Module.bsl - - type_dir_map = { - "Catalog": "Catalogs", - "Document": "Documents", - "Enum": "Enums", - "CommonModule": "CommonModules", - "Report": "Reports", - "DataProcessor": "DataProcessors", - "ExchangePlan": "ExchangePlans", - "ChartOfAccounts": "ChartsOfAccounts", - "ChartOfCharacteristicTypes": "ChartsOfCharacteristicTypes", - "ChartOfCalculationTypes": "ChartsOfCalculationTypes", - "BusinessProcess": "BusinessProcesses", - "Task": "Tasks", - "InformationRegister": "InformationRegisters", - "AccumulationRegister": "AccumulationRegisters", - "AccountingRegister": "AccountingRegisters", - "CalculationRegister": "CalculationRegisters", - "Catalogs": "Catalogs", - "Documents": "Documents", - "Enums": "Enums", - "CommonModules": "CommonModules", - "Reports": "Reports", - "DataProcessors": "DataProcessors", - "ExchangePlans": "ExchangePlans", - "ChartsOfAccounts": "ChartsOfAccounts", - "ChartsOfCharacteristicTypes": "ChartsOfCharacteristicTypes", - "ChartsOfCalculationTypes": "ChartsOfCalculationTypes", - "BusinessProcesses": "BusinessProcesses", - "Tasks": "Tasks", - "InformationRegisters": "InformationRegisters", - "AccumulationRegisters": "AccumulationRegisters", - "AccountingRegisters": "AccountingRegisters", - "CalculationRegisters": "CalculationRegisters", - } +def get_module_rel_path(module_path): parts = module_path.split(".") if len(parts) < 2: - print( - f"Invalid ModulePath format: {module_path}. " - "Expected: Type.Name.Module or CommonModule.Name", - file=sys.stderr, + raise ValueError( + "Invalid ModulePath format: %s. Expected: Type.Name.Module, " + "Type.Name.Form.FormName or CommonModule.Name" % module_path ) - sys.exit(1) - obj_type = parts[0] obj_name = parts[1] + if obj_type not in TYPE_DIR_MAP: + raise ValueError("Unknown object type: %s" % obj_type) + dir_name = TYPE_DIR_MAP[obj_type] - if obj_type not in type_dir_map: - print(f"Unknown object type: {obj_type}", file=sys.stderr) - sys.exit(1) - - dir_name = type_dir_map[obj_type] - - bsl_file = None if obj_type == "CommonModule": - # CommonModule.X -> CommonModules/X/Ext/Module.bsl - bsl_file = os.path.join(extension_path, dir_name, obj_name, "Ext", "Module.bsl") - elif len(parts) >= 4 and parts[2] == "Form": - # Type.X.Form.Y -> Types/X/Forms/Y/Ext/Form/Module.bsl + return [dir_name, obj_name, "Ext", "Module.bsl"] + if len(parts) >= 4 and parts[2] == "Form": form_name = parts[3] - bsl_file = os.path.join( - extension_path, dir_name, obj_name, "Forms", form_name, "Ext", "Form", "Module.bsl" - ) - elif len(parts) >= 3: - # Type.X.ObjectModule -> Types/X/Ext/ObjectModule.bsl + return [dir_name, obj_name, "Forms", form_name, "Ext", "Form", "Module.bsl"] + if len(parts) >= 3: module_name = parts[2] module_file_map = { "ObjectModule": "ObjectModule.bsl", "ManagerModule": "ManagerModule.bsl", "RecordSetModule": "RecordSetModule.bsl", "CommandModule": "CommandModule.bsl", + "ValueManagerModule": "ValueManagerModule.bsl", } - module_file_name = module_file_map.get(module_name, f"{module_name}.bsl") - bsl_file = os.path.join(extension_path, dir_name, obj_name, "Ext", module_file_name) - else: - print( - f"Invalid ModulePath format: {module_path}. " - "Expected: Type.Name.Module, Type.Name.Form.FormName, or CommonModule.Name", - file=sys.stderr, - ) - sys.exit(1) + return [dir_name, obj_name, "Ext", module_file_map.get(module_name, module_name + ".bsl")] + raise ValueError("Invalid ModulePath format: %s" % module_path) - # --- Map InterceptorType to decorator --- - decorator_map = { - "Before": "&\u041f\u0435\u0440\u0435\u0434", # &Перед - "After": "&\u041f\u043e\u0441\u043b\u0435", # &После - "ModificationAndControl": "&\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u0418\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c", # &ИзменениеИКонтроль - } - decorator = decorator_map[interceptor_type] - # --- Map Context to annotation --- - context_map = { - "\u041d\u0430\u0421\u0435\u0440\u0432\u0435\u0440\u0435": "&\u041d\u0430\u0421\u0435\u0440\u0432\u0435\u0440\u0435", # НаСервере -> &НаСервере - "\u041d\u0430\u041a\u043b\u0438\u0435\u043d\u0442\u0435": "&\u041d\u0430\u041a\u043b\u0438\u0435\u043d\u0442\u0435", # НаКлиенте -> &НаКлиенте - "\u041d\u0430\u0421\u0435\u0440\u0432\u0435\u0440\u0435\u0411\u0435\u0437\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430": "&\u041d\u0430\u0421\u0435\u0440\u0432\u0435\u0440\u0435\u0411\u0435\u0437\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430", # НаСервереБезКонтекста -> &НаСервереБезКонтекста - } - context_annotation = context_map.get(context, f"&{context}") +def get_rel_parts_from_file_path(path): + segs = [s for s in path.replace("\\", "/").split("/") if s] + anchors = set(TYPE_DIR_MAP.values()) + for i in range(len(segs)): + if segs[i] in anchors: + return segs[i:] + return None - # --- Procedure name --- - proc_name = f"{name_prefix}{method_name}" - # --- Generate BSL code --- - keyword = "\u0424\u0443\u043d\u043a\u0446\u0438\u044f" if is_function else "\u041f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0430" # Функция / Процедура - end_keyword = "\u041a\u043e\u043d\u0435\u0446\u0424\u0443\u043d\u043a\u0446\u0438\u0438" if is_function else "\u041a\u043e\u043d\u0435\u0446\u041f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b" # КонецФункции / КонецПроцедуры +def read_lines(path): + with open(path, "r", encoding="utf-8-sig", newline="") as f: + text = f.read() + text = text.replace("\r\n", "\n").replace("\r", "\n") + lines = text.split("\n") + if lines and lines[-1] == "": + lines.pop() + return lines + + +def write_bsl(path, lines): + text = "\r\n".join(lines) + "\r\n" + with open(path, "w", encoding="utf-8-sig", newline="") as f: + f.write(text) + + +def split_top_level(text, sep=","): + result = [] + depth = 0 + in_str = False + buf = [] + for ch in text: + if in_str: + buf.append(ch) + if ch == '"': + in_str = False + continue + if ch == '"': + in_str = True + buf.append(ch) + continue + if ch == '(': + depth += 1 + buf.append(ch) + continue + if ch == ')': + depth -= 1 + buf.append(ch) + continue + if ch == sep and depth == 0: + result.append("".join(buf)) + buf = [] + continue + buf.append(ch) + result.append("".join(buf)) + return result + + +def is_context_directive(trimmed): + return bool(CONTEXT_RE.match(trimmed)) + + +def read_signature(lines, start_idx): + """Return (params_text, end_line_idx) or None.""" + depth = 0 + in_str = False + open_found = False + params = [] + for li in range(start_idx, len(lines)): + line = lines[li] + for ch in line: + if in_str: + if open_found: + params.append(ch) + if ch == '"': + in_str = False + continue + if ch == '"': + in_str = True + if open_found: + params.append(ch) + continue + if ch == '(': + depth += 1 + if not open_found: + open_found = True + else: + params.append(ch) + continue + if ch == ')': + depth -= 1 + if depth == 0: + return ("".join(params), li) + params.append(ch) + continue + if open_found: + params.append(ch) + if open_found and depth >= 1: + params.append("\r\n") + return None + + +def effective_condition(frame): + conds = frame["conds"] + n = len(conds) + if frame["in_else"]: + return " И ".join("НЕ (%s)" % c for c in conds) + if n == 1: + return conds[0] + parts = ["НЕ (%s)" % conds[j] for j in range(n - 1)] + parts.append(conds[n - 1]) + return " И ".join(parts) + + +def get_enclosing_chain(lines, target_idx): + stack = [] + for i in range(target_idx): + t = lines[i].strip() + m = re.match(r'^#Область\s+(\S+)', t) + if m: + stack.append({"kind": "region", "name": m.group(1)}) + continue + if re.match(r'^#КонецОбласти', t): + for k in range(len(stack) - 1, -1, -1): + if stack[k]["kind"] == "region": + del stack[k] + break + continue + m = re.match(r'^#Если\s+(.+?)\s+Тогда', t) + if m: + stack.append({"kind": "if", "conds": [m.group(1).strip()], "in_else": False}) + continue + m = re.match(r'^#ИначеЕсли\s+(.+?)\s+Тогда', t) + if m: + for k in range(len(stack) - 1, -1, -1): + if stack[k]["kind"] == "if": + stack[k]["conds"].append(m.group(1).strip()) + stack[k]["in_else"] = False + break + continue + if re.match(r'^#Иначе(\s|$)', t): + for k in range(len(stack) - 1, -1, -1): + if stack[k]["kind"] == "if": + stack[k]["in_else"] = True + break + continue + if re.match(r'^#КонецЕсли', t): + for k in range(len(stack) - 1, -1, -1): + if stack[k]["kind"] == "if": + del stack[k] + break + continue + chain = [] + for f in stack: + if f["kind"] == "region": + chain.append({"kind": "region", "name": f["name"]}) + else: + chain.append({"kind": "if", "cond": effective_condition(f)}) + return chain + + +def extract_method(lines, method_name): + decl_re = re.compile( + r'^\s*(Асинх\s+)?(Процедура|Функция)\s+(' + re.escape(method_name) + r')\s*\(', + re.IGNORECASE, + ) + for i in range(len(lines)): + m = decl_re.match(lines[i]) + if not m: + continue + is_async = bool(m.group(1)) + keyword = m.group(2) + canonical = m.group(3) + is_function = keyword.lower() == "функция" + + sig = read_signature(lines, i) + if not sig: + raise ValueError("Не удалось разобрать сигнатуру метода '%s'" % method_name) + params_text, sig_end = sig + + param_names = [] + if params_text.strip(): + for seg in split_top_level(params_text): + s = re.sub(r'^Знач\s+', '', seg.strip()) + mm = re.match(r'^([\w]+)', s) + if mm: + param_names.append(mm.group(1)) + + end_re = re.compile(r'^\s*КонецФункции\b' if is_function else r'^\s*КонецПроцедуры\b', + re.IGNORECASE) + body_start = sig_end + 1 + body_end = -1 + for j in range(body_start, len(lines)): + if end_re.match(lines[j]): + body_end = j + break + if body_end < 0: + raise ValueError("Не найден конец метода '%s'" % method_name) + body_lines = lines[body_start:body_end] + + context = "" + if i >= 1: + prev = lines[i - 1].strip() + if is_context_directive(prev): + context = prev + + chain = get_enclosing_chain(lines, i) + + return { + "canonical": canonical, + "is_function": is_function, + "is_async": is_async, + "params_text": params_text, + "param_names": param_names, + "context": context, + "body_lines": body_lines, + "chain": chain, + "decl_idx": i, + "sig_end_idx": sig_end, + "body_end_idx": body_end, + } + return None + + +def get_interceptors(lines): + result = [] + pat = re.compile(r'^&(Перед|После|ИзменениеИКонтроль|Вместо)\("([^"]+)"\)') + for i in range(len(lines)): + m = pat.match(lines[i].strip()) + if m: + result.append({"type": m.group(1), "method": m.group(2), "line": i}) + return result + + +def get_proc_names(lines): + names = [] + pat = re.compile(r'^\s*(?:Асинх\s+)?(?:Процедура|Функция)\s+([\w]+)\s*\(', re.IGNORECASE) + for line in lines: + m = pat.match(line) + if m: + names.append(m.group(1)) + return names + + +def build_interceptor_core(method, interceptor_type, interceptor_name): + decorator_ru = DECORATOR_MAP[interceptor_type] + async_prefix = "Асинх " if method["is_async"] else "" + keyword = "Функция" if method["is_function"] else "Процедура" + end_keyword = "КонецФункции" if method["is_function"] else "КонецПроцедуры" + + lines = [] + if method["context"]: + lines.append(method["context"]) + lines.append('&%s("%s")' % (decorator_ru, method["canonical"])) + lines.append("%s%s %s(%s)" % (async_prefix, keyword, interceptor_name, method["params_text"])) - body_lines = [] if interceptor_type == "Before": - body_lines.append("\t// TODO: \u043a\u043e\u0434 \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430") # код перед вызовом оригинального метода + lines.append("\t// TODO: код перед вызовом оригинального метода") elif interceptor_type == "After": - body_lines.append("\t// TODO: \u043a\u043e\u0434 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430") # код после вызова оригинального метода + lines.append("\t// TODO: код после вызова оригинального метода") + elif interceptor_type == "Instead": + names_joined = ", ".join(method["param_names"]) + if method["is_function"]: + lines.append("\tРезультат = ПродолжитьВызов(%s);" % names_joined) + lines.append("\t// TODO: доработать поведение") + lines.append("\tВозврат Результат;") + else: + lines.append("\tПродолжитьВызов(%s);" % names_joined) + lines.append("\t// TODO: доработать поведение") elif interceptor_type == "ModificationAndControl": - body_lines.append("\t// \u0421\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0442\u0435\u043b\u043e \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u0438 \u0432\u043d\u0435\u0441\u0438\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f,") # Скопируйте тело оригинального метода и внесите изменения, - body_lines.append("\t// \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043c\u0430\u0440\u043a\u0435\u0440\u044b #\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 / #\u041a\u043e\u043d\u0435\u0446\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0438 #\u0412\u0441\u0442\u0430\u0432\u043a\u0430 / #\u041a\u043e\u043d\u0435\u0446\u0412\u0441\u0442\u0430\u0432\u043a\u0438") # используя маркеры #Удаление / #КонецУдаления и #Вставка / #КонецВставки + lines.extend(method["body_lines"]) - if is_function: - body_lines.append("\t") - body_lines.append("\t\u0412\u043e\u0437\u0432\u0440\u0430\u0442 \u041d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e; // TODO: \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435") # Возврат Неопределено; // TODO: заменить на реальное возвращаемое значение + lines.append(end_keyword) + return lines - bsl_code = [ - context_annotation, - f'{decorator}("{method_name}")', - f"{keyword} {proc_name}()", - ] - bsl_code.extend(body_lines) - bsl_code.append(end_keyword) - bsl_text = "\r\n".join(bsl_code) + "\r\n" +def build_wrapped_block(chain_arr, core): + """Wrap core with region/preprocessor lines, adding blank lines around each boundary.""" + b = [] + for w in chain_arr: + b.append("#Область %s" % w["name"] if w["kind"] == "region" else "#Если %s Тогда" % w["cond"]) + b.append("") + b.extend(core) + for w in reversed(chain_arr): + b.append("") + b.append("#КонецОбласти" if w["kind"] == "region" else "#КонецЕсли") + return b - # --- Check form borrowing for .Form. paths --- - if len(parts) >= 4 and parts[2] == "Form": - form_name = parts[3] - form_meta_file = os.path.join( - extension_path, dir_name, obj_name, "Forms", f"{form_name}.xml" - ) - form_xml_file = os.path.join( - extension_path, dir_name, obj_name, "Forms", form_name, "Ext", "Form.xml" + +def normalize(line): + return re.sub(r'\s+', ' ', line).strip() + + +def parse_marked_body(body_lines): + v1 = [] + ops = [] + i = 0 + n = len(body_lines) + while i < n: + t = body_lines[i].strip() + if t == "#Вставка": + ins = [] + i += 1 + while i < n and body_lines[i].strip() != "#КонецВставки": + ins.append(body_lines[i]) + i += 1 + i += 1 + ops.append({"kind": "insert", "after": len(v1) - 1, "lines": ins}) + elif t == "#Удаление": + start_idx = len(v1) + i += 1 + dels = [] + while i < n and body_lines[i].strip() != "#КонецУдаления": + dels.append(body_lines[i]) + v1.append(body_lines[i]) + i += 1 + i += 1 + ops.append({"kind": "delete", "start": start_idx, "end": len(v1) - 1, "lines": dels}) + else: + v1.append(body_lines[i]) + i += 1 + return {"v1": v1, "ops": ops} + + +def find_unique_index(v2norm, key): + found = -1 + for k in range(len(v2norm)): + if v2norm[k] == key: + if found >= 0: + return -1 + found = k + return found + + +def find_unique_run(v2norm, keys): + if not keys: + return -1 + found = -1 + for k in range(len(v2norm) - len(keys) + 1): + if v2norm[k:k + len(keys)] == keys: + if found >= 0: + return -1 + found = k + return found + + +def die(msg): + print(msg, file=sys.stderr) + sys.exit(1) + + +def main(): + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") + parser = argparse.ArgumentParser( + description="Source-aware method interceptor for 1C extension (CFE)", + allow_abbrev=False, + ) + parser.add_argument("-ExtensionPath", required=True) + parser.add_argument("-ConfigPath", required=False, default="") + parser.add_argument("-ModulePath", required=True) + parser.add_argument("-MethodName", required=True) + parser.add_argument("-InterceptorType", required=True, + choices=["Before", "After", "Instead", "ModificationAndControl"]) + args = parser.parse_args() + + extension_path = args.ExtensionPath + config_path = args.ConfigPath + module_path = args.ModulePath + method_name = args.MethodName + interceptor_type = args.InterceptorType + + # --- Resolve extension path --- + if not os.path.isabs(extension_path): + extension_path = os.path.join(os.getcwd(), extension_path) + if os.path.isfile(extension_path): + extension_path = os.path.dirname(extension_path) + cfg_file = os.path.join(extension_path, "Configuration.xml") + if not os.path.isfile(cfg_file): + die("Configuration.xml не найден в расширении: %s" % extension_path) + + # --- Read NamePrefix --- + ns = {"md": "http://v8.1c.ru/8.3/MDClasses"} + name_prefix = "Расш_" + try: + root = ET.parse(cfg_file).getroot() + props = root.find(".//md:Configuration/md:Properties", ns) + if props is not None: + pn = props.find("md:NamePrefix", ns) + if pn is not None and pn.text: + name_prefix = pn.text + except ET.ParseError: + pass + + # --- Resolve module file paths (ModulePath = logical name OR path to a .bsl) --- + has_config = bool(config_path) + if has_config: + if not os.path.isabs(config_path): + config_path = os.path.join(os.getcwd(), config_path) + if os.path.isfile(config_path): + config_path = os.path.dirname(config_path) + + is_file_path = bool(re.search(r'[\\/]', module_path)) or module_path.endswith(".bsl") + + if is_file_path: + mp_abs = module_path if os.path.isabs(module_path) else os.path.join(os.getcwd(), module_path) + rel_parts = get_rel_parts_from_file_path(module_path) + if not rel_parts: + die("Не удалось определить объект по пути модуля: %s\n" + "(нет распознаваемой типовой папки — Catalogs/Documents/CommonModules/…)" % module_path) + ext_bsl = os.path.join(extension_path, *rel_parts) + if has_config: + src_bsl = os.path.join(config_path, *rel_parts) + else: + ext_root_abs = os.path.normcase(os.path.abspath(extension_path)).rstrip("\\/") + mp_full = os.path.normcase(os.path.abspath(mp_abs)) + if mp_full.startswith(ext_root_abs): + die("Путь модуля указывает внутрь расширения, а не на источник. " + "Укажите путь к модулю-источнику или -ConfigPath.") + src_bsl = mp_abs + else: + if not has_config: + die("Не указан -ConfigPath. Укажите путь к исходникам конфигурации " + "или передайте путь к файлу модуля в -ModulePath.") + if not os.path.isfile(os.path.join(config_path, "Configuration.xml")): + die("Configuration.xml не найден в конфигурации-источнике: %s" % config_path) + rel_parts = get_module_rel_path(module_path) + ext_bsl = os.path.join(extension_path, *rel_parts) + src_bsl = os.path.join(config_path, *rel_parts) + + if not os.path.isfile(src_bsl): + die("Модуль-источник не найден: %s\n(проверьте ModulePath и ConfigPath)" % src_bsl) + + # --- Extract original method --- + src_lines = read_lines(src_bsl) + method = extract_method(src_lines, method_name) + if not method: + die("Метод '%s' не найден в модуле-источнике: %s" % (method_name, src_bsl)) + + # --- Guard: functions cannot use Before/After --- + if method["is_function"] and interceptor_type in ("Before", "After"): + die("Метод '%s' — функция. Для функций доступны только Instead и ModificationAndControl " + "(перехват &Перед/&После к функциям неприменим)." % method_name) + + decorator_ru = DECORATOR_MAP[interceptor_type] + + # --- Read existing extension module (if any) --- + ext_exists = os.path.isfile(ext_bsl) + ext_lines = read_lines(ext_bsl) if ext_exists else [] + + existing_interceptors = get_interceptors(ext_lines) if ext_exists else [] + existing_proc_names = get_proc_names(ext_lines) if ext_exists else [] + + dup = None + for ic in existing_interceptors: + if ic["type"] == decorator_ru and ic["method"].lower() == method_name.lower(): + dup = ic + break + + if dup: + if interceptor_type != "ModificationAndControl": + print('[ПРОПУЩЕН] Перехватчик &%s("%s") уже есть в модуле — дубль не создаётся.' + % (decorator_ru, method_name)) + print(" Файл: %s" % ext_bsl) + sys.exit(0) + resync(ext_bsl, ext_lines, dup, method, method_name, module_path) + sys.exit(0) + + # --- New interceptor --- + candidate = name_prefix + method["canonical"] + taken = [n.lower() for n in existing_proc_names] + interceptor_name = candidate + if candidate.lower() in taken: + if interceptor_type == "ModificationAndControl": + interceptor_name = candidate + "_ИзменениеИКонтроль" + else: + interceptor_name = candidate + "_" + decorator_ru + + core = build_interceptor_core(method, interceptor_type, interceptor_name) + + place_new(ext_bsl, ext_lines, ext_exists, method["chain"], core) + + # emit summary + placement = place_new.placement + print('[OK] Перехватчик &%s("%s") — %s' % (decorator_ru, method_name, placement)) + print(" Файл: %s" % ext_bsl) + print(" Процедура: %s(%s)" % (interceptor_name, normalize(method["params_text"]))) + if method["context"]: + print(" Контекст: %s" % method["context"]) + if method["chain"]: + desc = " > ".join( + ("Область:%s" % w["name"]) if w["kind"] == "region" else ("Если:%s" % w["cond"]) + for w in method["chain"] ) + print(" Обрамление: %s" % desc) - if not os.path.isfile(form_meta_file) or not os.path.isfile(form_xml_file): - print(f"[WARN] Form '{form_name}' metadata or Form.xml not found in extension.") - print(" Run /cfe-borrow first:") - print( - f" /cfe-borrow -ExtensionPath {extension_path} " - f'-ConfigPath -Object "{obj_type}.{obj_name}.Form.{form_name}"' - ) - print() - # --- Check if file exists and append --- - bsl_dir = os.path.dirname(bsl_file) +def place_new(ext_bsl, ext_lines, ext_exists, chain, core): + enc_bom = True # noqa + + # find innermost region in chain that already exists in the extension module + reuse_region_idx = -1 + reuse_line_idx = -1 + if ext_exists: + for c in range(len(chain) - 1, -1, -1): + if chain[c]["kind"] == "region": + rname = chain[c]["name"] + rre = re.compile(r'^#Область\s+' + re.escape(rname) + r'\s*$') + for li in range(len(ext_lines)): + if rre.match(ext_lines[li].strip()): + reuse_region_idx = c + reuse_line_idx = li + break + if reuse_region_idx >= 0: + break + + if reuse_region_idx >= 0: + inner_chain = chain[reuse_region_idx + 1:] + block = build_wrapped_block(inner_chain, core) + + depth = 0 + close_idx = -1 + for li in range(reuse_line_idx, len(ext_lines)): + t = ext_lines[li].strip() + if re.match(r'^#Область\s', t): + depth += 1 + elif re.match(r'^#КонецОбласти', t): + depth -= 1 + if depth == 0: + close_idx = li + break + if close_idx < 0: + die("Не найден #КонецОбласти для региона (переиспользование)") + + # strip trailing blank lines of the region content, then insert with air + last_content = close_idx - 1 + while last_content >= 0 and ext_lines[last_content].strip() == "": + last_content -= 1 + out = list(ext_lines[:last_content + 1]) + out.append("") + out.extend(block) + out.append("") + out.extend(ext_lines[close_idx:]) + write_bsl(ext_bsl, out) + place_new.placement = "в существующий регион '%s'" % chain[reuse_region_idx]["name"] + return + + # full wrapper chain, append (or create) + block = build_wrapped_block(chain, core) + block_text = "\r\n".join(block) + "\r\n" + + bsl_dir = os.path.dirname(ext_bsl) if not os.path.isdir(bsl_dir): os.makedirs(bsl_dir, exist_ok=True) - if os.path.isfile(bsl_file): - # Append to existing file - with open(bsl_file, "r", encoding="utf-8-sig", newline="") as f: + if ext_exists: + with open(ext_bsl, "r", encoding="utf-8-sig", newline="") as f: existing = f.read() - - separator = "\r\n" - if existing and not existing.endswith("\n"): - separator = "\r\n\r\n" - new_content = existing + separator + bsl_text - - with open(bsl_file, "w", encoding="utf-8-sig", newline="") as f: - f.write(new_content) - print("[OK] \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0447\u0438\u043a \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0444\u0430\u0439\u043b") # Добавлен перехватчик в существующий файл + if not existing.strip(): + with open(ext_bsl, "w", encoding="utf-8-sig", newline="") as f: + f.write(block_text) + place_new.placement = "заполнен модуль" + else: + sep = "\r\n" if existing.endswith("\n") else "\r\n\r\n" + with open(ext_bsl, "w", encoding="utf-8-sig", newline="") as f: + f.write(existing + sep + block_text) + place_new.placement = "дописан в модуль" else: - with open(bsl_file, "w", encoding="utf-8-sig", newline="") as f: - f.write(bsl_text) - print("[OK] \u0421\u043e\u0437\u0434\u0430\u043d \u0444\u0430\u0439\u043b \u043c\u043e\u0434\u0443\u043b\u044f") # Создан файл модуля + with open(ext_bsl, "w", encoding="utf-8-sig", newline="") as f: + f.write(block_text) + place_new.placement = "создан модуль" - print(f" \u0424\u0430\u0439\u043b: {bsl_file}") # Файл: - print(f' \u0414\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440: {decorator}("{method_name}")') # Декоратор: - print(f" \u041f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0430: {proc_name}()") # Процедура: - print(f" \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442: {context_annotation}") # Контекст: + +def resync(ext_bsl, ext_lines, dup, method, method_name, module_path): + dec_line = dup["line"] + sig_line_idx = dec_line + 1 + name_re = re.compile(r'^\s*(?:Асинх\s+)?(?:Процедура|Функция)\s+([\w]+)\s*\(', re.IGNORECASE) + if sig_line_idx >= len(ext_lines) or not name_re.match(ext_lines[sig_line_idx]): + die('Не удалось найти сигнатуру существующего перехватчика &ИзменениеИКонтроль("%s")' % method_name) + existing_name = name_re.match(ext_lines[sig_line_idx]).group(1) + sig = read_signature(ext_lines, sig_line_idx) + if not sig: + die("Не удалось разобрать сигнатуру существующего перехватчика") + _params, sig_end = sig + is_func = bool(re.match(r'^\s*(?:Асинх\s+)?Функция\b', ext_lines[sig_line_idx], re.IGNORECASE)) + end_re = re.compile(r'^\s*КонецФункции\b' if is_func else r'^\s*КонецПроцедуры\b', re.IGNORECASE) + block_end = -1 + for j in range(sig_end + 1, len(ext_lines)): + if end_re.match(ext_lines[j]): + block_end = j + break + if block_end < 0: + die("Не найден конец существующего перехватчика") + + marked_body = ext_lines[sig_end + 1:block_end] + parsed = parse_marked_body(marked_body) + v1 = parsed["v1"] + ops = parsed["ops"] + v2 = method["body_lines"] + + v1norm = [normalize(x) for x in v1] + v2norm = [normalize(x) for x in v2] + + if "\n".join(v1norm) == "\n".join(v2norm): + print('[АКТУАЛЕН] &ИзменениеИКонтроль("%s") — оригинал не менялся, изменений нет.' % method_name) + print(" Файл: %s" % ext_bsl) + return + + insert_top = [] + insert_after = {} + del_start = set() + del_end = set() + disputed = [] + + for op in ops: + if op["kind"] == "insert": + if op["after"] < 0: + insert_top.append(op["lines"]) + continue + k = find_unique_index(v2norm, v1norm[op["after"]]) + if k >= 0: + insert_after.setdefault(k, []).append(op["lines"]) + else: + disputed.append({"kind": "insert", "lines": op["lines"]}) + else: + keys = v1norm[op["start"]:op["end"] + 1] + p = find_unique_run(v2norm, keys) + if p >= 0: + del_start.add(p) + del_end.add(p + len(keys) - 1) + else: + disputed.append({"kind": "delete", "lines": op["lines"]}) + + new_body = [] + for blk in insert_top: + new_body.append("#Вставка") + new_body.extend(blk) + new_body.append("#КонецВставки") + for k in range(len(v2)): + if k in del_start: + new_body.append("#Удаление") + new_body.append(v2[k]) + if k in del_end: + new_body.append("#КонецУдаления") + if k in insert_after: + for blk in insert_after[k]: + new_body.append("#Вставка") + new_body.extend(blk) + new_body.append("#КонецВставки") + + if disputed: + new_body.append("\t// [РЕСИНК-КОНФЛИКТ] перенесите блоки ниже вручную — исходный якорь изменился в новой версии оригинала.") + new_body.append("\t// Материалы для анализа см. в выводе команды (файлы v1/v2/current/diff).") + for d in disputed: + if d["kind"] == "insert": + new_body.append("#Вставка") + new_body.extend(d["lines"]) + new_body.append("#КонецВставки") + else: + new_body.append("\t// [РЕСИНК-КОНФЛИКТ] не удалось найти для удаления:") + for l in d["lines"]: + new_body.append("\t// " + l.strip()) + + async_prefix = "Асинх " if method["is_async"] else "" + keyword = "Функция" if method["is_function"] else "Процедура" + end_keyword = "КонецФункции" if method["is_function"] else "КонецПроцедуры" + new_block = [] + if method["context"]: + new_block.append(method["context"]) + new_block.append('&ИзменениеИКонтроль("%s")' % method["canonical"]) + new_block.append("%s%s %s(%s)" % (async_prefix, keyword, existing_name, method["params_text"])) + new_block.extend(new_body) + new_block.append(end_keyword) + + block_start = dec_line + if dec_line >= 1 and is_context_directive(ext_lines[dec_line - 1].strip()): + block_start = dec_line - 1 + + out = list(ext_lines[:block_start]) + out.extend(new_block) + out.extend(ext_lines[block_end + 1:]) + write_bsl(ext_bsl, out) + + if disputed: + safe = re.sub(r'[\\/:*?"<>|]', '_', module_path) + tmp_root = os.path.join(tempfile.gettempdir(), "cfe-resync", safe + "." + method_name) + os.makedirs(tmp_root, exist_ok=True) + write_bsl(os.path.join(tmp_root, "v1.bsl"), v1) + write_bsl(os.path.join(tmp_root, "v2.bsl"), v2) + write_bsl(os.path.join(tmp_root, "current.bsl"), marked_body) + diff = ["--- v1 (что было скопировано) vs v2 (новый оригинал) ---"] + for l in v1: + if normalize(l) not in v2norm: + diff.append("- " + l) + for l in v2: + if normalize(l) not in v1norm: + diff.append("+ " + l) + write_bsl(os.path.join(tmp_root, "diff.txt"), diff) + + print('[АКТУАЛИЗИРОВАН-ЧАСТИЧНО] &ИзменениеИКонтроль("%s")' % method_name) + print(" Перенесено автоматически, конфликтов: %d (помечены // [РЕСИНК-КОНФЛИКТ])" % len(disputed)) + print(" Файлы-версии для анализа:") + print(" %s" % tmp_root) + print(" Проверьте конфликтные блоки и разместите их вручную.") + else: + print('[АКТУАЛИЗИРОВАН] &ИзменениеИКонтроль("%s") — тело обновлено по новому оригиналу, правки перенесены.' % method_name) + print(" Файл: %s" % ext_bsl) if __name__ == "__main__": diff --git a/tests/skills/cases/cfe-patch-method/_skill.json b/tests/skills/cases/cfe-patch-method/_skill.json index 98011d54..ce1f02b9 100644 --- a/tests/skills/cases/cfe-patch-method/_skill.json +++ b/tests/skills/cases/cfe-patch-method/_skill.json @@ -3,6 +3,7 @@ "setup": "empty-config", "args": [ { "flag": "-ExtensionPath", "from": "workPath", "field": "extensionPath" }, + { "flag": "-ConfigPath", "from": "workDir" }, { "flag": "-ModulePath", "from": "case.modulePath" }, { "flag": "-MethodName", "from": "case.methodName" }, { "flag": "-InterceptorType", "from": "case.interceptorType" } diff --git a/tests/skills/cases/cfe-patch-method/after-handler.json b/tests/skills/cases/cfe-patch-method/after-handler.json index e58897d5..5c34f9c2 100644 --- a/tests/skills/cases/cfe-patch-method/after-handler.json +++ b/tests/skills/cases/cfe-patch-method/after-handler.json @@ -6,6 +6,12 @@ "input": { "type": "Catalog", "name": "Товары" }, "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } }, + { + "writeFile": { + "path": "Catalogs/Товары/Ext/ObjectModule.bsl", + "content": "#Область ОбработчикиСобытий\n\nПроцедура ПриЗаписи(Отказ)\n\tЕсли Отказ Тогда\n\t\tВозврат;\n\tКонецЕсли;\nКонецПроцедуры\n\n#КонецОбласти\n" + } + }, { "script": "cfe-init/scripts/cfe-init", "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } @@ -20,5 +26,6 @@ "modulePath": "Catalog.Товары.ObjectModule", "methodName": "ПриЗаписи", "interceptorType": "After" - } + }, + "expect": { "stdoutContains": "&После(\"ПриЗаписи\")" } } diff --git a/tests/skills/cases/cfe-patch-method/before-handler.json b/tests/skills/cases/cfe-patch-method/before-handler.json index adbbb6ad..b69e31a2 100644 --- a/tests/skills/cases/cfe-patch-method/before-handler.json +++ b/tests/skills/cases/cfe-patch-method/before-handler.json @@ -6,6 +6,12 @@ "input": { "type": "Catalog", "name": "Товары" }, "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } }, + { + "writeFile": { + "path": "Catalogs/Товары/Ext/ObjectModule.bsl", + "content": "#Область ОбработчикиСобытий\n\nПроцедура ПриЗаписи(Отказ)\n\tЕсли Отказ Тогда\n\t\tВозврат;\n\tКонецЕсли;\nКонецПроцедуры\n\n#КонецОбласти\n" + } + }, { "script": "cfe-init/scripts/cfe-init", "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } @@ -20,5 +26,6 @@ "modulePath": "Catalog.Товары.ObjectModule", "methodName": "ПриЗаписи", "interceptorType": "Before" - } + }, + "expect": { "stdoutContains": "&Перед(\"ПриЗаписи\")" } } diff --git a/tests/skills/cases/cfe-patch-method/document-manager.json b/tests/skills/cases/cfe-patch-method/document-manager.json index 7542c86d..8a31279a 100644 --- a/tests/skills/cases/cfe-patch-method/document-manager.json +++ b/tests/skills/cases/cfe-patch-method/document-manager.json @@ -6,6 +6,12 @@ "input": { "type": "Document", "name": "ПриходТоваров" }, "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } }, + { + "writeFile": { + "path": "Documents/ПриходТоваров/Ext/ManagerModule.bsl", + "content": "#Область ОбработчикиСобытий\n\nПроцедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)\n\tСтандартнаяОбработка = Ложь;\nКонецПроцедуры\n\n#КонецОбласти\n" + } + }, { "script": "cfe-init/scripts/cfe-init", "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } @@ -20,5 +26,6 @@ "modulePath": "Document.ПриходТоваров.ManagerModule", "methodName": "ОбработкаПолученияДанныхВыбора", "interceptorType": "Before" - } + }, + "expect": { "stdoutContains": "ОбработкаПолученияДанныхВыбора" } } diff --git a/tests/skills/cases/cfe-patch-method/filepath-mode.json b/tests/skills/cases/cfe-patch-method/filepath-mode.json new file mode 100644 index 00000000..d9d65069 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/filepath-mode.json @@ -0,0 +1,31 @@ +{ + "name": "ModulePath как путь к файлу модуля-источника", + "preRun": [ + { + "script": "meta-compile/scripts/meta-compile", + "input": { "type": "CommonModule", "name": "ФПМодуль", "properties": { "Server": true } }, + "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } + }, + { + "writeFile": { + "path": "CommonModules/ФПМодуль/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n\nПроцедура ОбработатьДанные(Данные) Экспорт\n\tДанные.Очистить();\nКонецПроцедуры\n\n#КонецОбласти\n" + } + }, + { + "script": "cfe-init/scripts/cfe-init", + "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } + }, + { + "script": "cfe-borrow/scripts/cfe-borrow", + "args": { "-ExtensionPath": "{workDir}/ext", "-ConfigPath": "{workDir}", "-Object": "CommonModule.ФПМодуль" } + } + ], + "params": { + "extensionPath": "ext", + "modulePath": "CommonModules/ФПМодуль/Ext/Module.bsl", + "methodName": "ОбработатьДанные", + "interceptorType": "Before" + }, + "expect": { "stdoutContains": "&Перед(\"ОбработатьДанные\")" } +} diff --git a/tests/skills/cases/cfe-patch-method/form-handler.json b/tests/skills/cases/cfe-patch-method/form-handler.json new file mode 100644 index 00000000..2aa2c410 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/form-handler.json @@ -0,0 +1,44 @@ +{ + "name": "Перехватчик После для метода формы (директива контекста &НаКлиенте)", + "preRun": [ + { + "script": "meta-compile/scripts/meta-compile", + "input": { "type": "Catalog", "name": "Товары", "attributes": [ { "name": "Артикул", "type": "String", "length": 25 } ] }, + "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } + }, + { + "script": "form-add/scripts/form-add", + "args": { "-ObjectPath": "{workDir}/Catalogs/Товары.xml", "-FormName": "ФормаЭлемента" } + }, + { + "script": "form-compile/scripts/form-compile", + "input": { + "title": "Тест", + "elements": [ { "input": "Артикул", "path": "Объект.Артикул" } ], + "attributes": [ { "name": "Объект", "type": "CatalogObject.Товары", "main": true } ] + }, + "args": { "-JsonPath": "{inputFile}", "-OutputPath": "{workDir}/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form.xml" } + }, + { + "writeFile": { + "path": "Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form/Module.bsl", + "content": "#Область ОбработчикиСобытийФормы\n\n&НаКлиенте\nПроцедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)\n\tОповеститьОбИзменении(Источник);\nКонецПроцедуры\n\n#КонецОбласти\n" + } + }, + { + "script": "cfe-init/scripts/cfe-init", + "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } + }, + { + "script": "cfe-borrow/scripts/cfe-borrow", + "args": { "-ExtensionPath": "{workDir}/ext", "-ConfigPath": "{workDir}", "-Object": "Catalog.Товары.Form.ФормаЭлемента" } + } + ], + "params": { + "extensionPath": "ext", + "modulePath": "Catalog.Товары.Form.ФормаЭлемента", + "methodName": "ОбработкаОповещения", + "interceptorType": "After" + }, + "expect": { "stdoutContains": "Контекст: &НаКлиенте" } +} diff --git a/tests/skills/cases/cfe-patch-method/guard-function.json b/tests/skills/cases/cfe-patch-method/guard-function.json new file mode 100644 index 00000000..680cc2d9 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/guard-function.json @@ -0,0 +1,31 @@ +{ + "name": "Гвард: Перед/После для функции недоступны", + "preRun": [ + { + "script": "meta-compile/scripts/meta-compile", + "input": { "type": "CommonModule", "name": "ОбщийМодуль3", "properties": { "Server": true } }, + "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } + }, + { + "writeFile": { + "path": "CommonModules/ОбщийМодуль3/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n\nФункция Вычислить(А) Экспорт\n\tВозврат А * 2;\nКонецФункции\n\n#КонецОбласти\n" + } + }, + { + "script": "cfe-init/scripts/cfe-init", + "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } + }, + { + "script": "cfe-borrow/scripts/cfe-borrow", + "args": { "-ExtensionPath": "{workDir}/ext", "-ConfigPath": "{workDir}", "-Object": "CommonModule.ОбщийМодуль3" } + } + ], + "params": { + "extensionPath": "ext", + "modulePath": "CommonModule.ОбщийМодуль3", + "methodName": "Вычислить", + "interceptorType": "After" + }, + "expectError": "функция" +} diff --git a/tests/skills/cases/cfe-patch-method/function-handler.json b/tests/skills/cases/cfe-patch-method/instead-function.json similarity index 55% rename from tests/skills/cases/cfe-patch-method/function-handler.json rename to tests/skills/cases/cfe-patch-method/instead-function.json index 3f76511a..4f639787 100644 --- a/tests/skills/cases/cfe-patch-method/function-handler.json +++ b/tests/skills/cases/cfe-patch-method/instead-function.json @@ -1,11 +1,17 @@ { - "name": "Перехватчик После для функции", + "name": "Перехватчик Вместо для функции (ПродолжитьВызов)", "preRun": [ { "script": "meta-compile/scripts/meta-compile", "input": { "type": "CommonModule", "name": "ОбщийМодуль2", "properties": { "Server": true } }, "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } }, + { + "writeFile": { + "path": "CommonModules/ОбщийМодуль2/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n\nФункция ПолучитьЗначение(Ключ, ПоУмолчанию = Неопределено) Экспорт\n\tВозврат Ключ;\nКонецФункции\n\n#КонецОбласти\n" + } + }, { "script": "cfe-init/scripts/cfe-init", "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } @@ -19,7 +25,7 @@ "extensionPath": "ext", "modulePath": "CommonModule.ОбщийМодуль2", "methodName": "ПолучитьЗначение", - "interceptorType": "After" + "interceptorType": "Instead" }, - "args_extra": ["-IsFunction"] + "expect": { "stdoutContains": "&Вместо(\"ПолучитьЗначение\")" } } diff --git a/tests/skills/cases/cfe-patch-method/mod-and-control.json b/tests/skills/cases/cfe-patch-method/mod-and-control.json index 59cdd0db..d9f09a54 100644 --- a/tests/skills/cases/cfe-patch-method/mod-and-control.json +++ b/tests/skills/cases/cfe-patch-method/mod-and-control.json @@ -6,6 +6,12 @@ "input": { "type": "CommonModule", "name": "ОбщийМодуль1", "properties": { "Server": true } }, "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } }, + { + "writeFile": { + "path": "CommonModules/ОбщийМодуль1/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n\nФункция ПолучитьДанные(Параметр) Экспорт\n\tРезультат = Новый Массив;\n\tРезультат.Добавить(Параметр);\n\tВозврат Результат;\nКонецФункции\n\n#КонецОбласти\n" + } + }, { "script": "cfe-init/scripts/cfe-init", "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } @@ -20,5 +26,6 @@ "modulePath": "CommonModule.ОбщийМодуль1", "methodName": "ПолучитьДанные", "interceptorType": "ModificationAndControl" - } + }, + "expect": { "stdoutContains": "&ИзменениеИКонтроль(\"ПолучитьДанные\")" } } diff --git a/tests/skills/cases/cfe-patch-method/preproc-wrap.json b/tests/skills/cases/cfe-patch-method/preproc-wrap.json new file mode 100644 index 00000000..e8242e6b --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/preproc-wrap.json @@ -0,0 +1,31 @@ +{ + "name": "Наследование обрамляющего #Если (препроцессор снаружи региона)", + "preRun": [ + { + "script": "meta-compile/scripts/meta-compile", + "input": { "type": "Document", "name": "РасходТоваров" }, + "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } + }, + { + "writeFile": { + "path": "Documents/РасходТоваров/Ext/ObjectModule.bsl", + "content": "#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда\n\n#Область ОбработчикиСобытий\n\nПроцедура ОбработкаПроведения(Отказ, РежимПроведения)\n\tДвижения.Записывать = Истина;\nКонецПроцедуры\n\n#КонецОбласти\n\n#КонецЕсли\n" + } + }, + { + "script": "cfe-init/scripts/cfe-init", + "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } + }, + { + "script": "cfe-borrow/scripts/cfe-borrow", + "args": { "-ExtensionPath": "{workDir}/ext", "-ConfigPath": "{workDir}", "-Object": "Document.РасходТоваров" } + } + ], + "params": { + "extensionPath": "ext", + "modulePath": "Document.РасходТоваров.ObjectModule", + "methodName": "ОбработкаПроведения", + "interceptorType": "Before" + }, + "expect": { "stdoutContains": "Если:Сервер" } +} diff --git a/tests/skills/cases/cfe-patch-method/region-reuse.json b/tests/skills/cases/cfe-patch-method/region-reuse.json new file mode 100644 index 00000000..ae54a14c --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/region-reuse.json @@ -0,0 +1,37 @@ +{ + "name": "Вставка в существующий регион с воздухом между методами", + "preRun": [ + { + "script": "meta-compile/scripts/meta-compile", + "input": { "type": "CommonModule", "name": "РеюзМод", "properties": { "Server": true } }, + "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } + }, + { + "writeFile": { + "path": "CommonModules/РеюзМод/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n\nПроцедура МетодБ(Х) Экспорт\n\tСообщить(Х);\nКонецПроцедуры\n\n#КонецОбласти\n" + } + }, + { + "script": "cfe-init/scripts/cfe-init", + "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } + }, + { + "script": "cfe-borrow/scripts/cfe-borrow", + "args": { "-ExtensionPath": "{workDir}/ext", "-ConfigPath": "{workDir}", "-Object": "CommonModule.РеюзМод" } + }, + { + "writeFile": { + "path": "ext/CommonModules/РеюзМод/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n\n&Перед(\"МетодА\")\nПроцедура Тест_МетодА(П)\n\t// уже есть\nКонецПроцедуры\n\n#КонецОбласти\n" + } + } + ], + "params": { + "extensionPath": "ext", + "modulePath": "CommonModule.РеюзМод", + "methodName": "МетодБ", + "interceptorType": "Before" + }, + "expect": { "stdoutContains": "в существующий регион" } +} diff --git a/tests/skills/cases/cfe-patch-method/resync-conflict.json b/tests/skills/cases/cfe-patch-method/resync-conflict.json new file mode 100644 index 00000000..8ca4cd52 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/resync-conflict.json @@ -0,0 +1,37 @@ +{ + "name": "Ресинк ИзменениеИКонтроль: изменился якорь вставки (конфликт)", + "preRun": [ + { + "script": "meta-compile/scripts/meta-compile", + "input": { "type": "CommonModule", "name": "РесинкКонфл", "properties": { "Server": true } }, + "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } + }, + { + "writeFile": { + "path": "CommonModules/РесинкКонфл/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n\nФункция Расчёт(А, Б) Экспорт\n\tИтог = 0.00;\n\tИтог = А + Б;\n\tИтог = ОкруглитьВверх(Итог);\n\tВозврат Итог;\nКонецФункции\n\n#КонецОбласти\n" + } + }, + { + "script": "cfe-init/scripts/cfe-init", + "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } + }, + { + "script": "cfe-borrow/scripts/cfe-borrow", + "args": { "-ExtensionPath": "{workDir}/ext", "-ConfigPath": "{workDir}", "-Object": "CommonModule.РесинкКонфл" } + }, + { + "writeFile": { + "path": "ext/CommonModules/РесинкКонфл/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n&ИзменениеИКонтроль(\"Расчёт\")\nФункция Тест_Расчёт(А, Б)\n\tИтог = 0;\n#Вставка\n\tИтог = 999;\n#КонецВставки\n\tИтог = А + Б;\n\tВозврат Итог;\nКонецФункции\n#КонецОбласти\n" + } + } + ], + "params": { + "extensionPath": "ext", + "modulePath": "CommonModule.РесинкКонфл", + "methodName": "Расчёт", + "interceptorType": "ModificationAndControl" + }, + "expect": { "stdoutContains": "[АКТУАЛИЗИРОВАН-ЧАСТИЧНО]" } +} diff --git a/tests/skills/cases/cfe-patch-method/resync-noop.json b/tests/skills/cases/cfe-patch-method/resync-noop.json new file mode 100644 index 00000000..c7c80e67 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/resync-noop.json @@ -0,0 +1,38 @@ +{ + "name": "Ресинк ИзменениеИКонтроль: оригинал не менялся (no-op, идемпотентно)", + "preRun": [ + { + "script": "meta-compile/scripts/meta-compile", + "input": { "type": "CommonModule", "name": "РесинкМод", "properties": { "Server": true } }, + "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } + }, + { + "writeFile": { + "path": "CommonModules/РесинкМод/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n\nФункция Расчёт(А, Б) Экспорт\n\tИтог = 0;\n\tИтог = А + Б;\n\tВозврат Итог;\nКонецФункции\n\n#КонецОбласти\n" + } + }, + { + "script": "cfe-init/scripts/cfe-init", + "args": { "-Name": "Тест", "-OutputDir": "{workDir}/ext", "-ConfigPath": "{workDir}" } + }, + { + "script": "cfe-borrow/scripts/cfe-borrow", + "args": { "-ExtensionPath": "{workDir}/ext", "-ConfigPath": "{workDir}", "-Object": "CommonModule.РесинкМод" } + }, + { + "writeFile": { + "path": "ext/CommonModules/РесинкМод/Ext/Module.bsl", + "content": "#Область ПрограммныйИнтерфейс\n&ИзменениеИКонтроль(\"Расчёт\")\nФункция Тест_Расчёт(А, Б)\n\tИтог = 0;\n#Вставка\n\tИтог = 100;\n#КонецВставки\n\tИтог = А + Б;\n\tВозврат Итог;\nКонецФункции\n#КонецОбласти\n" + } + } + ], + "params": { + "extensionPath": "ext", + "modulePath": "CommonModule.РесинкМод", + "methodName": "Расчёт", + "interceptorType": "ModificationAndControl" + }, + "expect": { "stdoutContains": "[АКТУАЛЕН]" }, + "idempotent": true +} diff --git a/tests/skills/cases/cfe-patch-method/snapshots/after-handler/Catalogs/Товары/Ext/ObjectModule.bsl b/tests/skills/cases/cfe-patch-method/snapshots/after-handler/Catalogs/Товары/Ext/ObjectModule.bsl index e69de29b..a59f74b2 100644 --- a/tests/skills/cases/cfe-patch-method/snapshots/after-handler/Catalogs/Товары/Ext/ObjectModule.bsl +++ b/tests/skills/cases/cfe-patch-method/snapshots/after-handler/Catalogs/Товары/Ext/ObjectModule.bsl @@ -0,0 +1,9 @@ +#Область ОбработчикиСобытий + +Процедура ПриЗаписи(Отказ) + Если Отказ Тогда + Возврат; + КонецЕсли; +КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/after-handler/ext/Catalogs/Товары/Ext/ObjectModule.bsl b/tests/skills/cases/cfe-patch-method/snapshots/after-handler/ext/Catalogs/Товары/Ext/ObjectModule.bsl index bd702ffb..d7710fbe 100644 --- a/tests/skills/cases/cfe-patch-method/snapshots/after-handler/ext/Catalogs/Товары/Ext/ObjectModule.bsl +++ b/tests/skills/cases/cfe-patch-method/snapshots/after-handler/ext/Catalogs/Товары/Ext/ObjectModule.bsl @@ -1,5 +1,8 @@ -&НаСервере +#Область ОбработчикиСобытий + &После("ПриЗаписи") -Процедура Тест_ПриЗаписи() +Процедура Тест_ПриЗаписи(Отказ) // TODO: код после вызова оригинального метода КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/before-handler/Catalogs/Товары/Ext/ObjectModule.bsl b/tests/skills/cases/cfe-patch-method/snapshots/before-handler/Catalogs/Товары/Ext/ObjectModule.bsl index e69de29b..a59f74b2 100644 --- a/tests/skills/cases/cfe-patch-method/snapshots/before-handler/Catalogs/Товары/Ext/ObjectModule.bsl +++ b/tests/skills/cases/cfe-patch-method/snapshots/before-handler/Catalogs/Товары/Ext/ObjectModule.bsl @@ -0,0 +1,9 @@ +#Область ОбработчикиСобытий + +Процедура ПриЗаписи(Отказ) + Если Отказ Тогда + Возврат; + КонецЕсли; +КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/before-handler/ext/Catalogs/Товары/Ext/ObjectModule.bsl b/tests/skills/cases/cfe-patch-method/snapshots/before-handler/ext/Catalogs/Товары/Ext/ObjectModule.bsl index 08320fcf..ecaa7dc3 100644 --- a/tests/skills/cases/cfe-patch-method/snapshots/before-handler/ext/Catalogs/Товары/Ext/ObjectModule.bsl +++ b/tests/skills/cases/cfe-patch-method/snapshots/before-handler/ext/Catalogs/Товары/Ext/ObjectModule.bsl @@ -1,5 +1,8 @@ -&НаСервере +#Область ОбработчикиСобытий + &Перед("ПриЗаписи") -Процедура Тест_ПриЗаписи() +Процедура Тест_ПриЗаписи(Отказ) // TODO: код перед вызовом оригинального метода КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/document-manager/Documents/ПриходТоваров/Ext/ManagerModule.bsl b/tests/skills/cases/cfe-patch-method/snapshots/document-manager/Documents/ПриходТоваров/Ext/ManagerModule.bsl new file mode 100644 index 00000000..69ffbfd4 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/document-manager/Documents/ПриходТоваров/Ext/ManagerModule.bsl @@ -0,0 +1,7 @@ +#Область ОбработчикиСобытий + +Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка) + СтандартнаяОбработка = Ложь; +КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/document-manager/ext/Documents/ПриходТоваров/Ext/ManagerModule.bsl b/tests/skills/cases/cfe-patch-method/snapshots/document-manager/ext/Documents/ПриходТоваров/Ext/ManagerModule.bsl index 64313479..ac14b1d6 100644 --- a/tests/skills/cases/cfe-patch-method/snapshots/document-manager/ext/Documents/ПриходТоваров/Ext/ManagerModule.bsl +++ b/tests/skills/cases/cfe-patch-method/snapshots/document-manager/ext/Documents/ПриходТоваров/Ext/ManagerModule.bsl @@ -1,5 +1,8 @@ -&НаСервере +#Область ОбработчикиСобытий + &Перед("ОбработкаПолученияДанныхВыбора") -Процедура Тест_ОбработкаПолученияДанныхВыбора() +Процедура Тест_ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка) // TODO: код перед вызовом оригинального метода КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/CommonModules/ФПМодуль.xml b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/CommonModules/ФПМодуль.xml new file mode 100644 index 00000000..dd34953d --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/CommonModules/ФПМодуль.xml @@ -0,0 +1,23 @@ + + + + + ФПМодуль + + + ru + Фпмодуль + + + + false + false + false + false + false + false + false + DontUse + + + diff --git a/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/CommonModules/ФПМодуль/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/CommonModules/ФПМодуль/Ext/Module.bsl new file mode 100644 index 00000000..acd2b587 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/CommonModules/ФПМодуль/Ext/Module.bsl @@ -0,0 +1,7 @@ +#Область ПрограммныйИнтерфейс + +Процедура ОбработатьДанные(Данные) Экспорт + Данные.Очистить(); +КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Configuration.xml new file mode 100644 index 00000000..bc76ad22 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + 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/cfe-patch-method/snapshots/function-handler/ext/ClientApplicationInterface.xml b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/ClientApplicationInterface.xml similarity index 100% rename from tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/ClientApplicationInterface.xml rename to tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/ClientApplicationInterface.xml diff --git a/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/CommonModules/ФПМодуль.xml b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/CommonModules/ФПМодуль.xml new file mode 100644 index 00000000..11b4b311 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/CommonModules/ФПМодуль.xml @@ -0,0 +1,18 @@ + + + + + + Adopted + ФПМодуль + + UUID-002 + false + false + false + false + false + false + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/CommonModules/ФПМодуль/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/CommonModules/ФПМодуль/Ext/Module.bsl new file mode 100644 index 00000000..ab3080b0 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/CommonModules/ФПМодуль/Ext/Module.bsl @@ -0,0 +1,8 @@ +#Область ПрограммныйИнтерфейс + +&Перед("ОбработатьДанные") +Процедура Тест_ОбработатьДанные(Данные) + // TODO: код перед вызовом оригинального метода +КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/Configuration.xml new file mode 100644 index 00000000..a314da7b --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/Configuration.xml @@ -0,0 +1,72 @@ + + + + + + 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 + + + + Adopted + Тест + + + ru + Тест + + + + Customization + true + Тест_ + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + Role.Тест_ОсновнаяРоль + + + + Language.Русский + + + + + + TaxiEnableVersion8_2 + + + Русский + Тест_ОсновнаяРоль + ФПМодуль + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/Languages/Русский.xml similarity index 100% rename from tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/Languages/Русский.xml rename to tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/Languages/Русский.xml diff --git a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/Roles/Тест_ОсновнаяРоль.xml b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/Roles/Тест_ОсновнаяРоль.xml similarity index 100% rename from tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/Roles/Тест_ОсновнаяРоль.xml rename to tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Ext/Roles/Тест_ОсновнаяРоль.xml diff --git a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Languages/Русский.xml similarity index 100% rename from tests/skills/cases/cfe-patch-method/snapshots/function-handler/Languages/Русский.xml rename to tests/skills/cases/cfe-patch-method/snapshots/filepath-mode/Languages/Русский.xml diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары.xml new file mode 100644 index 00000000..912f60af --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/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 + Catalog.Товары.Form.ФормаЭлемента + + + + + + + + + + false + + + Managed + Use + + + + + + Use + Auto + DontUse + false + false + + + + + Артикул + + + ru + Артикул + + + + + xs:string + + 25 + Variable + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + ForItem + DontIndex + Use + Use + + +
ФормаЭлемента
+
+
+
diff --git a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/CommonModules/ОбщийМодуль2/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Ext/ObjectModule.bsl similarity index 100% rename from tests/skills/cases/cfe-patch-method/snapshots/function-handler/CommonModules/ОбщийМодуль2/Ext/Module.bsl rename to tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Ext/ObjectModule.bsl diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Forms/ФормаЭлемента.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Forms/ФормаЭлемента.xml new file mode 100644 index 00000000..e64cb98b --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Forms/ФормаЭлемента.xml @@ -0,0 +1,21 @@ + + +
+ + ФормаЭлемента + + + ru + ФормаЭлемента + + + + Managed + false + + PlatformApplication + MobilePlatformApplication + + +
+
\ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form.xml new file mode 100644 index 00000000..a03d6d82 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form.xml @@ -0,0 +1,27 @@ + +
+ + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Тест</v8:content> + </v8:item> + + false + + + + Объект.Артикул + + + + + + + + cfg:CatalogObject.Товары + + true + true + + + diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form/Module.bsl new file mode 100644 index 00000000..8056f820 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form/Module.bsl @@ -0,0 +1,8 @@ +#Область ОбработчикиСобытийФормы + +&НаКлиенте +Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник) + ОповеститьОбИзменении(Источник); +КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Configuration.xml new file mode 100644 index 00000000..5405b1b5 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + 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/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары.xml new file mode 100644 index 00000000..88608a09 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары.xml @@ -0,0 +1,36 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + + Adopted + Товары + + UUID-012 + + +
ФормаЭлемента
+
+
+
\ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары/Forms/ФормаЭлемента.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары/Forms/ФормаЭлемента.xml new file mode 100644 index 00000000..4e3c364d --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары/Forms/ФормаЭлемента.xml @@ -0,0 +1,13 @@ + + +
+ + + Adopted + ФормаЭлемента + + UUID-002 + Managed + + +
\ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form.xml new file mode 100644 index 00000000..12d767d0 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form.xml @@ -0,0 +1,35 @@ + +
+ + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Тест</v8:content> + </v8:item> + + false + + + + + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Тест</v8:content> + </v8:item> + + false + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form/Module.bsl new file mode 100644 index 00000000..9861d282 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Catalogs/Товары/Forms/ФормаЭлемента/Ext/Form/Module.bsl @@ -0,0 +1,9 @@ +#Область ОбработчикиСобытийФормы + +&НаКлиенте +&После("ОбработкаОповещения") +Процедура Тест_ОбработкаОповещения(ИмяСобытия, Параметр, Источник) + // TODO: код после вызова оригинального метода +КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/ClientApplicationInterface.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Configuration.xml new file mode 100644 index 00000000..5c0f84b5 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Configuration.xml @@ -0,0 +1,72 @@ + + + + + + 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 + + + + Adopted + Тест + + + ru + Тест + + + + Customization + true + Тест_ + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + Role.Тест_ОсновнаяРоль + + + + Language.Русский + + + + + + TaxiEnableVersion8_2 + + + Русский + Тест_ОсновнаяРоль + Товары + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Languages/Русский.xml new file mode 100644 index 00000000..c21624f5 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Languages/Русский.xml @@ -0,0 +1,13 @@ + + + + + + Adopted + Русский + + UUID-002 + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Roles/Тест_ОсновнаяРоль.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Roles/Тест_ОсновнаяРоль.xml new file mode 100644 index 00000000..ec9dfbaf --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Ext/Roles/Тест_ОсновнаяРоль.xml @@ -0,0 +1,10 @@ + + + + + Тест_ОсновнаяРоль + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/form-handler/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/CommonModules/ОбщийМодуль2/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/CommonModules/ОбщийМодуль2/Ext/Module.bsl deleted file mode 100644 index 1f364d82..00000000 --- a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/CommonModules/ОбщийМодуль2/Ext/Module.bsl +++ /dev/null @@ -1,7 +0,0 @@ -&НаСервере -&После("ПолучитьЗначение") -Функция Тест_ПолучитьЗначение() - // TODO: код после вызова оригинального метода - - Возврат Неопределено; // TODO: заменить на реальное возвращаемое значение -КонецФункции diff --git a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/CommonModules/ОбщийМодуль2.xml b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/CommonModules/ОбщийМодуль2.xml similarity index 100% rename from tests/skills/cases/cfe-patch-method/snapshots/function-handler/CommonModules/ОбщийМодуль2.xml rename to tests/skills/cases/cfe-patch-method/snapshots/instead-function/CommonModules/ОбщийМодуль2.xml diff --git a/tests/skills/cases/cfe-patch-method/snapshots/instead-function/CommonModules/ОбщийМодуль2/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/CommonModules/ОбщийМодуль2/Ext/Module.bsl new file mode 100644 index 00000000..083cf27e --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/CommonModules/ОбщийМодуль2/Ext/Module.bsl @@ -0,0 +1,7 @@ +#Область ПрограммныйИнтерфейс + +Функция ПолучитьЗначение(Ключ, ПоУмолчанию = Неопределено) Экспорт + Возврат Ключ; +КонецФункции + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Configuration.xml similarity index 100% rename from tests/skills/cases/cfe-patch-method/snapshots/function-handler/Configuration.xml rename to tests/skills/cases/cfe-patch-method/snapshots/instead-function/Configuration.xml diff --git a/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/ClientApplicationInterface.xml b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/CommonModules/ОбщийМодуль2.xml b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/CommonModules/ОбщийМодуль2.xml similarity index 100% rename from tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/CommonModules/ОбщийМодуль2.xml rename to tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/CommonModules/ОбщийМодуль2.xml diff --git a/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/CommonModules/ОбщийМодуль2/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/CommonModules/ОбщийМодуль2/Ext/Module.bsl new file mode 100644 index 00000000..8628bbeb --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/CommonModules/ОбщийМодуль2/Ext/Module.bsl @@ -0,0 +1,10 @@ +#Область ПрограммныйИнтерфейс + +&Вместо("ПолучитьЗначение") +Функция Тест_ПолучитьЗначение(Ключ, ПоУмолчанию = Неопределено) + Результат = ПродолжитьВызов(Ключ, ПоУмолчанию); + // TODO: доработать поведение + Возврат Результат; +КонецФункции + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/Configuration.xml similarity index 100% rename from tests/skills/cases/cfe-patch-method/snapshots/function-handler/ext/Configuration.xml rename to tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/Configuration.xml diff --git a/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/Languages/Русский.xml new file mode 100644 index 00000000..c21624f5 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/Languages/Русский.xml @@ -0,0 +1,13 @@ + + + + + + Adopted + Русский + + UUID-002 + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/Roles/Тест_ОсновнаяРоль.xml b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/Roles/Тест_ОсновнаяРоль.xml new file mode 100644 index 00000000..ec9dfbaf --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Ext/Roles/Тест_ОсновнаяРоль.xml @@ -0,0 +1,10 @@ + + + + + Тест_ОсновнаяРоль + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/instead-function/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/mod-and-control/CommonModules/ОбщийМодуль1/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/mod-and-control/CommonModules/ОбщийМодуль1/Ext/Module.bsl index e69de29b..8c4ffd5f 100644 --- a/tests/skills/cases/cfe-patch-method/snapshots/mod-and-control/CommonModules/ОбщийМодуль1/Ext/Module.bsl +++ b/tests/skills/cases/cfe-patch-method/snapshots/mod-and-control/CommonModules/ОбщийМодуль1/Ext/Module.bsl @@ -0,0 +1,9 @@ +#Область ПрограммныйИнтерфейс + +Функция ПолучитьДанные(Параметр) Экспорт + Результат = Новый Массив; + Результат.Добавить(Параметр); + Возврат Результат; +КонецФункции + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/mod-and-control/ext/CommonModules/ОбщийМодуль1/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/mod-and-control/ext/CommonModules/ОбщийМодуль1/Ext/Module.bsl index 652104bc..00d4935e 100644 --- a/tests/skills/cases/cfe-patch-method/snapshots/mod-and-control/ext/CommonModules/ОбщийМодуль1/Ext/Module.bsl +++ b/tests/skills/cases/cfe-patch-method/snapshots/mod-and-control/ext/CommonModules/ОбщийМодуль1/Ext/Module.bsl @@ -1,6 +1,10 @@ -&НаСервере +#Область ПрограммныйИнтерфейс + &ИзменениеИКонтроль("ПолучитьДанные") -Процедура Тест_ПолучитьДанные() - // Скопируйте тело оригинального метода и внесите изменения, - // используя маркеры #Удаление / #КонецУдаления и #Вставка / #КонецВставки -КонецПроцедуры +Функция Тест_ПолучитьДанные(Параметр) + Результат = Новый Массив; + Результат.Добавить(Параметр); + Возврат Результат; +КонецФункции + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Configuration.xml new file mode 100644 index 00000000..ed39461c --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + 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/cfe-patch-method/snapshots/preproc-wrap/Documents/РасходТоваров.xml b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Documents/РасходТоваров.xml new file mode 100644 index 00000000..cfec6e2c --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/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 + + + + diff --git a/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Documents/РасходТоваров/Ext/ObjectModule.bsl b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Documents/РасходТоваров/Ext/ObjectModule.bsl new file mode 100644 index 00000000..4453ac4d --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Documents/РасходТоваров/Ext/ObjectModule.bsl @@ -0,0 +1,11 @@ +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда + +#Область ОбработчикиСобытий + +Процедура ОбработкаПроведения(Отказ, РежимПроведения) + Движения.Записывать = Истина; +КонецПроцедуры + +#КонецОбласти + +#КонецЕсли diff --git a/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/ClientApplicationInterface.xml b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Configuration.xml new file mode 100644 index 00000000..0ad08c47 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Configuration.xml @@ -0,0 +1,72 @@ + + + + + + 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 + + + + Adopted + Тест + + + ru + Тест + + + + Customization + true + Тест_ + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + Role.Тест_ОсновнаяРоль + + + + Language.Русский + + + + + + TaxiEnableVersion8_2 + + + Русский + Тест_ОсновнаяРоль + РасходТоваров + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Documents/РасходТоваров.xml b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Documents/РасходТоваров.xml new file mode 100644 index 00000000..36966932 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Documents/РасходТоваров.xml @@ -0,0 +1,34 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + + Adopted + РасходТоваров + + UUID-012 + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Documents/РасходТоваров/Ext/ObjectModule.bsl b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Documents/РасходТоваров/Ext/ObjectModule.bsl new file mode 100644 index 00000000..7ab03686 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Documents/РасходТоваров/Ext/ObjectModule.bsl @@ -0,0 +1,12 @@ +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда + +#Область ОбработчикиСобытий + +&Перед("ОбработкаПроведения") +Процедура Тест_ОбработкаПроведения(Отказ, РежимПроведения) + // TODO: код перед вызовом оригинального метода +КонецПроцедуры + +#КонецОбласти + +#КонецЕсли diff --git a/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Languages/Русский.xml new file mode 100644 index 00000000..c21624f5 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Languages/Русский.xml @@ -0,0 +1,13 @@ + + + + + + Adopted + Русский + + UUID-002 + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Roles/Тест_ОсновнаяРоль.xml b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Roles/Тест_ОсновнаяРоль.xml new file mode 100644 index 00000000..ec9dfbaf --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Ext/Roles/Тест_ОсновнаяРоль.xml @@ -0,0 +1,10 @@ + + + + + Тест_ОсновнаяРоль + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/preproc-wrap/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/CommonModules/РеюзМод.xml b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/CommonModules/РеюзМод.xml new file mode 100644 index 00000000..c15a5cd0 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/CommonModules/РеюзМод.xml @@ -0,0 +1,23 @@ + + + + + РеюзМод + + + ru + Реюз мод + + + + false + false + false + false + false + false + false + DontUse + + + diff --git a/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/CommonModules/РеюзМод/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/CommonModules/РеюзМод/Ext/Module.bsl new file mode 100644 index 00000000..b12629d1 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/CommonModules/РеюзМод/Ext/Module.bsl @@ -0,0 +1,7 @@ +#Область ПрограммныйИнтерфейс + +Процедура МетодБ(Х) Экспорт + Сообщить(Х); +КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Configuration.xml new file mode 100644 index 00000000..85253811 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + 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/cfe-patch-method/snapshots/region-reuse/Ext/ClientApplicationInterface.xml b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/CommonModules/РеюзМод.xml b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/CommonModules/РеюзМод.xml new file mode 100644 index 00000000..c623215b --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/CommonModules/РеюзМод.xml @@ -0,0 +1,18 @@ + + + + + + Adopted + РеюзМод + + UUID-002 + false + false + false + false + false + false + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/CommonModules/РеюзМод/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/CommonModules/РеюзМод/Ext/Module.bsl new file mode 100644 index 00000000..c81e5c2b --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/CommonModules/РеюзМод/Ext/Module.bsl @@ -0,0 +1,13 @@ +#Область ПрограммныйИнтерфейс + +&Перед("МетодА") +Процедура Тест_МетодА(П) + // уже есть +КонецПроцедуры + +&Перед("МетодБ") +Процедура Тест_МетодБ(Х) + // TODO: код перед вызовом оригинального метода +КонецПроцедуры + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/Configuration.xml new file mode 100644 index 00000000..366852d0 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/Configuration.xml @@ -0,0 +1,72 @@ + + + + + + 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 + + + + Adopted + Тест + + + ru + Тест + + + + Customization + true + Тест_ + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + Role.Тест_ОсновнаяРоль + + + + Language.Русский + + + + + + TaxiEnableVersion8_2 + + + Русский + Тест_ОсновнаяРоль + РеюзМод + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/Languages/Русский.xml new file mode 100644 index 00000000..c21624f5 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/Languages/Русский.xml @@ -0,0 +1,13 @@ + + + + + + Adopted + Русский + + UUID-002 + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/Roles/Тест_ОсновнаяРоль.xml b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/Roles/Тест_ОсновнаяРоль.xml new file mode 100644 index 00000000..ec9dfbaf --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Ext/Roles/Тест_ОсновнаяРоль.xml @@ -0,0 +1,10 @@ + + + + + Тест_ОсновнаяРоль + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/region-reuse/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/CommonModules/РесинкКонфл.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/CommonModules/РесинкКонфл.xml new file mode 100644 index 00000000..99f82d6a --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/CommonModules/РесинкКонфл.xml @@ -0,0 +1,23 @@ + + + + + РесинкКонфл + + + ru + Ресинк конфл + + + + false + false + false + false + false + false + false + DontUse + + + diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/CommonModules/РесинкКонфл/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/CommonModules/РесинкКонфл/Ext/Module.bsl new file mode 100644 index 00000000..18d1baed --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/CommonModules/РесинкКонфл/Ext/Module.bsl @@ -0,0 +1,10 @@ +#Область ПрограммныйИнтерфейс + +Функция Расчёт(А, Б) Экспорт + Итог = 0.00; + Итог = А + Б; + Итог = ОкруглитьВверх(Итог); + Возврат Итог; +КонецФункции + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Configuration.xml new file mode 100644 index 00000000..c7445823 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + 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/cfe-patch-method/snapshots/resync-conflict/Ext/ClientApplicationInterface.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/CommonModules/РесинкКонфл.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/CommonModules/РесинкКонфл.xml new file mode 100644 index 00000000..fe3cafe5 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/CommonModules/РесинкКонфл.xml @@ -0,0 +1,18 @@ + + + + + + Adopted + РесинкКонфл + + UUID-002 + false + false + false + false + false + false + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/CommonModules/РесинкКонфл/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/CommonModules/РесинкКонфл/Ext/Module.bsl new file mode 100644 index 00000000..f297bccc --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/CommonModules/РесинкКонфл/Ext/Module.bsl @@ -0,0 +1,14 @@ +#Область ПрограммныйИнтерфейс +&ИзменениеИКонтроль("Расчёт") +Функция Тест_Расчёт(А, Б) + Итог = 0.00; + Итог = А + Б; + Итог = ОкруглитьВверх(Итог); + Возврат Итог; + // [РЕСИНК-КОНФЛИКТ] перенесите блоки ниже вручную — исходный якорь изменился в новой версии оригинала. + // Материалы для анализа см. в выводе команды (файлы v1/v2/current/diff). +#Вставка + Итог = 999; +#КонецВставки +КонецФункции +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/Configuration.xml new file mode 100644 index 00000000..72db4356 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/Configuration.xml @@ -0,0 +1,72 @@ + + + + + + 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 + + + + Adopted + Тест + + + ru + Тест + + + + Customization + true + Тест_ + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + Role.Тест_ОсновнаяРоль + + + + Language.Русский + + + + + + TaxiEnableVersion8_2 + + + Русский + Тест_ОсновнаяРоль + РесинкКонфл + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/Languages/Русский.xml new file mode 100644 index 00000000..c21624f5 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/Languages/Русский.xml @@ -0,0 +1,13 @@ + + + + + + Adopted + Русский + + UUID-002 + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/Roles/Тест_ОсновнаяРоль.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/Roles/Тест_ОсновнаяРоль.xml new file mode 100644 index 00000000..ec9dfbaf --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Ext/Roles/Тест_ОсновнаяРоль.xml @@ -0,0 +1,10 @@ + + + + + Тест_ОсновнаяРоль + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-conflict/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/CommonModules/РесинкМод.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/CommonModules/РесинкМод.xml new file mode 100644 index 00000000..a9c4e9e6 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/CommonModules/РесинкМод.xml @@ -0,0 +1,23 @@ + + + + + РесинкМод + + + ru + Ресинк мод + + + + false + false + false + false + false + false + false + DontUse + + + diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/CommonModules/РесинкМод/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/CommonModules/РесинкМод/Ext/Module.bsl new file mode 100644 index 00000000..e06813f8 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/CommonModules/РесинкМод/Ext/Module.bsl @@ -0,0 +1,9 @@ +#Область ПрограммныйИнтерфейс + +Функция Расчёт(А, Б) Экспорт + Итог = 0; + Итог = А + Б; + Возврат Итог; +КонецФункции + +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Configuration.xml new file mode 100644 index 00000000..6e981c55 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + 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/cfe-patch-method/snapshots/resync-noop/Ext/ClientApplicationInterface.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/CommonModules/РесинкМод.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/CommonModules/РесинкМод.xml new file mode 100644 index 00000000..12b9ab9e --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/CommonModules/РесинкМод.xml @@ -0,0 +1,18 @@ + + + + + + Adopted + РесинкМод + + UUID-002 + false + false + false + false + false + false + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/CommonModules/РесинкМод/Ext/Module.bsl b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/CommonModules/РесинкМод/Ext/Module.bsl new file mode 100644 index 00000000..ed1c3603 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/CommonModules/РесинкМод/Ext/Module.bsl @@ -0,0 +1,11 @@ +#Область ПрограммныйИнтерфейс +&ИзменениеИКонтроль("Расчёт") +Функция Тест_Расчёт(А, Б) + Итог = 0; +#Вставка + Итог = 100; +#КонецВставки + Итог = А + Б; + Возврат Итог; +КонецФункции +#КонецОбласти diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/Configuration.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/Configuration.xml new file mode 100644 index 00000000..4b34f991 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/Configuration.xml @@ -0,0 +1,72 @@ + + + + + + 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 + + + + Adopted + Тест + + + ru + Тест + + + + Customization + true + Тест_ + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + Role.Тест_ОсновнаяРоль + + + + Language.Русский + + + + + + TaxiEnableVersion8_2 + + + Русский + Тест_ОсновнаяРоль + РесинкМод + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/Languages/Русский.xml new file mode 100644 index 00000000..c21624f5 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/Languages/Русский.xml @@ -0,0 +1,13 @@ + + + + + + Adopted + Русский + + UUID-002 + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/Roles/Тест_ОсновнаяРоль.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/Roles/Тест_ОсновнаяРоль.xml new file mode 100644 index 00000000..ec9dfbaf --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Ext/Roles/Тест_ОсновнаяРоль.xml @@ -0,0 +1,10 @@ + + + + + Тест_ОсновнаяРоль + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Languages/Русский.xml b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/cfe-patch-method/snapshots/resync-noop/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file diff --git a/tests/skills/runner.mjs b/tests/skills/runner.mjs index 8a1dec65..a713bbde 100644 --- a/tests/skills/runner.mjs +++ b/tests/skills/runner.mjs @@ -529,6 +529,7 @@ async function runCaseAsync(testCase, opts) { const wfContent = typeof step.writeFile.content === 'string' ? step.writeFile.content : JSON.stringify(step.writeFile.content, null, 2); + mkdirSync(dirname(wfPath), { recursive: true }); writeFileSync(wfPath, wfContent, 'utf8'); continue; }