mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-13 01:14:56 +03:00
fix(skd-validate): handle composite valueType + system-type namespace
Calibrated against ~868 real ERP/БП reports — three false positives caught: 1. Composite types: <v8:Type>xs:string</v8:Type> followed by <v8:Type>d4p1:CatalogRef.X</v8:Type> with a single trailing <v8:StringQualifiers> is a legitimate pattern. Rewritten check to collect all <v8:Type> and qualifier blocks per <valueType>, then verify each qualifier has a matching scalar type anywhere in the block — not necessarily right before it. 2. System types: AccumulationRecordType (and similar enum-like system types) use the http://v8.1c.ru/8.1/data/enterprise namespace (without /current-config) and a plain TypeName local name with no dot. Whitelisted as a second valid namespace for ref-like types. 3. v8: scalar types extended: v8:Null, v8:Type, v8:ValueStorage — present in real configs as type-less placeholders. Also reverted SKILL.md change from previous commit (validator details don't belong in user-facing docs). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ allowed-tools:
|
||||
|
||||
# /skd-validate — валидация СКД (DataCompositionSchema)
|
||||
|
||||
Проверяет структурную корректность Template.xml схемы компоновки данных. Выявляет ошибки формата, битые ссылки, дубликаты имён, невалидный XDTO в `<valueType>` / `<value>` (отсутствие префикса `xs:`, несовпадение типа и квалификаторов, литералы вроде `_` в `DesignTimeValue`).
|
||||
Проверяет структурную корректность Template.xml схемы компоновки данных. Выявляет ошибки формата, битые ссылки, дубликаты имён.
|
||||
|
||||
## Параметры
|
||||
|
||||
|
||||
@@ -745,111 +745,127 @@ $validTypeQualifier = @{
|
||||
'xs:boolean' = ''
|
||||
'v8:StandardPeriod' = ''
|
||||
'v8:UUID' = ''
|
||||
'v8:Null' = ''
|
||||
'v8:Type' = ''
|
||||
'v8:ValueStorage' = ''
|
||||
}
|
||||
$validSign = @('Any', 'Nonnegative', 'Negative')
|
||||
$validLength = @('Variable', 'Fixed')
|
||||
$validFractions = @('Date', 'DateTime', 'Time')
|
||||
|
||||
# DCS supports composite types: multiple <v8:Type> blocks may share a single
|
||||
# trailing qualifier block (e.g. xs:string + CatalogRef.X + StringQualifiers).
|
||||
# So we collect all types and qualifiers per valueType, then check consistency.
|
||||
$qualifierProducers = @{
|
||||
'v8:NumberQualifiers' = 'xs:decimal'
|
||||
'v8:StringQualifiers' = 'xs:string'
|
||||
'v8:DateQualifiers' = 'xs:dateTime'
|
||||
}
|
||||
|
||||
$valueTypeNodes = $root.SelectNodes("//s:valueType", $ns)
|
||||
$vtChecked = 0
|
||||
$vtOk = $true
|
||||
foreach ($vt in $valueTypeNodes) {
|
||||
$vtChecked++
|
||||
# Walk children in document order
|
||||
$children = @($vt.ChildNodes | Where-Object { $_.NodeType -eq 'Element' })
|
||||
$lastType = $null # short form like 'xs:decimal' or '' (ref types resolved to '')
|
||||
$types = @() # list of short type strings; '' marks a ref type
|
||||
$qualifiers = @() # list of @{ name = 'v8:XQualifiers'; node = $child }
|
||||
|
||||
foreach ($child in $children) {
|
||||
$qName = "$($child.Prefix):$($child.LocalName)"
|
||||
if ($child.LocalName -eq 'Type' -and $child.NamespaceURI -eq 'http://v8.1c.ru/8.1/data/core') {
|
||||
$t = $child.InnerText.Trim()
|
||||
foreach ($child in $vt.ChildNodes) {
|
||||
if ($child.NodeType -ne 'Element') { continue }
|
||||
if ($child.NamespaceURI -ne 'http://v8.1c.ru/8.1/data/core') { continue }
|
||||
$localName = $child.LocalName
|
||||
|
||||
if ($localName -eq 'Type') {
|
||||
$t = "$($child.InnerText)".Trim()
|
||||
if (-not $t) {
|
||||
Report-Error "valueType: <v8:Type> is empty"
|
||||
$vtOk = $false
|
||||
$lastType = $null
|
||||
continue
|
||||
}
|
||||
# Must have a known prefix — xs:, v8:, or any prefix bound to current-config namespace
|
||||
if ($t -match '^([A-Za-z][A-Za-z0-9]*):(.+)$') {
|
||||
$prefix = $Matches[1]
|
||||
$localName = $Matches[2]
|
||||
$lastType = $t
|
||||
$localT = $Matches[2]
|
||||
if ($prefix -eq 'xs' -or $prefix -eq 'v8') {
|
||||
if (-not $validTypeQualifier.ContainsKey($t)) {
|
||||
Report-Error "valueType: unknown type '$t' (allowed: xs:decimal/xs:string/xs:dateTime/xs:boolean/v8:StandardPeriod or <prefix>:*Ref.X)"
|
||||
$vtOk = $false
|
||||
$lastType = $null
|
||||
} else {
|
||||
$types += $t
|
||||
}
|
||||
} else {
|
||||
# Inline-declared prefix — should resolve to current-config namespace
|
||||
$prefixNs = $child.GetNamespaceOfPrefix($prefix)
|
||||
if ($prefixNs -ne 'http://v8.1c.ru/8.1/data/enterprise/current-config') {
|
||||
Report-Error "valueType: type '$t' uses prefix '$prefix' which is not bound to enterprise/current-config namespace"
|
||||
$vtOk = $false
|
||||
$lastType = $null
|
||||
} elseif (-not ($localName -match '^[A-Za-z]+(Ref)?\.')) {
|
||||
Report-Error "valueType: ref type '$t' must look like '<prefix>:<Kind>.<Name>' (e.g. d5p1:CatalogRef.X)"
|
||||
$vtOk = $false
|
||||
$lastType = ''
|
||||
if ($prefixNs -eq 'http://v8.1c.ru/8.1/data/enterprise/current-config') {
|
||||
if (-not ($localT -match '^[A-Za-z]+(Ref)?\.')) {
|
||||
Report-Error "valueType: ref type '$t' must look like '<prefix>:<Kind>.<Name>' (e.g. d5p1:CatalogRef.X)"
|
||||
$vtOk = $false
|
||||
} else {
|
||||
$types += '' # ref — no qualifier needed
|
||||
}
|
||||
} elseif ($prefixNs -eq 'http://v8.1c.ru/8.1/data/enterprise') {
|
||||
# System types: AccumulationRecordType etc. — no qualifiers
|
||||
if (-not ($localT -match '^[A-Za-z][A-Za-z0-9]*$')) {
|
||||
Report-Error "valueType: system type '$t' has unexpected local-name shape"
|
||||
$vtOk = $false
|
||||
} else {
|
||||
$types += ''
|
||||
}
|
||||
} else {
|
||||
$lastType = '' # ref type — no qualifier expected
|
||||
Report-Error "valueType: type '$t' uses prefix '$prefix' bound to unexpected namespace '$prefixNs'"
|
||||
$vtOk = $false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Report-Error "valueType: type '$t' has no namespace prefix (expected xs:/v8:/d5p1: — e.g. xs:decimal not decimal)"
|
||||
$vtOk = $false
|
||||
$lastType = $null
|
||||
}
|
||||
} elseif ($child.LocalName -match 'Qualifiers$' -and $child.NamespaceURI -eq 'http://v8.1c.ru/8.1/data/core') {
|
||||
# Qualifier block — must match preceding Type
|
||||
$expected = if ($lastType -and $validTypeQualifier.ContainsKey($lastType)) {
|
||||
$validTypeQualifier[$lastType]
|
||||
} else { $null }
|
||||
|
||||
if ($null -eq $expected -or $expected -eq '') {
|
||||
Report-Error "valueType: <$qName> after <v8:Type>$lastType</v8:Type> — this type has no qualifiers"
|
||||
$vtOk = $false
|
||||
} elseif ($qName -ne $expected) {
|
||||
Report-Error "valueType: <$qName> doesn't match <v8:Type>$lastType</v8:Type> (expected <$expected>)"
|
||||
$vtOk = $false
|
||||
} else {
|
||||
# Validate qualifier internals
|
||||
if ($qName -eq 'v8:NumberQualifiers') {
|
||||
$digits = $child.SelectSingleNode("v8:Digits", $ns)
|
||||
$frac = $child.SelectSingleNode("v8:FractionDigits", $ns)
|
||||
$sign = $child.SelectSingleNode("v8:AllowedSign", $ns)
|
||||
if (-not $digits -or -not ($digits.InnerText -match '^\d+$')) {
|
||||
Report-Error "v8:NumberQualifiers: <v8:Digits> missing or not a non-negative integer"
|
||||
$vtOk = $false
|
||||
}
|
||||
if (-not $frac -or -not ($frac.InnerText -match '^\d+$')) {
|
||||
Report-Error "v8:NumberQualifiers: <v8:FractionDigits> missing or not a non-negative integer"
|
||||
$vtOk = $false
|
||||
}
|
||||
if ($sign -and $sign.InnerText -and $sign.InnerText -notin $validSign) {
|
||||
Report-Error "v8:NumberQualifiers: <v8:AllowedSign>$($sign.InnerText)</v8:AllowedSign> — must be one of: $($validSign -join ', ')"
|
||||
$vtOk = $false
|
||||
}
|
||||
} elseif ($qName -eq 'v8:StringQualifiers') {
|
||||
$len = $child.SelectSingleNode("v8:Length", $ns)
|
||||
$al = $child.SelectSingleNode("v8:AllowedLength", $ns)
|
||||
if (-not $len -or -not ($len.InnerText -match '^\d+$')) {
|
||||
Report-Error "v8:StringQualifiers: <v8:Length> missing or not a non-negative integer"
|
||||
$vtOk = $false
|
||||
}
|
||||
if ($al -and $al.InnerText -and $al.InnerText -notin $validLength) {
|
||||
Report-Error "v8:StringQualifiers: <v8:AllowedLength>$($al.InnerText)</v8:AllowedLength> — must be one of: $($validLength -join ', ')"
|
||||
$vtOk = $false
|
||||
}
|
||||
} elseif ($qName -eq 'v8:DateQualifiers') {
|
||||
$df = $child.SelectSingleNode("v8:DateFractions", $ns)
|
||||
if ($df -and $df.InnerText -and $df.InnerText -notin $validFractions) {
|
||||
Report-Error "v8:DateQualifiers: <v8:DateFractions>$($df.InnerText)</v8:DateFractions> — must be one of: $($validFractions -join ', ')"
|
||||
$vtOk = $false
|
||||
}
|
||||
} elseif ($localName -match 'Qualifiers$') {
|
||||
$qName = "v8:$localName"
|
||||
$qualifiers += @{ name = $qName; node = $child }
|
||||
# Validate qualifier internals
|
||||
if ($qName -eq 'v8:NumberQualifiers') {
|
||||
$digits = $child.SelectSingleNode("v8:Digits", $ns)
|
||||
$frac = $child.SelectSingleNode("v8:FractionDigits", $ns)
|
||||
$sign = $child.SelectSingleNode("v8:AllowedSign", $ns)
|
||||
if (-not $digits -or -not ($digits.InnerText -match '^\d+$')) {
|
||||
Report-Error "v8:NumberQualifiers: <v8:Digits> missing or not a non-negative integer"
|
||||
$vtOk = $false
|
||||
}
|
||||
if (-not $frac -or -not ($frac.InnerText -match '^\d+$')) {
|
||||
Report-Error "v8:NumberQualifiers: <v8:FractionDigits> missing or not a non-negative integer"
|
||||
$vtOk = $false
|
||||
}
|
||||
if ($sign -and $sign.InnerText -and $sign.InnerText -notin $validSign) {
|
||||
Report-Error "v8:NumberQualifiers: <v8:AllowedSign>$($sign.InnerText)</v8:AllowedSign> — must be one of: $($validSign -join ', ')"
|
||||
$vtOk = $false
|
||||
}
|
||||
} elseif ($qName -eq 'v8:StringQualifiers') {
|
||||
$len = $child.SelectSingleNode("v8:Length", $ns)
|
||||
$al = $child.SelectSingleNode("v8:AllowedLength", $ns)
|
||||
if (-not $len -or -not ($len.InnerText -match '^\d+$')) {
|
||||
Report-Error "v8:StringQualifiers: <v8:Length> missing or not a non-negative integer"
|
||||
$vtOk = $false
|
||||
}
|
||||
if ($al -and $al.InnerText -and $al.InnerText -notin $validLength) {
|
||||
Report-Error "v8:StringQualifiers: <v8:AllowedLength>$($al.InnerText)</v8:AllowedLength> — must be one of: $($validLength -join ', ')"
|
||||
$vtOk = $false
|
||||
}
|
||||
} elseif ($qName -eq 'v8:DateQualifiers') {
|
||||
$df = $child.SelectSingleNode("v8:DateFractions", $ns)
|
||||
if ($df -and $df.InnerText -and $df.InnerText -notin $validFractions) {
|
||||
Report-Error "v8:DateQualifiers: <v8:DateFractions>$($df.InnerText)</v8:DateFractions> — must be one of: $($validFractions -join ', ')"
|
||||
$vtOk = $false
|
||||
}
|
||||
}
|
||||
$lastType = $null # qualifier consumed; next must be another Type or end
|
||||
}
|
||||
}
|
||||
|
||||
# Cross-check: every qualifier must have a matching scalar type in this valueType
|
||||
foreach ($q in $qualifiers) {
|
||||
$producer = $qualifierProducers[$q.name]
|
||||
if (-not $producer) { continue }
|
||||
if ($types -notcontains $producer) {
|
||||
Report-Error "valueType: <$($q.name)> has no matching <v8:Type>$producer</v8:Type> in this valueType"
|
||||
$vtOk = $false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,6 +698,9 @@ _VALID_TYPE_QUALIFIER = {
|
||||
'xs:boolean': '',
|
||||
'v8:StandardPeriod': '',
|
||||
'v8:UUID': '',
|
||||
'v8:Null': '',
|
||||
'v8:Type': '',
|
||||
'v8:ValueStorage': '',
|
||||
}
|
||||
_VALID_SIGN = ('Any', 'Nonnegative', 'Negative')
|
||||
_VALID_LENGTH = ('Variable', 'Fixed')
|
||||
@@ -705,90 +708,107 @@ _VALID_FRACTIONS = ('Date', 'DateTime', 'Time')
|
||||
_V8_NS_URI = 'http://v8.1c.ru/8.1/data/core'
|
||||
_CONFIG_NS_URI = 'http://v8.1c.ru/8.1/data/enterprise/current-config'
|
||||
|
||||
# DCS supports composite types: multiple <v8:Type> blocks may share a single
|
||||
# trailing qualifier block (e.g. xs:string + CatalogRef.X + StringQualifiers).
|
||||
# So we collect all types and qualifiers per valueType, then check consistency.
|
||||
_QUALIFIER_PRODUCERS = {
|
||||
'v8:NumberQualifiers': 'xs:decimal',
|
||||
'v8:StringQualifiers': 'xs:string',
|
||||
'v8:DateQualifiers': 'xs:dateTime',
|
||||
}
|
||||
|
||||
vt_nodes = find_all(root, "//s:valueType")
|
||||
vt_checked = 0
|
||||
vt_ok = True
|
||||
for vt in vt_nodes:
|
||||
vt_checked += 1
|
||||
last_type = None # short form 'xs:decimal' or '' (ref — no qualifiers)
|
||||
types = [] # short type strings; '' marks a ref type
|
||||
qualifiers = [] # list of (qName, node)
|
||||
|
||||
for child in vt:
|
||||
if not isinstance(child.tag, str):
|
||||
continue # comments etc.
|
||||
qname_local = etree.QName(child.tag).localname
|
||||
qname_ns = etree.QName(child.tag).namespace
|
||||
continue
|
||||
qn = etree.QName(child.tag)
|
||||
if qn.namespace != _V8_NS_URI:
|
||||
continue
|
||||
local = qn.localname
|
||||
|
||||
if qname_local == 'Type' and qname_ns == _V8_NS_URI:
|
||||
if local == 'Type':
|
||||
t = (child.text or '').strip()
|
||||
if not t:
|
||||
report_error("valueType: <v8:Type> is empty")
|
||||
vt_ok = False
|
||||
last_type = None
|
||||
continue
|
||||
m = _re_vt.match(r'^([A-Za-z][A-Za-z0-9]*):(.+)$', t)
|
||||
if not m:
|
||||
report_error(f"valueType: type '{t}' has no namespace prefix (expected xs:/v8:/d5p1: — e.g. xs:decimal not decimal)")
|
||||
vt_ok = False
|
||||
last_type = None
|
||||
continue
|
||||
prefix, local = m.group(1), m.group(2)
|
||||
last_type = t
|
||||
prefix, local_t = m.group(1), m.group(2)
|
||||
if prefix in ('xs', 'v8'):
|
||||
if t not in _VALID_TYPE_QUALIFIER:
|
||||
report_error(f"valueType: unknown type '{t}' (allowed: xs:decimal/xs:string/xs:dateTime/xs:boolean/v8:StandardPeriod or <prefix>:*Ref.X)")
|
||||
vt_ok = False
|
||||
last_type = None
|
||||
else:
|
||||
# Inline-declared prefix — must resolve to current-config namespace
|
||||
prefix_ns = child.nsmap.get(prefix)
|
||||
if prefix_ns != _CONFIG_NS_URI:
|
||||
report_error(f"valueType: type '{t}' uses prefix '{prefix}' which is not bound to enterprise/current-config namespace")
|
||||
vt_ok = False
|
||||
last_type = None
|
||||
elif not _re_vt.match(r'^[A-Za-z]+(Ref)?\.', local):
|
||||
report_error(f"valueType: ref type '{t}' must look like '<prefix>:<Kind>.<Name>' (e.g. d5p1:CatalogRef.X)")
|
||||
vt_ok = False
|
||||
last_type = ''
|
||||
else:
|
||||
last_type = '' # ref — no qualifier expected
|
||||
|
||||
elif qname_local.endswith('Qualifiers') and qname_ns == _V8_NS_URI:
|
||||
q_name = f"v8:{qname_local}"
|
||||
expected = _VALID_TYPE_QUALIFIER.get(last_type) if last_type else None
|
||||
if expected is None or expected == '':
|
||||
report_error(f"valueType: <{q_name}> after <v8:Type>{last_type}</v8:Type> — this type has no qualifiers")
|
||||
vt_ok = False
|
||||
elif q_name != expected:
|
||||
report_error(f"valueType: <{q_name}> doesn't match <v8:Type>{last_type}</v8:Type> (expected <{expected}>)")
|
||||
vt_ok = False
|
||||
types.append(t)
|
||||
else:
|
||||
if q_name == 'v8:NumberQualifiers':
|
||||
digits = find(child, "v8:Digits")
|
||||
frac = find(child, "v8:FractionDigits")
|
||||
sign = find(child, "v8:AllowedSign")
|
||||
if digits is None or not _re_vt.match(r'^\d+$', text_of(digits)):
|
||||
report_error("v8:NumberQualifiers: <v8:Digits> missing or not a non-negative integer")
|
||||
prefix_ns = child.nsmap.get(prefix)
|
||||
if prefix_ns == _CONFIG_NS_URI:
|
||||
if not _re_vt.match(r'^[A-Za-z]+(Ref)?\.', local_t):
|
||||
report_error(f"valueType: ref type '{t}' must look like '<prefix>:<Kind>.<Name>' (e.g. d5p1:CatalogRef.X)")
|
||||
vt_ok = False
|
||||
if frac is None or not _re_vt.match(r'^\d+$', text_of(frac)):
|
||||
report_error("v8:NumberQualifiers: <v8:FractionDigits> missing or not a non-negative integer")
|
||||
else:
|
||||
types.append('') # ref — no qualifier needed
|
||||
elif prefix_ns == 'http://v8.1c.ru/8.1/data/enterprise':
|
||||
# System types: AccumulationRecordType etc. — no qualifiers
|
||||
if not _re_vt.match(r'^[A-Za-z][A-Za-z0-9]*$', local_t):
|
||||
report_error(f"valueType: system type '{t}' has unexpected local-name shape")
|
||||
vt_ok = False
|
||||
if sign is not None and text_of(sign) and text_of(sign) not in _VALID_SIGN:
|
||||
report_error(f"v8:NumberQualifiers: <v8:AllowedSign>{text_of(sign)}</v8:AllowedSign> — must be one of: {', '.join(_VALID_SIGN)}")
|
||||
vt_ok = False
|
||||
elif q_name == 'v8:StringQualifiers':
|
||||
length = find(child, "v8:Length")
|
||||
al = find(child, "v8:AllowedLength")
|
||||
if length is None or not _re_vt.match(r'^\d+$', text_of(length)):
|
||||
report_error("v8:StringQualifiers: <v8:Length> missing or not a non-negative integer")
|
||||
vt_ok = False
|
||||
if al is not None and text_of(al) and text_of(al) not in _VALID_LENGTH:
|
||||
report_error(f"v8:StringQualifiers: <v8:AllowedLength>{text_of(al)}</v8:AllowedLength> — must be one of: {', '.join(_VALID_LENGTH)}")
|
||||
vt_ok = False
|
||||
elif q_name == 'v8:DateQualifiers':
|
||||
df = find(child, "v8:DateFractions")
|
||||
if df is not None and text_of(df) and text_of(df) not in _VALID_FRACTIONS:
|
||||
report_error(f"v8:DateQualifiers: <v8:DateFractions>{text_of(df)}</v8:DateFractions> — must be one of: {', '.join(_VALID_FRACTIONS)}")
|
||||
vt_ok = False
|
||||
last_type = None # consumed
|
||||
else:
|
||||
types.append('')
|
||||
else:
|
||||
report_error(f"valueType: type '{t}' uses prefix '{prefix}' bound to unexpected namespace '{prefix_ns}'")
|
||||
vt_ok = False
|
||||
|
||||
elif local.endswith('Qualifiers'):
|
||||
q_name = f"v8:{local}"
|
||||
qualifiers.append((q_name, child))
|
||||
if q_name == 'v8:NumberQualifiers':
|
||||
digits = find(child, "v8:Digits")
|
||||
frac = find(child, "v8:FractionDigits")
|
||||
sign = find(child, "v8:AllowedSign")
|
||||
if digits is None or not _re_vt.match(r'^\d+$', text_of(digits)):
|
||||
report_error("v8:NumberQualifiers: <v8:Digits> missing or not a non-negative integer")
|
||||
vt_ok = False
|
||||
if frac is None or not _re_vt.match(r'^\d+$', text_of(frac)):
|
||||
report_error("v8:NumberQualifiers: <v8:FractionDigits> missing or not a non-negative integer")
|
||||
vt_ok = False
|
||||
if sign is not None and text_of(sign) and text_of(sign) not in _VALID_SIGN:
|
||||
report_error(f"v8:NumberQualifiers: <v8:AllowedSign>{text_of(sign)}</v8:AllowedSign> — must be one of: {', '.join(_VALID_SIGN)}")
|
||||
vt_ok = False
|
||||
elif q_name == 'v8:StringQualifiers':
|
||||
length = find(child, "v8:Length")
|
||||
al = find(child, "v8:AllowedLength")
|
||||
if length is None or not _re_vt.match(r'^\d+$', text_of(length)):
|
||||
report_error("v8:StringQualifiers: <v8:Length> missing or not a non-negative integer")
|
||||
vt_ok = False
|
||||
if al is not None and text_of(al) and text_of(al) not in _VALID_LENGTH:
|
||||
report_error(f"v8:StringQualifiers: <v8:AllowedLength>{text_of(al)}</v8:AllowedLength> — must be one of: {', '.join(_VALID_LENGTH)}")
|
||||
vt_ok = False
|
||||
elif q_name == 'v8:DateQualifiers':
|
||||
df = find(child, "v8:DateFractions")
|
||||
if df is not None and text_of(df) and text_of(df) not in _VALID_FRACTIONS:
|
||||
report_error(f"v8:DateQualifiers: <v8:DateFractions>{text_of(df)}</v8:DateFractions> — must be one of: {', '.join(_VALID_FRACTIONS)}")
|
||||
vt_ok = False
|
||||
|
||||
# Cross-check: every qualifier must have a matching scalar type in this valueType
|
||||
for q_name, _ in qualifiers:
|
||||
producer = _QUALIFIER_PRODUCERS.get(q_name)
|
||||
if not producer:
|
||||
continue
|
||||
if producer not in types:
|
||||
report_error(f"valueType: <{q_name}> has no matching <v8:Type>{producer}</v8:Type> in this valueType")
|
||||
vt_ok = False
|
||||
|
||||
if vt_checked > 0 and vt_ok:
|
||||
report_ok(f"{vt_checked} valueType block(s): structure and qualifiers OK")
|
||||
|
||||
Reference in New Issue
Block a user