Skip to content

Commit 1f5de53

Browse files
Rename modifiers to preprocessors
1 parent 5ca5c51 commit 1f5de53

File tree

2 files changed

+27
-61
lines changed

2 files changed

+27
-61
lines changed

src/store.ts

Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ export type Patch<T> = (value: T) => T;
22
export type ValueOrPatch<T> = T | Patch<T>;
33
export type Handler<T> = (nextValue: T, previousValue: T | undefined) => void;
44
export type Unsubscribe = () => void;
5-
6-
export type Unregister = Unsubscribe;
7-
export type Modifier<T> = Handler<T>;
5+
// aliases
6+
export type RemovePreprocessor = Unsubscribe;
7+
export type Preprocessor<T> = Handler<T>;
88

99
export const isPatch = <T>(value: ValueOrPatch<T>): value is Patch<T> =>
1010
typeof value === 'function';
@@ -14,12 +14,14 @@ const noop = () => {};
1414

1515
export class StateStore<T extends Record<string, unknown>> {
1616
protected handlers = new Set<Handler<T>>();
17-
protected modifiers = new Set<Handler<T>>();
17+
protected preprocessors = new Set<Preprocessor<T>>();
1818

1919
constructor(protected value: T) {}
2020

2121
/**
2222
* Allows merging two stores only if their keys differ otherwise there's no way to ensure the data type stability.
23+
* @experimental
24+
* This method is experimental and may change in future versions.
2325
*/
2426
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2527
public merge<Q extends StateStore<any>>(
@@ -44,7 +46,7 @@ export class StateStore<T extends Record<string, unknown>> {
4446
// do not notify subscribers if the value hasn't changed
4547
if (newValue === this.value) return;
4648

47-
this.modifiers.forEach((modifier) => modifier(newValue, this.value));
49+
this.preprocessors.forEach((preprocessor) => preprocessor(newValue, this.value));
4850

4951
const oldValue = this.value;
5052
this.value = newValue;
@@ -104,17 +106,17 @@ export class StateStore<T extends Record<string, unknown>> {
104106
};
105107

106108
/**
107-
* Registers a modifier function that will be called before the state is updated.
109+
* Registers a preprocessor function that will be called before the state is updated.
108110
*
109-
* Modifiers are invoked with the new and previous values whenever `next` or `partialNext`
110-
* is called, allowing you to mutate or react to the new value before it is set. Modifiers run in the
111+
* Preprocessors are invoked with the new and previous values whenever `next` or `partialNext` methods
112+
* are called, allowing you to mutate or react to the new value before it is set. Preprocessors run in the
111113
* order they were registered.
112114
*
113115
* @example
114116
* ```ts
115117
* const store = new StateStore<{ count: number; isMaxValue: bool; }>({ count: 0, isMaxValue: false });
116118
*
117-
* store.registerModifier((nextValue, prevValue) => {
119+
* store.addPreprocessor((nextValue, prevValue) => {
118120
* if (nextValue.count > 10) {
119121
* nextValue.count = 10; // Clamp the value to a maximum of 10
120122
* }
@@ -135,14 +137,14 @@ export class StateStore<T extends Record<string, unknown>> {
135137
* store.getLatestValue(); // { count: 5, isMaxValue: false }
136138
* ```
137139
*
138-
* @param modifier - The function to be called with the next and previous values before the state is updated.
139-
* @returns An `Unregister` function that removes the modifier when called.
140+
* @param preprocessor - The function to be called with the next and previous values before the state is updated.
141+
* @returns A `RemovePreprocessor` function that removes the preprocessor when called.
140142
*/
141-
public registerModifier(modifier: Modifier<T>): Unregister {
142-
this.modifiers.add(modifier);
143+
public addPreprocessor(preprocessor: Preprocessor<T>): RemovePreprocessor {
144+
this.preprocessors.add(preprocessor);
143145

144146
return () => {
145-
this.modifiers.delete(modifier);
147+
this.preprocessors.delete(preprocessor);
146148
};
147149
}
148150
}
@@ -154,7 +156,7 @@ export class StateStore<T extends Record<string, unknown>> {
154156
* It extends StateStore with the combined type of both source stores.
155157
* Changes to either the original or merged store will propagate to the combined store.
156158
*
157-
* Note: Direct mutations (next, partialNext, registerModifier) are disabled on the merged store.
159+
* Note: Direct mutations (next, partialNext, addPreprocessor) are disabled on the merged store.
158160
* You should instead call these methods on the original or merged stores.
159161
*
160162
* @template O The type of the original state store
@@ -292,46 +294,10 @@ export class MergedStateStore<
292294
`${MergedStateStore.name}.partialNext is disabled, call original.partialNext or merged.partialNext instead`,
293295
);
294296
};
295-
public registerModifier() {
297+
public addPreprocessor() {
296298
console.warn(
297-
`${MergedStateStore.name}.registerModifier is disabled, call original.registerModifier or merged.registerModifier instead`,
299+
`${MergedStateStore.name}.addPreprocessor is disabled, call original.addPreprocessor or merged.addPreprocessor instead`,
298300
);
299301
return noop;
300302
}
301303
}
302-
303-
/** EXAMPLE:
304-
const Uninitialized = Symbol('uninitialized');
305-
306-
const b = new StateStore<{
307-
previous: string | null | symbol;
308-
hasPrevious: boolean | symbol;
309-
}>({
310-
previous: Uninitialized,
311-
hasPrevious: Uninitialized,
312-
});
313-
314-
const a = new StateStore<{
315-
hasNext: boolean | symbol;
316-
next: string | null | symbol;
317-
}>({
318-
next: Uninitialized,
319-
hasNext: Uninitialized,
320-
}).merge(b);
321-
322-
a.original.registerModifier((nextValue) => {
323-
if (typeof nextValue.next === 'string') {
324-
nextValue.hasNext = true;
325-
} else if (nextValue.next === Uninitialized) {
326-
nextValue.hasNext = Uninitialized;
327-
} else {
328-
nextValue.hasNext = false;
329-
}
330-
});
331-
332-
a.subscribe((ns) => console.log(ns));
333-
334-
a.original.partialNext({ next: 'next' });
335-
a.original.partialNext({ next: null });
336-
a.original.partialNext({ next: Uninitialized });
337-
*/

test/unit/store.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ describe('StateStore', () => {
6565
expect(handler).toHaveBeenCalledWith({ count: 42 }, { count: 0 });
6666
});
6767

68-
it('should support registerModifier', () => {
68+
it('should support addPreprocessor', () => {
6969
const handler = vi.fn();
7070
store.subscribe(handler);
7171

72-
store.registerModifier((next) => {
72+
store.addPreprocessor((next) => {
7373
if (next.count > 5) next.count = 5;
7474
});
7575

@@ -78,18 +78,18 @@ describe('StateStore', () => {
7878
expect(store.getLatestValue().count).toBe(5);
7979
});
8080

81-
it('should not call modifiers if value does not change', () => {
81+
it('should not call preprocessors if value does not change', () => {
8282
const mod = vi.fn();
8383

84-
store.registerModifier(mod);
84+
store.addPreprocessor(mod);
8585
store.next(store.getLatestValue());
8686

8787
expect(mod).not.toHaveBeenCalled();
8888
});
8989

90-
it('should allow unregistering modifiers', () => {
90+
it('should allow unregistering preprocessors', () => {
9191
const mod = vi.fn();
92-
const unregister = store.registerModifier(mod);
92+
const unregister = store.addPreprocessor(mod);
9393
unregister();
9494
store.partialNext({ count: 2 });
9595
expect(mod).not.toHaveBeenCalled();
@@ -135,14 +135,14 @@ describe('MergedStateStore', () => {
135135
expect(handler).toHaveBeenCalledWith({ a: 3, b: 'z' }, { a: 3, b: 'x' });
136136
});
137137

138-
it('should not allow direct mutation via next/partialNext/registerModifier', () => {
138+
it('should not allow direct mutation via next/partialNext/addPreprocessor', () => {
139139
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
140140
// @ts-expect-error testing purposes
141141
merged.next({ a: 5, b: 'q' });
142142
// @ts-expect-error testing purposes
143143
merged.partialNext({ a: 5 });
144144
// @ts-expect-error testing purposes
145-
merged.registerModifier(() => {});
145+
merged.addPreprocessor(() => {});
146146
expect(warn).toHaveBeenCalledTimes(3);
147147
warn.mockRestore();
148148
});

0 commit comments

Comments
 (0)