Comparing version 0.3.0 to 0.4.0
1102
dist/dev-cjs.js
@@ -0,1 +1,2 @@ | ||
/* hydroxide v0.4.0 */ | ||
'use strict'; | ||
@@ -6,8 +7,7 @@ | ||
function ErrorBoundary(props) { | ||
try { | ||
return props.children; | ||
} | ||
catch (error) { | ||
return props.fallback || 'Error'; | ||
} | ||
try { | ||
return props.children; | ||
} catch (error) { | ||
return props.fallback || 'Error'; | ||
} | ||
} | ||
@@ -17,11 +17,14 @@ | ||
function List(props) { | ||
// @ts-expect-error | ||
return { $$list: props }; | ||
// @ts-expect-error | ||
return { | ||
$$list: props | ||
}; | ||
} | ||
/** a hook must be used inside a context */ | ||
function checkInvalidHookUsage(hookName) { | ||
if (!coreInfo.context) { | ||
throw new Error(`Invalid Hook Usage: Can not use ${hookName}() hook outside of a component`); | ||
} | ||
if (!coreInfo.context) { | ||
throw new Error(`Invalid Hook Usage: Can not use ${hookName}() hook outside of a component`); | ||
} | ||
} | ||
@@ -32,12 +35,13 @@ | ||
*/ | ||
function onConnect(cb) { | ||
{ | ||
checkInvalidHookUsage('onConnect'); | ||
} | ||
if (coreInfo.context.onConnect) { | ||
coreInfo.context.onConnect.push(cb); | ||
} | ||
else { | ||
coreInfo.context.onConnect = [cb]; | ||
} | ||
{ | ||
checkInvalidHookUsage('onConnect'); | ||
} | ||
if (coreInfo.context.onConnect) { | ||
coreInfo.context.onConnect.push(cb); | ||
} else { | ||
coreInfo.context.onConnect = [cb]; | ||
} | ||
} | ||
@@ -48,48 +52,40 @@ | ||
*/ | ||
function onDisconnect(cb) { | ||
{ | ||
checkInvalidHookUsage('onDisconnect'); | ||
} | ||
if (coreInfo.context.onDisconnect) { | ||
coreInfo.context.onDisconnect.push(cb); | ||
} | ||
else { | ||
coreInfo.context.onDisconnect = [cb]; | ||
} | ||
} | ||
{ | ||
checkInvalidHookUsage('onDisconnect'); | ||
} | ||
function onError(handleError) { | ||
checkInvalidHookUsage('onError'); | ||
if (coreInfo.context.onError) { | ||
coreInfo.context.onError.push(handleError); | ||
} | ||
else { | ||
coreInfo.context.onError = [handleError]; | ||
} | ||
if (coreInfo.context.onDisconnect) { | ||
coreInfo.context.onDisconnect.push(cb); | ||
} else { | ||
coreInfo.context.onDisconnect = [cb]; | ||
} | ||
} | ||
function detect(fn) { | ||
const outerDetected = coreInfo.detected; | ||
const outerDetectorEnabled = coreInfo.detectorEnabled; | ||
// set new detector | ||
coreInfo.detectorEnabled = true; | ||
coreInfo.detected = new Set(); | ||
// run fn | ||
const returnValue = fn(); | ||
const dependencies = coreInfo.detected; | ||
// add the detected dependencies of inner to outer | ||
if (outerDetectorEnabled) { | ||
dependencies.forEach((dep) => { | ||
outerDetected.add(dep); | ||
}); | ||
} | ||
// reset original detector | ||
coreInfo.detectorEnabled = outerDetectorEnabled; | ||
coreInfo.detected = outerDetected; | ||
// return detected dependencies and returnValue from fn | ||
return [dependencies, returnValue]; | ||
const outerDetected = coreInfo.detected; | ||
const outerDetectorEnabled = coreInfo.detectorEnabled; // set new detector | ||
coreInfo.detectorEnabled = true; | ||
coreInfo.detected = new Set(); // run fn | ||
const returnValue = fn(); | ||
const dependencies = coreInfo.detected; // add the detected dependencies of inner to outer | ||
if (outerDetectorEnabled) { | ||
dependencies.forEach(dep => { | ||
outerDetected.add(dep); | ||
}); | ||
} // reset original detector | ||
coreInfo.detectorEnabled = outerDetectorEnabled; | ||
coreInfo.detected = outerDetected; // return detected dependencies and returnValue from fn | ||
return [dependencies, returnValue]; | ||
} | ||
const invalidatedReactives = new Set(); | ||
// Phases | ||
const invalidatedReactives = new Set(); // Phases | ||
const LIST_PHASE = 0; | ||
@@ -100,6 +96,8 @@ const CONNECTION_PHASE = 1; | ||
/** information about batching */ | ||
const batching = { | ||
enabled: false, | ||
cloned: new Set() | ||
enabled: false, | ||
cloned: new Set() | ||
}; | ||
/** flush the subscribtions of give phase */ | ||
@@ -113,65 +111,76 @@ // function flushPhase(reactives: Reactive[], phase: Phase) { | ||
const renderQueue = []; | ||
const userEffectQueue = []; | ||
// only flush subs array till given length to avoid flushing the subs of next flush | ||
const userEffectQueue = []; // only flush subs array till given length to avoid flushing the subs of next flush | ||
function flushTaskQueue(taskQueue, len) { | ||
for (let i = 0; i < len; i++) { | ||
const set = taskQueue[i]; | ||
for (const cb of set) | ||
cb(); | ||
} | ||
// remove completed tasks | ||
taskQueue.splice(0, len); | ||
for (let i = 0; i < len; i++) { | ||
const set = taskQueue[i]; | ||
for (const cb of set) cb(); | ||
} // remove completed tasks | ||
taskQueue.splice(0, len); | ||
} | ||
/** call subscribers of all the invalidated reactives in proper order */ | ||
function flush() { | ||
invalidatedReactives.clear(); | ||
// must calculated length before flushing | ||
const connectionSubsLength = connectionQueue.length; | ||
const renderSubsLength = renderQueue.length; | ||
const userEffectSubsLength = userEffectQueue.length; | ||
if (connectionSubsLength !== 0) { | ||
flushTaskQueue(connectionQueue, connectionSubsLength); | ||
} | ||
if (renderSubsLength !== 0) { | ||
flushTaskQueue(renderQueue, renderSubsLength); | ||
} | ||
if (userEffectSubsLength !== 0) { | ||
flushTaskQueue(userEffectQueue, userEffectSubsLength); | ||
} | ||
// continue flushing until no invalidated reactives left | ||
if (invalidatedReactives.size !== 0) { | ||
flush(); | ||
} | ||
invalidatedReactives.clear(); // must calculated length before flushing | ||
const connectionSubsLength = connectionQueue.length; | ||
const renderSubsLength = renderQueue.length; | ||
const userEffectSubsLength = userEffectQueue.length; | ||
if (connectionSubsLength !== 0) { | ||
flushTaskQueue(connectionQueue, connectionSubsLength); | ||
} | ||
if (renderSubsLength !== 0) { | ||
flushTaskQueue(renderQueue, renderSubsLength); | ||
} | ||
if (userEffectSubsLength !== 0) { | ||
flushTaskQueue(userEffectQueue, userEffectSubsLength); | ||
} // continue flushing until no invalidated reactives left | ||
if (invalidatedReactives.size !== 0) { | ||
flush(); | ||
} | ||
} | ||
/** batch related updates to trigger single flush instead of multiple flushes */ | ||
function batch(fn) { | ||
batching.enabled = true; | ||
fn(); | ||
batching.enabled = false; | ||
batching.cloned.clear(); | ||
flush(); | ||
batching.enabled = true; | ||
fn(); | ||
batching.enabled = false; | ||
batching.cloned.clear(); | ||
flush(); | ||
} | ||
/** invalidate a reactive to notifiy subscribers */ | ||
function invalidate(reactive) { | ||
if (!batching.enabled) { | ||
reactive.subs[CONNECTION_PHASE]?.forEach((cb) => cb()); | ||
reactive.subs[RENDER_PHASE]?.forEach((cb) => cb()); | ||
reactive.subs[USER_EFFECT_PHASE]?.forEach((cb) => cb()); | ||
reactive.updateCount++; | ||
if (!batching.enabled) { | ||
reactive.subs[CONNECTION_PHASE]?.forEach(cb => cb()); | ||
reactive.subs[RENDER_PHASE]?.forEach(cb => cb()); | ||
reactive.subs[USER_EFFECT_PHASE]?.forEach(cb => cb()); | ||
reactive.updateCount++; | ||
} else { | ||
if (!invalidatedReactives.has(reactive)) { | ||
invalidatedReactives.add(reactive); // add subs | ||
if (reactive.subs[CONNECTION_PHASE]) { | ||
connectionQueue.push(reactive.subs[CONNECTION_PHASE]); | ||
} | ||
if (reactive.subs[RENDER_PHASE]) { | ||
renderQueue.push(reactive.subs[RENDER_PHASE]); | ||
} | ||
if (reactive.subs[USER_EFFECT_PHASE]) { | ||
userEffectQueue.push(reactive.subs[USER_EFFECT_PHASE]); | ||
} | ||
} | ||
else { | ||
if (!invalidatedReactives.has(reactive)) { | ||
invalidatedReactives.add(reactive); | ||
// add subs | ||
if (reactive.subs[CONNECTION_PHASE]) { | ||
connectionQueue.push(reactive.subs[CONNECTION_PHASE]); | ||
} | ||
if (reactive.subs[RENDER_PHASE]) { | ||
renderQueue.push(reactive.subs[RENDER_PHASE]); | ||
} | ||
if (reactive.subs[USER_EFFECT_PHASE]) { | ||
userEffectQueue.push(reactive.subs[USER_EFFECT_PHASE]); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -185,34 +194,36 @@ | ||
function subscribe(reactive, callback, phase, context = coreInfo.context) { | ||
if (!context) { | ||
throw new Error('subscriptions can only be created inside a context'); | ||
if (!context) { | ||
throw new Error('subscriptions can only be created inside a context'); | ||
} | ||
const subs = reactive.subs[phase] || (reactive.subs[phase] = new Set()); // subscribe | ||
subs.add(callback); // if non local dependencies, setup unsubscribe on disconnect and resubscribe on connect | ||
if (context !== reactive.context) { | ||
const unsub = () => { | ||
subs.delete(callback); | ||
}; | ||
const resub = () => { | ||
subs.add(callback); | ||
}; // unsubscribe when context gets disconnected | ||
if (!context.onDisconnect) { | ||
context.onDisconnect = [unsub]; | ||
} else { | ||
context.onDisconnect.push(unsub); | ||
} // subscribe when context is connected | ||
if (!context.onConnect) { | ||
context.onConnect = [resub]; | ||
} else { | ||
context.onConnect.push(resub); | ||
} | ||
const subs = reactive.subs[phase] || (reactive.subs[phase] = new Set()); | ||
// subscribe | ||
subs.add(callback); | ||
// if non local dependencies, setup unsubscribe on disconnect and resubscribe on connect | ||
if (context !== reactive.context) { | ||
const unsub = () => { | ||
subs.delete(callback); | ||
}; | ||
const resub = () => { | ||
subs.add(callback); | ||
}; | ||
// unsubscribe when context gets disconnected | ||
if (!context.onDisconnect) { | ||
context.onDisconnect = [unsub]; | ||
} | ||
else { | ||
context.onDisconnect.push(unsub); | ||
} | ||
// subscribe when context is connected | ||
if (!context.onConnect) { | ||
context.onConnect = [resub]; | ||
} | ||
else { | ||
context.onConnect.push(resub); | ||
} | ||
} | ||
} | ||
} | ||
function unsubscribe(reactive, callback, phase) { | ||
reactive.subs[phase].delete(callback); | ||
reactive.subs[phase].delete(callback); | ||
} | ||
@@ -229,49 +240,53 @@ | ||
*/ | ||
function effect(callback, phase = USER_EFFECT_PHASE) { | ||
const info = { | ||
deps: new Set() | ||
}; | ||
const effectContext = coreInfo.context; | ||
if (!effectContext) { | ||
console.error('invalid effect:', callback); | ||
throw new Error('effects can be only created inside a context'); | ||
const info = { | ||
deps: new Set() | ||
}; | ||
const effectContext = coreInfo.context; | ||
if (!effectContext) { | ||
console.error('invalid effect:', callback); | ||
throw new Error('effects can be only created inside a context'); | ||
} | ||
function runEffect() { | ||
const [newDeps] = detect(callback); // unsubscribe from reactives that are not in the newDeps | ||
info.deps.forEach(dep => { | ||
if (!newDeps.has(dep)) { | ||
unsubscribe(dep, runEffect, phase); | ||
} | ||
}); // subscribe to deps that are not already subscribed | ||
newDeps.forEach(newDep => { | ||
if (!info.deps.has(newDep)) { | ||
subscribe(newDep, runEffect, phase, effectContext); | ||
} | ||
}); // update the dependencies | ||
info.deps = newDeps; | ||
} | ||
function createEffect() { | ||
info.deps = detect(callback)[0]; | ||
info.deps.forEach(dep => subscribe(dep, runEffect, phase, effectContext)); | ||
} // render effects can be called immediately and since they don't have branching logic | ||
// no need to update the dependencies | ||
if (phase === RENDER_PHASE) { | ||
info.deps = detect(callback)[0]; | ||
info.deps.forEach(dep => subscribe(dep, callback, phase, effectContext)); | ||
} // effect or connection phase | ||
else { | ||
// run the effect after the context is connected | ||
if (effectContext.onConnect) { | ||
effectContext.onConnect.push(createEffect); | ||
} else { | ||
effectContext.onConnect = [createEffect]; | ||
} | ||
function runEffect() { | ||
const [newDeps] = detect(callback); | ||
// unsubscribe from reactives that are not in the newDeps | ||
info.deps.forEach((dep) => { | ||
if (!newDeps.has(dep)) { | ||
unsubscribe(dep, runEffect, phase); | ||
} | ||
}); | ||
// subscribe to deps that are not already subscribed | ||
newDeps.forEach((newDep) => { | ||
if (!info.deps.has(newDep)) { | ||
subscribe(newDep, runEffect, phase, effectContext); | ||
} | ||
}); | ||
// update the dependencies | ||
info.deps = newDeps; | ||
} | ||
function createEffect() { | ||
info.deps = detect(callback)[0]; | ||
info.deps.forEach((dep) => subscribe(dep, runEffect, phase, effectContext)); | ||
} | ||
// render effects can be called immediately and since they don't have branching logic | ||
// no need to update the dependencies | ||
if (phase === RENDER_PHASE) { | ||
info.deps = detect(callback)[0]; | ||
info.deps.forEach((dep) => subscribe(dep, callback, phase, effectContext)); | ||
} | ||
// effect or connection phase | ||
else { | ||
// run the effect after the context is connected | ||
if (effectContext.onConnect) { | ||
effectContext.onConnect.push(createEffect); | ||
} | ||
else { | ||
effectContext.onConnect = [createEffect]; | ||
} | ||
} | ||
return info; | ||
} | ||
return info; | ||
} | ||
@@ -284,139 +299,158 @@ | ||
*/ | ||
function memo(fn) { | ||
function update() { | ||
[state.deps, state.value] = detect(fn); | ||
cacheId = computeCacheId(state.deps); | ||
function update() { | ||
[state.deps, state.value] = detect(fn); | ||
cacheId = computeCacheId(state.deps); | ||
} // create computed state | ||
// @ts-expect-error | ||
const state = function () { | ||
const id = computeCacheId(state.deps); | ||
const isValueCorrect = cacheId === id; // if the value is not correct, update the value, cacheId and deps | ||
if (!isValueCorrect) { | ||
update(); | ||
} // if the detector is enabled, push the computed's deps | ||
else if (coreInfo.detectorEnabled) { | ||
state.deps.forEach(dep => { | ||
coreInfo.detected.add(dep); | ||
}); | ||
} | ||
// create computed state | ||
// @ts-expect-error | ||
const state = function () { | ||
const id = computeCacheId(state.deps); | ||
const isValueCorrect = cacheId === id; | ||
// if the value is not correct, update the value, cacheId and deps | ||
if (!isValueCorrect) { | ||
update(); | ||
} | ||
// if the detector is enabled, push the computed's deps | ||
else if (coreInfo.detectorEnabled) { | ||
state.deps.forEach((dep) => { | ||
coreInfo.detected.add(dep); | ||
}); | ||
} | ||
return state.value; | ||
}; | ||
[state.deps, state.value] = detect(fn); | ||
let cacheId = computeCacheId(state.deps); | ||
return state; | ||
return state.value; | ||
} // run the fn and get return value and dependecies | ||
; | ||
[state.deps, state.value] = detect(fn); | ||
let cacheId = computeCacheId(state.deps); | ||
return state; | ||
} | ||
function computeCacheId(deps) { | ||
let cacheId = 0; | ||
deps.forEach((dep) => { | ||
cacheId += dep.updateCount; | ||
}); | ||
return cacheId; | ||
let cacheId = 0; | ||
deps.forEach(dep => { | ||
cacheId += dep.updateCount; | ||
}); | ||
return cacheId; | ||
} | ||
function mutativeSwap(arr, i, j) { | ||
const temp = arr[i]; | ||
arr[i] = arr[j]; | ||
arr[j] = temp; | ||
const temp = arr[i]; | ||
arr[i] = arr[j]; | ||
arr[j] = temp; | ||
} | ||
function targetKey(obj, path) { | ||
if (path.length === 1) | ||
return [obj, path[0]]; | ||
const lastIndex = path.length - 1; | ||
let target = obj; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target = target[path[i]]; | ||
} | ||
return [target, path[lastIndex]]; | ||
if (path.length === 1) return [obj, path[0]]; | ||
const lastIndex = path.length - 1; | ||
let target = obj; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target = target[path[i]]; | ||
} | ||
return [target, path[lastIndex]]; | ||
} | ||
function valueAt(obj, path, start = 0, end = path.length - 1) { | ||
let target = obj; | ||
for (let i = start; i <= end; i++) { | ||
target = target[path[i]]; | ||
} | ||
return target; | ||
let target = obj; | ||
for (let i = start; i <= end; i++) { | ||
target = target[path[i]]; | ||
} | ||
return target; | ||
} | ||
function immutativeRemove(arr, index, count) { | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// if arr is already cloned in this batch | ||
if (batching.cloned.has(arr)) { | ||
// just mutate the cloned array | ||
arr.splice(index, count); | ||
return arr; // don't do anything else | ||
} | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// if arr is already cloned in this batch | ||
if (batching.cloned.has(arr)) { | ||
// just mutate the cloned array | ||
arr.splice(index, count); | ||
return arr; // don't do anything else | ||
} | ||
// clone the array if it's not already cloned or batching is disabled | ||
const arrClone = [...arr.slice(0, index), ...arr.slice(index + count)]; | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
return arrClone; | ||
} // clone the array if it's not already cloned or batching is disabled | ||
const arrClone = [...arr.slice(0, index), ...arr.slice(index + count)]; | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
return arrClone; | ||
} | ||
function immutativeSet(obj, path, newValue) { | ||
let root; | ||
// if batching is enabled, and the object is already cloned once in the batchf | ||
if (batching.enabled && batching.cloned.has(obj)) { | ||
// don't clone it | ||
root = obj; | ||
} | ||
else { | ||
// else clone it | ||
root = shallowClone(obj); | ||
// and mark it as cloned | ||
batching.cloned.add(root); | ||
} | ||
const lastIndex = path.length - 1; | ||
let target = root; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target[path[i]] = shallowClone(target[path[i]]); | ||
target = target[path[i]]; | ||
} | ||
target[path[lastIndex]] = newValue; | ||
return root; | ||
let root; // if batching is enabled, and the object is already cloned once in the batchf | ||
if (batching.enabled && batching.cloned.has(obj)) { | ||
// don't clone it | ||
root = obj; | ||
} else { | ||
// else clone it | ||
root = shallowClone(obj); // and mark it as cloned | ||
batching.cloned.add(root); | ||
} | ||
const lastIndex = path.length - 1; | ||
let target = root; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target[path[i]] = shallowClone(target[path[i]]); | ||
target = target[path[i]]; | ||
} | ||
target[path[lastIndex]] = newValue; | ||
return root; | ||
} | ||
function immutativeInsert(arr, index, values) { | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// if this array has already been cloned once in this batch | ||
if (batching.cloned.has(arr)) { | ||
// no need to clone the array, just mutate the array and insert the items | ||
arr.splice(index, 0, ...values); | ||
return; // don't do anything else | ||
} | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// if this array has already been cloned once in this batch | ||
if (batching.cloned.has(arr)) { | ||
// no need to clone the array, just mutate the array and insert the items | ||
arr.splice(index, 0, ...values); | ||
return; // don't do anything else | ||
} | ||
// clone the array if batching is disabled or this array has not been cloned yet in this batch | ||
const arrClone = [...arr.slice(0, index), ...values, ...arr.slice(index)]; | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
return arrClone; | ||
} // clone the array if batching is disabled or this array has not been cloned yet in this batch | ||
const arrClone = [...arr.slice(0, index), ...values, ...arr.slice(index)]; | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
return arrClone; | ||
} | ||
function immutativeSwap(arr, i, j) { | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// and if this array has already been cloned once in this batch | ||
if (batching.cloned.has(arr)) { | ||
// then just mutate the array for swap | ||
mutativeSwap(arr, i, j); | ||
return arr; // don't do anything else | ||
} | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// and if this array has already been cloned once in this batch | ||
if (batching.cloned.has(arr)) { | ||
// then just mutate the array for swap | ||
mutativeSwap(arr, i, j); | ||
return arr; // don't do anything else | ||
} | ||
// clone the array if batching is disabled or this array has not been cloned yet in this batch | ||
const arrClone = [...arr]; | ||
// mark this array as cloned in this batch | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
mutativeSwap(arrClone, i, j); | ||
return arrClone; | ||
} | ||
// create a shallow clone of give object or array | ||
} // clone the array if batching is disabled or this array has not been cloned yet in this batch | ||
const arrClone = [...arr]; // mark this array as cloned in this batch | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
mutativeSwap(arrClone, i, j); | ||
return arrClone; | ||
} // create a shallow clone of give object or array | ||
function shallowClone(obj) { | ||
// @ts-ignore | ||
return Array.isArray(obj) ? [...obj] : { ...obj }; | ||
// @ts-ignore | ||
return Array.isArray(obj) ? [...obj] : { ...obj | ||
}; | ||
} | ||
@@ -427,279 +461,296 @@ | ||
/** set new value */ | ||
function set(newValue) { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
if (path) { | ||
if (state.mutable) { | ||
const lastIndex = path.length - 1; | ||
let target = state.value; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target = target[path[i]]; | ||
} | ||
if (newValue !== target[path[lastIndex]]) { | ||
target[path[lastIndex]] = newValue; | ||
} | ||
} | ||
else { | ||
state.value = immutativeSet(state.value, path, newValue); | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; | ||
if (path) { | ||
if (state.mutable) { | ||
const lastIndex = path.length - 1; | ||
let target = state.value; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target = target[path[i]]; | ||
} | ||
if (newValue !== target[path[lastIndex]]) { | ||
target[path[lastIndex]] = newValue; | ||
} | ||
} else { | ||
state.value = immutativeSet(state.value, path, newValue); | ||
} | ||
else { | ||
if (newValue !== state.value) { | ||
state.value = newValue; | ||
} | ||
} else { | ||
if (newValue !== state.value) { | ||
state.value = newValue; | ||
} | ||
state.subs[LIST_PHASE]?.forEach((cb) => cb('set', path, newValue)); | ||
invalidate(state); | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
state.subs[LIST_PHASE]?.forEach(cb => cb('set', path, newValue)); | ||
invalidate(state); | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
/** perform an operation on reactive */ | ||
function perform(operation) { | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; | ||
if (path) { | ||
const oldValue = valueAt(state.value, path); | ||
const newValue = operation(oldValue); | ||
if (oldValue === newValue) return state; // @ts-expect-error | ||
return state.set(newValue); | ||
} else { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
if (path) { | ||
const oldValue = valueAt(state.value, path); | ||
const newValue = operation(oldValue); | ||
if (oldValue === newValue) | ||
return state; | ||
// @ts-expect-error | ||
return state.set(newValue); | ||
} | ||
else { | ||
// @ts-expect-error | ||
const newValue = operation(state.value); | ||
if (state.value === newValue) | ||
return state; | ||
// @ts-expect-error | ||
return state.set(newValue); | ||
} | ||
const newValue = operation(state.value); | ||
if (state.value === newValue) return state; // @ts-expect-error | ||
return state.set(newValue); | ||
} | ||
} | ||
/** insert a list of items on reactive at given index */ | ||
function insertList(_index, values) { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
// insert at path | ||
if (path) { | ||
const arr = valueAt(state.value, path); | ||
const index = _index < 0 ? arr.length + _index + 1 : _index; | ||
if (state.mutable) { | ||
arr.splice(index, 0, ...values); | ||
} | ||
else { | ||
state.value = immutativeSet(state, path, | ||
// @ts-ignore | ||
immutativeInsert(arr, index, values)); | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; // insert at path | ||
if (path) { | ||
const arr = valueAt(state.value, path); | ||
const index = _index < 0 ? arr.length + _index + 1 : _index; | ||
if (state.mutable) { | ||
arr.splice(index, 0, ...values); | ||
} else { | ||
state.value = immutativeSet(state, path, // @ts-ignore | ||
immutativeInsert(arr, index, values)); | ||
} | ||
// insert on root | ||
else { | ||
const index = _index < 0 ? state.value.length + _index + 1 : _index; | ||
if (state.mutable) { | ||
state.value.splice(index, 0, ...values); | ||
} | ||
else { | ||
state.value = immutativeInsert(state.value, index, values); | ||
} | ||
state.subs[LIST_PHASE]?.forEach((cb) => { | ||
cb('insert', index, values); | ||
}); | ||
} // insert on root | ||
else { | ||
const index = _index < 0 ? state.value.length + _index + 1 : _index; | ||
if (state.mutable) { | ||
state.value.splice(index, 0, ...values); | ||
} else { | ||
state.value = immutativeInsert(state.value, index, values); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
invalidate(state); | ||
return state; | ||
state.subs[LIST_PHASE]?.forEach(cb => { | ||
cb('insert', index, values); | ||
}); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
invalidate(state); | ||
return state; | ||
} | ||
/** insert a single item at given index */ | ||
function insert(index, value) { | ||
// @ts-expect-error | ||
$reactive = ($reactive || this); | ||
return insertList(index, [value]); | ||
// @ts-expect-error | ||
$reactive = $reactive || this; | ||
return insertList(index, [value]); | ||
} | ||
/** push single item to reactive */ | ||
function push(value) { | ||
// @ts-expect-error | ||
$reactive = ($reactive || this); | ||
return insertList(-1, [value]); | ||
// @ts-expect-error | ||
$reactive = $reactive || this; | ||
return insertList(-1, [value]); | ||
} | ||
/** push list of items to reactive */ | ||
function pushList(values) { | ||
// @ts-expect-error | ||
$reactive = ($reactive || this); | ||
return insertList(-1, values); | ||
// @ts-expect-error | ||
$reactive = $reactive || this; | ||
return insertList(-1, values); | ||
} | ||
/** remove item at given index from array */ | ||
function remove(_index, count = 1) { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
// remove at path | ||
if (path) { | ||
const arr = valueAt(state.value, path); | ||
const index = _index < 0 ? arr.length + _index : _index; | ||
if (state.mutable) { | ||
arr.splice(index, count); | ||
} | ||
else { | ||
state.value = immutativeSet(state.value, path, immutativeRemove(arr, index, count)); | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; // remove at path | ||
if (path) { | ||
const arr = valueAt(state.value, path); | ||
const index = _index < 0 ? arr.length + _index : _index; | ||
if (state.mutable) { | ||
arr.splice(index, count); | ||
} else { | ||
state.value = immutativeSet(state.value, path, immutativeRemove(arr, index, count)); | ||
} | ||
// remove on root | ||
else { | ||
const index = _index < 0 ? state.value.length + _index : _index; | ||
if (state.mutable) { | ||
state.value.splice(index, count); | ||
} | ||
else { | ||
state.value = immutativeRemove(state.value, index, count); | ||
} | ||
state.subs[LIST_PHASE]?.forEach((cb) => cb('remove', index, count)); | ||
} // remove on root | ||
else { | ||
const index = _index < 0 ? state.value.length + _index : _index; | ||
if (state.mutable) { | ||
state.value.splice(index, count); | ||
} else { | ||
state.value = immutativeRemove(state.value, index, count); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
invalidate(state); | ||
return state; | ||
state.subs[LIST_PHASE]?.forEach(cb => cb('remove', index, count)); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
invalidate(state); | ||
return state; | ||
} | ||
/** remove items from end of array */ | ||
function pop(count = 1) { | ||
// @ts-expect-error | ||
$reactive = ($reactive || this); | ||
return remove(-1 * count, count); | ||
// @ts-expect-error | ||
$reactive = $reactive || this; | ||
return remove(-1 * count, count); | ||
} | ||
/** clear array */ | ||
function clear() { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
// deep clear | ||
if (path) { | ||
if (state.mutable) { | ||
const [target, key] = targetKey(state.value, path); | ||
if (target[key].length !== 0) { | ||
target[key] = []; | ||
invalidate(state); | ||
} | ||
} | ||
else { | ||
if (state.value.length !== 0) { | ||
state.value = immutativeSet(state.value, path, []); | ||
invalidate(state); | ||
} | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; // deep clear | ||
if (path) { | ||
if (state.mutable) { | ||
const [target, key] = targetKey(state.value, path); | ||
if (target[key].length !== 0) { | ||
target[key] = []; | ||
invalidate(state); | ||
} | ||
} else { | ||
if (state.value.length !== 0) { | ||
state.value = immutativeSet(state.value, path, []); | ||
invalidate(state); | ||
} | ||
} | ||
// clear at root | ||
else { | ||
if (state.value.length !== 0) { | ||
state.value = []; | ||
state.subs[LIST_PHASE]?.forEach((cb) => cb('clear')); | ||
invalidate(state); | ||
} | ||
} // clear at root | ||
else { | ||
if (state.value.length !== 0) { | ||
state.value = []; | ||
state.subs[LIST_PHASE]?.forEach(cb => cb('clear')); | ||
invalidate(state); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
/** swap values at given indexes */ | ||
function swap(i, j) { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
if (path) { | ||
// deep swap | ||
const arr = valueAt(state.value, path); | ||
if (state.mutable) { | ||
// mutative deep swap | ||
mutativeSwap(arr, i, j); | ||
} | ||
else { | ||
// immutative deep swap | ||
const arr = valueAt(state.value, path); | ||
state.value = immutativeSet($reactive, path, immutativeSwap(arr, i, j)); | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; | ||
if (path) { | ||
// deep swap | ||
const arr = valueAt(state.value, path); | ||
if (state.mutable) { | ||
// mutative deep swap | ||
mutativeSwap(arr, i, j); | ||
} else { | ||
// immutative deep swap | ||
const arr = valueAt(state.value, path); | ||
state.value = immutativeSet($reactive, path, immutativeSwap(arr, i, j)); | ||
} | ||
else { | ||
// shallow swap | ||
if (state.mutable) { | ||
// mutative shallow swap | ||
mutativeSwap(state.value, i, j); | ||
} | ||
else { | ||
// immutative shallow swap | ||
state.value = immutativeSwap(state.value, i, j); | ||
} | ||
state.subs[LIST_PHASE]?.forEach((cb) => cb('swap', i, j)); | ||
} else { | ||
// shallow swap | ||
if (state.mutable) { | ||
// mutative shallow swap | ||
mutativeSwap(state.value, i, j); | ||
} else { | ||
// immutative shallow swap | ||
state.value = immutativeSwap(state.value, i, j); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
state.subs[LIST_PHASE]?.forEach(cb => cb('swap', i, j)); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
const reactiveMethods = { | ||
set, | ||
insert, | ||
insertList, | ||
remove, | ||
push, | ||
pushList, | ||
swap, | ||
clear, | ||
perform, | ||
pop | ||
set, | ||
insert, | ||
insertList, | ||
remove, | ||
push, | ||
pushList, | ||
swap, | ||
clear, | ||
perform, | ||
pop | ||
}; | ||
/** target given path in reactive value */ | ||
function $(...path) { | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias | ||
$reactive = this; | ||
// @ts-expect-error | ||
$path = path; | ||
// @ts-expect-error | ||
return reactiveMethods; | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias | ||
$reactive = this; // @ts-expect-error | ||
$path = path; // @ts-expect-error | ||
return reactiveMethods; | ||
} | ||
function reactive(value) { | ||
// @ts-expect-error | ||
const state = function $Reactive() { | ||
// detect | ||
if (coreInfo.detectorEnabled) { | ||
coreInfo.detected.add(state); | ||
} | ||
return state.value; | ||
}; | ||
state.value = value; | ||
state.subs = new Array(4); | ||
state.context = coreInfo.context; | ||
state.updateCount = 0; | ||
state.mutable = true; | ||
state.$ = $; // @ts-expect-error | ||
state.set = set; // @ts-expect-error | ||
state.perform = perform; | ||
if (Array.isArray(value)) { | ||
// @ts-expect-error | ||
const state = function $Reactive() { | ||
// detect | ||
if (coreInfo.detectorEnabled) { | ||
coreInfo.detected.add(state); | ||
} | ||
return state.value; | ||
}; | ||
state.value = value; | ||
state.subs = new Array(4); | ||
state.context = coreInfo.context; | ||
state.updateCount = 0; | ||
state.mutable = true; | ||
state.$ = $; | ||
// @ts-expect-error | ||
state.set = set; | ||
// @ts-expect-error | ||
state.perform = perform; | ||
if (Array.isArray(value)) { | ||
// @ts-expect-error | ||
state.insertList = insertList; | ||
// @ts-expect-error | ||
state.push = push; | ||
// @ts-expect-error | ||
state.pushList = pushList; | ||
// @ts-expect-error | ||
state.insert = insert; | ||
// @ts-expect-error | ||
state.remove = remove; | ||
// @ts-expect-error | ||
state.clear = clear; | ||
// @ts-expect-error | ||
state.swap = swap; | ||
// @ts-expect-error | ||
state.pop = pop; | ||
} | ||
return state; | ||
state.insertList = insertList; // @ts-expect-error | ||
state.push = push; // @ts-expect-error | ||
state.pushList = pushList; // @ts-expect-error | ||
state.insert = insert; // @ts-expect-error | ||
state.remove = remove; // @ts-expect-error | ||
state.clear = clear; // @ts-expect-error | ||
state.swap = swap; // @ts-expect-error | ||
state.pop = pop; | ||
} | ||
return state; | ||
} | ||
const coreInfo = { | ||
context: null, | ||
detectorEnabled: false, | ||
detected: new Set() | ||
context: null, | ||
detectorEnabled: false, | ||
detected: new Set() | ||
}; | ||
@@ -722,3 +773,2 @@ | ||
exports.onDisconnect = onDisconnect; | ||
exports.onError = onError; | ||
exports.reactive = reactive; | ||
@@ -725,0 +775,0 @@ exports.subscribe = subscribe; |
1103
dist/dev-esm.js
@@ -0,8 +1,8 @@ | ||
/* hydroxide v0.4.0 */ | ||
function ErrorBoundary(props) { | ||
try { | ||
return props.children; | ||
} | ||
catch (error) { | ||
return props.fallback || 'Error'; | ||
} | ||
try { | ||
return props.children; | ||
} catch (error) { | ||
return props.fallback || 'Error'; | ||
} | ||
} | ||
@@ -12,11 +12,14 @@ | ||
function List(props) { | ||
// @ts-expect-error | ||
return { $$list: props }; | ||
// @ts-expect-error | ||
return { | ||
$$list: props | ||
}; | ||
} | ||
/** a hook must be used inside a context */ | ||
function checkInvalidHookUsage(hookName) { | ||
if (!coreInfo.context) { | ||
throw new Error(`Invalid Hook Usage: Can not use ${hookName}() hook outside of a component`); | ||
} | ||
if (!coreInfo.context) { | ||
throw new Error(`Invalid Hook Usage: Can not use ${hookName}() hook outside of a component`); | ||
} | ||
} | ||
@@ -27,12 +30,13 @@ | ||
*/ | ||
function onConnect(cb) { | ||
{ | ||
checkInvalidHookUsage('onConnect'); | ||
} | ||
if (coreInfo.context.onConnect) { | ||
coreInfo.context.onConnect.push(cb); | ||
} | ||
else { | ||
coreInfo.context.onConnect = [cb]; | ||
} | ||
{ | ||
checkInvalidHookUsage('onConnect'); | ||
} | ||
if (coreInfo.context.onConnect) { | ||
coreInfo.context.onConnect.push(cb); | ||
} else { | ||
coreInfo.context.onConnect = [cb]; | ||
} | ||
} | ||
@@ -43,48 +47,40 @@ | ||
*/ | ||
function onDisconnect(cb) { | ||
{ | ||
checkInvalidHookUsage('onDisconnect'); | ||
} | ||
if (coreInfo.context.onDisconnect) { | ||
coreInfo.context.onDisconnect.push(cb); | ||
} | ||
else { | ||
coreInfo.context.onDisconnect = [cb]; | ||
} | ||
} | ||
{ | ||
checkInvalidHookUsage('onDisconnect'); | ||
} | ||
function onError(handleError) { | ||
checkInvalidHookUsage('onError'); | ||
if (coreInfo.context.onError) { | ||
coreInfo.context.onError.push(handleError); | ||
} | ||
else { | ||
coreInfo.context.onError = [handleError]; | ||
} | ||
if (coreInfo.context.onDisconnect) { | ||
coreInfo.context.onDisconnect.push(cb); | ||
} else { | ||
coreInfo.context.onDisconnect = [cb]; | ||
} | ||
} | ||
function detect(fn) { | ||
const outerDetected = coreInfo.detected; | ||
const outerDetectorEnabled = coreInfo.detectorEnabled; | ||
// set new detector | ||
coreInfo.detectorEnabled = true; | ||
coreInfo.detected = new Set(); | ||
// run fn | ||
const returnValue = fn(); | ||
const dependencies = coreInfo.detected; | ||
// add the detected dependencies of inner to outer | ||
if (outerDetectorEnabled) { | ||
dependencies.forEach((dep) => { | ||
outerDetected.add(dep); | ||
}); | ||
} | ||
// reset original detector | ||
coreInfo.detectorEnabled = outerDetectorEnabled; | ||
coreInfo.detected = outerDetected; | ||
// return detected dependencies and returnValue from fn | ||
return [dependencies, returnValue]; | ||
const outerDetected = coreInfo.detected; | ||
const outerDetectorEnabled = coreInfo.detectorEnabled; // set new detector | ||
coreInfo.detectorEnabled = true; | ||
coreInfo.detected = new Set(); // run fn | ||
const returnValue = fn(); | ||
const dependencies = coreInfo.detected; // add the detected dependencies of inner to outer | ||
if (outerDetectorEnabled) { | ||
dependencies.forEach(dep => { | ||
outerDetected.add(dep); | ||
}); | ||
} // reset original detector | ||
coreInfo.detectorEnabled = outerDetectorEnabled; | ||
coreInfo.detected = outerDetected; // return detected dependencies and returnValue from fn | ||
return [dependencies, returnValue]; | ||
} | ||
const invalidatedReactives = new Set(); | ||
// Phases | ||
const invalidatedReactives = new Set(); // Phases | ||
const LIST_PHASE = 0; | ||
@@ -95,6 +91,8 @@ const CONNECTION_PHASE = 1; | ||
/** information about batching */ | ||
const batching = { | ||
enabled: false, | ||
cloned: new Set() | ||
enabled: false, | ||
cloned: new Set() | ||
}; | ||
/** flush the subscribtions of give phase */ | ||
@@ -108,65 +106,76 @@ // function flushPhase(reactives: Reactive[], phase: Phase) { | ||
const renderQueue = []; | ||
const userEffectQueue = []; | ||
// only flush subs array till given length to avoid flushing the subs of next flush | ||
const userEffectQueue = []; // only flush subs array till given length to avoid flushing the subs of next flush | ||
function flushTaskQueue(taskQueue, len) { | ||
for (let i = 0; i < len; i++) { | ||
const set = taskQueue[i]; | ||
for (const cb of set) | ||
cb(); | ||
} | ||
// remove completed tasks | ||
taskQueue.splice(0, len); | ||
for (let i = 0; i < len; i++) { | ||
const set = taskQueue[i]; | ||
for (const cb of set) cb(); | ||
} // remove completed tasks | ||
taskQueue.splice(0, len); | ||
} | ||
/** call subscribers of all the invalidated reactives in proper order */ | ||
function flush() { | ||
invalidatedReactives.clear(); | ||
// must calculated length before flushing | ||
const connectionSubsLength = connectionQueue.length; | ||
const renderSubsLength = renderQueue.length; | ||
const userEffectSubsLength = userEffectQueue.length; | ||
if (connectionSubsLength !== 0) { | ||
flushTaskQueue(connectionQueue, connectionSubsLength); | ||
} | ||
if (renderSubsLength !== 0) { | ||
flushTaskQueue(renderQueue, renderSubsLength); | ||
} | ||
if (userEffectSubsLength !== 0) { | ||
flushTaskQueue(userEffectQueue, userEffectSubsLength); | ||
} | ||
// continue flushing until no invalidated reactives left | ||
if (invalidatedReactives.size !== 0) { | ||
flush(); | ||
} | ||
invalidatedReactives.clear(); // must calculated length before flushing | ||
const connectionSubsLength = connectionQueue.length; | ||
const renderSubsLength = renderQueue.length; | ||
const userEffectSubsLength = userEffectQueue.length; | ||
if (connectionSubsLength !== 0) { | ||
flushTaskQueue(connectionQueue, connectionSubsLength); | ||
} | ||
if (renderSubsLength !== 0) { | ||
flushTaskQueue(renderQueue, renderSubsLength); | ||
} | ||
if (userEffectSubsLength !== 0) { | ||
flushTaskQueue(userEffectQueue, userEffectSubsLength); | ||
} // continue flushing until no invalidated reactives left | ||
if (invalidatedReactives.size !== 0) { | ||
flush(); | ||
} | ||
} | ||
/** batch related updates to trigger single flush instead of multiple flushes */ | ||
function batch(fn) { | ||
batching.enabled = true; | ||
fn(); | ||
batching.enabled = false; | ||
batching.cloned.clear(); | ||
flush(); | ||
batching.enabled = true; | ||
fn(); | ||
batching.enabled = false; | ||
batching.cloned.clear(); | ||
flush(); | ||
} | ||
/** invalidate a reactive to notifiy subscribers */ | ||
function invalidate(reactive) { | ||
if (!batching.enabled) { | ||
reactive.subs[CONNECTION_PHASE]?.forEach((cb) => cb()); | ||
reactive.subs[RENDER_PHASE]?.forEach((cb) => cb()); | ||
reactive.subs[USER_EFFECT_PHASE]?.forEach((cb) => cb()); | ||
reactive.updateCount++; | ||
if (!batching.enabled) { | ||
reactive.subs[CONNECTION_PHASE]?.forEach(cb => cb()); | ||
reactive.subs[RENDER_PHASE]?.forEach(cb => cb()); | ||
reactive.subs[USER_EFFECT_PHASE]?.forEach(cb => cb()); | ||
reactive.updateCount++; | ||
} else { | ||
if (!invalidatedReactives.has(reactive)) { | ||
invalidatedReactives.add(reactive); // add subs | ||
if (reactive.subs[CONNECTION_PHASE]) { | ||
connectionQueue.push(reactive.subs[CONNECTION_PHASE]); | ||
} | ||
if (reactive.subs[RENDER_PHASE]) { | ||
renderQueue.push(reactive.subs[RENDER_PHASE]); | ||
} | ||
if (reactive.subs[USER_EFFECT_PHASE]) { | ||
userEffectQueue.push(reactive.subs[USER_EFFECT_PHASE]); | ||
} | ||
} | ||
else { | ||
if (!invalidatedReactives.has(reactive)) { | ||
invalidatedReactives.add(reactive); | ||
// add subs | ||
if (reactive.subs[CONNECTION_PHASE]) { | ||
connectionQueue.push(reactive.subs[CONNECTION_PHASE]); | ||
} | ||
if (reactive.subs[RENDER_PHASE]) { | ||
renderQueue.push(reactive.subs[RENDER_PHASE]); | ||
} | ||
if (reactive.subs[USER_EFFECT_PHASE]) { | ||
userEffectQueue.push(reactive.subs[USER_EFFECT_PHASE]); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -180,34 +189,36 @@ | ||
function subscribe(reactive, callback, phase, context = coreInfo.context) { | ||
if (!context) { | ||
throw new Error('subscriptions can only be created inside a context'); | ||
if (!context) { | ||
throw new Error('subscriptions can only be created inside a context'); | ||
} | ||
const subs = reactive.subs[phase] || (reactive.subs[phase] = new Set()); // subscribe | ||
subs.add(callback); // if non local dependencies, setup unsubscribe on disconnect and resubscribe on connect | ||
if (context !== reactive.context) { | ||
const unsub = () => { | ||
subs.delete(callback); | ||
}; | ||
const resub = () => { | ||
subs.add(callback); | ||
}; // unsubscribe when context gets disconnected | ||
if (!context.onDisconnect) { | ||
context.onDisconnect = [unsub]; | ||
} else { | ||
context.onDisconnect.push(unsub); | ||
} // subscribe when context is connected | ||
if (!context.onConnect) { | ||
context.onConnect = [resub]; | ||
} else { | ||
context.onConnect.push(resub); | ||
} | ||
const subs = reactive.subs[phase] || (reactive.subs[phase] = new Set()); | ||
// subscribe | ||
subs.add(callback); | ||
// if non local dependencies, setup unsubscribe on disconnect and resubscribe on connect | ||
if (context !== reactive.context) { | ||
const unsub = () => { | ||
subs.delete(callback); | ||
}; | ||
const resub = () => { | ||
subs.add(callback); | ||
}; | ||
// unsubscribe when context gets disconnected | ||
if (!context.onDisconnect) { | ||
context.onDisconnect = [unsub]; | ||
} | ||
else { | ||
context.onDisconnect.push(unsub); | ||
} | ||
// subscribe when context is connected | ||
if (!context.onConnect) { | ||
context.onConnect = [resub]; | ||
} | ||
else { | ||
context.onConnect.push(resub); | ||
} | ||
} | ||
} | ||
} | ||
function unsubscribe(reactive, callback, phase) { | ||
reactive.subs[phase].delete(callback); | ||
reactive.subs[phase].delete(callback); | ||
} | ||
@@ -224,49 +235,53 @@ | ||
*/ | ||
function effect(callback, phase = USER_EFFECT_PHASE) { | ||
const info = { | ||
deps: new Set() | ||
}; | ||
const effectContext = coreInfo.context; | ||
if (!effectContext) { | ||
console.error('invalid effect:', callback); | ||
throw new Error('effects can be only created inside a context'); | ||
const info = { | ||
deps: new Set() | ||
}; | ||
const effectContext = coreInfo.context; | ||
if (!effectContext) { | ||
console.error('invalid effect:', callback); | ||
throw new Error('effects can be only created inside a context'); | ||
} | ||
function runEffect() { | ||
const [newDeps] = detect(callback); // unsubscribe from reactives that are not in the newDeps | ||
info.deps.forEach(dep => { | ||
if (!newDeps.has(dep)) { | ||
unsubscribe(dep, runEffect, phase); | ||
} | ||
}); // subscribe to deps that are not already subscribed | ||
newDeps.forEach(newDep => { | ||
if (!info.deps.has(newDep)) { | ||
subscribe(newDep, runEffect, phase, effectContext); | ||
} | ||
}); // update the dependencies | ||
info.deps = newDeps; | ||
} | ||
function createEffect() { | ||
info.deps = detect(callback)[0]; | ||
info.deps.forEach(dep => subscribe(dep, runEffect, phase, effectContext)); | ||
} // render effects can be called immediately and since they don't have branching logic | ||
// no need to update the dependencies | ||
if (phase === RENDER_PHASE) { | ||
info.deps = detect(callback)[0]; | ||
info.deps.forEach(dep => subscribe(dep, callback, phase, effectContext)); | ||
} // effect or connection phase | ||
else { | ||
// run the effect after the context is connected | ||
if (effectContext.onConnect) { | ||
effectContext.onConnect.push(createEffect); | ||
} else { | ||
effectContext.onConnect = [createEffect]; | ||
} | ||
function runEffect() { | ||
const [newDeps] = detect(callback); | ||
// unsubscribe from reactives that are not in the newDeps | ||
info.deps.forEach((dep) => { | ||
if (!newDeps.has(dep)) { | ||
unsubscribe(dep, runEffect, phase); | ||
} | ||
}); | ||
// subscribe to deps that are not already subscribed | ||
newDeps.forEach((newDep) => { | ||
if (!info.deps.has(newDep)) { | ||
subscribe(newDep, runEffect, phase, effectContext); | ||
} | ||
}); | ||
// update the dependencies | ||
info.deps = newDeps; | ||
} | ||
function createEffect() { | ||
info.deps = detect(callback)[0]; | ||
info.deps.forEach((dep) => subscribe(dep, runEffect, phase, effectContext)); | ||
} | ||
// render effects can be called immediately and since they don't have branching logic | ||
// no need to update the dependencies | ||
if (phase === RENDER_PHASE) { | ||
info.deps = detect(callback)[0]; | ||
info.deps.forEach((dep) => subscribe(dep, callback, phase, effectContext)); | ||
} | ||
// effect or connection phase | ||
else { | ||
// run the effect after the context is connected | ||
if (effectContext.onConnect) { | ||
effectContext.onConnect.push(createEffect); | ||
} | ||
else { | ||
effectContext.onConnect = [createEffect]; | ||
} | ||
} | ||
return info; | ||
} | ||
return info; | ||
} | ||
@@ -279,139 +294,158 @@ | ||
*/ | ||
function memo(fn) { | ||
function update() { | ||
[state.deps, state.value] = detect(fn); | ||
cacheId = computeCacheId(state.deps); | ||
function update() { | ||
[state.deps, state.value] = detect(fn); | ||
cacheId = computeCacheId(state.deps); | ||
} // create computed state | ||
// @ts-expect-error | ||
const state = function () { | ||
const id = computeCacheId(state.deps); | ||
const isValueCorrect = cacheId === id; // if the value is not correct, update the value, cacheId and deps | ||
if (!isValueCorrect) { | ||
update(); | ||
} // if the detector is enabled, push the computed's deps | ||
else if (coreInfo.detectorEnabled) { | ||
state.deps.forEach(dep => { | ||
coreInfo.detected.add(dep); | ||
}); | ||
} | ||
// create computed state | ||
// @ts-expect-error | ||
const state = function () { | ||
const id = computeCacheId(state.deps); | ||
const isValueCorrect = cacheId === id; | ||
// if the value is not correct, update the value, cacheId and deps | ||
if (!isValueCorrect) { | ||
update(); | ||
} | ||
// if the detector is enabled, push the computed's deps | ||
else if (coreInfo.detectorEnabled) { | ||
state.deps.forEach((dep) => { | ||
coreInfo.detected.add(dep); | ||
}); | ||
} | ||
return state.value; | ||
}; | ||
[state.deps, state.value] = detect(fn); | ||
let cacheId = computeCacheId(state.deps); | ||
return state; | ||
return state.value; | ||
} // run the fn and get return value and dependecies | ||
; | ||
[state.deps, state.value] = detect(fn); | ||
let cacheId = computeCacheId(state.deps); | ||
return state; | ||
} | ||
function computeCacheId(deps) { | ||
let cacheId = 0; | ||
deps.forEach((dep) => { | ||
cacheId += dep.updateCount; | ||
}); | ||
return cacheId; | ||
let cacheId = 0; | ||
deps.forEach(dep => { | ||
cacheId += dep.updateCount; | ||
}); | ||
return cacheId; | ||
} | ||
function mutativeSwap(arr, i, j) { | ||
const temp = arr[i]; | ||
arr[i] = arr[j]; | ||
arr[j] = temp; | ||
const temp = arr[i]; | ||
arr[i] = arr[j]; | ||
arr[j] = temp; | ||
} | ||
function targetKey(obj, path) { | ||
if (path.length === 1) | ||
return [obj, path[0]]; | ||
const lastIndex = path.length - 1; | ||
let target = obj; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target = target[path[i]]; | ||
} | ||
return [target, path[lastIndex]]; | ||
if (path.length === 1) return [obj, path[0]]; | ||
const lastIndex = path.length - 1; | ||
let target = obj; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target = target[path[i]]; | ||
} | ||
return [target, path[lastIndex]]; | ||
} | ||
function valueAt(obj, path, start = 0, end = path.length - 1) { | ||
let target = obj; | ||
for (let i = start; i <= end; i++) { | ||
target = target[path[i]]; | ||
} | ||
return target; | ||
let target = obj; | ||
for (let i = start; i <= end; i++) { | ||
target = target[path[i]]; | ||
} | ||
return target; | ||
} | ||
function immutativeRemove(arr, index, count) { | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// if arr is already cloned in this batch | ||
if (batching.cloned.has(arr)) { | ||
// just mutate the cloned array | ||
arr.splice(index, count); | ||
return arr; // don't do anything else | ||
} | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// if arr is already cloned in this batch | ||
if (batching.cloned.has(arr)) { | ||
// just mutate the cloned array | ||
arr.splice(index, count); | ||
return arr; // don't do anything else | ||
} | ||
// clone the array if it's not already cloned or batching is disabled | ||
const arrClone = [...arr.slice(0, index), ...arr.slice(index + count)]; | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
return arrClone; | ||
} // clone the array if it's not already cloned or batching is disabled | ||
const arrClone = [...arr.slice(0, index), ...arr.slice(index + count)]; | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
return arrClone; | ||
} | ||
function immutativeSet(obj, path, newValue) { | ||
let root; | ||
// if batching is enabled, and the object is already cloned once in the batchf | ||
if (batching.enabled && batching.cloned.has(obj)) { | ||
// don't clone it | ||
root = obj; | ||
} | ||
else { | ||
// else clone it | ||
root = shallowClone(obj); | ||
// and mark it as cloned | ||
batching.cloned.add(root); | ||
} | ||
const lastIndex = path.length - 1; | ||
let target = root; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target[path[i]] = shallowClone(target[path[i]]); | ||
target = target[path[i]]; | ||
} | ||
target[path[lastIndex]] = newValue; | ||
return root; | ||
let root; // if batching is enabled, and the object is already cloned once in the batchf | ||
if (batching.enabled && batching.cloned.has(obj)) { | ||
// don't clone it | ||
root = obj; | ||
} else { | ||
// else clone it | ||
root = shallowClone(obj); // and mark it as cloned | ||
batching.cloned.add(root); | ||
} | ||
const lastIndex = path.length - 1; | ||
let target = root; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target[path[i]] = shallowClone(target[path[i]]); | ||
target = target[path[i]]; | ||
} | ||
target[path[lastIndex]] = newValue; | ||
return root; | ||
} | ||
function immutativeInsert(arr, index, values) { | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// if this array has already been cloned once in this batch | ||
if (batching.cloned.has(arr)) { | ||
// no need to clone the array, just mutate the array and insert the items | ||
arr.splice(index, 0, ...values); | ||
return; // don't do anything else | ||
} | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// if this array has already been cloned once in this batch | ||
if (batching.cloned.has(arr)) { | ||
// no need to clone the array, just mutate the array and insert the items | ||
arr.splice(index, 0, ...values); | ||
return; // don't do anything else | ||
} | ||
// clone the array if batching is disabled or this array has not been cloned yet in this batch | ||
const arrClone = [...arr.slice(0, index), ...values, ...arr.slice(index)]; | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
return arrClone; | ||
} // clone the array if batching is disabled or this array has not been cloned yet in this batch | ||
const arrClone = [...arr.slice(0, index), ...values, ...arr.slice(index)]; | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
return arrClone; | ||
} | ||
function immutativeSwap(arr, i, j) { | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// and if this array has already been cloned once in this batch | ||
if (batching.cloned.has(arr)) { | ||
// then just mutate the array for swap | ||
mutativeSwap(arr, i, j); | ||
return arr; // don't do anything else | ||
} | ||
// if batching is enabled | ||
if (batching.enabled) { | ||
// and if this array has already been cloned once in this batch | ||
if (batching.cloned.has(arr)) { | ||
// then just mutate the array for swap | ||
mutativeSwap(arr, i, j); | ||
return arr; // don't do anything else | ||
} | ||
// clone the array if batching is disabled or this array has not been cloned yet in this batch | ||
const arrClone = [...arr]; | ||
// mark this array as cloned in this batch | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
mutativeSwap(arrClone, i, j); | ||
return arrClone; | ||
} | ||
// create a shallow clone of give object or array | ||
} // clone the array if batching is disabled or this array has not been cloned yet in this batch | ||
const arrClone = [...arr]; // mark this array as cloned in this batch | ||
if (batching.enabled) { | ||
batching.cloned.add(arrClone); | ||
} | ||
mutativeSwap(arrClone, i, j); | ||
return arrClone; | ||
} // create a shallow clone of give object or array | ||
function shallowClone(obj) { | ||
// @ts-ignore | ||
return Array.isArray(obj) ? [...obj] : { ...obj }; | ||
// @ts-ignore | ||
return Array.isArray(obj) ? [...obj] : { ...obj | ||
}; | ||
} | ||
@@ -422,281 +456,298 @@ | ||
/** set new value */ | ||
function set(newValue) { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
if (path) { | ||
if (state.mutable) { | ||
const lastIndex = path.length - 1; | ||
let target = state.value; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target = target[path[i]]; | ||
} | ||
if (newValue !== target[path[lastIndex]]) { | ||
target[path[lastIndex]] = newValue; | ||
} | ||
} | ||
else { | ||
state.value = immutativeSet(state.value, path, newValue); | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; | ||
if (path) { | ||
if (state.mutable) { | ||
const lastIndex = path.length - 1; | ||
let target = state.value; | ||
for (let i = 0; i < lastIndex; i++) { | ||
target = target[path[i]]; | ||
} | ||
if (newValue !== target[path[lastIndex]]) { | ||
target[path[lastIndex]] = newValue; | ||
} | ||
} else { | ||
state.value = immutativeSet(state.value, path, newValue); | ||
} | ||
else { | ||
if (newValue !== state.value) { | ||
state.value = newValue; | ||
} | ||
} else { | ||
if (newValue !== state.value) { | ||
state.value = newValue; | ||
} | ||
state.subs[LIST_PHASE]?.forEach((cb) => cb('set', path, newValue)); | ||
invalidate(state); | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
state.subs[LIST_PHASE]?.forEach(cb => cb('set', path, newValue)); | ||
invalidate(state); | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
/** perform an operation on reactive */ | ||
function perform(operation) { | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; | ||
if (path) { | ||
const oldValue = valueAt(state.value, path); | ||
const newValue = operation(oldValue); | ||
if (oldValue === newValue) return state; // @ts-expect-error | ||
return state.set(newValue); | ||
} else { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
if (path) { | ||
const oldValue = valueAt(state.value, path); | ||
const newValue = operation(oldValue); | ||
if (oldValue === newValue) | ||
return state; | ||
// @ts-expect-error | ||
return state.set(newValue); | ||
} | ||
else { | ||
// @ts-expect-error | ||
const newValue = operation(state.value); | ||
if (state.value === newValue) | ||
return state; | ||
// @ts-expect-error | ||
return state.set(newValue); | ||
} | ||
const newValue = operation(state.value); | ||
if (state.value === newValue) return state; // @ts-expect-error | ||
return state.set(newValue); | ||
} | ||
} | ||
/** insert a list of items on reactive at given index */ | ||
function insertList(_index, values) { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
// insert at path | ||
if (path) { | ||
const arr = valueAt(state.value, path); | ||
const index = _index < 0 ? arr.length + _index + 1 : _index; | ||
if (state.mutable) { | ||
arr.splice(index, 0, ...values); | ||
} | ||
else { | ||
state.value = immutativeSet(state, path, | ||
// @ts-ignore | ||
immutativeInsert(arr, index, values)); | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; // insert at path | ||
if (path) { | ||
const arr = valueAt(state.value, path); | ||
const index = _index < 0 ? arr.length + _index + 1 : _index; | ||
if (state.mutable) { | ||
arr.splice(index, 0, ...values); | ||
} else { | ||
state.value = immutativeSet(state, path, // @ts-ignore | ||
immutativeInsert(arr, index, values)); | ||
} | ||
// insert on root | ||
else { | ||
const index = _index < 0 ? state.value.length + _index + 1 : _index; | ||
if (state.mutable) { | ||
state.value.splice(index, 0, ...values); | ||
} | ||
else { | ||
state.value = immutativeInsert(state.value, index, values); | ||
} | ||
state.subs[LIST_PHASE]?.forEach((cb) => { | ||
cb('insert', index, values); | ||
}); | ||
} // insert on root | ||
else { | ||
const index = _index < 0 ? state.value.length + _index + 1 : _index; | ||
if (state.mutable) { | ||
state.value.splice(index, 0, ...values); | ||
} else { | ||
state.value = immutativeInsert(state.value, index, values); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
invalidate(state); | ||
return state; | ||
state.subs[LIST_PHASE]?.forEach(cb => { | ||
cb('insert', index, values); | ||
}); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
invalidate(state); | ||
return state; | ||
} | ||
/** insert a single item at given index */ | ||
function insert(index, value) { | ||
// @ts-expect-error | ||
$reactive = ($reactive || this); | ||
return insertList(index, [value]); | ||
// @ts-expect-error | ||
$reactive = $reactive || this; | ||
return insertList(index, [value]); | ||
} | ||
/** push single item to reactive */ | ||
function push(value) { | ||
// @ts-expect-error | ||
$reactive = ($reactive || this); | ||
return insertList(-1, [value]); | ||
// @ts-expect-error | ||
$reactive = $reactive || this; | ||
return insertList(-1, [value]); | ||
} | ||
/** push list of items to reactive */ | ||
function pushList(values) { | ||
// @ts-expect-error | ||
$reactive = ($reactive || this); | ||
return insertList(-1, values); | ||
// @ts-expect-error | ||
$reactive = $reactive || this; | ||
return insertList(-1, values); | ||
} | ||
/** remove item at given index from array */ | ||
function remove(_index, count = 1) { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
// remove at path | ||
if (path) { | ||
const arr = valueAt(state.value, path); | ||
const index = _index < 0 ? arr.length + _index : _index; | ||
if (state.mutable) { | ||
arr.splice(index, count); | ||
} | ||
else { | ||
state.value = immutativeSet(state.value, path, immutativeRemove(arr, index, count)); | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; // remove at path | ||
if (path) { | ||
const arr = valueAt(state.value, path); | ||
const index = _index < 0 ? arr.length + _index : _index; | ||
if (state.mutable) { | ||
arr.splice(index, count); | ||
} else { | ||
state.value = immutativeSet(state.value, path, immutativeRemove(arr, index, count)); | ||
} | ||
// remove on root | ||
else { | ||
const index = _index < 0 ? state.value.length + _index : _index; | ||
if (state.mutable) { | ||
state.value.splice(index, count); | ||
} | ||
else { | ||
state.value = immutativeRemove(state.value, index, count); | ||
} | ||
state.subs[LIST_PHASE]?.forEach((cb) => cb('remove', index, count)); | ||
} // remove on root | ||
else { | ||
const index = _index < 0 ? state.value.length + _index : _index; | ||
if (state.mutable) { | ||
state.value.splice(index, count); | ||
} else { | ||
state.value = immutativeRemove(state.value, index, count); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
invalidate(state); | ||
return state; | ||
state.subs[LIST_PHASE]?.forEach(cb => cb('remove', index, count)); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
invalidate(state); | ||
return state; | ||
} | ||
/** remove items from end of array */ | ||
function pop(count = 1) { | ||
// @ts-expect-error | ||
$reactive = ($reactive || this); | ||
return remove(-1 * count, count); | ||
// @ts-expect-error | ||
$reactive = $reactive || this; | ||
return remove(-1 * count, count); | ||
} | ||
/** clear array */ | ||
function clear() { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
// deep clear | ||
if (path) { | ||
if (state.mutable) { | ||
const [target, key] = targetKey(state.value, path); | ||
if (target[key].length !== 0) { | ||
target[key] = []; | ||
invalidate(state); | ||
} | ||
} | ||
else { | ||
if (state.value.length !== 0) { | ||
state.value = immutativeSet(state.value, path, []); | ||
invalidate(state); | ||
} | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; // deep clear | ||
if (path) { | ||
if (state.mutable) { | ||
const [target, key] = targetKey(state.value, path); | ||
if (target[key].length !== 0) { | ||
target[key] = []; | ||
invalidate(state); | ||
} | ||
} else { | ||
if (state.value.length !== 0) { | ||
state.value = immutativeSet(state.value, path, []); | ||
invalidate(state); | ||
} | ||
} | ||
// clear at root | ||
else { | ||
if (state.value.length !== 0) { | ||
state.value = []; | ||
state.subs[LIST_PHASE]?.forEach((cb) => cb('clear')); | ||
invalidate(state); | ||
} | ||
} // clear at root | ||
else { | ||
if (state.value.length !== 0) { | ||
state.value = []; | ||
state.subs[LIST_PHASE]?.forEach(cb => cb('clear')); | ||
invalidate(state); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
/** swap values at given indexes */ | ||
function swap(i, j) { | ||
// @ts-expect-error | ||
const state = ($reactive || this); | ||
const path = $path; | ||
if (path) { | ||
// deep swap | ||
const arr = valueAt(state.value, path); | ||
if (state.mutable) { | ||
// mutative deep swap | ||
mutativeSwap(arr, i, j); | ||
} | ||
else { | ||
// immutative deep swap | ||
const arr = valueAt(state.value, path); | ||
state.value = immutativeSet($reactive, path, immutativeSwap(arr, i, j)); | ||
} | ||
// @ts-expect-error | ||
const state = $reactive || this; | ||
const path = $path; | ||
if (path) { | ||
// deep swap | ||
const arr = valueAt(state.value, path); | ||
if (state.mutable) { | ||
// mutative deep swap | ||
mutativeSwap(arr, i, j); | ||
} else { | ||
// immutative deep swap | ||
const arr = valueAt(state.value, path); | ||
state.value = immutativeSet($reactive, path, immutativeSwap(arr, i, j)); | ||
} | ||
else { | ||
// shallow swap | ||
if (state.mutable) { | ||
// mutative shallow swap | ||
mutativeSwap(state.value, i, j); | ||
} | ||
else { | ||
// immutative shallow swap | ||
state.value = immutativeSwap(state.value, i, j); | ||
} | ||
state.subs[LIST_PHASE]?.forEach((cb) => cb('swap', i, j)); | ||
} else { | ||
// shallow swap | ||
if (state.mutable) { | ||
// mutative shallow swap | ||
mutativeSwap(state.value, i, j); | ||
} else { | ||
// immutative shallow swap | ||
state.value = immutativeSwap(state.value, i, j); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
state.subs[LIST_PHASE]?.forEach(cb => cb('swap', i, j)); | ||
} | ||
$path = null; | ||
$reactive = null; | ||
return state; | ||
} | ||
const reactiveMethods = { | ||
set, | ||
insert, | ||
insertList, | ||
remove, | ||
push, | ||
pushList, | ||
swap, | ||
clear, | ||
perform, | ||
pop | ||
set, | ||
insert, | ||
insertList, | ||
remove, | ||
push, | ||
pushList, | ||
swap, | ||
clear, | ||
perform, | ||
pop | ||
}; | ||
/** target given path in reactive value */ | ||
function $(...path) { | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias | ||
$reactive = this; | ||
// @ts-expect-error | ||
$path = path; | ||
// @ts-expect-error | ||
return reactiveMethods; | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias | ||
$reactive = this; // @ts-expect-error | ||
$path = path; // @ts-expect-error | ||
return reactiveMethods; | ||
} | ||
function reactive(value) { | ||
// @ts-expect-error | ||
const state = function $Reactive() { | ||
// detect | ||
if (coreInfo.detectorEnabled) { | ||
coreInfo.detected.add(state); | ||
} | ||
return state.value; | ||
}; | ||
state.value = value; | ||
state.subs = new Array(4); | ||
state.context = coreInfo.context; | ||
state.updateCount = 0; | ||
state.mutable = true; | ||
state.$ = $; // @ts-expect-error | ||
state.set = set; // @ts-expect-error | ||
state.perform = perform; | ||
if (Array.isArray(value)) { | ||
// @ts-expect-error | ||
const state = function $Reactive() { | ||
// detect | ||
if (coreInfo.detectorEnabled) { | ||
coreInfo.detected.add(state); | ||
} | ||
return state.value; | ||
}; | ||
state.value = value; | ||
state.subs = new Array(4); | ||
state.context = coreInfo.context; | ||
state.updateCount = 0; | ||
state.mutable = true; | ||
state.$ = $; | ||
// @ts-expect-error | ||
state.set = set; | ||
// @ts-expect-error | ||
state.perform = perform; | ||
if (Array.isArray(value)) { | ||
// @ts-expect-error | ||
state.insertList = insertList; | ||
// @ts-expect-error | ||
state.push = push; | ||
// @ts-expect-error | ||
state.pushList = pushList; | ||
// @ts-expect-error | ||
state.insert = insert; | ||
// @ts-expect-error | ||
state.remove = remove; | ||
// @ts-expect-error | ||
state.clear = clear; | ||
// @ts-expect-error | ||
state.swap = swap; | ||
// @ts-expect-error | ||
state.pop = pop; | ||
} | ||
return state; | ||
state.insertList = insertList; // @ts-expect-error | ||
state.push = push; // @ts-expect-error | ||
state.pushList = pushList; // @ts-expect-error | ||
state.insert = insert; // @ts-expect-error | ||
state.remove = remove; // @ts-expect-error | ||
state.clear = clear; // @ts-expect-error | ||
state.swap = swap; // @ts-expect-error | ||
state.pop = pop; | ||
} | ||
return state; | ||
} | ||
const coreInfo = { | ||
context: null, | ||
detectorEnabled: false, | ||
detected: new Set() | ||
context: null, | ||
detectorEnabled: false, | ||
detected: new Set() | ||
}; | ||
export { CONNECTION_PHASE, ErrorBoundary, LIST_PHASE, List, RENDER_PHASE, USER_EFFECT_PHASE, batch, batching, coreInfo, detect, effect, invalidate, memo, onConnect, onDisconnect, onError, reactive, subscribe, targetKey, unsubscribe }; | ||
export { CONNECTION_PHASE, ErrorBoundary, LIST_PHASE, List, RENDER_PHASE, USER_EFFECT_PHASE, batch, batching, coreInfo, detect, effect, invalidate, memo, onConnect, onDisconnect, reactive, subscribe, targetKey, unsubscribe }; |
@@ -1,1 +0,1 @@ | ||
"use strict";function e(e){const n=k.detected,t=k.detectorEnabled;k.detectorEnabled=!0,k.detected=new Set;const o=e(),s=k.detected;return t&&s.forEach((e=>{n.add(e)})),k.detectorEnabled=t,k.detected=n,[s,o]}Object.defineProperty(exports,"__esModule",{value:!0});const n=new Set,t={enabled:!1,cloned:new Set},o=[],s=[],c=[];function r(e,n){for(let t=0;t<n;t++){const n=e[t];for(const e of n)e()}e.splice(0,n)}function u(){n.clear();const e=o.length,t=s.length,l=c.length;0!==e&&r(o,e),0!==t&&r(s,t),0!==l&&r(c,l),0!==n.size&&u()}function l(e){t.enabled?n.has(e)||(n.add(e),e.subs[1]&&o.push(e.subs[1]),e.subs[2]&&s.push(e.subs[2]),e.subs[3]&&c.push(e.subs[3])):(e.subs[1]?.forEach((e=>e())),e.subs[2]?.forEach((e=>e())),e.subs[3]?.forEach((e=>e())),e.updateCount++)}function a(e,n,t,o=k.context){const s=e.subs[t]||(e.subs[t]=new Set);if(s.add(n),o!==e.context){const e=()=>{s.delete(n)},t=()=>{s.add(n)};o.onDisconnect?o.onDisconnect.push(e):o.onDisconnect=[e],o.onConnect?o.onConnect.push(t):o.onConnect=[t]}}function i(e,n,t){e.subs[t].delete(n)}function d(e){let n=0;return e.forEach((e=>{n+=e.updateCount})),n}function f(e,n,t){const o=e[n];e[n]=e[t],e[t]=o}function p(e,n){if(1===n.length)return[e,n[0]];const t=n.length-1;let o=e;for(let e=0;e<t;e++)o=o[n[e]];return[o,n[t]]}function h(e,n,t=0,o=n.length-1){let s=e;for(let e=t;e<=o;e++)s=s[n[e]];return s}function b(e,n,o){if(t.enabled&&t.cloned.has(e))return e.splice(n,o),e;const s=[...e.slice(0,n),...e.slice(n+o)];return t.enabled&&t.cloned.add(s),s}function v(e,n,o){let s;t.enabled&&t.cloned.has(e)?s=e:(s=g(e),t.cloned.add(s));const c=n.length-1;let r=s;for(let e=0;e<c;e++)r[n[e]]=g(r[n[e]]),r=r[n[e]];return r[n[c]]=o,s}function E(e,n,o){if(t.enabled&&t.cloned.has(e))return void e.splice(n,0,...o);const s=[...e.slice(0,n),...o,...e.slice(n)];return t.enabled&&t.cloned.add(s),s}function x(e,n,o){if(t.enabled&&t.cloned.has(e))return f(e,n,o),e;const s=[...e];return t.enabled&&t.cloned.add(s),f(s,n,o),s}function g(e){return Array.isArray(e)?[...e]:{...e}}let m,C;function w(e){const n=C||this,t=m;if(t)if(n.mutable){const o=t.length-1;let s=n.value;for(let e=0;e<o;e++)s=s[t[e]];e!==s[t[o]]&&(s[t[o]]=e)}else n.value=v(n.value,t,e);else e!==n.value&&(n.value=e);return n.subs[0]?.forEach((n=>n("set",t,e))),l(n),m=null,C=null,n}function S(e){const n=C||this,t=m;if(t){const o=h(n.value,t),s=e(o);return o===s?n:n.set(s)}{const t=e(n.value);return n.value===t?n:n.set(t)}}function y(e,n){const t=C||this,o=m;if(o){const s=h(t.value,o),c=e<0?s.length+e+1:e;t.mutable?s.splice(c,0,...n):t.value=v(t,o,E(s,c,n))}else{const o=e<0?t.value.length+e+1:e;t.mutable?t.value.splice(o,0,...n):t.value=E(t.value,o,n),t.subs[0]?.forEach((e=>{e("insert",o,n)}))}return m=null,C=null,l(t),t}function A(e,n){return C=C||this,y(e,[n])}function D(e){return C=C||this,y(-1,[e])}function _(e){return C=C||this,y(-1,e)}function L(e,n=1){const t=C||this,o=m;if(o){const s=h(t.value,o),c=e<0?s.length+e:e;t.mutable?s.splice(c,n):t.value=v(t.value,o,b(s,c,n))}else{const o=e<0?t.value.length+e:e;t.mutable?t.value.splice(o,n):t.value=b(t.value,o,n),t.subs[0]?.forEach((e=>e("remove",o,n)))}return m=null,C=null,l(t),t}function H(e=1){return C=C||this,L(-1*e,e)}function P(){const e=C||this,n=m;if(n)if(e.mutable){const[t,o]=p(e.value,n);0!==t[o].length&&(t[o]=[],l(e))}else 0!==e.value.length&&(e.value=v(e.value,n,[]),l(e));else 0!==e.value.length&&(e.value=[],e.subs[0]?.forEach((e=>e("clear"))),l(e));return m=null,C=null,e}function I(e,n){const t=C||this,o=m;if(o){const s=h(t.value,o);if(t.mutable)f(s,e,n);else{const s=h(t.value,o);t.value=v(C,o,x(s,e,n))}}else t.mutable?f(t.value,e,n):t.value=x(t.value,e,n),t.subs[0]?.forEach((t=>t("swap",e,n)));return m=null,C=null,t}const N={set:w,insert:A,insertList:y,remove:L,push:D,pushList:_,swap:I,clear:P,perform:S,pop:H};function $(...e){return C=this,m=e,N}const k={context:null,detectorEnabled:!1,detected:new Set};exports.CONNECTION_PHASE=1,exports.ErrorBoundary=function(e){try{return e.children}catch(n){return e.fallback||"Error"}},exports.LIST_PHASE=0,exports.List=function(e){return{$$list:e}},exports.RENDER_PHASE=2,exports.USER_EFFECT_PHASE=3,exports.batch=function(e){t.enabled=!0,e(),t.enabled=!1,t.cloned.clear(),u()},exports.batching=t,exports.coreInfo=k,exports.detect=e,exports.effect=function(n,t=3){const o={deps:new Set},s=k.context;function c(){const[r]=e(n);o.deps.forEach((e=>{r.has(e)||i(e,c,t)})),r.forEach((e=>{o.deps.has(e)||a(e,c,t,s)})),o.deps=r}function r(){o.deps=e(n)[0],o.deps.forEach((e=>a(e,c,t,s)))}return 2===t?(o.deps=e(n)[0],o.deps.forEach((e=>a(e,n,t,s)))):s.onConnect?s.onConnect.push(r):s.onConnect=[r],o},exports.invalidate=l,exports.memo=function(n){const t=function(){const s=d(t.deps);return o===s?k.detectorEnabled&&t.deps.forEach((e=>{k.detected.add(e)})):([t.deps,t.value]=e(n),o=d(t.deps)),t.value};[t.deps,t.value]=e(n);let o=d(t.deps);return t},exports.onConnect=function(e){k.context.onConnect?k.context.onConnect.push(e):k.context.onConnect=[e]},exports.onDisconnect=function(e){k.context.onDisconnect?k.context.onDisconnect.push(e):k.context.onDisconnect=[e]},exports.onError=function(e){!function(e){if(!k.context)throw new Error(`Invalid Hook Usage: Can not use ${e}() hook outside of a component`)}("onError"),k.context.onError?k.context.onError.push(e):k.context.onError=[e]},exports.reactive=function(e){const n=function(){return k.detectorEnabled&&k.detected.add(n),n.value};return n.value=e,n.subs=new Array(4),n.context=k.context,n.updateCount=0,n.mutable=!0,n.$=$,n.set=w,n.perform=S,Array.isArray(e)&&(n.insertList=y,n.push=D,n.pushList=_,n.insert=A,n.remove=L,n.clear=P,n.swap=I,n.pop=H),n},exports.subscribe=a,exports.targetKey=p,exports.unsubscribe=i; | ||
"use strict";function e(e){const t=R.detected,n=R.detectorEnabled;R.detectorEnabled=!0,R.detected=new Set;const o=e(),s=R.detected;return n&&s.forEach((e=>{t.add(e)})),R.detectorEnabled=n,R.detected=t,[s,o]}Object.defineProperty(exports,"__esModule",{value:!0});const t=new Set,n={enabled:!1,cloned:new Set},o=[],s=[],c=[];function u(e,t){for(let n=0;n<t;n++){const t=e[n];for(const e of t)e()}e.splice(0,t)}function l(){t.clear();const e=o.length,n=s.length,r=c.length;0!==e&&u(o,e),0!==n&&u(s,n),0!==r&&u(c,r),0!==t.size&&l()}function r(e){n.enabled?t.has(e)||(t.add(e),e.subs[1]&&o.push(e.subs[1]),e.subs[2]&&s.push(e.subs[2]),e.subs[3]&&c.push(e.subs[3])):(e.subs[1]?.forEach((e=>e())),e.subs[2]?.forEach((e=>e())),e.subs[3]?.forEach((e=>e())),e.updateCount++)}function a(e,t,n,o=R.context){const s=e.subs[n]||(e.subs[n]=new Set);if(s.add(t),o!==e.context){const e=()=>{s.delete(t)},n=()=>{s.add(t)};o.onDisconnect?o.onDisconnect.push(e):o.onDisconnect=[e],o.onConnect?o.onConnect.push(n):o.onConnect=[n]}}function i(e,t,n){e.subs[n].delete(t)}function d(e){let t=0;return e.forEach((e=>{t+=e.updateCount})),t}function f(e,t,n){const o=e[t];e[t]=e[n],e[n]=o}function p(e,t){if(1===t.length)return[e,t[0]];const n=t.length-1;let o=e;for(let e=0;e<n;e++)o=o[t[e]];return[o,t[n]]}function h(e,t,n=0,o=t.length-1){let s=e;for(let e=n;e<=o;e++)s=s[t[e]];return s}function b(e,t,o){if(n.enabled&&n.cloned.has(e))return e.splice(t,o),e;const s=[...e.slice(0,t),...e.slice(t+o)];return n.enabled&&n.cloned.add(s),s}function v(e,t,o){let s;n.enabled&&n.cloned.has(e)?s=e:(s=g(e),n.cloned.add(s));const c=t.length-1;let u=s;for(let e=0;e<c;e++)u[t[e]]=g(u[t[e]]),u=u[t[e]];return u[t[c]]=o,s}function E(e,t,o){if(n.enabled&&n.cloned.has(e))return void e.splice(t,0,...o);const s=[...e.slice(0,t),...o,...e.slice(t)];return n.enabled&&n.cloned.add(s),s}function x(e,t,o){if(n.enabled&&n.cloned.has(e))return f(e,t,o),e;const s=[...e];return n.enabled&&n.cloned.add(s),f(s,t,o),s}function g(e){return Array.isArray(e)?[...e]:{...e}}let m,C;function S(e){const t=C||this,n=m;if(n)if(t.mutable){const o=n.length-1;let s=t.value;for(let e=0;e<o;e++)s=s[n[e]];e!==s[n[o]]&&(s[n[o]]=e)}else t.value=v(t.value,n,e);else e!==t.value&&(t.value=e);return t.subs[0]?.forEach((t=>t("set",n,e))),r(t),m=null,C=null,t}function w(e){const t=C||this,n=m;if(n){const o=h(t.value,n),s=e(o);return o===s?t:t.set(s)}{const n=e(t.value);return t.value===n?t:t.set(n)}}function y(e,t){const n=C||this,o=m;if(o){const s=h(n.value,o),c=e<0?s.length+e+1:e;n.mutable?s.splice(c,0,...t):n.value=v(n,o,E(s,c,t))}else{const o=e<0?n.value.length+e+1:e;n.mutable?n.value.splice(o,0,...t):n.value=E(n.value,o,t),n.subs[0]?.forEach((e=>{e("insert",o,t)}))}return m=null,C=null,r(n),n}function A(e,t){return C=C||this,y(e,[t])}function D(e){return C=C||this,y(-1,[e])}function _(e){return C=C||this,y(-1,e)}function L(e,t=1){const n=C||this,o=m;if(o){const s=h(n.value,o),c=e<0?s.length+e:e;n.mutable?s.splice(c,t):n.value=v(n.value,o,b(s,c,t))}else{const o=e<0?n.value.length+e:e;n.mutable?n.value.splice(o,t):n.value=b(n.value,o,t),n.subs[0]?.forEach((e=>e("remove",o,t)))}return m=null,C=null,r(n),n}function P(e=1){return C=C||this,L(-1*e,e)}function H(){const e=C||this,t=m;if(t)if(e.mutable){const[n,o]=p(e.value,t);0!==n[o].length&&(n[o]=[],r(e))}else 0!==e.value.length&&(e.value=v(e.value,t,[]),r(e));else 0!==e.value.length&&(e.value=[],e.subs[0]?.forEach((e=>e("clear"))),r(e));return m=null,C=null,e}function N(e,t){const n=C||this,o=m;if(o){const s=h(n.value,o);if(n.mutable)f(s,e,t);else{const s=h(n.value,o);n.value=v(C,o,x(s,e,t))}}else n.mutable?f(n.value,e,t):n.value=x(n.value,e,t),n.subs[0]?.forEach((n=>n("swap",e,t)));return m=null,C=null,n}const I={set:S,insert:A,insertList:y,remove:L,push:D,pushList:_,swap:N,clear:H,perform:w,pop:P};function O(...e){return C=this,m=e,I}const R={context:null,detectorEnabled:!1,detected:new Set};exports.CONNECTION_PHASE=1,exports.ErrorBoundary=function(e){try{return e.children}catch(t){return e.fallback||"Error"}},exports.LIST_PHASE=0,exports.List=function(e){return{$$list:e}},exports.RENDER_PHASE=2,exports.USER_EFFECT_PHASE=3,exports.batch=function(e){n.enabled=!0,e(),n.enabled=!1,n.cloned.clear(),l()},exports.batching=n,exports.coreInfo=R,exports.detect=e,exports.effect=function(t,n=3){const o={deps:new Set},s=R.context;function c(){const[u]=e(t);o.deps.forEach((e=>{u.has(e)||i(e,c,n)})),u.forEach((e=>{o.deps.has(e)||a(e,c,n,s)})),o.deps=u}function u(){o.deps=e(t)[0],o.deps.forEach((e=>a(e,c,n,s)))}return 2===n?(o.deps=e(t)[0],o.deps.forEach((e=>a(e,t,n,s)))):s.onConnect?s.onConnect.push(u):s.onConnect=[u],o},exports.invalidate=r,exports.memo=function(t){const n=function(){const s=d(n.deps);return o===s?R.detectorEnabled&&n.deps.forEach((e=>{R.detected.add(e)})):([n.deps,n.value]=e(t),o=d(n.deps)),n.value};[n.deps,n.value]=e(t);let o=d(n.deps);return n},exports.onConnect=function(e){R.context.onConnect?R.context.onConnect.push(e):R.context.onConnect=[e]},exports.onDisconnect=function(e){R.context.onDisconnect?R.context.onDisconnect.push(e):R.context.onDisconnect=[e]},exports.reactive=function(e){const t=function(){return R.detectorEnabled&&R.detected.add(t),t.value};return t.value=e,t.subs=new Array(4),t.context=R.context,t.updateCount=0,t.mutable=!0,t.$=O,t.set=S,t.perform=w,Array.isArray(e)&&(t.insertList=y,t.push=D,t.pushList=_,t.insert=A,t.remove=L,t.clear=H,t.swap=N,t.pop=P),t},exports.subscribe=a,exports.targetKey=p,exports.unsubscribe=i; |
@@ -1,1 +0,1 @@ | ||
function e(e){try{return e.children}catch(n){return e.fallback||"Error"}}function n(e){return{$$list:e}}function t(e){T.context.onConnect?T.context.onConnect.push(e):T.context.onConnect=[e]}function o(e){T.context.onDisconnect?T.context.onDisconnect.push(e):T.context.onDisconnect=[e]}function c(e){!function(e){if(!T.context)throw new Error(`Invalid Hook Usage: Can not use ${e}() hook outside of a component`)}("onError"),T.context.onError?T.context.onError.push(e):T.context.onError=[e]}function u(e){const n=T.detected,t=T.detectorEnabled;T.detectorEnabled=!0,T.detected=new Set;const o=e(),c=T.detected;return t&&c.forEach((e=>{n.add(e)})),T.detectorEnabled=t,T.detected=n,[c,o]}const s=new Set,l=0,r=1,a=2,i=3,d={enabled:!1,cloned:new Set},f=[],h=[],p=[];function b(e,n){for(let t=0;t<n;t++){const n=e[t];for(const e of n)e()}e.splice(0,n)}function v(){s.clear();const e=f.length,n=h.length,t=p.length;0!==e&&b(f,e),0!==n&&b(h,n),0!==t&&b(p,t),0!==s.size&&v()}function E(e){d.enabled=!0,e(),d.enabled=!1,d.cloned.clear(),v()}function x(e){d.enabled?s.has(e)||(s.add(e),e.subs[1]&&f.push(e.subs[1]),e.subs[2]&&h.push(e.subs[2]),e.subs[3]&&p.push(e.subs[3])):(e.subs[1]?.forEach((e=>e())),e.subs[2]?.forEach((e=>e())),e.subs[3]?.forEach((e=>e())),e.updateCount++)}function g(e,n,t,o=T.context){const c=e.subs[t]||(e.subs[t]=new Set);if(c.add(n),o!==e.context){const e=()=>{c.delete(n)},t=()=>{c.add(n)};o.onDisconnect?o.onDisconnect.push(e):o.onDisconnect=[e],o.onConnect?o.onConnect.push(t):o.onConnect=[t]}}function m(e,n,t){e.subs[t].delete(n)}function C(e,n=3){const t={deps:new Set},o=T.context;function c(){const[s]=u(e);t.deps.forEach((e=>{s.has(e)||m(e,c,n)})),s.forEach((e=>{t.deps.has(e)||g(e,c,n,o)})),t.deps=s}function s(){t.deps=u(e)[0],t.deps.forEach((e=>g(e,c,n,o)))}return 2===n?(t.deps=u(e)[0],t.deps.forEach((t=>g(t,e,n,o)))):o.onConnect?o.onConnect.push(s):o.onConnect=[s],t}function w(e){const n=function(){const o=y(n.deps);return t===o?T.detectorEnabled&&n.deps.forEach((e=>{T.detected.add(e)})):([n.deps,n.value]=u(e),t=y(n.deps)),n.value};[n.deps,n.value]=u(e);let t=y(n.deps);return n}function y(e){let n=0;return e.forEach((e=>{n+=e.updateCount})),n}function D(e,n,t){const o=e[n];e[n]=e[t],e[t]=o}function S(e,n){if(1===n.length)return[e,n[0]];const t=n.length-1;let o=e;for(let e=0;e<t;e++)o=o[n[e]];return[o,n[t]]}function A(e,n,t=0,o=n.length-1){let c=e;for(let e=t;e<=o;e++)c=c[n[e]];return c}function L(e,n,t){if(d.enabled&&d.cloned.has(e))return e.splice(n,t),e;const o=[...e.slice(0,n),...e.slice(n+t)];return d.enabled&&d.cloned.add(o),o}function $(e,n,t){let o;d.enabled&&d.cloned.has(e)?o=e:(o=H(e),d.cloned.add(o));const c=n.length-1;let u=o;for(let e=0;e<c;e++)u[n[e]]=H(u[n[e]]),u=u[n[e]];return u[n[c]]=t,o}function k(e,n,t){if(d.enabled&&d.cloned.has(e))return void e.splice(n,0,...t);const o=[...e.slice(0,n),...t,...e.slice(n)];return d.enabled&&d.cloned.add(o),o}function z(e,n,t){if(d.enabled&&d.cloned.has(e))return D(e,n,t),e;const o=[...e];return d.enabled&&d.cloned.add(o),D(o,n,t),o}function H(e){return Array.isArray(e)?[...e]:{...e}}let I,U;function j(e){const n=U||this,t=I;if(t)if(n.mutable){const o=t.length-1;let c=n.value;for(let e=0;e<o;e++)c=c[t[e]];e!==c[t[o]]&&(c[t[o]]=e)}else n.value=$(n.value,t,e);else e!==n.value&&(n.value=e);return n.subs[0]?.forEach((n=>n("set",t,e))),x(n),I=null,U=null,n}function q(e){const n=U||this,t=I;if(t){const o=A(n.value,t),c=e(o);return o===c?n:n.set(c)}{const t=e(n.value);return n.value===t?n:n.set(t)}}function B(e,n){const t=U||this,o=I;if(o){const c=A(t.value,o),u=e<0?c.length+e+1:e;t.mutable?c.splice(u,0,...n):t.value=$(t,o,k(c,u,n))}else{const o=e<0?t.value.length+e+1:e;t.mutable?t.value.splice(o,0,...n):t.value=k(t.value,o,n),t.subs[0]?.forEach((e=>{e("insert",o,n)}))}return I=null,U=null,x(t),t}function F(e,n){return U=U||this,B(e,[n])}function G(e){return U=U||this,B(-1,[e])}function J(e){return U=U||this,B(-1,e)}function K(e,n=1){const t=U||this,o=I;if(o){const c=A(t.value,o),u=e<0?c.length+e:e;t.mutable?c.splice(u,n):t.value=$(t.value,o,L(c,u,n))}else{const o=e<0?t.value.length+e:e;t.mutable?t.value.splice(o,n):t.value=L(t.value,o,n),t.subs[0]?.forEach((e=>e("remove",o,n)))}return I=null,U=null,x(t),t}function M(e=1){return U=U||this,K(-1*e,e)}function N(){const e=U||this,n=I;if(n)if(e.mutable){const[t,o]=S(e.value,n);0!==t[o].length&&(t[o]=[],x(e))}else 0!==e.value.length&&(e.value=$(e.value,n,[]),x(e));else 0!==e.value.length&&(e.value=[],e.subs[0]?.forEach((e=>e("clear"))),x(e));return I=null,U=null,e}function O(e,n){const t=U||this,o=I;if(o){const c=A(t.value,o);if(t.mutable)D(c,e,n);else{const c=A(t.value,o);t.value=$(U,o,z(c,e,n))}}else t.mutable?D(t.value,e,n):t.value=z(t.value,e,n),t.subs[0]?.forEach((t=>t("swap",e,n)));return I=null,U=null,t}const P={set:j,insert:F,insertList:B,remove:K,push:G,pushList:J,swap:O,clear:N,perform:q,pop:M};function Q(...e){return U=this,I=e,P}function R(e){const n=function(){return T.detectorEnabled&&T.detected.add(n),n.value};return n.value=e,n.subs=new Array(4),n.context=T.context,n.updateCount=0,n.mutable=!0,n.$=Q,n.set=j,n.perform=q,Array.isArray(e)&&(n.insertList=B,n.push=G,n.pushList=J,n.insert=F,n.remove=K,n.clear=N,n.swap=O,n.pop=M),n}const T={context:null,detectorEnabled:!1,detected:new Set};export{r as CONNECTION_PHASE,e as ErrorBoundary,l as LIST_PHASE,n as List,a as RENDER_PHASE,i as USER_EFFECT_PHASE,E as batch,d as batching,T as coreInfo,u as detect,C as effect,x as invalidate,w as memo,t as onConnect,o as onDisconnect,c as onError,R as reactive,g as subscribe,S as targetKey,m as unsubscribe}; | ||
function e(e){try{return e.children}catch(n){return e.fallback||"Error"}}function n(e){return{$$list:e}}function t(e){T.context.onConnect?T.context.onConnect.push(e):T.context.onConnect=[e]}function o(e){T.context.onDisconnect?T.context.onDisconnect.push(e):T.context.onDisconnect=[e]}function c(e){const n=T.detected,t=T.detectorEnabled;T.detectorEnabled=!0,T.detected=new Set;const o=e(),c=T.detected;return t&&c.forEach((e=>{n.add(e)})),T.detectorEnabled=t,T.detected=n,[c,o]}const u=new Set,s=0,l=1,r=2,a=3,i={enabled:!1,cloned:new Set},d=[],f=[],h=[];function p(e,n){for(let t=0;t<n;t++){const n=e[t];for(const e of n)e()}e.splice(0,n)}function b(){u.clear();const e=d.length,n=f.length,t=h.length;0!==e&&p(d,e),0!==n&&p(f,n),0!==t&&p(h,t),0!==u.size&&b()}function v(e){i.enabled=!0,e(),i.enabled=!1,i.cloned.clear(),b()}function E(e){i.enabled?u.has(e)||(u.add(e),e.subs[1]&&d.push(e.subs[1]),e.subs[2]&&f.push(e.subs[2]),e.subs[3]&&h.push(e.subs[3])):(e.subs[1]?.forEach((e=>e())),e.subs[2]?.forEach((e=>e())),e.subs[3]?.forEach((e=>e())),e.updateCount++)}function g(e,n,t,o=T.context){const c=e.subs[t]||(e.subs[t]=new Set);if(c.add(n),o!==e.context){const e=()=>{c.delete(n)},t=()=>{c.add(n)};o.onDisconnect?o.onDisconnect.push(e):o.onDisconnect=[e],o.onConnect?o.onConnect.push(t):o.onConnect=[t]}}function m(e,n,t){e.subs[t].delete(n)}function x(e,n=3){const t={deps:new Set},o=T.context;function u(){const[s]=c(e);t.deps.forEach((e=>{s.has(e)||m(e,u,n)})),s.forEach((e=>{t.deps.has(e)||g(e,u,n,o)})),t.deps=s}function s(){t.deps=c(e)[0],t.deps.forEach((e=>g(e,u,n,o)))}return 2===n?(t.deps=c(e)[0],t.deps.forEach((t=>g(t,e,n,o)))):o.onConnect?o.onConnect.push(s):o.onConnect=[s],t}function C(e){const n=function(){const o=w(n.deps);return t===o?T.detectorEnabled&&n.deps.forEach((e=>{T.detected.add(e)})):([n.deps,n.value]=c(e),t=w(n.deps)),n.value};[n.deps,n.value]=c(e);let t=w(n.deps);return n}function w(e){let n=0;return e.forEach((e=>{n+=e.updateCount})),n}function y(e,n,t){const o=e[n];e[n]=e[t],e[t]=o}function D(e,n){if(1===n.length)return[e,n[0]];const t=n.length-1;let o=e;for(let e=0;e<t;e++)o=o[n[e]];return[o,n[t]]}function S(e,n,t=0,o=n.length-1){let c=e;for(let e=t;e<=o;e++)c=c[n[e]];return c}function A(e,n,t){if(i.enabled&&i.cloned.has(e))return e.splice(n,t),e;const o=[...e.slice(0,n),...e.slice(n+t)];return i.enabled&&i.cloned.add(o),o}function L(e,n,t){let o;i.enabled&&i.cloned.has(e)?o=e:(o=z(e),i.cloned.add(o));const c=n.length-1;let u=o;for(let e=0;e<c;e++)u[n[e]]=z(u[n[e]]),u=u[n[e]];return u[n[c]]=t,o}function $(e,n,t){if(i.enabled&&i.cloned.has(e))return void e.splice(n,0,...t);const o=[...e.slice(0,n),...t,...e.slice(n)];return i.enabled&&i.cloned.add(o),o}function k(e,n,t){if(i.enabled&&i.cloned.has(e))return y(e,n,t),e;const o=[...e];return i.enabled&&i.cloned.add(o),y(o,n,t),o}function z(e){return Array.isArray(e)?[...e]:{...e}}let j,q;function B(e){const n=q||this,t=j;if(t)if(n.mutable){const o=t.length-1;let c=n.value;for(let e=0;e<o;e++)c=c[t[e]];e!==c[t[o]]&&(c[t[o]]=e)}else n.value=L(n.value,t,e);else e!==n.value&&(n.value=e);return n.subs[0]?.forEach((n=>n("set",t,e))),E(n),j=null,q=null,n}function F(e){const n=q||this,t=j;if(t){const o=S(n.value,t),c=e(o);return o===c?n:n.set(c)}{const t=e(n.value);return n.value===t?n:n.set(t)}}function G(e,n){const t=q||this,o=j;if(o){const c=S(t.value,o),u=e<0?c.length+e+1:e;t.mutable?c.splice(u,0,...n):t.value=L(t,o,$(c,u,n))}else{const o=e<0?t.value.length+e+1:e;t.mutable?t.value.splice(o,0,...n):t.value=$(t.value,o,n),t.subs[0]?.forEach((e=>{e("insert",o,n)}))}return j=null,q=null,E(t),t}function H(e,n){return q=q||this,G(e,[n])}function I(e){return q=q||this,G(-1,[e])}function J(e){return q=q||this,G(-1,e)}function K(e,n=1){const t=q||this,o=j;if(o){const c=S(t.value,o),u=e<0?c.length+e:e;t.mutable?c.splice(u,n):t.value=L(t.value,o,A(c,u,n))}else{const o=e<0?t.value.length+e:e;t.mutable?t.value.splice(o,n):t.value=A(t.value,o,n),t.subs[0]?.forEach((e=>e("remove",o,n)))}return j=null,q=null,E(t),t}function M(e=1){return q=q||this,K(-1*e,e)}function N(){const e=q||this,n=j;if(n)if(e.mutable){const[t,o]=D(e.value,n);0!==t[o].length&&(t[o]=[],E(e))}else 0!==e.value.length&&(e.value=L(e.value,n,[]),E(e));else 0!==e.value.length&&(e.value=[],e.subs[0]?.forEach((e=>e("clear"))),E(e));return j=null,q=null,e}function O(e,n){const t=q||this,o=j;if(o){const c=S(t.value,o);if(t.mutable)y(c,e,n);else{const c=S(t.value,o);t.value=L(q,o,k(c,e,n))}}else t.mutable?y(t.value,e,n):t.value=k(t.value,e,n),t.subs[0]?.forEach((t=>t("swap",e,n)));return j=null,q=null,t}const P={set:B,insert:H,insertList:G,remove:K,push:I,pushList:J,swap:O,clear:N,perform:F,pop:M};function Q(...e){return q=this,j=e,P}function R(e){const n=function(){return T.detectorEnabled&&T.detected.add(n),n.value};return n.value=e,n.subs=new Array(4),n.context=T.context,n.updateCount=0,n.mutable=!0,n.$=Q,n.set=B,n.perform=F,Array.isArray(e)&&(n.insertList=G,n.push=I,n.pushList=J,n.insert=H,n.remove=K,n.clear=N,n.swap=O,n.pop=M),n}const T={context:null,detectorEnabled:!1,detected:new Set};export{l as CONNECTION_PHASE,e as ErrorBoundary,s as LIST_PHASE,n as List,r as RENDER_PHASE,a as USER_EFFECT_PHASE,v as batch,i as batching,T as coreInfo,c as detect,x as effect,E as invalidate,C as memo,t as onConnect,o as onDisconnect,R as reactive,g as subscribe,D as targetKey,m as unsubscribe}; |
{ | ||
"name": "hydroxide", | ||
"description": "Next Generation Reactive Framework", | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"author": "Manan Tank", | ||
@@ -10,3 +10,3 @@ "license": "MIT", | ||
"module": "dist/prod-esm.js", | ||
"types": "dist/prod-esm.d.ts", | ||
"types": "dist/types/index.d.ts", | ||
"sideEffects": false, | ||
@@ -35,12 +35,22 @@ "exports": { | ||
}, | ||
"files": [ | ||
"dist", | ||
"package.json", | ||
"readme.md" | ||
], | ||
"scripts": { | ||
"clean": "rimraf dist", | ||
"build": "rollup -c", | ||
"build": "npm run clean && rollup -c && npm run build:types", | ||
"build:types": "tsc --project tsconfig.json --emitDeclarationOnly", | ||
"ts-check": "tsc --noEmit --project tsconfig.json", | ||
"test": "jest", | ||
"prepublishOnly": "npm run clean && npm run build" | ||
"prepublishOnly": "npm run build" | ||
}, | ||
"devDependencies": { | ||
"@babel/preset-typescript": "^7.18.6", | ||
"@rollup/plugin-babel": "^5.3.1", | ||
"@rollup/plugin-replace": "^4.0.0", | ||
"@rollup/plugin-typescript": "^8.3.3", | ||
"@types/jest": "^27.0.3", | ||
"hydroxide-jsx": "^0.2.0", | ||
"jest": "^27.4.5", | ||
@@ -50,3 +60,2 @@ "rimraf": "^3.0.2", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"rollup-plugin-ts": "^3.0.2", | ||
"ts-jest": "^27.1.2", | ||
@@ -53,0 +62,0 @@ "tsd": "^0.21.0", |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
61107
13
22
1505
1