keys-mapper
Version:
keys-mapper 是一个通过设置属性名字映射,就可将一个对象转换成另一个对象的工具;支持循环引用、反向映射、深度映射
189 lines (184 loc) • 6.26 kB
JavaScript
/*
keys-mapper v2.0.0
author: {
"name": "郭斌勇",
"email": "guobinyong@qq.com"
}
license: MIT
homepage: https://github.com/GuoBinyong/keys-mapper#readme
repository: {
"type": "git",
"url": "https://github.com/GuoBinyong/keys-mapper"
}
description: keys-mapper 是一个通过设置属性名字映射,就可将一个对象转换成另一个对象的工具;支持循环引用、反向映射、深度映射
*/
import { Decide } from 'com-tools';
/**
* 将 KeyMaps 类型 转为 KeyMapsObject 类型
* @param keyMaps
* @returns
*/
function toKeyMapsObject(keyMaps) {
if (!Array.isArray(keyMaps)) {
return keyMaps;
}
const entries = [];
for (const [sourceKeys, mapKeys] of keyMaps) {
if (Array.isArray(sourceKeys)) {
const flatKeyMapArr = sourceKeys.map(function (key) {
return [key, mapKeys];
});
Array.prototype.push.apply(entries, flatKeyMapArr);
}
else {
entries.push([sourceKeys, mapKeys]);
}
}
return Object.fromEntries(entries);
}
/**
* 将 keyMaps1 和 keyMaps2 合并成一个 KeyMapsObject 对象
*/
function mergeKeyMaps(keyMaps1, keyMaps2) {
const kmo1 = toKeyMapsObject(keyMaps1);
const kmo2 = toKeyMapsObject(keyMaps2);
const entries = [];
for (const [sourceKeys, mapKeys2] of Object.entries(kmo2)) {
const mapKeys1 = kmo1[sourceKeys];
let mapKeys = Array.isArray(mapKeys2) ? [...mapKeys2] : [mapKeys2];
if (mapKeys1 !== undefined) {
mapKeys = mapKeys.concat(mapKeys1);
}
entries.push([sourceKeys, mapKeys]);
}
return Object.fromEntries(entries);
}
/**
* 将 keyMaps 反转
* @param keyMaps
* @returns
*/
function reverseKeyMaps(keyMaps) {
const keyMapsArr = Array.isArray(keyMaps) ? keyMaps : Object.entries(keyMaps);
const reverseKMA = [];
for (const [sourceKeys, mapKeys] of keyMapsArr) {
const mapKeyArr = Array.isArray(mapKeys) ? mapKeys : [mapKeys];
const finalMKA = mapKeyArr.filter(function (key) {
return key != null;
});
reverseKMA.push([finalMKA, sourceKeys]);
}
return reverseKMA;
}
/**
* key映射的核心函数
* @param options
* @returns
*/
function keysMapperByRecursive(options) {
const { source, keyMaps, maxDepth, startDepth, deleOther, keep, rawCopyMap, completeCB: complete, array: hasArray } = options;
const completeCB = complete || function () { };
if (maxDepth < startDepth || !(source && typeof source === "object")) {
completeCB(source);
return source;
}
let decide = rawCopyMap.get(source);
if (decide) {
decide.then(completeCB);
return decide.value;
}
decide = new Decide();
decide.then(completeCB);
rawCopyMap.set(source, decide);
const nextDepth = startDepth + 1;
const newEntries = [];
let entries;
const isArray = Array.isArray(source);
const target = isArray ? [] : {};
if (isArray) {
if (!hasArray) {
source.forEach(function (value, index) {
target.push(undefined);
keysMapperByRecursive(Object.assign(Object.assign({}, options), { source: value, startDepth: nextDepth, completeCB: function (newValue) {
target.splice(index, 1, newValue);
} }));
});
decide.value = target;
return target;
}
entries = source.map(function (item, index) {
return [index, item];
});
}
else {
entries = Object.entries(source);
}
for (const [key, value] of entries) {
const newKeys = keyMaps[key];
const newMapKeyArr = Array.isArray(newKeys) ? [...newKeys] : [newKeys];
const newKeyArr = newMapKeyArr.filter(k => k != null);
if (newKeys === null || (newKeys === undefined && deleOther) || (newKeys !== undefined && !keep && newKeyArr.length === 0)) {
continue;
}
keysMapperByRecursive(Object.assign(Object.assign({}, options), { source: value, startDepth: nextDepth, completeCB: function (newValue) {
if (newKeys === undefined || keep) {
newKeyArr.push(key);
}
newKeyArr.forEach(function (newKey) {
newEntries.push([newKey, newValue]);
});
} }));
}
for (const [key, value] of newEntries) {
target[key] = value;
}
decide.value = target;
return target;
}
/**
* 创建以 presetKeyMapsObject 为预设的 keysMapper() 函数
* @param presetKeyMapsObject
* @returns
*/
function createKeysMapper(presetKeyMapsObject) {
function keysMapper(source, options, keyMaps) {
if (options) {
var { maxDepth, reverse } = options;
}
const maxDepth_Num = maxDepth == null ? Infinity : maxDepth;
const presetKMO = keysMapper.presetKeyMapsObject;
let finalKMO = presetKMO;
if (keyMaps) {
if (Object.keys(presetKMO).length > 0) {
finalKMO = mergeKeyMaps(presetKMO, keyMaps);
}
else {
finalKMO = toKeyMapsObject(keyMaps);
}
}
if (reverse) {
const reverseKMA = reverseKeyMaps(finalKMO);
finalKMO = toKeyMapsObject(reverseKMA);
}
return keysMapperByRecursive(Object.assign(Object.assign({}, options), { source, keyMaps: finalKMO, maxDepth: maxDepth_Num, startDepth: 0, rawCopyMap: new Map() }));
}
Object.defineProperty(keysMapper, "presetKeyMapsObject", {
configurable: true,
enumerable: true,
get: function () {
if (!this._presetKeyMapsObject) {
this._presetKeyMapsObject = {};
}
return this._presetKeyMapsObject;
},
set: function (newValue) {
this._presetKeyMapsObject = newValue;
}
});
if (presetKeyMapsObject) {
keysMapper.presetKeyMapsObject = presetKeyMapsObject;
}
return keysMapper;
}
const keysMapper = createKeysMapper();
export { createKeysMapper, keysMapper, mergeKeyMaps, reverseKeyMaps, toKeyMapsObject };