Skip to content

Commit 7de3c35

Browse files
committed
Add a memory storage provider
1 parent 588712b commit 7de3c35

6 files changed

Lines changed: 64 additions & 0 deletions

File tree

packages/docs/utils/storage/providers.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Storage providers are the low-level adapters that read and write to a specific s
77
| Provider | Backend | Sync event |
88
| ------------------------------- | --------------------------- | --------------------- |
99
| `localStorageProvider` | `globalThis.localStorage` | `storage` (cross-tab) |
10+
| `memoryStorageProvider` | in-memory `Map` | none |
1011
| `sessionStorageProvider` | `globalThis.sessionStorage` | none |
1112
| `urlSearchParamsProvider` | URL search params | `popstate` |
1213
| `urlSearchParamsInHashProvider` | URL hash params | `hashchange` |
@@ -19,6 +20,7 @@ All built-in providers also have factory functions:
1920

2021
- `createNoopProvider()`
2122
- `createLocalStorageProvider()`
23+
- `createMemoryStorageProvider()`
2224
- `createSessionStorageProvider()`
2325
- `createUrlSearchParamsProvider(options?)`
2426
- `createUrlSearchParamsInHashProvider(options?)`
@@ -31,6 +33,7 @@ The URL-based factories accept a `push` option to customize navigation behavior.
3133
// @twoslash-cache: {"v":1,"hash":"90ef5b3acd98c5ace6e14b8466f5416ce19de7d1fba0875819c96dfe5a9a7b0b","data":"N4Igdg9gJgpgziAXAbVAFwJ4AcZJACwgDcYAnEAGhDRgA808AKAQwBsBLZuASgAIAzAK5gAxmnYQwvEaRjMaAVVKsAynNIj8ABWalmAWzhbSxdrFKMsJombIB5LOMlwA/Il5LWx0+YdOwPO4qaBB6AOYw3jbmADpg7PpYoWjSsvIwnmq6mjp6hlG25FRQECIIiCAAwmk0vMweAEoAMlka2roGcLxWPmQAdJTUzGHlyMggWB36gz3R9o4SAbx+i138obxo+DDd1oUDALoU47JogqQBlGCCrKwHRyBwaLoMiACMb1SsMGBhW0gAJgAnFRnqQIq8QDI5IplK0clMjHtzIMOGBcO8qJoOmIyICAL4UdDYDEEYh40F0SEsDhcPhCUT+VIwjJw9QIvJwACSYAAElxtMiyJYhaQVs43B5lAVfAtnNwgiFwpFRXEEklSCloelMuz2pyefy4ILekUQCUynhqiy6o0Wnrcp1eOwpPgBbtTQNQcNRuNJnkZqLxUtg2sNlsdrN9iAjicYGcLggKNdbvcqE8XkgACxZr4/P74JAAZgArN7wfG8NrYaoHYjDQKZRSQGiMQCsW69LjyIgAYTiTg8IQSGaaPQq84UlhBMam6RFaFhirTQAeJ6kF1hAB8gwzmqQbwAHJ8W/n/u920MK5Dp7PRaiXRiAGwdnE0HtP/vUElD8mjqlMGwnA8MyOpstk+qdHOIqmqGkqeHOoYKrwwSLhEc5qokySgTW8KQfk97FKU5RVDUOz1AozR4Y6hgenMpBekMIxIGMExTIGsFyiGXFhqQmzbHR0axiApznJcyY3HcDx7q8bxAi+p6/OewLlhCVZkbqEE0UipoPuiSAKdiXbvoCbxfpgg4VMOzZjtSPQ4JqGB8AhQY8X0t74JKABGEAQN8zBSAAPrwwiwPwj5QIMFokQA6tsEZ8SEIVwDsAAGHnBOkqXOgENDMFAvAQPwvCpbIWCsMwIgwJlNCpYxzzMSg4xhcwNwMFQ/BsClMbSWCrwAgCh55kphaILmV5qRUHl6c+r7GXiiAlkW5k/lZf6DLZE65d0M74EaJr0QuypzmuaAbr8O7pn1gJZiCikFgeClgpNEy7ftc4zUgADsc2VSZiCfkS36WWSI4bQBFQ0sBfDVqytZafWfKNqKMH0XB7guZx/iBChSpLhh8RYZqOFw9RiPvYR5rEVaZG2pR9oI5yOW8G6xqCeY9U+ixfrsVQUaytjyw8QI4YCfz/QxscInxmJSYplJV2Zr2T5Dfd56lqplYVLDmltNpDZ3rpXyPt9v3doCJYrSD1n/uOkP2WQmDOdKrnY+5u3eb5/lBSFYBhRFUXUxUcXxtsiUQMlaUZc8tU5U8cgFUVJVlRVVU1TAdUbVzTXmjAnVtYMnWsN1aaPNdiBFgADAp3wjdmms3rtn2ID9UKdn9C1PstDwiNApLqthwBxLwJO6xyUGihQw+j+Bevk8jppT2A+ICCY+i8AA5AAAk8ghQBI+jxswAD0ABWcAALQhH5ADW7BoMfgjiMXG8ANxxHEx/Hx4KVdNH6RxzyonYqEZeAtTarwFOlVqoxxgHEXu20PJzl4AAXhnvDOenJoLAB2sadwZ1BA7HxNwd+ohJy4L2gveiqD0FkwNEjQ29FGA4I8vg0ghDeDENfoMQ+zwkCgCpD8OAiw8DnxAPifEQA=="}
3234
import {
3335
createLocalStorageProvider,
36+
createMemoryStorageProvider,
3437
createNoopProvider,
3538
createSessionStorageProvider,
3639
createUrlSearchParamsProvider,
@@ -39,6 +42,7 @@ import {
3942

4043
const noopProvider = createNoopProvider();
4144
const localProvider = createLocalStorageProvider();
45+
const memoryProvider = createMemoryStorageProvider();
4246
const sessionProvider = createSessionStorageProvider();
4347

4448
// Uses pushState instead of the default replaceState
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { StorageProvider } from './types.js';
2+
3+
export function createMemoryStorageProvider(): StorageProvider {
4+
const map = new Map<string, string>();
5+
6+
return {
7+
get(key) {
8+
return map.get(key) ?? null;
9+
},
10+
set(key, value) {
11+
map.set(key, value);
12+
},
13+
remove(key) {
14+
map.delete(key);
15+
},
16+
has(key) {
17+
return map.has(key);
18+
},
19+
keys() {
20+
return [...map.keys()];
21+
},
22+
clear() {
23+
map.clear();
24+
},
25+
};
26+
}

packages/js-toolkit/utils/storage/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ export type {
88

99
export {
1010
createLocalStorageProvider,
11+
createMemoryStorageProvider,
1112
createNoopProvider,
1213
createSessionStorageProvider,
1314
createUrlSearchParamsInHashProvider,
1415
createUrlSearchParamsProvider,
1516
localStorageProvider,
17+
memoryStorageProvider,
1618
sessionStorageProvider,
1719
urlSearchParamsInHashProvider,
1820
urlSearchParamsProvider,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import { createLocalStorageProvider } from './createLocalStorageProvider.js';
2+
import { createMemoryStorageProvider } from './createMemoryStorageProvider.js';
23
import { createSessionStorageProvider } from './createSessionStorageProvider.js';
34
import { createUrlSearchParamsInHashProvider } from './createUrlSearchParamsInHashProvider.js';
45
import { createUrlSearchParamsProvider } from './createUrlSearchParamsProvider.js';
56

67
export { createLocalStorageProvider } from './createLocalStorageProvider.js';
8+
export { createMemoryStorageProvider } from './createMemoryStorageProvider.js';
79
export { createNoopProvider } from './createNoopProvider.js';
810
export { createSessionStorageProvider } from './createSessionStorageProvider.js';
911
export { createUrlSearchParamsInHashProvider } from './createUrlSearchParamsInHashProvider.js';
1012
export { createUrlSearchParamsProvider } from './createUrlSearchParamsProvider.js';
1113

1214
export const localStorageProvider = createLocalStorageProvider();
15+
export const memoryStorageProvider = createMemoryStorageProvider();
1316
export const sessionStorageProvider = createSessionStorageProvider();
1417
export const urlSearchParamsProvider = createUrlSearchParamsProvider();
1518
export const urlSearchParamsInHashProvider = createUrlSearchParamsInHashProvider();

packages/tests/utils/index.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ describe('@studiometa/js-toolkit/utils exports', () => {
2525
"createElement",
2626
"createLocalStorage",
2727
"createLocalStorageProvider",
28+
"createMemoryStorageProvider",
2829
"createNoopProvider",
2930
"createRange",
3031
"createSessionStorage",
@@ -95,6 +96,7 @@ describe('@studiometa/js-toolkit/utils exports', () => {
9596
"mean",
9697
"memo",
9798
"memoize",
99+
"memoryStorageProvider",
98100
"nextFrame",
99101
"nextMicrotask",
100102
"nextTick",

packages/tests/utils/storage.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
22
import {
33
createLocalStorage,
4+
createMemoryStorageProvider,
45
createSessionStorage,
56
createUrlSearchParamsStorage,
67
createUrlSearchParamsInHashStorage,
78
createStorage,
89
createUrlSearchParamsProvider,
910
createUrlSearchParamsInHashProvider,
1011
localStorageProvider,
12+
memoryStorageProvider,
1113
sessionStorageProvider,
1214
urlSearchParamsProvider,
1315
urlSearchParamsInHashProvider,
@@ -512,6 +514,31 @@ describe('Storage utilities', () => {
512514
expect(sessionStorageProvider.syncEvent).toBeUndefined();
513515
});
514516

517+
it('should handle memoryStorage provider correctly', () => {
518+
expect(memoryStorageProvider.get('non-existent')).toBeNull();
519+
memoryStorageProvider.set('test', 'value');
520+
expect(memoryStorageProvider.get('test')).toBe('value');
521+
expect(memoryStorageProvider.has('test')).toBe(true);
522+
expect(memoryStorageProvider.keys()).toEqual(['test']);
523+
memoryStorageProvider.remove('test');
524+
expect(memoryStorageProvider.has('test')).toBe(false);
525+
});
526+
527+
it('should create isolated memory storage providers', () => {
528+
const providerA = createMemoryStorageProvider();
529+
const providerB = createMemoryStorageProvider();
530+
531+
providerA.set('test', 'a');
532+
providerB.set('test', 'b');
533+
534+
expect(providerA.get('test')).toBe('a');
535+
expect(providerB.get('test')).toBe('b');
536+
537+
providerA.clear();
538+
expect(providerA.keys()).toEqual([]);
539+
expect(providerB.keys()).toEqual(['test']);
540+
});
541+
515542
it('should handle urlSearchParams provider correctly', () => {
516543
window.history.replaceState({}, '', '/');
517544
expect(urlSearchParamsProvider.get('non-existent')).toBeNull();

0 commit comments

Comments
 (0)