UNPKG

immutablepatch

Version:

Apply RFC 6902 style patches to Immutable.JS data structures

134 lines (122 loc) 4.21 kB
'use strict'; var Immutable = require('immutable'); var path = require('./path'); var tryParseInt = function(n) { var int = parseInt(n); return isNaN(int) ? n : int; }; var primitivePatch = function (op, value) { if (op === 'add' || op === 'replace') { return value; } else if (op === 'remove') { return null; } }; var mapPatch = function(map, firstPath, restPath, op, value) { if (op === 'add') { if (restPath.length > 0 && map.get(firstPath) === undefined) { var baseValue = (restPath[0].match(/^\d+$/)) ? Immutable.List() : Immutable.Map(); return map.set(firstPath, anyPatch(baseValue, restPath, op, value)); } else { return map.set(firstPath, anyPatch(map.get(firstPath), restPath, op, value)); } } else if (op === 'replace') { if (restPath.length > 0) { return map.set(firstPath, anyPatch(map.get(firstPath), restPath, op, value)); } else { return map.set(firstPath, value); } } else if (op === 'remove') { if (restPath.length > 0) { return map.set(firstPath, anyPatch(map.get(firstPath), restPath, op, value)); } else { return map.remove(firstPath); } } else { throw new Error('map patch Error, unknown op: ' + op); } }; var sequencePatch = function(sequence, firstPath, restPath, op, value) { firstPath = tryParseInt(firstPath); if (op === 'add') { if (sequence.get(firstPath) === undefined) { if (restPath.length > 0) { var baseValue = (restPath[0].match(/^\d+$/)) ? Immutable.List() : Immutable.Map(); return sequence.set(firstPath, anyPatch(baseValue, restPath, op, value)); } else { // special case, add to the end if (firstPath === '-') { return sequence.splice(sequence.size, 0, value); } // special case, return the value return sequence.splice(firstPath, 0, value); } } else { if (restPath.length > 0) { return sequence.set(firstPath, anyPatch(sequence.get(firstPath), restPath, op, value)); } else { // special case, return the value return sequence.splice(firstPath, 0, value); } } } else if (op === 'replace') { if (restPath.length > 0) { return sequence.set(firstPath, anyPatch(sequence.get(firstPath), restPath, op, value)); } else { return sequence.set(firstPath, value); } } else if (op === 'remove') { if (restPath.length > 0) { return sequence.set(firstPath, anyPatch(sequence.get(firstPath), restPath, op, value)); } else { return sequence.remove(firstPath); } } else { throw new Error('sequence patch Error, unknown op: ' + op); } }; var isRecord = function(any) { return ( any != null && typeof any.updateIn === 'function' && typeof any.set === 'function' ) } var anyPatch = function(any, pathArray, op, value) { var firstPath, restPath; if (Immutable.Iterable.isIndexed(any)) { if (pathArray.length === 0) { return any; } firstPath = pathArray[0]; restPath = pathArray.slice(1); return sequencePatch(any, firstPath, restPath, op, value); } else if (Immutable.Iterable.isKeyed(any) || isRecord(any)) { // if the object is a record or a keyed iterable immutable object if (pathArray.length === 0) { return any; } firstPath = pathArray[0]; restPath = pathArray.slice(1); return mapPatch(any, firstPath, restPath, op, value); } else { if (pathArray.length === 0) { return value; } return primitivePatch(op, value); } }; var eachPatchInternal = function(value, patches) { while (patches.size) { var firstPatch = patches.get(0); var patches = patches.slice(1); var pathArray = firstPatch.get('path').split('/').slice(1).map(path.unescape); value = anyPatch(value, pathArray, firstPatch.get('op'), firstPatch.get('value')); } return value; }; var eachPatch = function(value, patches) { if (patches.size === 1) { var onlyPatch = patches.get(0); if (onlyPatch.get('op') === 'replace' && onlyPatch.get('path') === '/') { return onlyPatch.get('value'); } } return eachPatchInternal(value, patches); }; eachPatch.default = eachPatch; module.exports = eachPatch;