/** * @license * Copyright 2022-2026 Matter.js Authors * SPDX-License-Identifier: Apache-2.0 */ import { camelize, FLOAT32_MAX, FLOAT32_MIN, INT16_MAX, INT16_MIN, INT32_MAX, INT32_MIN, INT64_MAX, INT64_MIN, INT8_MAX, INT8_MIN, UINT16_MAX, UINT24_MAX, UINT32_MAX, UINT64_MAX, UINT8_MAX, } from "@matter/general"; import { Constraint, FieldValue, ValueModel } from "@matter/model"; /** * Helpers for generation of TLV schema from models. * * We must export these so long as we codegen TLV directly in TlvGenerator.ts. */ export namespace ModelBounds { export function createLengthBounds(model: ValueModel) { const constraint = extractApplicableConstraint(model); const value = FieldValue.numericValue(constraint.value, model.type); if (value !== undefined) { return { length: value }; } return createRangeBounds(constraint, "minLength", "maxLength"); } export function createNumberBounds(model: ValueModel) { const constraint = model.effectiveConstraint; const value = FieldValue.numericValue(constraint.value, model.type); if (value !== undefined) { return { min: value, max: value }; } return createRangeBounds(constraint, "min", "max", model.type); } /** * Bounds for numeric types. */ export const NumericRanges = { uint8: { min: 0, max: UINT8_MAX }, uint16: { min: 0, max: UINT16_MAX }, uint24: { min: 0, max: UINT24_MAX }, uint32: { min: 0, max: UINT32_MAX }, uint64: { min: 0, max: UINT64_MAX }, int8: { min: INT8_MIN, max: INT8_MAX }, int16: { min: INT16_MIN, max: INT16_MAX }, int32: { min: INT32_MIN, max: INT32_MAX }, int64: { min: INT64_MIN, max: INT64_MAX }, float32: { min: FLOAT32_MIN, max: FLOAT32_MAX }, percent: { min: 0, max: 100 }, percent100ths: { min: 0, max: 10000 }, }; } function createRangeBounds(constraint: Constraint, minKey: string, maxKey: string, type?: string) { let min = FieldValue.numericValue(constraint.min, type); let max = FieldValue.numericValue(constraint.max, type); if (min === (ModelBounds.NumericRanges as any)[type as any]?.min) { min = undefined; } if (max === (ModelBounds.NumericRanges as any)[type as any]?.max) { max = undefined; } if (min === undefined && max === undefined) { return; } const bounds = {} as { [key: string]: number }; if (min !== undefined) { bounds[minKey] = min; } if (max !== undefined) { bounds[maxKey] = max; } return bounds; } export function extractApplicableConstraint(model: ValueModel) { let constraint = model.effectiveConstraint; // Our TLV parser has no way of representing "in" constraints. But if the referenced array has a member // constraint then we can at least enforce to that level with the TLV parser if (constraint.in) { const siblingName = FieldValue.referenced(constraint.in); if (siblingName) { const sibling = model.parent?.member(camelize(siblingName, true)) as ValueModel; const siblingConstraint = sibling.effectiveConstraint; if (siblingConstraint.entry) { constraint = siblingConstraint.entry; } } } return constraint; }