UNPKG

@ndn/tlv

Version:
106 lines (105 loc) 4.76 kB
import type { Constructor, Except, IfNever, Simplify } from "type-fest"; import { type Decodable } from "./decoder.js"; import { type EncodableObj } from "./encoder.js"; import { EvDecoder } from "./ev-decoder.js"; import type { StructFieldType } from "./struct-field.js"; /** StructBuilder field options. */ interface Options<Required extends boolean, Repeat extends boolean, FlagPrefix extends string, FlagBit extends string> extends EvDecoder.RuleOptions { /** * Whether the field is required. * If both `.required` and `.repeat` are false, the field may be set to undefined and is initialized as undefined. * @defaultValue `false` */ required?: Required; /** * Whether the field is repeated. * If `.repeat` is true, the field is defined as an array and is initialized as an empty array. * @defaultValue `false` */ repeat?: Repeat; /** * Prefix of bit property names. * Ignored if `.flagBits` is unspecified. * * @defaultValue * Same as primary field name. */ flagPrefix?: FlagPrefix; /** * Mapping from bit name to bit value. * If specified, the field is treated as bit flags. */ flagBits?: Record<FlagBit, number>; } type ErrFlags = "ERROR: can only define flags on a non-repeatable number field"; type ValidateOptions<T, Repeat extends boolean, FlagBit extends string, R> = IfNever<FlagBit, R, Repeat extends true ? ErrFlags : T extends number ? R : ErrFlags>; type AddField<K extends string, T, Required extends boolean, Repeat extends boolean> = Repeat extends true ? { [key in K]: T[]; } : Required extends true ? { [key in K]: T; } : { [key in K]?: T; }; type AddFlags<FlagPrefix extends string, FlagBit extends string> = { [key in `${FlagPrefix}${Capitalize<FlagBit>}`]: boolean; }; /** * Helper to build a base class that represents a TLV structure. * * @remarks * StructBuilder allows you to define the typing, constructor, encoder, and decoder, while writing * each field only once. To be compatible with StructBuilder, the TLV structure being described * shall contain a sequence of sub-TLV elements with distinct TLV-TYPE numbers, where each * sub-TLV-TYPE appears zero, one, or multiple times. * * To use StructBuilder, calling code should follow these steps: * 1. Invoke `.add()` method successively to define sub-TLV elements. * 2. Obtain a base class via `.baseClass()` method, which contains one field for each sub-TLV-TYPE * as defined, along with constructor, encoding, and decoding functions. * 3. Declare a subclass deriving from this base class, to add more functionality. * 4. Assign the subclass constructor to `.subclass` property of the builder. */ export declare class StructBuilder<U extends {}> { readonly typeName: string; readonly topTT?: number | undefined; /** * Constructor. * @param typeName - Type name, used in error messages. * @param topTT - If specified, encode as complete TLV; otherwise, encode as TLV-VALUE only. */ constructor(typeName: string, topTT?: number | undefined); /** * Subclass constructor. * This must be assigned, otherwise decoding function will not work. */ subclass?: Constructor<U, []> & Decodable<U>; private readonly fields; private readonly flagBits; private readonly EVD; /** Access EvDecoder for certain customizations. */ static evdOf<U extends {}>(sb: StructBuilder<U>): Except<EvDecoder<U>, "add">; /** Retrieve field names. */ static keysOf<U extends {}>(sb: StructBuilder<U>): Array<keyof U>; /** * Add a field. * @param tt - TLV-TYPE number. * @param key - Field name on the base class. * @param type - Field type. * @param opts - Field options. * @returns StructBuilder annotated with field typing. */ add<T, K extends string, Required extends boolean = false, Repeat extends boolean = false, FlagPrefix extends string = K, FlagBit extends string = never>(tt: number, key: ValidateOptions<T, Repeat, FlagBit, K>, type: StructFieldType<T>, opts?: Options<Required, Repeat, FlagPrefix, FlagBit>): StructBuilder<Simplify<U & AddField<K, T, Required, Repeat> & AddFlags<FlagPrefix, FlagBit>>>; /** Change IsCritical on the EvDecoder. */ setIsCritical(cb: EvDecoder.IsCritical): this; /** * Obtain a base class for the TLV structure class. * @typeParam S - Subclass type. */ baseClass<S>(): (new () => Simplify<U> & EncodableObj) & Decodable<S>; } /** * Infer fields of a class built by StructBuilder. * @typeParam B - StructBuilder annotated with field typing. */ export type StructFields<B extends StructBuilder<{}>> = B extends StructBuilder<infer U> ? U : never; export {};