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:
Nick Shirokov
2026-07-10 20:09:36 +03:00
co-authored by Claude Opus 4.8
parent 4ca89343ae
commit 706cc919a2
11 changed files with 153 additions and 41 deletions
@@ -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
param(
[Parameter(Mandatory)]
@@ -421,9 +421,32 @@ function Split-CamelCase {
# Insert space before uppercase that follows lowercase (Cyrillic + Latin)
$result = [regex]::Replace($name, '([а-яё])([А-ЯЁ])', '$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) {
$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
}
@@ -1,5 +1,5 @@
#!/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
import argparse
@@ -233,8 +233,36 @@ def split_camel_case(name):
return name
result = re.sub(r'([а-яё])([А-ЯЁ])', r'\1 \2', name)
result = re.sub(r'([a-z])([A-Z])', r'\1 \2', result)
# Лоуэркейзим хвост, СОХРАНЯЯ аббревиатуры (зеркало эвристики платформы): максимальный прогон
# заглавных длиной >=2, если сразу за ним НЕ буква (пробел/цифра/спецсимвол/конец) — остаётся заглавным
# (НДС, ЕГАИС, ОС, ЭП). Прилипшие предлоги (СКлиентами)/бренды (ЮКасса) идут перед буквой → лоуэркейз.
# Первый символ строки — как есть.
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
# ---------------------------------------------------------------------------