@zk-tech/bedrock 0.0.1 → 0.1.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.
- package/dist/async/index.cjs.map +1 -1
- package/dist/async/index.d.cts +2 -2
- package/dist/async/index.d.ts +2 -2
- package/dist/async/index.js.map +1 -1
- package/dist/error/index.cjs.map +1 -1
- package/dist/error/index.d.cts +19 -19
- package/dist/error/index.d.ts +19 -19
- package/dist/error/index.js.map +1 -1
- package/dist/{error-base-B4zaiJ5m.d.cts → error-base-DOFtBFla.d.cts} +8 -8
- package/dist/{error-base-B4zaiJ5m.d.ts → error-base-DOFtBFla.d.ts} +8 -8
- package/dist/promise/index.cjs.map +1 -1
- package/dist/promise/index.d.cts +4 -4
- package/dist/promise/index.d.ts +4 -4
- package/dist/promise/index.js.map +1 -1
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +2 -2
- package/dist/worker/index.d.ts +2 -2
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -2
- package/src/_internal/logger.ts +0 -59
- package/src/array/array.test.ts +0 -35
- package/src/array/array.ts +0 -25
- package/src/array/index.ts +0 -1
- package/src/assert/assert.test.ts +0 -86
- package/src/assert/assert.ts +0 -42
- package/src/assert/index.ts +0 -2
- package/src/async/barrier.test.ts +0 -90
- package/src/async/barrier.ts +0 -58
- package/src/async/cancellation.test.ts +0 -85
- package/src/async/cancellation.ts +0 -193
- package/src/async/index.ts +0 -18
- package/src/async/queue/queue.test.ts +0 -70
- package/src/async/queue/queue.ts +0 -56
- package/src/async/queue/task.test.ts +0 -155
- package/src/async/queue/task.ts +0 -67
- package/src/async/utils.test.ts +0 -28
- package/src/async/utils.ts +0 -8
- package/src/async/wait.ts +0 -9
- package/src/byte/format.test.ts +0 -64
- package/src/byte/format.ts +0 -44
- package/src/byte/index.ts +0 -2
- package/src/byte/node_modules/.vitest/results.json +0 -1
- package/src/byte/var.ts +0 -11
- package/src/cache/index.ts +0 -2
- package/src/cache/lru-with-timeout.test.ts +0 -88
- package/src/cache/lru-with-timeout.ts +0 -85
- package/src/cache/lru.test.ts +0 -56
- package/src/cache/lru.ts +0 -59
- package/src/context/context.test.ts +0 -17
- package/src/context/context.ts +0 -60
- package/src/context/index.ts +0 -8
- package/src/di/base.ts +0 -73
- package/src/di/container-service.test.ts +0 -179
- package/src/di/context.web.tsx +0 -41
- package/src/di/descriptor.ts +0 -31
- package/src/di/idle-value.test.ts +0 -73
- package/src/di/idle-value.ts +0 -63
- package/src/di/index.common.ts +0 -32
- package/src/di/index.ts +0 -2
- package/src/di/instantiation-service.interface.ts +0 -46
- package/src/di/instantiation-service.test.ts +0 -337
- package/src/di/instantiation-service.ts +0 -468
- package/src/di/lazy/foo.mock.ts +0 -28
- package/src/di/lazy/idle-load.ts +0 -39
- package/src/di/lazy/index.ts +0 -4
- package/src/di/lazy/lazy-service.test.ts +0 -65
- package/src/di/lazy/lazy-service.ts +0 -71
- package/src/di/lazy/type.ts +0 -5
- package/src/di/node_modules/.vitest/results.json +0 -1
- package/src/di/proxy-builder.test.ts +0 -45
- package/src/di/proxy-builder.ts +0 -38
- package/src/di/service-collection.test.ts +0 -27
- package/src/di/service-collection.ts +0 -46
- package/src/di/service-ownership-collection.test.ts +0 -39
- package/src/di/service-ownership-collection.ts +0 -38
- package/src/di/service-registry.test.ts +0 -66
- package/src/di/service-registry.ts +0 -99
- package/src/di/trace.ts +0 -85
- package/src/dispose/disposable-store.test.ts +0 -57
- package/src/dispose/disposable-store.ts +0 -80
- package/src/dispose/disposable-t.test.ts +0 -123
- package/src/dispose/disposable-t.ts +0 -238
- package/src/dispose/disposable-utils.test.ts +0 -15
- package/src/dispose/disposable-utils.ts +0 -28
- package/src/dispose/dispose-base.ts +0 -9
- package/src/dispose/index.ts +0 -34
- package/src/dispose/logger.test.ts +0 -65
- package/src/dispose/logger.ts +0 -39
- package/src/dispose/timer.test.ts +0 -30
- package/src/dispose/timer.ts +0 -16
- package/src/dispose/tracker.test.ts +0 -51
- package/src/dispose/tracker.ts +0 -105
- package/src/error/error-base.ts +0 -45
- package/src/error/error-code.ts +0 -39
- package/src/error/error-const.test.ts +0 -30
- package/src/error/error-const.ts +0 -16
- package/src/error/error-or.test.ts +0 -44
- package/src/error/error-or.ts +0 -2
- package/src/error/error-t.test.ts +0 -116
- package/src/error/error-t.ts +0 -100
- package/src/error/index.ts +0 -24
- package/src/error/node_modules/.vitest/results.json +0 -1
- package/src/event/disposable-linked-list.ts +0 -29
- package/src/event/emitter.test.ts +0 -191
- package/src/event/emitter.ts +0 -162
- package/src/event/error-handler.ts +0 -22
- package/src/event/index.ts +0 -34
- package/src/event/once.ts +0 -29
- package/src/event/phase-emitter.test.ts +0 -212
- package/src/event/phase-emitter.ts +0 -209
- package/src/event/shortcut-event-utils.ts +0 -33
- package/src/event/utils.ts +0 -6
- package/src/event/when.ts +0 -40
- package/src/function/debounce.test.ts +0 -274
- package/src/function/debounce.ts +0 -168
- package/src/function/index.ts +0 -2
- package/src/function/node_modules/.vitest/results.json +0 -1
- package/src/function/throttle.test.ts +0 -179
- package/src/function/throttle.ts +0 -26
- package/src/hash/hash-t.test.ts +0 -100
- package/src/hash/hash-t.ts +0 -51
- package/src/hash/index.ts +0 -3
- package/src/json/index.ts +0 -1
- package/src/json/node_modules/.vitest/results.json +0 -1
- package/src/json/parse.ts +0 -19
- package/src/launch/abstract-job.ts +0 -45
- package/src/launch/cost-recorder.ts +0 -22
- package/src/launch/index.ts +0 -2
- package/src/launch/job-scheduler.test.ts +0 -122
- package/src/launch/job-scheduler.ts +0 -118
- package/src/launch/node_modules/.vitest/deps/_metadata.json +0 -8
- package/src/launch/node_modules/.vitest/deps/package.json +0 -3
- package/src/launch/node_modules/.vitest/results.json +0 -1
- package/src/lock/README.md +0 -11
- package/src/lock/capability.test.ts +0 -110
- package/src/lock/capability.ts +0 -89
- package/src/lock/index.ts +0 -15
- package/src/lock/node_modules/.vitest/results.json +0 -1
- package/src/lock/semaphore.ts +0 -21
- package/src/lock/shared-mutex.test.ts +0 -537
- package/src/lock/shared-mutex.ts +0 -242
- package/src/lock/utils.test.ts +0 -165
- package/src/lock/utils.ts +0 -135
- package/src/lodash-es/index.ts +0 -1
- package/src/math/degree.ts +0 -16
- package/src/math/index.ts +0 -7
- package/src/math/math.test.ts +0 -40
- package/src/math/math.ts +0 -64
- package/src/math/node_modules/.vitest/results.json +0 -1
- package/src/math/vector.test.ts +0 -73
- package/src/math/vector.ts +0 -114
- package/src/network/client.interface.ts +0 -104
- package/src/network/client.web.ts +0 -24
- package/src/network/index.common.ts +0 -10
- package/src/network/index.ts +0 -2
- package/src/network/plugins/retry.ts +0 -98
- package/src/objects/deep-clone.test.ts +0 -40
- package/src/objects/deep-clone.ts +0 -13
- package/src/objects/deep-equal.test.ts +0 -86
- package/src/objects/deep-equal.ts +0 -60
- package/src/objects/index.ts +0 -4
- package/src/platform/index.ts +0 -64
- package/src/promise/index.ts +0 -16
- package/src/promise/promise.test.ts +0 -254
- package/src/promise/promise.ts +0 -212
- package/src/scheduler/callback-token.ts +0 -31
- package/src/scheduler/core/actuator-args.test.ts +0 -47
- package/src/scheduler/core/actuator.test.ts +0 -82
- package/src/scheduler/core/actuator.ts +0 -58
- package/src/scheduler/core/chunk-scheduler.test.ts +0 -54
- package/src/scheduler/core/chunk-scheduler.ts +0 -28
- package/src/scheduler/core/node_modules/.vitest/results.json +0 -1
- package/src/scheduler/core/scheduler.test.ts +0 -328
- package/src/scheduler/core/scheduler.ts +0 -172
- package/src/scheduler/core/task-queue.test.ts +0 -78
- package/src/scheduler/core/task-queue.ts +0 -44
- package/src/scheduler/core/task.test.ts +0 -34
- package/src/scheduler/core/task.ts +0 -52
- package/src/scheduler/core/utils.ts +0 -48
- package/src/scheduler/executor/abstract-executor.test.ts +0 -44
- package/src/scheduler/executor/abstract-executor.ts +0 -38
- package/src/scheduler/executor/executor.interface.ts +0 -39
- package/src/scheduler/executor/idle-callback-executor.test.ts +0 -70
- package/src/scheduler/executor/idle-callback-executor.ts +0 -98
- package/src/scheduler/executor/make-executor.ts +0 -18
- package/src/scheduler/executor/post-message-executor.test.ts +0 -66
- package/src/scheduler/executor/post-message-executor.ts +0 -52
- package/src/scheduler/index.ts +0 -15
- package/src/scheduler/lv-scheduler-callback.ts +0 -19
- package/src/scheduler/lv-scheduler-config.ts +0 -17
- package/src/scheduler/type.ts +0 -48
- package/src/sprintf/index.ts +0 -2
- package/src/sprintf/sprintf.test.ts +0 -95
- package/src/sprintf/sprintf.ts +0 -97
- package/src/structure/graph.test.ts +0 -181
- package/src/structure/graph.ts +0 -105
- package/src/structure/index.ts +0 -8
- package/src/structure/linked-list.test.ts +0 -74
- package/src/structure/linked-list.ts +0 -145
- package/src/structure/min-heap.test.ts +0 -71
- package/src/structure/min-heap.ts +0 -91
- package/src/type/REAME.md +0 -2
- package/src/type/distributive-omit.interface.ts +0 -4
- package/src/type/index.ts +0 -3
- package/src/type/object-key-paths.interface.ts +0 -40
- package/src/undo-redo-stack/README.md +0 -61
- package/src/undo-redo-stack/action-stack.test.ts +0 -330
- package/src/undo-redo-stack/action-stack.ts +0 -150
- package/src/undo-redo-stack/element.ts +0 -4
- package/src/undo-redo-stack/index.ts +0 -7
- package/src/undo-redo-stack/state-stack.test.ts +0 -118
- package/src/undo-redo-stack/state-stack.ts +0 -133
- package/src/uuid/index.ts +0 -7
- package/src/uuid/uuid.ts +0 -86
- package/src/worker/cors-worker.ts +0 -38
- package/src/worker/index.ts +0 -4
- package/src/worker/node_modules/.vitest/results.json +0 -1
- package/src/worker/promise-worker-main-thread.test.ts +0 -91
- package/src/worker/promise-worker-main-thread.ts +0 -76
- package/src/worker/promise-worker-worker-thread.ts +0 -64
- package/src/worker/promise-worker.interface.ts +0 -15
|
@@ -1,468 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
2
|
-
import { IdleValue } from './idle-value';
|
|
3
|
-
import type { SyncDescriptor0 } from './descriptor';
|
|
4
|
-
import { SyncDescriptor } from './descriptor';
|
|
5
|
-
import { Graph } from '../structure/graph';
|
|
6
|
-
import { ServiceCollection } from './service-collection';
|
|
7
|
-
import { makeProxy } from './proxy-builder';
|
|
8
|
-
import type { ServiceIdentifier, ServicesAccessor } from './base';
|
|
9
|
-
import { getServiceDependencies } from './base';
|
|
10
|
-
import type { GetLeadingNonServiceArgs } from './instantiation-service.interface';
|
|
11
|
-
import { IInstantiationService } from './instantiation-service.interface';
|
|
12
|
-
import { Trace } from './trace';
|
|
13
|
-
import { Emitter, type Event } from '../event';
|
|
14
|
-
import { Logger } from '@/_internal/logger';
|
|
15
|
-
import { isDisposable, SET_PARENT_OF_DISPOSABLE } from '@/dispose';
|
|
16
|
-
import { ServiceOwnership } from './service-ownership-collection';
|
|
17
|
-
|
|
18
|
-
// 依赖图
|
|
19
|
-
type DepGraph = Graph<string, any>;
|
|
20
|
-
|
|
21
|
-
// TRACING
|
|
22
|
-
const _enableAllTracing = false;
|
|
23
|
-
// || "TRUE" // DO NOT CHECK IN!
|
|
24
|
-
class CyclicDependencyError extends Error {
|
|
25
|
-
constructor(graph: DepGraph) {
|
|
26
|
-
super('cyclic dependency between services');
|
|
27
|
-
this.message = graph.findCycleSlow() ?? `UNABLE to detect cycle, dumping graph: \n${graph.toString()}`;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export enum InstantiationErrorType {
|
|
32
|
-
UnknownDependency = 'UnknownDependency',
|
|
33
|
-
}
|
|
34
|
-
interface IBaseErrorEvent {
|
|
35
|
-
errorType: InstantiationErrorType;
|
|
36
|
-
message: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface IUnknownDependencyErrorEvent extends IBaseErrorEvent {
|
|
40
|
-
errorType: InstantiationErrorType.UnknownDependency;
|
|
41
|
-
dependencyId: string;
|
|
42
|
-
issuer: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
type ErrorDataType = IUnknownDependencyErrorEvent;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* 从容器中获取对应的service
|
|
49
|
-
* @param instantiationService
|
|
50
|
-
* @param id
|
|
51
|
-
* @returns Service<T>
|
|
52
|
-
*
|
|
53
|
-
* @remarks 减少使用该方法,尽量将业务函数作为invokeFunction的参数,从accessor中获取你所期望的service
|
|
54
|
-
*/
|
|
55
|
-
export function getService<T>(instantiationService: IInstantiationService, id: ServiceIdentifier<T>) {
|
|
56
|
-
return instantiationService.invokeFunction((accessor) => {
|
|
57
|
-
return accessor.get(id);
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export class InstantiationService implements IInstantiationService {
|
|
62
|
-
readonly _serviceBrand: undefined;
|
|
63
|
-
// 全局依赖图,开启tracing才会生成,整个instantiationSerive父子链上只会有一个globalGraph
|
|
64
|
-
readonly _globalGraph?: DepGraph;
|
|
65
|
-
// 该instantiationService所包含的服务集合
|
|
66
|
-
private readonly _services: ServiceCollection;
|
|
67
|
-
// 父instantiationService
|
|
68
|
-
private readonly _parent?: InstantiationService;
|
|
69
|
-
private readonly _childs = new Set<IInstantiationService>();
|
|
70
|
-
// 是否开启tracing
|
|
71
|
-
private readonly _enableTracing: boolean;
|
|
72
|
-
// 隐式依赖
|
|
73
|
-
private _globalGraphImplicitDependency?: string;
|
|
74
|
-
// 记录当前正在创建的服务,防止循环依赖
|
|
75
|
-
private readonly _activeInstantiations = new Set<ServiceIdentifier<any>>();
|
|
76
|
-
|
|
77
|
-
private _emitter: Emitter<[ErrorDataType]> | null = null;
|
|
78
|
-
|
|
79
|
-
constructor(
|
|
80
|
-
services: ServiceCollection = new ServiceCollection(),
|
|
81
|
-
parent?: InstantiationService,
|
|
82
|
-
enableTracing: boolean = _enableAllTracing,
|
|
83
|
-
) {
|
|
84
|
-
this._services = services;
|
|
85
|
-
this._services.set(IInstantiationService, this);
|
|
86
|
-
|
|
87
|
-
this._parent = parent;
|
|
88
|
-
if (this._parent) {
|
|
89
|
-
// 建立父子关系
|
|
90
|
-
this._parent._childs.add(this);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
this._enableTracing = enableTracing;
|
|
94
|
-
if (enableTracing) {
|
|
95
|
-
this._globalGraph = parent?._globalGraph ?? new Graph((e) => e);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
get services(): ServiceCollection {
|
|
100
|
-
return this._services;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// 仅限 Flow 调用
|
|
104
|
-
get onError(): Event<[ErrorDataType]> {
|
|
105
|
-
if (!this._emitter) {
|
|
106
|
-
this._emitter = new Emitter<[ErrorDataType]>();
|
|
107
|
-
}
|
|
108
|
-
return this._emitter.event;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// 创建子instantiationService
|
|
112
|
-
createChild(services: ServiceCollection): IInstantiationService {
|
|
113
|
-
return new InstantiationService(services, this, this._enableTracing);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// 提供通过instantiationService直接获取到内部服务的能力
|
|
117
|
-
// 返回servicesAccessor这一视图类,并不暴露instantiationService内部接口
|
|
118
|
-
invokeFunction<R, TS extends any[] = []>(
|
|
119
|
-
fn: (accessor: ServicesAccessor, ...args: TS) => R,
|
|
120
|
-
...args: TS
|
|
121
|
-
): R {
|
|
122
|
-
const _trace = Trace.traceInvocation(this._enableTracing, fn);
|
|
123
|
-
let _done = false;
|
|
124
|
-
try {
|
|
125
|
-
const accessor: ServicesAccessor = {
|
|
126
|
-
get: <T>(id: ServiceIdentifier<T>) => {
|
|
127
|
-
if (_done) {
|
|
128
|
-
throw new Error('service accessor is only valid during the invocation of its target method');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const result = this._getOrCreateServiceInstance(id, _trace);
|
|
132
|
-
if (!result) {
|
|
133
|
-
this._handleError({
|
|
134
|
-
errorType: InstantiationErrorType.UnknownDependency,
|
|
135
|
-
issuer: 'service-accessor',
|
|
136
|
-
dependencyId: `${id}`,
|
|
137
|
-
message: `[invokeFunction] unknown service '${id}'`,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
return result;
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
return fn(accessor, ...args);
|
|
144
|
-
} finally {
|
|
145
|
-
_done = true;
|
|
146
|
-
_trace.stop();
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// 通过描述符创建一个实例
|
|
151
|
-
createInstance<T>(descriptor: SyncDescriptor0<T>): T;
|
|
152
|
-
// 通过构造函数直接创建一个实例
|
|
153
|
-
createInstance<Ctor extends new (...args: any[]) => any, R extends InstanceType<Ctor>>(
|
|
154
|
-
ctor: Ctor,
|
|
155
|
-
...args: GetLeadingNonServiceArgs<ConstructorParameters<Ctor>>
|
|
156
|
-
): R;
|
|
157
|
-
createInstance<T, Ctor extends new (...args: any[]) => any, R extends InstanceType<Ctor>>(
|
|
158
|
-
descriptor: SyncDescriptor<T>,
|
|
159
|
-
...args: GetLeadingNonServiceArgs<ConstructorParameters<Ctor>>
|
|
160
|
-
): R;
|
|
161
|
-
createInstance(ctorOrDescriptor: any | SyncDescriptor<any>, ...rest: any[]): any {
|
|
162
|
-
let _trace: Trace, result: any;
|
|
163
|
-
if (ctorOrDescriptor instanceof SyncDescriptor) {
|
|
164
|
-
_trace = Trace.traceCreation(this._enableTracing, ctorOrDescriptor.ctor);
|
|
165
|
-
result = this._createInstance(
|
|
166
|
-
ctorOrDescriptor.ctor,
|
|
167
|
-
ctorOrDescriptor.staticArguments.concat(rest),
|
|
168
|
-
_trace,
|
|
169
|
-
);
|
|
170
|
-
} else {
|
|
171
|
-
_trace = Trace.traceCreation(this._enableTracing, ctorOrDescriptor);
|
|
172
|
-
result = this._createInstance(ctorOrDescriptor, rest, _trace);
|
|
173
|
-
}
|
|
174
|
-
_trace.stop();
|
|
175
|
-
return result;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
dispose() {
|
|
179
|
-
// 子容器进行dispose
|
|
180
|
-
for (const child of this._childs) {
|
|
181
|
-
child.dispose();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// 断开父容器
|
|
185
|
-
this._parent?._childs.delete(this);
|
|
186
|
-
|
|
187
|
-
// 内部服务进行清理
|
|
188
|
-
for (const [identifier, instanceOrDescriptor] of this._services.entries) {
|
|
189
|
-
if (instanceOrDescriptor instanceof SyncDescriptor) {
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
if (instanceOrDescriptor === this) {
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
if (instanceOrDescriptor.__origin__ === this) {
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
if (isDisposable(instanceOrDescriptor)) {
|
|
199
|
-
const ownerShip = this._services.ownerships?.get(identifier);
|
|
200
|
-
|
|
201
|
-
// eslint-disable-next-line max-depth
|
|
202
|
-
switch (ownerShip) {
|
|
203
|
-
case ServiceOwnership.Reference:
|
|
204
|
-
// skip dispose..
|
|
205
|
-
break;
|
|
206
|
-
case ServiceOwnership.Owned:
|
|
207
|
-
default:
|
|
208
|
-
instanceOrDescriptor.dispose();
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// 创建实例
|
|
216
|
-
private _createInstance<T>(ctor: any, args: any[] = [], _trace: Trace): T {
|
|
217
|
-
// 获取服务构造中的依赖情况,按参数顺序排列
|
|
218
|
-
const serviceDependencies = getServiceDependencies(ctor).sort((a, b) => a.index - b.index);
|
|
219
|
-
const serviceArgs: any[] = [];
|
|
220
|
-
// 先构造依赖的服务
|
|
221
|
-
for (const dependency of serviceDependencies) {
|
|
222
|
-
const service = this._getOrCreateServiceInstance(dependency.id, _trace);
|
|
223
|
-
if (!service) {
|
|
224
|
-
this._handleError({
|
|
225
|
-
errorType: InstantiationErrorType.UnknownDependency,
|
|
226
|
-
issuer: `create-instance-${ctor.name}`,
|
|
227
|
-
dependencyId: `${dependency.id}`,
|
|
228
|
-
message: `[createInstance] ${ctor.name} depends on UNKNOWN service ${dependency.id}.`,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
serviceArgs.push(service);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// 找到第一个服务的参数
|
|
235
|
-
const firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : args.length;
|
|
236
|
-
|
|
237
|
-
// 如果参数不匹配,调整静态参数位置
|
|
238
|
-
if (args.length !== firstServiceArgPos) {
|
|
239
|
-
Logger.trace(
|
|
240
|
-
`[createInstance] First service dependency of ${ctor.name} at position ${
|
|
241
|
-
firstServiceArgPos + 1
|
|
242
|
-
} conflicts with ${args.length} static arguments`,
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
const delta = firstServiceArgPos - args.length;
|
|
246
|
-
if (delta > 0) {
|
|
247
|
-
args = args.concat(new Array(delta));
|
|
248
|
-
} else {
|
|
249
|
-
args = args.slice(0, firstServiceArgPos);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// 通过createInstance明确指定的服务一定是立刻创建
|
|
254
|
-
return Reflect.construct<any, T>(ctor, args.concat(serviceArgs));
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// 保存服务实例
|
|
258
|
-
private _setServiceInstance<T>(id: ServiceIdentifier<T>, instance: T): void {
|
|
259
|
-
if (this._services.get(id) instanceof SyncDescriptor) {
|
|
260
|
-
this._services.set(id, instance);
|
|
261
|
-
} else if (this._parent) {
|
|
262
|
-
this._parent._setServiceInstance(id, instance);
|
|
263
|
-
} else {
|
|
264
|
-
throw new Error('illegalState - setting UNKNOWN service instance');
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// 获取服务实例或者描述符
|
|
269
|
-
private _getServiceInstanceOrDescriptor<T>(id: ServiceIdentifier<T>): T | SyncDescriptor<T> {
|
|
270
|
-
const instanceOrDesc = this._services.get(id);
|
|
271
|
-
if (!instanceOrDesc && this._parent) {
|
|
272
|
-
return this._parent._getServiceInstanceOrDescriptor(id);
|
|
273
|
-
} else {
|
|
274
|
-
return instanceOrDesc;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// 获取服务实例,没有的话就创建
|
|
279
|
-
private _getOrCreateServiceInstance<T>(id: ServiceIdentifier<T>, _trace: Trace): T {
|
|
280
|
-
if (this._globalGraph && this._globalGraphImplicitDependency) {
|
|
281
|
-
this._globalGraph.insertEdge(this._globalGraphImplicitDependency, String(id));
|
|
282
|
-
}
|
|
283
|
-
const thing = this._getServiceInstanceOrDescriptor(id);
|
|
284
|
-
if (thing instanceof SyncDescriptor) {
|
|
285
|
-
return this._safeCreateAndCacheServiceInstance(id, thing, _trace.branch(id, true));
|
|
286
|
-
} else {
|
|
287
|
-
_trace.branch(id, false);
|
|
288
|
-
return thing;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// 安全的创建并且记录在缓存中
|
|
293
|
-
private _safeCreateAndCacheServiceInstance<T>(
|
|
294
|
-
id: ServiceIdentifier<T>,
|
|
295
|
-
desc: SyncDescriptor<T>,
|
|
296
|
-
_trace: Trace,
|
|
297
|
-
): T {
|
|
298
|
-
if (this._activeInstantiations.has(id)) {
|
|
299
|
-
throw new Error(`illegal state - RECURSIVELY instantiating service '${id}'`);
|
|
300
|
-
}
|
|
301
|
-
this._activeInstantiations.add(id);
|
|
302
|
-
try {
|
|
303
|
-
return this._createAndCacheServiceInstance(id, desc, _trace);
|
|
304
|
-
} finally {
|
|
305
|
-
this._activeInstantiations.delete(id);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// 非安全创建并记录在缓存中
|
|
310
|
-
// 核心方法,服务创建的最基础流程
|
|
311
|
-
private _createAndCacheServiceInstance<T>(
|
|
312
|
-
id: ServiceIdentifier<T>,
|
|
313
|
-
desc: SyncDescriptor<T>,
|
|
314
|
-
_trace: Trace,
|
|
315
|
-
): T {
|
|
316
|
-
type Triple = {
|
|
317
|
-
id: ServiceIdentifier<any>;
|
|
318
|
-
desc: SyncDescriptor<any>;
|
|
319
|
-
_trace: Trace;
|
|
320
|
-
};
|
|
321
|
-
// 记录一个临时依赖图
|
|
322
|
-
const graph = new Graph<string, Triple>((data) => data.id.toString());
|
|
323
|
-
|
|
324
|
-
let cycleCount = 0;
|
|
325
|
-
// dfs
|
|
326
|
-
const stack = [{ id, desc, _trace }];
|
|
327
|
-
while (stack.length) {
|
|
328
|
-
const item = stack.pop()!;
|
|
329
|
-
graph.lookupOrInsertNode(item);
|
|
330
|
-
|
|
331
|
-
// a weak but working heuristic for cycle checks
|
|
332
|
-
if (cycleCount++ > 1000) {
|
|
333
|
-
throw new CyclicDependencyError(graph);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// 检查所有依赖项,并添加记录
|
|
337
|
-
// check all dependencies for existence and if they need to be created first
|
|
338
|
-
for (const dependency of getServiceDependencies(item.desc.ctor)) {
|
|
339
|
-
const instanceOrDesc = this._getServiceInstanceOrDescriptor(dependency.id);
|
|
340
|
-
if (!instanceOrDesc) {
|
|
341
|
-
this._handleError({
|
|
342
|
-
errorType: InstantiationErrorType.UnknownDependency,
|
|
343
|
-
issuer: `create-service-${id}`,
|
|
344
|
-
dependencyId: `${dependency.id}`,
|
|
345
|
-
message: `[createInstance] ${id} depends on ${dependency.id} which is NOT registered.`,
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// 全局的依赖图中需要添加
|
|
350
|
-
this._globalGraph?.insertEdge(String(item.id), String(dependency.id));
|
|
351
|
-
|
|
352
|
-
if (instanceOrDesc instanceof SyncDescriptor) {
|
|
353
|
-
const d = {
|
|
354
|
-
id: dependency.id,
|
|
355
|
-
desc: instanceOrDesc,
|
|
356
|
-
_trace: item._trace.branch(dependency.id, true),
|
|
357
|
-
};
|
|
358
|
-
// 当依赖没有初始化为实例,仍然是描述符式,添加到临时依赖图
|
|
359
|
-
graph.insertEdge(item, d);
|
|
360
|
-
stack.push(d);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// 将临时依赖图(只有描述符)初始化成服务实例
|
|
366
|
-
while (true) {
|
|
367
|
-
// 找到图的根节点集合
|
|
368
|
-
const leafs = graph.leafs();
|
|
369
|
-
|
|
370
|
-
// 临时依赖图中含有节点,但是没有叶子节点,意味着有循环依赖
|
|
371
|
-
if (leafs.length === 0) {
|
|
372
|
-
if (!graph.isEmpty()) {
|
|
373
|
-
throw new CyclicDependencyError(graph);
|
|
374
|
-
}
|
|
375
|
-
break;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// 迭代子节点
|
|
379
|
-
for (const { data } of leafs) {
|
|
380
|
-
const instanceOrDesc = this._getServiceInstanceOrDescriptor(data.id);
|
|
381
|
-
// 一定要重复检查,因为data可能会有重复的(某个服务被多个服务依赖)
|
|
382
|
-
if (instanceOrDesc instanceof SyncDescriptor) {
|
|
383
|
-
const instance = this._createServiceInstanceWithOwner(
|
|
384
|
-
data.id,
|
|
385
|
-
data.desc.ctor,
|
|
386
|
-
data.desc.staticArguments,
|
|
387
|
-
data.desc.supportsDelayedInstantiation,
|
|
388
|
-
data._trace,
|
|
389
|
-
);
|
|
390
|
-
this._setServiceInstance(data.id, instance);
|
|
391
|
-
}
|
|
392
|
-
graph.removeNode(data);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
// 一定返回的是实例
|
|
396
|
-
return this._getServiceInstanceOrDescriptor(id) as T;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// 创建服务实例(会判断在哪层instantiation中判断)
|
|
400
|
-
private _createServiceInstanceWithOwner<T>(
|
|
401
|
-
id: ServiceIdentifier<T>,
|
|
402
|
-
ctor: any,
|
|
403
|
-
args: any[] = [],
|
|
404
|
-
supportsDelayedInstantiation: boolean,
|
|
405
|
-
_trace: Trace,
|
|
406
|
-
): T {
|
|
407
|
-
// 如果注册在本层,就在本层创建
|
|
408
|
-
if (this._services.get(id) instanceof SyncDescriptor) {
|
|
409
|
-
return this._createServiceInstance(id, ctor, args, supportsDelayedInstantiation, _trace);
|
|
410
|
-
} else if (this._parent) {
|
|
411
|
-
// 本层没有尝试去上层找
|
|
412
|
-
return this._parent._createServiceInstanceWithOwner(
|
|
413
|
-
id,
|
|
414
|
-
ctor,
|
|
415
|
-
args,
|
|
416
|
-
supportsDelayedInstantiation,
|
|
417
|
-
_trace,
|
|
418
|
-
);
|
|
419
|
-
} else {
|
|
420
|
-
throw new Error(`illegalState - creating UNKNOWN service instance ${ctor.name}`);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// 准备创建服务实例
|
|
425
|
-
private _createServiceInstance<T>(
|
|
426
|
-
id: ServiceIdentifier<T>,
|
|
427
|
-
ctor: any,
|
|
428
|
-
args: any[] = [],
|
|
429
|
-
supportsDelayedInstantiation: boolean,
|
|
430
|
-
_trace: Trace,
|
|
431
|
-
): T {
|
|
432
|
-
// 如果不支持延迟初始化,走同步逻辑
|
|
433
|
-
if (!supportsDelayedInstantiation) {
|
|
434
|
-
return this._createService(ctor, args, _trace);
|
|
435
|
-
}
|
|
436
|
-
// 使用IdleValue容器包装真正的对象,按需要进行初始化
|
|
437
|
-
const idle = new IdleValue<T>(() => this._createService<T>(ctor, args, _trace));
|
|
438
|
-
// 实现了一个proxy
|
|
439
|
-
// 当真正需要的时候,才会去构造
|
|
440
|
-
return makeProxy(idle, ctor);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// 创建服务
|
|
444
|
-
private _createService<T>(ctor: any, args: any[] = [], _trace: Trace): T {
|
|
445
|
-
// 通过createInstance明确指定的服务一定是立刻创建
|
|
446
|
-
const service = this._createInstance<T>(ctor, args, _trace);
|
|
447
|
-
if (isDisposable(service)) {
|
|
448
|
-
SET_PARENT_OF_DISPOSABLE(service, this);
|
|
449
|
-
}
|
|
450
|
-
return service;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// 处理错误
|
|
454
|
-
private _handleError(errorData: ErrorDataType) {
|
|
455
|
-
// 错误统一上报到顶层容器
|
|
456
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
457
|
-
let topInstantiationService: InstantiationService = this;
|
|
458
|
-
while (topInstantiationService._parent) {
|
|
459
|
-
topInstantiationService = topInstantiationService._parent;
|
|
460
|
-
}
|
|
461
|
-
// 触发顶层容器的错误监听
|
|
462
|
-
if (topInstantiationService._emitter) {
|
|
463
|
-
topInstantiationService._emitter.fire(errorData);
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
throw new Error(errorData.message);
|
|
467
|
-
}
|
|
468
|
-
}
|
package/src/di/lazy/foo.mock.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { IDisposable } from '@/dispose';
|
|
2
|
-
|
|
3
|
-
// mock的文件,请勿直接引用
|
|
4
|
-
|
|
5
|
-
export interface IFoo {
|
|
6
|
-
readonly _serviceBrand: undefined;
|
|
7
|
-
|
|
8
|
-
disposed: boolean;
|
|
9
|
-
echo: () => void;
|
|
10
|
-
dispose: () => void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class Foo implements IDisposable {
|
|
14
|
-
readonly _serviceBrand: undefined;
|
|
15
|
-
private _disposed = false;
|
|
16
|
-
|
|
17
|
-
get disposed() {
|
|
18
|
-
return this._disposed;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
echo() {
|
|
22
|
-
return 'Hello Lvweb';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
dispose() {
|
|
26
|
-
this._disposed = true;
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/di/lazy/idle-load.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { IInstantiationService } from '../instantiation-service.interface';
|
|
2
|
-
import { lvSchedulerCallback } from '@/scheduler';
|
|
3
|
-
import { type ILazyServiceLoader, LazyServiceLoader } from './lazy-service';
|
|
4
|
-
import { SyncDescriptor } from '../descriptor';
|
|
5
|
-
import type { BrandedService } from '../base';
|
|
6
|
-
|
|
7
|
-
class IdleServiceLoader<T extends BrandedService> implements ILazyServiceLoader<T> {
|
|
8
|
-
public readonly _serviceBrand: undefined;
|
|
9
|
-
|
|
10
|
-
protected _service: ILazyServiceLoader<T>;
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
originService: new (...args: any[]) => LazyServiceLoader<T>,
|
|
14
|
-
staticArguments: any[],
|
|
15
|
-
@IInstantiationService protected readonly _instantiationService: IInstantiationService,
|
|
16
|
-
) {
|
|
17
|
-
this._service = this._instantiationService.createInstance(originService, ...staticArguments);
|
|
18
|
-
lvSchedulerCallback(() => this._service.preload());
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
get loaded() {
|
|
22
|
-
return this._service.loaded;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
getInstance() {
|
|
26
|
-
return this._service.getInstance();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
preload() {
|
|
30
|
-
this._service.preload();
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function makeLazyServiceIdleLoad<T extends BrandedService>(
|
|
35
|
-
ctor: new (..._args: any[]) => ILazyServiceLoader<T>,
|
|
36
|
-
staticArguments: any[] = [],
|
|
37
|
-
): SyncDescriptor<ILazyServiceLoader<T>> {
|
|
38
|
-
return new SyncDescriptor<ILazyServiceLoader<T>>(IdleServiceLoader, [ctor, staticArguments]);
|
|
39
|
-
}
|
package/src/di/lazy/index.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import type { IDisposable } from '@/dispose';
|
|
2
|
-
import { CancellationTokenSource } from '@/async';
|
|
3
|
-
import { InstantiationService } from '../instantiation-service';
|
|
4
|
-
import type { IFoo } from './foo.mock';
|
|
5
|
-
import { LazyServiceLoader } from './lazy-service';
|
|
6
|
-
|
|
7
|
-
class LazyFoo extends LazyServiceLoader<IFoo> {
|
|
8
|
-
protected async _getModule() {
|
|
9
|
-
return (await import(/* webpackChunkName: "foo_mock" */ './foo.mock')).Foo;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
class LazyFooWithDisposable extends LazyServiceLoader<IFoo> implements IDisposable {
|
|
14
|
-
private readonly _cancellationTokenSource = new CancellationTokenSource();
|
|
15
|
-
protected async _getModule() {
|
|
16
|
-
return (await import(/* webpackChunkName: "foo_mock" */ './foo.mock')).Foo;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async getInstance() {
|
|
20
|
-
const instance = await super.getInstance();
|
|
21
|
-
if (this._cancellationTokenSource.token.isCancellationRequested) {
|
|
22
|
-
instance.dispose();
|
|
23
|
-
}
|
|
24
|
-
return instance;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
dispose() {
|
|
28
|
-
if (this._instance) {
|
|
29
|
-
this._instance.dispose();
|
|
30
|
-
}
|
|
31
|
-
this._cancellationTokenSource.dispose(true);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
describe('lazyService', () => {
|
|
36
|
-
it('load lazyService', async () => {
|
|
37
|
-
const instantiationService = new InstantiationService();
|
|
38
|
-
const lazyFoo = new LazyFoo(instantiationService);
|
|
39
|
-
const foo = await lazyFoo.getInstance();
|
|
40
|
-
expect(foo.echo()).toBe('Hello Lvweb');
|
|
41
|
-
expect(foo.disposed).toBeFalsy();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// 获取instance之前就dipose了
|
|
45
|
-
it('lazyService dispose1', async () => {
|
|
46
|
-
const instantiationService = new InstantiationService();
|
|
47
|
-
const lazyFoo = new LazyFooWithDisposable(instantiationService);
|
|
48
|
-
lazyFoo.dispose();
|
|
49
|
-
const foo = await lazyFoo.getInstance();
|
|
50
|
-
expect(foo.echo()).toBe('Hello Lvweb');
|
|
51
|
-
// 获取到的对象,是disposed的
|
|
52
|
-
expect(foo.disposed).toBeTruthy();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('lazyService dispose2', async () => {
|
|
56
|
-
const instantiationService = new InstantiationService();
|
|
57
|
-
const lazyFoo = new LazyFooWithDisposable(instantiationService);
|
|
58
|
-
const foo = await lazyFoo.getInstance();
|
|
59
|
-
expect(foo.echo()).toBe('Hello Lvweb');
|
|
60
|
-
expect(foo.disposed).toBeFalsy();
|
|
61
|
-
lazyFoo.dispose();
|
|
62
|
-
// 后续dispose,foo被dispose
|
|
63
|
-
expect(foo.disposed).toBeTruthy();
|
|
64
|
-
});
|
|
65
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { SharedMutex } from '@/lock';
|
|
2
|
-
import type { BrandedService } from '../base';
|
|
3
|
-
import { IInstantiationService } from '../instantiation-service.interface';
|
|
4
|
-
|
|
5
|
-
export interface ILazyServiceLoader<T> {
|
|
6
|
-
readonly _serviceBrand: undefined;
|
|
7
|
-
|
|
8
|
-
getInstance: (...rest: any[]) => Promise<T>;
|
|
9
|
-
loaded: boolean;
|
|
10
|
-
preload: () => void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type ILoaderResult<T> = {
|
|
14
|
-
default: new (...args: any[]) => T;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type ILoaderResult0<T> = new (...args: any[]) => T;
|
|
18
|
-
|
|
19
|
-
export abstract class LazyServiceLoader<T extends BrandedService> implements ILazyServiceLoader<T> {
|
|
20
|
-
readonly _serviceBrand: undefined;
|
|
21
|
-
|
|
22
|
-
// 真实的service
|
|
23
|
-
protected _instance?: T;
|
|
24
|
-
|
|
25
|
-
private readonly _sharedMutex: SharedMutex = new SharedMutex();
|
|
26
|
-
|
|
27
|
-
constructor(@IInstantiationService protected readonly _instantiationService: IInstantiationService) {}
|
|
28
|
-
|
|
29
|
-
public get loaded() {
|
|
30
|
-
return Boolean(this._instance);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public preload() {
|
|
34
|
-
this._getModule();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// 创建模块实例
|
|
38
|
-
public async getInstance(): Promise<T> {
|
|
39
|
-
// 必须上写锁
|
|
40
|
-
// 本质上该函数是 getOrCreateInstance,包含了写行为
|
|
41
|
-
await this._sharedMutex.lock();
|
|
42
|
-
try {
|
|
43
|
-
if (this._instance) {
|
|
44
|
-
return this._instance;
|
|
45
|
-
}
|
|
46
|
-
this._instance = await this._makeInstance(...this._getStaticArguments());
|
|
47
|
-
return this._instance!;
|
|
48
|
-
} finally {
|
|
49
|
-
this._sharedMutex.unLock();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// 加载module,获取实例
|
|
54
|
-
protected async _makeInstance(...rest: any[]): Promise<T> {
|
|
55
|
-
const module = await this._getModule();
|
|
56
|
-
if ((module as ILoaderResult<T>).default) {
|
|
57
|
-
return this._instantiationService.createInstance((module as ILoaderResult<T>).default, ...rest);
|
|
58
|
-
} else {
|
|
59
|
-
return this._instantiationService.createInstance(module as ILoaderResult0<T>, ...rest);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 获取模块的纯虚函数
|
|
64
|
-
// 派生类必须复写
|
|
65
|
-
protected abstract _getModule(): Promise<ILoaderResult<T> | ILoaderResult0<T>>;
|
|
66
|
-
|
|
67
|
-
// 获取模块的静态参数,子类可以复写
|
|
68
|
-
protected _getStaticArguments(): any[] {
|
|
69
|
-
return [];
|
|
70
|
-
}
|
|
71
|
-
}
|
package/src/di/lazy/type.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":"1.0.1","results":[[":service-ownership-collection.test.ts",{"duration":0,"failed":false}],[":service-collection.test.ts",{"duration":0,"failed":false}],[":service-registry.test.ts",{"duration":0,"failed":false}],[":proxy-builder.test.ts",{"duration":0,"failed":false}],[":instantiation-service.test.ts",{"duration":2,"failed":false}],[":idle-value.test.ts",{"duration":0,"failed":false}],[":lazy/lazy-service.test.ts",{"duration":0,"failed":false}]]}
|