limu
Version:
A fast js lib of immutable data, based on shallow copy on read and mark modified on write mechanism
193 lines (192 loc) • 6.6 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Licensed under the MIT License.
*
* @Author: fantasticsoul
*--------------------------------------------------------------------------------------------*/
import { buildLimuApis, FINISH_HANDLER_MAP } from './core/build-limu-apis';
import { deepCopy as deepCopyFn } from './core/copy';
import { deepFreeze as deepFreezeFn } from './core/freeze';
import { getDraftMeta, getDraftProxyMeta, getMetaVer, isDiff as isDiffFn, isDraft as isDraftFn, shallowCompare as shallowCompareFn, } from './core/meta';
import { current as currentFn, markRaw as markRawFn, original as originalFn } from './core/user-util';
import { IMMUT_BASE, VER as v } from './support/consts';
import { conf } from './support/inner-data';
import { canBeNum, getDataType, has, isFn, isMap, isMardedRaw, isObject, isPrimitive, isPromiseFn, isPromiseResult, isSet, isSymbol, noop, } from './support/util';
// isDraft isDiff shallowCompare 高频使用的从顶层暴露,其他随 limuUtils 里暴露
/**
* 判断是否是草稿
* @see https://tnfe.github.io/limu/docs/api/basic/limu-utils#isdraft
*/
export const isDraft = isDraftFn;
/**
* 判断两个值是否相同
* @see https://tnfe.github.io/limu/docs/api/basic/limu-utils#isdiff
*/
export const isDiff = isDiffFn;
/**
* 浅比较两个对象是否相同
* @see https://tnfe.github.io/limu/docs/api/basic/limu-utils#shallowcompare
*/
export const shallowCompare = shallowCompareFn;
/**
* 内部工具函数集合,写为如下格式会降低覆盖率,故导入后再导出
* ```txt
* import * as limuUtils; from './support/util';
* const { isFn, isPromiseFn, isPromiseResult } = limuUtils;;
* export { limuUtils; };
* ```
*/
export const limuUtils = {
has,
noop,
isObject,
isMap,
isSet,
isFn,
isPrimitive,
isPromiseFn,
isPromiseResult,
isSymbol,
isMardedRaw,
canBeNum,
isDraft,
isDiff,
shallowCompare,
getDraftMeta,
getDataType,
};
// export interface IProduceWithPatches {
// <T = ObjectLike>(baseState: T, cb: ProduceCb<T>, options?: ICreateDraftOptions): any[];
// }
function checkCbFn(cb) {
if (!isFn(cb)) {
throw new Error('produce callback is not a function');
}
}
const notRootDraftTip = 'Not a Limu root draft';
const finishedTip = 'Draft has been finished!';
function getFinishHandler(draft) {
const finishHandler = FINISH_HANDLER_MAP.get(draft);
if (!finishHandler) {
if (!getMetaVer(draft)) {
throw new Error(notRootDraftTip);
}
const meta = getDraftProxyMeta(draft);
if ((meta === null || meta === void 0 ? void 0 : meta.level) !== 0) {
throw new Error(notRootDraftTip);
}
throw new Error(finishedTip);
}
return finishHandler;
}
/** limu 的版本号 */
export const VER = v;
/**
* 创建草稿函数,可对返回的草稿对象直接修改,此修改不会影响原始对象
* @see https://tnfe.github.io/limu/docs/api/basic/create-draft
*/
export function createDraft(base, options) {
const apis = buildLimuApis(options);
const rootDraft = apis.createDraft(base);
return rootDraft;
}
/**
* 结束草稿的函数,生成的新对象和原始对象会结构共享
* @see https://tnfe.github.io/limu/docs/api/basic/create-draft
*/
export function finishDraft(draft) {
const finishHandler = getFinishHandler(draft);
return finishHandler(draft);
}
/**
* 生成一个不可修改的对象im,但原始对象的修改将同步会影响到im
* immut 采用了读时浅代理的机制,相比deepFreeze会拥有更好性能,适用于不暴露原始对象出去,只暴露生成的不可变对象出去的场景
* @see: https://tnfe.github.io/limu/docs/api/basic/immut
*/
export function immut(base, options) {
const limuApis = buildLimuApis(Object.assign(Object.assign({}, (options || {})), { readOnly: true, [IMMUT_BASE]: true }));
const immutData = limuApis.createDraft(base);
return immutData;
}
/**
* 结束由 immut 创建的草稿对象
*/
export function finishImmut(immutDraft) {
const finishHandler = getFinishHandler(immutDraft);
return finishHandler(immutDraft, true);
}
// see issue https://github.com/tnfe/limu/issues/5
function checkCbPromise(cb, result) {
if (isPromiseFn(cb) || isPromiseResult(result)) {
throw new Error('produce callback can not be a promise function or result');
}
}
function innerProduce(baseState, cb, options) {
checkCbFn(cb);
const draft = createDraft(baseState, options);
const result = cb(draft);
checkCbPromise(cb, result);
return finishDraft(draft);
}
function produceFn(baseState, cb, options) {
if (!cb || !isFn(cb)) {
// expect baseState to be a callback, support curried invocation
// expect cb to be options
const mayCb = baseState;
const mayOptions = cb;
checkCbFn(baseState);
return (state) => {
return innerProduce(state, mayCb, mayOptions);
};
}
return innerProduce(baseState, cb, options);
}
/**
* ```ts
* // normal use:
* const next = produce(draft=>draft.a=1);
*
* // use in react:
* setState(produce(draft=>{
* draft.name = 2;
* }));
* ```
*/
export const produce = produceFn;
// to be implemented in the future
// export const produceWithPatches = producePatchesFn as unknown as IProduceWithPatches;
/**
* 深冻结传入的值,返回的是冻结后的新值,如传入原始值则不做任何操作,原样返回
*/
export const deepFreeze = deepFreezeFn;
/**
* 对传入值做深克隆,返回的是克隆后的新值,如传入原始值则不做任何操作,原样返回
*/
export function deepCopy(obj) {
return deepCopyFn(obj);
}
/**
* 设置全局冻结配置,可在 createDraft, produce 时二次覆盖此全局配置
*/
export function setAutoFreeze(autoFreeze) {
conf.autoFreeze = autoFreeze;
}
/**
* 获取全局设置的 autoFreeze 值
*/
export function getAutoFreeze() {
return conf.autoFreeze;
}
/**
* 查看草稿对应的原始值
*/
export const original = originalFn;
/**
* 标记对象为 raw,此对象再次被复用时不会被代理,需注意标为 raw 后此对象会失去结构共享特性
*/
export const markRaw = markRawFn;
/**
* 导出草稿的副本数据( 即深克隆当前草稿 )
*/
export const current = currentFn;
// disable [export default], let esModuleInterop=true, allowSyntheticDefaultImports=true works in tsconfig.json
// export default produce;