diff --git a/.claude/skills/skd-compile/SKILL.md b/.claude/skills/skd-compile/SKILL.md index f7321c2d..6d958f4a 100644 --- a/.claude/skills/skd-compile/SKILL.md +++ b/.claude/skills/skd-compile/SKILL.md @@ -85,6 +85,23 @@ powershell.exe -NoProfile -File .claude/skills/skd-compile/scripts/skd-compile.p В объектной форме: `"useRestriction": { "field": true, "condition": true, "group": true, "order": true }` или `"restrict": ["noField", "noFilter"]`. +### Вычисляемые поля (calculatedFields) + +Shorthand: `"Имя [Заголовок]: тип = Выражение #noField #noFilter #noGroup #noOrder"` — все части кроме имени опциональны. + +```json +"calculatedFields": [ + "Маржа = Цена - Закупка", + "Наценка [Наценка, %]: decimal(10,2) = Маржа / Закупка * 100", + "Служебное: string = \"\" #noField #noFilter #noGroup #noOrder" +] +``` + +Объектная форма — когда нужна `appearance`: +```json +{ "name": "Маржа", "title": "Маржа", "expression": "Цена - Закупка", "type": "decimal(15,2)", "useRestriction": "#noField #noFilter" } +``` + ### Итоги (shorthand) ```json diff --git a/.claude/skills/skd-compile/scripts/skd-compile.ps1 b/.claude/skills/skd-compile/scripts/skd-compile.ps1 index 52909ae8..f1201d0b 100644 --- a/.claude/skills/skd-compile/scripts/skd-compile.ps1 +++ b/.claude/skills/skd-compile/scripts/skd-compile.ps1 @@ -1,4 +1,4 @@ -# skd-compile v1.12 — Compile 1C DCS from JSON +# skd-compile v1.13 — Compile 1C DCS from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$DefinitionFile, @@ -367,15 +367,51 @@ function Parse-ParamShorthand { function Parse-CalcShorthand { param([string]$s) - # "DataPath = Expression" - $idx = $s.IndexOf('=') - if ($idx -gt 0) { - return @{ - dataPath = $s.Substring(0, $idx).Trim() - expression = $s.Substring($idx + 1).Trim() - } + # Pattern: "Name [Title]: type = Expression #noField #noFilter ...". + # - `[Title]` is extracted only from the LHS of '=' so that `[...]` inside + # an expression (e.g. index access) isn't interpreted as a title. + # - `#restrict` flags use a known-names pattern and are extracted globally — + # the docs put them after `=`, and the closed flag set avoids matching + # `#word` that happens to appear inside a string literal. + $restrictPattern = '#(noField|noFilter|noCondition|noGroup|noOrder)\b' + + $restrict = @() + foreach ($m in [regex]::Matches($s, $restrictPattern)) { + $restrict += $m.Groups[1].Value + } + $s = [regex]::Replace($s, "\s*$restrictPattern", '') + + $eqIdx = $s.IndexOf('=') + if ($eqIdx -gt 0) { + $lhs = $s.Substring(0, $eqIdx) + $rhs = $s.Substring($eqIdx + 1).Trim() + } else { + $lhs = $s + $rhs = "" + } + + $title = "" + if ($lhs -match '\[([^\]]+)\]') { + $title = $Matches[1] + $lhs = $lhs -replace '\s*\[[^\]]+\]', '' + } + $lhs = $lhs.Trim() + + $type = "" + $dataPath = $lhs + if ($lhs.Contains(':')) { + $parts = $lhs -split ':', 2 + $dataPath = $parts[0].Trim() + $type = Resolve-TypeStr ($parts[1].Trim()) + } + + return @{ + dataPath = $dataPath + expression = $rhs + type = $type + title = $title + restrict = $restrict } - return @{ dataPath = $s.Trim(); expression = "" } } # --- 8b. DataParameter shorthand parser --- @@ -771,64 +807,90 @@ function Emit-DataSetLinks { # === CalculatedFields === function Emit-CalcFields { if (-not $def.calculatedFields) { return } + $restrictMap = @{ + "noField" = "field"; "noFilter" = "condition"; "noCondition" = "condition" + "noGroup" = "group"; "noOrder" = "order" + } foreach ($cf in $def.calculatedFields) { + # Collect dataPath/expression/title/type/restrict/appearance from either + # shorthand string or object form. Object form accepts dataPath/field/name + # as synonyms; useRestriction/restrict accepts object, array, or flag string. + $title = "" + $typeStr = "" + $restrictTokens = @() + $restrictObj = $null + $appearance = $null + if ($cf -is [string]) { $parsed = Parse-CalcShorthand $cf + $dataPath = "$($parsed.dataPath)" + $expression = "$($parsed.expression)" + $title = "$($parsed.title)" + $typeStr = "$($parsed.type)" + if ($parsed.restrict) { $restrictTokens = @($parsed.restrict) } } else { - $dp = if ($cf.dataPath) { "$($cf.dataPath)" } else { "$($cf.field)" } - $parsed = @{ - dataPath = $dp - expression = "$($cf.expression)" - } - } + $dataPath = if ($cf.dataPath) { "$($cf.dataPath)" } + elseif ($cf.field) { "$($cf.field)" } + else { "$($cf.name)" } + $expression = "$($cf.expression)" + if ($cf.title) { $title = "$($cf.title)" } + if ($cf.type) { $typeStr = Resolve-TypeStr "$($cf.type)" } - X "`t" - X "`t`t$(Esc-Xml $parsed.dataPath)" - X "`t`t$(Esc-Xml $parsed.expression)" - - if ($cf -isnot [string]) { - if ($cf.title) { - Emit-MLText -tag "title" -text "$($cf.title)" -indent "`t`t" - } - if ($cf.type) { - $cfType = Resolve-TypeStr "$($cf.type)" - X "`t`t" - Emit-ValueType -typeStr $cfType -indent "`t`t`t" - X "`t`t" - } $restrictVal = if ($cf.restrict) { $cf.restrict } elseif ($cf.useRestriction) { $cf.useRestriction } else { $null } if ($restrictVal) { - X "`t`t" if ($restrictVal -is [System.Management.Automation.PSCustomObject] -or $restrictVal -is [hashtable]) { - # Object form: { "field": true, "condition": true, ... } - foreach ($prop in $restrictVal.PSObject.Properties) { - if ($prop.Value -eq $true) { - X "`t`t`t<$($prop.Name)>true" - } + $restrictObj = $restrictVal + } elseif ($restrictVal -is [string]) { + # Flag-string form: "#noField #noFilter #noGroup #noOrder" (or without `#`) + foreach ($tok in ($restrictVal -split '\s+')) { + $t = $tok.Trim().TrimStart('#') + if ($t) { $restrictTokens += $t } } } else { # Array form: ["noField", "noFilter", ...] - $restrictMap = @{ - "noField" = "field"; "noFilter" = "condition"; "noCondition" = "condition" - "noGroup" = "group"; "noOrder" = "order" - } - foreach ($r in $restrictVal) { - $xmlName = $restrictMap["$r"] - if ($xmlName) { X "`t`t`t<$xmlName>true" } + foreach ($r in $restrictVal) { $restrictTokens += "$r" } + } + } + if ($cf.appearance) { $appearance = $cf.appearance } + } + + X "`t" + X "`t`t$(Esc-Xml $dataPath)" + X "`t`t$(Esc-Xml $expression)" + + if ($title) { + Emit-MLText -tag "title" -text $title -indent "`t`t" + } + if ($typeStr) { + X "`t`t" + Emit-ValueType -typeStr $typeStr -indent "`t`t`t" + X "`t`t" + } + if ($restrictObj -or $restrictTokens.Count -gt 0) { + X "`t`t" + if ($restrictObj) { + foreach ($prop in $restrictObj.PSObject.Properties) { + if ($prop.Value -eq $true) { + X "`t`t`t<$($prop.Name)>true" } } - X "`t`t" - } - if ($cf.appearance) { - X "`t`t" - foreach ($prop in $cf.appearance.PSObject.Properties) { - X "`t`t`t" - X "`t`t`t`t$(Esc-Xml $prop.Name)" - X "`t`t`t`t$(Esc-Xml "$($prop.Value)")" - X "`t`t`t" + } else { + foreach ($r in $restrictTokens) { + $xmlName = $restrictMap["$r"] + if ($xmlName) { X "`t`t`t<$xmlName>true" } } - X "`t`t" } + X "`t`t" + } + if ($appearance) { + X "`t`t" + foreach ($prop in $appearance.PSObject.Properties) { + X "`t`t`t" + X "`t`t`t`t$(Esc-Xml $prop.Name)" + X "`t`t`t`t$(Esc-Xml "$($prop.Value)")" + X "`t`t`t" + } + X "`t`t" } X "`t" diff --git a/.claude/skills/skd-compile/scripts/skd-compile.py b/.claude/skills/skd-compile/scripts/skd-compile.py index 6c56512b..3d9add72 100644 --- a/.claude/skills/skd-compile/scripts/skd-compile.py +++ b/.claude/skills/skd-compile/scripts/skd-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# skd-compile v1.12 — Compile 1C DCS from JSON +# skd-compile v1.13 — Compile 1C DCS from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json @@ -277,13 +277,46 @@ def parse_param_shorthand(s): # --- Calculated field shorthand parser --- def parse_calc_shorthand(s): - idx = s.find('=') - if idx > 0: - return { - 'dataPath': s[:idx].strip(), - 'expression': s[idx + 1:].strip(), - } - return {'dataPath': s.strip(), 'expression': ''} + # Pattern: "Name [Title]: type = Expression #noField #noFilter ...". + # - `[Title]` is extracted only from the LHS of '=' so that `[...]` inside + # an expression (e.g. index access) isn't interpreted as a title. + # - `#restrict` flags use a known-names pattern and are extracted globally — + # the docs put them after `=`, and the closed flag set avoids matching + # `#word` that happens to appear inside a string literal. + restrict_pattern = r'#(noField|noFilter|noCondition|noGroup|noOrder)\b' + + restrict = re.findall(restrict_pattern, s) + s = re.sub(r'\s*' + restrict_pattern, '', s) + + eq_idx = s.find('=') + if eq_idx > 0: + lhs = s[:eq_idx] + rhs = s[eq_idx + 1:].strip() + else: + lhs = s + rhs = '' + + title = '' + m = re.search(r'\[([^\]]+)\]', lhs) + if m: + title = m.group(1) + lhs = re.sub(r'\s*\[[^\]]+\]', '', lhs) + lhs = lhs.strip() + + type_str = '' + data_path = lhs + if ':' in lhs: + colon_idx = lhs.index(':') + data_path = lhs[:colon_idx].strip() + type_str = resolve_type_str(lhs[colon_idx + 1:].strip()) + + return { + 'dataPath': data_path, + 'expression': rhs, + 'type': type_str, + 'title': title, + 'restrict': restrict, + } # --- DataParameter shorthand parser --- @@ -623,56 +656,81 @@ def emit_data_set_links(lines, defn): def emit_calc_fields(lines, defn): if not defn.get('calculatedFields'): return + restrict_map = { + 'noField': 'field', 'noFilter': 'condition', 'noCondition': 'condition', + 'noGroup': 'group', 'noOrder': 'order', + } for cf in defn['calculatedFields']: + # Collect dataPath/expression/title/type/restrict/appearance from either + # shorthand string or object form. Object form accepts dataPath/field/name + # as synonyms; useRestriction/restrict accepts object, array, or flag string. + title = '' + type_str = '' + restrict_tokens = [] + restrict_obj = None + appearance = None + if isinstance(cf, str): parsed = parse_calc_shorthand(cf) - is_obj = False + data_path = parsed['dataPath'] + expression = parsed['expression'] + title = parsed.get('title', '') or '' + type_str = parsed.get('type', '') or '' + restrict_tokens = list(parsed.get('restrict') or []) else: - parsed = { - 'dataPath': str(cf.get('dataPath') or cf.get('field', '')), - 'expression': str(cf.get('expression', '')), - } - is_obj = True - - lines.append('\t') - lines.append(f'\t\t{esc_xml(parsed["dataPath"])}') - lines.append(f'\t\t{esc_xml(parsed["expression"])}') - - if is_obj: + data_path = str(cf.get('dataPath') or cf.get('field') or cf.get('name') or '') + expression = str(cf.get('expression', '')) if cf.get('title'): - emit_mltext(lines, '\t\t', 'title', str(cf['title'])) + title = str(cf['title']) if cf.get('type'): - cf_type = resolve_type_str(str(cf['type'])) - lines.append('\t\t') - emit_value_type(lines, cf_type, '\t\t\t') - lines.append('\t\t') - restrict_val = cf.get('restrict') or cf.get('useRestriction') + type_str = resolve_type_str(str(cf['type'])) + + restrict_val = cf.get('restrict') if cf.get('restrict') is not None else cf.get('useRestriction') if restrict_val: - lines.append('\t\t') if isinstance(restrict_val, dict): - # Object form: { "field": true, "condition": true, ... } - for xml_name, flag in restrict_val.items(): - if flag: - lines.append(f'\t\t\t<{esc_xml(str(xml_name))}>true') + restrict_obj = restrict_val + elif isinstance(restrict_val, str): + # Flag-string form: "#noField #noFilter #noGroup #noOrder" (or without `#`) + for tok in restrict_val.split(): + t = tok.strip().lstrip('#') + if t: + restrict_tokens.append(t) else: # Array form: ["noField", "noFilter", ...] - restrict_map = { - 'noField': 'field', 'noFilter': 'condition', 'noCondition': 'condition', - 'noGroup': 'group', 'noOrder': 'order', - } for r in restrict_val: - xml_name = restrict_map.get(str(r)) - if xml_name: - lines.append(f'\t\t\t<{xml_name}>true') - lines.append('\t\t') - if cf.get('appearance'): - lines.append('\t\t') - for k, v in cf['appearance'].items(): - lines.append('\t\t\t') - lines.append(f'\t\t\t\t{esc_xml(k)}') - lines.append(f'\t\t\t\t{esc_xml(str(v))}') - lines.append('\t\t\t') - lines.append('\t\t') + restrict_tokens.append(str(r)) + appearance = cf.get('appearance') + + lines.append('\t') + lines.append(f'\t\t{esc_xml(data_path)}') + lines.append(f'\t\t{esc_xml(expression)}') + + if title: + emit_mltext(lines, '\t\t', 'title', title) + if type_str: + lines.append('\t\t') + emit_value_type(lines, type_str, '\t\t\t') + lines.append('\t\t') + if restrict_obj or restrict_tokens: + lines.append('\t\t') + if restrict_obj: + for xml_name, flag in restrict_obj.items(): + if flag: + lines.append(f'\t\t\t<{esc_xml(str(xml_name))}>true') + else: + for r in restrict_tokens: + xml_name = restrict_map.get(str(r)) + if xml_name: + lines.append(f'\t\t\t<{xml_name}>true') + lines.append('\t\t') + if appearance: + lines.append('\t\t') + for k, v in appearance.items(): + lines.append('\t\t\t') + lines.append(f'\t\t\t\t{esc_xml(k)}') + lines.append(f'\t\t\t\t{esc_xml(str(v))}') + lines.append('\t\t\t') + lines.append('\t\t') lines.append('\t') diff --git a/.claude/skills/skd-edit/scripts/skd-edit.ps1 b/.claude/skills/skd-edit/scripts/skd-edit.ps1 index 7a8cc25d..7b59bef2 100644 --- a/.claude/skills/skd-edit/scripts/skd-edit.ps1 +++ b/.claude/skills/skd-edit/scripts/skd-edit.ps1 @@ -1,4 +1,4 @@ -# skd-edit v1.10 — Atomic 1C DCS editor +# skd-edit v1.11 — Atomic 1C DCS editor # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -251,36 +251,46 @@ function Parse-TotalShorthand { function Parse-CalcShorthand { param([string]$s) - $title = "" - # Extract [Title] first - if ($s -match '\[([^\]]+)\]') { - $title = $Matches[1] - $s = $s -replace '\s*\[[^\]]+\]', '' - } + # Pattern: "Name [Title]: type = Expression #noField #noFilter ...". + # - `[Title]` is extracted only from the LHS of '=' so that `[...]` inside + # an expression (e.g. index access) isn't interpreted as a title. + # - `#restrict` flags use a known-names pattern and are extracted globally — + # the docs put them after `=`, and the closed flag set avoids matching + # `#word` that happens to appear inside a string literal. + $restrictPattern = '#(noField|noFilter|noCondition|noGroup|noOrder)\b' - # Extract #restrictions $restrict = @() - $restrictMatches = [regex]::Matches($s, '#(\w+)') - foreach ($m in $restrictMatches) { + foreach ($m in [regex]::Matches($s, $restrictPattern)) { $restrict += $m.Groups[1].Value } - $s = [regex]::Replace($s, '\s*#\w+', '') + $s = [regex]::Replace($s, "\s*$restrictPattern", '') - # Support "Name: Type = Expression" and "Name = Expression" $eqIdx = $s.IndexOf('=') if ($eqIdx -gt 0) { - $left = $s.Substring(0, $eqIdx).Trim() - $expression = $s.Substring($eqIdx + 1).Trim() - - if ($left.Contains(':')) { - $colonIdx = $left.IndexOf(':') - $dataPath = $left.Substring(0, $colonIdx).Trim() - $type = Resolve-TypeStr ($left.Substring($colonIdx + 1).Trim()) - return @{ dataPath = $dataPath; expression = $expression; type = $type; title = $title; restrict = $restrict } - } - return @{ dataPath = $left; expression = $expression; type = ""; title = $title; restrict = $restrict } + $lhs = $s.Substring(0, $eqIdx) + $rhs = $s.Substring($eqIdx + 1).Trim() + } else { + $lhs = $s + $rhs = $null } - return @{ dataPath = $s.Trim(); expression = ""; type = ""; title = $title; restrict = $restrict } + + $title = "" + if ($lhs -match '\[([^\]]+)\]') { + $title = $Matches[1] + $lhs = $lhs -replace '\s*\[[^\]]+\]', '' + } + $lhs = $lhs.Trim() + + if ($null -ne $rhs) { + if ($lhs.Contains(':')) { + $colonIdx = $lhs.IndexOf(':') + $dataPath = $lhs.Substring(0, $colonIdx).Trim() + $type = Resolve-TypeStr ($lhs.Substring($colonIdx + 1).Trim()) + return @{ dataPath = $dataPath; expression = $rhs; type = $type; title = $title; restrict = $restrict } + } + return @{ dataPath = $lhs; expression = $rhs; type = ""; title = $title; restrict = $restrict } + } + return @{ dataPath = $lhs; expression = ""; type = ""; title = $title; restrict = $restrict } } function Parse-ParamShorthand { diff --git a/.claude/skills/skd-edit/scripts/skd-edit.py b/.claude/skills/skd-edit/scripts/skd-edit.py index b63ed1d6..9f480516 100644 --- a/.claude/skills/skd-edit/scripts/skd-edit.py +++ b/.claude/skills/skd-edit/scripts/skd-edit.py @@ -1,4 +1,4 @@ -# skd-edit v1.10 — Atomic 1C DCS editor (Python port) +# skd-edit v1.11 — Atomic 1C DCS editor (Python port) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import os @@ -260,26 +260,42 @@ def parse_total_shorthand(s): def parse_calc_shorthand(s): - title = "" - m = re.search(r'\[([^\]]+)\]', s) - if m: - title = m.group(1) - s = re.sub(r'\s*\[[^\]]+\]', '', s) + # Pattern: "Name [Title]: type = Expression #noField #noFilter ...". + # - `[Title]` is extracted only from the LHS of '=' so that `[...]` inside + # an expression (e.g. index access) isn't interpreted as a title. + # - `#restrict` flags use a known-names pattern and are extracted globally — + # the docs put them after `=`, and the closed flag set avoids matching + # `#word` that happens to appear inside a string literal. + restrict_pattern = r'#(noField|noFilter|noCondition|noGroup|noOrder)\b' - restrict_matches = re.findall(r'#(\w+)', s) - s = re.sub(r'\s*#\w+', '', s) + restrict_matches = re.findall(restrict_pattern, s) + s = re.sub(r'\s*' + restrict_pattern, '', s) eq_idx = s.find("=") if eq_idx > 0: - left = s[:eq_idx].strip() - expression = s[eq_idx + 1:].strip() - if ":" in left: - colon_idx = left.index(":") - data_path = left[:colon_idx].strip() - type_str = resolve_type_str(left[colon_idx + 1:].strip()) - return {"dataPath": data_path, "expression": expression, "type": type_str, "title": title, "restrict": restrict_matches} - return {"dataPath": left, "expression": expression, "type": "", "title": title, "restrict": restrict_matches} - return {"dataPath": s.strip(), "expression": "", "type": "", "title": title, "restrict": restrict_matches} + lhs = s[:eq_idx] + rhs = s[eq_idx + 1:].strip() + has_rhs = True + else: + lhs = s + rhs = "" + has_rhs = False + + title = "" + m = re.search(r'\[([^\]]+)\]', lhs) + if m: + title = m.group(1) + lhs = re.sub(r'\s*\[[^\]]+\]', '', lhs) + lhs = lhs.strip() + + if has_rhs: + if ":" in lhs: + colon_idx = lhs.index(":") + data_path = lhs[:colon_idx].strip() + type_str = resolve_type_str(lhs[colon_idx + 1:].strip()) + return {"dataPath": data_path, "expression": rhs, "type": type_str, "title": title, "restrict": restrict_matches} + return {"dataPath": lhs, "expression": rhs, "type": "", "title": title, "restrict": restrict_matches} + return {"dataPath": lhs, "expression": "", "type": "", "title": title, "restrict": restrict_matches} def parse_param_shorthand(s): diff --git a/tests/skills/cases/skd-compile/calc-object-name-restrict-string.json b/tests/skills/cases/skd-compile/calc-object-name-restrict-string.json new file mode 100644 index 00000000..254d602a --- /dev/null +++ b/tests/skills/cases/skd-compile/calc-object-name-restrict-string.json @@ -0,0 +1,23 @@ +{ + "name": "calculatedFields объектная форма с name и строковым useRestriction", + "params": { "outputPath": "Template.xml" }, + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ Т.Номенклатура, Т.Сумма ИЗ Регистр КАК Т", + "fields": ["Номенклатура", "Сумма: decimal(15,2)"] + }], + "calculatedFields": [ + { + "name": "ИмяРесурса", + "title": "Имя ресурса", + "expression": "\"\"", + "useRestriction": "#noField #noFilter #noGroup #noOrder" + } + ] + }, + "validatePath": "Template.xml", + "expect": { + "files": ["Template.xml"] + } +} diff --git a/tests/skills/cases/skd-compile/calc-shorthand-extended.json b/tests/skills/cases/skd-compile/calc-shorthand-extended.json new file mode 100644 index 00000000..8570dba9 --- /dev/null +++ b/tests/skills/cases/skd-compile/calc-shorthand-extended.json @@ -0,0 +1,19 @@ +{ + "name": "calculatedFields shorthand с [Title], :type, =expr, #restrict", + "params": { "outputPath": "Template.xml" }, + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ Т.Цена, Т.Закупка ИЗ Регистр КАК Т", + "fields": ["Цена: decimal(15,2)", "Закупка: decimal(15,2)"] + }], + "calculatedFields": [ + "ИмяРесурса [Имя ресурса]: string = \"\" #noField #noFilter #noGroup #noOrder", + "Маржа [Маржа]: decimal(15,2) = Цена - Закупка" + ] + }, + "validatePath": "Template.xml", + "expect": { + "files": ["Template.xml"] + } +} diff --git a/tests/skills/cases/skd-compile/snapshots/calc-object-name-restrict-string/Template.xml b/tests/skills/cases/skd-compile/snapshots/calc-object-name-restrict-string/Template.xml new file mode 100644 index 00000000..a3e62e1c --- /dev/null +++ b/tests/skills/cases/skd-compile/snapshots/calc-object-name-restrict-string/Template.xml @@ -0,0 +1,72 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Номенклатура + Номенклатура + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Номенклатура, Т.Сумма ИЗ Регистр КАК Т + + + ИмяРесурса + "" + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Имя ресурса</v8:content> + </v8:item> + + + true + true + true + true + + + + Основной + + + ru + Основной + + + + + + + + + + + + + + + + diff --git a/tests/skills/cases/skd-compile/snapshots/calc-shorthand-extended/Template.xml b/tests/skills/cases/skd-compile/snapshots/calc-shorthand-extended/Template.xml new file mode 100644 index 00000000..212f0a72 --- /dev/null +++ b/tests/skills/cases/skd-compile/snapshots/calc-shorthand-extended/Template.xml @@ -0,0 +1,105 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Цена + Цена + + xs:decimal + + 15 + 2 + Any + + + + + Закупка + Закупка + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Цена, Т.Закупка ИЗ Регистр КАК Т + + + ИмяРесурса + "" + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Имя ресурса</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + true + true + true + true + + + + Маржа + Цена - Закупка + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Маржа</v8:content> + </v8:item> + + + xs:decimal + + 15 + 2 + Any + + + + + Основной + + + ru + Основной + + + + + + + + + + + + + + + +