molstar
Version:
A comprehensive macromolecular library.
101 lines (100 loc) • 6.09 kB
TypeScript
/**
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
import { AllRequired, ParamsSchema, ValuesFor } from './params-schema';
/** Type of "custom" of a tree node (key-value storage with arbitrary JSONable values) */
export type CustomProps = Partial<Record<string, any>>;
/** Tree node without children */
export type Node<TKind extends string = string, TParams extends {} = {}> = {} extends TParams ? {
kind: TKind;
params?: TParams;
custom?: CustomProps;
ref?: string;
} : {
kind: TKind;
params: TParams;
custom?: CustomProps;
ref?: string;
};
/** Kind type for a tree node */
export type Kind<TNode extends Node> = TNode['kind'];
/** Params type for a tree node */
export type Params<TNode extends Node> = NonNullable<TNode['params']>;
/** Tree (i.e. a node with optional children) where the root node is of type `TRoot` and other nodes are of type `TNode` */
export type Tree<TNode extends Node<string, {}> = Node<string, {}>, TRoot extends TNode = TNode> = TRoot & {
children?: Tree<TNode, TNode>[];
};
/** Type of any subtree that can occur within given `TTree` tree type */
export type Subtree<TTree extends Tree> = NonNullable<TTree['children']>[number];
/** Type of any subtree that can occur within given `TTree` tree type and has kind type `TKind` */
export type SubtreeOfKind<TTree extends Tree, TKind extends Kind<Subtree<TTree>> = Kind<Subtree<TTree>>> = RootOfKind<Subtree<TTree>, TKind>;
type RootOfKind<TTree extends Tree, TKind extends Kind<TTree>> = Extract<TTree, Tree<any, Node<TKind>>>;
/** Params type for a given kind type within a tree */
export type ParamsOfKind<TTree extends Tree, TKind extends Kind<Subtree<TTree>> = Kind<Subtree<TTree>>> = NonNullable<SubtreeOfKind<TTree, TKind>['params']>;
/** Get params from a tree node */
export declare function getParams<TNode extends Node>(node: TNode): Params<TNode>;
/** Get custom properties from a tree node */
export declare function getCustomProps<TCustomProps extends CustomProps = CustomProps>(node: Node): TCustomProps;
/** Get children from a tree node */
export declare function getChildren<TTree extends Tree>(tree: TTree): Subtree<TTree>[];
type ParamsSchemas = {
[kind: string]: ParamsSchema;
};
/** Definition of tree type, specifying allowed node kinds, types of their params, required kind for the root, and allowed parent-child kind combinations */
export interface TreeSchema<TParamsSchemas extends ParamsSchemas = ParamsSchemas, TRootKind extends keyof TParamsSchemas = string> {
/** Required kind of the root node */
rootKind: TRootKind;
/** Definition of allowed node kinds */
nodes: {
[kind in keyof TParamsSchemas]: {
/** Params schema for this node kind */
params: TParamsSchemas[kind];
/** Documentation for this node kind */
description?: string;
/** Node kinds that can serve as parent for this node kind (`undefined` means the parent can be of any kind) */
parent?: (string & keyof TParamsSchemas)[];
};
};
}
export declare function TreeSchema<P extends ParamsSchemas = ParamsSchemas, R extends keyof P = string>(schema: TreeSchema<P, R>): TreeSchema<P, R>;
/** ParamsSchemas per node kind */
type ParamsSchemasOf<TTreeSchema extends TreeSchema> = TTreeSchema extends TreeSchema<infer TParamsSchema, any> ? TParamsSchema : never;
/** Variation of params schemas where all param fields are required */
type ParamsSchemasWithAllRequired<TParamsSchemas extends ParamsSchemas> = {
[kind in keyof TParamsSchemas]: AllRequired<TParamsSchemas[kind]>;
};
/** Variation of a tree schema where all param fields are required */
export type TreeSchemaWithAllRequired<TTreeSchema extends TreeSchema> = TreeSchema<ParamsSchemasWithAllRequired<ParamsSchemasOf<TTreeSchema>>, TTreeSchema['rootKind']>;
export declare function TreeSchemaWithAllRequired<TTreeSchema extends TreeSchema>(schema: TTreeSchema): TreeSchemaWithAllRequired<TTreeSchema>;
/** Type of tree node which can occur as the root of a tree conforming to tree schema `TTreeSchema` */
export type RootFor<TTreeSchema extends TreeSchema> = NodeFor<TTreeSchema, TTreeSchema['rootKind']>;
/** Type of tree node which can occur anywhere in a tree conforming to tree schema `TTreeSchema`,
* optionally narrowing down to a given node kind */
export type NodeFor<TTreeSchema extends TreeSchema, TKind extends keyof ParamsSchemasOf<TTreeSchema> = keyof ParamsSchemasOf<TTreeSchema>> = {
[key in keyof ParamsSchemasOf<TTreeSchema>]: Node<key & string, ValuesFor<ParamsSchemasOf<TTreeSchema>[key]>>;
}[TKind];
/** Type of tree which conforms to tree schema `TTreeSchema` */
export type TreeFor<TTreeSchema extends TreeSchema> = Tree<NodeFor<TTreeSchema>, RootFor<TTreeSchema> & NodeFor<TTreeSchema>>;
/** Return `undefined` if a tree conforms to the given schema,
* return validation issues (as a list of lines) if it does not conform.
* If `options.requireAll`, all parameters (including optional) must have a value provided.
* If `options.noExtra` is true, presence of any extra parameters is treated as an issue.
* If `options.anyRoot` is true, the kind of the root node is not enforced.
*/
export declare function treeValidationIssues(schema: TreeSchema, tree: Tree, options?: {
requireAll?: boolean;
noExtra?: boolean;
anyRoot?: boolean;
parent?: string;
}): string[] | undefined;
/** Validate a tree against the given schema.
* Do nothing if OK; print validation issues on console and throw an error is the tree does not conform.
* Include `label` in the printed output. */
export declare function validateTree(schema: TreeSchema, tree: Tree, label: string): void;
/** Return documentation for a tree schema as plain text */
export declare function treeSchemaToString<S extends TreeSchema>(schema: S): string;
/** Return documentation for a tree schema as markdown text */
export declare function treeSchemaToMarkdown<S extends TreeSchema>(schema: S): string;
export {};