/** * @license * Copyright 2022-2026 Matter.js Authors * SPDX-License-Identifier: Apache-2.0 */ import { Behavior } from "#behavior/Behavior.js"; import { camelize, ImplementationError } from "@matter/general"; import { DescriptorBehavior } from "../../behaviors/descriptor/DescriptorBehavior.js"; /** * A set of behaviors an endpoint supports. */ export type SupportedBehaviors = Record; /** * Create SupportedBehaviors from a list of behavior types. */ export function SupportedBehaviors(...types: T) { const result = {} as SupportedBehaviors; addBehaviors(result, types); return result as SupportedBehaviors.MapOf; } /** * Utility functions and definitions for modifying lists of clusters. */ export namespace SupportedBehaviors { export type List = readonly Behavior.Type[]; /** * Create a new list with additional behaviors, replacing any previous * behavior for the same cluster. Replacement updates the set of supported * cluster features. * * Note: Functional equivalent of With<> but you can't have a method named * "with" in a namespace. */ export function extend( currentTypes: BehaviorsT, newTypes: NewBehaviorsT, ) { const result = { ...currentTypes } as SupportedBehaviors; addBehaviors(result, newTypes); return result as unknown as With; } /** * Add or replace behaviors. */ export type With = Omit & MapOf; /** * Convert a List to BehaviorTypes. */ export type MapOf = T extends readonly [infer F extends Behavior.Type] ? { readonly [K in F["id"]]: F } : T extends readonly [infer F extends Behavior.Type, ...infer R extends List] ? { readonly [K in F["id"]]: F } & MapOf : {}; /** * Properties of an endpoint contributed by listed behaviors. */ export type EndpointProperties = { readonly [K in keyof SB]: InstanceType; }; /** * Compound state for all behaviors. */ export type StateOf = { [K in keyof SB]: Behavior.StateOf; } & { descriptor: Behavior.StateOf; }; /** * Compound events for all behaviors. */ export type EventsOf = { [K in keyof SB]: Behavior.EventsOf; }; /** * Input version of {@link StateOf}. */ export type InputStateOf = { [K in keyof SB]?: Behavior.InputStateOf; } & { descriptor?: Behavior.InputStateOf; }; /** * Patch input version of {@link StateOf}. */ export type StatePatchOf = { readonly [K in keyof SB]?: Behavior.PatchStateOf; } & { descriptor?: Behavior.PatchStateOf; }; } function addBehaviors(target: SupportedBehaviors, types: SupportedBehaviors.List) { for (const type of types) { if (typeof type.id !== "string") { throw new ImplementationError("Behavior type has no ID"); } if (!/^[a-z]/.test(type.id)) { throw new ImplementationError( `Behavior ID "${type.id}" must start with a lowercase letter (for example "${camelize(type.id)}")`, ); } target[type.id] = type; } }