@typescript-guy/fn-monitor 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/ACKNOWLEDGEMENTS.md +10 -0
  2. package/LICENSE.md +10 -0
  3. package/README.md +201 -0
  4. package/dist/custom-types.d.ts +239 -0
  5. package/dist/custom-types.js +341 -0
  6. package/dist/evaluate/declaration.d.ts +27 -0
  7. package/dist/evaluate/declaration.js +289 -0
  8. package/dist/evaluate/expression.d.ts +40 -0
  9. package/dist/evaluate/expression.js +604 -0
  10. package/dist/evaluate/helper.d.ts +18 -0
  11. package/dist/evaluate/helper.js +270 -0
  12. package/dist/evaluate/identifier.d.ts +7 -0
  13. package/dist/evaluate/identifier.js +27 -0
  14. package/dist/evaluate/index.d.ts +3 -0
  15. package/dist/evaluate/index.js +112 -0
  16. package/dist/evaluate/literal.d.ts +3 -0
  17. package/dist/evaluate/literal.js +8 -0
  18. package/dist/evaluate/pattern.d.ts +13 -0
  19. package/dist/evaluate/pattern.js +118 -0
  20. package/dist/evaluate/program.d.ts +3 -0
  21. package/dist/evaluate/program.js +20 -0
  22. package/dist/evaluate/statement.d.ts +35 -0
  23. package/dist/evaluate/statement.js +323 -0
  24. package/dist/evaluate_n/declaration.d.ts +27 -0
  25. package/dist/evaluate_n/declaration.js +289 -0
  26. package/dist/evaluate_n/expression.d.ts +38 -0
  27. package/dist/evaluate_n/expression.js +596 -0
  28. package/dist/evaluate_n/helper.d.ts +18 -0
  29. package/dist/evaluate_n/helper.js +238 -0
  30. package/dist/evaluate_n/identifier.d.ts +7 -0
  31. package/dist/evaluate_n/identifier.js +27 -0
  32. package/dist/evaluate_n/index.d.ts +3 -0
  33. package/dist/evaluate_n/index.js +76 -0
  34. package/dist/evaluate_n/literal.d.ts +3 -0
  35. package/dist/evaluate_n/literal.js +8 -0
  36. package/dist/evaluate_n/pattern.d.ts +13 -0
  37. package/dist/evaluate_n/pattern.js +118 -0
  38. package/dist/evaluate_n/program.d.ts +3 -0
  39. package/dist/evaluate_n/program.js +20 -0
  40. package/dist/evaluate_n/statement.d.ts +35 -0
  41. package/dist/evaluate_n/statement.js +301 -0
  42. package/dist/examples/example-2.d.ts +1 -0
  43. package/dist/examples/example.d.ts +1 -0
  44. package/dist/helper-functions.d.ts +15 -0
  45. package/dist/helper-functions.js +104 -0
  46. package/dist/index.d.ts +55 -0
  47. package/dist/index.js +312 -0
  48. package/dist/q-list.d.ts +39 -0
  49. package/dist/q-list.js +146 -0
  50. package/dist/scope/index.d.ts +81 -0
  51. package/dist/scope/index.js +168 -0
  52. package/dist/scope/variable.d.ts +20 -0
  53. package/dist/scope/variable.js +38 -0
  54. package/dist/share/async.d.ts +7 -0
  55. package/dist/share/async.js +43 -0
  56. package/dist/share/const.d.ts +25 -0
  57. package/dist/share/const.js +21 -0
  58. package/dist/share/util.d.ts +33 -0
  59. package/dist/share/util.js +379 -0
  60. package/dist/sval.d.ts +15 -0
  61. package/dist/sval.js +104 -0
  62. package/package.json +54 -0
