1
1
import {
2
2
type StringDictionary ,
3
3
type JSNode ,
4
- type EventDisposable ,
4
+ type IDisposable ,
5
5
type JSExpression ,
6
6
type JSFunction ,
7
7
specTypes ,
8
+ isNode ,
9
+ toDisposable ,
10
+ Disposable ,
8
11
} from '@alilc/lowcode-shared' ;
9
12
import { type ICodeScope , CodeScope } from './codeScope' ;
10
- import { isNode } from '../../../../shared/src/utils/node' ;
11
- import { mapValue } from '../../utils/value' ;
13
+ import { mapValue } from './value' ;
12
14
import { evaluate } from './evaluate' ;
13
15
14
16
export interface CodeRuntimeOptions < T extends StringDictionary = StringDictionary > {
15
17
initScopeValue ?: Partial < T > ;
18
+
16
19
parentScope ?: ICodeScope ;
17
20
18
21
evalCodeFunction ?: EvalCodeFunction ;
19
22
}
20
23
21
- export interface ICodeRuntime < T extends StringDictionary = StringDictionary > {
24
+ export interface ICodeRuntime < T extends StringDictionary = StringDictionary > extends IDisposable {
22
25
getScope ( ) : ICodeScope < T > ;
23
26
24
27
run < R = unknown > ( code : string , scope ?: ICodeScope ) : R | undefined ;
25
28
26
29
resolve ( value : StringDictionary ) : any ;
27
30
28
- onResolve ( handler : NodeResolverHandler ) : EventDisposable ;
31
+ onResolve ( handler : NodeResolverHandler ) : IDisposable ;
29
32
30
33
createChild < V extends StringDictionary = StringDictionary > (
31
34
options : Omit < CodeRuntimeOptions < V > , 'parentScope' > ,
@@ -34,49 +37,55 @@ export interface ICodeRuntime<T extends StringDictionary = StringDictionary> {
34
37
35
38
export type NodeResolverHandler = ( node : JSNode ) => JSNode | false | undefined ;
36
39
37
- let onResolveHandlers : NodeResolverHandler [ ] = [ ] ;
38
-
39
40
export type EvalCodeFunction = ( code : string , scope : any ) => any ;
40
41
41
- export class CodeRuntime < T extends StringDictionary = StringDictionary > implements ICodeRuntime < T > {
42
- private codeScope : ICodeScope < T > ;
42
+ export class CodeRuntime < T extends StringDictionary = StringDictionary >
43
+ extends Disposable
44
+ implements ICodeRuntime < T >
45
+ {
46
+ private _codeScope : ICodeScope < T > ;
47
+
48
+ private _evalCodeFunction : EvalCodeFunction = evaluate ;
43
49
44
- private evalCodeFunction : EvalCodeFunction = evaluate ;
50
+ private _resolveHandlers : NodeResolverHandler [ ] = [ ] ;
45
51
46
52
constructor ( options : CodeRuntimeOptions < T > = { } ) {
47
- if ( options . evalCodeFunction ) this . evalCodeFunction = options . evalCodeFunction ;
53
+ super ( ) ;
48
54
49
- if ( options . parentScope ) {
50
- this . codeScope = options . parentScope . createChild < T > ( options . initScopeValue ?? { } ) ;
51
- } else {
52
- this . codeScope = new CodeScope ( options . initScopeValue ?? { } ) ;
53
- }
55
+ if ( options . evalCodeFunction ) this . _evalCodeFunction = options . evalCodeFunction ;
56
+ this . _codeScope = this . addDispose (
57
+ options . parentScope
58
+ ? options . parentScope . createChild < T > ( options . initScopeValue ?? { } )
59
+ : new CodeScope ( options . initScopeValue ?? { } ) ,
60
+ ) ;
54
61
}
55
62
56
63
getScope ( ) {
57
- return this . codeScope ;
64
+ return this . _codeScope ;
58
65
}
59
66
60
67
run < R = unknown > ( code : string ) : R | undefined {
68
+ this . _throwIfDisposed ( `this code runtime has been disposed` ) ;
69
+
61
70
if ( ! code ) return undefined ;
62
71
63
72
try {
64
- const result = this . evalCodeFunction ( code , this . codeScope . value ) ;
73
+ const result = this . _evalCodeFunction ( code , this . _codeScope . value ) ;
65
74
66
75
return result as R ;
67
76
} catch ( err ) {
68
77
// todo replace logger
69
- console . error ( 'eval error' , code , this . codeScope . value , err ) ;
78
+ console . error ( 'eval error' , code , this . _codeScope . value , err ) ;
70
79
return undefined ;
71
80
}
72
81
}
73
82
74
83
resolve ( data : StringDictionary ) : any {
75
- if ( onResolveHandlers . length > 0 ) {
84
+ if ( this . _resolveHandlers . length > 0 ) {
76
85
data = mapValue ( data , isNode , ( node : JSNode ) => {
77
86
let newNode : JSNode | false | undefined = node ;
78
87
79
- for ( const handler of onResolveHandlers ) {
88
+ for ( const handler of this . _resolveHandlers ) {
80
89
newNode = handler ( newNode as JSNode ) ;
81
90
if ( newNode === false || typeof newNode === 'undefined' ) {
82
91
break ;
@@ -110,20 +119,25 @@ export class CodeRuntime<T extends StringDictionary = StringDictionary> implemen
110
119
/**
111
120
* 顺序执行 handler
112
121
*/
113
- onResolve ( handler : NodeResolverHandler ) : EventDisposable {
114
- onResolveHandlers . push ( handler ) ;
115
- return ( ) => {
116
- onResolveHandlers = onResolveHandlers . filter ( ( h ) => h !== handler ) ;
117
- } ;
122
+ onResolve ( handler : NodeResolverHandler ) : IDisposable {
123
+ this . _resolveHandlers . push ( handler ) ;
124
+
125
+ return this . addDispose (
126
+ toDisposable ( ( ) => {
127
+ this . _resolveHandlers = this . _resolveHandlers . filter ( ( h ) => h !== handler ) ;
128
+ } ) ,
129
+ ) ;
118
130
}
119
131
120
132
createChild < V extends StringDictionary = StringDictionary > (
121
133
options ?: Omit < CodeRuntimeOptions < V > , 'parentScope' > ,
122
134
) : ICodeRuntime < V > {
123
- return new CodeRuntime ( {
124
- initScopeValue : options ?. initScopeValue ,
125
- parentScope : this . codeScope ,
126
- evalCodeFunction : options ?. evalCodeFunction ?? this . evalCodeFunction ,
127
- } ) ;
135
+ return this . addDispose (
136
+ new CodeRuntime ( {
137
+ initScopeValue : options ?. initScopeValue ,
138
+ parentScope : this . _codeScope ,
139
+ evalCodeFunction : options ?. evalCodeFunction ?? this . _evalCodeFunction ,
140
+ } ) ,
141
+ ) ;
128
142
}
129
143
}
0 commit comments