locutus
Version:
Locutus other languages' standard libraries to JavaScript for fun and educational purposes
63 lines (62 loc) • 2.35 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.update_in = update_in;
function isRecordLike(value) {
return typeof value === 'object' && value !== null;
}
function cloneForKey(value, nextKey) {
if (Array.isArray(value)) {
return value.slice();
}
if (isRecordLike(value)) {
return { ...value };
}
return typeof nextKey === 'number' ? [] : {};
}
function update_in(value, keys, updater, ...args) {
// discuss at: https://locutus.io/clojure/update_in/
// parity verified: Clojure 1.12
// original by: Kevin van Zonneveld (https://kvz.io)
// note 1: Mirrors Clojure update-in by immutably updating a nested path and creating missing containers.
// example 1: update_in({a: {b: 1}}, ['a', 'b'], (n) => Number(n) + 1)
// returns 1: {a: {b: 2}}
// example 2: update_in({a: {}}, ['a', 'b'], (v) => (v === undefined ? 10 : Number(v)))
// returns 2: {a: {b: 10}}
// example 3: update_in([1, {x: 3}], [1, 'x'], (n) => Number(n) * 2)
// returns 3: [1, {x: 6}]
if (typeof updater !== 'function') {
throw new TypeError('update_in(): updater must be a function');
}
if (!Array.isArray(keys)) {
return updater(value, ...args);
}
if (keys.length === 0) {
return updater(value, ...args);
}
const root = cloneForKey(value, keys[0]);
let sourceCursor = value;
let targetCursor = root;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
const nextKey = keys[i + 1];
if (key === undefined || nextKey === undefined) {
continue;
}
const sourceNext = sourceCursor !== null && typeof sourceCursor === 'object'
? sourceCursor[key]
: undefined;
const clonedNext = cloneForKey(sourceNext, nextKey);
targetCursor[key] = clonedNext;
sourceCursor = sourceNext;
targetCursor = clonedNext;
}
const leafKey = keys[keys.length - 1];
if (leafKey === undefined) {
return root;
}
const currentLeafValue = sourceCursor !== null && typeof sourceCursor === 'object'
? sourceCursor[leafKey]
: undefined;
targetCursor[leafKey] = updater(currentLeafValue, ...args);
return root;
}