limu
Version:
A fast js lib of immutable data, based on shallow copy on read and mark modified on write mechanism
170 lines (169 loc) • 4.96 kB
JavaScript
import { genSymbolId, strSymbolDict, symbolStrDict } from '../support/inner-data';
import { isMap, isSymbol } from '../support/util';
export function nodupPush(list, toPush) {
if (!list.includes(toPush))
list.push(toPush);
}
export function ensureStrKey(maySymbolKey) {
const key = maySymbolKey;
if (!isSymbol(maySymbolKey)) {
return maySymbolKey;
}
let symbolStr = symbolStrDict[key];
if (!symbolStr) {
symbolStr = genSymbolId();
symbolStrDict[key] = symbolStr;
}
return symbolStr;
}
function getKeyPathIdx(keyPaths, keyPath) {
const keyPathStrs = keyPaths.map((v) => v.join('|'));
const keyPathStr = keyPath.join('|');
return keyPathStrs.indexOf(keyPathStr);
}
export function getKeyStrByPath(keyPath, ensureStr) {
let target = keyPath;
if (ensureStr) {
target = toKeyStrPath(keyPath, true);
}
return target.join('|');
}
/**
* in: ['a', 'b', Symbol]
* out: ['a', 'b', 'SID_1']
*/
export function toKeyStrPath(keyPath, traversal) {
let keyStrPath = [];
if (traversal) {
keyPath.forEach((v) => {
const keyStr = ensureStrKey(v);
keyStrPath.push(keyStr);
});
return keyStrPath;
}
keyStrPath = keyPath.slice();
const lastIdx = keyPath.length - 1;
const lastKey = keyPath[lastIdx];
const keyStr = ensureStrKey(lastKey);
keyStrPath[lastIdx] = keyStr;
return keyStrPath;
}
/**
* out: ['a', 'b', 'SID_1']
* in: ['a', 'b', Symbol]
*/
export function toKeyPath(keyStrPath) {
return keyStrPath.map((str) => strSymbolDict[str] || str);
}
export function pushKeyPath(meta, keyPath, inputKeyStrPath) {
const { keyPaths, keyStrPaths } = meta;
const keyStrPath = inputKeyStrPath || toKeyStrPath(keyPath);
const idx = getKeyPathIdx(keyStrPaths, keyStrPath);
if (idx < 0) {
keyPaths.push(keyPath);
keyStrPaths.push(keyStrPath);
}
}
/**
* 删一条路径,并将 keyPath, keyStrPath 重新指向一个存在的路径
*/
export function delKeyPath(meta) {
const { keyPaths, keyStrPaths, keyStrPath } = meta;
const idx = getKeyPathIdx(keyStrPaths, keyStrPath);
keyStrPaths.splice(idx, 1);
keyPaths.splice(idx, 1);
meta.keyPath = keyPaths[0];
meta.keyStrPath = keyStrPaths[0];
}
/**
* string 获取不到,尝试转为 number 获取
*/
export function getMapVal(map, key) {
const strKeyVal = map.get(key);
if (strKeyVal !== undefined) {
return strKeyVal;
}
const numKeyVal = map.get(Number(key) || key);
if (numKeyVal !== undefined) {
return numKeyVal;
}
return undefined;
}
export function getVal(obj, keyPath) {
let val;
let parent = obj;
const lastIdx = keyPath.length - 1;
let isGetted = true;
for (let i = 0; i <= lastIdx; i++) {
const key = keyPath[i];
if (!parent && i < lastIdx) {
isGetted = false;
break;
}
val = isMap(parent) ? getMapVal(parent, key) : parent[key];
parent = val;
}
return { val, isGetted };
}
export function getValByKeyPaths(obj, keyPaths) {
let targetVal;
let isValGetted = false;
const lastIdx = keyPaths.length - 1;
for (let i = 0; i <= lastIdx; i++) {
const keyPath = keyPaths[i];
const { isGetted, val } = getVal(obj, keyPath);
if (isGetted) {
targetVal = val;
isValGetted = true;
break;
}
}
return { isGetted: isValGetted, val: targetVal };
}
export function setVal(obj, keyPath, val) {
let parent = obj;
const lastIdx = keyPath.length - 1;
for (let i = 0; i <= lastIdx; i++) {
if (!parent) {
break;
}
const key = keyPath[i];
if (i === lastIdx) {
parent[key] = val;
break;
}
parent = isMap(parent) ? getMapVal(parent, key) : parent[key];
}
}
export function setValByKeyPaths(obj, keyPaths, val) {
const lastIdx = keyPaths.length - 1;
for (let i = 0; i <= lastIdx; i++) {
const keyPath = keyPaths[i];
setVal(obj, keyPath, val);
}
}
/**
* in: keyPath [a,b,0,d,0] [[a,b,0], [info,0]]
* out: [[a,b,0,d,0], [info,0,d,0]]
*/
export function intersectPath(keyPath, commonKeyPaths) {
const inputKeyStr = getKeyStrByPath(keyPath);
let restStr = '';
for (const tmpKeyPath of commonKeyPaths) {
const tmpKeyStr = getKeyStrByPath(tmpKeyPath, true);
const prefix = `${tmpKeyStr}|`;
if (inputKeyStr.startsWith(prefix)) {
restStr = inputKeyStr.substring(prefix.length);
break;
}
}
const newKeyPaths = [];
if (restStr) {
const subStrPaths = restStr.split('|');
const subPaths = toKeyPath(subStrPaths);
commonKeyPaths.forEach((keyPath) => {
newKeyPaths.push(keyPath.concat(subPaths));
});
}
return newKeyPaths;
}