# cf-init v1.14 — Create empty 1C configuration scaffold (+write_xml_file/write_utf8_bom: общий эталон записи) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] [string]$Name, [string]$Synonym = $Name, [string]$OutputDir = "src", [string]$Version, [string]$Vendor, [string]$CompatibilityMode = "Version8_3_24", # Версия формата выгрузки (MDClasses). Её задаёт ПЛАТФОРМА, которой выгружают, и от режима # совместимости она не зависит. Дефолт 2.17 — нижняя граница проверенного диапазона. [string]$FormatVersion = "2.17" ) $ErrorActionPreference = "Stop" # --- Format version --- # Проверенный диапазон: 2.17 (8.3.24) … 2.21 (8.5). Полная лестница — docs/1c-configuration-spec.md, # «Лестница версий». Версии ниже 2.17 (платформы 8.3.23 и старше) реальны, поэтому запретом их не # закрываем: за пределами диапазона — ПРЕДУПРЕЖДЕНИЕ, скаффолд всё равно выпускается. Ошибка — только # на нечисловое значение: это опечатка, а не версия. $formatVerifiedMin = "2.17" $formatVerifiedMax = "2.21" # Версия формата как число: "2.20" → 220. Строковое сравнение неверно ("2.9" > "2.17"). function Get-FormatRank([string]$ver) { if ($ver -match '^(\d+)\.(\d+)$') { return [int]$Matches[1] * 100 + [int]$Matches[2] } return 0 } $formatRank = Get-FormatRank $FormatVersion function Esc-XmlText { param([string]$s) # Эскейп ТЕКСТА элемента: только & < > — кавычку и апостроф платформа держит сырыми. return $s.Replace('&','&').Replace('<','<').Replace('>','>') } [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 # Проверка версии — ПОСЛЕ настройки кодировки консоли: иначе em-dash в сообщении уедет в вопросы. # Пишем прямо в stderr, а не Write-Warning: в PS 5.1 предупреждение уходит в stdout, получает # локализованный префикс и переносится по 80 символов — подстрока в тесте перестаёт находиться. if ($formatRank -eq 0) { [Console]::Error.WriteLine("Malformed -FormatVersion '$FormatVersion' (expected N.N, e.g. 2.17)") exit 1 } if ($formatRank -lt (Get-FormatRank $formatVerifiedMin) -or $formatRank -gt (Get-FormatRank $formatVerifiedMax)) { [Console]::Error.WriteLine("WARNING: Format version '$FormatVersion' is outside the tested range $formatVerifiedMin-$formatVerifiedMax — the scaffold is emitted as requested but was not verified on that platform") } # «Не использовать» в Конфигураторе хранится как версия ТЕКУЩЕЙ платформы, а не как DontUse: # свежая база получает Version8_3_<своя>, и ни одна типовая в корпусе DontUse не содержит. # Само значение легально — платформа принимает его без ошибок, — но не выживает: замерено на # 8.3.25 и 8.3.27, выгрузка обоих возвращает Version8_3_8. Поэтому предупреждение, а не запрет. # Сравнение регистронезависимо ЯВНО: в PS -eq таков по умолчанию, в py — нет, и молчаливое # расхождение портов началось бы прямо здесь. if ($CompatibilityMode -and $CompatibilityMode.ToLowerInvariant() -eq 'dontuse') { [Console]::Error.WriteLine("WARNING: CompatibilityMode 'DontUse' is not `"no restrictions`" — the platform stores it as Version8_3_8. For no compatibility restrictions use the target platform version (e.g. Version8_3_27 for 8.3.27).") } # --- Resolve output dir --- if (-not [System.IO.Path]::IsPathRooted($OutputDir)) { $OutputDir = Join-Path (Get-Location).Path $OutputDir } # --- Check existing --- $cfgFile = Join-Path $OutputDir "Configuration.xml" if (Test-Path $cfgFile) { Write-Error "Configuration.xml already exists: $cfgFile" exit 1 } # --- Generate UUIDs --- $uuidCfg = [guid]::NewGuid().ToString() $uuidLang = [guid]::NewGuid().ToString() # 7 ContainedObject ObjectIds $co1 = [guid]::NewGuid().ToString() $co2 = [guid]::NewGuid().ToString() $co3 = [guid]::NewGuid().ToString() $co4 = [guid]::NewGuid().ToString() $co5 = [guid]::NewGuid().ToString() $co6 = [guid]::NewGuid().ToString() $co7 = [guid]::NewGuid().ToString() # --- Mobile functionalities --- # Версия формата как число — по ней ниже включаются вставки 2.21. $is221 = ($formatRank -ge 221) # TextToSpeech приехал раньше остальных вставок 8.5 — своей ступенью, поэтому гейт отдельный. $is218 = ($formatRank -ge 218) $mobileFuncs = @( @("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") ) # TextToSpeech — возможность мобильного приложения, добавленная форматом 2.18 (8.3.25), # последней в списке; в 2.21 список не менялся. Замерено выгрузками пустой ИБ шести платформ: # 2.13/2.17 — 37 записей без неё, 2.18-2.21 — 38 с ней. Гейт обязателен и в обе стороны: # на 2.17 тег ломает загрузку XDTO-ошибкой (проверено на 8.3.24), без тега на 2.18+ платформа # подставит дефолт false и допишет его при выгрузке — то есть разойдётся роундтрип. if ($is218) { $mobileFuncs += ,@("TextToSpeech","false") } $mobileXml = "" foreach ($mf in $mobileFuncs) { $mobileXml += "`r`n`t`t`t`t`r`n`t`t`t`t`t$($mf[0])`r`n`t`t`t`t`t$($mf[1])`r`n`t`t`t`t" } # --- Synonym XML --- $synonymXml = "" if ($Synonym) { $synonymXml = "`r`n`t`t`t`t`r`n`t`t`t`t`tru`r`n`t`t`t`t`t$(Esc-XmlText ($Synonym))`r`n`t`t`t`t`r`n`t`t`t" } # --- Optional properties --- # Элемент целиком, а не значение внутри пары: при пустом значении Конфигуратор # пишет , а не . $vendorEl = if ($Vendor) { "$(Esc-XmlText ($Vendor))" } else { "" } $versionEl = if ($Version) { "$(Esc-XmlText ($Version))" } else { "" } # --- Свойства и пространство имён формата 2.21 (платформа 8.5) --- # Значения и ПОЗИЦИИ сняты с выгрузки 8.5.1 (debug/fmt221/dump_v851): те же исходники, # выгруженные с 8.3.27 и с 8.5.1, различаются ровно этим. Порядок важен — вставки идут # на своё место, а не в конец. $nl = "`r`n" $f221AuxForms = ""; $f221WindowVariant = ""; $f221OpenVariant = ""; $f221Captions = ""; $f221Migration = "" $palNs = "" if ($is221) { $palNs = ' xmlns:pal="http://v8.1c.ru/8.1/data/ui/colors/palette"' # Скобки вокруг -join обязательны: без них `$nl + (массив) -join $nl` разбирается как # `($nl + массив) -join $nl`, массив склеивается пробелами и все теги уезжают в одну строку. $f221AuxForms = $nl + ((@( "", "", "", "", "", "", "", "" ) | ForEach-Object { "`t`t`t$_" }) -join $nl) $f221WindowVariant = $nl + "`t`t`tNavigationLeft" + $nl + "`t`t`tAuto" $f221OpenVariant = $nl + "`t`t`tOpenDataInDialogs" $f221Captions = $nl + "`t`t`t" + $nl + "`t`t`t" $f221Migration = $nl + "`t`t`tDontUse" } # --- Configuration.xml --- $cfgXml = @" 9cd510cd-abfc-11d4-9434-004095e12fc7 $co1 9fcd25a0-4822-11d4-9414-008048da11f9 $co2 e3687481-0a87-462c-a166-9f34594f9bba $co3 9de14907-ec23-4a07-96f0-85521cb6b53b $co4 51f2d5d8-ea4d-4064-8892-82951750031e $co5 e68182ea-4237-4383-967f-90c1e3370bc7 $co6 fb282519-d103-4dd3-bc12-cb271d631dfc $co7 $(Esc-XmlText ($Name)) $synonymXml $CompatibilityMode ManagedApplication PlatformApplication Russian $vendorEl $versionEl false false false $f221AuxForms $mobileXml $f221WindowVariant Normal$f221OpenVariant $f221Captions Language.Русский Managed NotAutoFree DontUse DontUse TaxiEnableVersion8_2$f221Migration DontUse $CompatibilityMode Русский "@ # --- Languages/Русский.xml --- $langXml = @" Русский ru Русский ru "@ # --- Ext/ClientApplicationInterface.xml (default ERP-style panel layout) --- # Open panel on top, Sections panel on left; Functions/Favorites/History declared # via panelDef but not placed by default. Without this file the web client renders # section icons without labels (icon-only mode). $openPanelInst = [guid]::NewGuid().ToString() $sectionsPanelInst = [guid]::NewGuid().ToString() $caiXml = @" cbab57f2-a0f3-4f0a-89ea-4cb19570ab75 b553047f-c9aa-4157-978d-448ecad24248 "@ # --- Create directories --- if (-not (Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null } $langDir = Join-Path $OutputDir "Languages" if (-not (Test-Path $langDir)) { New-Item -ItemType Directory -Path $langDir -Force | Out-Null } $extDir = Join-Path $OutputDir "Ext" if (-not (Test-Path $extDir)) { New-Item -ItemType Directory -Path $extDir -Force | Out-Null } # --- Write files with UTF-8 BOM --- $enc = New-Object System.Text.UTF8Encoding($true) # XML в каноне выгрузки Конфигуратора: CRLF в разделителях, без перевода в конце. # # Копия этой функции есть в каждом навыке-эмиттере (навыки автономны). Держать # копии одинаковыми — сознательно: разошедшиеся копии сводят на нет весь смысл. function Write-XmlFile([string]$path, [string]$text, $encoding) { $t = ($text -replace "`r`n", "`n") -replace "`n", "`r`n" [System.IO.File]::WriteAllText($path, $t.TrimEnd("`r", "`n"), $encoding) } Write-XmlFile $cfgFile $cfgXml $enc $langFile = Join-Path $langDir "Русский.xml" Write-XmlFile $langFile $langXml $enc $caiFile = Join-Path $extDir "ClientApplicationInterface.xml" Write-XmlFile $caiFile $caiXml $enc # --- Output --- Write-Host "[OK] Создана конфигурация: $Name" Write-Host " Каталог: $OutputDir" Write-Host " Configuration.xml: $cfgFile" Write-Host " Languages: $langFile" Write-Host " Ext/CAI: $caiFile"