mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-11 08:24:57 +03:00
feat(skd-compile): time type, string(N,fix), and composite type parameters
Calibrated against live Designer output in upload/erf/ПроверкаЭкранирования. - New type 'time' (synonym 'время'): xs:dateTime with DateFractions=Time for time-of-day values. Designer uses the same xs:dateTime XSD type as date/dateTime — only DateFractions differs. Empty value: typed-zero 0001-01-01T00:00:00 (same as dateTime). - Extended string regex to accept (N,fix) → AllowedLength=Fixed (was Variable-only). Non-empty fixed-string values are emitted as-given without space-padding to Length — the platform handles padding on save. - Composite types in parameters (array of types in object form, e.g. ["string(10,fix)", "CatalogRef.X"]) now work end-to-end: valueType emits each type with its qualifiers, and empty composite values serialize as <value xsi:nil="true"/> matching Designer. Test case empty-param-values extended with 5 new params covering all three additions. Snapshot validated by skd-validate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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 "$indent<v8:Type>xs:string</v8:Type>"
|
||||
X "$indent<v8:StringQualifiers>"
|
||||
X "$indent`t<v8:Length>$len</v8:Length>"
|
||||
X "$indent`t<v8:AllowedLength>Variable</v8:AllowedLength>"
|
||||
X "$indent`t<v8:AllowedLength>$al</v8:AllowedLength>"
|
||||
X "$indent</v8:StringQualifiers>"
|
||||
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 "$indent<v8:Type>xs:dateTime</v8:Type>"
|
||||
X "$indent<v8:DateQualifiers>"
|
||||
@@ -996,7 +999,15 @@ function Emit-SingleParam {
|
||||
|
||||
# Value — for valueListAllowed params Designer omits <value> 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<value xsi:nil=`"true`"/>" }
|
||||
}
|
||||
} 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>"
|
||||
|
||||
@@ -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}<v8:Type>xs:boolean</v8:Type>')
|
||||
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}<v8:Type>xs:string</v8:Type>')
|
||||
lines.append(f'{indent}<v8:StringQualifiers>')
|
||||
lines.append(f'{indent}\t<v8:Length>{length}</v8:Length>')
|
||||
lines.append(f'{indent}\t<v8:AllowedLength>Variable</v8:AllowedLength>')
|
||||
lines.append(f'{indent}\t<v8:AllowedLength>{al}</v8:AllowedLength>')
|
||||
lines.append(f'{indent}</v8:StringQualifiers>')
|
||||
return
|
||||
|
||||
@@ -181,10 +183,10 @@ def emit_single_value_type(lines, type_str, indent):
|
||||
lines.append(f'{indent}</v8:NumberQualifiers>')
|
||||
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}<v8:Type>xs:dateTime</v8:Type>')
|
||||
lines.append(f'{indent}<v8:DateQualifiers>')
|
||||
@@ -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 <value> 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<value xsi:nil="true"/>')
|
||||
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,
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -112,6 +112,60 @@
|
||||
</valueType>
|
||||
<valueListAllowed>true</valueListAllowed>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>ПараметрВремяСЗначением</name>
|
||||
<valueType>
|
||||
<v8:Type>xs:dateTime</v8:Type>
|
||||
<v8:DateQualifiers>
|
||||
<v8:DateFractions>Time</v8:DateFractions>
|
||||
</v8:DateQualifiers>
|
||||
</valueType>
|
||||
<value xsi:type="xs:dateTime">0001-01-01T12:30:00</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>ПараметрВремяПусто</name>
|
||||
<valueType>
|
||||
<v8:Type>xs:dateTime</v8:Type>
|
||||
<v8:DateQualifiers>
|
||||
<v8:DateFractions>Time</v8:DateFractions>
|
||||
</v8:DateQualifiers>
|
||||
</valueType>
|
||||
<value xsi:type="xs:dateTime">0001-01-01T00:00:00</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>ПараметрСтрокаФиксСЗначением</name>
|
||||
<valueType>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
<v8:Length>10</v8:Length>
|
||||
<v8:AllowedLength>Fixed</v8:AllowedLength>
|
||||
</v8:StringQualifiers>
|
||||
</valueType>
|
||||
<value xsi:type="xs:string">АБВ</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>ПараметрСтрокаФиксПусто</name>
|
||||
<valueType>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
<v8:Length>10</v8:Length>
|
||||
<v8:AllowedLength>Fixed</v8:AllowedLength>
|
||||
</v8:StringQualifiers>
|
||||
</valueType>
|
||||
<value xsi:type="xs:string"/>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>СоставнойТип</name>
|
||||
<valueType>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
<v8:Length>10</v8:Length>
|
||||
<v8:AllowedLength>Fixed</v8:AllowedLength>
|
||||
</v8:StringQualifiers>
|
||||
<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:CatalogRef.ПлоскийПростой</v8:Type>
|
||||
</valueType>
|
||||
<value xsi:nil="true"/>
|
||||
</parameter>
|
||||
<settingsVariant>
|
||||
<dcsset:name>Основной</dcsset:name>
|
||||
<dcsset:presentation xsi:type="v8:LocalStringType">
|
||||
|
||||
Reference in New Issue
Block a user