feat(cfe-patch-method): батч -Check/-Actualize контролируемых методов (v2.2)

После обновления КФ контролируемые методы (&ИзменениеИКонтроль) молча уезжают в
рассинхрон — платформа при загрузке не ругается, ошибка лишь в рантайме. Добавлены
два явных режима по всему расширению (или -ModulePath/-MethodName для сужения):

- -Check — отчёт: какие методы дрейфнули (ДРЕЙФ/КОНФЛИКТ/МЕТОД-ИСЧЕЗ), актуальные
  числом; ничего не пишет; exit 1 при наличии дрейфа.
- -Actualize — чинит пачкой: авто-перенос + merge-воркспейс на конфликтах.

Одиночный ресинк вынесен в общую функцию resync_one (report_only), одиночный путь и
батч используют её. Зона ответственности узкая — только тело &ИзменениеИКонтроль.

Merge-воркспейс переработан: тонкий index.md (список конфликтов + пути к .bsl расширения)
+ подпапка на метод (conflict.md с блоком/диффом + base/local/remote), без общей портянки.

cfe-validate: крошка-указатель [INFO] при наличии контролируемых методов -> /cfe-patch-method -Check.

Тесты: +check-clean/check-drift/actualize-batch. 16 кейсов, оба рантайма зелёные,
байтовый паритет ps1<->py. verify-snapshots (реальная 1С) Windows ps+py — 16/16.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-18 20:37:58 +03:00
co-authored by Claude Opus 4.8
parent 8399f13e5a
commit 9aaa3a1c1e
29 changed files with 1609 additions and 256 deletions
+27 -3
View File
@@ -30,9 +30,11 @@ allowed-tools:
|----------|----------|--------------|
| `ExtensionPath` | Путь к расширению (обязат.) | — |
| `ConfigPath` | Путь к конфигурации-источнику | обязат., кроме случая, когда `ModulePath` — путь к файлу |
| `ModulePath` | Логическое имя (`Тип.Имя.Модуль`) **или** путь к файлу модуля `.bsl` (обязат.) | — |
| `MethodName` | Имя перехватываемого метода (обязат.) | — |
| `InterceptorType` | `Before` / `After` / `Instead` / `ModificationAndControl` (обязат.) | — |
| `ModulePath` | Логическое имя (`Тип.Имя.Модуль`) **или** путь к файлу модуля `.bsl` | обязат. для генерации |
| `MethodName` | Имя перехватываемого метода | обязат. для генерации |
| `InterceptorType` | `Before` / `After` / `Instead` / `ModificationAndControl` | обязат. для генерации |
| `Check` | Проверить контролируемые методы на дрейф (только отчёт) | — |
| `Actualize` | Актуализировать дрейфнувшие контролируемые методы | — |
Директива контекста, `Процедура`/`Функция`, сигнатура и обрамление определяются из оригинала автоматически — вручную задавать не нужно.
@@ -82,6 +84,22 @@ allowed-tools:
Повторный вызов `Before`/`After`/`Instead` для уже перехваченного метода не создаёт дубль (`[ПРОПУЩЕН]`).
## Проверка и актуализация пачкой (`-Check` / `-Actualize`)
После обновления конфигурации контролируемые методы (`&ИзменениеИКонтроль`) могут разойтись с
исходником — платформа при загрузке об этом молчит, ошибка всплывает лишь в рантайме. Эти режимы
проходят по **всем** `&ИзменениеИКонтроль` расширения (или сузить: `-ModulePath` — модуль, `+ -MethodName` — один):
- **`-Check`** — только отчёт: какие методы дрейфнули (`ДРЕЙФ` / `КОНФЛИКТ` / `МЕТОД-ИСЧЕЗ`); актуальные
считаются числом (`100/103 актуальны`). Ничего не пишет. Код возврата **1**, если есть что чинить.
- **`-Actualize`** — чинит: авто-переносит правки, для неоднозначных — merge-воркспейс.
Зона ответственности — **только тело `&ИзменениеИКонтроль`** (не свойства/формы/сигнатуры).
Merge-воркспейс конфликтов (`-Actualize`) в системном temp: `index.md` (тонкий список конфликтов с
путями к `.bsl` расширения для правки) + подпапка на каждый конфликтный метод с `conflict.md`
(что перенести + дифф) и `base/local/remote`. Путь печатается в выводе.
## Команда
```powershell
@@ -105,6 +123,12 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-patch-method.ps
# ModulePath как путь к файлу модуля-источника (без -ConfigPath)
... -ExtensionPath src\cfe\ИмяРасширения -ModulePath "src\cf\CommonModules\ОбщийМодуль\Ext\Module.bsl" -MethodName "ПолучитьДанные" -InterceptorType Instead
# Проверить все контролируемые методы расширения на дрейф
... -ExtensionPath src\cfe\ИмяРасширения -ConfigPath src\cf -Check
# Актуализировать дрейфнувшие контролируемые методы пачкой
... -ExtensionPath src\cfe\ИмяРасширения -ConfigPath src\cf -Actualize
```
## Верификация
@@ -1,4 +1,4 @@
# cfe-patch-method v2.1 — Source-aware method interceptor for 1C extension (CFE)
# cfe-patch-method v2.2 — Source-aware method interceptor for 1C extension (CFE)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -6,15 +6,17 @@ param(
[string]$ConfigPath,
[Parameter(Mandatory)]
# Generation: logical name or path to .bsl. Optional in -Check/-Actualize (scope narrowing).
[string]$ModulePath,
[Parameter(Mandatory)]
[string]$MethodName,
[Parameter(Mandatory)]
[ValidateSet("Before","After","Instead","ModificationAndControl")]
[string]$InterceptorType
[ValidateSet("", "Before", "After", "Instead", "ModificationAndControl")]
[string]$InterceptorType,
# Batch modes over &ИзменениеИКонтроль of the extension (no generation):
[switch]$Check, # report drift only, no writes
[switch]$Actualize # actualize drifted controlled methods
)
$ErrorActionPreference = "Stop"
@@ -475,6 +477,199 @@ function Get-Truncated {
return $t
}
# Reverse of typeDirMap (plural dir -> singular type) for logical id display
$script:dirToType = @{
"Catalogs"="Catalog"; "Documents"="Document"; "Enums"="Enum"; "CommonModules"="CommonModule"
"Reports"="Report"; "DataProcessors"="DataProcessor"; "ExchangePlans"="ExchangePlan"
"ChartsOfAccounts"="ChartOfAccounts"; "ChartsOfCharacteristicTypes"="ChartOfCharacteristicTypes"
"ChartsOfCalculationTypes"="ChartOfCalculationTypes"; "BusinessProcesses"="BusinessProcess"
"Tasks"="Task"; "InformationRegisters"="InformationRegister"
"AccumulationRegisters"="AccumulationRegister"; "AccountingRegisters"="AccountingRegister"
"CalculationRegisters"="CalculationRegister"
}
# Rel-path segments (relative to ExtensionPath) -> logical ModulePath (Type.Name.Module / CommonModule.Name)
function Get-ModulePathFromRel {
param($relParts)
$dir0 = $relParts[0]; $name = $relParts[1]
$typ = if ($script:dirToType.ContainsKey($dir0)) { $script:dirToType[$dir0] } else { $dir0 }
if ($dir0 -eq "CommonModules") { return "CommonModule.$name" }
if ($relParts.Count -ge 7 -and $relParts[2] -eq "Forms") { return "$typ.$name.Form.$($relParts[3])" }
$mod = $relParts[$relParts.Count - 1]
if ($mod.EndsWith(".bsl")) { $mod = $mod.Substring(0, $mod.Length - 4) }
return "$typ.$name.$mod"
}
function Get-RelPartsUnder {
param([string]$root, [string]$fullPath)
$r = [IO.Path]::GetFullPath($root).TrimEnd('\', '/')
$f = [IO.Path]::GetFullPath($fullPath)
$rel = $f.Substring($r.Length).TrimStart('\', '/')
return (($rel -replace '\\', '/').Split('/') | Where-Object { $_ -ne '' })
}
function Get-ResyncConflictReason {
param($disputed)
$kinds = @($disputed | ForEach-Object { $_.Kind } | Select-Object -Unique)
$parts = @()
if ($kinds -contains 'insert') { $parts += 'якорь вставки изменён' }
if ($kinds -contains 'delete') { $parts += 'удаляемое исчезло' }
return ($parts -join '; ')
}
# Write per-method conflict folder: conflict.md + base/local/remote
function Write-ConflictFolder {
param($folder, $methodId, $extBsl, $existingName, $method, $v1, $markedBody, $v2, $v1norm, $v2norm, $disputed, $enc)
if (-not (Test-Path $folder)) { New-Item -ItemType Directory -Path $folder -Force | Out-Null }
[IO.File]::WriteAllText((Join-Path $folder 'base.bsl'), (($v1 -join "`r`n") + "`r`n"), $enc)
[IO.File]::WriteAllText((Join-Path $folder 'local.bsl'), (($markedBody -join "`r`n") + "`r`n"), $enc)
[IO.File]::WriteAllText((Join-Path $folder 'remote.bsl'), (($v2 -join "`r`n") + "`r`n"), $enc)
$md = @()
$md += "# $methodId"
$md += "Править: $extBsl"
$md += "Метод: $existingName (&ИзменениеИКонтроль(`"$($method.Canonical)`"))"
$md += "Причина: $(Get-ResyncConflictReason $disputed)"
$md += ""
$md += "## Не размещено — перенести в метод вручную"
foreach ($d in $disputed) {
if ($d.Kind -eq 'insert') { $md += '#Вставка'; foreach ($l in $d.Lines) { $md += $l }; $md += '#КонецВставки' }
else { $md += '// не удалось найти для удаления:'; foreach ($l in $d.Lines) { $md += ('// ' + $l.Trim()) } }
}
$md += ""
$md += "## Дифф base→remote (что изменилось в оригинале)"
foreach ($l in $v1) { if ($v2norm -notcontains (Get-Normalized $l)) { $md += "- $l" } }
foreach ($l in $v2) { if ($v1norm -notcontains (Get-Normalized $l)) { $md += "+ $l" } }
$md += ""
$md += "Рядом: base.bsl / local.bsl / remote.bsl"
[IO.File]::WriteAllText((Join-Path $folder 'conflict.md'), (($md -join "`r`n") + "`r`n"), $enc)
}
# Resync one &ИзменениеИКонтроль interceptor. Returns status hashtable.
# ReportOnly: classify without writing. Otherwise: apply to module (+ conflict folder on disputes).
function Invoke-Resync {
param($extBsl, $extLines, $dup, $method, [string]$logicalModule, [string]$conflictFolder, [switch]$ReportOnly, $enc)
$methodId = "$logicalModule.$($method.Canonical)"
$decLine = $dup.Line
$sigLineIdx = $decLine + 1
if ($sigLineIdx -ge $extLines.Count -or $extLines[$sigLineIdx] -notmatch '^\s*(?:Асинх\s+)?(?:Процедура|Функция)\s+([\w]+)\s*\(') {
return @{ Id = $methodId; Status = 'ОШИБКА'; ExtBsl = $extBsl; Reason = 'не разобрать сигнатуру перехватчика' }
}
$existingName = $Matches[1]
$sig = Read-Signature $extLines $sigLineIdx
if (-not $sig) { return @{ Id = $methodId; Status = 'ОШИБКА'; ExtBsl = $extBsl; Reason = 'не разобрать сигнатуру' } }
$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) { return @{ Id = $methodId; Status = 'ОШИБКА'; ExtBsl = $extBsl; Reason = 'не найден конец перехватчика' } }
$markedBody = @()
for ($j = $sigEnd + 1; $j -lt $blockEnd; $j++) { $markedBody += $extLines[$j] }
$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 $_ })
if (($v1norm -join "`n") -eq ($v2norm -join "`n")) {
return @{ Id = $methodId; Status = 'АКТУАЛЕН'; ExtBsl = $extBsl }
}
$insertTop = @(); $insertAfter = @{}; $delStart = @{}; $delEnd = @{}; $disputed = @(); $transferred = @()
foreach ($op in $ops) {
if ($op.Kind -eq 'insert') {
$beforeLines = @()
if ($op.After -ge 0) { $bs = [Math]::Max(0, $op.After - 2); for ($m = $bs; $m -le $op.After; $m++) { $beforeLines += $v1norm[$m] } }
$afterLines = @()
$ae = [Math]::Min($v1norm.Count - 1, $op.After + 3)
for ($m = $op.After + 1; $m -le $ae; $m++) { $afterLines += $v1norm[$m] }
$k = Resolve-InsertionPoint $v2norm $beforeLines $afterLines
if ($null -eq $k) { $disputed += @{ Kind = 'insert'; Lines = $op.Lines } }
elseif ($k -lt 0) { $insertTop += ,$op.Lines; $transferred += @{ Kind = 'insert' } }
else { if (-not $insertAfter.ContainsKey($k)) { $insertAfter[$k] = @() }; $insertAfter[$k] += ,$op.Lines; $transferred += @{ Kind = 'insert' } }
} 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; $transferred += @{ Kind = 'delete' } }
else { $disputed += @{ Kind = 'delete'; Lines = $op.Lines } }
}
}
if ($ReportOnly) {
$st = if ($disputed.Count -gt 0) { 'КОНФЛИКТ' } else { 'ДРЕЙФ' }
return @{ Id = $methodId; Status = $st; ExtBsl = $extBsl; Transferred = $transferred.Count; Disputed = $disputed.Count; Reason = (Get-ResyncConflictReason $disputed) }
}
# 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 += "#КонецВставки" } }
}
if ($disputed.Count -gt 0) {
$newBody += "`t// [РЕСИНК-КОНФЛИКТ] перенесите блоки ниже вручную — исходный якорь изменился в новой версии оригинала."
$newBody += "`t// Материалы: см. index.md / conflict.md в merge-воркспейсе (путь в выводе)."
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()) } }
}
}
$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
$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] }
[IO.File]::WriteAllText($extBsl, (($out -join "`r`n") + "`r`n"), $enc)
$conflictDir = $null
if ($disputed.Count -gt 0) {
$conflictDir = $conflictFolder
Write-ConflictFolder $conflictFolder $methodId $extBsl $existingName $method $v1 $markedBody $v2 $v1norm $v2norm $disputed $enc
}
$status = if ($disputed.Count -gt 0) { 'ЧАСТИЧНО' } else { 'АКТУАЛИЗИРОВАН' }
return @{ Id = $methodId; Status = $status; ExtBsl = $extBsl; Transferred = $transferred.Count; Disputed = $disputed.Count; ConflictDir = $conflictDir; Reason = (Get-ResyncConflictReason $disputed) }
}
# Write run-root index.md (only if there are conflicts). Returns run-root or $null.
function Write-ResyncIndex {
param($runRoot, $results, [string]$extName, [string]$configPath, [string]$verb, $enc)
$conflicts = @($results | Where-Object { $_.Status -eq 'ЧАСТИЧНО' })
if ($conflicts.Count -eq 0) { return $null }
if (-not (Test-Path $runRoot)) { New-Item -ItemType Directory -Path $runRoot -Force | Out-Null }
$total = $results.Count
$actual = @($results | Where-Object { $_.Status -eq 'АКТУАЛЕН' }).Count
$upd = @($results | Where-Object { $_.Status -eq 'АКТУАЛИЗИРОВАН' }).Count
$lines = @()
$lines += "[$verb] $extName -> $configPath"
$lines += "Итог: $actual/$total актуальны · $upd актуализировано · $($conflicts.Count) конфликтов"
$lines += ""
$lines += "Конфликты — править .bsl расширения:"
foreach ($c in $conflicts) {
$lines += " ЧАСТИЧНО $($c.Id)"
$lines += " -> $($c.ExtBsl) ($($c.Reason))"
}
[IO.File]::WriteAllText((Join-Path $runRoot 'index.md'), (($lines -join "`r`n") + "`r`n"), $enc)
return $runRoot
}
# ============================================================================
# Main
# ============================================================================
@@ -494,6 +689,93 @@ $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 { "Расш_" }
$extNameNode = if ($propsNode) { $propsNode.SelectSingleNode("md:Name", $cfgNs) } else { $null }
$extName = if ($extNameNode -and $extNameNode.InnerText) { $extNameNode.InnerText } else { "Расширение" }
# ============================================================================
# Batch modes: -Check / -Actualize over &ИзменениеИКонтроль of the extension
# ============================================================================
if ($Check -or $Actualize) {
if ($Check -and $Actualize) { Write-Error "Укажите либо -Check, либо -Actualize, не оба."; exit 1 }
if ([string]::IsNullOrEmpty($ConfigPath)) { Write-Error "Для -Check/-Actualize нужен -ConfigPath (сверка с исходником)."; exit 1 }
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 }
if (-not (Test-Path (Join-Path $ConfigPath "Configuration.xml"))) { Write-Error "Configuration.xml не найден в конфигурации-источнике: $ConfigPath"; exit 1 }
$enc = New-Object System.Text.UTF8Encoding($true)
$reportOnly = [bool]$Check
$verb = if ($Check) { "КОНТРОЛЬ" } else { "АКТУАЛИЗАЦИЯ" }
# target .bsl set: -ModulePath → один модуль; иначе — все .bsl расширения
$targetBsls = @()
if (-not [string]::IsNullOrEmpty($ModulePath)) {
$relParts = Get-ModuleRelPath $ModulePath
$mb = $ExtensionPath; foreach ($p in $relParts) { $mb = Join-Path $mb $p }
if (Test-Path $mb) { $targetBsls += $mb }
} else {
$targetBsls = @(Get-ChildItem -Path $ExtensionPath -Recurse -Filter *.bsl -File | ForEach-Object { $_.FullName })
}
$runRoot = Join-Path ([IO.Path]::GetTempPath()) (Join-Path "cfe-resync" ($extName -replace '[\\/:*?"<>|]', '_'))
if ($Actualize -and (Test-Path $runRoot)) { Remove-Item $runRoot -Recurse -Force -ErrorAction SilentlyContinue }
$results = @()
foreach ($tb in $targetBsls) {
$scan = @([IO.File]::ReadAllLines($tb, [Text.Encoding]::UTF8))
$mnames = @(Get-Interceptors $scan | Where-Object { $_.Type -eq 'ИзменениеИКонтроль' } | ForEach-Object { $_.Method })
if (-not [string]::IsNullOrEmpty($MethodName)) { $mnames = @($mnames | Where-Object { $_ -ieq $MethodName }) }
$mnames = @($mnames | Select-Object -Unique)
if ($mnames.Count -eq 0) { continue }
$rel = Get-RelPartsUnder $ExtensionPath $tb
$logicalModule = Get-ModulePathFromRel $rel
$srcBsl = $ConfigPath; foreach ($p in $rel) { $srcBsl = Join-Path $srcBsl $p }
$relJoined = ($rel -join '\') -replace '\.bsl$', ''
foreach ($mname in $mnames) {
$mid = "$logicalModule.$mname"
if (-not (Test-Path $srcBsl)) { $results += @{ Id = $mid; Status = 'ИСТОЧНИК-НЕ-НАЙДЕН'; ExtBsl = $tb }; continue }
$srcL = [IO.File]::ReadAllLines($srcBsl, [Text.Encoding]::UTF8)
$m = Extract-Method $srcL $mname
if (-not $m) { $results += @{ Id = $mid; Status = 'МЕТОД-ИСЧЕЗ'; ExtBsl = $tb }; continue }
# fresh read per method (writes shift line numbers)
$tbLines = @([IO.File]::ReadAllLines($tb, [Text.Encoding]::UTF8))
$ic = @(Get-Interceptors $tbLines | Where-Object { $_.Type -eq 'ИзменениеИКонтроль' -and $_.Method -ieq $mname })[0]
if (-not $ic) { continue }
$folder = Join-Path $runRoot (Join-Path $relJoined $m.Canonical)
$results += (Invoke-Resync $tb $tbLines $ic $m $logicalModule $folder -ReportOnly:$reportOnly $enc)
}
}
# --- report ---
$total = $results.Count
$actual = @($results | Where-Object { $_.Status -eq 'АКТУАЛЕН' }).Count
Write-Host "[$verb] $extName -> $ConfigPath (на контроле: $total)"
$listed = @($results | Where-Object { $_.Status -ne 'АКТУАЛЕН' })
foreach ($p in $listed) {
$line = " {0,-16} {1}" -f $p.Status, $p.Id
if ($p.Reason) { $line += " $($p.Reason)" }
Write-Host $line
}
if ($Check) {
$drift = @($results | Where-Object { $_.Status -eq 'ДРЕЙФ' }).Count
$confl = @($results | Where-Object { $_.Status -eq 'КОНФЛИКТ' }).Count
$gone = @($results | Where-Object { $_.Status -in @('МЕТОД-ИСЧЕЗ', 'ИСТОЧНИК-НЕ-НАЙДЕН') }).Count
Write-Host "Итог: $actual/$total актуальны · $drift дрейф · $confl конфликт · $gone требуют внимания"
if ($listed.Count -gt 0) { Write-Host "Починить: /cfe-patch-method -Actualize -ExtensionPath $ExtensionPath -ConfigPath $ConfigPath"; exit 1 } else { exit 0 }
} else {
$upd = @($results | Where-Object { $_.Status -eq 'АКТУАЛИЗИРОВАН' }).Count
$part = @($results | Where-Object { $_.Status -eq 'ЧАСТИЧНО' }).Count
Write-Host "Итог: $actual/$total актуальны · $upd актуализировано · $part частично"
$idx = Write-ResyncIndex $runRoot $results $extName $ConfigPath $verb $enc
if ($idx) { Write-Host "Merge-воркспейс конфликтов (см. index.md): $idx" }
exit 0
}
}
# --- Generation mode: require ModulePath + MethodName + InterceptorType ---
if ([string]::IsNullOrEmpty($ModulePath) -or [string]::IsNullOrEmpty($MethodName) -or [string]::IsNullOrEmpty($InterceptorType)) {
Write-Error "Нужны -ModulePath, -MethodName, -InterceptorType (генерация перехватчика). Для проверки/актуализации контролируемых методов используйте -Check или -Actualize."
exit 1
}
# --- Resolve module file paths (ModulePath = logical name OR path to a .bsl) ---
$hasConfigPath = -not [string]::IsNullOrEmpty($ConfigPath)
@@ -568,171 +850,23 @@ if ($dup) {
Write-Host " Файл: $extBsl"
exit 0
}
# ---- 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 = @()
$transferred = @() # for the summary: @{ Kind; Anchor }
foreach ($op in $ops) {
if ($op.Kind -eq 'insert') {
# two-sided context anchor
$beforeLines = @()
if ($op.After -ge 0) {
$bs = [Math]::Max(0, $op.After - 2)
for ($m = $bs; $m -le $op.After; $m++) { $beforeLines += $v1norm[$m] }
}
$afterLines = @()
$ae = [Math]::Min($v1norm.Count - 1, $op.After + 3)
for ($m = $op.After + 1; $m -le $ae; $m++) { $afterLines += $v1norm[$m] }
$k = Resolve-InsertionPoint $v2norm $beforeLines $afterLines
if ($null -eq $k) {
$disputed += @{ Kind = 'insert'; Lines = $op.Lines }
} elseif ($k -lt 0) {
$insertTop += ,$op.Lines
$transferred += @{ Kind = 'insert'; Anchor = '(в начало метода)' }
} else {
if (-not $insertAfter.ContainsKey($k)) { $insertAfter[$k] = @() }
$insertAfter[$k] += ,$op.Lines
$transferred += @{ Kind = 'insert'; Anchor = $v2[$k] }
}
} 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
$transferred += @{ Kind = 'delete'; Anchor = $op.Lines[0] }
} else {
$disputed += @{ Kind = 'delete'; Lines = $op.Lines }
}
# ---- RESYNC (&ИзменениеИКонтроль) — via Invoke-Resync ----
$rel = Get-RelPartsUnder $ExtensionPath $extBsl
$logicalModule = Get-ModulePathFromRel $rel
$relJoined = ($rel -join '') -replace '.bsl$', ''
$runRoot = Join-Path ([IO.Path]::GetTempPath()) (Join-Path "cfe-resync" ($extName -replace '[\/:*?"<>|]', '_'))
$folder = Join-Path $runRoot (Join-Path $relJoined $method.Canonical)
$res = Invoke-Resync $extBsl $extLines $dup $method $logicalModule $folder $enc
switch ($res.Status) {
'АКТУАЛЕН' { Write-Host "[АКТУАЛЕН] &ИзменениеИКонтроль(`"$MethodName`") — оригинал не менялся, изменений нет." }
'АКТУАЛИЗИРОВАН' { Write-Host "[АКТУАЛИЗИРОВАН] &ИзменениеИКонтроль(`"$MethodName`") — тело обновлено, перенесено правок: $($res.Transferred)" }
'ЧАСТИЧНО' {
$idx = Write-ResyncIndex $runRoot @($res) $extName $ConfigPath "АКТУАЛИЗАЦИЯ" $enc
Write-Host "[АКТУАЛИЗИРОВАН-ЧАСТИЧНО] &ИзменениеИКонтроль(`"$MethodName`") — перенесено: $($res.Transferred), конфликтов: $($res.Disputed)"
Write-Host " Конфликт помечен // [РЕСИНК-КОНФЛИКТ]. Папка метода: $($res.ConflictDir)"
if ($idx) { Write-Host " Индекс: $idx" }
}
}
# 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// Материалы для анализа см. в выводе команды (файлы base/local/remote/merged)."
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)
# transferred summary (shared by full-auto and partial)
function Write-TransferSummary {
param($items)
foreach ($t in $items) {
if ($t.Kind -eq 'insert') { Write-Host " • вставка после «$(Get-Truncated $t.Anchor)»" }
else { Write-Host " • удаление «$(Get-Truncated $t.Anchor)»" }
}
}
if ($disputed.Count -gt 0) {
# merge workspace (git-mergetool convention: base/local/remote/merged)
$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 "base.bsl"), (($v1 -join "`r`n") + "`r`n"), $enc)
[System.IO.File]::WriteAllText((Join-Path $tmpRoot "local.bsl"), (($markedBody -join "`r`n") + "`r`n"), $enc)
[System.IO.File]::WriteAllText((Join-Path $tmpRoot "remote.bsl"), (($v2 -join "`r`n") + "`r`n"), $enc)
[System.IO.File]::WriteAllText((Join-Path $tmpRoot "merged.bsl"), (($newBlock -join "`r`n") + "`r`n"), $enc)
$diff = @()
$diff += "--- base -> remote (что изменилось в оригинале) ---"
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`") — перенесено: $($transferred.Count), конфликтов: $($disputed.Count)"
Write-TransferSummary $transferred
Write-Host " Конфликтные блоки помечены // [РЕСИНК-КОНФЛИКТ] — разместите вручную."
Write-Host " Merge-воркспейс (base/local/remote/merged/diff):"
Write-Host " $tmpRoot"
} else {
Write-Host "[АКТУАЛИЗИРОВАН] &ИзменениеИКонтроль(`"$MethodName`") — тело обновлено, перенесено правок: $($transferred.Count)"
Write-TransferSummary $transferred
default { Write-Host "[$($res.Status)] &ИзменениеИКонтроль(`"$MethodName`") — $($res.Reason)" }
}
Write-Host " Файл: $extBsl"
exit 0
@@ -1,10 +1,11 @@
#!/usr/bin/env python3
# cfe-patch-method v2.1 — Source-aware method interceptor for 1C extension (CFE)
# cfe-patch-method v2.2 — Source-aware method interceptor for 1C extension (CFE)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
import re
import shutil
import sys
import tempfile
import xml.etree.ElementTree as ET
@@ -475,10 +476,12 @@ def main():
)
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"])
parser.add_argument("-ModulePath", required=False, default="")
parser.add_argument("-MethodName", required=False, default="")
parser.add_argument("-InterceptorType", required=False, default="",
choices=["", "Before", "After", "Instead", "ModificationAndControl"])
parser.add_argument("-Check", action="store_true")
parser.add_argument("-Actualize", action="store_true")
args = parser.parse_args()
extension_path = args.ExtensionPath
@@ -486,6 +489,8 @@ def main():
module_path = args.ModulePath
method_name = args.MethodName
interceptor_type = args.InterceptorType
check_mode = args.Check
actualize_mode = args.Actualize
# --- Resolve extension path ---
if not os.path.isabs(extension_path):
@@ -506,8 +511,111 @@ def main():
pn = props.find("md:NamePrefix", ns)
if pn is not None and pn.text:
name_prefix = pn.text
nn = props.find("md:Name", ns)
if nn is not None and nn.text:
ext_name = nn.text
except ET.ParseError:
pass
if 'ext_name' not in dir():
ext_name = "Расширение"
# --- Batch modes: -Check / -Actualize over &ИзменениеИКонтроль ---
if check_mode or actualize_mode:
if check_mode and actualize_mode:
die("Укажите либо -Check, либо -Actualize, не оба.")
if not config_path:
die("Для -Check/-Actualize нужен -ConfigPath (сверка с исходником).")
cp = config_path
if not os.path.isabs(cp):
cp = os.path.join(os.getcwd(), cp)
if os.path.isfile(cp):
cp = os.path.dirname(cp)
if not os.path.isfile(os.path.join(cp, "Configuration.xml")):
die("Configuration.xml не найден в конфигурации-источнике: %s" % cp)
report_only = check_mode
verb = "КОНТРОЛЬ" if check_mode else "АКТУАЛИЗАЦИЯ"
safe = re.sub(r'[\\/:*?"<>|]', "_", ext_name)
run_root = os.path.join(tempfile.gettempdir(), "cfe-resync", safe)
if actualize_mode and os.path.isdir(run_root):
shutil.rmtree(run_root, ignore_errors=True)
targets = []
if module_path:
rp = get_module_rel_path(module_path)
mb = os.path.join(extension_path, *rp)
if os.path.isfile(mb):
targets.append(mb)
else:
for dirpath, _dirs, files in os.walk(extension_path):
for fn in files:
if fn.endswith(".bsl"):
targets.append(os.path.join(dirpath, fn))
results = []
for tb in targets:
scan = read_lines(tb)
mnames = [ic["method"] for ic in get_interceptors(scan) if ic["type"] == "ИзменениеИКонтроль"]
if method_name:
mnames = [m for m in mnames if m.lower() == method_name.lower()]
seen = set(); uniq = []
for m in mnames:
if m.lower() not in seen:
seen.add(m.lower()); uniq.append(m)
if not uniq:
continue
rel = rel_parts_under(extension_path, tb)
logical_module = module_path_from_rel(rel)
src_bsl2 = os.path.join(cp, *rel)
rel_no_bsl = os.path.join(*rel)
if rel_no_bsl.endswith(".bsl"):
rel_no_bsl = rel_no_bsl[:-4]
for mname in uniq:
mid = "%s.%s" % (logical_module, mname)
if not os.path.isfile(src_bsl2):
results.append({"id": mid, "status": "ИСТОЧНИК-НЕ-НАЙДЕН", "ext_bsl": tb}); continue
m = extract_method(read_lines(src_bsl2), mname)
if not m:
results.append({"id": mid, "status": "МЕТОД-ИСЧЕЗ", "ext_bsl": tb}); continue
tb_lines = read_lines(tb)
ic = next((x for x in get_interceptors(tb_lines)
if x["type"] == "ИзменениеИКонтроль" and x["method"].lower() == mname.lower()), None)
if not ic:
continue
folder = os.path.join(run_root, rel_no_bsl, m["canonical"])
results.append(resync_one(tb, tb_lines, ic, m, logical_module, folder, report_only))
total = len(results)
actual = sum(1 for r in results if r["status"] == "АКТУАЛЕН")
print("[%s] %s -> %s (на контроле: %d)" % (verb, ext_name, cp, total))
listed = [r for r in results if r["status"] != "АКТУАЛЕН"]
for pr in listed:
line = " %-16s %s" % (pr["status"], pr["id"])
if pr.get("reason"):
line += " %s" % pr["reason"]
print(line)
if check_mode:
drift = sum(1 for r in results if r["status"] == "ДРЕЙФ")
confl = sum(1 for r in results if r["status"] == "КОНФЛИКТ")
gone = sum(1 for r in results if r["status"] in ("МЕТОД-ИСЧЕЗ", "ИСТОЧНИК-НЕ-НАЙДЕН"))
print("Итог: %d/%d актуальны · %d дрейф · %d конфликт · %d требуют внимания"
% (actual, total, drift, confl, gone))
if listed:
print("Починить: /cfe-patch-method -Actualize -ExtensionPath %s -ConfigPath %s" % (extension_path, cp))
sys.exit(1)
sys.exit(0)
else:
upd = sum(1 for r in results if r["status"] == "АКТУАЛИЗИРОВАН")
part = sum(1 for r in results if r["status"] == "ЧАСТИЧНО")
print("Итог: %d/%d актуальны · %d актуализировано · %d частично" % (actual, total, upd, part))
idx = write_resync_index(run_root, results, ext_name, cp, verb)
if idx:
print("Merge-воркспейс конфликтов (см. index.md): %s" % idx)
sys.exit(0)
# --- Generation mode: require ModulePath + MethodName + InterceptorType ---
if not (module_path and method_name and interceptor_type):
die("Нужны -ModulePath, -MethodName, -InterceptorType (генерация перехватчика). "
"Для проверки/актуализации контролируемых методов используйте -Check или -Actualize.")
# --- Resolve module file paths (ModulePath = logical name OR path to a .bsl) ---
has_config = bool(config_path)
@@ -580,7 +688,31 @@ def main():
% (decorator_ru, method_name))
print(" Файл: %s" % ext_bsl)
sys.exit(0)
resync(ext_bsl, ext_lines, dup, method, method_name, module_path)
rel = rel_parts_under(extension_path, ext_bsl)
logical_module = module_path_from_rel(rel)
rel_no_bsl = os.path.join(*rel)
if rel_no_bsl.endswith(".bsl"):
rel_no_bsl = rel_no_bsl[:-4]
safe = re.sub(r'[\\/:*?"<>|]', "_", ext_name)
run_root = os.path.join(tempfile.gettempdir(), "cfe-resync", safe)
folder = os.path.join(run_root, rel_no_bsl, method["canonical"])
res = resync_one(ext_bsl, ext_lines, dup, method, logical_module, folder, False)
st = res["status"]
if st == "АКТУАЛЕН":
print('[АКТУАЛЕН] &ИзменениеИКонтроль("%s") — оригинал не менялся, изменений нет.' % method_name)
elif st == "АКТУАЛИЗИРОВАН":
print('[АКТУАЛИЗИРОВАН] &ИзменениеИКонтроль("%s") — тело обновлено, перенесено правок: %d'
% (method_name, res.get("transferred", 0)))
elif st == "ЧАСТИЧНО":
idx = write_resync_index(run_root, [res], ext_name, config_path, "АКТУАЛИЗАЦИЯ")
print('[АКТУАЛИЗИРОВАН-ЧАСТИЧНО] &ИзменениеИКонтроль("%s") — перенесено: %d, конфликтов: %d'
% (method_name, res.get("transferred", 0), res.get("disputed", 0)))
print(" Конфликт помечен // [РЕСИНК-КОНФЛИКТ]. Папка метода: %s" % res.get("conflict_dir"))
if idx:
print(" Индекс: %s" % idx)
else:
print('[%s] &ИзменениеИКонтроль("%s") — %s' % (st, method_name, res.get("reason", "")))
print(" Файл: %s" % ext_bsl)
sys.exit(0)
# --- New interceptor ---
@@ -688,16 +820,87 @@ def place_new(ext_bsl, ext_lines, ext_exists, chain, core):
place_new.placement = "создан модуль"
def resync(ext_bsl, ext_lines, dup, method, method_name, module_path):
DIR_TO_TYPE = {
"Catalogs": "Catalog", "Documents": "Document", "Enums": "Enum", "CommonModules": "CommonModule",
"Reports": "Report", "DataProcessors": "DataProcessor", "ExchangePlans": "ExchangePlan",
"ChartsOfAccounts": "ChartOfAccounts", "ChartsOfCharacteristicTypes": "ChartOfCharacteristicTypes",
"ChartsOfCalculationTypes": "ChartOfCalculationTypes", "BusinessProcesses": "BusinessProcess",
"Tasks": "Task", "InformationRegisters": "InformationRegister",
"AccumulationRegisters": "AccumulationRegister", "AccountingRegisters": "AccountingRegister",
"CalculationRegisters": "CalculationRegister",
}
def module_path_from_rel(rel_parts):
dir0, name = rel_parts[0], rel_parts[1]
typ = DIR_TO_TYPE.get(dir0, dir0)
if dir0 == "CommonModules":
return "CommonModule.%s" % name
if len(rel_parts) >= 7 and rel_parts[2] == "Forms":
return "%s.%s.Form.%s" % (typ, name, rel_parts[3])
mod = rel_parts[-1][:-4] if rel_parts[-1].endswith(".bsl") else rel_parts[-1]
return "%s.%s.%s" % (typ, name, mod)
def rel_parts_under(root, full_path):
rel = os.path.relpath(os.path.abspath(full_path), os.path.abspath(root))
return [s for s in rel.replace("\\", "/").split("/") if s and s != "."]
def conflict_reason(disputed):
kinds = set(d["kind"] for d in disputed)
parts = []
if "insert" in kinds:
parts.append("якорь вставки изменён")
if "delete" in kinds:
parts.append("удаляемое исчезло")
return "; ".join(parts)
def write_conflict_folder(folder, method_id, ext_bsl, existing_name, method, v1, marked_body, v2, v1norm, v2norm, disputed):
os.makedirs(folder, exist_ok=True)
write_bsl(os.path.join(folder, "base.bsl"), v1)
write_bsl(os.path.join(folder, "local.bsl"), marked_body)
write_bsl(os.path.join(folder, "remote.bsl"), v2)
md = []
md.append("# %s" % method_id)
md.append("Править: %s" % ext_bsl)
md.append('Метод: %s (&ИзменениеИКонтроль("%s"))' % (existing_name, method["canonical"]))
md.append("Причина: %s" % conflict_reason(disputed))
md.append("")
md.append("## Не размещено — перенести в метод вручную")
for d in disputed:
if d["kind"] == "insert":
md.append("#Вставка"); md.extend(d["lines"]); md.append("#КонецВставки")
else:
md.append("// не удалось найти для удаления:")
for l in d["lines"]:
md.append("// " + l.strip())
md.append("")
md.append("## Дифф base→remote (что изменилось в оригинале)")
for l in v1:
if normalize(l) not in v2norm:
md.append("- " + l)
for l in v2:
if normalize(l) not in v1norm:
md.append("+ " + l)
md.append("")
md.append("Рядом: base.bsl / local.bsl / remote.bsl")
write_bsl(os.path.join(folder, "conflict.md"), md)
def resync_one(ext_bsl, ext_lines, dup, method, logical_module, conflict_folder, report_only):
method_id = "%s.%s" % (logical_module, method["canonical"])
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)
m0 = name_re.match(ext_lines[sig_line_idx]) if sig_line_idx < len(ext_lines) else None
if not m0:
return {"id": method_id, "status": "ОШИБКА", "ext_bsl": ext_bsl, "reason": "не разобрать сигнатуру перехватчика"}
existing_name = m0.group(1)
sig = read_signature(ext_lines, sig_line_idx)
if not sig:
die("Не удалось разобрать сигнатуру существующего перехватчика")
return {"id": method_id, "status": "ОШИБКА", "ext_bsl": ext_bsl, "reason": "не разобрать сигнатуру"}
_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)
@@ -707,29 +910,18 @@ def resync(ext_bsl, ext_lines, dup, method, method_name, module_path):
block_end = j
break
if block_end < 0:
die("Не найден конец существующего перехватчика")
return {"id": method_id, "status": "ОШИБКА", "ext_bsl": ext_bsl, "reason": "не найден конец перехватчика"}
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"]
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 = []
transferred = [] # for the summary: {"kind", "anchor"}
return {"id": method_id, "status": "АКТУАЛЕН", "ext_bsl": ext_bsl}
insert_top = []; insert_after = {}; del_start = set(); del_end = set(); disputed = []; transferred = 0
for op in ops:
if op["kind"] == "insert":
after = op["after"]
@@ -739,26 +931,25 @@ def resync(ext_bsl, ext_lines, dup, method, method_name, module_path):
if k is None:
disputed.append({"kind": "insert", "lines": op["lines"]})
elif k < 0:
insert_top.append(op["lines"])
transferred.append({"kind": "insert", "anchor": "(в начало метода)"})
insert_top.append(op["lines"]); transferred += 1
else:
insert_after.setdefault(k, []).append(op["lines"])
transferred.append({"kind": "insert", "anchor": v2[k]})
insert_after.setdefault(k, []).append(op["lines"]); transferred += 1
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)
transferred.append({"kind": "delete", "anchor": op["lines"][0]})
del_start.add(p); del_end.add(p + len(keys) - 1); transferred += 1
else:
disputed.append({"kind": "delete", "lines": op["lines"]})
if report_only:
st = "КОНФЛИКТ" if disputed else "ДРЕЙФ"
return {"id": method_id, "status": st, "ext_bsl": ext_bsl, "transferred": transferred,
"disputed": len(disputed), "reason": conflict_reason(disputed)}
new_body = []
for blk in insert_top:
new_body.append("#Вставка")
new_body.extend(blk)
new_body.append("#КонецВставки")
new_body.append("#Вставка"); new_body.extend(blk); new_body.append("#КонецВставки")
for k in range(len(v2)):
if k in del_start:
new_body.append("#Удаление")
@@ -767,18 +958,13 @@ def resync(ext_bsl, ext_lines, dup, method, method_name, module_path):
new_body.append("#КонецУдаления")
if k in insert_after:
for blk in insert_after[k]:
new_body.append("#Вставка")
new_body.extend(blk)
new_body.append("#КонецВставки")
new_body.append("#Вставка"); new_body.extend(blk); new_body.append("#КонецВставки")
if disputed:
new_body.append("\t// [РЕСИНК-КОНФЛИКТ] перенесите блоки ниже вручную — исходный якорь изменился в новой версии оригинала.")
new_body.append("\t// Материалы для анализа см. в выводе команды (файлы base/local/remote/merged).")
new_body.append("\t// Материалы: см. index.md / conflict.md в merge-воркспейсе (путь в выводе).")
for d in disputed:
if d["kind"] == "insert":
new_body.append("#Вставка")
new_body.extend(d["lines"])
new_body.append("#КонецВставки")
new_body.append("#Вставка"); new_body.extend(d["lines"]); new_body.append("#КонецВставки")
else:
new_body.append("\t// [РЕСИНК-КОНФЛИКТ] не удалось найти для удаления:")
for l in d["lines"]:
@@ -798,48 +984,36 @@ def resync(ext_bsl, ext_lines, dup, method, method_name, module_path):
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:])
out = list(ext_lines[:block_start]) + new_block + list(ext_lines[block_end + 1:])
write_bsl(ext_bsl, out)
def print_transfer_summary(items):
for t in items:
if t["kind"] == "insert":
print(" • вставка после «%s»" % truncate(t["anchor"]))
else:
print(" • удаление «%s»" % truncate(t["anchor"]))
conflict_dir = None
if disputed:
# merge workspace (git-mergetool convention: base/local/remote/merged)
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, "base.bsl"), v1)
write_bsl(os.path.join(tmp_root, "local.bsl"), marked_body)
write_bsl(os.path.join(tmp_root, "remote.bsl"), v2)
write_bsl(os.path.join(tmp_root, "merged.bsl"), new_block)
diff = ["--- base -> remote (что изменилось в оригинале) ---"]
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)
conflict_dir = conflict_folder
write_conflict_folder(conflict_folder, method_id, ext_bsl, existing_name, method, v1, marked_body, v2, v1norm, v2norm, disputed)
status = "ЧАСТИЧНО" if disputed else "АКТУАЛИЗИРОВАН"
return {"id": method_id, "status": status, "ext_bsl": ext_bsl, "transferred": transferred,
"disputed": len(disputed), "conflict_dir": conflict_dir, "reason": conflict_reason(disputed)}
print('[АКТУАЛИЗИРОВАН-ЧАСТИЧНО] &ИзменениеИКонтроль("%s") — перенесено: %d, конфликтов: %d'
% (method_name, len(transferred), len(disputed)))
print_transfer_summary(transferred)
print(" Конфликтные блоки помечены // [РЕСИНК-КОНФЛИКТ] — разместите вручную.")
print(" Merge-воркспейс (base/local/remote/merged/diff):")
print(" %s" % tmp_root)
else:
print('[АКТУАЛИЗИРОВАН] &ИзменениеИКонтроль("%s") — тело обновлено, перенесено правок: %d'
% (method_name, len(transferred)))
print_transfer_summary(transferred)
print(" Файл: %s" % ext_bsl)
def write_resync_index(run_root, results, ext_name, config_path, verb):
conflicts = [r for r in results if r["status"] == "ЧАСТИЧНО"]
if not conflicts:
return None
os.makedirs(run_root, exist_ok=True)
total = len(results)
actual = sum(1 for r in results if r["status"] == "АКТУАЛЕН")
upd = sum(1 for r in results if r["status"] == "АКТУАЛИЗИРОВАН")
lines = []
lines.append("[%s] %s -> %s" % (verb, ext_name, config_path))
lines.append("Итог: %d/%d актуальны · %d актуализировано · %d конфликтов" % (actual, total, upd, len(conflicts)))
lines.append("")
lines.append("Конфликты — править .bsl расширения:")
for c in conflicts:
lines.append(" ЧАСТИЧНО %s" % c["id"])
lines.append(" -> %s (%s)" % (c["ext_bsl"], c.get("reason", "")))
write_bsl(os.path.join(run_root, "index.md"), lines)
return run_root
if __name__ == "__main__":
@@ -930,6 +930,17 @@ if ($script:borrowedFormsWithTree.Count -eq 0) {
Report-OK "13. TypeLink: clean"
}
# --- Breadcrumb: controlled methods (&ИзменениеИКонтроль) drift is not checked here ---
$extRootDir = Split-Path $resolvedPath -Parent
$ctrlCount = 0
foreach ($bslFile in (Get-ChildItem -Path $extRootDir -Recurse -Filter *.bsl -File -ErrorAction SilentlyContinue)) {
$txt = [System.IO.File]::ReadAllText($bslFile.FullName, [System.Text.Encoding]::UTF8)
$ctrlCount += ([regex]::Matches($txt, '(?m)^\s*&ИзменениеИКонтроль\(')).Count
}
if ($ctrlCount -gt 0) {
Out-Line "[INFO] Контролируемых методов (&ИзменениеИКонтроль): $ctrlCount — их актуальность здесь не проверяется. Сверьте: /cfe-patch-method -Check -ExtensionPath <ext> -ConfigPath <cf>"
}
# --- Final output ---
& $finalize
@@ -885,6 +885,21 @@ def main():
elif check13_ok:
r.ok('13. TypeLink: clean')
# --- Breadcrumb: controlled methods (&ИзменениеИКонтроль) drift is not checked here ---
ctrl_count = 0
for dp, _dn, files in os.walk(config_dir):
for fn in files:
if fn.endswith('.bsl'):
try:
with open(os.path.join(dp, fn), 'r', encoding='utf-8-sig') as f:
for ln in f:
if re.match(r'^\s*&ИзменениеИКонтроль\(', ln):
ctrl_count += 1
except OSError:
pass
if ctrl_count > 0:
r.out('[INFO] Контролируемых методов (&ИзменениеИКонтроль): %d — их актуальность здесь не проверяется. Сверьте: /cfe-patch-method -Check -ExtensionPath <ext> -ConfigPath <cf>' % ctrl_count)
# --- Final output ---
r.finalize(out_file)
sys.exit(1 if r.errors > 0 else 0)
@@ -0,0 +1,33 @@
{
"name": "-Actualize: батч по всему расширению — дрейф чинится авто",
"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Х = 1;\n\tВозврат Х;\nКонецФункции\n\nФункция РасчётБ() Экспорт\n\tY = 2;\n\tW = 5;\n\tВозврат Y;\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Х = 1;\n\tВозврат Х;\nКонецФункции\n&ИзменениеИКонтроль(\"РасчётБ\")\nФункция Тест_РасчётБ()\n\tY = 2;\n\tВозврат Y;\nКонецФункции\n#КонецОбласти\n"
}
}
],
"params": { "extensionPath": "ext" },
"args_extra": ["-Actualize"],
"expect": { "stdoutContains": "1 актуализировано" }
}
@@ -0,0 +1,33 @@
{
"name": "-Check: все контролируемые методы актуальны (exit 0)",
"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Х = 1;\n\tВозврат Х;\nКонецФункции\n\nФункция РасчётБ() Экспорт\n\tY = 2;\n\tВозврат Y;\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Х = 1;\n\tВозврат Х;\nКонецФункции\n&ИзменениеИКонтроль(\"РасчётБ\")\nФункция Тест_РасчётБ()\n\tY = 2;\n\tВозврат Y;\nКонецФункции\n#КонецОбласти\n"
}
}
],
"params": { "extensionPath": "ext" },
"args_extra": ["-Check"],
"expect": { "stdoutContains": "2/2 актуальны" }
}
@@ -0,0 +1,33 @@
{
"name": "-Check: дрейф контролируемого метода (exit 1, ничего не пишет)",
"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Х = 1;\n\tВозврат Х;\nКонецФункции\n\nФункция РасчётБ() Экспорт\n\tY = 2;\n\tW = 5;\n\tВозврат Y;\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Х = 1;\n\tВозврат Х;\nКонецФункции\n&ИзменениеИКонтроль(\"РасчётБ\")\nФункция Тест_РасчётБ()\n\tY = 2;\n\tВозврат Y;\nКонецФункции\n#КонецОбласти\n"
}
}
],
"params": { "extensionPath": "ext" },
"args_extra": ["-Check"],
"expectError": true
}
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<CommonModule uuid="UUID-001">
<Properties>
<Name>БатчМод</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Батч мод</v8:content>
</v8:item>
</Synonym>
<Comment/>
<Global>false</Global>
<ClientManagedApplication>false</ClientManagedApplication>
<Server>false</Server>
<ExternalConnection>false</ExternalConnection>
<ClientOrdinaryApplication>false</ClientOrdinaryApplication>
<ServerCall>false</ServerCall>
<Privileged>false</Privileged>
<ReturnValuesReuse>DontUse</ReturnValuesReuse>
</Properties>
</CommonModule>
</MetaDataObject>
@@ -0,0 +1,14 @@
#Область ПрограммныйИнтерфейс
Функция РасчётА() Экспорт
Х = 1;
Возврат Х;
КонецФункции
Функция РасчётБ() Экспорт
Y = 2;
W = 5;
Возврат Y;
КонецФункции
#КонецОбласти
@@ -0,0 +1,252 @@
<?xml version="1.0" encoding="utf-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Configuration uuid="UUID-001">
<InternalInfo>
<xr:ContainedObject>
<xr:ClassId>UUID-002</xr:ClassId>
<xr:ObjectId>UUID-003</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-004</xr:ClassId>
<xr:ObjectId>UUID-005</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-006</xr:ClassId>
<xr:ObjectId>UUID-007</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-008</xr:ClassId>
<xr:ObjectId>UUID-009</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-010</xr:ClassId>
<xr:ObjectId>UUID-011</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-012</xr:ClassId>
<xr:ObjectId>UUID-013</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-014</xr:ClassId>
<xr:ObjectId>UUID-015</xr:ObjectId>
</xr:ContainedObject>
</InternalInfo>
<Properties>
<Name>TestConfig</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>TestConfig</v8:content>
</v8:item>
</Synonym>
<Comment />
<NamePrefix />
<ConfigurationExtensionCompatibilityMode>Version8_3_24</ConfigurationExtensionCompatibilityMode>
<DefaultRunMode>ManagedApplication</DefaultRunMode>
<UsePurposes>
<v8:Value xsi:type="app:ApplicationUsePurpose">PlatformApplication</v8:Value>
</UsePurposes>
<ScriptVariant>Russian</ScriptVariant>
<DefaultRoles />
<Vendor></Vendor>
<Version></Version>
<UpdateCatalogAddress />
<IncludeHelpInContents>false</IncludeHelpInContents>
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
<UseOrdinaryFormInManagedApplication>false</UseOrdinaryFormInManagedApplication>
<AdditionalFullTextSearchDictionaries />
<CommonSettingsStorage />
<ReportsUserSettingsStorage />
<ReportsVariantsStorage />
<FormDataSettingsStorage />
<DynamicListsUserSettingsStorage />
<URLExternalDataStorage />
<Content />
<DefaultReportForm />
<DefaultReportVariantForm />
<DefaultReportSettingsForm />
<DefaultReportAppearanceTemplate />
<DefaultDynamicListSettingsForm />
<DefaultSearchForm />
<DefaultDataHistoryChangeHistoryForm />
<DefaultDataHistoryVersionDataForm />
<DefaultDataHistoryVersionDifferencesForm />
<DefaultCollaborationSystemUsersChoiceForm />
<RequiredMobileApplicationPermissions />
<UsedMobileApplicationFunctionalities>
<app:functionality>
<app:functionality>Biometrics</app:functionality>
<app:use>true</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Location</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BackgroundLocation</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BluetoothPrinters</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>WiFiPrinters</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Contacts</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Calendars</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>PushNotifications</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>LocalNotifications</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>InAppPurchases</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>PersonalComputerFileExchange</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Ads</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>NumberDialing</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>CallProcessing</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>CallLog</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AutoSendSMS</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>ReceiveSMS</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>SMSLog</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Camera</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Microphone</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>MusicLibrary</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>PictureAndVideoLibraries</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AudioPlaybackAndVibration</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BackgroundAudioPlaybackAndVibration</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>InstallPackages</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>OSBackup</app:functionality>
<app:use>true</app:use>
</app:functionality>
<app:functionality>
<app:functionality>ApplicationUsageStatistics</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BarcodeScanning</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BackgroundAudioRecording</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AllFilesAccess</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Videoconferences</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>NFC</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>DocumentScanning</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>SpeechToText</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Geofences</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>IncomingShareRequests</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AllIncomingShareRequestsTypesProcessing</app:functionality>
<app:use>false</app:use>
</app:functionality>
</UsedMobileApplicationFunctionalities>
<StandaloneConfigurationRestrictionRoles />
<MobileApplicationURLs />
<AllowedIncomingShareRequestTypes />
<MainClientApplicationWindowMode>Normal</MainClientApplicationWindowMode>
<DefaultInterface />
<DefaultStyle />
<DefaultLanguage>Language.Русский</DefaultLanguage>
<BriefInformation />
<DetailedInformation />
<Copyright />
<VendorInformationAddress />
<ConfigurationInformationAddress />
<DataLockControlMode>Managed</DataLockControlMode>
<ObjectAutonumerationMode>NotAutoFree</ObjectAutonumerationMode>
<ModalityUseMode>DontUse</ModalityUseMode>
<SynchronousPlatformExtensionAndAddInCallUseMode>DontUse</SynchronousPlatformExtensionAndAddInCallUseMode>
<InterfaceCompatibilityMode>TaxiEnableVersion8_2</InterfaceCompatibilityMode>
<DatabaseTablespacesUseMode>DontUse</DatabaseTablespacesUseMode>
<CompatibilityMode>Version8_3_24</CompatibilityMode>
<DefaultConstantsForm />
</Properties>
<ChildObjects>
<Language>Русский</Language>
<CommonModule>БатчМод</CommonModule>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<ClientApplicationInterface xmlns="http://v8.1c.ru/8.2/managed-application/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="InterfaceLayouter">
<top>
<panel id="UUID-001">
<uuid>UUID-002</uuid>
</panel>
</top>
<left>
<panel id="UUID-003">
<uuid>UUID-004</uuid>
</panel>
</left>
<panelDef id="UUID-004"/>
<panelDef id="UUID-005"/>
<panelDef id="UUID-006"/>
<panelDef id="UUID-002"/>
<panelDef id="UUID-007"/>
</ClientApplicationInterface>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<CommonModule uuid="UUID-001">
<InternalInfo/>
<Properties>
<ObjectBelonging>Adopted</ObjectBelonging>
<Name>БатчМод</Name>
<Comment/>
<ExtendedConfigurationObject>UUID-002</ExtendedConfigurationObject>
<Global>false</Global>
<ClientManagedApplication>false</ClientManagedApplication>
<Server>false</Server>
<ExternalConnection>false</ExternalConnection>
<ClientOrdinaryApplication>false</ClientOrdinaryApplication>
<ServerCall>false</ServerCall>
</Properties>
</CommonModule>
</MetaDataObject>
@@ -0,0 +1,13 @@
#Область ПрограммныйИнтерфейс
&ИзменениеИКонтроль("РасчётА")
Функция Тест_РасчётА()
Х = 1;
Возврат Х;
КонецФункции
&ИзменениеИКонтроль("РасчётБ")
Функция Тест_РасчётБ()
Y = 2;
W = 5;
Возврат Y;
КонецФункции
#КонецОбласти
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Configuration uuid="UUID-001">
<InternalInfo>
<xr:ContainedObject>
<xr:ClassId>UUID-002</xr:ClassId>
<xr:ObjectId>UUID-003</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-004</xr:ClassId>
<xr:ObjectId>UUID-005</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-006</xr:ClassId>
<xr:ObjectId>UUID-007</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-008</xr:ClassId>
<xr:ObjectId>UUID-009</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-010</xr:ClassId>
<xr:ObjectId>UUID-011</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-012</xr:ClassId>
<xr:ObjectId>UUID-013</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-014</xr:ClassId>
<xr:ObjectId>UUID-015</xr:ObjectId>
</xr:ContainedObject>
</InternalInfo>
<Properties>
<ObjectBelonging>Adopted</ObjectBelonging>
<Name>Тест</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Тест</v8:content>
</v8:item>
</Synonym>
<Comment />
<ConfigurationExtensionPurpose>Customization</ConfigurationExtensionPurpose>
<KeepMappingToExtendedConfigurationObjectsByIDs>true</KeepMappingToExtendedConfigurationObjectsByIDs>
<NamePrefix>Тест_</NamePrefix>
<ConfigurationExtensionCompatibilityMode>Version8_3_24</ConfigurationExtensionCompatibilityMode>
<DefaultRunMode>ManagedApplication</DefaultRunMode>
<UsePurposes>
<v8:Value xsi:type="app:ApplicationUsePurpose">PlatformApplication</v8:Value>
</UsePurposes>
<ScriptVariant>Russian</ScriptVariant>
<DefaultRoles>
<xr:Item xsi:type="xr:MDObjectRef">Role.Тест_ОсновнаяРоль</xr:Item>
</DefaultRoles>
<Vendor></Vendor>
<Version></Version>
<DefaultLanguage>Language.Русский</DefaultLanguage>
<BriefInformation />
<DetailedInformation />
<Copyright />
<VendorInformationAddress />
<ConfigurationInformationAddress />
<InterfaceCompatibilityMode>TaxiEnableVersion8_2</InterfaceCompatibilityMode>
</Properties>
<ChildObjects>
<Language>Русский</Language>
<Role>Тест_ОсновнаяРоль</Role>
<CommonModule>БатчМод</CommonModule>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Language uuid="UUID-001">
<InternalInfo/>
<Properties>
<ObjectBelonging>Adopted</ObjectBelonging>
<Name>Русский</Name>
<Comment/>
<ExtendedConfigurationObject>UUID-002</ExtendedConfigurationObject>
<LanguageCode>ru</LanguageCode>
</Properties>
</Language>
</MetaDataObject>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Role uuid="UUID-001">
<Properties>
<Name>Тест_ОсновнаяРоль</Name>
<Synonym/>
<Comment/>
</Properties>
</Role>
</MetaDataObject>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Language uuid="UUID-001">
<Properties>
<Name>Русский</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Русский</v8:content>
</v8:item>
</Synonym>
<Comment/>
<LanguageCode>ru</LanguageCode>
</Properties>
</Language>
</MetaDataObject>
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<CommonModule uuid="UUID-001">
<Properties>
<Name>БатчМод</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Батч мод</v8:content>
</v8:item>
</Synonym>
<Comment/>
<Global>false</Global>
<ClientManagedApplication>false</ClientManagedApplication>
<Server>false</Server>
<ExternalConnection>false</ExternalConnection>
<ClientOrdinaryApplication>false</ClientOrdinaryApplication>
<ServerCall>false</ServerCall>
<Privileged>false</Privileged>
<ReturnValuesReuse>DontUse</ReturnValuesReuse>
</Properties>
</CommonModule>
</MetaDataObject>
@@ -0,0 +1,13 @@
#Область ПрограммныйИнтерфейс
Функция РасчётА() Экспорт
Х = 1;
Возврат Х;
КонецФункции
Функция РасчётБ() Экспорт
Y = 2;
Возврат Y;
КонецФункции
#КонецОбласти
@@ -0,0 +1,252 @@
<?xml version="1.0" encoding="utf-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Configuration uuid="UUID-001">
<InternalInfo>
<xr:ContainedObject>
<xr:ClassId>UUID-002</xr:ClassId>
<xr:ObjectId>UUID-003</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-004</xr:ClassId>
<xr:ObjectId>UUID-005</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-006</xr:ClassId>
<xr:ObjectId>UUID-007</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-008</xr:ClassId>
<xr:ObjectId>UUID-009</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-010</xr:ClassId>
<xr:ObjectId>UUID-011</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-012</xr:ClassId>
<xr:ObjectId>UUID-013</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-014</xr:ClassId>
<xr:ObjectId>UUID-015</xr:ObjectId>
</xr:ContainedObject>
</InternalInfo>
<Properties>
<Name>TestConfig</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>TestConfig</v8:content>
</v8:item>
</Synonym>
<Comment />
<NamePrefix />
<ConfigurationExtensionCompatibilityMode>Version8_3_24</ConfigurationExtensionCompatibilityMode>
<DefaultRunMode>ManagedApplication</DefaultRunMode>
<UsePurposes>
<v8:Value xsi:type="app:ApplicationUsePurpose">PlatformApplication</v8:Value>
</UsePurposes>
<ScriptVariant>Russian</ScriptVariant>
<DefaultRoles />
<Vendor></Vendor>
<Version></Version>
<UpdateCatalogAddress />
<IncludeHelpInContents>false</IncludeHelpInContents>
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
<UseOrdinaryFormInManagedApplication>false</UseOrdinaryFormInManagedApplication>
<AdditionalFullTextSearchDictionaries />
<CommonSettingsStorage />
<ReportsUserSettingsStorage />
<ReportsVariantsStorage />
<FormDataSettingsStorage />
<DynamicListsUserSettingsStorage />
<URLExternalDataStorage />
<Content />
<DefaultReportForm />
<DefaultReportVariantForm />
<DefaultReportSettingsForm />
<DefaultReportAppearanceTemplate />
<DefaultDynamicListSettingsForm />
<DefaultSearchForm />
<DefaultDataHistoryChangeHistoryForm />
<DefaultDataHistoryVersionDataForm />
<DefaultDataHistoryVersionDifferencesForm />
<DefaultCollaborationSystemUsersChoiceForm />
<RequiredMobileApplicationPermissions />
<UsedMobileApplicationFunctionalities>
<app:functionality>
<app:functionality>Biometrics</app:functionality>
<app:use>true</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Location</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BackgroundLocation</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BluetoothPrinters</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>WiFiPrinters</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Contacts</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Calendars</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>PushNotifications</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>LocalNotifications</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>InAppPurchases</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>PersonalComputerFileExchange</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Ads</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>NumberDialing</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>CallProcessing</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>CallLog</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AutoSendSMS</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>ReceiveSMS</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>SMSLog</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Camera</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Microphone</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>MusicLibrary</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>PictureAndVideoLibraries</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AudioPlaybackAndVibration</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BackgroundAudioPlaybackAndVibration</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>InstallPackages</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>OSBackup</app:functionality>
<app:use>true</app:use>
</app:functionality>
<app:functionality>
<app:functionality>ApplicationUsageStatistics</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BarcodeScanning</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BackgroundAudioRecording</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AllFilesAccess</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Videoconferences</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>NFC</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>DocumentScanning</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>SpeechToText</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Geofences</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>IncomingShareRequests</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AllIncomingShareRequestsTypesProcessing</app:functionality>
<app:use>false</app:use>
</app:functionality>
</UsedMobileApplicationFunctionalities>
<StandaloneConfigurationRestrictionRoles />
<MobileApplicationURLs />
<AllowedIncomingShareRequestTypes />
<MainClientApplicationWindowMode>Normal</MainClientApplicationWindowMode>
<DefaultInterface />
<DefaultStyle />
<DefaultLanguage>Language.Русский</DefaultLanguage>
<BriefInformation />
<DetailedInformation />
<Copyright />
<VendorInformationAddress />
<ConfigurationInformationAddress />
<DataLockControlMode>Managed</DataLockControlMode>
<ObjectAutonumerationMode>NotAutoFree</ObjectAutonumerationMode>
<ModalityUseMode>DontUse</ModalityUseMode>
<SynchronousPlatformExtensionAndAddInCallUseMode>DontUse</SynchronousPlatformExtensionAndAddInCallUseMode>
<InterfaceCompatibilityMode>TaxiEnableVersion8_2</InterfaceCompatibilityMode>
<DatabaseTablespacesUseMode>DontUse</DatabaseTablespacesUseMode>
<CompatibilityMode>Version8_3_24</CompatibilityMode>
<DefaultConstantsForm />
</Properties>
<ChildObjects>
<Language>Русский</Language>
<CommonModule>БатчМод</CommonModule>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<ClientApplicationInterface xmlns="http://v8.1c.ru/8.2/managed-application/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="InterfaceLayouter">
<top>
<panel id="UUID-001">
<uuid>UUID-002</uuid>
</panel>
</top>
<left>
<panel id="UUID-003">
<uuid>UUID-004</uuid>
</panel>
</left>
<panelDef id="UUID-004"/>
<panelDef id="UUID-005"/>
<panelDef id="UUID-006"/>
<panelDef id="UUID-002"/>
<panelDef id="UUID-007"/>
</ClientApplicationInterface>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<CommonModule uuid="UUID-001">
<InternalInfo/>
<Properties>
<ObjectBelonging>Adopted</ObjectBelonging>
<Name>БатчМод</Name>
<Comment/>
<ExtendedConfigurationObject>UUID-002</ExtendedConfigurationObject>
<Global>false</Global>
<ClientManagedApplication>false</ClientManagedApplication>
<Server>false</Server>
<ExternalConnection>false</ExternalConnection>
<ClientOrdinaryApplication>false</ClientOrdinaryApplication>
<ServerCall>false</ServerCall>
</Properties>
</CommonModule>
</MetaDataObject>
@@ -0,0 +1,12 @@
#Область ПрограммныйИнтерфейс
&ИзменениеИКонтроль("РасчётА")
Функция Тест_РасчётА()
Х = 1;
Возврат Х;
КонецФункции
&ИзменениеИКонтроль("РасчётБ")
Функция Тест_РасчётБ()
Y = 2;
Возврат Y;
КонецФункции
#КонецОбласти
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Configuration uuid="UUID-001">
<InternalInfo>
<xr:ContainedObject>
<xr:ClassId>UUID-002</xr:ClassId>
<xr:ObjectId>UUID-003</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-004</xr:ClassId>
<xr:ObjectId>UUID-005</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-006</xr:ClassId>
<xr:ObjectId>UUID-007</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-008</xr:ClassId>
<xr:ObjectId>UUID-009</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-010</xr:ClassId>
<xr:ObjectId>UUID-011</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-012</xr:ClassId>
<xr:ObjectId>UUID-013</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-014</xr:ClassId>
<xr:ObjectId>UUID-015</xr:ObjectId>
</xr:ContainedObject>
</InternalInfo>
<Properties>
<ObjectBelonging>Adopted</ObjectBelonging>
<Name>Тест</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Тест</v8:content>
</v8:item>
</Synonym>
<Comment />
<ConfigurationExtensionPurpose>Customization</ConfigurationExtensionPurpose>
<KeepMappingToExtendedConfigurationObjectsByIDs>true</KeepMappingToExtendedConfigurationObjectsByIDs>
<NamePrefix>Тест_</NamePrefix>
<ConfigurationExtensionCompatibilityMode>Version8_3_24</ConfigurationExtensionCompatibilityMode>
<DefaultRunMode>ManagedApplication</DefaultRunMode>
<UsePurposes>
<v8:Value xsi:type="app:ApplicationUsePurpose">PlatformApplication</v8:Value>
</UsePurposes>
<ScriptVariant>Russian</ScriptVariant>
<DefaultRoles>
<xr:Item xsi:type="xr:MDObjectRef">Role.Тест_ОсновнаяРоль</xr:Item>
</DefaultRoles>
<Vendor></Vendor>
<Version></Version>
<DefaultLanguage>Language.Русский</DefaultLanguage>
<BriefInformation />
<DetailedInformation />
<Copyright />
<VendorInformationAddress />
<ConfigurationInformationAddress />
<InterfaceCompatibilityMode>TaxiEnableVersion8_2</InterfaceCompatibilityMode>
</Properties>
<ChildObjects>
<Language>Русский</Language>
<Role>Тест_ОсновнаяРоль</Role>
<CommonModule>БатчМод</CommonModule>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Language uuid="UUID-001">
<InternalInfo/>
<Properties>
<ObjectBelonging>Adopted</ObjectBelonging>
<Name>Русский</Name>
<Comment/>
<ExtendedConfigurationObject>UUID-002</ExtendedConfigurationObject>
<LanguageCode>ru</LanguageCode>
</Properties>
</Language>
</MetaDataObject>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Role uuid="UUID-001">
<Properties>
<Name>Тест_ОсновнаяРоль</Name>
<Synonym/>
<Comment/>
</Properties>
</Role>
</MetaDataObject>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Language uuid="UUID-001">
<Properties>
<Name>Русский</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Русский</v8:content>
</v8:item>
</Synonym>
<Comment/>
<LanguageCode>ru</LanguageCode>
</Properties>
</Language>
</MetaDataObject>
@@ -3,7 +3,7 @@
Функция Тест_Расчёт(А, Б)
Возврат 0;
// [РЕСИНК-КОНФЛИКТ] перенесите блоки ниже вручную — исходный якорь изменился в новой версии оригинала.
// Материалы для анализа см. в выводе команды (файлы base/local/remote/merged).
// Материалы: см. index.md / conflict.md в merge-воркспейсе (путь в выводе).
#Вставка
Итог = Итог + Б;
#КонецВставки