Skip to content

Commit cf96884

Browse files
authored
Add getApiMaturityFromXML() in conformance-xml-parser: if apiMaturity is (#1699)
set on the element, use it; otherwise treat conformance as provisional when the parsed expression includes provisional (including otherwiseConform with provisionalConform plus other branches). Use it from zcl-loader-silabs for clusters, commands, args, attributes, events, event fields, enums, enum items, bitmaps, bitmap fields, features, structs, and struct items. Extend test/resource/meta/api_maturity.xml and gen-matter-api-maturity tests for plain provisionalConform, otherwiseConform+provisional, and explicit apiMaturity winning over conflicting conformance. - update schema - Github: ZAP #1664
1 parent 27f4885 commit cf96884

6 files changed

Lines changed: 98 additions & 12 deletions

File tree

docs/api.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21346,6 +21346,7 @@ This module provides utilities for parsing conformance data from XML into expres
2134621346
* [~parseConformanceFromXML(operand)](#module_Validation API_ Parse conformance data from XML..parseConformanceFromXML) ⇒
2134721347
* [~parseConformanceRecursively(operand, depth, parentJoinChar)](#module_Validation API_ Parse conformance data from XML..parseConformanceRecursively) ⇒
2134821348
* [~getOptionalAttributeFromXML(element, elementType)](#module_Validation API_ Parse conformance data from XML..getOptionalAttributeFromXML) ⇒
21349+
* [~getApiMaturityFromXML(element)](#module_Validation API_ Parse conformance data from XML..getApiMaturityFromXML) ⇒ <code>string</code> \| <code>null</code>
2134921350

2135021351
<a name="module_Validation API_ Parse conformance data from XML..parseConformanceFromXML"></a>
2135121352

@@ -21424,6 +21425,22 @@ Log warnings to zap.log if both optional attribute and conformance are defined
2142421425
| element | <code>\*</code> |
2142521426
| elementType | <code>\*</code> |
2142621427

21428+
<a name="module_Validation API_ Parse conformance data from XML..getApiMaturityFromXML"></a>
21429+
21430+
### Validation API: Parse conformance data from XML~getApiMaturityFromXML(element) ⇒ <code>string</code> \| <code>null</code>
21431+
Determine the effective apiMaturity for an Data Model XML element.
21432+
21433+
If the element has an explicit 'apiMaturity' attribute, return it as-is.
21434+
Otherwise, if the element's conformance contains a <provisionalConform/>
21435+
(including nested conformance tags), return 'provisional'.
21436+
Return null when neither source specifies maturity.
21437+
21438+
**Kind**: inner method of [<code>Validation API: Parse conformance data from XML</code>](#module_Validation API_ Parse conformance data from XML)
21439+
21440+
| Param | Type | Description |
21441+
| --- | --- | --- |
21442+
| element | <code>\*</code> | XML element from xml2js |
21443+
2142721444
<a name="module_Validation API_ Validation APIs"></a>
2142821445

2142921446
## Validation API: Validation APIs

src-electron/validation/conformance-xml-parser.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,5 +194,34 @@ function getOptionalAttributeFromXML(element, elementType) {
194194
}
195195
}
196196

197+
/**
198+
* Determine the effective apiMaturity for an Data Model XML element.
199+
*
200+
* If the element has an explicit 'apiMaturity' attribute, return it as-is.
201+
* Otherwise, if the element's conformance contains a <provisionalConform/>
202+
* (including nested conformance tags), return 'provisional'.
203+
* Return null when neither source specifies maturity.
204+
*
205+
* @param {*} element XML element from xml2js
206+
* @returns {string|null}
207+
*/
208+
function getApiMaturityFromXML(element) {
209+
if (element && element.$ && element.$.apiMaturity) {
210+
return element.$.apiMaturity
211+
}
212+
let conformance = parseConformanceFromXML(element)
213+
if (
214+
conformance &&
215+
conformEvaluator.checkIfExpressionHasOperand(
216+
conformance,
217+
dbEnum.conformanceTag.provisional
218+
)
219+
) {
220+
return dbEnum.conformanceVal.provisional
221+
}
222+
return null
223+
}
224+
197225
exports.parseConformanceFromXML = parseConformanceFromXML
198226
exports.getOptionalAttributeFromXML = getOptionalAttributeFromXML
227+
exports.getApiMaturityFromXML = getApiMaturityFromXML

src-electron/zcl/zcl-loader-silabs.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ function prepareCluster(cluster, context, isExtension = false) {
502502
}
503503
ret.introducedIn = cluster.$.introducedIn
504504
ret.removedIn = cluster.$.removedIn
505-
ret.apiMaturity = cluster.$.apiMaturity
505+
ret.apiMaturity = conformParser.getApiMaturityFromXML(cluster)
506506
}
507507
}
508508

@@ -536,7 +536,7 @@ function prepareCluster(cluster, context, isExtension = false) {
536536
command.$.disableDefaultResponse == 'true' ? false : true,
537537
isFabricScoped: command.$.isFabricScoped == 'true',
538538
isLargeMessage: quality ? quality.largeMessage == 'true' : false,
539-
apiMaturity: command.$.apiMaturity
539+
apiMaturity: conformParser.getApiMaturityFromXML(command)
540540
}
541541
cmd.access = extractAccessIntoArray(command)
542542
if (cmd.manufacturerCode == null) {
@@ -571,7 +571,7 @@ function prepareCluster(cluster, context, isExtension = false) {
571571
fieldIdentifier: lastFieldId,
572572
introducedIn: arg.$.introducedIn,
573573
removedIn: arg.$.removedIn,
574-
apiMaturity: arg.$.apiMaturity
574+
apiMaturity: conformParser.getApiMaturityFromXML(arg)
575575
})
576576
})
577577
}
@@ -588,7 +588,7 @@ function prepareCluster(cluster, context, isExtension = false) {
588588
side: event.$.side,
589589
conformance: conformParser.parseConformanceFromXML(event),
590590
priority: event.$.priority,
591-
apiMaturity: event.$.apiMaturity,
591+
apiMaturity: conformParser.getApiMaturityFromXML(event),
592592
description: event.description ? event.description[0].trim() : '',
593593
isOptional: conformParser.getOptionalAttributeFromXML(event, 'event'),
594594
isFabricSensitive: event.$.isFabricSensitive == 'true'
@@ -617,7 +617,7 @@ function prepareCluster(cluster, context, isExtension = false) {
617617
fieldIdentifier: lastFieldId,
618618
introducedIn: field.$.introducedIn,
619619
removedIn: field.$.removedIn,
620-
apiMaturity: field.$.apiMaturity
620+
apiMaturity: conformParser.getApiMaturityFromXML(field)
621621
})
622622
}
623623
})
@@ -726,7 +726,7 @@ function prepareCluster(cluster, context, isExtension = false) {
726726
isFabricSensitive: isAccessFabricSensitive(attribute),
727727
entryType: attribute.$.entryType,
728728
mustUseTimedWrite: attribute.$.mustUseTimedWrite == 'true',
729-
apiMaturity: attribute.$.apiMaturity,
729+
apiMaturity: conformParser.getApiMaturityFromXML(attribute),
730730
isChangeOmitted: quality ? quality.changeOmitted == 'true' : false,
731731
persistence: quality ? quality.persistence : null
732732
}
@@ -1410,7 +1410,7 @@ function prepareEnumOrBitmap(db, packageId, a, dataType, typeMap) {
14101410
? [{ $: { code: a.$.cluster_code[0] } }]
14111411
: null, // else case: Treating features in a cluster as a bitmap
14121412
discriminator_ref: dataType,
1413-
apiMaturity: a.$.apiMaturity
1413+
apiMaturity: conformParser.getApiMaturityFromXML(a)
14141414
}
14151415
}
14161416

