Skip to content

Commit d4bdf14

Browse files
committed
feat: add event methods, like rxjs
1 parent a02b19e commit d4bdf14

16 files changed

+429
-180
lines changed

packages/renderer-core/src/main.ts packages/renderer-core/src/createRenderer.ts

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export function createRenderer<RenderObject = IRenderObject>(
8383
},
8484
destroy: () => {
8585
lifeCycleService.setPhase(LifecyclePhase.Destroying);
86+
instantiationService.dispose();
8687
},
8788
};
8889

packages/renderer-core/src/index.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* --------------- api -------------------- */
2-
export { createRenderer } from './main';
2+
export { createRenderer } from './createRenderer';
33
export { IExtensionHostService } from './services/extension';
44
export { definePackageLoader, IPackageManagementService } from './services/package';
55
export { LifecyclePhase, ILifeCycleService } from './services/lifeCycleService';
@@ -9,7 +9,6 @@ export { IRuntimeIntlService } from './services/runtimeIntlService';
99
export { IRuntimeUtilService } from './services/runtimeUtilService';
1010
export { ISchemaService } from './services/schema';
1111
export { Widget } from './widget';
12-
export * from './utils/value';
1312

1413
/* --------------- types ---------------- */
1514
export type * from './types';
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
11
import {
22
type StringDictionary,
33
type JSNode,
4-
type EventDisposable,
4+
type IDisposable,
55
type JSExpression,
66
type JSFunction,
77
specTypes,
8+
isNode,
9+
toDisposable,
10+
Disposable,
811
} from '@alilc/lowcode-shared';
912
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';
1214
import { evaluate } from './evaluate';
1315

1416
export interface CodeRuntimeOptions<T extends StringDictionary = StringDictionary> {
1517
initScopeValue?: Partial<T>;
18+
1619
parentScope?: ICodeScope;
1720

1821
evalCodeFunction?: EvalCodeFunction;
1922
}
2023

