@ndn/tlv
Version:
NDNts: TLV
106 lines (105 loc) • 4.76 kB
TypeScript
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 {};