diff --git a/.claude/skills/skd-compile/scripts/skd-compile.ps1 b/.claude/skills/skd-compile/scripts/skd-compile.ps1
index 4fa26c2a..00c37ad9 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.25 — Compile 1C DCS from JSON
+# skd-compile v1.26 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$DefinitionFile,
@@ -143,6 +143,7 @@ $script:typeSynonyms["строка"] = "string"
$script:typeSynonyms["булево"] = "boolean"
$script:typeSynonyms["дата"] = "date"
$script:typeSynonyms["датавремя"] = "dateTime"
+$script:typeSynonyms["время"] = "time"
$script:typeSynonyms["стандартныйпериод"] = "StandardPeriod"
# English canonical (lowercase for lookup)
$script:typeSynonyms["bool"] = "boolean"
@@ -219,13 +220,14 @@ function Emit-SingleValueType {
return
}
- # string or string(N)
- if ($typeStr -match '^string(\((\d+)\))?$') {
+ # string, string(N), string(N,fix) — fix → AllowedLength=Fixed
+ if ($typeStr -match '^string(\((\d+)(,(fix|fixed))?\))?$') {
$len = if ($Matches[2]) { $Matches[2] } else { "0" }
+ $al = if ($Matches[4]) { "Fixed" } else { "Variable" }
X "$indentxs:string"
X "$indent"
X "$indent`t$len"
- X "$indent`tVariable"
+ X "$indent`t$al"
X "$indent"
return
}
@@ -253,11 +255,12 @@ function Emit-SingleValueType {
return
}
- # date / dateTime
- if ($typeStr -match '^(date|dateTime)$') {
+ # date / dateTime / time — all use xs:dateTime, differ only in DateFractions
+ if ($typeStr -match '^(date|dateTime|time)$') {
$fractions = switch ($typeStr) {
"date" { "Date" }
"dateTime" { "DateTime" }
+ "time" { "Time" }
}
X "$indentxs:dateTime"
X "$indent"
@@ -996,7 +999,15 @@ function Emit-SingleParam {
# Value — for valueListAllowed params Designer omits when empty
$vla = [bool]$parsed.valueListAllowed
- Emit-ParamValue -type $parsed.type -val $parsed.value -indent "`t`t" -valueListAllowed $vla
+ if ($parsed.type -is [array] -or $parsed.type -is [System.Collections.IList]) {
+ # Composite type — Designer writes xsi:nil for any empty composite;
+ # non-empty composite values are uncommon and would need per-type tagging.
+ if (Test-EmptyValue $parsed.value) {
+ if (-not $vla) { X "`t`t" }
+ }
+ } else {
+ Emit-ParamValue -type $parsed.type -val $parsed.value -indent "`t`t" -valueListAllowed $vla
+ }
# Hidden implies useRestriction=true + availableAsField=false
if ($parsed.hidden -eq $true) {
@@ -1073,9 +1084,19 @@ function Emit-Parameters {
if ($p -is [string]) {
$parsed = Parse-ParamShorthand $p
} else {
+ # Composite type: ["string(10,fix)", "CatalogRef.X"] → array of resolved
+ # strings; emit-valueType handles arrays, empty value falls through to nil.
+ $resolvedType = ""
+ if ($p.type) {
+ if ($p.type -is [array] -or $p.type -is [System.Collections.IList]) {
+ $resolvedType = @($p.type | ForEach-Object { Resolve-TypeStr "$_" })
+ } else {
+ $resolvedType = Resolve-TypeStr "$($p.type)"
+ }
+ }
$parsed = @{
name = "$($p.name)"
- type = if ($p.type) { Resolve-TypeStr "$($p.type)" } else { "" }
+ type = $resolvedType
value = $p.value
autoDates = $false
}
@@ -1148,7 +1169,7 @@ function Emit-EmptyValue {
X "$indent${pf}value>"
} elseif ($t -match '^string') {
X "$indent<${pf}value xsi:type=`"xs:string`"/>"
- } elseif ($t -match '^date') {
+ } elseif ($t -match '^(date|time)') {
X "$indent<${pf}value xsi:type=`"xs:dateTime`">0001-01-01T00:00:00${pf}value>"
} elseif ($t -match '^decimal') {
X "$indent<${pf}value xsi:type=`"xs:decimal`">0${pf}value>"
diff --git a/.claude/skills/skd-compile/scripts/skd-compile.py b/.claude/skills/skd-compile/scripts/skd-compile.py
index bf2e5e6a..63c33b5b 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.25 — Compile 1C DCS from JSON
+# skd-compile v1.26 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import json
@@ -74,6 +74,7 @@ TYPE_SYNONYMS = {
"\u0431\u0443\u043b\u0435\u0432\u043e": "boolean",
"\u0434\u0430\u0442\u0430": "date",
"\u0434\u0430\u0442\u0430\u0432\u0440\u0435\u043c\u044f": "dateTime",
+ "\u0432\u0440\u0435\u043c\u044f": "time",
"\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439\u043f\u0435\u0440\u0438\u043e\u0434": "StandardPeriod",
# English canonical (lowercase)
"bool": "boolean",
@@ -148,14 +149,15 @@ def emit_single_value_type(lines, type_str, indent):
lines.append(f'{indent}xs:boolean')
return
- # string or string(N)
- m = re.match(r'^string(\((\d+)\))?$', type_str)
+ # string, string(N), string(N,fix) — fix → AllowedLength=Fixed
+ m = re.match(r'^string(\((\d+)(,(fix|fixed))?\))?$', type_str)
if m:
length = m.group(2) if m.group(2) else '0'
+ al = 'Fixed' if m.group(4) else 'Variable'
lines.append(f'{indent}xs:string')
lines.append(f'{indent}')
lines.append(f'{indent}\t{length}')
- lines.append(f'{indent}\tVariable')
+ lines.append(f'{indent}\t{al}')
lines.append(f'{indent}')
return
@@ -181,10 +183,10 @@ def emit_single_value_type(lines, type_str, indent):
lines.append(f'{indent}')
return
- # date / dateTime
- m = re.match(r'^(date|dateTime)$', type_str)
+ # date / dateTime / time — all use xs:dateTime, differ only in DateFractions
+ m = re.match(r'^(date|dateTime|time)$', type_str)
if m:
- fractions_map = {'date': 'Date', 'dateTime': 'DateTime'}
+ fractions_map = {'date': 'Date', 'dateTime': 'DateTime', 'time': 'Time'}
fractions = fractions_map[type_str]
lines.append(f'{indent}xs:dateTime')
lines.append(f'{indent}')
@@ -827,7 +829,7 @@ def emit_empty_value(lines, type_str, indent, tag_prefix='', value_list_allowed=
lines.append(f'{indent}{pf}value>')
elif re.match(r'^string', t):
lines.append(f'{indent}<{pf}value xsi:type="xs:string"/>')
- elif re.match(r'^date', t):
+ elif re.match(r'^(date|time)', t):
lines.append(f'{indent}<{pf}value xsi:type="xs:dateTime">0001-01-01T00:00:00{pf}value>')
elif re.match(r'^decimal', t):
lines.append(f'{indent}<{pf}value xsi:type="xs:decimal">0{pf}value>')
@@ -898,7 +900,15 @@ def emit_single_param(lines, p, parsed):
# Value — for valueListAllowed params Designer omits when empty
vla = bool(parsed.get('valueListAllowed'))
- emit_param_value(lines, parsed.get('type', ''), parsed.get('value'), '\t\t', vla)
+ p_type = parsed.get('type', '')
+ if isinstance(p_type, (list, tuple)):
+ # Composite type — Designer writes xsi:nil for any empty composite;
+ # non-empty composite values are uncommon and would need per-type tagging.
+ if is_empty_value(parsed.get('value')):
+ if not vla:
+ lines.append('\t\t')
+ else:
+ emit_param_value(lines, p_type, parsed.get('value'), '\t\t', vla)
# Hidden implies useRestriction=true + availableAsField=false
if parsed.get('hidden') is True:
@@ -971,9 +981,18 @@ def emit_parameters(lines, defn):
if isinstance(p, str):
parsed = parse_param_shorthand(p)
else:
+ # Composite type: ["string(10,fix)", "CatalogRef.X"] → list of resolved
+ # strings; emit_value_type handles lists, empty value falls through to nil.
+ raw_type = p.get('type')
+ if isinstance(raw_type, (list, tuple)):
+ resolved_type = [resolve_type_str(str(t)) for t in raw_type]
+ elif raw_type:
+ resolved_type = resolve_type_str(str(raw_type))
+ else:
+ resolved_type = ''
parsed = {
'name': str(p.get('name', '')),
- 'type': resolve_type_str(str(p['type'])) if p.get('type') else '',
+ 'type': resolved_type,
'value': p.get('value'),
'autoDates': False,
}
diff --git a/tests/skills/cases/skd-compile/empty-param-values.json b/tests/skills/cases/skd-compile/empty-param-values.json
index 2131d040..e0091f9f 100644
--- a/tests/skills/cases/skd-compile/empty-param-values.json
+++ b/tests/skills/cases/skd-compile/empty-param-values.json
@@ -17,7 +17,12 @@
"ПараметрБулево: boolean = ",
"ПараметрСтандартныйПериод: StandardPeriod = _",
{ "name": "ПараметрТипНеЗадан", "value": null },
- "ПараметрСписокСтрок: string @valueList"
+ "ПараметрСписокСтрок: string @valueList",
+ "ПараметрВремяСЗначением: time = 0001-01-01T12:30:00",
+ "ПараметрВремяПусто: time",
+ "ПараметрСтрокаФиксСЗначением: string(10,fix) = АБВ",
+ "ПараметрСтрокаФиксПусто: string(10,fix)",
+ { "name": "СоставнойТип", "type": ["string(10,fix)", "CatalogRef.ПлоскийПростой"], "value": null }
]
},
"validatePath": "Template.xml",
diff --git a/tests/skills/cases/skd-compile/snapshots/empty-param-values/Template.xml b/tests/skills/cases/skd-compile/snapshots/empty-param-values/Template.xml
index 40d32cb4..75000f69 100644
--- a/tests/skills/cases/skd-compile/snapshots/empty-param-values/Template.xml
+++ b/tests/skills/cases/skd-compile/snapshots/empty-param-values/Template.xml
@@ -112,6 +112,60 @@
true
+
+ ПараметрВремяСЗначением
+
+ xs:dateTime
+
+ Time
+
+
+ 0001-01-01T12:30:00
+
+
+ ПараметрВремяПусто
+
+ xs:dateTime
+
+ Time
+
+
+ 0001-01-01T00:00:00
+
+
+ ПараметрСтрокаФиксСЗначением
+
+ xs:string
+
+ 10
+ Fixed
+
+
+ АБВ
+
+
+ ПараметрСтрокаФиксПусто
+
+ xs:string
+
+ 10
+ Fixed
+
+
+
+
+
+ СоставнойТип
+
+ xs:string
+
+ 10
+ Fixed
+
+ d5p1:CatalogRef.ПлоскийПростой
+
+
+
Основной