@pravosleva/reactive-engine 0.2.2-beta → 0.2.4-beta
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/index.cjs +6 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.iife.js +6 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.mjs +230 -0
- package/dist/index.mjs.map +1 -0
- package/dist/vite.svg +1 -0
- package/package.json +1 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react");class h{activeEffect=null;isBatching=!1;pendingEffects=new Set;services=new Map;factories=new Map;proxyCache=new WeakMap;allEffects=new Set;onSignalChange;reactAdapters={useState:l.useState,useEffect:l.useEffect};provide(e,t){typeof t=="function"&&!t.prototype?this.factories.set(e,t):this.services.set(e,t)}inject(e){if(!e)throw new Error("[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.");if(this.services.has(e))return this.services.get(e);try{const t=this.factories.get(e);if(t){const r=t(this);return this.services.set(e,r),r}if(typeof e=="function"&&e.prototype){const r=new e(this);return this.services.set(e,r),r}throw new Error(`Service not found: ${String(e)}`)}catch(t){throw new Error(`[DI Error]: Не удалось создать сервис ${String(e)}. Ошибка: ${t?.message||"No e?.message"}`)}}signal(e,t){const r=this;let s=e;const a=new Set,o=typeof t=="string"?{name:t}:t||{},n=o.name||"unnamed_signal";return{get value(){return r.activeEffect&&a.add(r.activeEffect),s},set value(i){if(s===i)return;if(o.validate){const f=o.validate(i);if(f===!1||typeof f=="string"){const u=typeof f=="string"?f:`[Validation Error]: Некорректное значение для сигнала "${n}"`;console.error(`%c${u}`,"color: orange; font-weight: bold;",{received:i,current:s});return}}const c=s;s=i,r.onSignalChange?.(n,i,c),a.forEach(f=>r.isBatching?r.pendingEffects.add(f):f.run())},subscribe(i){return r.effect(()=>i(this.value))}}}effect(e){const t=this,r={cleanups:new Set,run(){this.cleanups.forEach(a=>a()),this.cleanups.clear();const s=t.activeEffect;t.activeEffect=this,t.safeRun(this,()=>{const a=e();typeof a=="function"&&this.cleanups.add(a)}),t.activeEffect=s}};return this.allEffects.add(r),r.run(),()=>{r.cleanups.forEach(s=>s()),t.pendingEffects.delete(r)}}computed(e,t){const r=this.signal(void 0,t||"unnamed_computed");return this.effect(()=>{const s=e();r.value=s}),{get value(){return r.value},subscribe:s=>r.subscribe(s)}}reactive(e,t="reactive"){if(this.proxyCache.has(e))return this.proxyCache.get(e);const r=this,s=new Map,a=new Proxy(e,{get(o,n,i){r.activeEffect&&(s.has(n)||s.set(n,new Set),s.get(n).add(r.activeEffect));const c=Reflect.get(o,n,i);return c!==null&&typeof c=="object"?r.reactive(c,`${t}.${String(n)}`):c},set(o,n,i,c){const f=Reflect.get(o,n,c);return f===i||f!==i&&(Reflect.set(o,n,i,c),r.onSignalChange?.(`${t}.${String(n)}`,i,f),s.get(n)?.forEach(u=>r.isBatching?r.pendingEffects.add(u):u.run())),!0}});return this.proxyCache.set(e,a),a}batch(e){this.isBatching=!0;try{e()}finally{queueMicrotask(()=>{const t=Array.from(this.pendingEffects);this.pendingEffects.clear(),this.isBatching=!1,t.forEach(r=>r.run())})}}resource(e,t,r){const s=this.signal({data:null,loading:!0,error:null},r||"unnamed_resource");let a=null;const o=async n=>{a?.abort(),a=new AbortController;const i=this.untrack(()=>s.value.data);s.value={data:i,loading:!0,error:null};try{const c=await e(n,a.signal);a.signal.aborted||(s.value={data:c,loading:!1,error:null})}catch(c){c.name!=="AbortError"&&(s.value={data:null,loading:!1,error:c})}};return this.effect(()=>{const n=t?t.value:void 0;return o(n),()=>a?.abort()}),{get data(){return s.value.data},get loading(){return s.value.loading},get error(){return s.value.error},get value(){return s.value},refetch:()=>o(t?t.value:void 0),subscribe:n=>s.subscribe(n)}}untrack(e){const t=this.activeEffect;this.activeEffect=null;try{return e()}finally{this.activeEffect=t}}setReactAdapters(e,t){this.reactAdapters={useState:e,useEffect:t}}use(e){if(!this.reactAdapters)throw new Error("[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).");if(!e||typeof e.subscribe!="function"){const s=`
|
|
2
|
+
[Reactive Error]: engine.use() получил некорректный объект!
|
|
3
|
+
Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.
|
|
4
|
+
Проверьте, что в классе написано: public mySignal = this.engine.signal(...)
|
|
5
|
+
`;throw console.error(s,{item:e}),new Error(s)}const[t,r]=this.reactAdapters.useState(e.value);return this.reactAdapters.useEffect(()=>e.subscribe(r),[e]),t}safeRun(e,t){try{t()}catch(r){console.error("%c[Reactive Error] %cОшибка в эффекте/computed:","color: white; background: red; padding: 2px 4px; border-radius: 3px;","font-weight: bold;",r)}}}class d{constructor(e){this.engine=e}engine;createNumericSignal(e,t){return this.engine.signal(e,{name:t,validate:r=>typeof r=="number"&&!isNaN(r)})}}exports.BaseREService=d;exports.ReactiveEngine=h;
|
|
6
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/core.ts","../src/BaseREService.ts"],"sourcesContent":["import { useState, useEffect } from 'react';\n\n// --- ТИПЫ ---\nexport type CleanupFn = () => void;\nexport type EffectFn = () => CleanupFn | void;\nexport type Token<T> = string | symbol | { new(engine: ReactiveEngine, ...args: any[]): T };\nexport type Factory<T> = (engine: ReactiveEngine) => T;\n\nexport interface IEffect {\n run: () => void;\n cleanups: Set<CleanupFn>;\n}\n\nexport interface ResourceState<T> {\n data: T | null;\n loading: boolean;\n error: any | null;\n}\n\nexport interface Signal<T> {\n value: T;\n subscribe: (cb: (val: T) => void) => CleanupFn;\n}\n\nexport interface Computed<T> {\n readonly value: T;\n subscribe: (cb: (val: T) => void) => CleanupFn;\n}\n\nexport interface Resource<T> extends ResourceState<T> {\n refetch: () => void;\n subscribe: (cb: (val: ResourceState<T>) => void) => CleanupFn;\n readonly value: ResourceState<T>;\n}\n\ninterface SignalOptions<T> {\n name?: string;\n validate?: (val: T) => boolean | string;\n}\n\n// --- ЯДРО ---\nexport class ReactiveEngine {\n private activeEffect: IEffect | null = null;\n private isBatching = false;\n private pendingEffects = new Set<IEffect>();\n private services = new Map<Token<any>, any>();\n private factories = new Map<Token<any>, Factory<any>>();\n private proxyCache = new WeakMap<object, any>();\n private allEffects = new Set<IEffect>();\n\n public onSignalChange?: (name: string, next: any, prev: any) => void;\n\n private reactAdapters = {\n useState: useState as any,\n useEffect: useEffect as any,\n };\n\n /** DI: Регистрация */\n public provide<T>(token: Token<T>, valueOrFactory: T | Factory<T>): void {\n if (typeof valueOrFactory === 'function' && !valueOrFactory.prototype) {\n this.factories.set(token, valueOrFactory as Factory<T>);\n } else {\n this.services.set(token, valueOrFactory);\n }\n }\n\n /** DI: Инъекция */\n public inject<T>(token: Token<T>): T {\n if (!token) {\n throw new Error(`[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.`);\n }\n\n if (this.services.has(token)) return this.services.get(token);\n\n // NOTE: (new way) Если это класс, но мы забыли его унаследовать от BaseService или передать engine\n try {\n // NOTE: Логика создания инстанса\n const factory = this.factories.get(token);\n if (factory) {\n const instance = factory(this);\n this.services.set(token, instance);\n return instance;\n }\n if (typeof token === 'function' && token.prototype) {\n const instance = new (token as { new(eng: ReactiveEngine): T })(this);\n this.services.set(token, instance);\n return instance;\n }\n throw new Error(`Service not found: ${String(token)}`);\n } catch (e) {\n throw new Error(`[DI Error]: Не удалось создать сервис ${String(token)}. Ошибка: ${(e as Error)?.message || 'No e?.message'}`);\n }\n }\n\n /** Создание Сигнала */\n public signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T> {\n const engine = this;\n let val = initialValue;\n const subscribers = new Set<IEffect>();\n\n // Парсим аргументы для обратной совместимости\n const options = typeof optionsOrName === 'string'\n ? { name: optionsOrName }\n : optionsOrName || {};\n\n const name = options.name || 'unnamed_signal';\n\n return {\n get value(): T {\n if (engine.activeEffect) subscribers.add(engine.activeEffect);\n return val;\n },\n set value(newValue: T) {\n if (val === newValue) return;\n\n // ВАЛИДАЦИЯ В RUNTIME\n if (options.validate) {\n const result = options.validate(newValue);\n if (result === false || typeof result === 'string') {\n const errorMsg = typeof result === 'string'\n ? result\n : `[Validation Error]: Некорректное значение для сигнала \"${name}\"`;\n\n console.error(`%c${errorMsg}`, \"color: orange; font-weight: bold;\", {\n received: newValue,\n current: val\n });\n return; // Прерываем обновление, если данные не валидны\n }\n }\n\n const old = val;\n val = newValue;\n engine.onSignalChange?.(name, newValue, old);\n subscribers.forEach(e =>\n engine.isBatching ? engine.pendingEffects.add(e) : e.run()\n );\n },\n subscribe(cb) {\n return engine.effect(() => cb(this.value));\n }\n };\n }\n\n /** Эффект */\n public effect(fn: EffectFn): CleanupFn {\n const engine = this;\n const effectObj: IEffect = {\n cleanups: new Set(),\n run() {\n this.cleanups.forEach(c => c());\n this.cleanups.clear();\n const prev = engine.activeEffect;\n engine.activeEffect = this;\n engine.safeRun(this, () => {\n const cleanup = fn();\n if (typeof cleanup === 'function') this.cleanups.add(cleanup);\n });\n engine.activeEffect = prev;\n }\n };\n this.allEffects.add(effectObj); // Регистрируем эффект в глобальном списке\n effectObj.run();\n return () => {\n effectObj.cleanups.forEach(c => c());\n engine.pendingEffects.delete(effectObj);\n };\n }\n\n /** Вычисляемое значение */\n public computed<T>(fn: () => T, signalName?: string): Computed<T> {\n const sig = this.signal<T>(undefined as any, signalName || 'unnamed_computed');\n this.effect(() => {\n const newValue = fn();\n // Сигнал сам внутри себя проверит (sig.value === newValue)\n // благодаря правке в пункте №1\n sig.value = newValue;\n });\n return {\n get value() { return sig.value; },\n // Подписываемся на внутренний сигнал\n subscribe: (cb) => sig.subscribe(cb)\n };\n }\n\n /** Реактивный объект (Proxy) */\n public reactive<T extends object>(target: T, name: string = 'reactive'): T {\n if (this.proxyCache.has(target)) return this.proxyCache.get(target);\n const engine = this;\n const propsSubscribers = new Map<string | symbol, Set<IEffect>>();\n\n const proxy = new Proxy(target, {\n get(obj, prop, receiver) {\n if (engine.activeEffect) {\n if (!propsSubscribers.has(prop)) propsSubscribers.set(prop, new Set());\n propsSubscribers.get(prop)!.add(engine.activeEffect);\n }\n const value = Reflect.get(obj, prop, receiver);\n return (value !== null && typeof value === 'object')\n ? engine.reactive(value, `${name}.${String(prop)}`)\n : value;\n },\n set(obj, prop, value, receiver) {\n const old = Reflect.get(obj, prop, receiver);\n // ПРОВЕРКА НА ИДЕНТИЧНОСТЬ\n if (old === value) return true;\n\n if (old !== value) {\n Reflect.set(obj, prop, value, receiver);\n engine.onSignalChange?.(`${name}.${String(prop)}`, value, old);\n propsSubscribers.get(prop)?.forEach(e =>\n engine.isBatching ? engine.pendingEffects.add(e) : e.run()\n );\n }\n return true;\n }\n });\n this.proxyCache.set(target, proxy);\n return proxy;\n }\n\n /** Группировка изменений */\n public batch(fn: () => void): void {\n this.isBatching = true;\n try { fn(); } finally {\n queueMicrotask(() => {\n const effects = Array.from(this.pendingEffects);\n this.pendingEffects.clear();\n this.isBatching = false;\n effects.forEach(e => e.run());\n });\n }\n }\n\n /** Асинхронный ресурс */\n public resource<T, S = void>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n source?: { value: S },\n signalName?: string,\n ): Resource<T> {\n const state = this.signal<ResourceState<T>>({ data: null, loading: true, error: null }, signalName || 'unnamed_resource');\n let controller: AbortController | null = null;\n\n const load = async (sValue: S) => {\n controller?.abort();\n controller = new AbortController();\n\n // Читаем текущие данные без создания зависимости!\n const currentData = this.untrack(() => state.value.data);\n\n // Теперь обновление состояния не вызовет перезапуск эффекта\n state.value = { data: currentData, loading: true, error: null };\n\n try {\n const data = await fetcher(sValue, controller.signal);\n if (!controller.signal.aborted) {\n state.value = { data, loading: false, error: null };\n }\n } catch (e: any) {\n if (e.name !== 'AbortError') {\n state.value = { data: null, loading: false, error: e };\n }\n }\n };\n\n // Чтобы эффект не подписывался на state,\n // нам нужно изолировать чтение source от чтения state\n this.effect(() => {\n // Читаем ТОЛЬКО source. Это наша единственная зависимость.\n const sValue = source ? source.value : undefined as S;\n\n // Вызываем load. Внутри load чтение state.value\n // не должно регистрироваться как зависимость этого эффекта.\n load(sValue);\n\n return () => controller?.abort();\n });\n\n return {\n get data() { return state.value.data; },\n get loading() { return state.value.loading; },\n get error() { return state.value.error; },\n get value() { return state.value; },\n refetch: () => load(source ? source.value : undefined as S),\n subscribe: (cb) => state.subscribe(cb)\n };\n }\n\n /**\n * Выполняет функцию без отслеживания зависимостей\n */\n public untrack<T>(fn: () => T): T {\n const prev = this.activeEffect;\n this.activeEffect = null; // Временно \"забываем\" про активный эффект\n try {\n return fn();\n } finally {\n this.activeEffect = prev; // Возвращаем эффект на место\n }\n }\n\n /** React Хук */\n public setReactAdapters(useState: any, useEffect: any) {\n this.reactAdapters = { useState, useEffect };\n }\n\n public use<T>(item: { value: T; subscribe: (cb: (v: T) => void) => CleanupFn }): T {\n if (!this.reactAdapters) {\n throw new Error(\"[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).\");\n }\n\n // NOTE: (защита) проверяем, что нам передали объект сигнала\n if (!item || typeof item.subscribe !== 'function') {\n const errorMsg = `\n [Reactive Error]: engine.use() получил некорректный объект!\n Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.\n Проверьте, что в классе написано: public mySignal = this.engine.signal(...)\n `;\n console.error(errorMsg, { item });\n throw new Error(errorMsg);\n }\n const [val, setVal] = this.reactAdapters.useState(item.value);\n\n this.reactAdapters.useEffect(\n () => {\n return item.subscribe(setVal);\n },\n [item]\n );\n\n return val;\n }\n\n private safeRun(effect: IEffect, fn: () => void) {\n try {\n fn();\n } catch (error) {\n console.error(\n `%c[Reactive Error] %cОшибка в эффекте/computed:`,\n \"color: white; background: red; padding: 2px 4px; border-radius: 3px;\",\n \"font-weight: bold;\",\n error\n );\n // Здесь можно отправить ошибку в Sentry или другой сервис мониторинга\n }\n }\n}\n","import { ReactiveEngine } from './core';\n\n// export abstract class BaseService {\n// constructor(protected engine: ReactiveEngine) {\n// // Вызываем метод инициализации, который можно переопределить в наследниках\n// this.onInit();\n// }\n\n// // NOTE: Жизненный цикл: вызывается сразу после создания сервиса.\n// // Удобно для инициализации сигналов, которые зависят от engine.\n// protected onInit(): void {}\n\n// // NOTE: Полезные хелперы для сокращения кода\n// protected createSignal<T>(val: T, name?: string) {\n// return this.engine.signal(val, name);\n// }\n\n// protected createComputed<T>(fn: () => T) {\n// return this.engine.computed(fn);\n// }\n// }\n\nexport abstract class BaseREService {\n constructor(protected engine: ReactiveEngine) { } // Просто сохраняем engine\n\n protected createNumericSignal(val: number, name: string) {\n return this.engine.signal(val, {\n name,\n validate: (v) => typeof v === 'number' && !isNaN(v)\n });\n }\n}\n"],"names":["ReactiveEngine","useState","useEffect","token","valueOrFactory","factory","instance","e","initialValue","optionsOrName","engine","val","subscribers","options","name","newValue","result","errorMsg","old","cb","fn","effectObj","c","prev","cleanup","signalName","sig","target","propsSubscribers","proxy","obj","prop","receiver","value","effects","fetcher","source","state","controller","load","sValue","currentData","data","item","setVal","effect","error","BaseREService","v"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export declare abstract class BaseREService {
|
|
2
|
+
protected engine: ReactiveEngine;
|
|
3
|
+
constructor(engine: ReactiveEngine);
|
|
4
|
+
protected createNumericSignal(val: number, name: string): Signal<number>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export declare type CleanupFn = () => void;
|
|
8
|
+
|
|
9
|
+
export declare interface Computed<T> {
|
|
10
|
+
readonly value: T;
|
|
11
|
+
subscribe: (cb: (val: T) => void) => CleanupFn;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export declare type EffectFn = () => CleanupFn | void;
|
|
15
|
+
|
|
16
|
+
export declare type Factory<T> = (engine: ReactiveEngine) => T;
|
|
17
|
+
|
|
18
|
+
export declare interface IEffect {
|
|
19
|
+
run: () => void;
|
|
20
|
+
cleanups: Set<CleanupFn>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export declare class ReactiveEngine {
|
|
24
|
+
private activeEffect;
|
|
25
|
+
private isBatching;
|
|
26
|
+
private pendingEffects;
|
|
27
|
+
private services;
|
|
28
|
+
private factories;
|
|
29
|
+
private proxyCache;
|
|
30
|
+
private allEffects;
|
|
31
|
+
onSignalChange?: (name: string, next: any, prev: any) => void;
|
|
32
|
+
private reactAdapters;
|
|
33
|
+
/** DI: Регистрация */
|
|
34
|
+
provide<T>(token: Token<T>, valueOrFactory: T | Factory<T>): void;
|
|
35
|
+
/** DI: Инъекция */
|
|
36
|
+
inject<T>(token: Token<T>): T;
|
|
37
|
+
/** Создание Сигнала */
|
|
38
|
+
signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T>;
|
|
39
|
+
/** Эффект */
|
|
40
|
+
effect(fn: EffectFn): CleanupFn;
|
|
41
|
+
/** Вычисляемое значение */
|
|
42
|
+
computed<T>(fn: () => T, signalName?: string): Computed<T>;
|
|
43
|
+
/** Реактивный объект (Proxy) */
|
|
44
|
+
reactive<T extends object>(target: T, name?: string): T;
|
|
45
|
+
/** Группировка изменений */
|
|
46
|
+
batch(fn: () => void): void;
|
|
47
|
+
/** Асинхронный ресурс */
|
|
48
|
+
resource<T, S = void>(fetcher: (source: S, signal: AbortSignal) => Promise<T>, source?: {
|
|
49
|
+
value: S;
|
|
50
|
+
}, signalName?: string): Resource<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Выполняет функцию без отслеживания зависимостей
|
|
53
|
+
*/
|
|
54
|
+
untrack<T>(fn: () => T): T;
|
|
55
|
+
/** React Хук */
|
|
56
|
+
setReactAdapters(useState: any, useEffect: any): void;
|
|
57
|
+
use<T>(item: {
|
|
58
|
+
value: T;
|
|
59
|
+
subscribe: (cb: (v: T) => void) => CleanupFn;
|
|
60
|
+
}): T;
|
|
61
|
+
private safeRun;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export declare interface Resource<T> extends ResourceState<T> {
|
|
65
|
+
refetch: () => void;
|
|
66
|
+
subscribe: (cb: (val: ResourceState<T>) => void) => CleanupFn;
|
|
67
|
+
readonly value: ResourceState<T>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export declare interface ResourceState<T> {
|
|
71
|
+
data: T | null;
|
|
72
|
+
loading: boolean;
|
|
73
|
+
error: any | null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export declare interface Signal<T> {
|
|
77
|
+
value: T;
|
|
78
|
+
subscribe: (cb: (val: T) => void) => CleanupFn;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
declare interface SignalOptions<T> {
|
|
82
|
+
name?: string;
|
|
83
|
+
validate?: (val: T) => boolean | string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export declare type Token<T> = string | symbol | {
|
|
87
|
+
new (engine: ReactiveEngine, ...args: any[]): T;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export { }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var MyLib=(function(u,g){"use strict";class h{activeEffect=null;isBatching=!1;pendingEffects=new Set;services=new Map;factories=new Map;proxyCache=new WeakMap;allEffects=new Set;onSignalChange;reactAdapters={useState:g.useState,useEffect:g.useEffect};provide(e,t){typeof t=="function"&&!t.prototype?this.factories.set(e,t):this.services.set(e,t)}inject(e){if(!e)throw new Error("[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.");if(this.services.has(e))return this.services.get(e);try{const t=this.factories.get(e);if(t){const r=t(this);return this.services.set(e,r),r}if(typeof e=="function"&&e.prototype){const r=new e(this);return this.services.set(e,r),r}throw new Error(`Service not found: ${String(e)}`)}catch(t){throw new Error(`[DI Error]: Не удалось создать сервис ${String(e)}. Ошибка: ${t?.message||"No e?.message"}`)}}signal(e,t){const r=this;let n=e;const a=new Set,f=typeof t=="string"?{name:t}:t||{},s=f.name||"unnamed_signal";return{get value(){return r.activeEffect&&a.add(r.activeEffect),n},set value(i){if(n===i)return;if(f.validate){const o=f.validate(i);if(o===!1||typeof o=="string"){const l=typeof o=="string"?o:`[Validation Error]: Некорректное значение для сигнала "${s}"`;console.error(`%c${l}`,"color: orange; font-weight: bold;",{received:i,current:n});return}}const c=n;n=i,r.onSignalChange?.(s,i,c),a.forEach(o=>r.isBatching?r.pendingEffects.add(o):o.run())},subscribe(i){return r.effect(()=>i(this.value))}}}effect(e){const t=this,r={cleanups:new Set,run(){this.cleanups.forEach(a=>a()),this.cleanups.clear();const n=t.activeEffect;t.activeEffect=this,t.safeRun(this,()=>{const a=e();typeof a=="function"&&this.cleanups.add(a)}),t.activeEffect=n}};return this.allEffects.add(r),r.run(),()=>{r.cleanups.forEach(n=>n()),t.pendingEffects.delete(r)}}computed(e,t){const r=this.signal(void 0,t||"unnamed_computed");return this.effect(()=>{const n=e();r.value=n}),{get value(){return r.value},subscribe:n=>r.subscribe(n)}}reactive(e,t="reactive"){if(this.proxyCache.has(e))return this.proxyCache.get(e);const r=this,n=new Map,a=new Proxy(e,{get(f,s,i){r.activeEffect&&(n.has(s)||n.set(s,new Set),n.get(s).add(r.activeEffect));const c=Reflect.get(f,s,i);return c!==null&&typeof c=="object"?r.reactive(c,`${t}.${String(s)}`):c},set(f,s,i,c){const o=Reflect.get(f,s,c);return o===i||o!==i&&(Reflect.set(f,s,i,c),r.onSignalChange?.(`${t}.${String(s)}`,i,o),n.get(s)?.forEach(l=>r.isBatching?r.pendingEffects.add(l):l.run())),!0}});return this.proxyCache.set(e,a),a}batch(e){this.isBatching=!0;try{e()}finally{queueMicrotask(()=>{const t=Array.from(this.pendingEffects);this.pendingEffects.clear(),this.isBatching=!1,t.forEach(r=>r.run())})}}resource(e,t,r){const n=this.signal({data:null,loading:!0,error:null},r||"unnamed_resource");let a=null;const f=async s=>{a?.abort(),a=new AbortController;const i=this.untrack(()=>n.value.data);n.value={data:i,loading:!0,error:null};try{const c=await e(s,a.signal);a.signal.aborted||(n.value={data:c,loading:!1,error:null})}catch(c){c.name!=="AbortError"&&(n.value={data:null,loading:!1,error:c})}};return this.effect(()=>{const s=t?t.value:void 0;return f(s),()=>a?.abort()}),{get data(){return n.value.data},get loading(){return n.value.loading},get error(){return n.value.error},get value(){return n.value},refetch:()=>f(t?t.value:void 0),subscribe:s=>n.subscribe(s)}}untrack(e){const t=this.activeEffect;this.activeEffect=null;try{return e()}finally{this.activeEffect=t}}setReactAdapters(e,t){this.reactAdapters={useState:e,useEffect:t}}use(e){if(!this.reactAdapters)throw new Error("[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).");if(!e||typeof e.subscribe!="function"){const n=`
|
|
2
|
+
[Reactive Error]: engine.use() получил некорректный объект!
|
|
3
|
+
Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.
|
|
4
|
+
Проверьте, что в классе написано: public mySignal = this.engine.signal(...)
|
|
5
|
+
`;throw console.error(n,{item:e}),new Error(n)}const[t,r]=this.reactAdapters.useState(e.value);return this.reactAdapters.useEffect(()=>e.subscribe(r),[e]),t}safeRun(e,t){try{t()}catch(r){console.error("%c[Reactive Error] %cОшибка в эффекте/computed:","color: white; background: red; padding: 2px 4px; border-radius: 3px;","font-weight: bold;",r)}}}class d{constructor(e){this.engine=e}engine;createNumericSignal(e,t){return this.engine.signal(e,{name:t,validate:r=>typeof r=="number"&&!isNaN(r)})}}return u.BaseREService=d,u.ReactiveEngine=h,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"}),u})({},React);
|
|
6
|
+
//# sourceMappingURL=index.iife.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.iife.js","sources":["../src/core.ts","../src/BaseREService.ts"],"sourcesContent":["import { useState, useEffect } from 'react';\n\n// --- ТИПЫ ---\nexport type CleanupFn = () => void;\nexport type EffectFn = () => CleanupFn | void;\nexport type Token<T> = string | symbol | { new(engine: ReactiveEngine, ...args: any[]): T };\nexport type Factory<T> = (engine: ReactiveEngine) => T;\n\nexport interface IEffect {\n run: () => void;\n cleanups: Set<CleanupFn>;\n}\n\nexport interface ResourceState<T> {\n data: T | null;\n loading: boolean;\n error: any | null;\n}\n\nexport interface Signal<T> {\n value: T;\n subscribe: (cb: (val: T) => void) => CleanupFn;\n}\n\nexport interface Computed<T> {\n readonly value: T;\n subscribe: (cb: (val: T) => void) => CleanupFn;\n}\n\nexport interface Resource<T> extends ResourceState<T> {\n refetch: () => void;\n subscribe: (cb: (val: ResourceState<T>) => void) => CleanupFn;\n readonly value: ResourceState<T>;\n}\n\ninterface SignalOptions<T> {\n name?: string;\n validate?: (val: T) => boolean | string;\n}\n\n// --- ЯДРО ---\nexport class ReactiveEngine {\n private activeEffect: IEffect | null = null;\n private isBatching = false;\n private pendingEffects = new Set<IEffect>();\n private services = new Map<Token<any>, any>();\n private factories = new Map<Token<any>, Factory<any>>();\n private proxyCache = new WeakMap<object, any>();\n private allEffects = new Set<IEffect>();\n\n public onSignalChange?: (name: string, next: any, prev: any) => void;\n\n private reactAdapters = {\n useState: useState as any,\n useEffect: useEffect as any,\n };\n\n /** DI: Регистрация */\n public provide<T>(token: Token<T>, valueOrFactory: T | Factory<T>): void {\n if (typeof valueOrFactory === 'function' && !valueOrFactory.prototype) {\n this.factories.set(token, valueOrFactory as Factory<T>);\n } else {\n this.services.set(token, valueOrFactory);\n }\n }\n\n /** DI: Инъекция */\n public inject<T>(token: Token<T>): T {\n if (!token) {\n throw new Error(`[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.`);\n }\n\n if (this.services.has(token)) return this.services.get(token);\n\n // NOTE: (new way) Если это класс, но мы забыли его унаследовать от BaseService или передать engine\n try {\n // NOTE: Логика создания инстанса\n const factory = this.factories.get(token);\n if (factory) {\n const instance = factory(this);\n this.services.set(token, instance);\n return instance;\n }\n if (typeof token === 'function' && token.prototype) {\n const instance = new (token as { new(eng: ReactiveEngine): T })(this);\n this.services.set(token, instance);\n return instance;\n }\n throw new Error(`Service not found: ${String(token)}`);\n } catch (e) {\n throw new Error(`[DI Error]: Не удалось создать сервис ${String(token)}. Ошибка: ${(e as Error)?.message || 'No e?.message'}`);\n }\n }\n\n /** Создание Сигнала */\n public signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T> {\n const engine = this;\n let val = initialValue;\n const subscribers = new Set<IEffect>();\n\n // Парсим аргументы для обратной совместимости\n const options = typeof optionsOrName === 'string'\n ? { name: optionsOrName }\n : optionsOrName || {};\n\n const name = options.name || 'unnamed_signal';\n\n return {\n get value(): T {\n if (engine.activeEffect) subscribers.add(engine.activeEffect);\n return val;\n },\n set value(newValue: T) {\n if (val === newValue) return;\n\n // ВАЛИДАЦИЯ В RUNTIME\n if (options.validate) {\n const result = options.validate(newValue);\n if (result === false || typeof result === 'string') {\n const errorMsg = typeof result === 'string'\n ? result\n : `[Validation Error]: Некорректное значение для сигнала \"${name}\"`;\n\n console.error(`%c${errorMsg}`, \"color: orange; font-weight: bold;\", {\n received: newValue,\n current: val\n });\n return; // Прерываем обновление, если данные не валидны\n }\n }\n\n const old = val;\n val = newValue;\n engine.onSignalChange?.(name, newValue, old);\n subscribers.forEach(e =>\n engine.isBatching ? engine.pendingEffects.add(e) : e.run()\n );\n },\n subscribe(cb) {\n return engine.effect(() => cb(this.value));\n }\n };\n }\n\n /** Эффект */\n public effect(fn: EffectFn): CleanupFn {\n const engine = this;\n const effectObj: IEffect = {\n cleanups: new Set(),\n run() {\n this.cleanups.forEach(c => c());\n this.cleanups.clear();\n const prev = engine.activeEffect;\n engine.activeEffect = this;\n engine.safeRun(this, () => {\n const cleanup = fn();\n if (typeof cleanup === 'function') this.cleanups.add(cleanup);\n });\n engine.activeEffect = prev;\n }\n };\n this.allEffects.add(effectObj); // Регистрируем эффект в глобальном списке\n effectObj.run();\n return () => {\n effectObj.cleanups.forEach(c => c());\n engine.pendingEffects.delete(effectObj);\n };\n }\n\n /** Вычисляемое значение */\n public computed<T>(fn: () => T, signalName?: string): Computed<T> {\n const sig = this.signal<T>(undefined as any, signalName || 'unnamed_computed');\n this.effect(() => {\n const newValue = fn();\n // Сигнал сам внутри себя проверит (sig.value === newValue)\n // благодаря правке в пункте №1\n sig.value = newValue;\n });\n return {\n get value() { return sig.value; },\n // Подписываемся на внутренний сигнал\n subscribe: (cb) => sig.subscribe(cb)\n };\n }\n\n /** Реактивный объект (Proxy) */\n public reactive<T extends object>(target: T, name: string = 'reactive'): T {\n if (this.proxyCache.has(target)) return this.proxyCache.get(target);\n const engine = this;\n const propsSubscribers = new Map<string | symbol, Set<IEffect>>();\n\n const proxy = new Proxy(target, {\n get(obj, prop, receiver) {\n if (engine.activeEffect) {\n if (!propsSubscribers.has(prop)) propsSubscribers.set(prop, new Set());\n propsSubscribers.get(prop)!.add(engine.activeEffect);\n }\n const value = Reflect.get(obj, prop, receiver);\n return (value !== null && typeof value === 'object')\n ? engine.reactive(value, `${name}.${String(prop)}`)\n : value;\n },\n set(obj, prop, value, receiver) {\n const old = Reflect.get(obj, prop, receiver);\n // ПРОВЕРКА НА ИДЕНТИЧНОСТЬ\n if (old === value) return true;\n\n if (old !== value) {\n Reflect.set(obj, prop, value, receiver);\n engine.onSignalChange?.(`${name}.${String(prop)}`, value, old);\n propsSubscribers.get(prop)?.forEach(e =>\n engine.isBatching ? engine.pendingEffects.add(e) : e.run()\n );\n }\n return true;\n }\n });\n this.proxyCache.set(target, proxy);\n return proxy;\n }\n\n /** Группировка изменений */\n public batch(fn: () => void): void {\n this.isBatching = true;\n try { fn(); } finally {\n queueMicrotask(() => {\n const effects = Array.from(this.pendingEffects);\n this.pendingEffects.clear();\n this.isBatching = false;\n effects.forEach(e => e.run());\n });\n }\n }\n\n /** Асинхронный ресурс */\n public resource<T, S = void>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n source?: { value: S },\n signalName?: string,\n ): Resource<T> {\n const state = this.signal<ResourceState<T>>({ data: null, loading: true, error: null }, signalName || 'unnamed_resource');\n let controller: AbortController | null = null;\n\n const load = async (sValue: S) => {\n controller?.abort();\n controller = new AbortController();\n\n // Читаем текущие данные без создания зависимости!\n const currentData = this.untrack(() => state.value.data);\n\n // Теперь обновление состояния не вызовет перезапуск эффекта\n state.value = { data: currentData, loading: true, error: null };\n\n try {\n const data = await fetcher(sValue, controller.signal);\n if (!controller.signal.aborted) {\n state.value = { data, loading: false, error: null };\n }\n } catch (e: any) {\n if (e.name !== 'AbortError') {\n state.value = { data: null, loading: false, error: e };\n }\n }\n };\n\n // Чтобы эффект не подписывался на state,\n // нам нужно изолировать чтение source от чтения state\n this.effect(() => {\n // Читаем ТОЛЬКО source. Это наша единственная зависимость.\n const sValue = source ? source.value : undefined as S;\n\n // Вызываем load. Внутри load чтение state.value\n // не должно регистрироваться как зависимость этого эффекта.\n load(sValue);\n\n return () => controller?.abort();\n });\n\n return {\n get data() { return state.value.data; },\n get loading() { return state.value.loading; },\n get error() { return state.value.error; },\n get value() { return state.value; },\n refetch: () => load(source ? source.value : undefined as S),\n subscribe: (cb) => state.subscribe(cb)\n };\n }\n\n /**\n * Выполняет функцию без отслеживания зависимостей\n */\n public untrack<T>(fn: () => T): T {\n const prev = this.activeEffect;\n this.activeEffect = null; // Временно \"забываем\" про активный эффект\n try {\n return fn();\n } finally {\n this.activeEffect = prev; // Возвращаем эффект на место\n }\n }\n\n /** React Хук */\n public setReactAdapters(useState: any, useEffect: any) {\n this.reactAdapters = { useState, useEffect };\n }\n\n public use<T>(item: { value: T; subscribe: (cb: (v: T) => void) => CleanupFn }): T {\n if (!this.reactAdapters) {\n throw new Error(\"[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).\");\n }\n\n // NOTE: (защита) проверяем, что нам передали объект сигнала\n if (!item || typeof item.subscribe !== 'function') {\n const errorMsg = `\n [Reactive Error]: engine.use() получил некорректный объект!\n Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.\n Проверьте, что в классе написано: public mySignal = this.engine.signal(...)\n `;\n console.error(errorMsg, { item });\n throw new Error(errorMsg);\n }\n const [val, setVal] = this.reactAdapters.useState(item.value);\n\n this.reactAdapters.useEffect(\n () => {\n return item.subscribe(setVal);\n },\n [item]\n );\n\n return val;\n }\n\n private safeRun(effect: IEffect, fn: () => void) {\n try {\n fn();\n } catch (error) {\n console.error(\n `%c[Reactive Error] %cОшибка в эффекте/computed:`,\n \"color: white; background: red; padding: 2px 4px; border-radius: 3px;\",\n \"font-weight: bold;\",\n error\n );\n // Здесь можно отправить ошибку в Sentry или другой сервис мониторинга\n }\n }\n}\n","import { ReactiveEngine } from './core';\n\n// export abstract class BaseService {\n// constructor(protected engine: ReactiveEngine) {\n// // Вызываем метод инициализации, который можно переопределить в наследниках\n// this.onInit();\n// }\n\n// // NOTE: Жизненный цикл: вызывается сразу после создания сервиса.\n// // Удобно для инициализации сигналов, которые зависят от engine.\n// protected onInit(): void {}\n\n// // NOTE: Полезные хелперы для сокращения кода\n// protected createSignal<T>(val: T, name?: string) {\n// return this.engine.signal(val, name);\n// }\n\n// protected createComputed<T>(fn: () => T) {\n// return this.engine.computed(fn);\n// }\n// }\n\nexport abstract class BaseREService {\n constructor(protected engine: ReactiveEngine) { } // Просто сохраняем engine\n\n protected createNumericSignal(val: number, name: string) {\n return this.engine.signal(val, {\n name,\n validate: (v) => typeof v === 'number' && !isNaN(v)\n });\n }\n}\n"],"names":["ReactiveEngine","useState","useEffect","token","valueOrFactory","factory","instance","e","initialValue","optionsOrName","engine","val","subscribers","options","name","newValue","result","errorMsg","old","cb","fn","effectObj","c","prev","cleanup","signalName","sig","target","propsSubscribers","proxy","obj","prop","receiver","value","effects","fetcher","source","state","controller","load","sValue","currentData","data","item","setVal","effect","error","BaseREService","v"],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { useEffect as h, useState as g } from "react";
|
|
2
|
+
class v {
|
|
3
|
+
activeEffect = null;
|
|
4
|
+
isBatching = !1;
|
|
5
|
+
pendingEffects = /* @__PURE__ */ new Set();
|
|
6
|
+
services = /* @__PURE__ */ new Map();
|
|
7
|
+
factories = /* @__PURE__ */ new Map();
|
|
8
|
+
proxyCache = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
allEffects = /* @__PURE__ */ new Set();
|
|
10
|
+
onSignalChange;
|
|
11
|
+
reactAdapters = {
|
|
12
|
+
useState: g,
|
|
13
|
+
useEffect: h
|
|
14
|
+
};
|
|
15
|
+
/** DI: Регистрация */
|
|
16
|
+
provide(e, t) {
|
|
17
|
+
typeof t == "function" && !t.prototype ? this.factories.set(e, t) : this.services.set(e, t);
|
|
18
|
+
}
|
|
19
|
+
/** DI: Инъекция */
|
|
20
|
+
inject(e) {
|
|
21
|
+
if (!e)
|
|
22
|
+
throw new Error("[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.");
|
|
23
|
+
if (this.services.has(e)) return this.services.get(e);
|
|
24
|
+
try {
|
|
25
|
+
const t = this.factories.get(e);
|
|
26
|
+
if (t) {
|
|
27
|
+
const r = t(this);
|
|
28
|
+
return this.services.set(e, r), r;
|
|
29
|
+
}
|
|
30
|
+
if (typeof e == "function" && e.prototype) {
|
|
31
|
+
const r = new e(this);
|
|
32
|
+
return this.services.set(e, r), r;
|
|
33
|
+
}
|
|
34
|
+
throw new Error(`Service not found: ${String(e)}`);
|
|
35
|
+
} catch (t) {
|
|
36
|
+
throw new Error(`[DI Error]: Не удалось создать сервис ${String(e)}. Ошибка: ${t?.message || "No e?.message"}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Создание Сигнала */
|
|
40
|
+
signal(e, t) {
|
|
41
|
+
const r = this;
|
|
42
|
+
let s = e;
|
|
43
|
+
const a = /* @__PURE__ */ new Set(), o = typeof t == "string" ? { name: t } : t || {}, n = o.name || "unnamed_signal";
|
|
44
|
+
return {
|
|
45
|
+
get value() {
|
|
46
|
+
return r.activeEffect && a.add(r.activeEffect), s;
|
|
47
|
+
},
|
|
48
|
+
set value(i) {
|
|
49
|
+
if (s === i) return;
|
|
50
|
+
if (o.validate) {
|
|
51
|
+
const f = o.validate(i);
|
|
52
|
+
if (f === !1 || typeof f == "string") {
|
|
53
|
+
const u = typeof f == "string" ? f : `[Validation Error]: Некорректное значение для сигнала "${n}"`;
|
|
54
|
+
console.error(`%c${u}`, "color: orange; font-weight: bold;", {
|
|
55
|
+
received: i,
|
|
56
|
+
current: s
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const c = s;
|
|
62
|
+
s = i, r.onSignalChange?.(n, i, c), a.forEach(
|
|
63
|
+
(f) => r.isBatching ? r.pendingEffects.add(f) : f.run()
|
|
64
|
+
);
|
|
65
|
+
},
|
|
66
|
+
subscribe(i) {
|
|
67
|
+
return r.effect(() => i(this.value));
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Эффект */
|
|
72
|
+
effect(e) {
|
|
73
|
+
const t = this, r = {
|
|
74
|
+
cleanups: /* @__PURE__ */ new Set(),
|
|
75
|
+
run() {
|
|
76
|
+
this.cleanups.forEach((a) => a()), this.cleanups.clear();
|
|
77
|
+
const s = t.activeEffect;
|
|
78
|
+
t.activeEffect = this, t.safeRun(this, () => {
|
|
79
|
+
const a = e();
|
|
80
|
+
typeof a == "function" && this.cleanups.add(a);
|
|
81
|
+
}), t.activeEffect = s;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return this.allEffects.add(r), r.run(), () => {
|
|
85
|
+
r.cleanups.forEach((s) => s()), t.pendingEffects.delete(r);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Вычисляемое значение */
|
|
89
|
+
computed(e, t) {
|
|
90
|
+
const r = this.signal(void 0, t || "unnamed_computed");
|
|
91
|
+
return this.effect(() => {
|
|
92
|
+
const s = e();
|
|
93
|
+
r.value = s;
|
|
94
|
+
}), {
|
|
95
|
+
get value() {
|
|
96
|
+
return r.value;
|
|
97
|
+
},
|
|
98
|
+
// Подписываемся на внутренний сигнал
|
|
99
|
+
subscribe: (s) => r.subscribe(s)
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Реактивный объект (Proxy) */
|
|
103
|
+
reactive(e, t = "reactive") {
|
|
104
|
+
if (this.proxyCache.has(e)) return this.proxyCache.get(e);
|
|
105
|
+
const r = this, s = /* @__PURE__ */ new Map(), a = new Proxy(e, {
|
|
106
|
+
get(o, n, i) {
|
|
107
|
+
r.activeEffect && (s.has(n) || s.set(n, /* @__PURE__ */ new Set()), s.get(n).add(r.activeEffect));
|
|
108
|
+
const c = Reflect.get(o, n, i);
|
|
109
|
+
return c !== null && typeof c == "object" ? r.reactive(c, `${t}.${String(n)}`) : c;
|
|
110
|
+
},
|
|
111
|
+
set(o, n, i, c) {
|
|
112
|
+
const f = Reflect.get(o, n, c);
|
|
113
|
+
return f === i || f !== i && (Reflect.set(o, n, i, c), r.onSignalChange?.(`${t}.${String(n)}`, i, f), s.get(n)?.forEach(
|
|
114
|
+
(u) => r.isBatching ? r.pendingEffects.add(u) : u.run()
|
|
115
|
+
)), !0;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
return this.proxyCache.set(e, a), a;
|
|
119
|
+
}
|
|
120
|
+
/** Группировка изменений */
|
|
121
|
+
batch(e) {
|
|
122
|
+
this.isBatching = !0;
|
|
123
|
+
try {
|
|
124
|
+
e();
|
|
125
|
+
} finally {
|
|
126
|
+
queueMicrotask(() => {
|
|
127
|
+
const t = Array.from(this.pendingEffects);
|
|
128
|
+
this.pendingEffects.clear(), this.isBatching = !1, t.forEach((r) => r.run());
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** Асинхронный ресурс */
|
|
133
|
+
resource(e, t, r) {
|
|
134
|
+
const s = this.signal({ data: null, loading: !0, error: null }, r || "unnamed_resource");
|
|
135
|
+
let a = null;
|
|
136
|
+
const o = async (n) => {
|
|
137
|
+
a?.abort(), a = new AbortController();
|
|
138
|
+
const i = this.untrack(() => s.value.data);
|
|
139
|
+
s.value = { data: i, loading: !0, error: null };
|
|
140
|
+
try {
|
|
141
|
+
const c = await e(n, a.signal);
|
|
142
|
+
a.signal.aborted || (s.value = { data: c, loading: !1, error: null });
|
|
143
|
+
} catch (c) {
|
|
144
|
+
c.name !== "AbortError" && (s.value = { data: null, loading: !1, error: c });
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
return this.effect(() => {
|
|
148
|
+
const n = t ? t.value : void 0;
|
|
149
|
+
return o(n), () => a?.abort();
|
|
150
|
+
}), {
|
|
151
|
+
get data() {
|
|
152
|
+
return s.value.data;
|
|
153
|
+
},
|
|
154
|
+
get loading() {
|
|
155
|
+
return s.value.loading;
|
|
156
|
+
},
|
|
157
|
+
get error() {
|
|
158
|
+
return s.value.error;
|
|
159
|
+
},
|
|
160
|
+
get value() {
|
|
161
|
+
return s.value;
|
|
162
|
+
},
|
|
163
|
+
refetch: () => o(t ? t.value : void 0),
|
|
164
|
+
subscribe: (n) => s.subscribe(n)
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Выполняет функцию без отслеживания зависимостей
|
|
169
|
+
*/
|
|
170
|
+
untrack(e) {
|
|
171
|
+
const t = this.activeEffect;
|
|
172
|
+
this.activeEffect = null;
|
|
173
|
+
try {
|
|
174
|
+
return e();
|
|
175
|
+
} finally {
|
|
176
|
+
this.activeEffect = t;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/** React Хук */
|
|
180
|
+
setReactAdapters(e, t) {
|
|
181
|
+
this.reactAdapters = { useState: e, useEffect: t };
|
|
182
|
+
}
|
|
183
|
+
use(e) {
|
|
184
|
+
if (!this.reactAdapters)
|
|
185
|
+
throw new Error("[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).");
|
|
186
|
+
if (!e || typeof e.subscribe != "function") {
|
|
187
|
+
const s = `
|
|
188
|
+
[Reactive Error]: engine.use() получил некорректный объект!
|
|
189
|
+
Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.
|
|
190
|
+
Проверьте, что в классе написано: public mySignal = this.engine.signal(...)
|
|
191
|
+
`;
|
|
192
|
+
throw console.error(s, { item: e }), new Error(s);
|
|
193
|
+
}
|
|
194
|
+
const [t, r] = this.reactAdapters.useState(e.value);
|
|
195
|
+
return this.reactAdapters.useEffect(
|
|
196
|
+
() => e.subscribe(r),
|
|
197
|
+
[e]
|
|
198
|
+
), t;
|
|
199
|
+
}
|
|
200
|
+
safeRun(e, t) {
|
|
201
|
+
try {
|
|
202
|
+
t();
|
|
203
|
+
} catch (r) {
|
|
204
|
+
console.error(
|
|
205
|
+
"%c[Reactive Error] %cОшибка в эффекте/computed:",
|
|
206
|
+
"color: white; background: red; padding: 2px 4px; border-radius: 3px;",
|
|
207
|
+
"font-weight: bold;",
|
|
208
|
+
r
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
class E {
|
|
214
|
+
constructor(e) {
|
|
215
|
+
this.engine = e;
|
|
216
|
+
}
|
|
217
|
+
engine;
|
|
218
|
+
// Просто сохраняем engine
|
|
219
|
+
createNumericSignal(e, t) {
|
|
220
|
+
return this.engine.signal(e, {
|
|
221
|
+
name: t,
|
|
222
|
+
validate: (r) => typeof r == "number" && !isNaN(r)
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
export {
|
|
227
|
+
E as BaseREService,
|
|
228
|
+
v as ReactiveEngine
|
|
229
|
+
};
|
|
230
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/core.ts","../src/BaseREService.ts"],"sourcesContent":["import { useState, useEffect } from 'react';\n\n// --- ТИПЫ ---\nexport type CleanupFn = () => void;\nexport type EffectFn = () => CleanupFn | void;\nexport type Token<T> = string | symbol | { new(engine: ReactiveEngine, ...args: any[]): T };\nexport type Factory<T> = (engine: ReactiveEngine) => T;\n\nexport interface IEffect {\n run: () => void;\n cleanups: Set<CleanupFn>;\n}\n\nexport interface ResourceState<T> {\n data: T | null;\n loading: boolean;\n error: any | null;\n}\n\nexport interface Signal<T> {\n value: T;\n subscribe: (cb: (val: T) => void) => CleanupFn;\n}\n\nexport interface Computed<T> {\n readonly value: T;\n subscribe: (cb: (val: T) => void) => CleanupFn;\n}\n\nexport interface Resource<T> extends ResourceState<T> {\n refetch: () => void;\n subscribe: (cb: (val: ResourceState<T>) => void) => CleanupFn;\n readonly value: ResourceState<T>;\n}\n\ninterface SignalOptions<T> {\n name?: string;\n validate?: (val: T) => boolean | string;\n}\n\n// --- ЯДРО ---\nexport class ReactiveEngine {\n private activeEffect: IEffect | null = null;\n private isBatching = false;\n private pendingEffects = new Set<IEffect>();\n private services = new Map<Token<any>, any>();\n private factories = new Map<Token<any>, Factory<any>>();\n private proxyCache = new WeakMap<object, any>();\n private allEffects = new Set<IEffect>();\n\n public onSignalChange?: (name: string, next: any, prev: any) => void;\n\n private reactAdapters = {\n useState: useState as any,\n useEffect: useEffect as any,\n };\n\n /** DI: Регистрация */\n public provide<T>(token: Token<T>, valueOrFactory: T | Factory<T>): void {\n if (typeof valueOrFactory === 'function' && !valueOrFactory.prototype) {\n this.factories.set(token, valueOrFactory as Factory<T>);\n } else {\n this.services.set(token, valueOrFactory);\n }\n }\n\n /** DI: Инъекция */\n public inject<T>(token: Token<T>): T {\n if (!token) {\n throw new Error(`[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.`);\n }\n\n if (this.services.has(token)) return this.services.get(token);\n\n // NOTE: (new way) Если это класс, но мы забыли его унаследовать от BaseService или передать engine\n try {\n // NOTE: Логика создания инстанса\n const factory = this.factories.get(token);\n if (factory) {\n const instance = factory(this);\n this.services.set(token, instance);\n return instance;\n }\n if (typeof token === 'function' && token.prototype) {\n const instance = new (token as { new(eng: ReactiveEngine): T })(this);\n this.services.set(token, instance);\n return instance;\n }\n throw new Error(`Service not found: ${String(token)}`);\n } catch (e) {\n throw new Error(`[DI Error]: Не удалось создать сервис ${String(token)}. Ошибка: ${(e as Error)?.message || 'No e?.message'}`);\n }\n }\n\n /** Создание Сигнала */\n public signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T> {\n const engine = this;\n let val = initialValue;\n const subscribers = new Set<IEffect>();\n\n // Парсим аргументы для обратной совместимости\n const options = typeof optionsOrName === 'string'\n ? { name: optionsOrName }\n : optionsOrName || {};\n\n const name = options.name || 'unnamed_signal';\n\n return {\n get value(): T {\n if (engine.activeEffect) subscribers.add(engine.activeEffect);\n return val;\n },\n set value(newValue: T) {\n if (val === newValue) return;\n\n // ВАЛИДАЦИЯ В RUNTIME\n if (options.validate) {\n const result = options.validate(newValue);\n if (result === false || typeof result === 'string') {\n const errorMsg = typeof result === 'string'\n ? result\n : `[Validation Error]: Некорректное значение для сигнала \"${name}\"`;\n\n console.error(`%c${errorMsg}`, \"color: orange; font-weight: bold;\", {\n received: newValue,\n current: val\n });\n return; // Прерываем обновление, если данные не валидны\n }\n }\n\n const old = val;\n val = newValue;\n engine.onSignalChange?.(name, newValue, old);\n subscribers.forEach(e =>\n engine.isBatching ? engine.pendingEffects.add(e) : e.run()\n );\n },\n subscribe(cb) {\n return engine.effect(() => cb(this.value));\n }\n };\n }\n\n /** Эффект */\n public effect(fn: EffectFn): CleanupFn {\n const engine = this;\n const effectObj: IEffect = {\n cleanups: new Set(),\n run() {\n this.cleanups.forEach(c => c());\n this.cleanups.clear();\n const prev = engine.activeEffect;\n engine.activeEffect = this;\n engine.safeRun(this, () => {\n const cleanup = fn();\n if (typeof cleanup === 'function') this.cleanups.add(cleanup);\n });\n engine.activeEffect = prev;\n }\n };\n this.allEffects.add(effectObj); // Регистрируем эффект в глобальном списке\n effectObj.run();\n return () => {\n effectObj.cleanups.forEach(c => c());\n engine.pendingEffects.delete(effectObj);\n };\n }\n\n /** Вычисляемое значение */\n public computed<T>(fn: () => T, signalName?: string): Computed<T> {\n const sig = this.signal<T>(undefined as any, signalName || 'unnamed_computed');\n this.effect(() => {\n const newValue = fn();\n // Сигнал сам внутри себя проверит (sig.value === newValue)\n // благодаря правке в пункте №1\n sig.value = newValue;\n });\n return {\n get value() { return sig.value; },\n // Подписываемся на внутренний сигнал\n subscribe: (cb) => sig.subscribe(cb)\n };\n }\n\n /** Реактивный объект (Proxy) */\n public reactive<T extends object>(target: T, name: string = 'reactive'): T {\n if (this.proxyCache.has(target)) return this.proxyCache.get(target);\n const engine = this;\n const propsSubscribers = new Map<string | symbol, Set<IEffect>>();\n\n const proxy = new Proxy(target, {\n get(obj, prop, receiver) {\n if (engine.activeEffect) {\n if (!propsSubscribers.has(prop)) propsSubscribers.set(prop, new Set());\n propsSubscribers.get(prop)!.add(engine.activeEffect);\n }\n const value = Reflect.get(obj, prop, receiver);\n return (value !== null && typeof value === 'object')\n ? engine.reactive(value, `${name}.${String(prop)}`)\n : value;\n },\n set(obj, prop, value, receiver) {\n const old = Reflect.get(obj, prop, receiver);\n // ПРОВЕРКА НА ИДЕНТИЧНОСТЬ\n if (old === value) return true;\n\n if (old !== value) {\n Reflect.set(obj, prop, value, receiver);\n engine.onSignalChange?.(`${name}.${String(prop)}`, value, old);\n propsSubscribers.get(prop)?.forEach(e =>\n engine.isBatching ? engine.pendingEffects.add(e) : e.run()\n );\n }\n return true;\n }\n });\n this.proxyCache.set(target, proxy);\n return proxy;\n }\n\n /** Группировка изменений */\n public batch(fn: () => void): void {\n this.isBatching = true;\n try { fn(); } finally {\n queueMicrotask(() => {\n const effects = Array.from(this.pendingEffects);\n this.pendingEffects.clear();\n this.isBatching = false;\n effects.forEach(e => e.run());\n });\n }\n }\n\n /** Асинхронный ресурс */\n public resource<T, S = void>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n source?: { value: S },\n signalName?: string,\n ): Resource<T> {\n const state = this.signal<ResourceState<T>>({ data: null, loading: true, error: null }, signalName || 'unnamed_resource');\n let controller: AbortController | null = null;\n\n const load = async (sValue: S) => {\n controller?.abort();\n controller = new AbortController();\n\n // Читаем текущие данные без создания зависимости!\n const currentData = this.untrack(() => state.value.data);\n\n // Теперь обновление состояния не вызовет перезапуск эффекта\n state.value = { data: currentData, loading: true, error: null };\n\n try {\n const data = await fetcher(sValue, controller.signal);\n if (!controller.signal.aborted) {\n state.value = { data, loading: false, error: null };\n }\n } catch (e: any) {\n if (e.name !== 'AbortError') {\n state.value = { data: null, loading: false, error: e };\n }\n }\n };\n\n // Чтобы эффект не подписывался на state,\n // нам нужно изолировать чтение source от чтения state\n this.effect(() => {\n // Читаем ТОЛЬКО source. Это наша единственная зависимость.\n const sValue = source ? source.value : undefined as S;\n\n // Вызываем load. Внутри load чтение state.value\n // не должно регистрироваться как зависимость этого эффекта.\n load(sValue);\n\n return () => controller?.abort();\n });\n\n return {\n get data() { return state.value.data; },\n get loading() { return state.value.loading; },\n get error() { return state.value.error; },\n get value() { return state.value; },\n refetch: () => load(source ? source.value : undefined as S),\n subscribe: (cb) => state.subscribe(cb)\n };\n }\n\n /**\n * Выполняет функцию без отслеживания зависимостей\n */\n public untrack<T>(fn: () => T): T {\n const prev = this.activeEffect;\n this.activeEffect = null; // Временно \"забываем\" про активный эффект\n try {\n return fn();\n } finally {\n this.activeEffect = prev; // Возвращаем эффект на место\n }\n }\n\n /** React Хук */\n public setReactAdapters(useState: any, useEffect: any) {\n this.reactAdapters = { useState, useEffect };\n }\n\n public use<T>(item: { value: T; subscribe: (cb: (v: T) => void) => CleanupFn }): T {\n if (!this.reactAdapters) {\n throw new Error(\"[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).\");\n }\n\n // NOTE: (защита) проверяем, что нам передали объект сигнала\n if (!item || typeof item.subscribe !== 'function') {\n const errorMsg = `\n [Reactive Error]: engine.use() получил некорректный объект!\n Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.\n Проверьте, что в классе написано: public mySignal = this.engine.signal(...)\n `;\n console.error(errorMsg, { item });\n throw new Error(errorMsg);\n }\n const [val, setVal] = this.reactAdapters.useState(item.value);\n\n this.reactAdapters.useEffect(\n () => {\n return item.subscribe(setVal);\n },\n [item]\n );\n\n return val;\n }\n\n private safeRun(effect: IEffect, fn: () => void) {\n try {\n fn();\n } catch (error) {\n console.error(\n `%c[Reactive Error] %cОшибка в эффекте/computed:`,\n \"color: white; background: red; padding: 2px 4px; border-radius: 3px;\",\n \"font-weight: bold;\",\n error\n );\n // Здесь можно отправить ошибку в Sentry или другой сервис мониторинга\n }\n }\n}\n","import { ReactiveEngine } from './core';\n\n// export abstract class BaseService {\n// constructor(protected engine: ReactiveEngine) {\n// // Вызываем метод инициализации, который можно переопределить в наследниках\n// this.onInit();\n// }\n\n// // NOTE: Жизненный цикл: вызывается сразу после создания сервиса.\n// // Удобно для инициализации сигналов, которые зависят от engine.\n// protected onInit(): void {}\n\n// // NOTE: Полезные хелперы для сокращения кода\n// protected createSignal<T>(val: T, name?: string) {\n// return this.engine.signal(val, name);\n// }\n\n// protected createComputed<T>(fn: () => T) {\n// return this.engine.computed(fn);\n// }\n// }\n\nexport abstract class BaseREService {\n constructor(protected engine: ReactiveEngine) { } // Просто сохраняем engine\n\n protected createNumericSignal(val: number, name: string) {\n return this.engine.signal(val, {\n name,\n validate: (v) => typeof v === 'number' && !isNaN(v)\n });\n }\n}\n"],"names":["ReactiveEngine","useState","useEffect","token","valueOrFactory","factory","instance","e","initialValue","optionsOrName","engine","val","subscribers","options","name","newValue","result","errorMsg","old","cb","fn","effectObj","c","prev","cleanup","signalName","sig","target","propsSubscribers","proxy","obj","prop","receiver","value","effects","fetcher","source","state","controller","load","sValue","currentData","data","item","setVal","effect","error","BaseREService","v"],"mappings":"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"}
|
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pravosleva/reactive-engine",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4-beta",
|
|
4
4
|
"description": "JS Reactive Engine",
|
|
5
5
|
"author": "Den Pol <selection4test@gmail.com> (https://pravosleva.pro)",
|
|
6
6
|
"homepage": "https://github.com/garage-13/reactive-engine",
|