Skip to content

Commit ae8f8a3

Browse files
committed
Moving getPath into store methods
1 parent 7d2ec60 commit ae8f8a3

5 files changed

Lines changed: 126 additions & 138 deletions

File tree

deep-map/deepmap.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect } from 'vitest'
2-
import { deepMap, getKey } from './deepmap.js'
2+
import { deepMap } from './deepmap.js'
33
import { setPath, getPath, normalizePath } from './path.js'
44

55
type Obj1 = {
@@ -154,6 +154,6 @@ describe('setPath', () => {
154154
describe('getKey', () => {
155155
it('Should get a value from store', () => {
156156
const $storeObj1 = deepMap<Obj1>({ c: 'initial' })
157-
expect(getKey($storeObj1, 'c')).toBe('initial')
157+
expect($storeObj1.getKey('c')).toBe('initial')
158158
})
159159
})

deep-map/deepmap.ts

Lines changed: 102 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,107 @@
1-
import { atom } from 'nanostores'
2-
import type { AnyStore, WritableAtom } from 'nanostores';
3-
import type { AllPaths, BaseDeepMap, FromPath, FromPathWithIndexSignatureUndefined } from './path.types.js';
4-
import { getPath, isObject, setPath } from './path.js';
1+
import { atom } from "nanostores";
2+
import type { WritableAtom } from "nanostores";
3+
import type {
4+
AllPaths,
5+
BaseDeepMap,
6+
FromPath,
7+
FromPathWithIndexSignatureUndefined,
8+
} from "./path.types.js";
9+
import { getPath, isObject, setPath } from "./path.js";
510

611
export type DeepMapStore<T extends BaseDeepMap> = {
7-
value: T
12+
value: T;
813

914
/**
10-
* Subscribe to store changes.
11-
*
12-
* In contrast with {@link Store#subscribe} it do not call listener
13-
* immediately.
14-
*
15-
* @param listener Callback with store value and old value.
16-
* @param changedKey Key that was changed. Will present only if `setKey`
17-
* has been used to change a store.
18-
* @returns Function to remove listener.
19-
*/
15+
* Subscribe to store changes.
16+
*
17+
* In contrast with {@link Store#subscribe} it do not call listener
18+
* immediately.
19+
*
20+
* @param listener Callback with store value and old value.
21+
* @param changedKey Key that was changed. Will present only if `setKey`
22+
* has been used to change a store.
23+
* @returns Function to remove listener.
24+
*/
2025
listen(
2126
listener: (
2227
value: T,
2328
oldValue: T,
24-
changedKey: AllPaths<T> | undefined
25-
) => void
26-
): () => void
29+
changedKey: AllPaths<T> | undefined,
30+
) => void,
31+
): () => void;
2732

2833
/**
29-
* Low-level method to notify listeners about changes in the store.
30-
*
31-
* Can cause unexpected behaviour when combined with frontend frameworks
32-
* doing equality checks for values, e.g. React.
33-
*/
34-
notify(oldValue?: T, changedKey?: AllPaths<T>): void
34+
* Low-level method to notify listeners about changes in the store.
35+
*
36+
* Can cause unexpected behaviour when combined with frontend frameworks
37+
* doing equality checks for values, e.g. React.
38+
*/
39+
notify(oldValue?: T, changedKey?: AllPaths<T>): void;
40+
41+
getKey: <K extends AllPaths<T> | "">(key: K) => FromPath<T, K>;
3542

3643
/**
37-
* Change key in store value. Copies are made at each level of `key` so that
38-
* no part of the original object is mutated.
39-
*
40-
* ```js
41-
* $settings.setKey('visuals.theme', 'dark')
42-
* ```
43-
*
44-
* @param key The key name. Attributes can be split with a dot `.` and `[]`.
45-
* @param value New value.
46-
*/
47-
setKey: <K extends AllPaths<T> | ''>(
44+
* Change key in store value. Copies are made at each level of `key` so that
45+
* no part of the original object is mutated.
46+
*
47+
* ```js
48+
* $settings.setKey('visuals.theme', 'dark')
49+
* ```
50+
*
51+
* @param key The key name. Attributes can be split with a dot `.` and `[]`.
52+
* @param value New value.
53+
*/
54+
setKey: <K extends AllPaths<T> | "">(
4855
key: K,
49-
value: FromPathWithIndexSignatureUndefined<T, K> | undefined
50-
) => void
56+
value: FromPathWithIndexSignatureUndefined<T, K> | undefined,
57+
) => void;
5158

5259
/**
53-
* Change key in store value. Copies are made at each level of `key` so that
54-
* no part of the original object is mutated.
55-
*
56-
* ```js
57-
* $settings.updateKey('settings', { theme: 'dark' })
58-
* ```
59-
*
60-
* @param key The key name. Attributes can be split with a dot `.` and `[]`.
61-
* @param value New value.
62-
*/
63-
updateKey: <K extends AllPaths<T> | ''>(
60+
* Change store value.
61+
* @param newValue — Update store value.
62+
*/
63+
update: (value: Partial<T> | undefined) => void;
64+
65+
/**
66+
* Change key in store value. Copies are made at each level of `key` so that
67+
* no part of the original object is mutated.
68+
*
69+
* ```js
70+
* $settings.updateKey('settings', { theme: 'dark' })
71+
* ```
72+
*
73+
* @param key The key name. Attributes can be split with a dot `.` and `[]`.
74+
* @param value New value.
75+
*/
76+
updateKey: <K extends AllPaths<T> | "">(
6477
key: K,
65-
value: Partial<FromPathWithIndexSignatureUndefined<T, K>> | undefined
66-
) => void
78+
value: Partial<FromPathWithIndexSignatureUndefined<T, K>> | undefined,
79+
) => void;
6780

6881
/**
69-
* Subscribe to store changes and call listener immediately.
70-
*
71-
* ```
72-
* import { $settings } from '../store'
73-
*
74-
* $settings.subscribe(settings => {
75-
* console.log(settings)
76-
* })
77-
* ```
78-
*
79-
* @param listener Callback with store value and old value.
80-
* @param changedKey Key that was changed. Will present only
81-
* if `setKey` has been used to change a store.
82-
* @returns Function to remove listener.
83-
*/
82+
* Subscribe to store changes and call listener immediately.
83+
*
84+
* ```
85+
* import { $settings } from '../store'
86+
*
87+
* $settings.subscribe(settings => {
88+
* console.log(settings)
89+
* })
90+
* ```
91+
*
92+
* @param listener Callback with store value and old value.
93+
* @param changedKey Key that was changed. Will present only
94+
* if `setKey` has been used to change a store.
95+
* @returns Function to remove listener.
96+
*/
8497
subscribe(
8598
listener: (
8699
value: T,
87100
oldValue: T | undefined,
88-
changedKey: AllPaths<T> | undefined
89-
) => void
90-
): () => void
91-
} & Omit<WritableAtom<T>, 'listen' | 'notify' | 'setKey' | 'subscribe'>
101+
changedKey: AllPaths<T> | undefined,
102+
) => void,
103+
): () => void;
104+
} & Omit<WritableAtom<T>, "listen" | "notify" | "setKey" | "subscribe">;
92105

