mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-17 00:05:17 +03:00
feat(meta-compile,meta-decompile): HE-эвристика аббревиатур в авто-синониме + регистрочувствительный авто-вывод (v1.61/v0.52)
Корень: split_camel_case слепо лоуэркейзил хвост, теряя аббревиатуры (НДС/ЕГАИС/ОС/ЭП), которые платформа сохраняет. Вскрыто py-раундтрипом на маке (АбонентыЭДО: синоним "Абоненты ЭДО" регенерился как "эдо"). Дважды замаскировано: декомпилятор опускал синоним регистронезависимо (ne_ci), харнес Compare-Object был без -CaseSensitive. Масштаб survey: 7706. Фикс (правило подтверждено эмпирически по корпусу): сохранять максимальный прогон заглавных >=2, если сразу за ним НЕ буква (пробел/цифра/спецсимвол/конец). ">=2" ловит ОС/ЭП; граница "не буква" отсекает предлоги (РасчетыСКлиентами->склиентами) и бренды (ЮКасса). - Компилятор Split-CamelCase -> HE (ps1+py), радиус = авто-синонимы + авто-описания предопределённых. - Декомпилятор Split-CamelWords -> HE (зеркало) + регистрочувствительная страховка (-ne->-cne / ne_ci->ne_cs) в 9 точках: кастом-синонимы (ВетИС/МИР) эмитятся дословно. Валидация 8.3.24 (1765): синонимы/описания закрыты полностью, ноль case-диффов. Декомпилятор ps1==py 189/189. Регресс 511/511 ps+py. spec §2. Снэпшоты meta-compile — казинг аббревиатур. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# meta-compile v1.60 — Compile 1C metadata object from JSON
|
# meta-compile v1.61 — Compile 1C metadata object from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -421,9 +421,32 @@ function Split-CamelCase {
|
|||||||
# Insert space before uppercase that follows lowercase (Cyrillic + Latin)
|
# Insert space before uppercase that follows lowercase (Cyrillic + Latin)
|
||||||
$result = [regex]::Replace($name, '([а-яё])([А-ЯЁ])', '$1 $2')
|
$result = [regex]::Replace($name, '([а-яё])([А-ЯЁ])', '$1 $2')
|
||||||
$result = [regex]::Replace($result, '([a-z])([A-Z])', '$1 $2')
|
$result = [regex]::Replace($result, '([a-z])([A-Z])', '$1 $2')
|
||||||
# Lowercase all but first character of the result
|
# Лоуэркейзим хвост, СОХРАНЯЯ аббревиатуры (зеркало эвристики платформы): максимальный прогон
|
||||||
|
# заглавных длиной >=2, если сразу за ним НЕ буква (пробел/цифра/спецсимвол/конец) — остаётся заглавным
|
||||||
|
# (НДС, ЕГАИС, ОС, ЭП). Прилипшие предлоги (СКлиентами) и бренды (ЮКасса) идут перед буквой → лоуэркейз.
|
||||||
|
# Первый символ строки — как есть.
|
||||||
if ($result.Length -gt 1) {
|
if ($result.Length -gt 1) {
|
||||||
$result = $result.Substring(0,1) + $result.Substring(1).ToLower()
|
$chars = $result.ToCharArray()
|
||||||
|
$n = $chars.Length
|
||||||
|
$keep = New-Object 'bool[]' $n
|
||||||
|
$i = 0
|
||||||
|
while ($i -lt $n) {
|
||||||
|
if ([char]::IsUpper($chars[$i])) {
|
||||||
|
$j = $i
|
||||||
|
while ($j -lt $n -and [char]::IsUpper($chars[$j])) { $j++ }
|
||||||
|
$afterBoundary = ($j -eq $n) -or (-not [char]::IsLetter($chars[$j]))
|
||||||
|
if (($j - $i) -ge 2 -and $afterBoundary) { for ($k = $i; $k -lt $j; $k++) { $keep[$k] = $true } }
|
||||||
|
$i = $j
|
||||||
|
} else { $i++ }
|
||||||
|
}
|
||||||
|
$sb = New-Object System.Text.StringBuilder
|
||||||
|
for ($idx = 0; $idx -lt $n; $idx++) {
|
||||||
|
$c = $chars[$idx]
|
||||||
|
if ($idx -eq 0 -or $keep[$idx]) { [void]$sb.Append($c) }
|
||||||
|
elseif ([char]::IsUpper($c)) { [void]$sb.Append([char]::ToLower($c)) }
|
||||||
|
else { [void]$sb.Append($c) }
|
||||||
|
}
|
||||||
|
$result = $sb.ToString()
|
||||||
}
|
}
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# meta-compile v1.60 — Compile 1C metadata object from JSON
|
# meta-compile v1.61 — Compile 1C metadata object from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -233,8 +233,36 @@ def split_camel_case(name):
|
|||||||
return name
|
return name
|
||||||
result = re.sub(r'([а-яё])([А-ЯЁ])', r'\1 \2', name)
|
result = re.sub(r'([а-яё])([А-ЯЁ])', r'\1 \2', name)
|
||||||
result = re.sub(r'([a-z])([A-Z])', r'\1 \2', result)
|
result = re.sub(r'([a-z])([A-Z])', r'\1 \2', result)
|
||||||
|
# Лоуэркейзим хвост, СОХРАНЯЯ аббревиатуры (зеркало эвристики платформы): максимальный прогон
|
||||||
|
# заглавных длиной >=2, если сразу за ним НЕ буква (пробел/цифра/спецсимвол/конец) — остаётся заглавным
|
||||||
|
# (НДС, ЕГАИС, ОС, ЭП). Прилипшие предлоги (СКлиентами)/бренды (ЮКасса) идут перед буквой → лоуэркейз.
|
||||||
|
# Первый символ строки — как есть.
|
||||||
if len(result) > 1:
|
if len(result) > 1:
|
||||||
result = result[0] + result[1:].lower()
|
chars = list(result)
|
||||||
|
n = len(chars)
|
||||||
|
keep = [False] * n
|
||||||
|
i = 0
|
||||||
|
while i < n:
|
||||||
|
if chars[i].isupper():
|
||||||
|
j = i
|
||||||
|
while j < n and chars[j].isupper():
|
||||||
|
j += 1
|
||||||
|
after_boundary = (j == n) or (not chars[j].isalpha())
|
||||||
|
if j - i >= 2 and after_boundary:
|
||||||
|
for k in range(i, j):
|
||||||
|
keep[k] = True
|
||||||
|
i = j
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
out = []
|
||||||
|
for idx, c in enumerate(chars):
|
||||||
|
if idx == 0 or keep[idx]:
|
||||||
|
out.append(c)
|
||||||
|
elif c.isupper():
|
||||||
|
out.append(c.lower())
|
||||||
|
else:
|
||||||
|
out.append(c)
|
||||||
|
result = ''.join(out)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# meta-decompile v0.51 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
# meta-decompile v0.52 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
#
|
#
|
||||||
# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document,
|
# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document,
|
||||||
@@ -135,7 +135,31 @@ function Split-CamelWords {
|
|||||||
if (-not $name) { return $name }
|
if (-not $name) { return $name }
|
||||||
$result = [regex]::Replace($name, '([а-яё])([А-ЯЁ])', '$1 $2')
|
$result = [regex]::Replace($name, '([а-яё])([А-ЯЁ])', '$1 $2')
|
||||||
$result = [regex]::Replace($result, '([a-z])([A-Z])', '$1 $2')
|
$result = [regex]::Replace($result, '([a-z])([A-Z])', '$1 $2')
|
||||||
if ($result.Length -gt 1) { $result = $result.Substring(0,1) + $result.Substring(1).ToLower() }
|
# HE-эвристика (зеркало Split-CamelCase компилятора): сохраняем прогон заглавных >=2, если сразу за ним
|
||||||
|
# НЕ буква (пробел/цифра/спецсимвол/конец); прилипшие предлоги/бренды перед буквой → лоуэркейз. Первый символ — как есть.
|
||||||
|
if ($result.Length -gt 1) {
|
||||||
|
$chars = $result.ToCharArray()
|
||||||
|
$n = $chars.Length
|
||||||
|
$keep = New-Object 'bool[]' $n
|
||||||
|
$i = 0
|
||||||
|
while ($i -lt $n) {
|
||||||
|
if ([char]::IsUpper($chars[$i])) {
|
||||||
|
$j = $i
|
||||||
|
while ($j -lt $n -and [char]::IsUpper($chars[$j])) { $j++ }
|
||||||
|
$afterBoundary = ($j -eq $n) -or (-not [char]::IsLetter($chars[$j]))
|
||||||
|
if (($j - $i) -ge 2 -and $afterBoundary) { for ($k = $i; $k -lt $j; $k++) { $keep[$k] = $true } }
|
||||||
|
$i = $j
|
||||||
|
} else { $i++ }
|
||||||
|
}
|
||||||
|
$sb = New-Object System.Text.StringBuilder
|
||||||
|
for ($idx = 0; $idx -lt $n; $idx++) {
|
||||||
|
$c = $chars[$idx]
|
||||||
|
if ($idx -eq 0 -or $keep[$idx]) { [void]$sb.Append($c) }
|
||||||
|
elseif ([char]::IsUpper($c)) { [void]$sb.Append([char]::ToLower($c)) }
|
||||||
|
else { [void]$sb.Append($c) }
|
||||||
|
}
|
||||||
|
$result = $sb.ToString()
|
||||||
|
}
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +295,7 @@ function Attr-ToDsl {
|
|||||||
# Пустой <Synonym/> (узел есть, значения нет) ≠ авто-синоним из имени → явный пустой (synonym:"").
|
# Пустой <Synonym/> (узел есть, значения нет) ≠ авто-синоним из имени → явный пустой (synonym:"").
|
||||||
# У Catalog-реквизитов не встречается (0/4018), у части ExchangePlan — да.
|
# У Catalog-реквизитов не встречается (0/4018), у части ExchangePlan — да.
|
||||||
$synEmpty = ($synNode -and $null -eq $synVal)
|
$synEmpty = ($synNode -and $null -eq $synVal)
|
||||||
if ($synVal -is [string]) { if ($synVal -ne (Split-CamelWords $nm)) { $synCustom = $true } }
|
if ($synVal -is [string]) { if ($synVal -cne (Split-CamelWords $nm)) { $synCustom = $true } }
|
||||||
elseif ($null -ne $synVal) { $synCustom = $true } # {ru,en} = всегда кастом
|
elseif ($null -ne $synVal) { $synCustom = $true } # {ru,en} = всегда кастом
|
||||||
$ttVal = Get-MLValue ($ap.SelectSingleNode('md:ToolTip', $nsm))
|
$ttVal = Get-MLValue ($ap.SelectSingleNode('md:ToolTip', $nsm))
|
||||||
|
|
||||||
@@ -395,7 +419,7 @@ $dsl = [ordered]@{ type = $objType; name = $objName }
|
|||||||
# Пустой <Synonym/> (узел есть, значения нет) ≠ авто-синоним из имени → явный synonym:"" (иначе компилятор до-генерит из имени).
|
# Пустой <Synonym/> (узел есть, значения нет) ≠ авто-синоним из имени → явный synonym:"" (иначе компилятор до-генерит из имени).
|
||||||
$synNodeObj = $props.SelectSingleNode('md:Synonym', $nsm)
|
$synNodeObj = $props.SelectSingleNode('md:Synonym', $nsm)
|
||||||
$synVal = Get-MLValue $synNodeObj
|
$synVal = Get-MLValue $synNodeObj
|
||||||
if ($synVal -is [string]) { if ($synVal -ne (Split-CamelWords $objName)) { $dsl['synonym'] = $synVal } }
|
if ($synVal -is [string]) { if ($synVal -cne (Split-CamelWords $objName)) { $dsl['synonym'] = $synVal } }
|
||||||
elseif ($null -ne $synVal) { $dsl['synonym'] = $synVal }
|
elseif ($null -ne $synVal) { $dsl['synonym'] = $synVal }
|
||||||
elseif ($synNodeObj) { $dsl['synonym'] = '' }
|
elseif ($synNodeObj) { $dsl['synonym'] = '' }
|
||||||
$cmt = P 'Comment'; if ($cmt) { $dsl['comment'] = $cmt }
|
$cmt = P 'Comment'; if ($cmt) { $dsl['comment'] = $cmt }
|
||||||
@@ -1101,7 +1125,7 @@ if ($childObjs) {
|
|||||||
# $evSynVal: строка ≠ авто → кастом; {ru,en} → кастом; пустой `<Synonym/>` (node есть, значения нет) →
|
# $evSynVal: строка ≠ авто → кастом; {ru,en} → кастом; пустой `<Synonym/>` (node есть, значения нет) →
|
||||||
# явный '' (≠ авто-синоним из имени, аналог object-level фикса); авто/отсутствие → $null (короткая строка).
|
# явный '' (≠ авто-синоним из имени, аналог object-level фикса); авто/отсутствие → $null (короткая строка).
|
||||||
$evSynVal = $null
|
$evSynVal = $null
|
||||||
if ($evSyn -is [string]) { if ($evSyn -ne (Split-CamelWords $evName)) { $evSynVal = $evSyn } }
|
if ($evSyn -is [string]) { if ($evSyn -cne (Split-CamelWords $evName)) { $evSynVal = $evSyn } }
|
||||||
elseif ($null -ne $evSyn) { $evSynVal = $evSyn }
|
elseif ($null -ne $evSyn) { $evSynVal = $evSyn }
|
||||||
elseif ($evSynNode) { $evSynVal = '' }
|
elseif ($evSynNode) { $evSynVal = '' }
|
||||||
if (($null -ne $evSynVal) -or $evCmt) {
|
if (($null -ne $evSynVal) -or $evCmt) {
|
||||||
@@ -1126,7 +1150,7 @@ if ($childObjs) {
|
|||||||
$o = [ordered]@{ name = $cName }
|
$o = [ordered]@{ name = $cName }
|
||||||
$cSynNode = $cp.SelectSingleNode('md:Synonym', $nsm)
|
$cSynNode = $cp.SelectSingleNode('md:Synonym', $nsm)
|
||||||
$cSyn = Get-MLValue $cSynNode
|
$cSyn = Get-MLValue $cSynNode
|
||||||
if ($cSyn -is [string]) { if ($cSyn -ne (Split-CamelWords $cName)) { $o['synonym'] = $cSyn } }
|
if ($cSyn -is [string]) { if ($cSyn -cne (Split-CamelWords $cName)) { $o['synonym'] = $cSyn } }
|
||||||
elseif ($null -ne $cSyn) { $o['synonym'] = $cSyn }
|
elseif ($null -ne $cSyn) { $o['synonym'] = $cSyn }
|
||||||
elseif ($cSynNode) { $o['synonym'] = '' } # пустой <Synonym/> ≠ авто-синоним → явный ''
|
elseif ($cSynNode) { $o['synonym'] = '' } # пустой <Synonym/> ≠ авто-синоним → явный ''
|
||||||
$cCmtN = $cp.SelectSingleNode('md:Comment', $nsm); if ($cCmtN -and $cCmtN.InnerText) { $o['comment'] = $cCmtN.InnerText }
|
$cCmtN = $cp.SelectSingleNode('md:Comment', $nsm); if ($cCmtN -and $cCmtN.InnerText) { $o['comment'] = $cCmtN.InnerText }
|
||||||
@@ -1163,7 +1187,7 @@ if ($childObjs) {
|
|||||||
$dName = ($dp.SelectSingleNode('md:Name', $nsm)).InnerText
|
$dName = ($dp.SelectSingleNode('md:Name', $nsm)).InnerText
|
||||||
$o = [ordered]@{ name = $dName }
|
$o = [ordered]@{ name = $dName }
|
||||||
$dSyn = Get-MLValue ($dp.SelectSingleNode('md:Synonym', $nsm))
|
$dSyn = Get-MLValue ($dp.SelectSingleNode('md:Synonym', $nsm))
|
||||||
if ($dSyn -is [string]) { if ($dSyn -ne (Split-CamelWords $dName)) { $o['synonym'] = $dSyn } }
|
if ($dSyn -is [string]) { if ($dSyn -cne (Split-CamelWords $dName)) { $o['synonym'] = $dSyn } }
|
||||||
elseif ($null -ne $dSyn) { $o['synonym'] = $dSyn }
|
elseif ($null -ne $dSyn) { $o['synonym'] = $dSyn }
|
||||||
$dCmtN = $dp.SelectSingleNode('md:Comment', $nsm); if ($dCmtN -and $dCmtN.InnerText) { $o['comment'] = $dCmtN.InnerText }
|
$dCmtN = $dp.SelectSingleNode('md:Comment', $nsm); if ($dCmtN -and $dCmtN.InnerText) { $o['comment'] = $dCmtN.InnerText }
|
||||||
$dt = Get-TypeShorthand ($dp.SelectSingleNode('md:Type', $nsm)); if ($dt) { $o['type'] = $dt }
|
$dt = Get-TypeShorthand ($dp.SelectSingleNode('md:Type', $nsm)); if ($dt) { $o['type'] = $dt }
|
||||||
@@ -1207,7 +1231,7 @@ if ($childObjs) {
|
|||||||
# Синоним/подсказка/комментарий ТЧ. Кастом → объектная форма {synonym?, tooltip?, comment?, attributes}.
|
# Синоним/подсказка/комментарий ТЧ. Кастом → объектная форма {synonym?, tooltip?, comment?, attributes}.
|
||||||
$tsSyn = Get-MLValue ($tsp.SelectSingleNode('md:Synonym', $nsm))
|
$tsSyn = Get-MLValue ($tsp.SelectSingleNode('md:Synonym', $nsm))
|
||||||
$tsSynCustom = $false
|
$tsSynCustom = $false
|
||||||
if ($tsSyn -is [string]) { if ($tsSyn -ne (Split-CamelWords $tsName)) { $tsSynCustom = $true } }
|
if ($tsSyn -is [string]) { if ($tsSyn -cne (Split-CamelWords $tsName)) { $tsSynCustom = $true } }
|
||||||
elseif ($null -ne $tsSyn) { $tsSynCustom = $true }
|
elseif ($null -ne $tsSyn) { $tsSynCustom = $true }
|
||||||
$tsTt = Get-MLValue ($tsp.SelectSingleNode('md:ToolTip', $nsm))
|
$tsTt = Get-MLValue ($tsp.SelectSingleNode('md:ToolTip', $nsm))
|
||||||
$tsCmtN = $tsp.SelectSingleNode('md:Comment', $nsm); $tsCmt = if ($tsCmtN) { $tsCmtN.InnerText } else { '' }
|
$tsCmtN = $tsp.SelectSingleNode('md:Comment', $nsm); $tsCmt = if ($tsCmtN) { $tsCmtN.InnerText } else { '' }
|
||||||
@@ -1260,7 +1284,7 @@ if ($childObjs) {
|
|||||||
$cn = ($cp.SelectSingleNode('md:Name', $nsm)).InnerText
|
$cn = ($cp.SelectSingleNode('md:Name', $nsm)).InnerText
|
||||||
$o = [ordered]@{}
|
$o = [ordered]@{}
|
||||||
$syn = Get-MLValue ($cp.SelectSingleNode('md:Synonym', $nsm))
|
$syn = Get-MLValue ($cp.SelectSingleNode('md:Synonym', $nsm))
|
||||||
if ($syn -is [string]) { if ($syn -ne (Split-CamelWords $cn)) { $o['synonym'] = $syn } }
|
if ($syn -is [string]) { if ($syn -cne (Split-CamelWords $cn)) { $o['synonym'] = $syn } }
|
||||||
elseif ($null -ne $syn) { $o['synonym'] = $syn }
|
elseif ($null -ne $syn) { $o['synonym'] = $syn }
|
||||||
$cmtN = $cp.SelectSingleNode('md:Comment', $nsm); if ($cmtN -and $cmtN.InnerText) { $o['comment'] = $cmtN.InnerText }
|
$cmtN = $cp.SelectSingleNode('md:Comment', $nsm); if ($cmtN -and $cmtN.InnerText) { $o['comment'] = $cmtN.InnerText }
|
||||||
$grpN = $cp.SelectSingleNode('md:Group', $nsm); if ($grpN -and $grpN.InnerText) { $o['group'] = $grpN.InnerText }
|
$grpN = $cp.SelectSingleNode('md:Group', $nsm); if ($grpN -and $grpN.InnerText) { $o['group'] = $grpN.InnerText }
|
||||||
@@ -1328,7 +1352,7 @@ if (Test-Path -LiteralPath $predefPath) {
|
|||||||
if (-not $isFolder -and $kids.Count -eq 0 -and ($null -eq $typeStr -or $typeStr -ne '')) {
|
if (-not $isFolder -and $kids.Count -eq 0 -and ($null -eq $typeStr -or $typeStr -ne '')) {
|
||||||
$s = if ($code) { "($code) $name" } else { $name }
|
$s = if ($code) { "($code) $name" } else { $name }
|
||||||
if ($desc -eq '') { $s = "$s []" }
|
if ($desc -eq '') { $s = "$s []" }
|
||||||
elseif ($desc -ne $auto) { $s = "$s [$desc]" }
|
elseif ($desc -cne $auto) { $s = "$s [$desc]" }
|
||||||
if ($typeStr) { $s = "${s}: $typeStr" }
|
if ($typeStr) { $s = "${s}: $typeStr" }
|
||||||
return $s
|
return $s
|
||||||
}
|
}
|
||||||
@@ -1336,7 +1360,7 @@ if (Test-Path -LiteralPath $predefPath) {
|
|||||||
$o = [ordered]@{ name = $name }
|
$o = [ordered]@{ name = $name }
|
||||||
if ($code) { $o['code'] = $code }
|
if ($code) { $o['code'] = $code }
|
||||||
if ($desc -eq '') { $o['description'] = '' }
|
if ($desc -eq '') { $o['description'] = '' }
|
||||||
elseif ($desc -ne $auto) { $o['description'] = $desc }
|
elseif ($desc -cne $auto) { $o['description'] = $desc }
|
||||||
if ($null -ne $typeStr) { $o['type'] = $typeStr }
|
if ($null -ne $typeStr) { $o['type'] = $typeStr }
|
||||||
if ($isFolder) { $o['isFolder'] = $true }
|
if ($isFolder) { $o['isFolder'] = $true }
|
||||||
if ($kids.Count -gt 0) {
|
if ($kids.Count -gt 0) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# meta-decompile v0.51 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
# meta-decompile v0.52 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
#
|
#
|
||||||
# Зеркало meta-decompile.ps1 (КАНОН). Структура 1:1 — те же имена функций, порядок, комментарии.
|
# Зеркало meta-decompile.ps1 (КАНОН). Структура 1:1 — те же имена функций, порядок, комментарии.
|
||||||
@@ -143,20 +143,47 @@ def quote_json(s):
|
|||||||
|
|
||||||
|
|
||||||
# --- Сравнение регистров (зеркало PS -ne / -cne) ---
|
# --- Сравнение регистров (зеркало PS -ne / -cne) ---
|
||||||
def ne_ci(a, b):
|
def ne_cs(a, b):
|
||||||
"""PS -ne на строках (регистронезависимо). True когда различаются без учёта регистра."""
|
"""PS -cne на строках (регистрочувствительно). True когда различаются с учётом регистра.
|
||||||
return (a if a is not None else '').lower() != (b if b is not None else '').lower()
|
Зеркало компилятора: авто-синоним/описание опускаем только при ТОЧНОМ совпадении со split_camel_words."""
|
||||||
|
return (a if a is not None else '') != (b if b is not None else '')
|
||||||
|
|
||||||
|
|
||||||
def split_camel_words(name):
|
def split_camel_words(name):
|
||||||
"""Авто-синоним: точное зеркало Split-CamelCase из meta-compile (split_camel_case).
|
"""Авто-синоним: точное зеркало Split-CamelCase из meta-compile (split_camel_case, HE-эвристика).
|
||||||
ВАЖНО: логика должна совпадать байт-в-байт с компилятором, иначе ложные «синоним==авто» → диффы."""
|
ВАЖНО: логика должна совпадать байт-в-байт с компилятором, иначе ложные «синоним==авто» → диффы."""
|
||||||
if not name:
|
if not name:
|
||||||
return name
|
return name
|
||||||
result = re.sub(r'([а-яё])([А-ЯЁ])', r'\1 \2', name)
|
result = re.sub(r'([а-яё])([А-ЯЁ])', r'\1 \2', name)
|
||||||
result = re.sub(r'([a-z])([A-Z])', r'\1 \2', result)
|
result = re.sub(r'([a-z])([A-Z])', r'\1 \2', result)
|
||||||
|
# HE: сохраняем прогон заглавных >=2, если сразу за ним НЕ буква (пробел/цифра/спецсимвол/конец);
|
||||||
|
# предлоги/бренды перед буквой → лоуэркейз. Первый символ — как есть.
|
||||||
if len(result) > 1:
|
if len(result) > 1:
|
||||||
result = result[0] + result[1:].lower()
|
chars = list(result)
|
||||||
|
n = len(chars)
|
||||||
|
keep = [False] * n
|
||||||
|
i = 0
|
||||||
|
while i < n:
|
||||||
|
if chars[i].isupper():
|
||||||
|
j = i
|
||||||
|
while j < n and chars[j].isupper():
|
||||||
|
j += 1
|
||||||
|
after_boundary = (j == n) or (not chars[j].isalpha())
|
||||||
|
if j - i >= 2 and after_boundary:
|
||||||
|
for k in range(i, j):
|
||||||
|
keep[k] = True
|
||||||
|
i = j
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
out = []
|
||||||
|
for idx, c in enumerate(chars):
|
||||||
|
if idx == 0 or keep[idx]:
|
||||||
|
out.append(c)
|
||||||
|
elif c.isupper():
|
||||||
|
out.append(c.lower())
|
||||||
|
else:
|
||||||
|
out.append(c)
|
||||||
|
result = ''.join(out)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -359,7 +386,7 @@ def attr_to_dsl(attr_node):
|
|||||||
# Пустой <Synonym/> (узел есть, значения нет) ≠ авто-синоним из имени → явный пустой (synonym:"").
|
# Пустой <Synonym/> (узел есть, значения нет) ≠ авто-синоним из имени → явный пустой (synonym:"").
|
||||||
syn_empty = (syn_node is not None and syn_val is None)
|
syn_empty = (syn_node is not None and syn_val is None)
|
||||||
if isinstance(syn_val, str):
|
if isinstance(syn_val, str):
|
||||||
if ne_ci(syn_val, split_camel_words(nm)):
|
if ne_cs(syn_val, split_camel_words(nm)):
|
||||||
syn_custom = True
|
syn_custom = True
|
||||||
elif syn_val is not None:
|
elif syn_val is not None:
|
||||||
syn_custom = True # {ru,en} = всегда кастом
|
syn_custom = True # {ru,en} = всегда кастом
|
||||||
@@ -654,7 +681,7 @@ def predef_item_to_dsl(item_el):
|
|||||||
s = ("(%s) %s" % (code, name)) if code else name
|
s = ("(%s) %s" % (code, name)) if code else name
|
||||||
if desc == '':
|
if desc == '':
|
||||||
s = s + " []"
|
s = s + " []"
|
||||||
elif ne_ci(desc, auto):
|
elif ne_cs(desc, auto):
|
||||||
s = s + (" [%s]" % desc)
|
s = s + (" [%s]" % desc)
|
||||||
if type_str:
|
if type_str:
|
||||||
s = "%s: %s" % (s, type_str)
|
s = "%s: %s" % (s, type_str)
|
||||||
@@ -665,7 +692,7 @@ def predef_item_to_dsl(item_el):
|
|||||||
o['code'] = code
|
o['code'] = code
|
||||||
if desc == '':
|
if desc == '':
|
||||||
o['description'] = ''
|
o['description'] = ''
|
||||||
elif ne_ci(desc, auto):
|
elif ne_cs(desc, auto):
|
||||||
o['description'] = desc
|
o['description'] = desc
|
||||||
if type_str is not None:
|
if type_str is not None:
|
||||||
o['type'] = type_str
|
o['type'] = type_str
|
||||||
@@ -778,7 +805,7 @@ def build_dsl():
|
|||||||
syn_node_obj = _single(props, 'md:Synonym')
|
syn_node_obj = _single(props, 'md:Synonym')
|
||||||
syn_val = get_ml_value(syn_node_obj)
|
syn_val = get_ml_value(syn_node_obj)
|
||||||
if isinstance(syn_val, str):
|
if isinstance(syn_val, str):
|
||||||
if ne_ci(syn_val, split_camel_words(obj_name)):
|
if ne_cs(syn_val, split_camel_words(obj_name)):
|
||||||
dsl['synonym'] = syn_val
|
dsl['synonym'] = syn_val
|
||||||
elif syn_val is not None:
|
elif syn_val is not None:
|
||||||
dsl['synonym'] = syn_val
|
dsl['synonym'] = syn_val
|
||||||
@@ -1588,7 +1615,7 @@ def build_dsl():
|
|||||||
ev_cmt = _text(ev_cmt_n) if ev_cmt_n is not None else ''
|
ev_cmt = _text(ev_cmt_n) if ev_cmt_n is not None else ''
|
||||||
ev_syn_val = None
|
ev_syn_val = None
|
||||||
if isinstance(ev_syn, str):
|
if isinstance(ev_syn, str):
|
||||||
if ne_ci(ev_syn, split_camel_words(ev_name)):
|
if ne_cs(ev_syn, split_camel_words(ev_name)):
|
||||||
ev_syn_val = ev_syn
|
ev_syn_val = ev_syn
|
||||||
elif ev_syn is not None:
|
elif ev_syn is not None:
|
||||||
ev_syn_val = ev_syn
|
ev_syn_val = ev_syn
|
||||||
@@ -1615,7 +1642,7 @@ def build_dsl():
|
|||||||
c_syn_node = _single(cp, 'md:Synonym')
|
c_syn_node = _single(cp, 'md:Synonym')
|
||||||
c_syn = get_ml_value(c_syn_node)
|
c_syn = get_ml_value(c_syn_node)
|
||||||
if isinstance(c_syn, str):
|
if isinstance(c_syn, str):
|
||||||
if ne_ci(c_syn, split_camel_words(c_name)):
|
if ne_cs(c_syn, split_camel_words(c_name)):
|
||||||
o['synonym'] = c_syn
|
o['synonym'] = c_syn
|
||||||
elif c_syn is not None:
|
elif c_syn is not None:
|
||||||
o['synonym'] = c_syn
|
o['synonym'] = c_syn
|
||||||
@@ -1658,7 +1685,7 @@ def build_dsl():
|
|||||||
o = {'name': d_name}
|
o = {'name': d_name}
|
||||||
d_syn = get_ml_value(_single(dp, 'md:Synonym'))
|
d_syn = get_ml_value(_single(dp, 'md:Synonym'))
|
||||||
if isinstance(d_syn, str):
|
if isinstance(d_syn, str):
|
||||||
if ne_ci(d_syn, split_camel_words(d_name)):
|
if ne_cs(d_syn, split_camel_words(d_name)):
|
||||||
o['synonym'] = d_syn
|
o['synonym'] = d_syn
|
||||||
elif d_syn is not None:
|
elif d_syn is not None:
|
||||||
o['synonym'] = d_syn
|
o['synonym'] = d_syn
|
||||||
@@ -1709,7 +1736,7 @@ def build_dsl():
|
|||||||
ts_syn = get_ml_value(_single(tsp, 'md:Synonym'))
|
ts_syn = get_ml_value(_single(tsp, 'md:Synonym'))
|
||||||
ts_syn_custom = False
|
ts_syn_custom = False
|
||||||
if isinstance(ts_syn, str):
|
if isinstance(ts_syn, str):
|
||||||
if ne_ci(ts_syn, split_camel_words(ts_name)):
|
if ne_cs(ts_syn, split_camel_words(ts_name)):
|
||||||
ts_syn_custom = True
|
ts_syn_custom = True
|
||||||
elif ts_syn is not None:
|
elif ts_syn is not None:
|
||||||
ts_syn_custom = True
|
ts_syn_custom = True
|
||||||
@@ -1779,7 +1806,7 @@ def build_dsl():
|
|||||||
o = {}
|
o = {}
|
||||||
syn = get_ml_value(_single(cp, 'md:Synonym'))
|
syn = get_ml_value(_single(cp, 'md:Synonym'))
|
||||||
if isinstance(syn, str):
|
if isinstance(syn, str):
|
||||||
if ne_ci(syn, split_camel_words(cn)):
|
if ne_cs(syn, split_camel_words(cn)):
|
||||||
o['synonym'] = syn
|
o['synonym'] = syn
|
||||||
elif syn is not None:
|
elif syn is not None:
|
||||||
o['synonym'] = syn
|
o['synonym'] = syn
|
||||||
|
|||||||
+14
-4
@@ -35,19 +35,29 @@ JSON DSL для описания объектов метаданных конф
|
|||||||
|
|
||||||
## 2. Автогенерация синонима (CamelCase → слова)
|
## 2. Автогенерация синонима (CamelCase → слова)
|
||||||
|
|
||||||
Если `synonym` не указан, имя автоматически разбивается на слова:
|
Если `synonym` не указан, имя автоматически разбивается на слова (зеркало эвристики платформы):
|
||||||
|
|
||||||
| Вход | Результат |
|
| Вход | Результат |
|
||||||
|------|-----------|
|
|------|-----------|
|
||||||
| `АвансовыйОтчет` | `Авансовый отчет` |
|
| `АвансовыйОтчет` | `Авансовый отчет` |
|
||||||
| `ОсновнаяВалюта` | `Основная валюта` |
|
| `ОсновнаяВалюта` | `Основная валюта` |
|
||||||
| `НДС20` | `НДС20` |
|
| `АбонентыЭДО` | `Абоненты ЭДО` |
|
||||||
|
| `ВыработкаОС` | `Выработка ОС` |
|
||||||
|
| `СчетУчетаНДС` | `Счет учета НДС` |
|
||||||
|
| `СтатусЭДО2` | `Статус ЭДО2` |
|
||||||
|
| `РасчетыСКлиентами` | `Расчеты склиентами` |
|
||||||
|
| `ЮКассаЛоготип` | `Юкасса логотип` |
|
||||||
| `IncomingDocument` | `Incoming document` |
|
| `IncomingDocument` | `Incoming document` |
|
||||||
|
|
||||||
Правила:
|
Правила:
|
||||||
- Граница на переходе `[а-яё][А-ЯЁ]` и `[a-z][A-Z]`
|
- Граница на переходе `[а-яё][А-ЯЁ]` и `[a-z][A-Z]`
|
||||||
- Первое слово сохраняет заглавную, остальные — строчные
|
- Первое слово сохраняет заглавную, остальные — строчные, **кроме аббревиатур**: максимальный прогон
|
||||||
- Явный `synonym` перекрывает автогенерацию
|
заглавных длиной **≥2, если сразу за ним НЕ буква** (пробел/цифра/спецсимвол/конец строки) — остаётся
|
||||||
|
заглавным (`НДС`, `ЕГАИС`, `ОС`, `ЭП`)
|
||||||
|
- Прилипшие предлоги и бренды (`СКлиентами`, `ЮКасса`) стоят перед буквой → строчные (не аббревиатура)
|
||||||
|
- То же правило — для авто-Наименования предопределённых (§7.1.2) и авто-описаний
|
||||||
|
- Явный `synonym` перекрывает автогенерацию; при расхождении с авто хотя бы в регистре синоним
|
||||||
|
сохраняется дословно (напр. брендовый `ВетИС`, `МИР`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -183,7 +183,7 @@
|
|||||||
<Synonym>
|
<Synonym>
|
||||||
<v8:item>
|
<v8:item>
|
||||||
<v8:lang>ru</v8:lang>
|
<v8:lang>ru</v8:lang>
|
||||||
<v8:content>Тип ттн</v8:content>
|
<v8:content>Тип ТТН</v8:content>
|
||||||
</v8:item>
|
</v8:item>
|
||||||
</Synonym>
|
</Synonym>
|
||||||
<Comment/>
|
<Comment/>
|
||||||
|
|||||||
+1
-1
@@ -93,7 +93,7 @@
|
|||||||
<Synonym>
|
<Synonym>
|
||||||
<v8:item>
|
<v8:item>
|
||||||
<v8:lang>ru</v8:lang>
|
<v8:lang>ru</v8:lang>
|
||||||
<v8:content>Инн</v8:content>
|
<v8:content>ИНН</v8:content>
|
||||||
</v8:item>
|
</v8:item>
|
||||||
</Synonym>
|
</Synonym>
|
||||||
<Comment>Налоговый номер</Comment>
|
<Comment>Налоговый номер</Comment>
|
||||||
|
|||||||
+1
-1
@@ -299,7 +299,7 @@
|
|||||||
<Synonym>
|
<Synonym>
|
||||||
<v8:item>
|
<v8:item>
|
||||||
<v8:lang>ru</v8:lang>
|
<v8:lang>ru</v8:lang>
|
||||||
<v8:content>Любая ссылка иб</v8:content>
|
<v8:content>Любая ссылка ИБ</v8:content>
|
||||||
</v8:item>
|
</v8:item>
|
||||||
</Synonym>
|
</Synonym>
|
||||||
<Comment/>
|
<Comment/>
|
||||||
|
|||||||
+1
-1
@@ -93,7 +93,7 @@
|
|||||||
<Synonym>
|
<Synonym>
|
||||||
<v8:item>
|
<v8:item>
|
||||||
<v8:lang>ru</v8:lang>
|
<v8:lang>ru</v8:lang>
|
||||||
<v8:content>Инн</v8:content>
|
<v8:content>ИНН</v8:content>
|
||||||
</v8:item>
|
</v8:item>
|
||||||
</Synonym>
|
</Synonym>
|
||||||
<Comment/>
|
<Comment/>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<Synonym>
|
<Synonym>
|
||||||
<v8:item>
|
<v8:item>
|
||||||
<v8:lang>ru</v8:lang>
|
<v8:lang>ru</v8:lang>
|
||||||
<v8:content>Ставка ндс</v8:content>
|
<v8:content>Ставка НДС</v8:content>
|
||||||
</v8:item>
|
</v8:item>
|
||||||
</Synonym>
|
</Synonym>
|
||||||
<Comment>(Демо)</Comment>
|
<Comment>(Демо)</Comment>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<Synonym>
|
<Synonym>
|
||||||
<v8:item>
|
<v8:item>
|
||||||
<v8:lang>ru</v8:lang>
|
<v8:lang>ru</v8:lang>
|
||||||
<v8:content>Товарныйapi</v8:content>
|
<v8:content>ТоварныйAPI</v8:content>
|
||||||
</v8:item>
|
</v8:item>
|
||||||
</Synonym>
|
</Synonym>
|
||||||
<Comment/>
|
<Comment/>
|
||||||
|
|||||||
Reference in New Issue
Block a user