cmpstr
Version:
CmpStr is a lightweight, fast and well performing package for calculating string similarity
108 lines (105 loc) • 3.02 kB
JavaScript
// CmpStr v3.2.2 build-bb61120-260311 by Paul Köhler @komed3 / MIT License
import { CmpStrUsageError } from './Errors.mjs';
const BRACKET_PATTERN = /\[(\d+)]/g;
const PATH_CACHE = new Map();
function parse(p) {
let cached = PATH_CACHE.get(p);
if (cached) return cached;
const parsed = p
.replace(BRACKET_PATTERN, '.$1')
.split('.')
.map((s) => {
const n = Number(s);
return Number.isInteger(n) && String(n) === s ? n : s;
});
PATH_CACHE.set(p, parsed);
return parsed;
}
function get(t, path, fb) {
let o = t;
for (const k of parse(path)) {
if (o == null || !(k in o)) return fb;
o = o[k];
}
return o;
}
function has(t, path) {
let o = t;
for (const k of parse(path)) {
if (o == null || !(k in o)) return false;
o = o[k];
}
return true;
}
function set(t, path, value) {
if (path === '') return value;
const keys = parse(path);
if (t !== undefined && (typeof t !== 'object' || t === null))
throw new CmpStrUsageError(
`Cannot set property <${keys[0]}> of <${JSON.stringify(t)}>`,
{ path: keys[0], target: t }
);
const root = t ?? (typeof keys[0] === 'number' ? [] : Object.create(null));
let cur = root;
for (let i = 0; i < keys.length - 1; i++) {
const k = keys[i];
let n = cur[k];
if (n != null && typeof n !== 'object')
throw new CmpStrUsageError(
`Cannot set property <${keys[i + 1]}> of <${JSON.stringify(n)}>`,
{ path: keys.slice(0, i + 2), value: n }
);
if (n == null)
n = cur[k] = typeof keys[i + 1] === 'number' ? [] : Object.create(null);
cur = n;
}
cur[keys[keys.length - 1]] = value;
return root;
}
function merge(
t = Object.create(null),
o = Object.create(null),
mergeUndefined = false
) {
const target = t ?? Object.create(null);
Object.keys(o).forEach((k) => {
const val = o[k];
if (!mergeUndefined && val === undefined) return;
if (k === '__proto__' || k === 'constructor') return;
if (val !== null && typeof val === 'object' && !Array.isArray(val)) {
const existing = target[k];
target[k] = merge(
existing !== null &&
typeof existing === 'object' &&
!Array.isArray(existing)
? existing
: Object.create(null),
val,
mergeUndefined
);
} else target[k] = val;
});
return target;
}
function rmv(t, path, preserveEmpty = false) {
const keys = parse(path);
const remove = (obj, i = 0) => {
const key = keys[i];
if (!obj || typeof obj !== 'object') return false;
if (i === keys.length - 1) return delete obj[key];
if (!remove(obj[key], i + 1)) return false;
if (!preserveEmpty) {
const val = obj[key];
if (
typeof val === 'object' &&
((Array.isArray(val) && val.every((v) => v == null)) ||
(!Array.isArray(val) && Object.keys(val).length === 0))
)
delete obj[key];
}
return true;
};
remove(t);
return t;
}
export { get, has, merge, rmv, set };