diff --git a/docs/api.md b/docs/api.md
index 4f5a7c68ac..de5c358755 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -20135,7 +20135,7 @@ This module provides the APIs for dotdot Loading
* [~parseProfilesData(db, ctx)](#module_Loader API_ Loader APIs..parseProfilesData) ⇒
* [~parseFeatureFlags(db, packageId, featureFlags)](#module_Loader API_ Loader APIs..parseFeatureFlags) ⇒
* [~parseConformanceFromXML(operand)](#module_Loader API_ Loader APIs..parseConformanceFromXML) ⇒
- * [~parseConformanceRecursively(operand, parentJoinChar)](#module_Loader API_ Loader APIs..parseConformanceRecursively) ⇒
+ * [~parseConformanceRecursively(operand, depth, parentJoinChar)](#module_Loader API_ Loader APIs..parseConformanceRecursively) ⇒
* [~parseUiOptions(db, packageId, featureFlags)](#module_Loader API_ Loader APIs..parseUiOptions) ⇒
* [~parseOptions(db)](#module_Loader API_ Loader APIs..parseOptions) ⇒
* [~parseTextOptions(db, pkgRef, textOptions)](#module_Loader API_ Loader APIs..parseTextOptions) ⇒
@@ -21531,7 +21531,7 @@ Output conformance string:
-### Loader API: Loader APIs~parseConformanceRecursively(operand, parentJoinChar) ⇒
+### Loader API: Loader APIs~parseConformanceRecursively(operand, depth, parentJoinChar) ⇒
helper function to parse conformance or an operand in conformance recursively
The baseLevelTerms variable include terms that can not have nested terms.
@@ -21540,10 +21540,11 @@ When they appear, stop recursing and return the name inside directly
**Kind**: inner method of [Loader API: Loader APIs
](#module_Loader API_ Loader APIs)
**Returns**: The conformance string.
-| Param | Type |
-| --- | --- |
-| operand | \*
|
-| parentJoinChar | \*
|
+| Param | Type | Default |
+| --- | --- | --- |
+| operand | \*
| |
+| depth | \*
| 0
|
+| parentJoinChar | \*
| |
@@ -21968,7 +21969,7 @@ This module provides the APIs for new data model loading
* [~parseProfilesData(db, ctx)](#module_Loader API_ Loader APIs..parseProfilesData) ⇒
* [~parseFeatureFlags(db, packageId, featureFlags)](#module_Loader API_ Loader APIs..parseFeatureFlags) ⇒
* [~parseConformanceFromXML(operand)](#module_Loader API_ Loader APIs..parseConformanceFromXML) ⇒
- * [~parseConformanceRecursively(operand, parentJoinChar)](#module_Loader API_ Loader APIs..parseConformanceRecursively) ⇒
+ * [~parseConformanceRecursively(operand, depth, parentJoinChar)](#module_Loader API_ Loader APIs..parseConformanceRecursively) ⇒
* [~parseUiOptions(db, packageId, featureFlags)](#module_Loader API_ Loader APIs..parseUiOptions) ⇒
* [~parseOptions(db)](#module_Loader API_ Loader APIs..parseOptions) ⇒
* [~parseTextOptions(db, pkgRef, textOptions)](#module_Loader API_ Loader APIs..parseTextOptions) ⇒
@@ -23364,7 +23365,7 @@ Output conformance string:
-### Loader API: Loader APIs~parseConformanceRecursively(operand, parentJoinChar) ⇒
+### Loader API: Loader APIs~parseConformanceRecursively(operand, depth, parentJoinChar) ⇒
helper function to parse conformance or an operand in conformance recursively
The baseLevelTerms variable include terms that can not have nested terms.
@@ -23373,10 +23374,11 @@ When they appear, stop recursing and return the name inside directly
**Kind**: inner method of [Loader API: Loader APIs
](#module_Loader API_ Loader APIs)
**Returns**: The conformance string.
-| Param | Type |
-| --- | --- |
-| operand | \*
|
-| parentJoinChar | \*
|
+| Param | Type | Default |
+| --- | --- | --- |
+| operand | \*
| |
+| depth | \*
| 0
|
+| parentJoinChar | \*
| |
@@ -23801,7 +23803,7 @@ This module provides the APIs for ZCL/Data-Model loading.
* [~parseProfilesData(db, ctx)](#module_Loader API_ Loader APIs..parseProfilesData) ⇒
* [~parseFeatureFlags(db, packageId, featureFlags)](#module_Loader API_ Loader APIs..parseFeatureFlags) ⇒
* [~parseConformanceFromXML(operand)](#module_Loader API_ Loader APIs..parseConformanceFromXML) ⇒
- * [~parseConformanceRecursively(operand, parentJoinChar)](#module_Loader API_ Loader APIs..parseConformanceRecursively) ⇒
+ * [~parseConformanceRecursively(operand, depth, parentJoinChar)](#module_Loader API_ Loader APIs..parseConformanceRecursively) ⇒
* [~parseUiOptions(db, packageId, featureFlags)](#module_Loader API_ Loader APIs..parseUiOptions) ⇒
* [~parseOptions(db)](#module_Loader API_ Loader APIs..parseOptions) ⇒
* [~parseTextOptions(db, pkgRef, textOptions)](#module_Loader API_ Loader APIs..parseTextOptions) ⇒
@@ -25197,7 +25199,7 @@ Output conformance string:
-### Loader API: Loader APIs~parseConformanceRecursively(operand, parentJoinChar) ⇒
+### Loader API: Loader APIs~parseConformanceRecursively(operand, depth, parentJoinChar) ⇒
helper function to parse conformance or an operand in conformance recursively
The baseLevelTerms variable include terms that can not have nested terms.
@@ -25206,10 +25208,11 @@ When they appear, stop recursing and return the name inside directly
**Kind**: inner method of [Loader API: Loader APIs
](#module_Loader API_ Loader APIs)
**Returns**: The conformance string.
-| Param | Type |
-| --- | --- |
-| operand | \*
|
-| parentJoinChar | \*
|
+| Param | Type | Default |
+| --- | --- | --- |
+| operand | \*
| |
+| depth | \*
| 0
|
+| parentJoinChar | \*
| |
@@ -25634,7 +25637,7 @@ This module provides the APIs for for common functionality related to loading.
* [~parseProfilesData(db, ctx)](#module_Loader API_ Loader APIs..parseProfilesData) ⇒
* [~parseFeatureFlags(db, packageId, featureFlags)](#module_Loader API_ Loader APIs..parseFeatureFlags) ⇒
* [~parseConformanceFromXML(operand)](#module_Loader API_ Loader APIs..parseConformanceFromXML) ⇒
- * [~parseConformanceRecursively(operand, parentJoinChar)](#module_Loader API_ Loader APIs..parseConformanceRecursively) ⇒
+ * [~parseConformanceRecursively(operand, depth, parentJoinChar)](#module_Loader API_ Loader APIs..parseConformanceRecursively) ⇒
* [~parseUiOptions(db, packageId, featureFlags)](#module_Loader API_ Loader APIs..parseUiOptions) ⇒
* [~parseOptions(db)](#module_Loader API_ Loader APIs..parseOptions) ⇒
* [~parseTextOptions(db, pkgRef, textOptions)](#module_Loader API_ Loader APIs..parseTextOptions) ⇒
@@ -27030,7 +27033,7 @@ Output conformance string:
-### Loader API: Loader APIs~parseConformanceRecursively(operand, parentJoinChar) ⇒
+### Loader API: Loader APIs~parseConformanceRecursively(operand, depth, parentJoinChar) ⇒
helper function to parse conformance or an operand in conformance recursively
The baseLevelTerms variable include terms that can not have nested terms.
@@ -27039,10 +27042,11 @@ When they appear, stop recursing and return the name inside directly
**Kind**: inner method of [Loader API: Loader APIs
](#module_Loader API_ Loader APIs)
**Returns**: The conformance string.
-| Param | Type |
-| --- | --- |
-| operand | \*
|
-| parentJoinChar | \*
|
+| Param | Type | Default |
+| --- | --- | --- |
+| operand | \*
| |
+| depth | \*
| 0
|
+| parentJoinChar | \*
| |
diff --git a/src-electron/zcl/zcl-loader-silabs.js b/src-electron/zcl/zcl-loader-silabs.js
index 4921730333..3e001867eb 100644
--- a/src-electron/zcl/zcl-loader-silabs.js
+++ b/src-electron/zcl/zcl-loader-silabs.js
@@ -2309,16 +2309,21 @@ function parseConformanceFromXML(operand) {
* When they appear, stop recursing and return the name inside directly
*
* @param {*} operand
+ * @param {*} depth
* @param {*} parentJoinChar
* @returns The conformance string.
*/
-function parseConformanceRecursively(operand, parentJoinChar = '') {
+function parseConformanceRecursively(operand, depth = 0, parentJoinChar = '') {
+ if (depth > 200) {
+ throw new Error(`Maximum recursion depth exceeded
+ when parsing conformance: ${JSON.stringify(operand)}`)
+ }
const baseLevelTerms = ['feature', 'condition', 'attribute', 'command']
if (operand.mandatoryConform) {
let insideTerm = operand.mandatoryConform[0]
// Recurse further if insideTerm is not empty
if (insideTerm && Object.keys(insideTerm).toString() != '$') {
- return parseConformanceRecursively(operand.mandatoryConform[0])
+ return parseConformanceRecursively(operand.mandatoryConform[0], depth + 1)
} else {
return 'M'
}
@@ -2327,13 +2332,15 @@ function parseConformanceRecursively(operand, parentJoinChar = '') {
// check '$' key is not the only key in the object to handle special cases
// e.g. ''
if (insideTerm && Object.keys(insideTerm).toString() != '$') {
- return `[${parseConformanceRecursively(operand.optionalConform[0])}]`
+ return `[${parseConformanceRecursively(operand.optionalConform[0], depth + 1)}]`
} else {
return 'O'
}
} else if (operand.otherwiseConform) {
return Object.entries(operand.otherwiseConform[0])
- .map(([key, value]) => parseConformanceRecursively({ [key]: value }))
+ .map(([key, value]) =>
+ parseConformanceRecursively({ [key]: value }, depth + 1)
+ )
.join(', ')
} else if (operand.notTerm) {
// need to surround terms inside a notTerm with '()' if it contains multiple terms
@@ -2341,7 +2348,7 @@ function parseConformanceRecursively(operand, parentJoinChar = '') {
// able to process multiple parallel notTerms, e.g. !A & !B
return operand.notTerm
.map((term) => {
- let nt = parseConformanceRecursively(term)
+ let nt = parseConformanceRecursively(term, depth + 1)
return nt.includes('&') || nt.includes('|') ? `!(${nt})` : `!${nt}`
})
.join(` ${parentJoinChar} `)
@@ -2358,7 +2365,11 @@ function parseConformanceRecursively(operand, parentJoinChar = '') {
if (baseLevelTerms.includes(key)) {
return value.map((operand) => operand.$.name).join(` ${joinChar} `)
} else {
- let terms = parseConformanceRecursively({ [key]: value }, joinChar)
+ let terms = parseConformanceRecursively(
+ { [key]: value },
+ depth + 1,
+ joinChar
+ )
return terms.includes(oppositeChar) ? `(${terms})` : terms
}
})