Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@libre/atom

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@libre/atom - npm Package Compare versions

Comparing version 1.0.2 to 1.1.0

dist/types/deref.d.ts

218

dist/index.esm.js

@@ -1,24 +0,42 @@

/** @ignore */
const derefArgMustBeAtom = "deref only accepts Atom instances, but got:";
// ------------------------------------------------------------------------------------------ //
// ---------------------------------- INTERNAL STATE ---------------------------------------- //
// ------------------------------------------------------------------------------------------ //
let nextAtomUid = 0;
const stateByAtomId = Object.create(null);
const validatorByAtomId = Object.create(null);
/** @ignore */
function getState(atom) {
function _useNextAtomId() {
return nextAtomUid++;
}
/** @ignore */
function _getState(atom) {
return stateByAtomId[atom["$$id"]];
}
// ------------------------------------------------------------------------------------------ //
// -------------------------------------- PUBLIC API ---------------------------------------- //
// ------------------------------------------------------------------------------------------ //
/** @ignore */
function _setState(atom, state) {
stateByAtomId[atom["$$id"]] = state;
}
/** @ignore */
function _getValidator(atom) {
return validatorByAtomId[atom["$$id"]];
}
/** @ignore */
function _setValidator(atom, validator) {
validatorByAtomId[atom["$$id"]] = validator;
}
/** @ignore */
const expectedAtomButGot = "Expected an Atom instances, but got:";
/** @ignore */
function _prettyPrint(val) {
return JSON.stringify(val, null, " ");
}
/** @ignore */
function _throwIfNotAtom(atom) {
if (!(atom instanceof Atom)) {
throw TypeError(`${expectedAtomButGot}\n\n${_prettyPrint(atom)}`);
}
}
/**
* `@libre/atom` provides a data type called `Atom` and a few functions for working with `Atom`s.
* It is heavily inspired by `atom`s in Clojure(Script).
*
* Atoms provide a predictable way to manage state that is shared by multiple components of a
* program as that state changes over time. They are particularly useful in the functional and reactive
* programming paradigms, where most components of a program are pure functions operating on
* immutable data. In this context, Atoms provide a form of mutability that is controlled in such
* A data structure useful for providing a controlled, predictable mechanism for mutability.
* Allows multiple components of a program to share read/write access to some state in such
* a way that no component can mutate another component's current reference to the state in

@@ -28,10 +46,15 @@ * the middle of some process or asynchronous operation.

*/
//
// ======================================= ATOM ==============================================
//
class Atom {
/** @ignore */
constructor(state) {
Object.defineProperty(this, "$$id", { value: nextAtomUid++ });
stateByAtomId[this["$$id"]] = state;
constructor(state, { validator } = {}) {
validator = validator || (() => true);
if (!validator(state)) {
const errMsg = `Atom initialized with invalid state:\n\n${_prettyPrint(state)}\n\naccording to validator function:\n${validator}\n\n`;
const err = Error(errMsg);
err.name = "AtomInvalidStateError";
throw err;
}
Object.defineProperty(this, "$$id", { value: _useNextAtomId() });
_setState(this, state);
_setValidator(this, validator);
return this;

@@ -54,11 +77,8 @@ }

*/
static of(state) {
return new Atom(state);
static of(state, options) {
return new Atom(state, options);
}
/** @ignore */
toString() {
return `Atom ${JSON.stringify({
$$id: this["$$id"],
"[[inner_state]]": getState(this)
}, null, " ")}`;
return `Atom<${_prettyPrint(_getState(this))}>`;
}

@@ -70,7 +90,5 @@ /** @ignore */

}
//
// ======================================= DEREF ==============================================
//
/**
* Reads (i.e. "*dereferences*") the current state of an [[Atom]]. The dereferenced value
* Dereferences (i.e. "*reads*") the current state of an [[Atom]]. The dereferenced value
* should ___not___ be mutated.

@@ -91,35 +109,27 @@ *

function deref(atom) {
if (!(atom instanceof Atom)) {
const arg = JSON.stringify(atom, null, " ");
throw TypeError(`${derefArgMustBeAtom}\n${arg}`);
}
return getState(atom);
_throwIfNotAtom(atom);
return _getState(atom);
}
//
// ======================================= SWAP ==============================================
//
/**
* Swaps `atom`'s state with the value returned from applying `updateFn` to `atom`'s
* current state. `updateFn` should be a pure function and ___not___ mutate `state`.
* Gets `atom`'s validator function
*
* @param atom an instance of [[Atom]]
* @param updateFn a pure function that takes the current state and returns the next state; the next state should be of the same type/interface as the current state;
* @param <S> the type of `atom`'s inner state
*
* @example
* ```jsx
*
*import {Atom, swap} from '@libre/atom'
*
*const stateAtom = Atom.of({ count: 0 })
*const increment = () => swap(stateAtom, (state) => ({
* count: state.count + 1
*}));
* ```
```js
import {Atom, deref, getValidator, swap} from '@libre/atom'
const atom = Atom.of({ count: 0 }, { validator: (state) => isEven(state.count) })
const validator = getValidator(atom)
validator({ count: 3 }) // => false
validator({ count: 2 }) // => true
```
*/
function swap(atom, updateFn) {
stateByAtomId[atom["$$id"]] = updateFn(getState(atom));
function getValidator(atom) {
_throwIfNotAtom(atom);
return _getValidator(atom);
}
//
// ======================================= SET ==============================================
//
/**

@@ -130,2 +140,3 @@ * Sets `atom`s state to `nextState`.

*
* @param <S> the type of `atom`'s inner state
* @param atom an instance of [[Atom]]

@@ -137,4 +148,3 @@ * @param nextState the value to which to set the state; it should be the same type/interface as current state

import {Atom, useAtom, set} from '@libre/atom'
import { DeepImmutable } from './internal-types';
import {Atom, deref, set} from '@libre/atom'

@@ -148,6 +158,88 @@ const atom = Atom.of({ count: 0 })

function set(atom, nextState) {
swap(atom, () => nextState);
_throwIfNotAtom(atom);
const validator = _getValidator(atom);
const didValidate = validator(nextState);
if (!didValidate) {
const errMsg = `Attempted to set the state of\n\n${atom}\n\nwith:\n\n${_prettyPrint(nextState)}\n\nbut it did not pass validator:\n${validator}\n\n`;
const err = Error(errMsg);
err.name = "AtomInvalidStateError";
throw err;
}
else {
_setState(atom, nextState);
}
}
export { Atom, deref, swap, set };
/**
* Sets the `validator` for `atom`. `validator` must be a pure function of one argument,
* which will be passed the intended new state on any state change. If the new state is
* unacceptable, `validator` should return false or throw an exception. If the current state
* is not acceptable to the new validator, an exception will be thrown and the validator will
* not be changed.
*
* @param <S> the type of `atom`'s inner state
*
* @example
```js
import {Atom, deref, setValidator, set} from '@libre/atom'
import { _setValidator } from './internal-state';
const atom = Atom.of({ count: 0 }, {validator: (state) => isNumber(state.count) })
setValidator(atom, (state) => isOdd(state.count)) // Error; new validator rejected
set(atom, {count: "not number"}) // Error; new state not set
setValidator(atom, (state) => isEven(state.count)) // All good
set(atom, {count: 2}) // All good
```
*/
function setValidator(atom, validator) {
_throwIfNotAtom(atom);
if (!validator(_getState(atom))) {
const errMsg = `Could not set validator on\n\n${atom}\n\nbecause current state would be invalid according to new validator:\n${validator}\n\n`;
const err = Error(errMsg);
err.name = "AtomInvalidStateError";
throw err;
}
else {
_setValidator(atom, validator);
}
}
/**
* Swaps `atom`'s state with the value returned from applying `updateFn` to `atom`'s
* current state. `updateFn` should be a pure function and ___not___ mutate `state`.
*
* @param <S> the type of `atom`'s inner state
* @param atom an instance of [[Atom]]
* @param updateFn a pure function that takes the current state and returns the next state; the next state should be of the same type/interface as the current state;
*
* @example
* ```jsx
*
*import {Atom, swap} from '@libre/atom'
*
*const stateAtom = Atom.of({ count: 0 })
*const increment = () => swap(stateAtom, (state) => ({
* count: state.count + 1
*}));
* ```
*/
function swap(atom, updateFn) {
_throwIfNotAtom(atom);
const nextState = updateFn(_getState(atom));
const validator = _getValidator(atom);
const didValidate = validator(nextState);
if (!didValidate) {
const errMsg = `swap updateFn\n${updateFn}\n\nattempted to swap the state of\n\n${atom}\n\nwith:\n\n${_prettyPrint(nextState)}\n\nbut it did not pass validator:\n${validator}\n\n`;
const err = Error(errMsg);
err.name = "AtomInvalidStateError";
throw err;
}
else {
_setState(atom, nextState);
}
}
export { Atom, deref, getValidator, set, setValidator, swap };
//# sourceMappingURL=index.esm.js.map

@@ -1,2 +0,2 @@

!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t["@libre/atom"]={})}(this,function(t){"use strict";var e=0,i=Object.create(null);function r(t){return i[t.$$id]}var o=function(){function n(t){return Object.defineProperty(this,"$$id",{value:e++}),i[this.$$id]=t,this}return n.of=function(t){return new n(t)},n.prototype.toString=function(){return"Atom "+JSON.stringify({$$id:this.$$id,"[[inner_state]]":r(this)},null," ")},n.prototype.inspect=function(){return this.toString()},n}();function u(t,n){i[t.$$id]=n(r(t))}t.Atom=o,t.deref=function(t){if(t instanceof o)return r(t);var n=JSON.stringify(t,null," ");throw TypeError("deref only accepts Atom instances, but got:\n"+n)},t.swap=u,t.set=function(t,n){u(t,function(){return n})},Object.defineProperty(t,"__esModule",{value:!0})});
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t["@libre/atom"]={})}(this,function(t){"use strict";var i=0,r=Object.create(null),e=Object.create(null);function a(t){return r[t.$$id]}function u(t,n){r[t.$$id]=n}function d(t){return e[t.$$id]}function f(t,n){e[t.$$id]=n}var n="Expected an Atom instances, but got:";function c(t){return JSON.stringify(t,null," ")}function s(t){if(!(t instanceof o))throw TypeError(n+"\n\n"+c(t))}var o=function(){function r(t,n){var r=(void 0===n?{}:n).validator;if((r=r||function(){return!0})(t))return Object.defineProperty(this,"$$id",{value:i++}),u(this,t),f(this,r),this;var e="Atom initialized with invalid state:\n\n"+c(t)+"\n\naccording to validator function:\n"+r+"\n\n",o=Error(e);throw o.name="AtomInvalidStateError",o}return r.of=function(t,n){return new r(t,n)},r.prototype.toString=function(){return"Atom<"+c(a(this))+">"},r.prototype.inspect=function(){return this.toString()},r}();t.Atom=o,t.deref=function(t){return s(t),a(t)},t.getValidator=function(t){return s(t),d(t)},t.set=function(t,n){s(t);var r=d(t);if(!r(n)){var e="Attempted to set the state of\n\n"+t+"\n\nwith:\n\n"+c(n)+"\n\nbut it did not pass validator:\n"+r+"\n\n",o=Error(e);throw o.name="AtomInvalidStateError",o}u(t,n)},t.setValidator=function(t,n){if(s(t),!n(a(t))){var r=Error("Could not set validator on\n\n"+t+"\n\nbecause current state would be invalid according to new validator:\n"+n+"\n\n");throw r.name="AtomInvalidStateError",r}f(t,n)},t.swap=function(t,n){s(t);var r=n(a(t)),e=d(t);if(!e(r)){var o="swap updateFn\n"+n+"\n\nattempted to swap the state of\n\n"+t+"\n\nwith:\n\n"+c(r)+"\n\nbut it did not pass validator:\n"+e+"\n\n",i=Error(o);throw i.name="AtomInvalidStateError",i}u(t,r)},Object.defineProperty(t,"__esModule",{value:!0})});
//# sourceMappingURL=index.umd.js.map

