dynamic-multikey-map 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Liam Martens
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # dynamic-multikey-map
2
+
3
+ [![badge](https://img.shields.io/npm/v/dynamic-multikey-map)](https://www.npmjs.com/package/dynamic-multikey-map) [![badge](https://img.shields.io/bundlephobia/min/dynamic-multikey-map)](https://bundlephobia.com/package/dynamic-multikey-map) ![badge](https://img.shields.io/github/license/LiamMartens/dynamic-multikey-map)
4
+
5
+ This is a dynamic multiple key map to map a single object to multiple dynamic values.
6
+
7
+ ## Usage
8
+
9
+ ```js
10
+ import { MultiKeyMap } from "dynamic-multikey-map";
11
+
12
+ type ValueType = {
13
+ username: string;
14
+ ssn: string;
15
+ };
16
+
17
+ const map = new MultiKeyMap<ValueType, string>([
18
+ (value: ValueType) => value.ssn,
19
+ (value: ValueType) => value.username,
20
+ ]);
21
+
22
+ map.add({
23
+ username: "john.doe",
24
+ ssn: "123-45-6789",
25
+ });
26
+
27
+ expect(map.get("john.doe")).toEqual(map.get("123-45-6789"));
28
+ ```
@@ -0,0 +1,66 @@
1
+ type ExtractorFunction<T, K> = (value: T) => K;
2
+ export declare class MultiKeyMap<ObjectType, KeyValueTypes extends unknown> {
3
+ extractors: ExtractorFunction<ObjectType, KeyValueTypes>[];
4
+ protected valueKeys: Map<ObjectType, KeyValueTypes[]>;
5
+ protected map: Map<KeyValueTypes, ObjectType>;
6
+ constructor(extractors: ExtractorFunction<ObjectType, KeyValueTypes>[]);
7
+ get size(): number;
8
+ /**
9
+ * Clears the map keys and values
10
+ */
11
+ clear: () => void;
12
+ /**
13
+ * Adds a value to the map
14
+ * @param value
15
+ */
16
+ add: (value: ObjectType) => void;
17
+ /**
18
+ * Removes a value from the map by value
19
+ * @param value
20
+ * @returns false if the value was not found in the map, true if successfull
21
+ */
22
+ deleteByValue: (value: ObjectType) => boolean;
23
+ /**
24
+ * Removes a value from the map by key
25
+ * @param key
26
+ * @returns false if the key was not found in the map, true if successfull
27
+ */
28
+ deleteByKey: (key: KeyValueTypes) => boolean;
29
+ /**
30
+ * @param key
31
+ * @returns if a key exists in the map
32
+ */
33
+ has: (key: KeyValueTypes) => boolean;
34
+ /**
35
+ * Finds he value for a specified key
36
+ * @param key
37
+ * @returns associated value
38
+ */
39
+ get: (key: KeyValueTypes) => ObjectType | undefined;
40
+ /**
41
+ * Replaces the value of a specific key. It will update all previously associated keys to match
42
+ * @param key
43
+ * @param value
44
+ * @returns true if successfull, false if not found
45
+ */
46
+ replace: (key: KeyValueTypes, value: ObjectType) => boolean;
47
+ /**
48
+ * @returns an iterator for the map keys
49
+ */
50
+ keys: () => IterableIterator<KeyValueTypes[]>;
51
+ /**
52
+ * @returns an iterator for the map entries
53
+ */
54
+ entries: () => IterableIterator<[KeyValueTypes[], ObjectType]>;
55
+ /**
56
+ * @returns an iterator for the map values
57
+ */
58
+ values: () => IterableIterator<ObjectType>;
59
+ /**
60
+ * Loops over the map with a callback
61
+ * @param callbackfn
62
+ * @param thisArg
63
+ */
64
+ forEach: (callbackfn: (value: ObjectType, key: KeyValueTypes[], map: this) => void, thisArg?: any) => void;
65
+ }
66
+ export {};
package/lib/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { MultiKeyMap } from "./MultiKeyMap.js";
package/lib/index.js ADDED
@@ -0,0 +1,182 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+
8
+ // src/MultiKeyMap.ts
9
+ var MultiKeyMap = class {
10
+ constructor(extractors) {
11
+ this.extractors = extractors;
12
+ __publicField(this, "valueKeys", /* @__PURE__ */ new Map());
13
+ __publicField(this, "map", /* @__PURE__ */ new Map());
14
+ /**
15
+ * Clears the map keys and values
16
+ */
17
+ __publicField(this, "clear", () => {
18
+ this.valueKeys.clear();
19
+ this.map.clear();
20
+ });
21
+ /**
22
+ * Adds a value to the map
23
+ * @param value
24
+ */
25
+ __publicField(this, "add", (value) => {
26
+ const valueKeys = [];
27
+ for (const fn of this.extractors) {
28
+ const key = fn(value);
29
+ valueKeys.push(key);
30
+ if (this.map.has(key)) {
31
+ console.warn("[duplicate_key] ".concat(key), value);
32
+ }
33
+ this.map.set(key, value);
34
+ }
35
+ this.valueKeys.set(value, valueKeys);
36
+ });
37
+ /**
38
+ * Removes a value from the map by value
39
+ * @param value
40
+ * @returns false if the value was not found in the map, true if successfull
41
+ */
42
+ __publicField(this, "deleteByValue", (value) => {
43
+ if (this.valueKeys.has(value)) {
44
+ const keys = this.valueKeys.get(value);
45
+ this.valueKeys.delete(value);
46
+ for (const key of keys) {
47
+ this.map.delete(key);
48
+ }
49
+ return true;
50
+ }
51
+ return false;
52
+ });
53
+ /**
54
+ * Removes a value from the map by key
55
+ * @param key
56
+ * @returns false if the key was not found in the map, true if successfull
57
+ */
58
+ __publicField(this, "deleteByKey", (key) => {
59
+ if (this.map.has(key)) {
60
+ const value = this.map.get(key);
61
+ const keys = this.valueKeys.get(value);
62
+ if (keys) {
63
+ this.valueKeys.delete(value);
64
+ for (const key2 of keys) {
65
+ this.map.delete(key2);
66
+ }
67
+ }
68
+ return true;
69
+ }
70
+ return false;
71
+ });
72
+ /**
73
+ * @param key
74
+ * @returns if a key exists in the map
75
+ */
76
+ __publicField(this, "has", (key) => {
77
+ return this.map.has(key);
78
+ });
79
+ /**
80
+ * Finds he value for a specified key
81
+ * @param key
82
+ * @returns associated value
83
+ */
84
+ __publicField(this, "get", (key) => {
85
+ return this.map.get(key);
86
+ });
87
+ /**
88
+ * Replaces the value of a specific key. It will update all previously associated keys to match
89
+ * @param key
90
+ * @param value
91
+ * @returns true if successfull, false if not found
92
+ */
93
+ __publicField(this, "replace", (key, value) => {
94
+ if (this.has(key)) {
95
+ this.deleteByValue(value);
96
+ this.add(value);
97
+ return true;
98
+ }
99
+ return false;
100
+ });
101
+ /**
102
+ * @returns an iterator for the map keys
103
+ */
104
+ __publicField(this, "keys", () => {
105
+ const valueKeys = this.valueKeys.values();
106
+ const iterator = {
107
+ [Symbol.iterator]: () => iterator,
108
+ next: () => {
109
+ const entry = valueKeys.next();
110
+ if (entry.done) {
111
+ return { done: true, value: void 0 };
112
+ }
113
+ return {
114
+ done: entry.done,
115
+ value: entry.value
116
+ };
117
+ }
118
+ };
119
+ return iterator;
120
+ });
121
+ /**
122
+ * @returns an iterator for the map entries
123
+ */
124
+ __publicField(this, "entries", () => {
125
+ const valueKeys = this.valueKeys.entries();
126
+ const iterator = {
127
+ [Symbol.iterator]: () => iterator,
128
+ next: () => {
129
+ const entry = valueKeys.next();
130
+ if (entry.done) {
131
+ return { done: true, value: void 0 };
132
+ }
133
+ return {
134
+ done: entry.done,
135
+ value: [entry.value[1], entry.value[0]]
136
+ };
137
+ }
138
+ };
139
+ return iterator;
140
+ });
141
+ /**
142
+ * @returns an iterator for the map values
143
+ */
144
+ __publicField(this, "values", () => {
145
+ const values = this.valueKeys.keys();
146
+ const iterator = {
147
+ [Symbol.iterator]: () => iterator,
148
+ next: () => {
149
+ const entry = values.next();
150
+ if (entry.done) {
151
+ return { done: true, value: void 0 };
152
+ }
153
+ return {
154
+ done: entry.done,
155
+ value: entry.value
156
+ };
157
+ }
158
+ };
159
+ return iterator;
160
+ });
161
+ /**
162
+ * Loops over the map with a callback
163
+ * @param callbackfn
164
+ * @param thisArg
165
+ */
166
+ __publicField(this, "forEach", (callbackfn, thisArg) => {
167
+ for (const [value, keys] of this.valueKeys) {
168
+ if (typeof thisArg === "undefined" || thisArg === null) {
169
+ callbackfn(value, keys, this);
170
+ } else {
171
+ callbackfn.call(thisArg, value, keys, this);
172
+ }
173
+ }
174
+ });
175
+ }
176
+ get size() {
177
+ return this.valueKeys.size;
178
+ }
179
+ };
180
+ export {
181
+ MultiKeyMap
182
+ };
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "dynamic-multikey-map",
3
+ "type": "module",
4
+ "packageManager": "bun@1.0.23",
5
+ "version": "1.0.0",
6
+ "license": "MIT",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./lib/index.d.ts",
10
+ "import": "./lib/index.js"
11
+ }
12
+ },
13
+ "files": ["lib", "LICENSE"],
14
+ "devDependencies": {
15
+ "esbuild": "^0.20.0",
16
+ "vitest": "^1.2.2"
17
+ },
18
+ "peerDependencies": {
19
+ "typescript": "^5.0.0"
20
+ },
21
+ "scripts": {
22
+ "test": "vitest",
23
+ "compile:js": "esbuild --bundle --target=safari11 --outfile=./lib/index.js --format=esm ./src/index.ts",
24
+ "compile:ts": "tsc -p tsconfig.build.json",
25
+ "compile": "bun run compile:js && bun run compile:ts"
26
+ }
27
+ }