From c92cdc6e587a22654afac30bcd3351352b1c13fd Mon Sep 17 00:00:00 2001 From: "Ethan.Z" Date: Thu, 21 Nov 2024 19:56:23 -0500 Subject: [PATCH] add max depth to recursion --- docs/api.md | 52 ++++++++++++++------------- src-electron/zcl/zcl-loader-silabs.js | 23 ++++++++---- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/docs/api.md b/docs/api.md index f05af0b7cf..ce7e140ee0 100644 --- a/docs/api.md +++ b/docs/api.md @@ -20136,7 +20136,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) ⇒ @@ -21532,7 +21532,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. @@ -21541,10 +21541,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 | \* | | @@ -21969,7 +21970,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) ⇒ @@ -23365,7 +23366,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. @@ -23374,10 +23375,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 | \* | | @@ -23802,7 +23804,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) ⇒ @@ -25198,7 +25200,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. @@ -25207,10 +25209,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 | \* | | @@ -25635,7 +25638,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) ⇒ @@ -27031,7 +27034,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. @@ -27040,10 +27043,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 27a7d0ad70..518ab91c68 100644 --- a/src-electron/zcl/zcl-loader-silabs.js +++ b/src-electron/zcl/zcl-loader-silabs.js @@ -2304,16 +2304,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' } @@ -2322,13 +2327,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 @@ -2336,7 +2343,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} `) @@ -2353,7 +2360,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 } })