![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
immutable-ops
Advanced tools
A collection of functions to perform immutable operations on plain JavaScript objects
A collection of functions to perform immutable operations on plain JavaScript objects and arrays.
Like updeep but with batched mutations and no freezing.
Like icepick, but with batched mutations and a curried API that puts the target object as the last argument. No freezing.
npm install immutable-ops --save
import compose from 'ramda/src/compose';
import ops from 'immutable-ops';
// These are all the available functions.
const {
// Functions operating on objects.
merge,
mergeDeep,
omit,
setIn,
// Functions operating on arrays.
insert,
splice,
push,
filter,
// Functions operating on both
set,
// Placeholder for currying.
__,
} = ops;
const arr = [1, 2, 3];
const pushFour = ops.push(4);
const pushFive = ops.push(5);
// All functions are curried. These functions
// still need the final argument, the array to
// operate on.
expect(pushFive).to.be.a('function');
const pushFourAndFive = compose(pushFive, pushFour);
const result = pushFourAndFive(arr);
// Two new arrays were created during `pushFourAndFive` execution.
expect(result).to.deep.equal([1, 2, 3, 4, 5]);
// Only one new array is created.
const sameResult = ops.batched(batchedOps => {
// batchedOps is able to keep track of mutated
// objects.
return compose(
batchedOps.push(5),
batchedOps.push(4)
)(arr);
});
expect(sameResult).to.deep.equal([1, 2, 3, 4, 5]);
A batch token is supplied by the user at the start of a batch, or created by immutable-ops
. Each newly created object within a batch is tagged with that token. If a batch using token X
operates on an object that is tagged with token X
, it is free to mutate it. You can think of it as an ownership; the batch owns the newly created object and therefore is free to mutate it. New batches use a token Y
that will never be equal to the previous token.
Tags are not removed; They are assigned to a non-enumerable property @@_______immutableOpsOwnerID
which should avoid any collisions.
This token strategy is similar to what ImmutableJS uses to track batches.
Manually using batch tokens
ops.batch
gives you access to all the immutable-ops
functions that take a token as their additional first argument. Otherwise they are identical to the functions found in ops
directly.
import ops from 'immutable-ops';
const token = ops.getBatchToken();
// This object has no batch token, since it was not created by immutable-ops.
const obj = {a: 1, b: 2};
// obj2 is a newly created object tagged with the token.
const obj2 = ops.batch.set(token, 'a', 10, obj);
expect(obj).to.not.equal(obj2)
// Because we operate on obj2 that has the same token as
// we passed to the function, obj2 is mutated.
const obj3 = ops.batch.set(token, 'b', 20, obj2);
expect(obj2).to.equal(obj3);
Handling batch tokens implicitly
import ops from 'immutable-ops';
const obj = {a: 1, b: 2};
const obj3 = ops.batched(batchedOps => {
// batchedOps has functions that are bound to a new batch token.
const obj2 = batchedOps.set('a', 10, obj);
return batchedOps.set('b', 20, obj2);
});
All operations are curried by default. Functions are curried with ramda.curry
. In addition to normal currying behaviour, you can use the ramda
placeholder variable available in ops.__
to specify parameters you want to pass arguments for later. Example:
const removeNFromHead = ops.splice(/* startIndex */ 0, /* deleteCount */ops.__, /* valsToAdd */[]);
const removeTwoFromHead = removeNFromHead(2);
const arr = [1, 2, 3];
console.log(removeTwoFromHead(arr));
// [3];
Performs a shallow merge on targetObj
. mergeObj
can be a single object to merge, or a list of objects. If a list is passed as mergeObj
, objects to the right in the list will have priority when determining final attributes.
Returns the merged object, which will be a different object if an actual change was detected during the merge.
const result = ops.merge(
// mergeObj
{
a: 'theA',
b: {
c: 'nestedC',
},
},
// targetObj
{
a: 'theA2',
b: {
d: 'nestedD',
},
c: 'theC',
}
);
console.log(result);
// {
// {
// a: 'theA',
// b: {
// c: 'nestedC'
// },
// c: 'theC',
// },
// }
Same as merge
, but performs merge
recursively on attributes that are objects (not arrays).
const result = ops.deepMerge(
// mergeObj
{
a: 'theA',
b: {
c: 'nestedC',
},
},
// targetObj
{
a: 'theA2',
b: {
d: 'nestedD',
},
c: 'theC',
}
);
console.log(result);
// {
// {
// a: 'theA',
// b: {
// c: 'nestedC',
// d: 'nestedD',
// },
// c: 'theC',
// },
// }
Returns an object, with the value at path
set to value
. path
can be a dot-separated list of attribute values or an array of attribute names to traverse.
const obj = {
location: {
city: 'San Francisco',
},
};
const newObj = ops.setIn(['location', 'city'], 'Helsinki', obj);
console.log(newObj);
// {
// location: {
// city: 'Helsinki',
// },
// };
Returns a shallow copy of targetObj
without the keys specified in keysToOmit
. keysToOmit
can be a single key name or an array of key names.
const obj = {
a: true,
b: true,
};
const result = ops.omit('a', obj);
console.log(result);
// {
// b: true,
// }
Returns a new array with values
inserted at starting at index startIndex
to targetArray
.
const arr = [1, 2, 4];
const result = ops.insert(2, [3], arr);
console.log(result);
// [1, 2, 3, 4]
Returns a shallow copy of targetArray
with value
added to the end. value
can be a single value or an array of values to push.
const arr = [1, 2, 3];
const result = ops.push(4, arr);
console.log(result);
// [1, 2, 3, 4]
Returns a shallow copy of targetArray
with items that func
returns true
for, when calling it with the item.
const arr = [1, 2, 3, 4];
const result = ops.filter(item => item % 2 === 0, arr);
console.log(result);
// [2, 4]
Like Array.prototype.splice
, but operates on a shallow copy of targetArray
and returns the shallow copy.
const arr = [1, 2, 3, 3, 3, 4];
const result = ops.splice(2, 2, [], arr);
console.log(result);
// [1, 2, 3, 4]
Returns a shallow copy of target
with its value at index or key key
set to value
.
const arr = [1, 2, 5];
const result = ops.set(2, 3, arr);
console.log(result);
// [1, 2, 3]
const obj = {
a: 'X',
b: 'theB',
};
const resultObj = ops.set('a', 'theA', obj);
console.log(resultObj);
// {
// a: 'theA',
// b: 'theB',
// }
BREAKING: No getImmutableOps
function, which was the main export, is exported anymore because options were removed. Now the object containing the operation functions is exported directly.
BREAKING: removed option to choose whether operations are curried. Functions are now always curried.
BREAKING: former batched mutations API totally replaced.
BREAKING: batched mutations implementation changed.
Previously newly created objects were tagged with a "can mutate" tag, and references to those objects were kept in a list. After the batch was finished, the list was processed by removing the tags from each object in the list.
Now a batch token is created at the start of a batch (or supplied by the user). Each newly created object is tagged with that token. If a batch using token X
operates on an object that is tagged with token X
, it is free to mutate it. New batches use a token Y
that will never be equal to the previous token.
Tags are not removed anymore; They are assigned to a non-enumerable property @@_______immutableOpsOwnerID
which should avoid any collisions.
This token strategy is similar to what ImmutableJS uses to track batches.
MIT. See LICENSE
.
FAQs
A collection of functions to perform immutable operations on plain JavaScript objects
The npm package immutable-ops receives a total of 3,376 weekly downloads. As such, immutable-ops popularity was classified as popular.
We found that immutable-ops demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.