@@ -0,0 +1,10 @@
1
+ ## Acknowledgements
2
+
3
+ The core execution engine of this project is a modified and extended version of `sval`, a JavaScript interpreter written in JavaScript.
4
+
5
+ Original repository: https://github.com/Siubaak/sval
6
+
7
+ `sval` is licensed under the MIT License. The full text of the MIT License governing this original code can be found at:
8
+ https://github.com/Siubaak/sval/blob/master/LICENSE
9
+
10
+ *Please note: This project is an independent extension and is not affiliated with, endorsed by, or sponsored by the original `sval` project or its authors.*
package/LICENSE.md ADDED
@@ -0,0 +1,10 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Siubaak
4
+ Copyright (c) 2026 typescript-guy
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
+
8
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
+
10
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,201 @@
1
+ # @typescript-guy/fn-monitor
2
+
3
+ ![npm](https://img.shields.io/npm/v/@typescript-guy/fn-monitor)
4
+
5
+ An augmentation of the [`sval`](https://github.com/Siubaak/sval) JS-in-JS interpreter designed to monitor functions as they execute.
6
+
7
+ This package allows developers to inspect, debug, or sandbox JavaScript functions at runtime by injecting hooks at any part of a function's lifecycle. It treats your hooks as first-class citizens within the interpreter, effectively turning your functions into white-boxes.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @typescript-guy/fn-monitor
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ The core of the package is the `monitor` function. It accepts a configuration object and returns a new function that behaves exactly like the original, but is executed by the custom interpreter.
18
+
19
+ ```typescript
20
+ import { monitor } from '@typescript-guy/fn-monitor';
21
+
22
+ function add(a: number, b: number) {
23
+ return a + b;
24
+ }
25
+
26
+ // Create a monitored version of the function
27
+ const monitoredAdd = monitor({
28
+ main: { ref: add },
29
+ beforeEachCall: (a, b) => console.log(`Adding ${a} and ${b}`),
30
+ afterEachCall: (result) => console.log(`Result: ${result}`),
31
+ });
32
+
33
+ monitoredAdd(2, 3);
34
+ // Logs: Adding 2 and 3
35
+ // Logs: Result: 5
36
+ ```
37
+
38
+ ### Capturing External Variables
39
+ Because monitored functions run in an isolated interpreter context, external variables must be explicitly captured:
40
+
41
+ ```typescript
42
+ const multiplier = 10;
43
+
44
+ const multiply = (x: number) => x * multiplier;
45
+
46
+ const monitoredMultiply = monitor({
47
+ main: {
48
+ ref: multiply,
49
+ captures: { multiplier } // Map the variable name to its value
50
+ }
51
+ });
52
+
53
+ monitoredMultiply(5); // Returns 50
54
+ ```
55
+
56
+ ## Advanced Usage
57
+
58
+ ### Intercepting and Modifying the AST (Inspector Hook)
59
+ The `inspector` hook provides a rich `visit` object, allowing you to inspect nodes, modify them before execution, and manually execute nodes to observe or change their results.
60
+
61
+ ```typescript
62
+ const monitoredSum = monitor({
63
+ main: { ref: sumUp },
64
+ inspector: (visit) => {
65
+ // Intercept all assignment expressions
66
+ visit.is('AssignmentExpression', (event) => {
67
+ event.node.operator = "-="; // Silently change the operator
68
+ console.log('Assignment result:', visit.execute());
69
+ });
70
+
71
+ // Intercept return statements
72
+ visit.is('ReturnStatement', (event) => {
73
+ const result = visit.execute();
74
+ result.sum = 'INTERCEPTED'; // Modify the return value
75
+ });
76
+ }
77
+ });
78
+ ```
79
+
80
+ ### Execution Timeouts & Sandboxing (`onStep` Hook)
81
+ If you don't need deep AST inspection, use the lightweight `onStep` hook. It fires before each interpreted step without the overhead of allocating the `visit` object. This is perfect for implementing execution timeouts or simulating a sandbox.
82
+
83
+ ```typescript
84
+ const timeoutTracker = { limitMs: 50, startTime: 0, stepCounter: 0 };
85
+
86
+ const safeFn = monitor({
87
+ main: { ref: heavyComputation },
88
+ beforeEachCall: () => {
89
+ timeoutTracker.stepCounter = 0;
90
+ timeoutTracker.startTime = performance.now();
91
+ },
92
+ onStep: () => {
93
+ timeoutTracker.stepCounter++;
94
+ // Bitmask check: Only evaluate time every 1024 steps for performance
95
+ if ((timeoutTracker.stepCounter & 1023) === 0) {
96
+ if (performance.now() - timeoutTracker.startTime > timeoutTracker.limitMs) {
97
+ throw new Error('Max execution time exceeded!');
98
+ }
99
+ }
100
+ }
101
+ });
102
+ ```
103
+
104
+ ### Embedding Functions & Extracting Source Code
105
+ You can embed external functions directly into the interpreter's context and extract the final generated code using `sourceOut`.
106
+
107
+ ```typescript
108
+ const generatedCode = { value: '' };
109
+
110
+ const monitoredAsyncFn = monitor({
111
+ main: { ref: async (a, b) => await log(a + b) },
112
+ embed: {
113
+ log: { ref: console.log } // Embed console.log into the interpreter context
114
+ },
115
+ sourceOut: generatedCode // Populates the generated code string
116
+ });
117
+
118
+ console.log(generatedCode.value); // Prints the interpreted JS code
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Full API Reference
124
+
125
+ ### `monitor<T>(setup: MonitorFnSetup<T>)`
126
+ The main export. Returns the monitored function `T` augmented with an `alreadyMonitored: true` property.
127
+
128
+ #### `MonitorFnSetup` Configuration
129
+ | Property | Type | Description |
130
+ | :--- | :--- | :--- |
131
+ | `main` | `Metadata<T>` | **Required.** The main function to monitor and its captures. |
132
+ | `embed` | `Record<string, Metadata<Fn>>` | Alternative to capturing. Includes external functions' source code directly in the interpreter context. |
133
+ | `inspector` | `Inspector` | The main hook fed the interpreter's context (`visit` object) to inspect/modify nodes. |
134
+ | `onStep` | `OnStep` | Lightweight hook called before each step. No `visit` object. Much faster than `inspector`. |
135
+ | `sourceOut` | `{ value: string }` | Overwrites the `value` property with the generated code used in the interpreter. |
136
+ | `beforeEachCall` | `(...args) => void` | Hook called before each execution with the passed arguments. |
137
+ | `afterEachCall` | `(result \| Error) => void` | Hook called after each execution with the result or thrown error. |
138
+
139
+ #### `Metadata<T>`
140
+ | Property | Type | Description |
141
+ | :--- | :--- | :--- |
142
+ | `ref` | `T` | The reference to the function. |
143
+ | `captures` | `Record<string, any>` | Maps variable names to their outside-scope values. Follows copy-by-value/primitive and copy-by-reference/object semantics. |
144
+
145
+ ### The `Visit` Object (Inspector Context)
146
+ Passed to the `inspector` hook. It is allocated once per monitored function (not per call) to save memory. **Must only be used strictly within the inspector hook.**
147
+
148
+ * **`visit.is(query, callback)`**: Registers a callback for specific AST node types (e.g., `'CallExpression'`, `'Any'`). If matched, it allocates a scope and event object.
149
+ * **`visit.execute()`**: Manually executes the current node and returns the result. For async nodes, it returns `LAZY_NODE` (requires the inspector to be a generator to `yield`).
150
+ * **`visit.localExeStack()`**: Returns a readonly stack of the latest evaluated child node results.
151
+ * **`visit.perExecution`**: A setter for a callback fired on each executed node. Short-lived; exists only for the current node and its children.
152
+
153
+ ### Events and Queries
154
+ The `visit.is` method accepts a `Query` (any valid ESTree node type string, plus `'Any'`). The callback receives a specific `Event` object tailored to that node type (e.g., `CallExprEvent`, `BinaryExprEvent`), which contains:
155
+ * `node`: The AST node.
156
+ * `scope`: The safe scope object (`ScopeForEvent`), allowing you to search local variables and check scope depth.
157
+
158
+ ### Utility Types
159
+ * **`QList<T>` / `ReadonlyQList<T>`**: Custom optimized dequeue with random array access. Used internally for the execution stack.
160
+ * **`Var`**: Represents a variable in the scope.
161
+ * **Symbols**: `NOT_ALLOCATED`, `LAZY_NODE`.
162
+ * **Events**: Over 30 specific event classes (e.g., `IfStmtEvent`, `ForStmtEvent`, `LiteralEvent`) extending the base `LangEvent`.
163
+
164
+ ---
165
+
166
+ ## How it Works (Architecture)
167
+
168
+ Under the hood, `@typescript-guy/fn-monitor` utilizes an **AST-walker interpreter** (rather than a bytecode implementation) to evaluate functions.
169
+
170
+ * **Interpreter Isolation:** Each monitored function is assigned its own dedicated interpreter instance. While this incurs a slight memory overhead, it strictly prevents state collision between executions.
171
+ * **Reusables Architecture:** To share interpretation context with the inspector hook performantly, the implementation leverages internal "reusable" objects. This prevents the allocation of intermediate objects mid-evaluation. To handle complex async/await state transitions safely, it uses a "copy, then overwrite" pattern.
172
+ * **Single Parse:** A monitored function is parsed into an AST only once. The resulting nodes and scope objects are reused across all calls to maximize execution speed.
173
+
174
+ ---
175
+
176
+ ## Limitations & Important Notes
177
+
178
+ Please keep the following architectural constraints in mind when using this package:
179
+
180
+ 1. **Debugging & Stack Traces:** Because monitored functions run in an isolated context, errors thrown within them will not map directly to their original source location in your editor. You should debug functions in their unmonitored state first. *(Note: The inspector hook itself runs in the native JS runtime, so it will still display a proper stack trace if the inspector throws an error).*
181
+ 2. **AST Mutation Persistence:** Because the AST is parsed only once, **any mutations made to a node within the inspector will persist and reflect in all subsequent calls** to that function.
182
+ 3. **Sandboxing:** This monitor is not designed to act as a secure, impenetrable sandbox out-of-the-box. However, you can simulate a sandboxed environment by actively monitoring and intercepting nodes via the `inspector` and `onStep` hooks.
183
+ 4. **Scope Limitations:** Do not attempt to expand this into a script-level or module-level monitor. The package is strictly designed around hidden function-context assumptions.
184
+
185
+ ---
186
+
187
+ ## Acknowledgements
188
+
189
+ The core execution engine of this project is a modified and extended version of [`sval`](https://github.com/Siubaak/sval), a JavaScript interpreter written in JavaScript, originally authored by Siubaak.
190
+
191
+ *Please note: This project is an independent extension and is not affiliated with, endorsed by, or sponsored by the original `sval` project or its authors.*
192
+
193
+ `sval` is licensed under the MIT License.
194
+
195
+ ## Questions & Support
196
+
197
+ If you have questions about how to use `@typescript-guy/fn-monitor`, need help with a specific implementation, or want to discuss architecture:
198
+ * **Open a [GitHub Discussion](https://github.com/The-BigMan-tech/fn-monitor/discussions)**: This is the best place for Q&A and community help.
199
+ * **Open an [Issue](https://github.com/The-BigMan-tech/fn-monitor/issues)**: If you've found a bug or want to request a new feature.
200
+
201
+ *Note: This is an open-source project maintained in my free time. I will do my best to respond, but please allow a few days for a reply. Before opening a new thread, please check existing Discussions and Issues to see if your question has already been answered!*
@@ -0,0 +1,239 @@
1
+ import { default as Scope } from './scope/index.ts';
2
+ import { Node as EsTreeNode, Literal, VariableDeclaration, FunctionDeclaration, IfStatement, SwitchStatement, TryStatement, CatchClause, ReturnStatement, ThrowStatement, ForStatement, WhileStatement, DoWhileStatement, ForOfStatement, ForInStatement, BreakStatement, ContinueStatement, LabeledStatement, YieldExpression, BinaryExpression, CallExpression, AssignmentExpression, UpdateExpression, LogicalExpression, MemberExpression, AwaitExpression, FunctionExpression, ArrowFunctionExpression, ConditionalExpression, NewExpression, ExpressionStatement, ArrayExpression, ObjectExpression, TemplateLiteral, SequenceExpression, UnaryExpression } from 'estree';
3
+ import { Var } from './scope/variable.ts';
4
+ import { QList, ReadonlyQList } from './q-list.ts';
5
+ export type Fn = (...args: any[]) => any;
6
+ export type EsNode = EsTreeNode;
7
+ /**
8
+ * This is a string union of all the possible nodes the caller can query in the visit.is callback.
9
+ * They are all estree node types.You will see type definitions shortening this to EsNode.
10
+ * There are over 30 types of nodes that you can query and if any of the nodes dont match your needs,you can always use the 'Any' query which matches for every node.You can then use the estree node type to cast it to specific types
11
+ */
12
+ export type Query = Literal['type'] | BinaryExpression['type'] | CallExpression['type'] | AssignmentExpression['type'] | UpdateExpression['type'] | LogicalExpression['type'] | MemberExpression['type'] | AwaitExpression['type'] | FunctionExpression['type'] | ReturnStatement['type'] | IfStatement['type'] | SwitchStatement['type'] | ThrowStatement['type'] | TryStatement['type'] | CatchClause['type'] | VariableDeclaration['type'] | FunctionDeclaration['type'] | ForStatement['type'] | WhileStatement['type'] | DoWhileStatement['type'] | ForOfStatement['type'] | ForInStatement['type'] | LabeledStatement['type'] | BreakStatement['type'] | ContinueStatement['type'] | ArrowFunctionExpression['type'] | ConditionalExpression['type'] | NewExpression['type'] | YieldExpression['type'] | ExpressionStatement['type'] | ArrayExpression['type'] | ObjectExpression['type'] | TemplateLiteral['type'] | SequenceExpression['type'] | UnaryExpression['type'] | 'Any';
13
+ /**
14
+ * The type definiton that maps each node query to the event object you will get from that query
15
+ * Each type has its own dedicated Event class which helps to tailor intellisense
16
+ */
17
+ export type EventMap = (Record<Literal['type'], LiteralEvent> & Record<BinaryExpression['type'], BinaryExprEvent> & Record<CallExpression['type'], CallExprEvent> & Record<AssignmentExpression['type'], AssignmentExprEvent> & Record<UpdateExpression['type'], UpdateExprEvent> & Record<LogicalExpression['type'], LogicalExprEvent> & Record<MemberExpression['type'], MemberExprEvent> & Record<AwaitExpression['type'], AwaitExprEvent> & Record<FunctionExpression['type'], FuncExprEvent> & Record<ReturnStatement['type'], ReturnStmtEvent> & Record<IfStatement['type'], IfStmtEvent> & Record<SwitchStatement['type'], SwitchStmtEvent> & Record<ThrowStatement['type'], ThrowStmtEvent> & Record<TryStatement['type'], TryStmtEvent> & Record<CatchClause['type'], CatchClauseEvent> & Record<VariableDeclaration['type'], VarDeclEvent> & Record<FunctionDeclaration['type'], FuncDeclEvent> & Record<ForStatement['type'], ForStmtEvent> & Record<WhileStatement['type'], WhileStmtEvent> & Record<DoWhileStatement['type'], DoWhileStmtEvent> & Record<ForOfStatement['type'], ForOfStmtEvent> & Record<ForInStatement['type'], ForInStmtEvent> & Record<LabeledStatement['type'], LabeledStmtEvent> & Record<BreakStatement['type'], BreakStmtEvent> & Record<ContinueStatement['type'], ContinueStmtEvent> & Record<ArrowFunctionExpression['type'], ArrowFnExprEvent> & Record<ConditionalExpression['type'], TernaryExprEvent> & Record<NewExpression['type'], NewExprEvent> & Record<YieldExpression['type'], YieldExprEvent> & Record<ExpressionStatement['type'], ExpressionStmtEvent> & Record<ArrayExpression['type'], ArrayExprEvent> & Record<ObjectExpression['type'], ObjectExprEvent> & Record<TemplateLiteral['type'], TemplateLiteralEvent> & Record<SequenceExpression['type'], SequenceExprEvent> & Record<UnaryExpression['type'], UnaryExprEvent> & Record<'Any', LangEvent>);
18
+ export declare const LAZY_NODE: unique symbol;
19
+ export declare const NOT_ALLOCATED: unique symbol;
20
+ export declare const UNASSIGNED: unique symbol;
21
+ export declare const SEEN: unique symbol;
22
+ export type InspectorGenerator = Generator<typeof LAZY_NODE, undefined, any>;
23
+ export type PerExe = () => void;
24
+ /**
25
+ * The rich object that gives inspectors their ability to participate in the interpretation of the function
26
+ * Every monitored function has exactly one interpreter and also,exactly one visit object to themselves
27
+ * This means that the visit object is only alloacted once per monitored function and not per call to save memory
28
+ * You will shoot yourself in the foot if you attempt to take the visit object oustide of the inspector hook to use elsewhere.It can cause unexpected side effects.It is to be used strictly within that hook
29
+ *
30
+ * Because there is only one unique visit object,it uses live references to the current interpreter's state.This means that:
31
+ * -The local exe stack is volatile.
32
+ * -The 'is' method does not register your callback as a hook.Although that is what it will look like on the outside,its actually eagerly evaluating your callback the moment you call it and check your query against the current node.It will then discard your callback right after.
33
+ * -The perExecution method does not register your callback as a hook.You use it like a setter and its short lived.It only exists for the current node and all its children
34
+ * -The execute method must strictly be called within the lifetime of the inspector hook if you ever wish to call it.
35
+ *
36
+ * You dont have to worry too much about all of this if you use the visit object in the inspector hook where you know using it is safe.
37
+ */
38
+ export interface Visit {
39
+ /**
40
+ * You pass in which node you are interested in as the first argument and you pass in your callback as the second.
41
+ * For each node that matches your query,it will fire your callback and allocate a scope object to wrap together with the node under a single event object
42
+ * You can mutate the node or query the scope.
43
+ *
44
+ * If you dont set a query for a particular node,the interpreter will not allocate a scope nor an event object.This is to save memory.
45
+ * So in the exe result,you will see a symbol called NOT_ALLOCATED.but you can use visit.is('Any',...) to force the interpreter to allocate a scope and event object for every node it visits
46
+ */
47
+ is: <T extends Query>(query: T, ifMatched: (event: EventMap[T]) => void) => void;
48
+ /**
49
+ * This is fired on each executed node.The hook itself does not get passed anything.It is actually a good place to check the local exe stack.By querying for the last element,you get to see the exe result in real time which includes the nodes,the results and each scope
50
+ */
51
+ set perExecution(perExe: PerExe);
52
+ /**
53
+ * The function that tells the interpreter to execute the current node and return the result.
54
+ * If its an async node like an await call,you get LAZY_NODE instead of the awaited result.You must explicitly type yield visit.execute() to get it.but it requires the inspector to be a generator instead of a regular function
55
+ * Once you get the result,you can read it or even modify it before it is returned to the caller
56
+ * The interpreter will execute the node manually if you never call this.
57
+ * There is no way to directly stop the interpreter from executing a node.This is to prevent a half broken state.If required,the inspector hook must throw an error
58
+ */
59
+ execute: <T extends any = any>() => T;
60
+ /**
61
+ * This is a stack data structure that contains the results of each evaluated child node for a given node.
62
+ * The latest results stay at the top and the oldest remain at the bottom.
63
+ * It is not the full execution history of the entire function.
64
+ */
65
+ localExeStack: () => Omit<ReadonlyQList<ExeResult>, 'swapSrc'>;
66
+ }
67
+ export interface ExeResult {
68
+ /**The result of the node's evaluation */
69
+ evaluation: unknown;
70
+ /**The type of the node*/
71
+ type: EsNode['type'];
72
+ /**
73
+ * The node itself.Unlike the scope object,the nodes are always allocated.
74
+ * The reality is that the interpreter always allocates a node and a scope object to process each step.
75
+ * But it doesnt openly pass the original scope object because mutating the scope directly isnt as safe as a specific node
76
+ * So it only directly passes the internal node object and allocates a safe scope object that cant be used to mutate the original scope in any way.But it is only selectively allocated
77
+ */
78
+ node: EsNode;
79
+ /**
80
+ *the safe scope created for the caller
81
+ */
82
+ scope: ScopeForEvent | typeof NOT_ALLOCATED;
83
+ }
84
+ /**This type describes an internal object */
85
+ export interface Reusables {
86
+ node: EsNode | null;
87
+ currentScope: Scope | null;
88
+ handler: null | ((node: EsNode, scope: Scope<SvalPlus>) => any);
89
+ result: any | typeof UNASSIGNED | typeof SEEN;
90
+ currentEvent: LangEvent | typeof NOT_ALLOCATED;
91
+ shared: {
92
+ exeStack: QList<ExeResult>;
93
+ readonlyExeStack: ReadonlyQList<ExeResult>;
94
+ evalStack: {
95
+ value: number;
96
+ };
97
+ perExe: null | {
98
+ owner: EsNode;
99
+ fn: PerExe;
100
+ };
101
+ };
102
+ }
103
+ export type Inspector = (visit: Visit) => void | InspectorGenerator;
104
+ export type OnStep = () => void;
105
+ export interface SvalPlus {
106
+ inspector: Inspector | null;
107
+ onStep: OnStep | null;
108
+ reusables: Reusables;
109
+ visit: Visit;
110
+ stage: 'IDLE' | 'PRE-PROCESSING' | 'MONITORING';
111
+ createEventScope: () => ScopeForEvent;
112
+ }
113
+ export interface VariableForEvent {
114
+ /**The value of the variable */
115
+ value: () => any;
116
+ }
117
+ export interface ScopeForEvent {
118
+ /**The variables in the scope.You can check for all the local variables or use the search method to get a variable from its identifier.*/
119
+ variables: {
120
+ /**If a variable cannot be identified from the given name,you get null instead of the object */
121
+ search: (name: string) => VariableForEvent | null;
122
+ local: Record<string, Var>;
123
+ };
124
+ /**The parent scope */
125
+ parent: Scope | null;
126
+ /**The depth of the scope of the current node*/
127
+ depth: number;
128
+ }
129
+ export declare class LangEvent<NodeType extends EsNode = EsNode> {
130
+ node: NodeType;
131
+ scope: ScopeForEvent;
132
+ constructor(interpreter: SvalPlus);
133
+ }
134
+ export declare class ExpressionStmtEvent extends LangEvent<ExpressionStatement> {
135
+ constructor(interpreter: SvalPlus);
136
+ }
137
+ export declare class ArrayExprEvent extends LangEvent<ArrayExpression> {
138
+ constructor(interpreter: SvalPlus);
139
+ }
140
+ export declare class ObjectExprEvent extends LangEvent<ObjectExpression> {
141
+ constructor(interpreter: SvalPlus);
142
+ }
143
+ export declare class TemplateLiteralEvent extends LangEvent<TemplateLiteral> {
144
+ constructor(interpreter: SvalPlus);
145
+ }
146
+ export declare class SequenceExprEvent extends LangEvent<SequenceExpression> {
147
+ constructor(interpreter: SvalPlus);
148
+ }
149
+ export declare class UnaryExprEvent extends LangEvent<UnaryExpression> {
150
+ constructor(interpreter: SvalPlus);
151
+ }
152
+ export declare class BinaryExprEvent extends LangEvent<BinaryExpression> {
153
+ constructor(interpreter: SvalPlus);
154
+ }
155
+ export declare class CallExprEvent extends LangEvent<CallExpression> {
156
+ constructor(interpreter: SvalPlus);
157
+ }
158
+ export declare class AssignmentExprEvent extends LangEvent<AssignmentExpression> {
159
+ constructor(interpreter: SvalPlus);
160
+ }
161
+ export declare class UpdateExprEvent extends LangEvent<UpdateExpression> {
162
+ constructor(interpreter: SvalPlus);
163
+ }
164
+ export declare class LogicalExprEvent extends LangEvent<LogicalExpression> {
165
+ constructor(interpreter: SvalPlus);
166
+ }
167
+ export declare class MemberExprEvent extends LangEvent<MemberExpression> {
168
+ constructor(interpreter: SvalPlus);
169
+ }
170
+ export declare class AwaitExprEvent extends LangEvent<AwaitExpression> {
171
+ constructor(interpreter: SvalPlus);
172
+ }
173
+ export declare class FuncExprEvent extends LangEvent<FunctionExpression> {
174
+ constructor(interpreter: SvalPlus);
175
+ }
176
+ export declare class ArrowFnExprEvent extends LangEvent<ArrowFunctionExpression> {
177
+ constructor(interpreter: SvalPlus);
178
+ }
179
+ export declare class TernaryExprEvent extends LangEvent<ConditionalExpression> {
180
+ constructor(interpreter: SvalPlus);
181
+ }
182
+ export declare class NewExprEvent extends LangEvent<NewExpression> {
183
+ constructor(interpreter: SvalPlus);
184
+ }
185
+ export declare class YieldExprEvent extends LangEvent<YieldExpression> {
186
+ constructor(interpreter: SvalPlus);
187
+ }
188
+ export declare class ReturnStmtEvent extends LangEvent<ReturnStatement> {
189
+ constructor(interpreter: SvalPlus);
190
+ }
191
+ export declare class IfStmtEvent extends LangEvent<IfStatement> {
192
+ constructor(interpreter: SvalPlus);
193
+ }
194
+ export declare class SwitchStmtEvent extends LangEvent<SwitchStatement> {
195
+ constructor(interpreter: SvalPlus);
196
+ }
197
+ export declare class ThrowStmtEvent extends LangEvent<ThrowStatement> {
198
+ constructor(interpreter: SvalPlus);
199
+ }
200
+ export declare class TryStmtEvent extends LangEvent<TryStatement> {
201
+ constructor(interpreter: SvalPlus);
202
+ }
203
+ export declare class CatchClauseEvent extends LangEvent<CatchClause> {
204
+ constructor(interpreter: SvalPlus);
205
+ }
206
+ export declare class VarDeclEvent extends LangEvent<VariableDeclaration> {
207
+ constructor(interpreter: SvalPlus);
208
+ }
209
+ export declare class FuncDeclEvent extends LangEvent<FunctionDeclaration> {
210
+ constructor(interpreter: SvalPlus);
211
+ }
212
+ export declare class ForStmtEvent extends LangEvent<ForStatement> {
213
+ constructor(interpreter: SvalPlus);
214
+ }
215
+ export declare class WhileStmtEvent extends LangEvent<WhileStatement> {
216
+ constructor(interpreter: SvalPlus);
217
+ }
218
+ export declare class DoWhileStmtEvent extends LangEvent<DoWhileStatement> {
219
+ constructor(interpreter: SvalPlus);
220
+ }
221
+ export declare class ForOfStmtEvent extends LangEvent<ForOfStatement> {
222
+ constructor(interpreter: SvalPlus);
223
+ }
224
+ export declare class ForInStmtEvent extends LangEvent<ForInStatement> {
225
+ constructor(interpreter: SvalPlus);
226
+ }
227
+ export declare class LabeledStmtEvent extends LangEvent<LabeledStatement> {
228
+ constructor(interpreter: SvalPlus);
229
+ }
230
+ export declare class BreakStmtEvent extends LangEvent<BreakStatement> {
231
+ constructor(interpreter: SvalPlus);
232
+ }
233
+ export declare class ContinueStmtEvent extends LangEvent<ContinueStatement> {
234
+ constructor(interpreter: SvalPlus);
235
+ }
236
+ export declare class LiteralEvent extends LangEvent<Literal> {
237
+ constructor(interpreter: SvalPlus);
238
+ }
239
+ export declare function createEvent<T extends Query>(query: Query, interpreter: SvalPlus): EventMap[T];