@@ -1467,7 +1467,7 @@ async function processEnumItems(db, filePath, packageId, knownPackages, data) {
14671467
name: item.$.name,
14681468
value: parseInt(item.$.value),
14691469
fieldIdentifier: lastFieldId,
1470-
apiMaturity: item.$.apiMaturity
1470+
apiMaturity: conformParser.getApiMaturityFromXML(item)
14711471
})
14721472
})
14731473
}
@@ -1570,7 +1570,7 @@ async function processBitmapFields(
15701570
name: item.$.name,
15711571
mask: parseInt(item.$.mask),
15721572
fieldIdentifier: lastFieldId,
1573-
apiMaturity: item.$.apiMaturity
1573+
apiMaturity: conformParser.getApiMaturityFromXML(item)
15741574
})
15751575
})
15761576
}
@@ -1605,7 +1605,7 @@ async function processBitmapFields(
16051605
name: item.$.name,
16061606
mask: 1 << itemBit,
16071607
fieldIdentifier: itemBit,
1608-
apiMaturity: item.$.apiMaturity
1608+
apiMaturity: conformParser.getApiMaturityFromXML(item)
16091609
})
16101610
})
16111611
)
@@ -1631,7 +1631,7 @@ function prepareStruct(a, dataType) {
16311631
cluster_code: a.cluster ? a.cluster : null,
16321632
discriminator_ref: dataType,
16331633
isFabricScoped: a.$.isFabricScoped == 'true',
1634-
apiMaturity: a.$.apiMaturity
1634+
apiMaturity: conformParser.getApiMaturityFromXML(a)
16351635
}
16361636
}
16371637

@@ -1691,7 +1691,7 @@ async function processStructItems(db, filePath, packageIds, data, context) {
16911691
isNullable: item.$.isNullable == 'true' ? true : false,
16921692
isOptional: item.$.optional == 'true' ? true : false,
16931693
isFabricSensitive: item.$.isFabricSensitive == 'true' ? true : false,
1694-
apiMaturity: item.$.apiMaturity
1694+
apiMaturity: conformParser.getApiMaturityFromXML(item)
16951695
})
16961696
})
16971697
}

