@pravosleva/reactive-engine 2.6.4-alpha.9 → 2.7.0-beta.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/README.md +8 -8
- package/dist/core/core.d.ts +161 -0
- package/dist/core/core.d.ts.map +1 -1
- package/dist/core/core.effect.test.d.ts +2 -0
- package/dist/core/core.effect.test.d.ts.map +1 -0
- package/dist/core/core.method.computed.d.ts.map +1 -1
- package/dist/core/core.method.effect.d.ts.map +1 -1
- package/dist/core/core.method.signal.d.ts.map +1 -1
- package/dist/core.method.computed.mjs +3 -2
- package/dist/core.method.computed.mjs.map +1 -1
- package/dist/core.method.effect.mjs +65 -45
- package/dist/core.method.effect.mjs.map +1 -1
- package/dist/core.method.resource.mjs +3 -1
- package/dist/core.method.resource.mjs.map +1 -1
- package/dist/core.method.signal.mjs +4 -2
- package/dist/core.method.signal.mjs.map +1 -1
- package/dist/core.mjs +1 -0
- package/dist/core.mjs.map +1 -1
- package/dist/decorators/withValidation/withValidation.d.ts +2 -2
- package/dist/decorators/withValidation/withValidation.d.ts.map +1 -1
- package/dist/decorators/withValidation/withValidation.mjs +1 -1
- package/dist/decorators/withValidation/withValidation.mjs.map +1 -1
- package/dist/decorators/withValidation/withValidation.test.d.ts +2 -0
- package/dist/decorators/withValidation/withValidation.test.d.ts.map +1 -0
- package/dist/index.mjs +2 -2
- package/dist/reactive-engine.umd.js +2 -2
- package/dist/reactive-engine.umd.js.map +1 -1
- package/package.json +8 -11
- package/dist/AbstractService.cjs +0 -2
- package/dist/AbstractService.cjs.map +0 -1
- package/dist/BaseREServiceEnhanced.cjs +0 -2
- package/dist/BaseREServiceEnhanced.cjs.map +0 -1
- package/dist/angular/core.angular-adapter.cjs +0 -2
- package/dist/angular/core.angular-adapter.cjs.map +0 -1
- package/dist/angular/index.cjs +0 -2
- package/dist/angular/index.cjs.map +0 -1
- package/dist/core.autolog.cjs +0 -2
- package/dist/core.autolog.cjs.map +0 -1
- package/dist/core.automatic.cjs +0 -2
- package/dist/core.automatic.cjs.map +0 -1
- package/dist/core.cjs +0 -2
- package/dist/core.cjs.map +0 -1
- package/dist/core.global.cjs +0 -2
- package/dist/core.global.cjs.map +0 -1
- package/dist/core.logger.cjs +0 -2
- package/dist/core.logger.cjs.map +0 -1
- package/dist/core.method.computed.cjs +0 -2
- package/dist/core.method.computed.cjs.map +0 -1
- package/dist/core.method.effect.cjs +0 -2
- package/dist/core.method.effect.cjs.map +0 -1
- package/dist/core.method.reactive.cjs +0 -2
- package/dist/core.method.reactive.cjs.map +0 -1
- package/dist/core.method.resource.cjs +0 -2
- package/dist/core.method.resource.cjs.map +0 -1
- package/dist/core.method.signal.cjs +0 -2
- package/dist/core.method.signal.cjs.map +0 -1
- package/dist/core.method.untrack.cjs +0 -2
- package/dist/core.method.untrack.cjs.map +0 -1
- package/dist/decorators/withCache/withCache.cjs +0 -2
- package/dist/decorators/withCache/withCache.cjs.map +0 -1
- package/dist/decorators/withDebounce/withDebounce.cjs +0 -2
- package/dist/decorators/withDebounce/withDebounce.cjs.map +0 -1
- package/dist/decorators/withLongPolling/withLongPolling.cjs +0 -2
- package/dist/decorators/withLongPolling/withLongPolling.cjs.map +0 -1
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs +0 -2
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs.map +0 -1
- package/dist/decorators/withThrottle/withThrottle.cjs +0 -2
- package/dist/decorators/withThrottle/withThrottle.cjs.map +0 -1
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.cjs +0 -2
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.cjs.map +0 -1
- package/dist/decorators/withThrottleComputed/withThrottleComputed.cjs +0 -2
- package/dist/decorators/withThrottleComputed/withThrottleComputed.cjs.map +0 -1
- package/dist/decorators/withValidation/withValidation.cjs +0 -2
- package/dist/decorators/withValidation/withValidation.cjs.map +0 -1
- package/dist/index.cjs +0 -1
- package/dist/index2.cjs +0 -1
- package/dist/react/hooks/useReactiveSubscription.cjs +0 -2
- package/dist/react/hooks/useReactiveSubscription.cjs.map +0 -1
- package/dist/react/hooks/useReactiveValue.cjs +0 -2
- package/dist/react/hooks/useReactiveValue.cjs.map +0 -1
- package/dist/react/index.cjs +0 -2
- package/dist/react/index.cjs.map +0 -1
- package/dist/utils/getExtractedValues.cjs +0 -2
- package/dist/utils/getExtractedValues.cjs.map +0 -1
- package/dist/vue/core.vue-adapter.cjs +0 -2
- package/dist/vue/core.vue-adapter.cjs.map +0 -1
- package/dist/vue/index.cjs +0 -2
- package/dist/vue/index.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -213,7 +213,7 @@ Copying external async state directly into local mutable signals introduces sync
|
|
|
213
213
|
// ❌ Mirroring Trap (Causes redundant pushes & recursion)
|
|
214
214
|
engine.effect(() => {
|
|
215
215
|
const data = apiResource.data
|
|
216
|
-
if (data) localSignal.value = data
|
|
216
|
+
if (data) localSignal.value = data
|
|
217
217
|
})
|
|
218
218
|
|
|
219
219
|
// 🟢 Canonical Pattern (Pure Lazy Derivation)
|
|
@@ -229,7 +229,7 @@ To eliminate parent re-renders in deep form trees, push state subscriptions down
|
|
|
229
229
|
## Architecture-Grade Form Wizard (Example 254)
|
|
230
230
|
This enterprise-ready multi-step form implementation demonstrates absolute separation of concerns: state, cross-step validation schemas, and API fetch mechanics are completely decoupled from React.
|
|
231
231
|
|
|
232
|
-
1. Action Validation Decorators (`
|
|
232
|
+
1. Action Validation Decorators (`withValidationSync.ts`)
|
|
233
233
|
```ts
|
|
234
234
|
import { Signal } from '@pravosleva/reactive-engine'
|
|
235
235
|
|
|
@@ -242,7 +242,7 @@ export interface ValidationOptions<T> {
|
|
|
242
242
|
errorsSignal: Signal<Record<string, string>>
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
export const
|
|
245
|
+
export const withValidationSync = <T, Args extends any[], R>(
|
|
246
246
|
targetAction: (...args: Args) => R,
|
|
247
247
|
options: ValidationOptions<T>
|
|
248
248
|
) => {
|
|
@@ -269,7 +269,7 @@ export const withValidation = <T, Args extends any[], R>(
|
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
export const
|
|
272
|
+
export const withValidationAsync = <S, T>(
|
|
273
273
|
fetcher: (source: S, signal: AbortSignal) => Promise<T>,
|
|
274
274
|
options: ValidationOptions<S>
|
|
275
275
|
) => {
|
|
@@ -299,7 +299,7 @@ export const withResourceValidation = <S, T>(
|
|
|
299
299
|
2. Domain & Validation Service (`FormWizardLogic.ts`)
|
|
300
300
|
```tsx
|
|
301
301
|
import { AbstractService } from '@pravosleva/reactive-engine'
|
|
302
|
-
import {
|
|
302
|
+
import { withValidationSync, withValidationAsync, ValidationSchema } from './withValidation'
|
|
303
303
|
|
|
304
304
|
export interface WizardState {
|
|
305
305
|
step: number
|
|
@@ -345,15 +345,15 @@ export class FormWizardLogic extends AbstractService {
|
|
|
345
345
|
private profileSource = this.engine.computed(() => this.formData.profile)
|
|
346
346
|
|
|
347
347
|
public nextToProfileStep = () => {
|
|
348
|
-
const action =
|
|
348
|
+
const action = withValidationSync(() => {
|
|
349
349
|
this.currentStep.value = 2
|
|
350
350
|
}, { schema: this.accountSchema, errorsSignal: this.errors })
|
|
351
|
-
|
|
351
|
+
|
|
352
352
|
action(this.formData.account)
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
public submitWizardForm = this.engine.resource(
|
|
356
|
-
|
|
356
|
+
withValidationAsync(
|
|
357
357
|
async (profileData, abortSignal) => {
|
|
358
358
|
return this.api.submitWizard(profileData)
|
|
359
359
|
},
|
package/dist/core/core.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export declare class ReactiveEngineCore {
|
|
|
26
26
|
private cycleDetectionStack;
|
|
27
27
|
batchedSignals: Set<any>;
|
|
28
28
|
activeOwner: any;
|
|
29
|
+
activeCleanupNode: any;
|
|
29
30
|
pendingCleanups: Set<() => void>;
|
|
30
31
|
queueCleanup(cleanup: () => void): void;
|
|
31
32
|
constructor(options?: {
|
|
@@ -40,7 +41,111 @@ export declare class ReactiveEngineCore {
|
|
|
40
41
|
batch<T>(fn: () => T): T;
|
|
41
42
|
flushEffects(): void;
|
|
42
43
|
log(params: any): void;
|
|
44
|
+
/**
|
|
45
|
+
* Создает новый реактивный сигнал с заданным начальным значением и опциями.
|
|
46
|
+
*
|
|
47
|
+
* @template T Тип значения сигнала.
|
|
48
|
+
* @param initialValue Начальное значение сигнала.
|
|
49
|
+
* @param optionsOrName Конфигурационные параметры сигнала или его имя.
|
|
50
|
+
* @param optionsOrName.name Уникальное текстовое имя сигнала для отладки и вывода в транзакционный логгер.
|
|
51
|
+
* @param optionsOrName.validate Пользовательская функция валидации значения, возвращающая true/false или строку ошибки.
|
|
52
|
+
*
|
|
53
|
+
* @method signal
|
|
54
|
+
* @memberof ReactiveEngine
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // Пример 1: Чистый TypeScript (Базовый)
|
|
58
|
+
* const engine = new ReactiveEngineCore();
|
|
59
|
+
* const counter = engine.signal(0, { name: 'counter' });
|
|
60
|
+
* console.log(counter.value); // 0
|
|
61
|
+
* counter.value = 1;
|
|
62
|
+
* console.log(counter.value); // 1
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* // Пример 2: Чистый TypeScript (Продвинутый с валидацией)
|
|
66
|
+
* interface User { id: number; name: string; }
|
|
67
|
+
* const engine = new ReactiveEngineCore();
|
|
68
|
+
* const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' }, {
|
|
69
|
+
* name: 'user',
|
|
70
|
+
* validate: (user) => user.id > 0 && typeof user.name === 'string'
|
|
71
|
+
* });
|
|
72
|
+
* userSignal.value = { id: -1, name: 'Jane Doe' }; // Ошибка валидации
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* // Пример 3: Интеграция с React (через DI контейнер)
|
|
76
|
+
* interface User { id: number; name: string; }
|
|
77
|
+
* class UserService {
|
|
78
|
+
* constructor(engine: ReactiveEngineCore) {
|
|
79
|
+
* this.mySignal = engine.signal<User>({ id: 1, name: 'John Doe' }, { name: 'userSignal' });
|
|
80
|
+
* }
|
|
81
|
+
*
|
|
82
|
+
* mySignal: Signal<User>;
|
|
83
|
+
* }
|
|
84
|
+
*
|
|
85
|
+
* const engine = new ReactiveEngineCore();
|
|
86
|
+
* engine.provide(UserService, UserService);
|
|
87
|
+
* const logic = engine.inject(UserService);
|
|
88
|
+
*
|
|
89
|
+
* function MyComponent() {
|
|
90
|
+
* const user = useReactiveValue(logic.mySignal);
|
|
91
|
+
* return <div>{user.name}</div>;
|
|
92
|
+
* }
|
|
93
|
+
*/
|
|
43
94
|
signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T>;
|
|
95
|
+
/**
|
|
96
|
+
* Создает новое вычисляемое свойство (Computed) на основе чистой функции.
|
|
97
|
+
*
|
|
98
|
+
* @template T Тип значения, возвращаемого вычисляемым свойством.
|
|
99
|
+
* @param fn Чистая функция-вычислитель, которая определяет логику вычисления значения.
|
|
100
|
+
* @param signalName Опциональное имя сигнала для отладки и вывода в транзакционный логгер.
|
|
101
|
+
*
|
|
102
|
+
* @method computed
|
|
103
|
+
* @memberof ReactiveEngine
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* // Пример 1: Чистый TypeScript (Базовый)
|
|
107
|
+
* const engine = new ReactiveEngineCore();
|
|
108
|
+
* const counter = engine.signal(0, { name: 'counter' });
|
|
109
|
+
* const doubleCounter = engine.computed(() => counter.value * 2);
|
|
110
|
+
* console.log(doubleCounter.value); // 0
|
|
111
|
+
* counter.value = 1;
|
|
112
|
+
* console.log(doubleCounter.value); // 2
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* // Пример 2: Чистый TypeScript (Продвинутый с цепочкой зависимостей)
|
|
116
|
+
* interface User { id: number; name: string; }
|
|
117
|
+
* const engine = new ReactiveEngineCore();
|
|
118
|
+
* const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' }, { name: 'user' });
|
|
119
|
+
* const userNameLength = engine.computed(() => userSignal.value.name.length);
|
|
120
|
+
* const hasLongName = engine.computed(() => userNameLength.value > 5);
|
|
121
|
+
*
|
|
122
|
+
* console.log(hasLongName.value); // false
|
|
123
|
+
* userSignal.value = { id: 1, name: 'Johnathan' };
|
|
124
|
+
* console.log(userNameLength.value); // 9
|
|
125
|
+
* console.log(hasLongName.value); // true
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* // Пример 3: Интеграция с React (через DI контейнер)
|
|
129
|
+
* interface User { id: number; name: string; }
|
|
130
|
+
* class UserService {
|
|
131
|
+
* constructor(engine: ReactiveEngineCore) {
|
|
132
|
+
* this.userSignal = engine.signal<User>({ id: 1, name: 'John Doe' }, { name: 'userSignal' });
|
|
133
|
+
* this.userNameLength = engine.computed(() => this.userSignal.value.name.length);
|
|
134
|
+
* }
|
|
135
|
+
*
|
|
136
|
+
* userSignal: Signal<User>;
|
|
137
|
+
* userNameLength: Computed<number>;
|
|
138
|
+
* }
|
|
139
|
+
*
|
|
140
|
+
* const engine = new ReactiveEngineCore();
|
|
141
|
+
* engine.provide(UserService, UserService);
|
|
142
|
+
* const logic = engine.inject(UserService);
|
|
143
|
+
*
|
|
144
|
+
* function MyComponent() {
|
|
145
|
+
* const hasLongName = engine.use(logic.userNameLength);
|
|
146
|
+
* return <div>{hasLongName ? 'Long name' : 'Short name'}</div>;
|
|
147
|
+
* }
|
|
148
|
+
*/
|
|
44
149
|
computed<T>(fn: () => T, signalName?: string): Computed<T>;
|
|
45
150
|
effect(fn: () => void | CleanupFn, effectName?: string): () => void;
|
|
46
151
|
untrack<T>(fn: () => T): T;
|
|
@@ -51,6 +156,62 @@ export declare class ReactiveEngineCore {
|
|
|
51
156
|
/**
|
|
52
157
|
* Создает умную реактивную декларативную обертку над асинхронными операциями
|
|
53
158
|
* с автоматическим подавлением Race Conditions и встроенным методом .destroy().
|
|
159
|
+
*
|
|
160
|
+
* @template T Тип данных, возвращаемых фетчером после успешного выполнения.
|
|
161
|
+
* @template S Тип реактивной зависимости (source).
|
|
162
|
+
* @param fetcher Асинхронная функция, выполняющая запрос и возвращающая данные типа T.
|
|
163
|
+
* @param source Реактивный сигнал или примитив, предоставляющий источник данных для фетчера.
|
|
164
|
+
* @param optionsOrName Конфигурационные опции ресурса или его имя.
|
|
165
|
+
* @param optionsOrName.name Имя ресурса.
|
|
166
|
+
* @param optionsOrName.resetDataOnSourceChange Флаг, указывающий, следует ли сбрасывать данные при изменении источника.
|
|
167
|
+
* @param optionsOrName.validateBeforeFetch Функция валидации источника перед выполнением фетча.
|
|
168
|
+
* @param optionsOrName.responseValidate Функция валидации ответа после выполнения фетча.
|
|
169
|
+
* @param optionsOrName.timeout Максимальное время ожидания запроса в миллисекундах.
|
|
170
|
+
* @param optionsOrName.retryCount Количество попыток повторного выполнения запроса в случае ошибки.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* // Пример 1: Чистый TypeScript (Базовый)
|
|
174
|
+
* interface User { id: number; name: string; }
|
|
175
|
+
* interface ApiResponse<T> { ok: boolean; message?: string; data: T; }
|
|
176
|
+
* const engine = new ReactiveEngineCore();
|
|
177
|
+
* const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' });
|
|
178
|
+
* const fetchUser = async (source: User, signal: AbortSignal): Promise<ApiResponse<User>> => {
|
|
179
|
+
* // Реализация фетча пользователя
|
|
180
|
+
* };
|
|
181
|
+
* const userResource = engine.resource(fetchUser, { value: userSignal.value }, { name: 'userResource' });
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* // Пример 2: Чистый TypeScript (Продвинутый)
|
|
185
|
+
* interface User { id: number; name: string; }
|
|
186
|
+
* interface ApiResponse<T> { ok: boolean; message?: string; data: T; }
|
|
187
|
+
* const engine = new ReactiveEngineCore();
|
|
188
|
+
* const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' });
|
|
189
|
+
* const fetchUser = async (source: User, signal: AbortSignal): Promise<ApiResponse<User>> => {
|
|
190
|
+
* // Реализация фетча пользователя с использованием AbortSignal и timeout
|
|
191
|
+
* };
|
|
192
|
+
* const userResource = engine.resource(fetchUser, { value: userSignal.value }, {
|
|
193
|
+
* name: 'userResource',
|
|
194
|
+
* timeout: 5000,
|
|
195
|
+
* retryCount: 3,
|
|
196
|
+
* });
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* // Пример 3: Интеграция с React (через DI контейнер)
|
|
200
|
+
* interface User { id: number; name: string; }
|
|
201
|
+
* interface ApiResponse<T> { ok: boolean; message?: string; data: T; }
|
|
202
|
+
* class UserService {
|
|
203
|
+
* constructor(engine: ReactiveEngineCore) {
|
|
204
|
+
* const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' });
|
|
205
|
+
* this.myResource = engine.resource(fetchUser, { value: userSignal.value }, { name: 'userResource' });
|
|
206
|
+
* }
|
|
207
|
+
*
|
|
208
|
+
* myResource: Resource<ApiResponse<User>>;
|
|
209
|
+
* }
|
|
210
|
+
*
|
|
211
|
+
* const engine = new ReactiveEngineCore();
|
|
212
|
+
* engine.provide(UserService, UserService);
|
|
213
|
+
* const logic = engine.inject(UserService);
|
|
214
|
+
* const state = useReactiveValue(logic.myResource);
|
|
54
215
|
*/
|
|
55
216
|
resource<T, S = void>(fetcher: (source: S, signal: AbortSignal) => Promise<T>, source?: {
|
|
56
217
|
value: S;
|
package/dist/core/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core/core.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAW,mBAAmB,EAAE,YAAY,EAAE,SAAS,EAAiC,aAAa,EAAE,eAAe,EAAiB,QAAQ,EAAE,MAAM,SAAS,CAAA;AAWzL,KAAK,WAAW,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;AAE/C,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAA;AAEpC,KAAK,cAAc,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,CAAA;AAuBtE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAM/H;AACD,wBAAgB,SAAS,IAAI,IAAI,CA8BhC;AACD,qBAAa,kBAAkB;IAC7B,SAAS,CAAC,eAAe,SAAS;IAC3B,MAAM,EAAE,mBAAmB,CAAA;IAC3B,KAAK,SAAI;IACT,cAAc,EAAE,GAAG,CAAO;IAC1B,UAAU,SAAI;IACd,YAAY,SAAI;IAChB,cAAc,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAAK;IAChD,eAAe,SAAI;IACnB,aAAa,yBAA+B;IACnD,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,mBAAmB,CAAqB;IACzC,cAAc,WAAiB;IAC/B,WAAW,EAAE,GAAG,CAAO;
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.effect.test.d.ts","sourceRoot":"","sources":["../../src/core/core.effect.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.method.computed.d.ts","sourceRoot":"","sources":["../../src/core/core.method.computed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,SAAS,CAAA;AAE7C,wBAAgB,cAAc,CAAC,CAAC,EAC9B,MAAM,EAAE,GAAG,EACX,EAAE,EAAE,MAAM,CAAC,EACX,UAAU,CAAC,EAAE,MAAM,GAClB,QAAQ,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"core.method.computed.d.ts","sourceRoot":"","sources":["../../src/core/core.method.computed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,SAAS,CAAA;AAE7C,wBAAgB,cAAc,CAAC,CAAC,EAC9B,MAAM,EAAE,GAAG,EACX,EAAE,EAAE,MAAM,CAAC,EACX,UAAU,CAAC,EAAE,MAAM,GAClB,QAAQ,CAAC,CAAC,CAAC,CA8Tb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.method.effect.d.ts","sourceRoot":"","sources":["../../src/core/core.method.effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,QAAQ,EAAa,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"core.method.effect.d.ts","sourceRoot":"","sources":["../../src/core/core.method.effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,QAAQ,EAAa,MAAM,SAAS,CAAA;AActD,wBAAgB,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,CA2LvF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.method.signal.d.ts","sourceRoot":"","sources":["../../src/core/core.method.signal.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE/C,wBAAgB,YAAY,CAAC,CAAC,EAC5B,MAAM,EAAE,GAAG,EACX,YAAY,EAAE,CAAC,EACf,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,GACxC,MAAM,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"core.method.signal.d.ts","sourceRoot":"","sources":["../../src/core/core.method.signal.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE/C,wBAAgB,YAAY,CAAC,CAAC,EAC5B,MAAM,EAAE,GAAG,EACX,YAAY,EAAE,CAAC,EACf,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,GACxC,MAAM,CAAC,CAAC,CAAC,CAuKX"}
|
|
@@ -14,6 +14,7 @@ function e(e, t, n) {
|
|
|
14
14
|
}
|
|
15
15
|
}, h = (t) => {
|
|
16
16
|
if (!s || l === 2) return t.run();
|
|
17
|
+
if (p && p.size > 0 && t.verifiedInEpoch === e.epoch && e.batchDepth === 0 && l === 0) return !1;
|
|
17
18
|
let n = !1;
|
|
18
19
|
if (u && u.size > 0) for (let t of u) {
|
|
19
20
|
let r = t._node || t;
|
|
@@ -22,7 +23,7 @@ function e(e, t, n) {
|
|
|
22
23
|
break;
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
|
-
return
|
|
26
|
+
return t.verifiedInEpoch = e.epoch, n || a ? t.run() : (l = 0, !1);
|
|
26
27
|
}, g = 0, _ = {
|
|
27
28
|
id: e.subscriberId++,
|
|
28
29
|
dependencies: u,
|
|
@@ -110,7 +111,7 @@ function e(e, t, n) {
|
|
|
110
111
|
let e = _.depth || 1, n = t._node || t;
|
|
111
112
|
n.depth !== void 0 && e >= n.depth && (n.depth = e + 1), t.activeRunId !== void 0 && (_._lastSeenInRunId = t.activeRunId);
|
|
112
113
|
}
|
|
113
|
-
return
|
|
114
|
+
return h(_), t && t.depVersions && t.depVersions.set(v, o), i;
|
|
114
115
|
},
|
|
115
116
|
get valueWithoutTracking() {
|
|
116
117
|
return i;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.method.computed.mjs","names":[],"sources":["../src/core/core.method.computed.ts"],"sourcesContent":["import { Computed, CleanupFn } from './types'\n\nexport function createComputed<T>(\n engine: any,\n fn: () => T,\n signalName?: string\n): Computed<T> {\n // 1. Ультимативный канонический WeakMap путь (строго по ссылке на объект-функцию)\n // Работает со скоростью нативной ссылки в V8, полностью исключая утечки памяти\n const existing = engine.computedCache.get(fn)\n if (existing) return existing as Computed<T>\n\n let value: T\n let isDirty = true\n let version = 0\n let isInitialized = false\n let evaluatedInEpoch = -1\n let state = 2 // 2 = DIRTY, 1 = CHECK, 0 = STABLE\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<any>()\n const subscribers = new Set<any>()\n\n const releaseNode = (node: any): void => {\n if (!node) return\n const actNode = node._node || node\n\n if (actNode.dependencies && actNode.dependencies.size > 0) {\n for (const unknownDep of actNode.dependencies) {\n const dep = unknownDep as any\n const rawDepNode = dep._node || dep\n\n if (rawDepNode.subscribers) {\n rawDepNode.subscribers.delete(actNode)\n rawDepNode.subscribers.delete(node)\n rawDepNode.subscribers.delete(computedNode)\n\n if (rawDepNode.type === 'computed' && rawDepNode.subscribers.size === 0) {\n releaseNode(rawDepNode)\n }\n }\n }\n actNode.dependencies.clear()\n if (actNode.depVersions) actNode.depVersions.clear()\n }\n }\n\n const updateIfNecessary = (node: any): boolean => {\n if (!isInitialized || state === 2) {\n return node.run()\n }\n\n // 1. Сначала честно сканируем родителей по физическим версиям мутаций в V8.\n // Это единственный способ отловить inner write на фазе ленивого pull-запроса,\n // так как вложенный сеттер мог сдвинуть версии сигналов в обход markDirty.\n let hasChangedParent = false\n\n if (dependencies && dependencies.size > 0) {\n for (const dep of dependencies) {\n const rawDep = dep._node || dep\n\n if (rawDep.type === 'computed' && rawDep.state > 0) {\n if (rawDep.update && rawDep.verifiedInEpoch !== engine.epoch) {\n rawDep.update()\n }\n }\n\n if (dep.hasBatchValue || depVersions.get(dep) !== rawDep.version) {\n hasChangedParent = true\n break\n }\n }\n }\n\n // ⚛️ УЛЬТИМАТИВНЫЙ ФИКС ТЕСТOВ #180 и #186:\n // Если обход родителей подтвердил изменение версий из побочного канала (hasChangedParent === true),\n // мы ОБЯЗАНЫ сбросить кэши эпох текущей ноды и пустить её на честный пересчет.\n // При этом мы НЕ выставляем принудительно state = 2, благодаря чему метод run()\n // сможет сравнить результаты через Object.is и легитимно остановить волну (Value-Equality Cut)!\n if (hasChangedParent) {\n evaluatedInEpoch = -1\n node.verifiedInEpoch = -1\n return node.run()\n }\n\n // 2. И только если родители НЕ менялись, мы можем применить быстрый O(1) возврат по эпохам\n if (subscribers && subscribers.size > 0) {\n if (node.verifiedInEpoch === engine.epoch && engine.batchDepth === 0 && state === 0) {\n return false\n }\n }\n\n if (isDirty) {\n return node.run()\n }\n\n // Канонический сброс для unobserved pull-цепочек из тестов матрицы сайта\n if (node.verifiedInEpoch !== -1 && node.verifiedInEpoch < engine.epoch && (!subscribers || subscribers.size === 0)) {\n node.verifiedInEpoch = -1\n } else {\n node.verifiedInEpoch = engine.epoch\n }\n\n state = 0\n return false\n }\n\n let currentRunId = 0\n\n const computedNode: any = {\n id: engine.subscriberId++,\n dependencies,\n subscribers,\n ownedEffects,\n depth: 1,\n type: 'computed',\n fn,\n get version() { return version },\n get state() { return state },\n set state(val: number) { state = val },\n get depVersions() { return depVersions },\n verifiedInEpoch: -1, // Перенесено напрямую на объект ноды для ультимативного O(1)\n update: () => updateIfNecessary(computedNode),\n run: () => {\n // ⚛️ КАНOНИЧЕСКИЙ БЫСТРЫЙ ВЫХOД:\n // Срабатывает только если эпоха стабильна, узел не сброшен в updateIfNecessary\n // и в текущем кадре не происходило inner write мутаций у родителей\n if (evaluatedInEpoch === engine.epoch && isInitialized && state === 0 && engine.batchDepth === 0) {\n return false\n }\n\n // Запоминаем стартовую эпоху до вызова функции пользователя\n const startEpoch = engine.epoch\n evaluatedInEpoch = startEpoch\n computedNode.verifiedInEpoch = startEpoch\n\n if (engine.cycleDetectionStack.has(computedNode)) {\n throw new Error('[Graph Error] Cyclic dependency detected')\n }\n engine.cycleDetectionStack.add(computedNode)\n\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n\n engine.activeConsumer = computedNode\n engine.activeOwner = computedNode\n\n currentRunId++\n computedNode.activeRunId = currentRunId\n\n const oldDeps = dependencies.size > 0 ? Array.from(dependencies) : null\n dependencies.clear()\n\n try {\n if (ownedEffects.size > 0) {\n for (const child of ownedEffects) {\n if (child && typeof child.dispose === 'function') {\n child.dispose()\n }\n }\n ownedEffects.clear()\n }\n\n // Выполняем пользовательскую функцию (здесь могут произойти inner writes из тестов #179, #180, #186)\n const newValue = fn()\n\n if (oldDeps !== null) {\n const isSizeIdentical = oldDeps.length === dependencies.size\n for (const unknownDep of oldDeps) {\n const dep = unknownDep as any\n if (!isSizeIdentical || !dependencies.has(dep)) {\n const rawDepNode = dep._node || dep\n if (rawDepNode.subscribers) rawDepNode.subscribers.delete(computedNode)\n depVersions.delete(dep)\n }\n }\n }\n\n const changed = isDirty || !Object.is(value, newValue)\n\n if (changed) {\n const previousValueSnapshot = isDirty ? undefined : (typeof value === 'object' && value !== null ? JSON.parse(JSON.stringify(value)) : value)\n value = newValue\n version++\n\n if (engine.log && signalName) {\n engine.log({\n type: 'computed',\n label: signalName,\n details: { from: previousValueSnapshot, to: newValue }\n })\n }\n }\n\n isDirty = false\n state = 0\n isInitialized = true\n\n let maxDepDepth = 0\n for (const unknownDep of dependencies) {\n const dep = unknownDep as any\n const rawNode = dep._node || dep\n depVersions.set(dep, rawNode.version)\n if (rawNode.subscribers) rawNode.subscribers.add(computedNode)\n if (rawNode.depth !== undefined && rawNode.depth > maxDepDepth) {\n maxDepDepth = rawNode.depth\n }\n }\n\n computedNode.depth = maxDepDepth + 1\n\n // ⚡ ФИКС ДЛЯ INNER WRITES (#179, #180, #186):\n // Если во время исполнения fn() эпоха ядра сдвинулась (был вложенный сеттер),\n // мы обязаны сбросить кэш верификации этой эпохи, чтобы последующие цепочки\n // зависимостей внутри этого же тика пересчитали свои значения нативно.\n if (engine.epoch !== startEpoch) {\n evaluatedInEpoch = -1\n computedNode.verifiedInEpoch = -1\n state = 2 // Переводим в DIRTY для немедленной инвалидации\n }\n\n return changed\n } finally {\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n engine.cycleDetectionStack.delete(computedNode)\n }\n },\n markDirty: (parentState: number) => {\n if (state >= parentState) return\n state = parentState\n\n for (const sub of subscribers) {\n const rawSub = sub._node || sub\n if (rawSub.type === 'effect') {\n rawSub.isDirty = true\n engine.scheduleEffect(sub)\n } else if (rawSub.markDirty) {\n rawSub.markDirty(1)\n }\n }\n }\n }\n\n const computedInstance: Computed<T> = {\n get value() {\n const consumer = engine.activeConsumer\n if (consumer && consumer !== computedNode) {\n if (typeof consumer.dependencies?.add === 'function') {\n subscribers.add(consumer)\n consumer.dependencies.add(computedNode)\n\n const currentDepth = computedNode.depth || 1\n const consumerRaw = consumer._node || consumer\n if (consumerRaw.depth !== undefined && currentDepth >= consumerRaw.depth) {\n consumerRaw.depth = currentDepth + 1\n }\n\n if (consumer.activeRunId !== undefined) {\n computedNode._lastSeenInRunId = consumer.activeRunId\n }\n }\n }\n\n // ⚛️ ВЕЛИКИЙ ПРЕДOХРАНИТЕЛЬ ДЛЯ INNER WRITES (#180 и #186):\n // Если у ноды есть сохраненный маркер эпохи, но состояние у узла DIRTY (state === 2)\n // из-за вложенного вызова markDirty(2) во время flush-цикла, либо если глобальная эпоха\n // ядра ушла вперед — мы ОБЯЗАНЫ обнулить verifiedInEpoch, чтобы пропустить пулл-запрос к родителям!\n if (state === 2 || (computedNode.verifiedInEpoch !== -1 && computedNode.verifiedInEpoch < engine.epoch)) {\n computedNode.verifiedInEpoch = -1\n evaluatedInEpoch = -1\n }\n\n updateIfNecessary(computedNode)\n\n if (consumer && consumer.depVersions) {\n consumer.depVersions.set(computedInstance, version)\n }\n return value\n },\n get valueWithoutTracking() { return value },\n get version() { return version },\n get dependencies() { return dependencies },\n\n subscribe(cb: (val: T) => void): CleanupFn {\n const self = this\n const fakeEffect: any = {\n id: engine.subscriberId++,\n isDirty: true,\n depth: 9999,\n dependencies: new Set(),\n type: 'effect',\n run: () => {\n if (fakeEffect.isDisposed) return\n try { cb(self.value) } catch (err) { console.error(err) }\n }\n }\n subscribers.add(fakeEffect)\n cb(this.value)\n return () => {\n fakeEffect.isDisposed = true\n subscribers.delete(fakeEffect)\n fakeEffect.dependencies.clear()\n }\n },\n subscribeState(cb: () => void): CleanupFn {\n return (computedInstance as any).subscribe(cb)\n },\n destroy: () => {\n releaseNode(computedNode)\n if (subscribers) subscribers.clear()\n engine.computedCache.delete(fn)\n\n dependencies.clear()\n depVersions.clear()\n ownedEffects.clear()\n\n isDirty = true\n state = 2\n isInitialized = false\n },\n __subscribe(cb: () => void): CleanupFn {\n const hookEffect: any = {\n id: engine.subscriberId++,\n type: 'effect',\n run: cb,\n isDirty: false\n }\n subscribers.add(hookEffect)\n return () => {\n subscribers.delete(hookEffect)\n }\n }\n } as any\n\n computedInstance.run = () => computedNode.run()\n engine.computedCache.set(fn, computedInstance)\n\n ;(computedInstance as any)._node = computedNode\n ;(computedInstance as any).subscribers = subscribers\n\n return computedInstance\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.method.computed.mjs","names":[],"sources":["../src/core/core.method.computed.ts"],"sourcesContent":["import { Computed, CleanupFn } from './types'\n\nexport function createComputed<T>(\n engine: any,\n fn: () => T,\n signalName?: string\n): Computed<T> {\n // 1. Ультимативный канонический WeakMap путь (строго по ссылке на объект-функцию)\n // Работает со скоростью нативной ссылки в V8, полностью исключая утечки памяти\n const existing = engine.computedCache.get(fn)\n if (existing) return existing as Computed<T>\n\n let value: T\n let isDirty = true\n let version = 0\n let isInitialized = false\n let evaluatedInEpoch = -1\n let state = 2 // 2 = DIRTY, 1 = CHECK, 0 = STABLE\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<any>()\n const subscribers = new Set<any>()\n\n const releaseNode = (node: any): void => {\n if (!node) return\n const actNode = node._node || node\n\n if (actNode.dependencies && actNode.dependencies.size > 0) {\n for (const unknownDep of actNode.dependencies) {\n const dep = unknownDep as any\n const rawDepNode = dep._node || dep\n\n if (rawDepNode.subscribers) {\n rawDepNode.subscribers.delete(actNode)\n rawDepNode.subscribers.delete(node)\n rawDepNode.subscribers.delete(computedNode)\n\n if (rawDepNode.type === 'computed' && rawDepNode.subscribers.size === 0) {\n releaseNode(rawDepNode)\n }\n }\n }\n actNode.dependencies.clear()\n if (actNode.depVersions) actNode.depVersions.clear()\n }\n }\n\n const updateIfNecessary = (node: any): boolean => {\n if (!isInitialized || state === 2) {\n return node.run()\n }\n\n // ⚛️ КОРРЕКТНЫЙ МЕМОИЗАЦИОННЫЙ ГВАРД (Pull-совместимый проход):\n // Если у узла есть активные подписчики (observed), мы можем оптимизировать расчет через эпохи.\n // Но если подписчиков НЕТ (unobserved), мы ОБЯЗАНЫ пропустить быстрый выход по эпохам\n // и честно проверить, изменились ли версии родителей ниже.\n if (subscribers && subscribers.size > 0) {\n if (node.verifiedInEpoch === engine.epoch && engine.batchDepth === 0 && state === 0) {\n return false\n }\n }\n\n let hasChangedParent = false\n\n if (dependencies && dependencies.size > 0) {\n for (const dep of dependencies) {\n const rawDep = dep._node || dep\n\n if (rawDep.type === 'computed' && rawDep.state > 0) {\n // ⚛️ ЗАЩИТА ОТ КАСКАДНОГО ОБХОДА:\n // Вызываем update() родителя только если он еще не был верифицирован в текущей эпохе.\n // Это ликвидирует квадратичную рекурсию на динамических структурах графа!\n if (rawDep.update && rawDep.verifiedInEpoch !== engine.epoch) {\n rawDep.update()\n }\n }\n\n // Если родитель имеет отложенное батч-значение (hasBatchValue)\n // или его версия изменилась — кэш невалиден!\n if (dep.hasBatchValue || depVersions.get(dep) !== rawDep.version) {\n hasChangedParent = true\n break\n }\n }\n }\n\n node.verifiedInEpoch = engine.epoch\n\n if (hasChangedParent || isDirty) {\n return node.run()\n }\n\n state = 0\n return false\n }\n\n let currentRunId = 0\n\n const computedNode: any = {\n id: engine.subscriberId++,\n dependencies,\n subscribers,\n ownedEffects,\n depth: 1,\n type: 'computed',\n fn,\n get version() { return version },\n get state() { return state },\n set state(val: number) { state = val },\n get depVersions() { return depVersions },\n verifiedInEpoch: -1, // Перенесено напрямую на объект ноды для ультимативного O(1)\n update: () => updateIfNecessary(computedNode),\n run: () => {\n // Стандартный быстрый выход для стабильных эпох\n if (evaluatedInEpoch === engine.epoch && isInitialized && state === 0 && engine.batchDepth === 0) {\n return false\n }\n\n // Запоминаем стартовую эпоху до вызова функции пользователя\n const startEpoch = engine.epoch\n evaluatedInEpoch = startEpoch\n computedNode.verifiedInEpoch = startEpoch\n\n if (engine.cycleDetectionStack.has(computedNode)) {\n throw new Error('[Graph Error] Cyclic dependency detected')\n }\n engine.cycleDetectionStack.add(computedNode)\n\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n\n engine.activeConsumer = computedNode\n engine.activeOwner = computedNode\n\n currentRunId++\n computedNode.activeRunId = currentRunId\n\n const oldDeps = dependencies.size > 0 ? Array.from(dependencies) : null\n dependencies.clear()\n\n try {\n if (ownedEffects.size > 0) {\n for (const child of ownedEffects) {\n if (child && typeof child.dispose === 'function') {\n child.dispose()\n }\n }\n ownedEffects.clear()\n }\n\n // Выполняем пользовательскую функцию (здесь могут произойти inner writes из тестов #179, #180, #186)\n const newValue = fn()\n\n if (oldDeps !== null) {\n const isSizeIdentical = oldDeps.length === dependencies.size\n for (const unknownDep of oldDeps) {\n const dep = unknownDep as any\n if (!isSizeIdentical || !dependencies.has(dep)) {\n const rawDepNode = dep._node || dep\n if (rawDepNode.subscribers) rawDepNode.subscribers.delete(computedNode)\n depVersions.delete(dep)\n }\n }\n }\n\n const changed = isDirty || !Object.is(value, newValue)\n\n if (changed) {\n const previousValueSnapshot = isDirty ? undefined : (typeof value === 'object' && value !== null ? JSON.parse(JSON.stringify(value)) : value)\n value = newValue\n version++\n\n if (engine.log && signalName) {\n engine.log({\n type: 'computed',\n label: signalName,\n details: { from: previousValueSnapshot, to: newValue }\n })\n }\n }\n\n isDirty = false\n state = 0\n isInitialized = true\n\n let maxDepDepth = 0\n for (const unknownDep of dependencies) {\n const dep = unknownDep as any\n const rawNode = dep._node || dep\n depVersions.set(dep, rawNode.version)\n if (rawNode.subscribers) rawNode.subscribers.add(computedNode)\n if (rawNode.depth !== undefined && rawNode.depth > maxDepDepth) {\n maxDepDepth = rawNode.depth\n }\n }\n\n computedNode.depth = maxDepDepth + 1\n\n // ⚡ ФИКС ДЛЯ INNER WRITES (#179, #180, #186):\n // Если во время исполнения fn() эпоха ядра сдвинулась (был вложенный сеттер),\n // мы обязаны сбросить кэш верификации этой эпохи, чтобы последующие цепочки\n // зависимостей внутри этого же тика пересчитали свои значения нативно.\n if (engine.epoch !== startEpoch) {\n evaluatedInEpoch = -1\n computedNode.verifiedInEpoch = -1\n state = 2 // Переводим в DIRTY для немедленной инвалидации\n }\n\n return changed\n } finally {\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n engine.cycleDetectionStack.delete(computedNode)\n }\n },\n markDirty: (parentState: number) => {\n if (state >= parentState) return\n state = parentState\n\n for (const sub of subscribers) {\n const rawSub = sub._node || sub\n if (rawSub.type === 'effect') {\n rawSub.isDirty = true\n engine.scheduleEffect(sub)\n } else if (rawSub.markDirty) {\n rawSub.markDirty(1)\n }\n }\n }\n }\n\n const computedInstance: Computed<T> = {\n get value() {\n // 🛡️ АТОМАРНАЯ ЗАЩИТА: Фиксируем ссылку локально и работаем строго с ней.\n // Это полностью предотвращает TypeError: ... reading 'add' на проде Next.js.\n const consumer = engine.activeConsumer\n if (consumer && consumer !== computedNode) {\n // Проверяем наличие метода add у консьюмера, страхуя граф от стороннего мусора Webpack\n if (typeof consumer.dependencies?.add === 'function') {\n subscribers.add(consumer)\n consumer.dependencies.add(computedNode)\n\n const currentDepth = computedNode.depth || 1\n const consumerRaw = consumer._node || consumer\n if (consumerRaw.depth !== undefined && currentDepth >= consumerRaw.depth) {\n consumerRaw.depth = currentDepth + 1\n }\n\n if (consumer.activeRunId !== undefined) {\n computedNode._lastSeenInRunId = consumer.activeRunId\n }\n }\n }\n\n updateIfNecessary(computedNode)\n\n if (consumer && consumer.depVersions) {\n consumer.depVersions.set(computedInstance, version)\n }\n return value\n },\n get valueWithoutTracking() { return value },\n get version() { return version },\n get dependencies() { return dependencies },\n\n subscribe(cb: (val: T) => void): CleanupFn {\n const self = this\n const fakeEffect: any = {\n id: engine.subscriberId++,\n isDirty: true,\n depth: 9999,\n dependencies: new Set(),\n type: 'effect',\n run: () => {\n if (fakeEffect.isDisposed) return\n try { cb(self.value) } catch (err) { console.error(err) }\n }\n }\n subscribers.add(fakeEffect)\n cb(this.value)\n return () => {\n fakeEffect.isDisposed = true\n subscribers.delete(fakeEffect)\n fakeEffect.dependencies.clear()\n }\n },\n subscribeState(cb: () => void): CleanupFn {\n return (computedInstance as any).subscribe(cb)\n },\n destroy: () => {\n releaseNode(computedNode)\n if (subscribers) subscribers.clear()\n engine.computedCache.delete(fn)\n\n dependencies.clear()\n depVersions.clear()\n ownedEffects.clear()\n\n isDirty = true\n state = 2\n isInitialized = false\n },\n __subscribe(cb: () => void): CleanupFn {\n const hookEffect: any = {\n id: engine.subscriberId++,\n type: 'effect',\n run: cb,\n isDirty: false\n }\n subscribers.add(hookEffect)\n return () => {\n subscribers.delete(hookEffect)\n }\n }\n } as any\n\n computedInstance.run = () => computedNode.run()\n engine.computedCache.set(fn, computedInstance)\n\n ;(computedInstance as any)._node = computedNode\n ;(computedInstance as any).subscribers = subscribers\n\n return computedInstance\n}\n"],"mappings":"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"}
|
|
@@ -1,35 +1,46 @@
|
|
|
1
1
|
//#region src/core/core.method.effect.ts
|
|
2
2
|
function e(e, t, n) {
|
|
3
|
-
let r = !1, i = !1, a =
|
|
4
|
-
if (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
let r = !1, i = !1, a = !1, o = 2, s = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Map(), d = () => {
|
|
4
|
+
if (a) return;
|
|
5
|
+
a = !0;
|
|
6
|
+
let t = e.activeCleanupNode;
|
|
7
|
+
e.activeCleanupNode = f;
|
|
8
|
+
try {
|
|
9
|
+
if (l.size > 0) {
|
|
10
|
+
let t = e.activeConsumer, n = e.activeOwner;
|
|
11
|
+
e.activeConsumer = null, e.activeOwner = null;
|
|
12
|
+
for (let e of l) e.dispose && e.dispose();
|
|
13
|
+
l.clear(), e.activeConsumer = t, e.activeOwner = n;
|
|
14
|
+
}
|
|
15
|
+
if (f.cleanups.size > 0) {
|
|
16
|
+
let t = e.activeConsumer;
|
|
17
|
+
e.activeConsumer = null;
|
|
18
|
+
let n = null, r = Array.from(f.cleanups);
|
|
19
|
+
f.cleanups.clear();
|
|
20
|
+
for (let e of r) try {
|
|
21
|
+
e();
|
|
22
|
+
} catch (e) {
|
|
23
|
+
console.error(e), n ||= e;
|
|
24
|
+
}
|
|
25
|
+
if (e.activeConsumer = t, n) throw n;
|
|
17
26
|
}
|
|
18
|
-
|
|
27
|
+
} finally {
|
|
28
|
+
e.activeCleanupNode = t, a = !1;
|
|
19
29
|
}
|
|
20
|
-
},
|
|
30
|
+
}, f = {
|
|
21
31
|
id: e.subscriberId++,
|
|
22
|
-
dependencies:
|
|
23
|
-
ownedEffects:
|
|
32
|
+
dependencies: s,
|
|
33
|
+
ownedEffects: l,
|
|
24
34
|
cleanups: /* @__PURE__ */ new Set(),
|
|
25
35
|
type: "effect",
|
|
26
36
|
depth: 0,
|
|
27
37
|
label: n,
|
|
38
|
+
_snapshotValues: u,
|
|
28
39
|
get isDirty() {
|
|
29
|
-
return
|
|
40
|
+
return o > 0;
|
|
30
41
|
},
|
|
31
42
|
set isDirty(e) {
|
|
32
|
-
e && (
|
|
43
|
+
e && (o = 2);
|
|
33
44
|
},
|
|
34
45
|
get isDisposed() {
|
|
35
46
|
return r;
|
|
@@ -38,60 +49,69 @@ function e(e, t, n) {
|
|
|
38
49
|
r = e;
|
|
39
50
|
},
|
|
40
51
|
get state() {
|
|
41
|
-
return
|
|
52
|
+
return o;
|
|
42
53
|
},
|
|
43
54
|
set state(e) {
|
|
44
|
-
|
|
55
|
+
o = e;
|
|
45
56
|
},
|
|
46
57
|
get depVersions() {
|
|
47
|
-
return
|
|
58
|
+
return c;
|
|
48
59
|
},
|
|
49
60
|
get _node() {
|
|
50
|
-
return
|
|
61
|
+
return f;
|
|
51
62
|
},
|
|
52
63
|
markDirty: () => {
|
|
53
|
-
|
|
64
|
+
r || o >= 1 || (o = 1, e.scheduleEffect(f));
|
|
54
65
|
},
|
|
55
66
|
run: () => {
|
|
56
67
|
if (r || i) return;
|
|
57
|
-
i = !0
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
i = !0;
|
|
69
|
+
try {
|
|
70
|
+
d();
|
|
71
|
+
} catch (e) {
|
|
72
|
+
throw i = !1, e;
|
|
73
|
+
}
|
|
74
|
+
if (r) {
|
|
75
|
+
i = !1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
let n = e.activeConsumer, a = e.activeOwner;
|
|
79
|
+
e.activeConsumer = f, e.activeOwner = f;
|
|
80
|
+
let l = s.size > 0 ? Array.from(s) : null;
|
|
81
|
+
s.clear();
|
|
62
82
|
try {
|
|
63
|
-
|
|
83
|
+
o = 0;
|
|
64
84
|
let e = t();
|
|
65
|
-
if (typeof e == "function" &&
|
|
85
|
+
if (typeof e == "function" && f.cleanups.add(e), l !== null) for (let e of l) {
|
|
66
86
|
let t = e;
|
|
67
|
-
if (!
|
|
87
|
+
if (!s.has(t)) {
|
|
68
88
|
let e = t._node || t;
|
|
69
|
-
e.subscribers && e.subscribers.delete(
|
|
89
|
+
e.subscribers && e.subscribers.delete(f), c.delete(t), u.delete(t);
|
|
70
90
|
}
|
|
71
91
|
}
|
|
72
92
|
let n = 0;
|
|
73
|
-
for (let e of
|
|
93
|
+
for (let e of s) {
|
|
74
94
|
let t = e, r = t._node || t;
|
|
75
|
-
|
|
95
|
+
c.set(t, r.version), r.subscribers && r.subscribers.add(f), r.depth !== void 0 && r.depth > n && (n = r.depth);
|
|
76
96
|
}
|
|
77
|
-
|
|
97
|
+
f.depth = n + 1;
|
|
78
98
|
} finally {
|
|
79
|
-
i = !1, e.activeConsumer = n, e.activeOwner =
|
|
99
|
+
i = !1, e.activeConsumer = n, e.activeOwner = a;
|
|
80
100
|
}
|
|
81
101
|
},
|
|
82
102
|
dispose: () => {
|
|
83
103
|
if (!r) {
|
|
84
|
-
r = !0,
|
|
85
|
-
for (let e of
|
|
104
|
+
r = !0, f.isDisposed = !0, d();
|
|
105
|
+
for (let e of s) {
|
|
86
106
|
let t = e._node || e;
|
|
87
|
-
t.subscribers && t.subscribers.delete(
|
|
107
|
+
t.subscribers && t.subscribers.delete(f);
|
|
88
108
|
}
|
|
89
|
-
|
|
109
|
+
s.clear(), c.clear(), u.clear();
|
|
90
110
|
}
|
|
91
111
|
}
|
|
92
|
-
},
|
|
93
|
-
return
|
|
94
|
-
|
|
112
|
+
}, p = e.activeOwner ? e.activeOwner._node || e.activeOwner : null;
|
|
113
|
+
return p && p.ownedEffects && p.ownedEffects.add(f), f.run(), () => {
|
|
114
|
+
f.dispose();
|
|
95
115
|
};
|
|
96
116
|
}
|
|
97
117
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.method.effect.mjs","names":[],"sources":["../src/core/core.method.effect.ts"],"sourcesContent":["import { IEffect, EffectFn, CleanupFn } from './types'\n\ninterface ICoreEffectNode extends IEffect {\n dependencies: Set<any>;\n depVersions: Map<any, number>;\n ownedEffects: Set<ICoreEffectNode>;\n type: string;\n depth: number;\n state: number;\n _node: any;\n dispose: () => void;\n}\n\nexport function createEffect(engine: any, fn: EffectFn, effectName?: string): () => void {\n let isDisposed = false\n let isRunning = false\n let state = 2 // 0 = STABLE, 1 = CHECK, 2 = DIRTY\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<ICoreEffectNode>()\n\n const runCleanupPhase = () => {\n //
|
|
1
|
+
{"version":3,"file":"core.method.effect.mjs","names":[],"sources":["../src/core/core.method.effect.ts"],"sourcesContent":["import { IEffect, EffectFn, CleanupFn } from './types'\n\ninterface ICoreEffectNode extends IEffect {\n dependencies: Set<any>;\n depVersions: Map<any, number>;\n ownedEffects: Set<ICoreEffectNode>;\n type: string;\n depth: number;\n state: number;\n _node: any;\n dispose: () => void;\n _snapshotValues: Map<any, any>;\n}\n\nexport function createEffect(engine: any, fn: EffectFn, effectName?: string): () => void {\n let isDisposed = false\n let isRunning = false\n let isCleaning = false\n let state = 2 // 0 = STABLE, 1 = CHECK, 2 = DIRTY (Гарантированное объявление переменной)\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<ICoreEffectNode>()\n const snapshotValues = new Map<any, any>()\n\n const runCleanupPhase = () => {\n if (isCleaning) return\n isCleaning = true\n\n // Активируем контекст чтения исторических снапшотов\n const prevCleanupNode = engine.activeCleanupNode\n engine.activeCleanupNode = effectNode\n\n try {\n // 1. Каскадное уничтожение вложенных дочерних эффектов\n if (ownedEffects.size > 0) {\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n engine.activeConsumer = null\n engine.activeOwner = null\n\n for (const child of ownedEffects) {\n if (child.dispose) child.dispose()\n }\n ownedEffects.clear()\n\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n }\n\n // 2. Вызов деструкторов пользователя в режиме untracked\n if (effectNode.cleanups.size > 0) {\n const prevConsumer = engine.activeConsumer\n engine.activeConsumer = null\n\n let firstError: unknown = null\n const cleanupsArray = Array.from(effectNode.cleanups)\n effectNode.cleanups.clear()\n\n for (const cleanup of cleanupsArray) {\n try {\n cleanup()\n } catch (err) {\n console.error(err)\n if (!firstError) {\n firstError = err\n }\n }\n }\n\n engine.activeConsumer = prevConsumer\n\n if (firstError) {\n throw firstError\n }\n }\n } finally {\n engine.activeCleanupNode = prevCleanupNode\n isCleaning = false\n }\n }\n\n const effectNode: ICoreEffectNode = {\n id: engine.subscriberId++,\n dependencies,\n ownedEffects,\n cleanups: new Set<CleanupFn>(),\n type: 'effect',\n depth: 0,\n label: effectName,\n _snapshotValues: snapshotValues,\n\n get isDirty(): boolean { return state > 0 },\n set isDirty(val: boolean) { if (val) state = 2 },\n\n get isDisposed(): boolean { return isDisposed },\n set isDisposed(val: boolean) { isDisposed = val },\n\n get state(): number { return state },\n set state(val: number) { state = val },\n get depVersions(): Map<any, number> { return depVersions },\n get _node(): any { return effectNode },\n\n markDirty: () => {\n if (isDisposed || state >= 1) return\n state = 1\n engine.scheduleEffect(effectNode)\n },\n\n run: () => {\n if (isDisposed || isRunning) return\n isRunning = true\n\n try {\n runCleanupPhase()\n } catch (err) {\n isRunning = false\n throw err\n }\n\n if (isDisposed) {\n isRunning = false\n return\n }\n\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n\n engine.activeConsumer = effectNode\n engine.activeOwner = effectNode\n\n const oldDeps = dependencies.size > 0 ? Array.from(dependencies) : null\n dependencies.clear()\n\n try {\n state = 0 // Локальная переменная замыкания теперь успешно сбрасывается в STABLE\n\n const result = fn()\n if (typeof result === 'function') {\n effectNode.cleanups.add(result)\n }\n\n if (oldDeps !== null) {\n for (const unknownDep of oldDeps) {\n const dep = unknownDep as any\n if (!dependencies.has(dep)) {\n const rawDepNode = dep._node || dep\n if (rawDepNode.subscribers) rawDepNode.subscribers.delete(effectNode)\n depVersions.delete(dep)\n snapshotValues.delete(dep)\n }\n }\n }\n\n let maxDepDepth = 0\n for (const unknownDep of dependencies) {\n const dep = unknownDep as any\n const rawNode = dep._node || dep\n depVersions.set(dep, rawNode.version)\n if (rawNode.subscribers) rawNode.subscribers.add(effectNode)\n if (rawNode.depth !== undefined && rawNode.depth > maxDepDepth) {\n maxDepDepth = rawNode.depth\n }\n }\n effectNode.depth = maxDepDepth + 1\n\n } finally {\n isRunning = false\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n }\n },\n\n dispose: () => {\n if (isDisposed) return\n isDisposed = true\n effectNode.isDisposed = true\n\n runCleanupPhase()\n\n for (const dep of dependencies) {\n const rawNode = dep._node || dep\n if (rawNode.subscribers) rawNode.subscribers.delete(effectNode)\n }\n dependencies.clear()\n depVersions.clear()\n snapshotValues.clear()\n }\n }\n\n const actualOwnerNode = engine.activeOwner ? (engine.activeOwner._node || engine.activeOwner) : null\n\n if (actualOwnerNode && actualOwnerNode.ownedEffects) {\n actualOwnerNode.ownedEffects.add(effectNode)\n }\n\n effectNode.run()\n\n return () => {\n effectNode.dispose()\n }\n}\n"],"mappings":"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"}
|
|
@@ -124,7 +124,9 @@ function t(t, n, r, i) {
|
|
|
124
124
|
total: d,
|
|
125
125
|
nextDelayMs: Math.round(e)
|
|
126
126
|
} }
|
|
127
|
-
})
|
|
127
|
+
});
|
|
128
|
+
let n = r ? "таймауту" : "ошибке сети";
|
|
129
|
+
t.logger.isEnabled && console.warn(`[Resource Retry] "${o}" сбой по ${n}. Запрос ${a + 1} из ${d + 1} не удался. Ожидание повтора: ${Math.round(e)}ms`);
|
|
128
130
|
try {
|
|
129
131
|
if (await t.delay(e, i), i.aborted) return;
|
|
130
132
|
} catch {
|