93106
/**
94107
* Create deep map store. Deep map store is a store with an object as store
@@ -98,66 +111,42 @@ export type DeepMapStore<T extends BaseDeepMap> = {
98111
* @returns The store object with methods to subscribe.
99112
*/
100113
export function deepMap<T extends BaseDeepMap>(init?: T): DeepMapStore<T> {
101-
const $deepmap = atom(init) as DeepMapStore<T>
114+
const $deepmap = atom(init) as DeepMapStore<T>;
102115

103-
$deepmap.setKey = <K extends AllPaths<T> | ''>(
116+
$deepmap.getKey = <K extends AllPaths<T> | "">(key: K): any => {
117+
return getPath(key, $deepmap.value as BaseDeepMap);
118+
};
119+
120+
$deepmap.setKey = <K extends AllPaths<T> | "">(
104121
key: K,
105-
value: FromPathWithIndexSignatureUndefined<T, K> | undefined
122+
value: FromPathWithIndexSignatureUndefined<T, K> | undefined,
106123
): void => {
107124
if (getPath(key, $deepmap.value as BaseDeepMap) !== value) {
108-
const oldValue = $deepmap.value
109-
$deepmap.value = setPath(key, value, $deepmap.value as BaseDeepMap) as T
110-
$deepmap.notify(oldValue, key as AllPaths<T>)
125+
const oldValue = $deepmap.value;
126+
$deepmap.value = setPath(key, value, $deepmap.value as BaseDeepMap) as T;
127+
$deepmap.notify(oldValue, key as AllPaths<T>);
111128
}
112-
}
129+
};
113130

114-
$deepmap.updateKey = <K extends AllPaths<T> | ''>(
131+
$deepmap.updateKey = <K extends AllPaths<T> | "">(
115132
key: K,
116-
value: Partial<FromPathWithIndexSignatureUndefined<T, K>> | undefined
133+
value: Partial<FromPathWithIndexSignatureUndefined<T, K>> | undefined,
117134
): void => {
118-
const oldValue = getPath(key, $deepmap.value as BaseDeepMap)
135+
const oldValue = getPath(key, $deepmap.value as BaseDeepMap);
119136
let newValue: any = value;
120137

121138
if (isObject(oldValue) && isObject(value)) {
122-
newValue = { ...oldValue as object, ...value };
139+
newValue = { ...(oldValue as object), ...value };
123140
} else if (Array.isArray(oldValue) && Array.isArray(value)) {
124141
newValue = [...oldValue, ...value];
125142
}
126143

127144
$deepmap.setKey(key, newValue as any);
128-
}
145+
};
129146

130-
return $deepmap
131-
}
147+
$deepmap.update = (value: Partial<T> | undefined): void => {
148+
$deepmap.updateKey("", value);
149+
};
132150