test/gen-matter-api-maturity.test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,25 @@ test(
103103
'optional int8u attribute provisionalAttribute = 1 (provisional);'
104104
)
105105

106+
// apiMaturity is derived from conformance ONLY when no explicit
107+
// apiMaturity attribute is present on the XML element.
108+
expect(ept).toContain(
109+
'optional int8u attribute conformProvisionalAttr = 5 (provisional);'
110+
)
111+
expect(ept).toContain(
112+
'optional int8u attribute otherwiseProvisionalAttr = 6 (provisional);'
113+
)
114+
// An explicit apiMaturity attribute is authoritative: conformance never
115+
// overrides it, even when the two disagree.
116+
expect(ept).toContain(
117+
'optional int8u attribute contradictoryApiMaturityAttr = 7 (deprecated);'
118+
)
119+
expect(ept).not.toContain('contradictoryApiMaturityAttr = 7 (provisional)')
120+
// Explicit 'internal' apiMaturity is preserved regardless of conformance.
121+
expect(ept).toContain(
122+
'optional int8u attribute internalWithMandatoryConformAttr = 8 (internal);'
123+
)
124+
106125
// Maturity for structures should be correct
107126
expect(ept).toContain('struct StableStruct {')
108127
expect(ept).toContain('struct ProvisionalStruct (provisional) {')

test/resource/meta/api_maturity.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ limitations under the License.
6767
<attribute side="server" code="0x0003" define="STRUCT_ATTR_1" type="StableStruct" writable="true" optional="true">StructAttr1</attribute>
6868
<attribute side="server" code="0x0004" define="STRUCT_ATTR_2" type="ProvisionalStruct" writable="true" optional="true">StructAttr2</attribute>
6969

70+
<!-- No 'apiMaturity' attribute; <provisionalConform/> fills it in as 'provisional'. -->
71+
<attribute side="server" code="0x0005" define="CONFORM_PROVISIONAL_ATTR" type="INT8U" writable="true" optional="true">ConformProvisionalAttr<provisionalConform/></attribute>
72+
<!-- No 'apiMaturity' attribute; provisional under <otherwiseConform> (spec-style). -->
73+
<attribute side="server" code="0x0006" define="OTHERWISE_PROVISIONAL_ATTR" type="INT8U" writable="true" optional="true">OtherwiseProvisionalAttr<otherwiseConform>
74+
<provisionalConform/>
75+
<mandatoryConform>
76+
<greaterOrEqualTerm>
77+
<revision value="current"/>
78+
<revision value="2"/>
79+
</greaterOrEqualTerm>
80+
</mandatoryConform>
81+
</otherwiseConform></attribute>
82+
<!-- Explicit 'apiMaturity' always wins; conformance never overrides it even when they disagree. -->
83+
<attribute apiMaturity="deprecated" side="server" code="0x0007" define="CONTRADICTORY_ATTR" type="INT8U" writable="true" optional="true">ContradictoryApiMaturityAttr<provisionalConform/></attribute>
84+
<!-- Explicit 'internal' is Silabs-specific and preserved regardless of conformance. -->
85+
<attribute apiMaturity="internal" side="server" code="0x0008" define="INTERNAL_WITH_M_ATTR" type="INT8U" writable="true" optional="true">InternalWithMandatoryConformAttr<mandatoryConform/></attribute>
86+
7087
<command source="client" code="0x00" name="StableCommand" response="StableCommandResponse" optional="false" apiMaturity="provisional">
7188
<description>A Test command</description>
7289
<access op="invoke" privilege="administer"/>

zcl-builtin/shared/schema/zcl.xsd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,8 @@ This schema describes the format of the XML files, that describe the ZCL specifi
585585
<xs:element ref="otherwiseConform"/>
586586
<xs:element ref="deprecateConform"/>
587587
<xs:element ref="describedConform"/>
588+
<xs:element ref="provisionalConform"/>
589+
<xs:element ref="disallowConform"/>
588590
</xs:choice>
589591
<xs:attribute name="cli"/>
590592
<xs:attribute name="cliFunctionName" type="xs:string"/>
@@ -617,6 +619,8 @@ This schema describes the format of the XML files, that describe the ZCL specifi
617619
<xs:element ref="otherwiseConform"/>
618620
<xs:element ref="deprecateConform"/>
619621
<xs:element ref="describedConform"/>
622+
<xs:element ref="provisionalConform"/>
623+
<xs:element ref="disallowConform"/>
620624
</xs:choice>
621625
<xs:attribute name="code" type="zclCode" use="optional"/>
622626
<xs:attribute name="default" use="optional"/>

0 commit comments

Comments
 (0)