21-
export interface ICodeRuntime<T extends StringDictionary = StringDictionary> {
24+
export interface ICodeRuntime<T extends StringDictionary = StringDictionary> extends IDisposable {
2225
getScope(): ICodeScope<T>;
2326

2427
run<R = unknown>(code: string, scope?: ICodeScope): R | undefined;
2528

2629
resolve(value: StringDictionary): any;
2730

28-
onResolve(handler: NodeResolverHandler): EventDisposable;
31+
onResolve(handler: NodeResolverHandler): IDisposable;
2932

3033
createChild<V extends StringDictionary = StringDictionary>(
3134
options: Omit<CodeRuntimeOptions<V>, 'parentScope'>,
@@ -34,49 +37,55 @@ export interface ICodeRuntime<T extends StringDictionary = StringDictionary> {
3437

3538
export type NodeResolverHandler = (node: JSNode) => JSNode | false | undefined;
3639

37-
let onResolveHandlers: NodeResolverHandler[] = [];
38-
3940
export type EvalCodeFunction = (code: string, scope: any) => any;
4041

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;
4349

44-
private evalCodeFunction: EvalCodeFunction = evaluate;
50+
private _resolveHandlers: NodeResolverHandler[] = [];
4551

4652
constructor(options: CodeRuntimeOptions<T> = {}) {
47-
if (options.evalCodeFunction) this.evalCodeFunction = options.evalCodeFunction;
53+
super();
4854

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+
);
5461
}
5562

5663
getScope() {
57-
return this.codeScope;
64+
return this._codeScope;
5865
}
5966

6067
run<R = unknown>(code: string): R | undefined {
68+
this._throwIfDisposed(`this code runtime has been disposed`);
69+
6170
if (!code) return undefined;
6271

6372
try {
64-
const result = this.evalCodeFunction(code, this.codeScope.value);
73+
const result = this._evalCodeFunction(code, this._codeScope.value);
6574

6675
return result as R;
6776
} catch (err) {
6877
// todo replace logger
69-
console.error('eval error', code, this.codeScope.value, err);
78+
console.error('eval error', code, this._codeScope.value, err);
7079
return undefined;
7180
}
7281
}
7382

7483
resolve(data: StringDictionary): any {
75-
if (onResolveHandlers.length > 0) {
84+
if (this._resolveHandlers.length > 0) {
7685
data = mapValue(data, isNode, (node: JSNode) => {
7786
let newNode: JSNode | false | undefined = node;
7887

79-
for (const handler of onResolveHandlers) {
88+
for (const handler of this._resolveHandlers) {
8089
newNode = handler(newNode as JSNode);
8190
if (newNode === false || typeof newNode === 'undefined') {
8291
break;
@@ -110,20 +119,25 @@ export class CodeRuntime<T extends StringDictionary = StringDictionary> implemen
110119
/**
111120
* 顺序执行 handler
112121
*/
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+
);
118130
}
119131

120132
createChild<V extends StringDictionary = StringDictionary>(
121133
options?: Omit<CodeRuntimeOptions<V>, 'parentScope'>,
122134
): 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+
);
128142
}
129143
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import {
22
createDecorator,
3-
invariant,
43
Disposable,
54
type StringDictionary,
5+
type IDisposable,
66
} from '@alilc/lowcode-shared';
77
import { type ICodeRuntime, type CodeRuntimeOptions, CodeRuntime } from './codeRuntime';
88
import { ISchemaService } from '../schema';
99

10-
export interface ICodeRuntimeService {
10+
export interface ICodeRuntimeService extends IDisposable {
1111
readonly rootRuntime: ICodeRuntime;
1212

1313
createCodeRuntime<T extends StringDictionary = StringDictionary>(
@@ -18,15 +18,18 @@ export interface ICodeRuntimeService {
1818
export const ICodeRuntimeService = createDecorator<ICodeRuntimeService>('codeRuntimeService');
1919

2020
export class CodeRuntimeService extends Disposable implements ICodeRuntimeService {
21-
rootRuntime: ICodeRuntime;
21+
private _rootRuntime: ICodeRuntime;
22+
get rootRuntime() {
23+
return this._rootRuntime;
24+
}
2225

2326
constructor(
2427
options: CodeRuntimeOptions = {},
2528
@ISchemaService private schemaService: ISchemaService,
2629
) {
2730
super();
28-
this.rootRuntime = new CodeRuntime(options);
2931

32+
this._rootRuntime = this.addDispose(new CodeRuntime(options));
3033
this.addDispose(
3134
this.schemaService.onSchemaUpdate(({ key, data }) => {
3235
if (key === 'constants') {
@@ -39,10 +42,10 @@ export class CodeRuntimeService extends Disposable implements ICodeRuntimeServic
3942
createCodeRuntime<T extends StringDictionary = StringDictionary>(
4043
options: CodeRuntimeOptions<T> = {},
4144
): ICodeRuntime<T> {
42-
invariant(this.rootRuntime, `please initialize codeRuntimeService on renderer starting!`);
45+
this._throwIfDisposed();
4346

44-
return options.parentScope
45-
? new CodeRuntime(options)
46-
: this.rootRuntime.createChild<T>(options);
47+
return this.addDispose(
48+
options.parentScope ? new CodeRuntime(options) : this.rootRuntime.createChild<T>(options),
49+
);
4750
}
4851
}

packages/renderer-core/src/services/code-runtime/codeScope.ts

+40-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { type StringDictionary, LinkedListNode } from '@alilc/lowcode-shared';
1+
import {
2+
type StringDictionary,
3+
Disposable,
4+
type IDisposable,
5+
LinkedListNode,
6+
} from '@alilc/lowcode-shared';
27
import { trustedGlobals } from './globals-es2015';
38

49
/*
@@ -9,33 +14,50 @@ const unscopables = trustedGlobals.reduce((acc, key) => ({ ...acc, [key]: true }
914
__proto__: null,
1015
});
1116

12-
export interface ICodeScope<T extends StringDictionary = StringDictionary> {
17+
export interface ICodeScope<T extends StringDictionary = StringDictionary> extends IDisposable {
1318
readonly value: T;
1419

1520
set(name: keyof T, value: any): void;
21+
1622
setValue(value: Partial<T>, replace?: boolean): void;
23+
1724
createChild<V extends StringDictionary = StringDictionary>(initValue: Partial<V>): ICodeScope<V>;
25+
26+
dispose(): void;
1827
}
1928

20-
export class CodeScope<T extends StringDictionary = StringDictionary> implements ICodeScope<T> {
29+
export class CodeScope<T extends StringDictionary = StringDictionary>
30+
extends Disposable
31+
implements ICodeScope<T>
32+
{
2133
node = LinkedListNode.Undefined;
2234

23-
private proxyValue: T;
35+
private _proxyValue?: T;
2436

2537
constructor(initValue: Partial<T>) {
38+
super();
39+
2640
this.node.current = initValue;
27-
this.proxyValue = this.createProxy();
2841
}
2942

3043
get value(): T {
31-
return this.proxyValue;
44+
this._throwIfDisposed('code scope has been disposed');
45+
46+
if (!this._proxyValue) {
47+
this._proxyValue = this._createProxy();
48+
}
49+
return this._proxyValue;
3250
}
3351

3452
set(name: keyof T, value: any): void {
53+
this._throwIfDisposed('code scope has been disposed');
54+
3555
this.node.current[name] = value;
3656
}
3757

3858
setValue(value: Partial<T>, replace = false) {
59+
this._throwIfDisposed('code scope has been disposed');
60+
3961
if (replace) {
4062
this.node.current = { ...value };
4163
} else {
@@ -44,24 +66,30 @@ export class CodeScope<T extends StringDictionary = StringDictionary> implements
4466
}
4567

4668
createChild<V extends StringDictionary = StringDictionary>(initValue: Partial<V>): ICodeScope<V> {
47-
const childScope = new CodeScope(initValue);
69+
const childScope = this.addDispose(new CodeScope(initValue));
4870
childScope.node.prev = this.node;
4971

5072
return childScope;
5173
}
5274

53-
private createProxy(): T {
75+
dispose(): void {
76+
super.dispose();
77+
this.node = LinkedListNode.Undefined;
78+
this._proxyValue = undefined;
79+
}
80+
81+
private _createProxy(): T {
5482
return new Proxy(Object.create(null) as T, {
5583
set: (target, p, newValue) => {
5684
this.set(p as string, newValue);
5785
return true;
5886
},
59-
get: (_, p) => this.findValue(p) ?? undefined,
60-
has: (_, p) => this.hasProperty(p),
87+
get: (_, p) => this._findValue(p) ?? undefined,
88+
has: (_, p) => this._hasProperty(p),
6189
});
6290
}
6391

64-
private findValue(prop: PropertyKey) {
92+
private _findValue(prop: PropertyKey) {
6593
if (prop === Symbol.unscopables) return unscopables;
6694

6795
let node = this.node;
@@ -73,7 +101,7 @@ export class CodeScope<T extends StringDictionary = StringDictionary> implements
73101
}
74102
}
75103

76-
private hasProperty(prop: PropertyKey): boolean {
104+
private _hasProperty(prop: PropertyKey): boolean {
77105
if (prop in unscopables) return true;
78106

79107
let node = this.node;
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './codeScope';
22
export * from './codeRuntimeService';
33
export * from './codeRuntime';
4+
export * from './value';

0 commit comments

Comments
 (0)