133-
/**
134-
* Get a value by key from a store with an object value.
135-
* Works with `map`, `deepMap`, and `atom`.
136-
*
137-
* ```js
138-
* import { getKey, map } from 'nanostores'
139-
*
140-
* const $user = map({ name: 'John', profile: { age: 30 } })
141-
*
142-
* // Simple key access
143-
* getKey($user, 'name') // Returns 'John'
144-
*
145-
* // Nested access with dot notation
146-
* getKey($user, 'profile.age') // Returns 30
147-
*
148-
* // Array access
149-
* const $items = map({ products: ['apple', 'banana'] })
150-
* getKey($items, 'products[1]') // Returns 'banana'
151-
* ```
152-
*
153-
* @param store The store to get the value from.
154-
* @param key The key to access. Can be a simple key or a path with dot notation.
155-
* @returns The value for this key
156-
*/
157-
export function getKey<
158-
T extends Record<string, unknown>,
159-
K extends AllPaths<T> | ''
160-
>(store: AnyStore<T>, key: K): FromPath<T, K> {
161-
const value = store.get()
162-
return getPath(key, value)
151+
return $deepmap;
163152
}

deep-map/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
export {
22
deepMap,
3-
getKey,
43
type DeepMapStore
54
} from './deepmap.js'
65

eslint.config.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
import js from '@eslint/js';
2-
import tseslint from 'typescript-eslint';
1+
import js from "@eslint/js";
2+
import tseslint from "typescript-eslint";
33
/** @type {import('eslint').Linter.FlatConfig[]} */
44
export default [
5-
{ ignores: ['**/errors.ts', 'dist/'] },
5+
{ ignores: ["**/errors.ts", "dist/", "TEST/"] },
66
js.configs.recommended,
77
...tseslint.configs.recommended,
88
{
99
rules: {
10-
'@typescript-eslint/no-explicit-any': 'off',
11-
'@typescript-eslint/unified-signatures': 'off',
12-
'camelcase': 'off',
13-
'consistent-return': 'off',
14-
'symbol-description': 'off'
15-
}
10+
"@typescript-eslint/no-explicit-any": "off",
11+
"@typescript-eslint/unified-signatures": "off",
12+
camelcase: "off",
13+
"consistent-return": "off",
14+
"symbol-description": "off",
15+
},
1616
},
1717
{
18-
files: ['**/*.test.ts'],
18+
files: ["**/*.test.ts"],
1919
rules: {
20-
'@typescript-eslint/no-floating-promises': 'off',
21-
'@typescript-eslint/no-unsafe-argument': 'off',
22-
'@typescript-eslint/no-unsafe-assignment': 'off',
23-
'@typescript-eslint/no-unsafe-call': 'off',
24-
'@typescript-eslint/no-unsafe-member-access': 'off',
25-
'@typescript-eslint/no-unsafe-return': 'off',
26-
'@typescript-eslint/unbound-method': 'off'
27-
}
28-
}
29-
]
20+
"@typescript-eslint/no-floating-promises": "off",
21+
"@typescript-eslint/no-unsafe-argument": "off",
22+
"@typescript-eslint/no-unsafe-assignment": "off",
23+
"@typescript-eslint/no-unsafe-call": "off",
24+
"@typescript-eslint/no-unsafe-member-access": "off",
25+
"@typescript-eslint/no-unsafe-return": "off",
26+
"@typescript-eslint/unbound-method": "off",
27+
},
28+
},
29+
];

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nanostores/deepmap",
3-
"version": "0.0.1",
3+
"version": "0.0.2",
44
"description": "A helper for Nanostores to create deep maps",
55
"keywords": [
66
"store",
@@ -24,7 +24,7 @@
2424
},
2525
"author": "Edgar Sanchez <albertolifo@gmail.com>",
2626
"license": "MIT",
27-
"repository": "nanostores/deep-map",
27+
"repository": "nanostores/deepmap",
2828
"sideEffects": false,
2929
"type": "module",
3030
"main": "./dist/index.js",

0 commit comments

Comments
 (0)