@@ -1,12 +0,5 @@

import { DeepImmutable } from "./internal-types";
/** @ignore */
export declare function getState<S>(atom: Atom<S>): DeepImmutable<S>;
import { AtomConstructorOptions } from "./internal-types";
/**
* `@libre/atom` provides a data type called `Atom` and a few functions for working with `Atom`s.
* It is heavily inspired by `atom`s in Clojure(Script).
*
* Atoms provide a predictable way to manage state that is shared by multiple components of a
* program as that state changes over time. They are particularly useful in the functional and reactive
* programming paradigms, where most components of a program are pure functions operating on
* immutable data. In this context, Atoms provide a form of mutability that is controlled in such
* A data structure useful for providing a controlled, predictable mechanism for mutability.
* Allows multiple components of a program to share read/write access to some state in such
* a way that no component can mutate another component's current reference to the state in

@@ -32,3 +25,3 @@ * the middle of some process or asynchronous operation.

*/
static of<S>(state: S): Atom<S>;
static of<S>(state: S, options?: AtomConstructorOptions<S>): Atom<S>;
/** @ignore */

@@ -43,58 +36,1 @@ readonly ["$$id"]: number;

}
/**
* Reads (i.e. "*dereferences*") the current state of an [[Atom]]. The dereferenced value
* should ___not___ be mutated.
*
* @param <S> the type of `atom`'s inner state
*
* @example
```js
import {Atom, deref} from '@libre/atom'
const stateAtom = Atom.of({ count: 0 })
deref(stateAtom) // => { count: 0 }
```
*/
export declare function deref<S>(atom: Atom<S>): DeepImmutable<S>;
/**
* Swaps `atom`'s state with the value returned from applying `updateFn` to `atom`'s
* current state. `updateFn` should be a pure function and ___not___ mutate `state`.
*
* @param atom an instance of [[Atom]]
* @param updateFn a pure function that takes the current state and returns the next state; the next state should be of the same type/interface as the current state;
*
* @example
* ```jsx
*
*import {Atom, swap} from '@libre/atom'
*
*const stateAtom = Atom.of({ count: 0 })
*const increment = () => swap(stateAtom, (state) => ({
* count: state.count + 1
*}));
* ```
*/
export declare function swap<S>(atom: Atom<S>, updateFn: (state: DeepImmutable<S>) => S): void;
/**
* Sets `atom`s state to `nextState`.
*
* It is equivalent to `swap(atom, () => newState)`.
*
* @param atom an instance of [[Atom]]
* @param nextState the value to which to set the state; it should be the same type/interface as current state
*
* @example
```js
import {Atom, useAtom, set} from '@libre/atom'
import { DeepImmutable } from './internal-types';
const atom = Atom.of({ count: 0 })
set(atom, { count: 100 })
deref(atom) // => { count: 100 }
```
*/
export declare function set<S>(atom: Atom<S>, nextState: S): void;
/** @ignore */
export declare const derefArgMustBeAtom = "deref only accepts Atom instances, but got:";
export declare const expectedAtomButGot = "Expected an Atom instances, but got:";

@@ -1,2 +0,7 @@

export { Atom, deref, swap, set } from "./atom";
export { Atom } from "./atom";
export { AtomState } from "./internal-types";
export { deref } from "./deref";
export { getValidator } from "./getValidator";
export { set } from "./set";
export { setValidator } from "./setValidator";
export { swap } from "./swap";
import { Atom } from "./atom";
/**
* Optional paramaters accepted by [[Atom.of]]
*
* @param <S> the type of the [[Atom]]'s inner state
*/
export interface AtomConstructorOptions<S> {
/**
* Validates the next state of an [[Atom]] during [[Atom.of]], [[swap]],
* and [[set]]. It should either return a `boolean` or throw an error. If it
* returns `false`, then an Error is thrown and the new state is not committed.
*
* @default `() => true`
*/
validator?(state: DeepImmutable<S>): boolean;
}
/**
* Extracts the type info of an [[Atom]]'s inner state

@@ -4,0 +19,0 @@ *

@@ -91,3 +91,3 @@ {

"unpkg": "https://unpkg.com/@libre/atom",
"version": "1.0.2"
"version": "1.1.0"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc