@ibyar/expressions
Version:
Aurora expression, an template expression and evaluation, An 100% spec compliant ES2022 JavaScript toolchain,
213 lines • 7.44 kB
TypeScript
import type { Scope, Context } from '../scope/scope.js';
import type { Stack } from '../scope/stack.js';
import { TypeOf } from './utils.js';
/**
* Each Position object consists of
* a line number (1-indexed)
* and a column number (0-indexed)
*/
export interface Position {
line: number;
column: number;
}
export interface SourceLocation {
source?: string | null;
start: Position;
end: Position;
}
export type NodeType = {
type: string;
};
export type NodeJsonType = {
[key: string]: any;
} & NodeType;
export type ExpressionEventPathDotNotation = {
computed: false;
path: string;
};
export type ExpressionEventPathBracketNotation = {
computed: true;
path: string;
computedPath: ExpressionEventPath[][];
};
export type ExpressionEventPath = ExpressionEventPathDotNotation | ExpressionEventPathBracketNotation;
export type ExpressionEventMap = {
[key: string]: ExpressionEventMap;
};
export type DeclarationType = 'HoistableDeclaration' | 'ClassDeclaration' | 'LexicalDeclaration';
export type HoistableDeclaration = 'FunctionDeclaration' | 'GeneratorDeclaration' | 'AsyncFunctionDeclaration' | 'AsyncGeneratorDeclaration';
export type LexicalDeclaration = 'Let' | 'Const';
export interface ExpressionNode {
/**
* The `type` field is a string representing the AST variant type.
* Each subtype of `Node` is documented below with the specific string of its type field.
* You can use this field to determine which interface a node implements.
*/
type: string;
/**
* The `loc` field represents the source location information of the node.
* If the node contains no information about the source location,
* the field is `null` or `undefined`;
* otherwise it is an object consisting of
* a start position (the position of the first character of the parsed source region)
* and an end position (the position of the first character after the parsed source region):
* and offset index (the position of the first character)
*/
loc?: SourceLocation;
/**
* start and end position offset
*/
range?: [number, number];
/**
* assign the value to this expression in stack.
*
* most ExpressionNode will not implement this method, and will throw an exception.
* @param stack
* @param value
*/
set(stack: Stack, value: any): any;
/**
* execute/get the code for this expression and return the result value.
* @param stack
* @param thisContext
*/
get(stack: Stack, thisContext?: any): any;
/**
* get all dependencies form an expression node
*
* the return from this method, is represent an answer for what identifiers this expression depends-on.
*
*
* ex:
* ```js
* x + y;
* ```
*
* - for `+` operator : the answer should be `lhs` and `rhs`,
* - for `x` identifier: the answer should be node `x`,
* - for `y` identifier: the answer should be node `y`.
*
* so, the return from `+` will be `[ node 'x', node 'y']`
*
* and:
* - `x.y.z * a` ==> `[ member node `x.y.z`, identifier 'a']`
* @param computed
*/
dependency(computed?: true): ExpressionNode[];
/**
* ex:
* ```js
* x + y;
* ```
*
* - for `+` operator : the answer should be `lhs` and `rhs`,
* - for `x` identifier: the answer should be node `x`,
* - for `y` identifier: the answer should be node `y`.
*
* so, the return from `+` will be `['x', 'y']`
*
* and:
* - `x.y.z` ==> `['x', 'y', 'z']`
* - `x[y].z` ==> ['x', ]
* @param computed required for member and chaining operators
*/
dependencyPath(computed?: true): ExpressionEventPath[];
/**
* get all the events form this expression
*
* the return from this method, is represent an answer for what is this expression depends-on as identifier name
*
* ex:
* ```js
* x + y;
* ```
*
* - for `+` operator : the answer should be `lhs` and `rhs`,
* - for `x` identifier: the answer should be `x`
* - for `y` identifier: the answer should be `y`
* the final output will be
*
* so, the return from `+` will be `{ x: undefined, y: undefined }`
*
* and:
* - `x.y.z * a` ==> `{ x: { y: { z: undefined }, a: undefined } }`
* - `x.y.z > x.y.h.g` ==> `{ x: { y: { z: undefined, h: { g: undefined} } } }`
* - `x[Symbol.toStringTag] + 'Class' + classType + array[3]` ==> `{ x: { 'Symbol.toStringTag': undefined }, classType: undefined, array: { 3: undefined } }`
* - `'name'` ==> {}
* - ```js
* user[firstName + `son of ${fatherName}`]
* ``` ==> `{ user: { 'firstName:fatherName': undefined }, firstName: undefined, fatherName: undefined }`
* @param parent
*/
events(): ExpressionEventMap;
/**
* re-write this expression as a javascript source
*/
toString(): string;
/**
* used to map this object to represent an [ESTree](https://github.com/estree/estree) json object
* @param key
*/
toJSON(): NodeJsonType;
/**
* just a helper method to force class that implement this interface to
* have a static method `fromJSON` to help reconstruct this ExpressionNode
* from an [ESTree](https://github.com/estree/estree) json object,
* with all necessary implementation to execute the code
*/
getClass(): ExpressionNodConstructor<ExpressionNode>;
}
export type NodeDeserializer<N = ExpressionNode> = (node: N) => N;
export type VisitNodeType = (expression: ExpressionNode) => void;
/**
* this is how to:
* describe a class with it's static functions and properties
* in the interface add getClass method
*/
export interface ExpressionNodConstructor<N extends ExpressionNode> extends TypeOf<N> {
/**
* the type of an expression
*/
type: string;
/**
* build expression node from [ESTree](https://github.com/estree/estree) json object
* @param node
* @param deserializer
*/
fromJSON(node: N, deserializer: NodeDeserializer): N;
/**
* visit nodes inside expression
* @param expression
* @param callback
*/
visit?(node: N, visitNode: Object): void;
}
export interface DeclarationExpression extends ExpressionNode {
/**
* declare variable in the current local scope (block),
* or closest function scope (global) scop,
* the propertyName will be calculated at runtime
* @param stack the stack which an identifier will be declared
* @param propertyValue the initial value of identifier
* @param scope which scop to declare this identifier
*/
declareVariable(stack: Stack, propertyValue?: any): any;
/**
* get the variable declaration name
*/
getDeclarationName?(): string;
}
/**
* An interface meant to be implemented by MemberExpression,
* Identifier and ChainExpression and all Literal expressions
*/
export interface CanFindScope {
/**
* try to search for scope of this expression
* @param stack
*/
findScope<V extends Context>(stack: Stack): Scope<V>;
findScope<V extends Context>(stack: Stack, scope: Scope<Record<PropertyKey, V>>): Scope<V>;
findScope<V extends Context>(stack: Stack, scope?: Scope<Record<PropertyKey, V>>): Scope<V> | undefined;
}
//# sourceMappingURL=expression.d.ts.map