diff --git a/.claude/skills/meta-compile/reference/attributes.md b/.claude/skills/meta-compile/reference/attributes.md
index f38c8d05..05ae3710 100644
--- a/.claude/skills/meta-compile/reference/attributes.md
+++ b/.claude/skills/meta-compile/reference/attributes.md
@@ -125,6 +125,7 @@ shorthand — вместо строки задаётся объект:
| `use` | `ForItem` | `ForItem` / `ForFolder` / `ForFolderAndItem` (только Catalog / ChartOfCharacteristicTypes) |
| `attributes` | `[]` | колонки (shorthand или объектная форма реквизита) |
| `lineNumber` | — | кастомизация стандартного реквизита НомерСтроки (см. ниже) |
+| `lineNumberLength` | по режиму совместимости | `5`…`9` — разрядность номера строки: `5` → до 99 999 строк, `9` → до 999 999 999. Требует формата 2.20 (платформа 8.3.27) |
### `lineNumber` — стандартный реквизит НомерСтроки
diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1
index 1be7c23f..f9ae61be 100644
--- a/.claude/skills/meta-compile/scripts/meta-compile.ps1
+++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1
@@ -1,4 +1,4 @@
-# meta-compile v1.67 — Compile 1C metadata object from JSON
+# meta-compile v1.68 — Compile 1C metadata object from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -1321,6 +1321,12 @@ function Emit-StandardAttribute {
X "$indent`tfalse"
X "$indent`t$ffv"
X "$indent`tAuto"
+ # Формат 2.20 (8.3.27): режим приведения типов. Платформа пишет его КАЖДОМУ стандартному
+ # реквизиту; значение всегда TransformValues, кроме владельца (Owner) — там Deny.
+ if ($script:isFormat220) {
+ $trm = OvOr 'TypeReductionMode' $(if ($attrName -ceq 'Owner') { 'Deny' } else { 'TransformValues' })
+ X "$indent`t$trm"
+ }
X "$indent`t"
Emit-MLText "$indent`t" "xr:ToolTip" $tt
X "$indent`tfalse"
@@ -1949,6 +1955,12 @@ function Emit-Attribute {
X "$indent`t`t$dh"
}
}
+ # Формат 2.20 (8.3.27): режим приведения типов — последним в Properties и ТОЛЬКО у измерений
+ # регистра сведений (у реквизитов/ресурсов и у прочих семейств регистров платформа его не пишет).
+ if ($script:isFormat220 -and $elemTag -eq "Dimension" -and $context -eq "register-info") {
+ $trm = if ($parsed.typeReductionMode) { "$($parsed.typeReductionMode)" } else { "TransformValues" }
+ X "$indent`t`t$trm"
+ }
X "$indent`t"
X "$indent$elemTag>"
@@ -2020,7 +2032,7 @@ function Emit-Command {
# --- 9. TabularSection emitter ---
function Emit-TabularSection {
- param([string]$indent, [string]$tsName, $columns, [string]$objectType, [string]$objectName, $tsSynonymArg = $null, $tsTooltip = $null, $tsComment = $null, $tsLineNumber = $null, $tsFillChecking = $null, $tsUse = $null)
+ param([string]$indent, [string]$tsName, $columns, [string]$objectType, [string]$objectName, $tsSynonymArg = $null, $tsTooltip = $null, $tsComment = $null, $tsLineNumber = $null, $tsFillChecking = $null, $tsUse = $null, $tsLineNumberLength = $null)
$uuid = New-Guid-String
X "$indent"
@@ -2059,6 +2071,12 @@ function Emit-TabularSection {
$use = if ($tsUse) { "$tsUse" } else { "ForItem" }
X "$indent`t`t"
}
+ # Формат 2.20 (8.3.27): длина номера строки ТЧ (5..9 → до 999 999 999 строк вместо 99 999).
+ # Последним в Properties. Дефолт платформа берёт из режима совместимости на момент создания ТЧ.
+ if ($script:isFormat220) {
+ $lnl = if ($null -ne $tsLineNumberLength -and "$tsLineNumberLength" -ne '') { [int]$tsLineNumberLength } else { $script:lineNumberLengthDefault }
+ X "$indent`t`t$lnl"
+ }
X "$indent`t"
$tsContext = if ($objectType -in @("DataProcessor","Report")) { "processor-tabular" } else { "tabular" }
@@ -3984,7 +4002,51 @@ function Detect-FormatVersion([string]$dir) {
return "2.17"
}
+# Режим совместимости конфигурации — из него выводится дефолт табличной части
+# (≤Version8_3_26 → 5, ≥Version8_3_27 → 9; платформа фиксирует значение при СОЗДАНии ТЧ).
+# NB: версия ФОРМАТА от режима совместимости не зависит (её задаёт платформа выгрузки) — это
+# независимые вещи, читаются из одного файла разными функциями.
+# Читаем префикс побольше: лежит ~11-12 КБ от начала (в отличие от version=
+# в первой строке), 2000 байт Detect-FormatVersion сюда не хватает.
+function Detect-CompatibilityMode([string]$dir) {
+ $d = $dir
+ while ($d) {
+ $cfgPath = Join-Path $d "Configuration.xml"
+ if (Test-Path $cfgPath) {
+ # NB: длина файла — в БАЙТАХ, а Substring режет по СИМВОЛАМ (кириллица = 2 байта),
+ # поэтому ограничиваем по длине уже декодированной строки.
+ $text = [System.IO.File]::ReadAllText($cfgPath, [System.Text.Encoding]::UTF8)
+ $head = $text.Substring(0, [Math]::Min(65536, $text.Length))
+ if ($head -match '([^<]+)') { return $Matches[1].Trim() }
+ }
+ $parent = Split-Path $d -Parent
+ if ($parent -eq $d) { break }
+ $d = $parent
+ }
+ return "Version8_3_24"
+}
+
+# Номер версии режима совместимости для сравнений: "Version8_3_27" → 80327, "Version8_5_1" → 80501.
+function Get-CompatModeRank([string]$mode) {
+ if ($mode -match '^Version(\d+)_(\d+)_(\d+)$') {
+ return [int]$Matches[1] * 10000 + [int]$Matches[2] * 100 + [int]$Matches[3]
+ }
+ return 0
+}
+
+# Версия формата как число для сравнений: "2.20" → 220, "2.9" → 209.
+# Строковое сравнение здесь неверно ("2.9" > "2.17" лексикографически) — известная ловушка.
+function Get-FormatRank([string]$ver) {
+ if ($ver -match '^(\d+)\.(\d+)$') { return [int]$Matches[1] * 100 + [int]$Matches[2] }
+ return 0
+}
+
$script:formatVersion = Detect-FormatVersion $OutputDir
+$script:compatMode = Detect-CompatibilityMode $OutputDir
+# Формат 2.20+ (платформа 8.3.27) — только тогда эмитим новые свойства.
+$script:isFormat220 = (Get-FormatRank $script:formatVersion) -ge 220
+# Дефолт длины номера строки ТЧ: с режима 8.3.27 платформа заводит новые ТЧ с 9 разрядами.
+$script:lineNumberLengthDefault = if ((Get-CompatModeRank $script:compatMode) -ge 80327) { 9 } else { 5 }
# --- 15. Main assembler ---
@@ -4064,10 +4126,10 @@ if ($objType -in $typesWithAttrTS) {
# Нормализуем в $tsSections[name] = @{ columns; synonym; tooltip; comment }.
function New-TsEntry { param($val)
if ($val -is [array] -or $val.GetType().Name -eq 'Object[]') {
- return @{ columns = @($val); synonym = $null; tooltip = $null; comment = $null; lineNumber = $null; fillChecking = $null; use = $null }
+ return @{ columns = @($val); synonym = $null; tooltip = $null; comment = $null; lineNumber = $null; fillChecking = $null; use = $null; lineNumberLength = $null }
}
$cols = if ($val.attributes) { @($val.attributes) } elseif ($val.columns) { @($val.columns) } else { @() }
- return @{ columns = $cols; synonym = $val.synonym; tooltip = $val.tooltip; comment = if ($val.comment) { "$($val.comment)" } else { $null }; lineNumber = $val.lineNumber; fillChecking = $val.fillChecking; use = $val.use }
+ return @{ columns = $cols; synonym = $val.synonym; tooltip = $val.tooltip; comment = if ($val.comment) { "$($val.comment)" } else { $null }; lineNumber = $val.lineNumber; fillChecking = $val.fillChecking; use = $val.use; lineNumberLength = $val.lineNumberLength }
}
if ($def.tabularSections -is [array] -or $def.tabularSections.GetType().Name -eq "Object[]") {
foreach ($ts in $def.tabularSections) { $tsSections[$ts.name] = New-TsEntry $ts }
@@ -4117,7 +4179,7 @@ if ($objType -in $typesWithAttrTS) {
}
foreach ($tsName in $tsSections.Keys) {
$tsE = $tsSections[$tsName]
- Emit-TabularSection "`t`t`t" $tsName $tsE.columns $objType $objName $tsE.synonym $tsE.tooltip $tsE.comment $tsE.lineNumber $tsE.fillChecking $tsE.use
+ Emit-TabularSection "`t`t`t" $tsName $tsE.columns $objType $objName $tsE.synonym $tsE.tooltip $tsE.comment $tsE.lineNumber $tsE.fillChecking $tsE.use $tsE.lineNumberLength
}
foreach ($af in $acctFlags) {
Emit-Attribute "`t`t`t" $af "account-flag" "AccountingFlag"
diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py
index 80df290e..a25106ef 100644
--- a/.claude/skills/meta-compile/scripts/meta-compile.py
+++ b/.claude/skills/meta-compile/scripts/meta-compile.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# meta-compile v1.67 — Compile 1C metadata object from JSON
+# meta-compile v1.68 — Compile 1C metadata object from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -1340,6 +1340,11 @@ def emit_standard_attribute(indent, attr_name, ov=None):
X(f'{indent}\tfalse')
X(f'{indent}\t{ffv}')
X(f'{indent}\tAuto')
+ # Формат 2.20 (8.3.27): режим приведения типов. Платформа пишет его КАЖДОМУ стандартному
+ # реквизиту; значение всегда TransformValues, кроме владельца (Owner) — там Deny.
+ if is_format_220:
+ trm = ov.get('TypeReductionMode', 'Deny' if attr_name == 'Owner' else 'TransformValues')
+ X(f'{indent}\t{trm}')
X(f'{indent}\t')
emit_mltext(f'{indent}\t', 'xr:ToolTip', tt)
X(f'{indent}\tfalse')
@@ -2012,6 +2017,10 @@ def emit_attribute(indent, parsed, context, elem_tag='Attribute'):
# DataHistory — not for Chart* types and non-InformationRegister register family
if context not in ('chart', 'register-other', 'register-accum', 'register-calc', 'register-account'):
X(f'{indent}\t\t{parsed.get("dataHistory") or "Use"}')
+ # Формат 2.20 (8.3.27): режим приведения типов — последним в Properties и ТОЛЬКО у измерений
+ # регистра сведений (у реквизитов/ресурсов и у прочих семейств регистров платформа его не пишет).
+ if is_format_220 and elem_tag == 'Dimension' and context == 'register-info':
+ X(f'{indent}\t\t{parsed.get("typeReductionMode") or "TransformValues"}')
X(f'{indent}\t')
X(f'{indent}{elem_tag}>')
@@ -2088,7 +2097,7 @@ def emit_command(indent, cmd_name, cmd):
X(f'{indent}\t')
X(f'{indent}')
-def emit_tabular_section(indent, ts_name, columns, object_type, object_name, ts_synonym_arg=None, ts_tooltip=None, ts_comment=None, ts_line_number=None, ts_fill_checking=None, ts_use=None):
+def emit_tabular_section(indent, ts_name, columns, object_type, object_name, ts_synonym_arg=None, ts_tooltip=None, ts_comment=None, ts_line_number=None, ts_fill_checking=None, ts_use=None, ts_line_number_length=None):
uid = new_uuid()
X(f'{indent}')
type_prefix = f'{object_type}TabularSection'
@@ -2119,6 +2128,11 @@ def emit_tabular_section(indent, ts_name, columns, object_type, object_name, ts_
emit_tabular_standard_attributes(f'{indent}\t\t', ts_line_number)
if object_type in ('Catalog', 'ChartOfCharacteristicTypes'):
X(f'{indent}\t\t')
+ # Формат 2.20 (8.3.27): длина номера строки ТЧ (5..9 → до 999 999 999 строк вместо 99 999).
+ # Последним в Properties. Дефолт платформа берёт из режима совместимости на момент создания ТЧ.
+ if is_format_220:
+ lnl = int(ts_line_number_length) if ts_line_number_length not in (None, '') else line_number_length_default
+ X(f'{indent}\t\t{lnl}')
X(f'{indent}\t')
ts_context = 'processor-tabular' if object_type in ('DataProcessor', 'Report') else 'tabular'
X(f'{indent}\t')
@@ -3887,7 +3901,44 @@ def detect_format_version(d):
d = parent
return "2.17"
+def detect_compatibility_mode(d):
+ """Режим совместимости конфигурации — из него выводится дефолт табличной части
+ (<=Version8_3_26 → 5, >=Version8_3_27 → 9; платформа фиксирует значение при СОЗДАНИИ ТЧ).
+ NB: версия ФОРМАТА от режима совместимости не зависит (её задаёт платформа выгрузки).
+ Читаем префикс побольше: лежит ~11-12 КБ от начала."""
+ while d:
+ cfg_path = os.path.join(d, "Configuration.xml")
+ if os.path.isfile(cfg_path):
+ with open(cfg_path, "r", encoding="utf-8-sig") as f:
+ head = f.read(65536)
+ m = re.search(r'([^<]+)', head)
+ if m:
+ return m.group(1).strip()
+ parent = os.path.dirname(d)
+ if parent == d:
+ break
+ d = parent
+ return "Version8_3_24"
+
+
+def compat_mode_rank(mode):
+ """"Version8_3_27" → 80327, "Version8_5_1" → 80501."""
+ m = re.match(r'^Version(\d+)_(\d+)_(\d+)$', mode or '')
+ return int(m.group(1)) * 10000 + int(m.group(2)) * 100 + int(m.group(3)) if m else 0
+
+
+def format_rank(ver):
+ """"2.20" → 220, "2.9" → 209. Строковое сравнение неверно ("2.9" > "2.17")."""
+ m = re.match(r'^(\d+)\.(\d+)$', ver or '')
+ return int(m.group(1)) * 100 + int(m.group(2)) if m else 0
+
+
format_version = detect_format_version(output_dir)
+compat_mode = detect_compatibility_mode(output_dir)
+# Формат 2.20+ (платформа 8.3.27) — только тогда эмитим новые свойства.
+is_format_220 = format_rank(format_version) >= 220
+# Дефолт длины номера строки ТЧ: с режима 8.3.27 платформа заводит новые ТЧ с 9 разрядами.
+line_number_length_default = 9 if compat_mode_rank(compat_mode) >= 80327 else 5
# ---------------------------------------------------------------------------
# 15. Main assembler
@@ -3980,10 +4031,10 @@ if obj_type in types_with_attr_ts:
# Значение ТЧ: массив колонок (синоним авто) ЛИБО объект {attributes/columns, synonym, tooltip, comment}.
def new_ts_entry(val):
if isinstance(val, list):
- return {'columns': val, 'synonym': None, 'tooltip': None, 'comment': None, 'lineNumber': None, 'fillChecking': None, 'use': None}
+ return {'columns': val, 'synonym': None, 'tooltip': None, 'comment': None, 'lineNumber': None, 'fillChecking': None, 'use': None, 'lineNumberLength': None}
cols = _as_list(val.get('attributes') or val.get('columns') or [])
return {'columns': cols, 'synonym': val.get('synonym'), 'tooltip': val.get('tooltip'),
- 'comment': str(val['comment']) if val.get('comment') else None, 'lineNumber': val.get('lineNumber'), 'fillChecking': val.get('fillChecking'), 'use': val.get('use')}
+ 'comment': str(val['comment']) if val.get('comment') else None, 'lineNumber': val.get('lineNumber'), 'fillChecking': val.get('fillChecking'), 'use': val.get('use'), 'lineNumberLength': val.get('lineNumberLength')}
if isinstance(ts_data, list):
for ts in ts_data:
ts_sections[ts['name']] = new_ts_entry(ts)
@@ -4035,7 +4086,7 @@ if obj_type in types_with_attr_ts:
emit_attribute('\t\t\t', a, context)
for ts_name in ts_order:
e = ts_sections[ts_name]
- emit_tabular_section('\t\t\t', ts_name, e['columns'], obj_type, obj_name, e['synonym'], e['tooltip'], e['comment'], e.get('lineNumber'), e.get('fillChecking'), e.get('use'))
+ emit_tabular_section('\t\t\t', ts_name, e['columns'], obj_type, obj_name, e['synonym'], e['tooltip'], e['comment'], e.get('lineNumber'), e.get('fillChecking'), e.get('use'), e.get('lineNumberLength'))
for af in acct_flags:
emit_attribute('\t\t\t', af, 'account-flag', 'AccountingFlag')
for edf in ext_dim_flags:
diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1
index 639985e2..f6ed05fb 100644
--- a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1
+++ b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1
@@ -1,4 +1,4 @@
-# meta-decompile v0.54 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
+# meta-decompile v0.55 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
#
# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document,
@@ -323,6 +323,9 @@ function Attr-ToDsl {
$v = & $en 'MainFilter'; if ($v -eq 'true') { $extra['mainFilter'] = $true }
$v = & $en 'DenyIncompleteValues'; if ($v -eq 'true') { $extra['denyIncompleteValues'] = $true }
$v = & $en 'UseInTotals'; if ($v -eq 'false') { $extra['useInTotals'] = $false } # дефолт true → захват при false
+ # Формат 2.20: режим приведения типов измерения РС. Дефолт TransformValues (его компилятор
+ # эмитит сам) → захватываем только отклонение.
+ $v = & $en 'TypeReductionMode'; if ($v -and $v -ne 'TransformValues') { $extra['typeReductionMode'] = $v }
$v = & $en 'BaseDimension'; if ($v -eq 'true') { $extra['baseDimension'] = $true }
$v = & $en 'ScheduleLink'; if ($v) { $extra['scheduleLink'] = $v } # ссылка на измерение графика (пустой → пропуск)
$v = & $en 'Balance'; if ($v -eq 'true') { $extra['balance'] = $true }
@@ -1092,6 +1095,13 @@ if ($saNode) {
$ov['linkByType'] = [ordered]@{ dataPath = $saLbtDp.InnerText; linkItem = $li }
}
}
+ # Формат 2.20: режим приведения типов. Компилятор выводит его сам (TransformValues, у Owner —
+ # Deny), поэтому захватываем только отклонение от этого правила.
+ $saTrmN = $sa.SelectSingleNode('xr:TypeReductionMode', $nsm)
+ if ($saTrmN -and $saTrmN.InnerText) {
+ $saTrmDef = if ($an -ceq 'Owner') { 'Deny' } else { 'TransformValues' }
+ if ($saTrmN.InnerText -ne $saTrmDef) { $ov['TypeReductionMode'] = $saTrmN.InnerText }
+ }
# Доп./опциональный реквизит (не в фикс-списке) — эмитим по присутствию даже без отклонений.
if ($ov.Count -gt 0 -or ($stdFixed -notcontains $an)) { $saMap[$an] = $ov }
}
@@ -1262,13 +1272,20 @@ if ($childObjs) {
if ($lnFvT -match 'decimal$') { $lnObj['fillValue'] = if ($lnFvN.InnerText -match '^-?\d+$') { [long]$lnFvN.InnerText } else { [double]$lnFvN.InnerText } }
}
}
- if ($tsSynCustom -or ($null -ne $tsTt) -or $tsCmt -or $tsFc -or $tsUse -or $lnObj.Count -gt 0 -or (-not $hasBlock)) {
+ # Формат 2.20: длина номера строки ТЧ. Захватываем ВСЕГДА при наличии тега, а не
+ # omit-on-default: дефолт зависит от режима совместимости конфигурации (≤8_3_26 → 5,
+ # ≥8_3_27 → 9) и фиксируется платформой при создании ТЧ, так что вывести его здесь
+ # значило бы продублировать логику компилятора с риском разойтись. Явный захват точен.
+ $tsLnlN = $tsp.SelectSingleNode('md:LineNumberLength', $nsm)
+ $tsLnl = if ($tsLnlN -and $tsLnlN.InnerText) { [int]$tsLnlN.InnerText } else { $null }
+ if ($tsSynCustom -or ($null -ne $tsTt) -or $tsCmt -or $tsFc -or $tsUse -or $lnObj.Count -gt 0 -or (-not $hasBlock) -or ($null -ne $tsLnl)) {
$to = [ordered]@{}
if ($tsSynCustom) { $to['synonym'] = $tsSyn }
if ($null -ne $tsTt) { $to['tooltip'] = $tsTt }
if ($tsCmt) { $to['comment'] = $tsCmt }
if ($tsFc) { $to['fillChecking'] = $tsFc }
if ($tsUse) { $to['use'] = $tsUse }
+ if ($null -ne $tsLnl) { $to['lineNumberLength'] = $tsLnl }
if (-not $hasBlock) { $to['lineNumber'] = '' } elseif ($lnObj.Count -gt 0) { $to['lineNumber'] = $lnObj }
$to['attributes'] = $cols
$tsMap[$tsName] = $to
diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.py b/.claude/skills/meta-decompile/scripts/meta-decompile.py
index 6be4aec5..f6a17262 100644
--- a/.claude/skills/meta-decompile/scripts/meta-decompile.py
+++ b/.claude/skills/meta-decompile/scripts/meta-decompile.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# meta-decompile v0.54 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
+# meta-decompile v0.55 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
#
# Зеркало meta-decompile.ps1 (КАНОН). Структура 1:1 — те же имена функций, порядок, комментарии.
@@ -456,6 +456,11 @@ def attr_to_dsl(attr_node):
v = en('UseInTotals')
if v == 'false':
extra['useInTotals'] = False # дефолт true → захват при false
+ # Формат 2.20: режим приведения типов измерения РС. Дефолт TransformValues (его компилятор
+ # эмитит сам) → захватываем только отклонение.
+ v = en('TypeReductionMode')
+ if v and v != 'TransformValues':
+ extra['typeReductionMode'] = v
v = en('BaseDimension')
if v == 'true':
extra['baseDimension'] = True
@@ -1587,6 +1592,13 @@ def build_dsl():
li = int(_text(sa_lbt_li)) if (sa_lbt_li is not None and _text(sa_lbt_li)) else 0
ov['linkByType'] = {'dataPath': _text(sa_lbt_dp), 'linkItem': li}
# Доп./опциональный реквизит (не в фикс-списке) — эмитим по присутствию даже без отклонений.
+ # Формат 2.20: режим приведения типов. Компилятор выводит его сам (TransformValues,
+ # у Owner — Deny), поэтому захватываем только отклонение от этого правила.
+ sa_trm_n = _single(sa, 'xr:TypeReductionMode')
+ if sa_trm_n is not None and (sa_trm_n.text or '').strip():
+ sa_trm_def = 'Deny' if an == 'Owner' else 'TransformValues'
+ if sa_trm_n.text.strip() != sa_trm_def:
+ ov['TypeReductionMode'] = sa_trm_n.text.strip()
if len(ov) > 0 or (an not in std_fixed):
sa_map[an] = ov
if len(sa_map) > 0 or (obj_type in std_conditional_types):
@@ -1782,7 +1794,13 @@ def build_dsl():
ln_fv_t = _attr(ln_fv_n, 'type', NS_XSI)
if re.search(r'decimal$', ln_fv_t, re.I):
ln_obj['fillValue'] = int(_text(ln_fv_n)) if re.match(r'^-?\d+$', _text(ln_fv_n)) else float(_text(ln_fv_n))
- if ts_syn_custom or (ts_tt is not None) or ts_cmt or ts_fc or ts_use or len(ln_obj) > 0 or (not has_block):
+ # Формат 2.20: длина номера строки ТЧ. Захватываем ВСЕГДА при наличии тега, а не
+ # omit-on-default: дефолт зависит от режима совместимости конфигурации (<=8_3_26 → 5,
+ # >=8_3_27 → 9) и фиксируется платформой при создании ТЧ, так что вывести его здесь
+ # значило бы продублировать логику компилятора с риском разойтись. Явный захват точен.
+ ts_lnl_n = _single(tsp, 'md:LineNumberLength')
+ ts_lnl = int(ts_lnl_n.text) if ts_lnl_n is not None and (ts_lnl_n.text or '').strip() else None
+ if ts_syn_custom or (ts_tt is not None) or ts_cmt or ts_fc or ts_use or len(ln_obj) > 0 or (not has_block) or (ts_lnl is not None):
to = {}
if ts_syn_custom:
to['synonym'] = ts_syn
@@ -1794,6 +1812,8 @@ def build_dsl():
to['fillChecking'] = ts_fc
if ts_use:
to['use'] = ts_use
+ if ts_lnl is not None:
+ to['lineNumberLength'] = ts_lnl
if not has_block:
to['lineNumber'] = ''
elif len(ln_obj) > 0:
diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md
index ba226c03..48467062 100644
--- a/docs/meta-dsl-spec.md
+++ b/docs/meta-dsl-spec.md
@@ -308,7 +308,7 @@ JSON-**строка** → `xsi:type="xs:string"` (напр. год `"2000"`, к
}
```
-Свойства объектной формы ТЧ: `synonym` (ML; нет ключа → авто из имени), `tooltip` (ML), `comment` (строка), `fillChecking` (`DontCheck`|`ShowError`|`ShowWarning`), `use` (`ForItem`|`ForFolder`|`ForFolderAndItem`, только Catalog/ПВХ; omit при дефолте `ForItem`), `attributes` (колонки; синоним `columns`), `lineNumber` (кастомизация стандартного реквизита НомерСтроки, см. ниже).
+Свойства объектной формы ТЧ: `synonym` (ML; нет ключа → авто из имени), `tooltip` (ML), `comment` (строка), `fillChecking` (`DontCheck`|`ShowError`|`ShowWarning`), `use` (`ForItem`|`ForFolder`|`ForFolderAndItem`, только Catalog/ПВХ; omit при дефолте `ForItem`), `attributes` (колонки; синоним `columns`), `lineNumber` (кастомизация стандартного реквизита НомерСтроки, см. ниже), `lineNumberLength` (разрядность номера строки, см. §5.2).
Для Catalog/ChartOfCharacteristicTypes в Properties ТЧ пишется `