@pravosleva/reactive-engine 0.2.5-beta → 0.2.6-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 +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.iife.js +2 -2
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +58 -49
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("react");class g{activeEffect=null;isBatching=!1;pendingEffects=new Set;services=new Map;factories=new Map;proxyCache=new WeakMap;allEffects=new Set;onSignalChange;reactAdapters={useState:h.useState,useEffect:h.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 i=new Set,o=typeof t=="string"?{name:t}:t||{},s=o.name||"unnamed_signal";return{get value(){return r.activeEffect&&i.add(r.activeEffect),n},set value(a){if(n===a)return;if(o.validate){const f=o.validate(a);if(f===!1||typeof f=="string"){const u=typeof f=="string"?f:`[Validation Error]: Некорректное значение для сигнала "${s}"`;console.error(`%c${u}`,"color: orange; font-weight: bold;",{received:a,current:n});return}}const c=n;n=a,r.onSignalChange?.(s,a,c),i.forEach(f=>r.isBatching?r.pendingEffects.add(f):f.run())},subscribe(a){return r.effect(()=>a(this.value))}}}effect(e){const t=this,r={cleanups:new Set,run(){this.cleanups.forEach(i=>i()),this.cleanups.clear();const n=t.activeEffect;t.activeEffect=this,t.safeRun(this,()=>{const i=e();typeof i=="function"&&this.cleanups.add(i)}),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,i=new Proxy(e,{get(o,s,a){r.activeEffect&&(n.has(s)||n.set(s,new Set),n.get(s).add(r.activeEffect));const c=Reflect.get(o,s,a);return c!==null&&typeof c=="object"?r.reactive(c,`${t}.${String(s)}`):c},set(o,s,a,c){const f=Reflect.get(o,s,c);return f===a||f!==a&&(Reflect.set(o,s,a,c),r.onSignalChange?.(`${t}.${String(s)}`,a,f),n.get(s)?.forEach(u=>r.isBatching?r.pendingEffects.add(u):u.run())),!0}});return this.proxyCache.set(e,i),i}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 i=null;const o=async s=>{i?.abort(),i=new AbortController;const a=this.untrack(()=>n.value.data);n.value={data:a,loading:!0,error:null};try{const c=await e(s,i.signal);i.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 o(s),()=>i?.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:()=>o(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
2
|
[Reactive Error]: engine.use() получил некорректный объект!
|
|
3
3
|
Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.
|
|
4
4
|
Проверьте, что в классе написано: public mySignal = this.engine.signal(...)
|
|
5
|
-
`;throw console.error(
|
|
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)})}}class v{constructor(e){this.engine=e,setTimeout(()=>this.onInit(),0)}engine;onInit(){}}exports.BaseREService=d;exports.BaseREServiceEnhanced=v;exports.ReactiveEngine=g;
|
|
6
6
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/core.ts","../src/BaseREService.ts","../src/BaseREServiceEnhanced.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","import { ReactiveEngine } from './core';\n\nexport abstract class BaseREServiceEnhanced {\n constructor(protected engine: ReactiveEngine) {\n setTimeout(() => this.onInit(), 0)\n }\n\n protected onInit(): void { }\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","BaseREServiceEnhanced"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,12 @@ export declare abstract class BaseREService {
|
|
|
4
4
|
protected createNumericSignal(val: number, name: string): Signal<number>;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
export declare abstract class BaseREServiceEnhanced {
|
|
8
|
+
protected engine: ReactiveEngine;
|
|
9
|
+
constructor(engine: ReactiveEngine);
|
|
10
|
+
protected onInit(): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
export declare type CleanupFn = () => void;
|
|
8
14
|
|
|
9
15
|
export declare interface Computed<T> {
|
package/dist/index.iife.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var MyLib=(function(u,
|
|
1
|
+
var MyLib=(function(u,h){"use strict";class d{activeEffect=null;isBatching=!1;pendingEffects=new Set;services=new Map;factories=new Map;proxyCache=new WeakMap;allEffects=new Set;onSignalChange;reactAdapters={useState:h.useState,useEffect:h.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 i=new Set,o=typeof t=="string"?{name:t}:t||{},s=o.name||"unnamed_signal";return{get value(){return r.activeEffect&&i.add(r.activeEffect),n},set value(a){if(n===a)return;if(o.validate){const f=o.validate(a);if(f===!1||typeof f=="string"){const l=typeof f=="string"?f:`[Validation Error]: Некорректное значение для сигнала "${s}"`;console.error(`%c${l}`,"color: orange; font-weight: bold;",{received:a,current:n});return}}const c=n;n=a,r.onSignalChange?.(s,a,c),i.forEach(f=>r.isBatching?r.pendingEffects.add(f):f.run())},subscribe(a){return r.effect(()=>a(this.value))}}}effect(e){const t=this,r={cleanups:new Set,run(){this.cleanups.forEach(i=>i()),this.cleanups.clear();const n=t.activeEffect;t.activeEffect=this,t.safeRun(this,()=>{const i=e();typeof i=="function"&&this.cleanups.add(i)}),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,i=new Proxy(e,{get(o,s,a){r.activeEffect&&(n.has(s)||n.set(s,new Set),n.get(s).add(r.activeEffect));const c=Reflect.get(o,s,a);return c!==null&&typeof c=="object"?r.reactive(c,`${t}.${String(s)}`):c},set(o,s,a,c){const f=Reflect.get(o,s,c);return f===a||f!==a&&(Reflect.set(o,s,a,c),r.onSignalChange?.(`${t}.${String(s)}`,a,f),n.get(s)?.forEach(l=>r.isBatching?r.pendingEffects.add(l):l.run())),!0}});return this.proxyCache.set(e,i),i}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 i=null;const o=async s=>{i?.abort(),i=new AbortController;const a=this.untrack(()=>n.value.data);n.value={data:a,loading:!0,error:null};try{const c=await e(s,i.signal);i.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 o(s),()=>i?.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:()=>o(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
2
|
[Reactive Error]: engine.use() получил некорректный объект!
|
|
3
3
|
Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.
|
|
4
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
|
|
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 v{constructor(e){this.engine=e}engine;createNumericSignal(e,t){return this.engine.signal(e,{name:t,validate:r=>typeof r=="number"&&!isNaN(r)})}}class E{constructor(e){this.engine=e,setTimeout(()=>this.onInit(),0)}engine;onInit(){}}return u.BaseREService=v,u.BaseREServiceEnhanced=E,u.ReactiveEngine=d,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"}),u})({},React);
|
|
6
6
|
//# sourceMappingURL=index.iife.js.map
|
package/dist/index.iife.js.map
CHANGED
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"index.iife.js","sources":["../src/core.ts","../src/BaseREService.ts","../src/BaseREServiceEnhanced.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","import { ReactiveEngine } from './core';\n\nexport abstract class BaseREServiceEnhanced {\n constructor(protected engine: ReactiveEngine) {\n setTimeout(() => this.onInit(), 0)\n }\n\n protected onInit(): void { }\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","BaseREServiceEnhanced"],"mappings":"sCAyCO,MAAMA,CAAe,CAClB,aAA+B,KAC/B,WAAa,GACb,mBAAqB,IACrB,aAAe,IACf,cAAgB,IAChB,eAAiB,QACjB,eAAiB,IAElB,eAEC,cAAgB,CAAA,SACtBC,EAAAA,SAAA,UACAC,EAAAA,SAAA,EAIK,QAAWC,EAAiBC,EAAsC,CACnE,OAAOA,GAAmB,YAAc,CAACA,EAAe,UAC1D,KAAK,UAAU,IAAID,EAAOC,CAA4B,EAEtD,KAAK,SAAS,IAAID,EAAOC,CAAc,CAE3C,CAGO,OAAUD,EAAoB,CACnC,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,qFAAqF,EAGvG,GAAI,KAAK,SAAS,IAAIA,CAAK,EAAG,OAAO,KAAK,SAAS,IAAIA,CAAK,EAG5D,GAAI,CAEF,MAAME,EAAU,KAAK,UAAU,IAAIF,CAAK,EACxC,GAAIE,EAAS,CACX,MAAMC,EAAWD,EAAQ,IAAI,EAC7B,YAAK,SAAS,IAAIF,EAAOG,CAAQ,EAC1BA,CACT,CACA,GAAI,OAAOH,GAAU,YAAcA,EAAM,UAAW,CAClD,MAAMG,EAAW,IAAKH,EAA0C,IAAI,EACpE,YAAK,SAAS,IAAIA,EAAOG,CAAQ,EAC1BA,CACT,CACA,MAAM,IAAI,MAAM,sBAAsB,OAAOH,CAAK,CAAC,EAAE,CACvD,OAASI,EAAG,CACV,MAAM,IAAI,MAAM,yCAAyC,OAAOJ,CAAK,CAAC,aAAcI,GAAa,SAAW,eAAe,EAAE,CAC/H,CACF,CAGO,OAAUC,EAAiBC,EAAsD,CACtF,MAAMC,EAAS,KACf,IAAIC,EAAMH,EACV,MAAMI,MAAkB,IAGlBC,EAAU,OAAOJ,GAAkB,SACrC,CAAE,KAAMA,CAAA,EACRA,GAAiB,CAAA,EAEfK,EAAOD,EAAQ,MAAQ,iBAE7B,MAAO,CACL,IAAI,OAAW,CACb,OAAIH,EAAO,cAAcE,EAAY,IAAIF,EAAO,YAAY,EACrDC,CACT,EACA,IAAI,MAAMI,EAAa,CACrB,GAAIJ,IAAQI,EAAU,OAGtB,GAAIF,EAAQ,SAAU,CACpB,MAAMG,EAASH,EAAQ,SAASE,CAAQ,EACxC,GAAIC,IAAW,IAAS,OAAOA,GAAW,SAAU,CAClD,MAAMC,EAAW,OAAOD,GAAW,SAC/BA,EACA,0DAA0DF,CAAI,IAElE,QAAQ,MAAM,KAAKG,CAAQ,GAAI,oCAAqC,CAClE,SAAUF,EACV,QAASJ,CAAA,CACV,EACD,MACF,CACF,CAEA,MAAMO,EAAMP,EACZA,EAAMI,EACNL,EAAO,iBAAiBI,EAAMC,EAAUG,CAAG,EAC3CN,EAAY,QAAQL,GAClBG,EAAO,WAAaA,EAAO,eAAe,IAAIH,CAAC,EAAIA,EAAE,IAAA,CAAI,CAE7D,EACA,UAAUY,EAAI,CACZ,OAAOT,EAAO,OAAO,IAAMS,EAAG,KAAK,KAAK,CAAC,CAC3C,CAAA,CAEJ,CAGO,OAAOC,EAAyB,CACrC,MAAMV,EAAS,KACTW,EAAqB,CACzB,aAAc,IACd,KAAM,CACJ,KAAK,SAAS,QAAQC,GAAKA,EAAA,CAAG,EAC9B,KAAK,SAAS,MAAA,EACd,MAAMC,EAAOb,EAAO,aACpBA,EAAO,aAAe,KACtBA,EAAO,QAAQ,KAAM,IAAM,CACzB,MAAMc,EAAUJ,EAAA,EACZ,OAAOI,GAAY,YAAY,KAAK,SAAS,IAAIA,CAAO,CAC9D,CAAC,EACDd,EAAO,aAAea,CACxB,CAAA,EAEF,YAAK,WAAW,IAAIF,CAAS,EAC7BA,EAAU,IAAA,EACH,IAAM,CACXA,EAAU,SAAS,QAAQC,GAAKA,EAAA,CAAG,EACnCZ,EAAO,eAAe,OAAOW,CAAS,CACxC,CACF,CAGO,SAAYD,EAAaK,EAAkC,CAChE,MAAMC,EAAM,KAAK,OAAU,OAAkBD,GAAc,kBAAkB,EAC7E,YAAK,OAAO,IAAM,CAChB,MAAMV,EAAWK,EAAA,EAGjBM,EAAI,MAAQX,CACd,CAAC,EACM,CACL,IAAI,OAAQ,CAAE,OAAOW,EAAI,KAAO,EAEhC,UAAYP,GAAOO,EAAI,UAAUP,CAAE,CAAA,CAEvC,CAGO,SAA2BQ,EAAWb,EAAe,WAAe,CACzE,GAAI,KAAK,WAAW,IAAIa,CAAM,EAAG,OAAO,KAAK,WAAW,IAAIA,CAAM,EAClE,MAAMjB,EAAS,KACTkB,MAAuB,IAEvBC,EAAQ,IAAI,MAAMF,EAAQ,CAC9B,IAAIG,EAAKC,EAAMC,EAAU,CACnBtB,EAAO,eACJkB,EAAiB,IAAIG,CAAI,KAAoB,IAAIA,EAAM,IAAI,GAAK,EACrEH,EAAiB,IAAIG,CAAI,EAAG,IAAIrB,EAAO,YAAY,GAErD,MAAMuB,EAAQ,QAAQ,IAAIH,EAAKC,EAAMC,CAAQ,EAC7C,OAAQC,IAAU,MAAQ,OAAOA,GAAU,SACvCvB,EAAO,SAASuB,EAAO,GAAGnB,CAAI,IAAI,OAAOiB,CAAI,CAAC,EAAE,EAChDE,CACN,EACA,IAAIH,EAAKC,EAAME,EAAOD,EAAU,CAC9B,MAAMd,EAAM,QAAQ,IAAIY,EAAKC,EAAMC,CAAQ,EAE3C,OAAId,IAAQe,GAERf,IAAQe,IACV,QAAQ,IAAIH,EAAKC,EAAME,EAAOD,CAAQ,EACtCtB,EAAO,iBAAiB,GAAGI,CAAI,IAAI,OAAOiB,CAAI,CAAC,GAAIE,EAAOf,CAAG,EAC7DU,EAAiB,IAAIG,CAAI,GAAG,QAAQxB,GAClCG,EAAO,WAAaA,EAAO,eAAe,IAAIH,CAAC,EAAIA,EAAE,IAAA,CAAI,GAGtD,EACT,CAAA,CACD,EACD,YAAK,WAAW,IAAIoB,EAAQE,CAAK,EAC1BA,CACT,CAGO,MAAMT,EAAsB,CACjC,KAAK,WAAa,GAClB,GAAI,CAAEA,EAAA,CAAM,QAAA,CACV,eAAe,IAAM,CACnB,MAAMc,EAAU,MAAM,KAAK,KAAK,cAAc,EAC9C,KAAK,eAAe,MAAA,EACpB,KAAK,WAAa,GAClBA,EAAQ,QAAQ3B,GAAKA,EAAE,IAAA,CAAK,CAC9B,CAAC,CACH,CACF,CAGO,SACL4B,EACAC,EACAX,EACa,CACb,MAAMY,EAAQ,KAAK,OAAyB,CAAE,KAAM,KAAM,QAAS,GAAM,MAAO,MAAQZ,GAAc,kBAAkB,EACxH,IAAIa,EAAqC,KAEzC,MAAMC,EAAO,MAAOC,GAAc,CAChCF,GAAY,MAAA,EACZA,EAAa,IAAI,gBAGjB,MAAMG,EAAc,KAAK,QAAQ,IAAMJ,EAAM,MAAM,IAAI,EAGvDA,EAAM,MAAQ,CAAE,KAAMI,EAAa,QAAS,GAAM,MAAO,IAAA,EAEzD,GAAI,CACF,MAAMC,EAAO,MAAMP,EAAQK,EAAQF,EAAW,MAAM,EAC/CA,EAAW,OAAO,UACrBD,EAAM,MAAQ,CAAE,KAAAK,EAAM,QAAS,GAAO,MAAO,IAAA,EAEjD,OAASnC,EAAQ,CACXA,EAAE,OAAS,eACb8B,EAAM,MAAQ,CAAE,KAAM,KAAM,QAAS,GAAO,MAAO9B,CAAA,EAEvD,CACF,EAIA,YAAK,OAAO,IAAM,CAEhB,MAAMiC,EAASJ,EAASA,EAAO,MAAQ,OAIvC,OAAAG,EAAKC,CAAM,EAEJ,IAAMF,GAAY,MAAA,CAC3B,CAAC,EAEM,CACL,IAAI,MAAO,CAAE,OAAOD,EAAM,MAAM,IAAM,EACtC,IAAI,SAAU,CAAE,OAAOA,EAAM,MAAM,OAAS,EAC5C,IAAI,OAAQ,CAAE,OAAOA,EAAM,MAAM,KAAO,EACxC,IAAI,OAAQ,CAAE,OAAOA,EAAM,KAAO,EAClC,QAAS,IAAME,EAAKH,EAASA,EAAO,MAAQ,MAAc,EAC1D,UAAYjB,GAAOkB,EAAM,UAAUlB,CAAE,CAAA,CAEzC,CAKO,QAAWC,EAAgB,CAChC,MAAMG,EAAO,KAAK,aAClB,KAAK,aAAe,KACpB,GAAI,CACF,OAAOH,EAAA,CACT,QAAA,CACE,KAAK,aAAeG,CACtB,CACF,CAGO,iBAAiBtB,EAAeC,EAAgB,CACrD,KAAK,cAAgB,CAAE,SAAAD,EAAU,UAAAC,CAAAA,CACnC,CAEO,IAAOyC,EAAqE,CACjF,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,sGAAsG,EAIxH,GAAI,CAACA,GAAQ,OAAOA,EAAK,WAAc,WAAY,CACjD,MAAM1B,EAAW;AAAA;AAAA;AAAA;AAAA,QAKjB,cAAQ,MAAMA,EAAU,CAAE,KAAA0B,CAAA,CAAM,EAC1B,IAAI,MAAM1B,CAAQ,CAC1B,CACA,KAAM,CAACN,EAAKiC,CAAM,EAAI,KAAK,cAAc,SAASD,EAAK,KAAK,EAE5D,YAAK,cAAc,UACjB,IACSA,EAAK,UAAUC,CAAM,EAE9B,CAACD,CAAI,CAAA,EAGAhC,CACT,CAEQ,QAAQkC,EAAiBzB,EAAgB,CAC/C,GAAI,CACFA,EAAA,CACF,OAAS0B,EAAO,CACd,QAAQ,MACN,kDACA,uEACA,qBACAA,CAAA,CAGJ,CACF,CACF,CCpUO,MAAeC,CAAc,CAClC,YAAsBrC,EAAwB,CAAxB,KAAA,OAAAA,CAA0B,CAA1B,OAEZ,oBAAoBC,EAAaG,EAAc,CACvD,OAAO,KAAK,OAAO,OAAOH,EAAK,CAC7B,KAAAG,EACA,SAAWkC,GAAM,OAAOA,GAAM,UAAY,CAAC,MAAMA,CAAC,CAAA,CACnD,CACH,CACF,CC7BO,MAAeC,CAAsB,CAC1C,YAAsBvC,EAAwB,CAAxB,KAAA,OAAAA,EACpB,WAAW,IAAM,KAAK,OAAA,EAAU,CAAC,CACnC,CAFsB,OAIZ,QAAe,CAAE,CAC7B"}
|
package/dist/index.mjs
CHANGED
|
@@ -39,32 +39,32 @@ class v {
|
|
|
39
39
|
/** Создание Сигнала */
|
|
40
40
|
signal(e, t) {
|
|
41
41
|
const r = this;
|
|
42
|
-
let
|
|
43
|
-
const
|
|
42
|
+
let n = e;
|
|
43
|
+
const i = /* @__PURE__ */ new Set(), o = typeof t == "string" ? { name: t } : t || {}, s = o.name || "unnamed_signal";
|
|
44
44
|
return {
|
|
45
45
|
get value() {
|
|
46
|
-
return r.activeEffect &&
|
|
46
|
+
return r.activeEffect && i.add(r.activeEffect), n;
|
|
47
47
|
},
|
|
48
|
-
set value(
|
|
49
|
-
if (
|
|
48
|
+
set value(a) {
|
|
49
|
+
if (n === a) return;
|
|
50
50
|
if (o.validate) {
|
|
51
|
-
const f = o.validate(
|
|
51
|
+
const f = o.validate(a);
|
|
52
52
|
if (f === !1 || typeof f == "string") {
|
|
53
|
-
const u = typeof f == "string" ? f : `[Validation Error]: Некорректное значение для сигнала "${
|
|
53
|
+
const u = typeof f == "string" ? f : `[Validation Error]: Некорректное значение для сигнала "${s}"`;
|
|
54
54
|
console.error(`%c${u}`, "color: orange; font-weight: bold;", {
|
|
55
|
-
received:
|
|
56
|
-
current:
|
|
55
|
+
received: a,
|
|
56
|
+
current: n
|
|
57
57
|
});
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
const c =
|
|
62
|
-
|
|
61
|
+
const c = n;
|
|
62
|
+
n = a, r.onSignalChange?.(s, a, c), i.forEach(
|
|
63
63
|
(f) => r.isBatching ? r.pendingEffects.add(f) : f.run()
|
|
64
64
|
);
|
|
65
65
|
},
|
|
66
|
-
subscribe(
|
|
67
|
-
return r.effect(() =>
|
|
66
|
+
subscribe(a) {
|
|
67
|
+
return r.effect(() => a(this.value));
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
}
|
|
@@ -73,49 +73,49 @@ class v {
|
|
|
73
73
|
const t = this, r = {
|
|
74
74
|
cleanups: /* @__PURE__ */ new Set(),
|
|
75
75
|
run() {
|
|
76
|
-
this.cleanups.forEach((
|
|
77
|
-
const
|
|
76
|
+
this.cleanups.forEach((i) => i()), this.cleanups.clear();
|
|
77
|
+
const n = t.activeEffect;
|
|
78
78
|
t.activeEffect = this, t.safeRun(this, () => {
|
|
79
|
-
const
|
|
80
|
-
typeof
|
|
81
|
-
}), t.activeEffect =
|
|
79
|
+
const i = e();
|
|
80
|
+
typeof i == "function" && this.cleanups.add(i);
|
|
81
|
+
}), t.activeEffect = n;
|
|
82
82
|
}
|
|
83
83
|
};
|
|
84
84
|
return this.allEffects.add(r), r.run(), () => {
|
|
85
|
-
r.cleanups.forEach((
|
|
85
|
+
r.cleanups.forEach((n) => n()), t.pendingEffects.delete(r);
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
88
|
/** Вычисляемое значение */
|
|
89
89
|
computed(e, t) {
|
|
90
90
|
const r = this.signal(void 0, t || "unnamed_computed");
|
|
91
91
|
return this.effect(() => {
|
|
92
|
-
const
|
|
93
|
-
r.value =
|
|
92
|
+
const n = e();
|
|
93
|
+
r.value = n;
|
|
94
94
|
}), {
|
|
95
95
|
get value() {
|
|
96
96
|
return r.value;
|
|
97
97
|
},
|
|
98
98
|
// Подписываемся на внутренний сигнал
|
|
99
|
-
subscribe: (
|
|
99
|
+
subscribe: (n) => r.subscribe(n)
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
/** Реактивный объект (Proxy) */
|
|
103
103
|
reactive(e, t = "reactive") {
|
|
104
104
|
if (this.proxyCache.has(e)) return this.proxyCache.get(e);
|
|
105
|
-
const r = this,
|
|
106
|
-
get(o,
|
|
107
|
-
r.activeEffect && (
|
|
108
|
-
const c = Reflect.get(o,
|
|
109
|
-
return c !== null && typeof c == "object" ? r.reactive(c, `${t}.${String(
|
|
105
|
+
const r = this, n = /* @__PURE__ */ new Map(), i = new Proxy(e, {
|
|
106
|
+
get(o, s, a) {
|
|
107
|
+
r.activeEffect && (n.has(s) || n.set(s, /* @__PURE__ */ new Set()), n.get(s).add(r.activeEffect));
|
|
108
|
+
const c = Reflect.get(o, s, a);
|
|
109
|
+
return c !== null && typeof c == "object" ? r.reactive(c, `${t}.${String(s)}`) : c;
|
|
110
110
|
},
|
|
111
|
-
set(o,
|
|
112
|
-
const f = Reflect.get(o,
|
|
113
|
-
return f ===
|
|
111
|
+
set(o, s, a, c) {
|
|
112
|
+
const f = Reflect.get(o, s, c);
|
|
113
|
+
return f === a || f !== a && (Reflect.set(o, s, a, c), r.onSignalChange?.(`${t}.${String(s)}`, a, f), n.get(s)?.forEach(
|
|
114
114
|
(u) => r.isBatching ? r.pendingEffects.add(u) : u.run()
|
|
115
115
|
)), !0;
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
|
-
return this.proxyCache.set(e,
|
|
118
|
+
return this.proxyCache.set(e, i), i;
|
|
119
119
|
}
|
|
120
120
|
/** Группировка изменений */
|
|
121
121
|
batch(e) {
|
|
@@ -131,37 +131,37 @@ class v {
|
|
|
131
131
|
}
|
|
132
132
|
/** Асинхронный ресурс */
|
|
133
133
|
resource(e, t, r) {
|
|
134
|
-
const
|
|
135
|
-
let
|
|
136
|
-
const o = async (
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
|
|
134
|
+
const n = this.signal({ data: null, loading: !0, error: null }, r || "unnamed_resource");
|
|
135
|
+
let i = null;
|
|
136
|
+
const o = async (s) => {
|
|
137
|
+
i?.abort(), i = new AbortController();
|
|
138
|
+
const a = this.untrack(() => n.value.data);
|
|
139
|
+
n.value = { data: a, loading: !0, error: null };
|
|
140
140
|
try {
|
|
141
|
-
const c = await e(
|
|
142
|
-
|
|
141
|
+
const c = await e(s, i.signal);
|
|
142
|
+
i.signal.aborted || (n.value = { data: c, loading: !1, error: null });
|
|
143
143
|
} catch (c) {
|
|
144
|
-
c.name !== "AbortError" && (
|
|
144
|
+
c.name !== "AbortError" && (n.value = { data: null, loading: !1, error: c });
|
|
145
145
|
}
|
|
146
146
|
};
|
|
147
147
|
return this.effect(() => {
|
|
148
|
-
const
|
|
149
|
-
return o(
|
|
148
|
+
const s = t ? t.value : void 0;
|
|
149
|
+
return o(s), () => i?.abort();
|
|
150
150
|
}), {
|
|
151
151
|
get data() {
|
|
152
|
-
return
|
|
152
|
+
return n.value.data;
|
|
153
153
|
},
|
|
154
154
|
get loading() {
|
|
155
|
-
return
|
|
155
|
+
return n.value.loading;
|
|
156
156
|
},
|
|
157
157
|
get error() {
|
|
158
|
-
return
|
|
158
|
+
return n.value.error;
|
|
159
159
|
},
|
|
160
160
|
get value() {
|
|
161
|
-
return
|
|
161
|
+
return n.value;
|
|
162
162
|
},
|
|
163
163
|
refetch: () => o(t ? t.value : void 0),
|
|
164
|
-
subscribe: (
|
|
164
|
+
subscribe: (s) => n.subscribe(s)
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
167
|
/**
|
|
@@ -184,12 +184,12 @@ class v {
|
|
|
184
184
|
if (!this.reactAdapters)
|
|
185
185
|
throw new Error("[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).");
|
|
186
186
|
if (!e || typeof e.subscribe != "function") {
|
|
187
|
-
const
|
|
187
|
+
const n = `
|
|
188
188
|
[Reactive Error]: engine.use() получил некорректный объект!
|
|
189
189
|
Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.
|
|
190
190
|
Проверьте, что в классе написано: public mySignal = this.engine.signal(...)
|
|
191
191
|
`;
|
|
192
|
-
throw console.error(
|
|
192
|
+
throw console.error(n, { item: e }), new Error(n);
|
|
193
193
|
}
|
|
194
194
|
const [t, r] = this.reactAdapters.useState(e.value);
|
|
195
195
|
return this.reactAdapters.useEffect(
|
|
@@ -223,8 +223,17 @@ class E {
|
|
|
223
223
|
});
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
+
class p {
|
|
227
|
+
constructor(e) {
|
|
228
|
+
this.engine = e, setTimeout(() => this.onInit(), 0);
|
|
229
|
+
}
|
|
230
|
+
engine;
|
|
231
|
+
onInit() {
|
|
232
|
+
}
|
|
233
|
+
}
|
|
226
234
|
export {
|
|
227
235
|
E as BaseREService,
|
|
236
|
+
p as BaseREServiceEnhanced,
|
|
228
237
|
v as ReactiveEngine
|
|
229
238
|
};
|
|
230
239
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +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":";AAyCO,MAAMA,EAAe;AAAA,EAClB,eAA+B;AAAA,EAC/B,aAAa;AAAA,EACb,qCAAqB,IAAA;AAAA,EACrB,+BAAe,IAAA;AAAA,EACf,gCAAgB,IAAA;AAAA,EAChB,iCAAiB,QAAA;AAAA,EACjB,iCAAiB,IAAA;AAAA,EAElB;AAAA,EAEC,gBAAgB;AAAA,IACtB,UAAAC;AAAA,IACA,WAAAC;AAAA,EAAA;AAAA;AAAA,EAIK,QAAWC,GAAiBC,GAAsC;AACvE,IAAI,OAAOA,KAAmB,cAAc,CAACA,EAAe,YAC1D,KAAK,UAAU,IAAID,GAAOC,CAA4B,IAEtD,KAAK,SAAS,IAAID,GAAOC,CAAc;AAAA,EAE3C;AAAA;AAAA,EAGO,OAAUD,GAAoB;AACnC,QAAI,CAACA;AACH,YAAM,IAAI,MAAM,qFAAqF;AAGvG,QAAI,KAAK,SAAS,IAAIA,CAAK,EAAG,QAAO,KAAK,SAAS,IAAIA,CAAK;AAG5D,QAAI;AAEF,YAAME,IAAU,KAAK,UAAU,IAAIF,CAAK;AACxC,UAAIE,GAAS;AACX,cAAMC,IAAWD,EAAQ,IAAI;AAC7B,oBAAK,SAAS,IAAIF,GAAOG,CAAQ,GAC1BA;AAAA,MACT;AACA,UAAI,OAAOH,KAAU,cAAcA,EAAM,WAAW;AAClD,cAAMG,IAAW,IAAKH,EAA0C,IAAI;AACpE,oBAAK,SAAS,IAAIA,GAAOG,CAAQ,GAC1BA;AAAA,MACT;AACA,YAAM,IAAI,MAAM,sBAAsB,OAAOH,CAAK,CAAC,EAAE;AAAA,IACvD,SAASI,GAAG;AACV,YAAM,IAAI,MAAM,yCAAyC,OAAOJ,CAAK,CAAC,aAAcI,GAAa,WAAW,eAAe,EAAE;AAAA,IAC/H;AAAA,EACF;AAAA;AAAA,EAGO,OAAUC,GAAiBC,GAAsD;AACtF,UAAMC,IAAS;AACf,QAAIC,IAAMH;AACV,UAAMI,wBAAkB,IAAA,GAGlBC,IAAU,OAAOJ,KAAkB,WACrC,EAAE,MAAMA,EAAA,IACRA,KAAiB,CAAA,GAEfK,IAAOD,EAAQ,QAAQ;AAE7B,WAAO;AAAA,MACL,IAAI,QAAW;AACb,eAAIH,EAAO,gBAAcE,EAAY,IAAIF,EAAO,YAAY,GACrDC;AAAA,MACT;AAAA,MACA,IAAI,MAAMI,GAAa;AACrB,YAAIJ,MAAQI,EAAU;AAGtB,YAAIF,EAAQ,UAAU;AACpB,gBAAMG,IAASH,EAAQ,SAASE,CAAQ;AACxC,cAAIC,MAAW,MAAS,OAAOA,KAAW,UAAU;AAClD,kBAAMC,IAAW,OAAOD,KAAW,WAC/BA,IACA,0DAA0DF,CAAI;AAElE,oBAAQ,MAAM,KAAKG,CAAQ,IAAI,qCAAqC;AAAA,cAClE,UAAUF;AAAA,cACV,SAASJ;AAAA,YAAA,CACV;AACD;AAAA,UACF;AAAA,QACF;AAEA,cAAMO,IAAMP;AACZ,QAAAA,IAAMI,GACNL,EAAO,iBAAiBI,GAAMC,GAAUG,CAAG,GAC3CN,EAAY;AAAA,UAAQ,CAAAL,MAClBG,EAAO,aAAaA,EAAO,eAAe,IAAIH,CAAC,IAAIA,EAAE,IAAA;AAAA,QAAI;AAAA,MAE7D;AAAA,MACA,UAAUY,GAAI;AACZ,eAAOT,EAAO,OAAO,MAAMS,EAAG,KAAK,KAAK,CAAC;AAAA,MAC3C;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA,EAGO,OAAOC,GAAyB;AACrC,UAAMV,IAAS,MACTW,IAAqB;AAAA,MACzB,8BAAc,IAAA;AAAA,MACd,MAAM;AACJ,aAAK,SAAS,QAAQ,CAAAC,MAAKA,EAAA,CAAG,GAC9B,KAAK,SAAS,MAAA;AACd,cAAMC,IAAOb,EAAO;AACpB,QAAAA,EAAO,eAAe,MACtBA,EAAO,QAAQ,MAAM,MAAM;AACzB,gBAAMc,IAAUJ,EAAA;AAChB,UAAI,OAAOI,KAAY,cAAY,KAAK,SAAS,IAAIA,CAAO;AAAA,QAC9D,CAAC,GACDd,EAAO,eAAea;AAAA,MACxB;AAAA,IAAA;AAEF,gBAAK,WAAW,IAAIF,CAAS,GAC7BA,EAAU,IAAA,GACH,MAAM;AACX,MAAAA,EAAU,SAAS,QAAQ,CAAAC,MAAKA,EAAA,CAAG,GACnCZ,EAAO,eAAe,OAAOW,CAAS;AAAA,IACxC;AAAA,EACF;AAAA;AAAA,EAGO,SAAYD,GAAaK,GAAkC;AAChE,UAAMC,IAAM,KAAK,OAAU,QAAkBD,KAAc,kBAAkB;AAC7E,gBAAK,OAAO,MAAM;AAChB,YAAMV,IAAWK,EAAA;AAGjB,MAAAM,EAAI,QAAQX;AAAA,IACd,CAAC,GACM;AAAA,MACL,IAAI,QAAQ;AAAE,eAAOW,EAAI;AAAA,MAAO;AAAA;AAAA,MAEhC,WAAW,CAACP,MAAOO,EAAI,UAAUP,CAAE;AAAA,IAAA;AAAA,EAEvC;AAAA;AAAA,EAGO,SAA2BQ,GAAWb,IAAe,YAAe;AACzE,QAAI,KAAK,WAAW,IAAIa,CAAM,EAAG,QAAO,KAAK,WAAW,IAAIA,CAAM;AAClE,UAAMjB,IAAS,MACTkB,wBAAuB,IAAA,GAEvBC,IAAQ,IAAI,MAAMF,GAAQ;AAAA,MAC9B,IAAIG,GAAKC,GAAMC,GAAU;AACvB,QAAItB,EAAO,iBACJkB,EAAiB,IAAIG,CAAI,OAAoB,IAAIA,GAAM,oBAAI,KAAK,GACrEH,EAAiB,IAAIG,CAAI,EAAG,IAAIrB,EAAO,YAAY;AAErD,cAAMuB,IAAQ,QAAQ,IAAIH,GAAKC,GAAMC,CAAQ;AAC7C,eAAQC,MAAU,QAAQ,OAAOA,KAAU,WACvCvB,EAAO,SAASuB,GAAO,GAAGnB,CAAI,IAAI,OAAOiB,CAAI,CAAC,EAAE,IAChDE;AAAA,MACN;AAAA,MACA,IAAIH,GAAKC,GAAME,GAAOD,GAAU;AAC9B,cAAMd,IAAM,QAAQ,IAAIY,GAAKC,GAAMC,CAAQ;AAE3C,eAAId,MAAQe,KAERf,MAAQe,MACV,QAAQ,IAAIH,GAAKC,GAAME,GAAOD,CAAQ,GACtCtB,EAAO,iBAAiB,GAAGI,CAAI,IAAI,OAAOiB,CAAI,CAAC,IAAIE,GAAOf,CAAG,GAC7DU,EAAiB,IAAIG,CAAI,GAAG;AAAA,UAAQ,CAAAxB,MAClCG,EAAO,aAAaA,EAAO,eAAe,IAAIH,CAAC,IAAIA,EAAE,IAAA;AAAA,QAAI,IAGtD;AAAA,MACT;AAAA,IAAA,CACD;AACD,gBAAK,WAAW,IAAIoB,GAAQE,CAAK,GAC1BA;AAAA,EACT;AAAA;AAAA,EAGO,MAAMT,GAAsB;AACjC,SAAK,aAAa;AAClB,QAAI;AAAE,MAAAA,EAAA;AAAA,IAAM,UAAA;AACV,qBAAe,MAAM;AACnB,cAAMc,IAAU,MAAM,KAAK,KAAK,cAAc;AAC9C,aAAK,eAAe,MAAA,GACpB,KAAK,aAAa,IAClBA,EAAQ,QAAQ,CAAA3B,MAAKA,EAAE,IAAA,CAAK;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGO,SACL4B,GACAC,GACAX,GACa;AACb,UAAMY,IAAQ,KAAK,OAAyB,EAAE,MAAM,MAAM,SAAS,IAAM,OAAO,QAAQZ,KAAc,kBAAkB;AACxH,QAAIa,IAAqC;AAEzC,UAAMC,IAAO,OAAOC,MAAc;AAChC,MAAAF,GAAY,MAAA,GACZA,IAAa,IAAI,gBAAA;AAGjB,YAAMG,IAAc,KAAK,QAAQ,MAAMJ,EAAM,MAAM,IAAI;AAGvD,MAAAA,EAAM,QAAQ,EAAE,MAAMI,GAAa,SAAS,IAAM,OAAO,KAAA;AAEzD,UAAI;AACF,cAAMC,IAAO,MAAMP,EAAQK,GAAQF,EAAW,MAAM;AACpD,QAAKA,EAAW,OAAO,YACrBD,EAAM,QAAQ,EAAE,MAAAK,GAAM,SAAS,IAAO,OAAO,KAAA;AAAA,MAEjD,SAASnC,GAAQ;AACf,QAAIA,EAAE,SAAS,iBACb8B,EAAM,QAAQ,EAAE,MAAM,MAAM,SAAS,IAAO,OAAO9B,EAAA;AAAA,MAEvD;AAAA,IACF;AAIA,gBAAK,OAAO,MAAM;AAEhB,YAAMiC,IAASJ,IAASA,EAAO,QAAQ;AAIvC,aAAAG,EAAKC,CAAM,GAEJ,MAAMF,GAAY,MAAA;AAAA,IAC3B,CAAC,GAEM;AAAA,MACL,IAAI,OAAO;AAAE,eAAOD,EAAM,MAAM;AAAA,MAAM;AAAA,MACtC,IAAI,UAAU;AAAE,eAAOA,EAAM,MAAM;AAAA,MAAS;AAAA,MAC5C,IAAI,QAAQ;AAAE,eAAOA,EAAM,MAAM;AAAA,MAAO;AAAA,MACxC,IAAI,QAAQ;AAAE,eAAOA,EAAM;AAAA,MAAO;AAAA,MAClC,SAAS,MAAME,EAAKH,IAASA,EAAO,QAAQ,MAAc;AAAA,MAC1D,WAAW,CAACjB,MAAOkB,EAAM,UAAUlB,CAAE;AAAA,IAAA;AAAA,EAEzC;AAAA;AAAA;AAAA;AAAA,EAKO,QAAWC,GAAgB;AAChC,UAAMG,IAAO,KAAK;AAClB,SAAK,eAAe;AACpB,QAAI;AACF,aAAOH,EAAA;AAAA,IACT,UAAA;AACE,WAAK,eAAeG;AAAA,IACtB;AAAA,EACF;AAAA;AAAA,EAGO,iBAAiBtB,GAAeC,GAAgB;AACrD,SAAK,gBAAgB,EAAE,UAAAD,GAAU,WAAAC,EAAAA;AAAAA,EACnC;AAAA,EAEO,IAAOyC,GAAqE;AACjF,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,sGAAsG;AAIxH,QAAI,CAACA,KAAQ,OAAOA,EAAK,aAAc,YAAY;AACjD,YAAM1B,IAAW;AAAA;AAAA;AAAA;AAAA;AAKjB,oBAAQ,MAAMA,GAAU,EAAE,MAAA0B,EAAA,CAAM,GAC1B,IAAI,MAAM1B,CAAQ;AAAA,IAC1B;AACA,UAAM,CAACN,GAAKiC,CAAM,IAAI,KAAK,cAAc,SAASD,EAAK,KAAK;AAE5D,gBAAK,cAAc;AAAA,MACjB,MACSA,EAAK,UAAUC,CAAM;AAAA,MAE9B,CAACD,CAAI;AAAA,IAAA,GAGAhC;AAAA,EACT;AAAA,EAEQ,QAAQkC,GAAiBzB,GAAgB;AAC/C,QAAI;AACF,MAAAA,EAAA;AAAA,IACF,SAAS0B,GAAO;AACd,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACAA;AAAA,MAAA;AAAA,IAGJ;AAAA,EACF;AACF;ACpUO,MAAeC,EAAc;AAAA,EAClC,YAAsBrC,GAAwB;AAAxB,SAAA,SAAAA;AAAA,EAA0B;AAAA,EAA1B;AAAA;AAAA,EAEZ,oBAAoBC,GAAaG,GAAc;AACvD,WAAO,KAAK,OAAO,OAAOH,GAAK;AAAA,MAC7B,MAAAG;AAAA,MACA,UAAU,CAACkC,MAAM,OAAOA,KAAM,YAAY,CAAC,MAAMA,CAAC;AAAA,IAAA,CACnD;AAAA,EACH;AACF;"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/core.ts","../src/BaseREService.ts","../src/BaseREServiceEnhanced.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","import { ReactiveEngine } from './core';\n\nexport abstract class BaseREServiceEnhanced {\n constructor(protected engine: ReactiveEngine) {\n setTimeout(() => this.onInit(), 0)\n }\n\n protected onInit(): void { }\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","BaseREServiceEnhanced"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pravosleva/reactive-engine",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6-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",
|