UNPKG

@player-ui/player

Version:

252 lines (199 loc) 6.37 kB
import type { DataModelWithParser } from "../data"; import type { Logger } from "../logger"; export type ExpressionObjectType = { /** The expression to eval */ value: BasicExpressionTypes; }; export type ExpressionLiteralType = | string | number | boolean | undefined | null; export type BasicExpressionTypes = | ExpressionLiteralType | ExpressionObjectType | Array<ExpressionLiteralType | ExpressionObjectType>; export type ExpressionType = BasicExpressionTypes | ExpressionNode; export interface OperatorProcessingOptions { /** * When set to a falsy value, the arguments passed to the handler will be raw AST Nodes * This enables lazy evaluation of arguments */ resolveParams: boolean; /** * Whether the expression should be allowed to be evaluated asynchronously */ async?: boolean; } export type BinaryOperatorBasic = ( left: any, right: any, async: boolean, ) => unknown; export type BinaryOperatorAdvanced = OperatorProcessingOptions & ((ctx: ExpressionContext, left: any, right: any, async: boolean) => unknown); export type BinaryOperator = BinaryOperatorAdvanced | BinaryOperatorBasic; export type UnaryOperator = | ((arg: any, async: boolean) => unknown) | (((ctx: ExpressionContext, arg: any, async: boolean) => unknown) & OperatorProcessingOptions); export interface ExpressionContext { /** A means of executing an expression */ evaluate: (expr: ExpressionType) => unknown; /** The data model that expression handlers can use when fetching data */ model: DataModelWithParser; /** A logger to use */ logger?: Logger; } export type ExpressionHandler< T extends readonly unknown[] = unknown[], R = void, > = ((context: ExpressionContext, ...args: T) => R) & Partial<OperatorProcessingOptions>; export const ExpNodeOpaqueIdentifier: unique symbol = Symbol("Expression Node ID"); /** Checks if the input is an already processed Expression node */ export function isExpressionNode(x: any): x is ExpressionNode { return ( typeof x === "object" && x !== null && !Array.isArray(x) && x.__id === ExpNodeOpaqueIdentifier ); } export interface NodePosition { /** The character location */ character: number; } export interface NodeLocation { // We only care about the character offset, not the line/column for now // But making these objects allows us to add more (like line number) later /** The start of the node */ start: NodePosition; /** The end of the node */ end: NodePosition; } export interface BaseNode<T> { /** The thing to discriminate the AST type on */ type: T; /** How to tell this apart from other objects */ __id: typeof ExpNodeOpaqueIdentifier; /** The location of the node in the source expression string */ location?: NodeLocation; /** * The error that occurred while parsing this node * This is only set if the parsing mode is set to non-strict */ error?: Error; } /** A helper interface for nodes that container left and right children */ export interface DirectionalNode { /** The left node. Often for the left hand side of an expression */ left: ExpressionNode; /** The right child. Often for the right hand side of an expression */ right: ExpressionNode; } export interface LiteralNode extends BaseNode<"Literal"> { /** A node that holds a literal value */ value: string | number; /** The unprocessed value */ raw?: any; } export interface BinaryNode extends BaseNode<"BinaryExpression">, DirectionalNode { /** The operation to perform on the nodes */ operator: string; } export interface LogicalNode extends BaseNode<"LogicalExpression">, DirectionalNode { /** The logical operation to perform on the nodes */ operator: string; } export interface UnaryNode extends BaseNode<"UnaryExpression"> { /** The operation to perform on the node */ operator: string; /** The single argument that the operation should be performed on */ argument: ExpressionNode; } export type ThisNode = BaseNode<"ThisExpression">; export interface ModelRefNode extends BaseNode<"ModelRef"> { /** The binding that the model reference points to */ ref: string; } export interface ObjectNode extends BaseNode<"Object"> { /** */ attributes: Array<{ /** The property name of the object */ key: ExpressionNode; /** the associated value */ value: ExpressionNode; }>; } export interface MemberExpressionNode extends BaseNode<"MemberExpression"> { /** The object to be introspected */ object: ExpressionNode; /** If the property uses . or open-bracket */ computed: boolean; /** The property to access on the object */ property: ExpressionNode; } export interface ConditionalExpressionNode extends BaseNode<"ConditionalExpression"> { /** The test for the ternary */ test: ExpressionNode; /** The truthy case for the ternary */ consequent: ExpressionNode; /** The falsy case for the ternary */ alternate: ExpressionNode; } export interface CompoundNode extends BaseNode<"Compound"> { /** The contents of the compound expression */ body: ExpressionNode[]; } export interface CallExpressionNode extends BaseNode<"CallExpression"> { /** The arguments to the function */ args: ExpressionNode[]; /** The function name */ callTarget: IdentifierNode; } export interface ArrayExpressionNode extends BaseNode<"ArrayExpression"> { /** The items in an array */ elements: ExpressionNode[]; } export interface IdentifierNode extends BaseNode<"Identifier"> { /** The variable name */ name: string; } export type AssignmentNode = BaseNode<"Assignment"> & DirectionalNode; export interface ModificationNode extends BaseNode<"Modification">, DirectionalNode { /** The operator for the modification */ operator: string; } export type ExpressionNode = | LiteralNode | BinaryNode | LogicalNode | UnaryNode | ThisNode | ModelRefNode | MemberExpressionNode | ConditionalExpressionNode | CompoundNode | CallExpressionNode | ArrayExpressionNode | IdentifierNode | AssignmentNode | ModificationNode | ObjectNode; export type ExpressionNodeType = ExpressionNode["type"]; export interface ErrorWithLocation extends Error { /** The place in the string where the error occurs */ index: number; /** a helpful description */ description: string; }