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

@domonda/plumb

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@domonda/plumb - npm Package Compare versions

Comparing version 1.0.0 to 2.0.0

130

createPlumb.js

@@ -8,12 +8,15 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const equality_1 = require("./equality");
function createPlumb(initialState, props = {}) {
const { handler } = props;
const { transformer, skipInitialTransform } = props;
let disposeHandlers = [];
let disposed = false;
let internalState = initialState;
// when the piped plumb triggers next it internally handles
if (transformer && !skipInitialTransform) {
internalState = transformer(internalState);
}
// when the chained plumb triggers next it internally transforms
// the value before sending it to next, this flag is used to
// skip re-handling the value
let skipHandler = null;
const handlers = [];
// skip transforming the value twice
let skipTransformer = null;
const transformers = [];
const subscribers = [];

@@ -27,3 +30,3 @@ function subscribe(subscriber) {

dispose: () => {
subscribers.splice(subscribers.indexOf(subscriber));
subscribers.splice(subscribers.indexOf(subscriber), 1);
},

@@ -37,11 +40,11 @@ };

internalState = state;
// first do all extra handlers
for (const handler of handlers) {
if (handler !== skipHandler) {
internalState = handler(internalState);
// first do all extra transformers
for (const transformer of transformers) {
if (transformer !== skipTransformer) {
internalState = transformer(internalState);
}
}
// then do main handler
if (handler) {
internalState = handler(internalState);
// then do main transformer
if (transformer) {
internalState = transformer(internalState);
}

@@ -57,29 +60,49 @@ for (const subscriber of subscribers) {

}
function pipe(props) {
function chain(props) {
if (disposed) {
throw new Error('cannot pipe a disposed plumb');
throw new Error('cannot chain a disposed plumb');
}
const { selector, updater, filter = () => true } = props;
function pipeHandler(state) {
return updater(state, selector(state));
const { selector, updater, filter = () => true, transformer: chainTransformer, skipInitialTransform: chainSkipInitialTransform, } = props;
const memoData = {
state: internalState,
selectedState: selector(internalState),
};
function memoSelector(state) {
if (memoData.state !== state) {
memoData.state = state;
memoData.selectedState = selector(memoData.state);
}
return memoData.selectedState;
}
const nextState = pipeHandler(internalState);
if (!equality_1.shallowEqual(internalState, nextState)) {
next(nextState);
function parentTransformer(state) {
let selectedState = memoSelector(state);
if (chainTransformer) {
selectedState = chainTransformer(selectedState);
}
return updater(state, selectedState);
}
handlers.push(pipeHandler);
let selectedState = selector(internalState);
let outside = false; // next is triggered by the parent plumb
let inside = false; // next is triggered on the piped plump
const piped = createPlumb(selectedState, {
handler: (selectedState) => {
if (!outside) {
transformers.push(parentTransformer);
let isInitialTransform = true;
let parentNext = false; // next is triggered by the parent plumb
let chainedNext = false; // next is triggered on the chained/child plump
const chained = createPlumb(memoSelector(internalState), {
transformer: (selectedState) => {
if (chainTransformer) {
if (chainSkipInitialTransform && isInitialTransform) {
// skip initial transform
}
else {
selectedState = chainTransformer(selectedState);
}
}
isInitialTransform = false;
if (!parentNext) {
const nextState = updater(internalState, selectedState);
if (!equality_1.shallowEqual(internalState, nextState)) {
inside = true;
skipHandler = pipeHandler;
if (internalState !== nextState) {
chainedNext = true;
skipTransformer = parentTransformer;
next(nextState);
skipHandler = null;
inside = false;
return selector(internalState);
skipTransformer = null;
chainedNext = false;
return memoSelector(internalState);
}

@@ -91,18 +114,29 @@ }

const subscription = subscribe((state) => {
if (!inside) {
selectedState = selector(state);
if (!chainedNext) {
const selectedState = memoSelector(state);
if (filter(selectedState)) {
outside = true;
piped.next(selectedState);
outside = false;
parentNext = true;
chained.next(selectedState);
parentNext = false;
}
}
});
piped.subscribe({
// indicates that dispose was called from the parent
let parentDispose = false;
function chainedDispose() {
parentDispose = true;
chained.dispose();
}
disposeHandlers.push(chainedDispose);
chained.subscribe({
dispose: () => {
subscription.dispose();
handlers.splice(handlers.indexOf(pipeHandler));
// when parent disposals happen, the transformers will get deleted by the parent
if (!parentDispose) {
transformers.splice(transformers.indexOf(parentTransformer), 1);
disposeHandlers.splice(disposeHandlers.indexOf(chainedDispose), 1);
}
},
});
return piped;
return chained;
}

@@ -119,2 +153,7 @@ function dispose() {

subscribers.splice(0, subscribers.length);
transformers.splice(0, transformers.length);
for (const disposeHandler of disposeHandlers) {
disposeHandler();
}
disposeHandlers.splice(0, disposeHandlers.length);
internalState = undefined;

@@ -136,5 +175,8 @@ disposed = true;

},
get disposed() {
return disposed;
},
next,
subscribe,
pipe,
chain,
dispose,

@@ -141,0 +183,0 @@ };

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

export * from './Plumb';
export * from './createPlumb';
export * from './equality';
{
"name": "@domonda/plumb",
"version": "1.0.0",
"version": "2.0.0",
"description": "Simple state management inspired by Observables.",

@@ -23,5 +23,4 @@ "keywords": [

},
"dependencies": {},
"main": "index.js",
"typings": "index.d.ts"
}

@@ -14,8 +14,7 @@ /**

export declare type Subscription = Disposable;
export declare type Handler<T> = (state: Readonly<T>) => T;
export declare type Transformer<T> = (state: Readonly<T>) => T;
export declare type Filter<T> = (state: T) => boolean;
export declare type Next<T> = (state: T) => void;
export declare type Selector<T, K> = (state: Readonly<T>) => K;
export declare type Updater<T, K> = (state: Readonly<T>, selectedState: Readonly<K>) => T;
export interface PipeProps<T, K> {
export interface ChainProps<T, K> extends PlumbProps<K> {
selector: Selector<T, K>;

@@ -26,4 +25,4 @@ updater: Updater<T, K>;

export interface PlumbProps<T> {
handler?: Handler<T>;
next?: Next<T>;
transformer?: Transformer<T>;
skipInitialTransform?: boolean;
}

@@ -33,5 +32,6 @@ export interface Plumb<T> extends Disposable {

readonly subscribers: Subscriber<T>[];
pipe: <K>(props: PipeProps<T, K>) => Plumb<K>;
next: Next<T>;
readonly disposed: boolean;
chain: <K>(props: ChainProps<T, K>) => Plumb<K>;
next: (state: T) => void;
subscribe: (subscriber: Subscriber<T>) => Subscription;
}
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