diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index 5ca0ca74..7d0683bc 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -331,17 +331,30 @@ function Esc-Xml { return $s.Replace('&','&').Replace('<','<').Replace('>','>').Replace('"','"') } +# ML-значение: строка → один ru; объект {lang: content} → item на язык (в порядке ключей). +function Emit-MLItems { + param([string]$indent, $val) + if ($val -is [System.Collections.IDictionary]) { + foreach ($k in $val.Keys) { + X "$indent"; X "$indent`t$k"; X "$indent`t$(Esc-Xml "$($val[$k])")"; X "$indent" + } + } elseif ($val -is [System.Management.Automation.PSCustomObject]) { + foreach ($p in $val.PSObject.Properties) { + X "$indent"; X "$indent`t$($p.Name)"; X "$indent`t$(Esc-Xml "$($p.Value)")"; X "$indent" + } + } else { + X "$indent"; X "$indent`tru"; X "$indent`t$(Esc-Xml "$val")"; X "$indent" + } +} function Emit-MLText { - param([string]$indent, [string]$tag, [string]$text) - if (-not $text) { + param([string]$indent, [string]$tag, $text) + # Пусто (null / пустая строка) → самозакрывающийся тег. + if (($null -eq $text) -or (($text -is [string]) -and ($text -eq ''))) { X "$indent<$tag/>" return } X "$indent<$tag>" - X "$indent`t" - X "$indent`t`tru" - X "$indent`t`t$(Esc-Xml $text)" - X "$indent`t" + Emit-MLItems "$indent`t" $text X "$indent" } @@ -611,12 +624,13 @@ function Parse-AttributeShorthand { return $parsed } - # Object form + # Object form. synonym/tooltip — сквозной проброс (строка ИЛИ объект {ru,en}), НЕ стрингифаим. $name = "$($val.name)" return @{ name = $name type = Build-TypeStr $val - synonym = if ($val.synonym) { "$($val.synonym)" } else { Split-CamelCase $name } + synonym = if ($null -ne $val.synonym) { $val.synonym } else { Split-CamelCase $name } + tooltip = $val.tooltip comment = if ($val.comment) { "$($val.comment)" } else { "" } flags = @(if ($val.flags) { $val.flags } else { @() }) fillChecking = if ($val.fillChecking) { "$($val.fillChecking)" } else { "" } @@ -962,7 +976,7 @@ function Emit-Attribute { X "$indent`t`tfalse" X "$indent`t`t" X "$indent`t`t" - X "$indent`t`t" + Emit-MLText "$indent`t`t" "ToolTip" $parsed.tooltip X "$indent`t`tfalse" X "$indent`t`t" $multiLine = if ($parsed.multiLine -eq $true -or $parsed.flags -contains "multiline") { "true" } else { "false" } diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 26d1339a..c254aec9 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -197,15 +197,27 @@ lines = [] def X(text): lines.append(text) +# ML-значение: строка → один ru; dict {lang: content} → item на язык (в порядке ключей). +def emit_ml_items(indent, val): + if isinstance(val, dict): + for k, v in val.items(): + X(f'{indent}') + X(f'{indent}\t{k}') + X(f'{indent}\t{esc_xml(str(v))}') + X(f'{indent}') + else: + X(f'{indent}') + X(f'{indent}\tru') + X(f'{indent}\t{esc_xml(str(val))}') + X(f'{indent}') + def emit_mltext(indent, tag, text): - if not text: + # Пусто (None / '') → самозакрывающийся тег. + if text is None or (isinstance(text, str) and text == ''): X(f'{indent}<{tag}/>') return X(f'{indent}<{tag}>') - X(f'{indent}\t') - X(f'{indent}\t\tru') - X(f'{indent}\t\t{esc_xml(text)}') - X(f'{indent}\t') + emit_ml_items(f'{indent}\t', text) X(f'{indent}') # --------------------------------------------------------------------------- @@ -615,12 +627,13 @@ def parse_attribute_shorthand(val): parsed['type'] = colon_parts[1].strip() parsed['synonym'] = split_camel_case(parsed['name']) return parsed - # Object form + # Object form. synonym/tooltip — сквозной проброс (строка ИЛИ dict {ru,en}), НЕ стрингифаим. name = str(val.get('name', '')) return { 'name': name, 'type': build_type_str(val), - 'synonym': str(val['synonym']) if val.get('synonym') else split_camel_case(name), + 'synonym': val['synonym'] if val.get('synonym') is not None else split_camel_case(name), + 'tooltip': val.get('tooltip'), 'comment': str(val['comment']) if val.get('comment') else '', 'flags': list(val.get('flags', [])), 'fillChecking': str(val['fillChecking']) if val.get('fillChecking') else '', @@ -957,7 +970,7 @@ def emit_attribute(indent, parsed, context): X(f'{indent}\t\tfalse') X(f'{indent}\t\t') X(f'{indent}\t\t') - X(f'{indent}\t\t') + emit_mltext(f'{indent}\t\t', 'ToolTip', parsed.get('tooltip')) X(f'{indent}\t\tfalse') X(f'{indent}\t\t') multi_line = 'true' if (parsed.get('multiLine') is True or 'multiline' in parsed.get('flags', [])) else 'false' diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 index 9826a094..779308cf 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.3 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.4 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # # Пилот: только Catalog. Инверс meta-compile (omit-on-default: ключ эмитим только @@ -105,6 +105,26 @@ function Get-MLru { if ($it) { return $it.InnerText } return $null } +# ML-значение → строка (если единственный item ru) ЛИБО [ordered]{lang:content} (мультиязычно, порядок из XML). +# null если контента нет. Компактная строка для ru-only, объект для мультиязычных. +function Get-MLValue { + param($node) + if (-not $node) { return $null } + $items = @($node.SelectNodes('v8:item', $nsm)) + if ($items.Count -eq 0) { return $null } + if ($items.Count -eq 1) { + $lang = $items[0].SelectSingleNode('v8:lang', $nsm).InnerText + $content = $items[0].SelectSingleNode('v8:content', $nsm).InnerText + if ($lang -eq 'ru') { return $content } + } + $o = [ordered]@{} + foreach ($it in $items) { + $l = $it.SelectSingleNode('v8:lang', $nsm).InnerText + $c = $it.SelectSingleNode('v8:content', $nsm).InnerText + $o[$l] = $c + } + return $o +} # Авто-синоним: точное зеркало Split-CamelCase из meta-compile (стр.354). Совпало → ключ опускаем. # ВАЖНО: логика должна совпадать байт-в-байт с компилятором, иначе ложные «синоним==авто» → диффы. function Split-CamelWords { @@ -175,12 +195,18 @@ function Attr-ToDsl { if ($ix) { if ($ix.InnerText -eq 'Index') { $flags += 'index' } elseif ($ix.InnerText -eq 'IndexWithAdditionalOrder') { $flags += 'indexAdditional' } } $ml = $ap.SelectSingleNode('md:MultiLine', $nsm); if ($ml -and $ml.InnerText -eq 'true') { $flags += 'multiline' } - $syn = Get-MLru ($ap.SelectSingleNode('md:Synonym', $nsm)) - # Кастомный синоним (есть и ≠ авто) → object-форма (shorthand его не выражает). - if ($syn -and $syn -ne (Split-CamelWords $nm)) { + # Синоним/подсказка (строка ru-only ИЛИ {ru,en}). Кастомный синоним ИЛИ наличие подсказки → object-форма. + $synVal = Get-MLValue ($ap.SelectSingleNode('md:Synonym', $nsm)) + $synCustom = $false + if ($synVal -is [string]) { if ($synVal -ne (Split-CamelWords $nm)) { $synCustom = $true } } + elseif ($null -ne $synVal) { $synCustom = $true } # {ru,en} = всегда кастом + $ttVal = Get-MLValue ($ap.SelectSingleNode('md:ToolTip', $nsm)) + + if ($synCustom -or ($null -ne $ttVal)) { $o = [ordered]@{ name = $nm } if ($ts) { $o['type'] = $ts } - $o['synonym'] = $syn + if ($synCustom) { $o['synonym'] = $synVal } + if ($null -ne $ttVal) { $o['tooltip'] = $ttVal } if ($flags.Count -gt 0) { $o['flags'] = [System.Collections.ArrayList]@($flags) } return $o } diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md index 7c65f2bf..cfbdbf57 100644 --- a/docs/meta-dsl-spec.md +++ b/docs/meta-dsl-spec.md @@ -1,6 +1,6 @@ # Meta DSL — спецификация JSON-формата для объектов метаданных 1С -Версия: 2.2 +Версия: 2.3 ## Обзор @@ -124,12 +124,15 @@ JSON DSL для описания объектов метаданных конф "name": "Имя", "type": "String(100)", "synonym": "Мой синоним", + "tooltip": "Всплывающая подсказка", "comment": "Комментарий", "fillChecking": "ShowError", "indexing": "Index" } ``` +**`synonym` и `tooltip` — ML-значения** (см. §4.4): строка → русский текст; объект `{ "ru": "…", "en": "…" }` → мультиязычный (`` на язык, в порядке ключей). `tooltip` → `` реквизита; нет ключа → `` (пусто). `synonym` не задан → авто из имени (§2). + Тип можно задать единой строкой (`"type": "String(100)"`) или раздельными полями: ```json @@ -157,6 +160,15 @@ JSON DSL для описания объектов метаданных конф Флаги разделяются запятой после `|`. +### 4.4 ML-значения (многоязычный текст) + +Текстовые поля, попадающие в ``-структуру 1С (`synonym`, `tooltip`), принимают две формы: + +- **строка** → один язык `ru`: `"synonym": "Наименование"`; +- **объект `{ lang: content }`** → по `` на язык, **в порядке ключей**: `"tooltip": { "ru": "Подсказка", "en": "Hint" }`. + +Пустая строка `""` / отсутствие ключа → самозакрывающийся тег (``). Консистентно с формой `title`/`tooltip` в form-compile. + --- ## 5. Табличные части diff --git a/tests/skills/cases/meta-compile/catalog-attr-ml.json b/tests/skills/cases/meta-compile/catalog-attr-ml.json new file mode 100644 index 00000000..51bb479b --- /dev/null +++ b/tests/skills/cases/meta-compile/catalog-attr-ml.json @@ -0,0 +1,12 @@ +{ + "name": "Справочник с ML-синонимом и подсказкой реквизита", + "input": { + "type": "Catalog", "name": "Контрагенты", + "attributes": [ + { "name": "ИНН", "type": "String(12)", "synonym": { "ru": "ИНН", "en": "TIN" }, "tooltip": "Идентификационный номер налогоплательщика" }, + { "name": "Комментарий", "type": "String(200)", "tooltip": { "ru": "Произвольный комментарий", "en": "Free-form comment" } } + ] + }, + "validatePath": "Catalogs/Контрагенты", + "expect": { "files": ["Catalogs/Контрагенты.xml"] } +} diff --git a/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Catalogs/Контрагенты.xml b/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Catalogs/Контрагенты.xml new file mode 100644 index 00000000..cf2a78f2 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Catalogs/Контрагенты.xml @@ -0,0 +1,198 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + + Контрагенты + + + ru + Контрагенты + + + + false + HierarchyFoldersAndItems + false + 2 + true + true + + ToItems + 9 + 25 + String + Variable + WholeCatalog + false + true + AsDescription + + Auto + InDialog + false + BothWays + + Catalog.Контрагенты.StandardAttribute.Description + Catalog.Контрагенты.StandardAttribute.Code + + Begin + DontUse + Directly + + + + + + + + + + + false + + + Automatic + Use + + + + + + DontUse + Auto + DontUse + false + false + + + + + ИНН + + + ru + ИНН + + + en + TIN + + + + + xs:string + + 12 + Variable + + + false + + + + + ru + Идентификационный номер налогоплательщика + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + ForItem + DontIndex + Use + Use + + + + + Комментарий + + + ru + Комментарий + + + + + xs:string + + 200 + Variable + + + false + + + + + ru + Произвольный комментарий + + + en + Free-form comment + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + ForItem + DontIndex + Use + Use + + + + + diff --git a/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Catalogs/Контрагенты/Ext/ObjectModule.bsl b/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Catalogs/Контрагенты/Ext/ObjectModule.bsl new file mode 100644 index 00000000..e69de29b diff --git a/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Configuration.xml b/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Configuration.xml new file mode 100644 index 00000000..c07959c0 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + UUID-012 + UUID-013 + + + UUID-014 + UUID-015 + + + + TestConfig + + + ru + TestConfig + + + + + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + + + + false + false + false + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + + Normal + + + Language.Русский + + + + + + Managed + NotAutoFree + DontUse + DontUse + TaxiEnableVersion8_2 + DontUse + Version8_3_24 + + + + Русский + Контрагенты + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Ext/ClientApplicationInterface.xml b/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Languages/Русский.xml b/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/catalog-attr-ml/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file