@cfcs/core
Version:
Write once, create framework components that supports React, Vue, Svelte, and more.
111 lines (94 loc) • 2.55 kB
text/typescript
/**
* cfcs
* Copyright (c) 2022-present NAVER Corp.
* MIT license
*/
import { COMPUTED_PATH, OBSERVERS_PATH } from "./const";
import { Observer } from "./Observer";
import { ReactiveMethods } from "./types";
import { isObject, Ref } from "../core";
import { observe } from "./inline";
import { ReactiveSubscribe } from "./decorators/ReactiveSubscribe";
/**
* @hidden
*/
export function withReactiveMethods<
Instance,
Names extends keyof Partial<Instance>,
Return extends ReactiveMethods<Instance, Names>
>(ref: Ref<Instance>, methods?: readonly Names[]): Return {
const obj: Record<any, any> = {};
if (!methods) {
return obj;
}
methods.forEach(name => {
obj[name] = function (...args: any[]) {
const current: any = ref.current || ref.value;
return current[name](...args);
};
});
return obj as Return;
}
/**
* @hidden
*/
export function defineObservers(instance: any) {
const observers: Record<string, Observer<any>> = {};
Object.defineProperty(instance, OBSERVERS_PATH, {
get() {
return observers;
},
});
return observers;
}
/**
* @hidden
*/
export function getObservers(instance: any, isComputed?: boolean): Record<string, Observer<any>> {
if (!instance[OBSERVERS_PATH]) {
defineObservers(instance);
}
const observers = instance[OBSERVERS_PATH];
if (!isComputed) {
const computedList = instance?.constructor?.prototype?.[COMPUTED_PATH];
if (computedList) {
computedList.forEach(name => {
if (!(name in observers) && name in instance) {
instance[name];
}
});
}
}
return observers;
}
/**
* @hidden
*/
export function getObserver(instance: any, name: string, defaultValue?: any): Observer<any> {
const observers = getObservers(instance);
if (!observers[name]) {
observers[name] = observe(defaultValue);
}
return observers[name];
}
/**
* @hidden
*/
export function setObserver(instance: any, name: string, observer: Observer<any>) {
const observers = getObservers(instance);
observers[name] = observer;
}
/**
* @description Whether that object is an observer instance
* @category Reactive
*/
export function isObserver(val: any): val is Observer {
return val && isObject(val) && "current" in val && "subscribe" in val && "unsubscribe" in val;
}
/**
* @description Whether the object is reactive
* @category Reactive
*/
export function isReactive(val: any): val is ReactiveSubscribe<any> {
return val && !isObserver(val) && "subscribe" in val && "unsubscribe" in val;
}