Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
electrum-store
Advanced tools
Electrum Store (electrum-store
) provides a store implementation tailored
for use with electrum-arc
, the Electrum Agnostic Reactive Components.
The store maintains state organized as a tree. State is immutable. When the store is updated, new state is produced and nodes get replaced in the tree.
Neither the store nor its states will emit notifications when things
change, since electrum
does not need the feature.
Thanks to immutability, whole trees can be compared for equality
with ===
. Whenever a (sub-)tree changes, the store guarantees that
the state
objects change too, from the node in the tree where the
change happened up to the root of the tree (change percolation).
To create a store, call Store.create()
. The constructor is not available
for public consumption and should not be called.
const store = Store.create ();
The store maintains its state as a tree. Selecting state located at a.b.c
will automatically create a
, a.b
and a.b.c
if they did not yet exist
in the tree. You can call select()
on a state
object, which can be used
to navigate down the tree.
select()
creates missing nodes whereas find()
returns undefined
if
it does not find the specified nodes.
const store = Store.create ();
const state1 = store.select ('a.b.c');
const state2 = store.select ('a').select ('b.c');
const state3 = store.find ('a.b.c');
const state4 = store.find ('x.y');
expect (state1).to.equal (state2);
expect (state1).to.equal (state3);
expect (state4).to.equal (undefined);
Whenever new state needs to be recorded in the store, the tree will be updated and new generation tags will be applied to the parts of the tree which changed as a result of this.
Setting a.b.c
first will produce nodes a
, b
and c
in generation 1.
Adding a.b.d
will mutate a.b
(it contains a new child d
) and
also mutate a
(it contains an updated a.b
); all this will happen
inside generation 2. Nodes a
, b
and d
will have generation:2
whereas node c
will remain at generation:1
.
const store = Store.create ();
store.select ('a.b.c'); // generation 1
store.select ('a.b.d'); // generation 2
expect (store.find ('a').generation).to.equal (2);
expect (store.find ('a.b').generation).to.equal (2);
expect (store.find ('a.b.c').generation).to.equal (1);
expect (store.find ('a.b.d').generation).to.equal (2);
A state (with all its children) can also be removed from the store:
const store = Store.create ();
store.select ('a.b.c'); // generation 1
store.select ('a.b.d'); // generation 2
store.remove ('a.b'); // generation 3
expect (store.find ('a').generation).to.equal (3);
expect (store.find ('a.b')).to.not.exist ();
expect (store.find ('a.b.c')).to.not.exist ();
expect (store.find ('a.b.d')).to.not.exist ();
State is usually updated using with()
, withValue()
and withValues()
or created implicitly by select()
. It is also possible to set state
explicitly:
const store = Store.create ();
const state1 = State.create ('x.y');
const state2 = store.setState (state1);
expect (state1.generation).to.equal (0);
expect (state1).to.not.equal (state2);
expect (state2.generation).to.equal (1);
State has an intrinsic generation which can be retrieved with the
generation
property. As soon as a state is attached to a store, its
generation will be a strictly positive integer (1...n).
The helper method shouldUpdate()
returns true
when the provided
generation is compatible with the state's own generation (i.e. equal
or more recent to the state generation).
const store = Store.create ();
store.select ('a');
store.select ('a.b');
const state = store.select ('a.b');
expect (state.generation).to.equal (2);
expect (state.shouldUpdate (1)).to.be.false (); // provided gen=1 older than state.generation
expect (state.shouldUpdate (2)).to.be.true ();
expect (state.shouldUpdate (3)).to.be.true ();
Setting the state in the store requires calls to select()
to proper
node and then changing the state's internal values using set()
. This
can quickly become cumbersome if the state we want to set is stored as
a Plain Old JavaScript Object (POJO).
const store = Store.create ();
store.select ('a.b').set ('x', 10, 'y', 20);
const pojo = {x: 15, name: 'foo', c: {value: 'bar'}};
store.apply ('a.b', pojo);
expect (store.select ('a.b').get ('x')).to.equal (15);
expect (store.select ('a.b').get ('y')).to.equal (20);
expect (store.select ('a.b').get ('name')).to.equal ('foo');
expect (store.select ('a.b.c').get ('value')).to.equal ('bar');
The apply()
method also accepts objects with arrays, such as:
const store = Store.create ();
const pojo = {items: ['x', {value: 'bar'}]};
store.apply ('a', pojo);
expect (store.select ('a.items.0').get ()).to.equal ('x');
expect (store.select ('a.items.1').get ('value')).to.equal ('bar');
...or even arrays, directly:
const store = Store.create ();
const pojo = ['x', {value: 'bar'}];
store.apply ('a', pojo);
expect (store.select ('a.0').get ()).to.equal ('x');
expect (store.select ('a.1').get ('value')).to.equal ('bar');
State holds following information:
id
→ the absolute path of the node (e.g. 'a.b.c'
).key
→ the local path of the node (e.g. 'c'
if the id
is 'a.b.c'
).store
→ a reference to the containing store.generation
→ the generation number of last update.values
→ a collection of values - this is never accessed directly.The default value is accessed with state.value
. Named values can be
accessed using state.get(name)
.
get (name)
or get ()
→ the value for name
(or the default value if
no name is specified), if it exists; otherwise undefined
.getInherited (name)
→ the value for name
if it can be found on the
state or any of its parent nodes, otherwise undefined
.contains (name)
→ true
if a value exists for name
, otherwise false
.When a state (a node of the tree) contains multiple child nodes, and when these
nodes have an integer key
(zero or positive), this can be considered as a poor
men's array. The keys are then equivalent to the indexes into the array. They
can have gaps and need not be consecutive: [23, 24, 37]
would be valid index
keys.
any (id)
or any ()
→ true
if the state specified by id
exists
and if it is non-empty.exists (id)
→ true
if the state specified by id
exists.keys
→ an array of all the key
s found for the state's child nodes.['a', '0', '12', 'b']
indexKeys
→ an array of all the indexes of the state's child nodes;
nodes will only be reported if their key
is zero or a positive
integer. The values will always be sorted.[0, 1, 34]
The state can also be used as a starting point for find()
and select()
.
Without any argument, they return the state itself.
select()
creates missing nodes.find()
returns undefined
if it does not find the specified child.remove()
removes the node (if called without arguments) or the specified
child, if an id
is provided.select()
, find()
, remove()
and any()
accept a child id
or an index,
which will be converted to a key and used to look up the child.
State ids are similar to paths where the elements are separated by .
.
Class State
provides some static methods to manipulate these ids:
State.join (a, b, c, ...)
→ returns the joined path.State.getLeafId (id)
→ returns the last element of the path.State.getParentId (id)
→ returns the path of the immediate parent.State.getAncestorId (id, part)
→ returns the path of the first ancestor
which contains the specified part (path element); if the last element of the
id
matches part
, the full id
will be returned.expect (State.join ('a', 'b', 'c')).to.equal ('a.b.c');
expect (State.getLeafId ('a.b.c')).to.equal ('c');
expect (State.getParentId ('a.b.c')).to.equal ('a.b');
expect (State.getAncestorId ('a.b.c', 'b')).to.equal ('a.b');
Arrays can be built using state.add()
:
add ()
→ a new child state, where the key
is equal to the current
highest index, plus one.This is an easy way to add new states to an array of states.
const store = Store.create ();
store.select ('a.1');
store.select ('a.2');
store.select ('a.5');
expect (store.select ('a').add ().key).to.equal ('6');
expect (store.select ('a').indexKeys).to.deep.equal ([1, 2, 5, 6]);
To create state with an initial value, use State.create()
.
const state1 = State.create ('empty');
expect (state1.value).to.equal (undefined);
const state2 = State.create ('message', {'': 'Hello'});
expect (state2.value).to.equal ('Hello');
const state3 = State.create ('person', {name: 'Joe', age: 78});
expect (state3.get ('name')).to.equal ('Joe');
expect (state3.get ('age')).to.equal (78);
State objects are immutable. Updating state will produce a copy of the state object with the new values.
const state1 = State.create ('a', {x: 1, y: 2});
const state2 = State.withValue (state1, 'x', 10);
const state3 = State.withValues (state1, 'x', 10, 'y', 20);
const state4 = State.with (state1, {values: {x: 10, y: 20}});
// Setting same values does not mutate state:
const state5 = State.with (state1, {values: {x: 1, y: 2}});
expect (state1).to.equal (state5); // same values, same state
It is also possible to use method set()
to create a new state;
this is just syntactic sugar over the State.withValue()
static
methods.
const state1 = State.create ('a');
const state2 = state1.set ('x', 1);
const state3 = state2.set ('a'); // set default value
const state4 = state1.set ('x', 1, 'y', 2);
expect (state2.get ('x')).to.equal (1);
expect (state3.get ()).to.equal ('a');
expect (state4.get ('x')).to.equal (1);
expect (state4.get ('y')).to.equal (2);
When a state attached to a store is being mutated, the new state will be stored in the tree, and all nodes up to the root will get updated while doing so.
const store = Store.create ();
expect (store.select ('a.b.c').generation).to.equal (1); // gen. 1
expect (store.select ('a.b.d').generation).to.equal (2); // gen. 2
State.withValue (store.select ('a.b.c'), 'x', 10); // gen. 3
expect (store.select ('a.b.c').generation).to.equal (3);
expect (store.select ('a.b.d').generation).to.equal (2); // unchanged
expect (store.select ('a.b').generation).to.equal (3);
expect (store.select ('a').generation).to.equal (3);
State.withValue (store.select ('a.b'), 'y', 20); // gen. 4
expect (store.select ('a.b.c').generation).to.equal (3); // unchanged
expect (store.select ('a.b.d').generation).to.equal (2); // unchanged
expect (store.select ('a.b').generation).to.equal (4);
expect (store.select ('a').generation).to.equal (4);
FAQs
Electrum store provides a store implementation tailored for Electrum.
The npm package electrum-store receives a total of 2 weekly downloads. As such, electrum-store popularity was classified as not popular.
We found that electrum-store demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers 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
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.