Skip to content

Commit b128a26

Browse files
committed
fix case insensitive primitives
1 parent 0e68e85 commit b128a26

File tree

4 files changed

+124
-54
lines changed

4 files changed

+124
-54
lines changed

src/Primitives/CaseInsensitiveKeysMap.ts

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,5 @@
11
import { TypeUtil } from "../Utility/TypeUtil";
2-
import { stringify } from "qs";
3-
4-
const originalKeysMap: WeakMap<Map<string, any>, Map<string, string>>
5-
= new WeakMap();
6-
7-
function getOriginalKey(targetMap: Map<string, any>, key: string) {
8-
const keysMap = originalKeysMap.get(targetMap);
9-
return keysMap.get(key);
10-
}
11-
12-
function setOriginalKey(targetMap: Map<string, any>, origKey: string, lowerKey: string) {
13-
let keysMap;
14-
if (!originalKeysMap.has(targetMap)) {
15-
keysMap = new Map<string, string>();
16-
originalKeysMap.set(targetMap, keysMap);
17-
} else {
18-
keysMap = originalKeysMap.get(targetMap);
19-
}
20-
21-
keysMap.set(lowerKey, origKey);
22-
}
23-
24-
function deleteOriginalKey(targetMap: Map<string, any>, lowerKey: string) {
25-
if (!originalKeysMap.has(targetMap)) {
26-
return;
27-
}
28-
29-
originalKeysMap.get(targetMap).delete(lowerKey);
30-
}
2+
import { CaseInsensitiveKeysStore } from "./CaseInsensitiveKeysStore";
313

324
function validateKey(key) {
335
if (TypeUtil.isNullOrUndefined(key)
@@ -38,9 +10,6 @@ function validateKey(key) {
3810
throw Error("Key must be a string.");
3911
}
4012

41-
function normalizeKey(key: string) {
42-
return key ? key.toLowerCase() : key;
43-
}
4413
export class CaseInsensitiveKeysMap {
4514

4615
public static create<TValue>(): Map<string, TValue> {
@@ -50,45 +19,52 @@ export class CaseInsensitiveKeysMap {
5019
const origHas = result.has;
5120
const origDelete = result.delete;
5221

22+
const originalKeysStore = new CaseInsensitiveKeysStore();
23+
5324
result["keysCaseSensitive"] = false;
5425
result.set = function (...args) {
5526
const [ key, ...rest ] = args;
5627
validateKey(key);
57-
const lowerKey = normalizeKey(key);
58-
setOriginalKey(result, key, lowerKey);
28+
const lowerKey = originalKeysStore.setKey(key);
5929
return origSet.call(result, lowerKey, ...rest);
6030
};
6131

6232
result.get = function (...args) {
6333
const [ key, ...rest ] = args;
64-
validateKey(key);
65-
const lowerKey = normalizeKey(key);
34+
const lowerKey = originalKeysStore.normalizeKey(key);
6635
return origGet.call(result, lowerKey, ...rest);
6736
};
6837

6938
result.has = function (...args) {
7039
const [ key, ...rest ] = args;
71-
validateKey(key);
72-
const lowerKey = normalizeKey(key);
40+
const lowerKey = originalKeysStore.normalizeKey(key);
7341
return origHas.call(result, lowerKey, ...rest);
7442
};
7543

7644
result.delete = function (...args) {
7745
const [ key, ...rest ] = args;
7846
validateKey(key);
79-
const lowerKey = normalizeKey(key);
80-
deleteOriginalKey(result, lowerKey);
47+
const lowerKey = originalKeysStore.deleteKey(key);
8148
return origDelete.call(result, lowerKey, ...rest);
8249
};
8350

8451
const origEntries = result.entries;
8552
result.entries = function () {
8653
return Array.from(origEntries.call(result) as Iterable<[string, TValue]>)
8754
.reduce((reduced, next) => {
88-
const actualKey = getOriginalKey(result, next[0]);
55+
const actualKey = originalKeysStore.getKey(next[0]);
56+
return [...reduced, [actualKey, next[1]]];
57+
}, [])[Symbol.iterator]();
58+
};
59+
60+
result[Symbol.iterator] = function () {
61+
return Array.from(origEntries.call(result) as Iterable<[string, TValue]>)
62+
.reduce((reduced, next) => {
63+
const actualKey = originalKeysStore.getKey(next[0]);
8964
return [...reduced, [actualKey, next[1]]];
9065
}, [])[Symbol.iterator]();
9166
};
67+
9268

9369
return result;
9470
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
// export class CaseInsensitiveKeysStore<T extends object> {
3+
4+
// private _originalKeys: WeakMap<T, Map<string, string>> = new WeakMap();
5+
6+
// public getKey(target: T, key: string) {
7+
// const keysMap = this._originalKeys.get(target);
8+
// return keysMap.get(key);
9+
// }
10+
11+
// public getKeys(target: T): IterableIterator<string> {
12+
// const keysMap = this._originalKeys.get(target);
13+
// return keysMap.values();
14+
// }
15+
16+
// public setKey(target: T, origKey: string): string {
17+
// let keysMap;
18+
// if (!this._originalKeys.has(target)) {
19+
// keysMap = new Map<string, string>();
20+
// this._originalKeys.set(target, keysMap);
21+
// } else {
22+
// keysMap = this._originalKeys.get(target);
23+
// }
24+
25+
// const lowerKey = this.normalizeKey(origKey);
26+
// keysMap.set(lowerKey, origKey);
27+
// return lowerKey;
28+
// }
29+
30+
// public deleteKey(target: T, origKey: string): string {
31+
// if (!this._originalKeys.has(target)) {
32+
// return;
33+
// }
34+
35+
// const lowerKey = this.normalizeKey(origKey);
36+
37+
// this._originalKeys.get(target).delete(lowerKey);
38+
// return lowerKey;
39+
// }
40+
41+
// public normalizeKey(key: string) {
42+
// return key ? key.toLowerCase() : key;
43+
// }
44+
45+
// }
46+
47+
export class CaseInsensitiveKeysStore {
48+
49+
private _originalKeys: Map<string, string> = new Map();
50+
51+
public getKey(key: string) {
52+
return this._originalKeys.get(
53+
this.normalizeKey(key));
54+
}
55+
56+
public getKeys(): IterableIterator<string> {
57+
return this._originalKeys.values();
58+
}
59+
60+
public setKey(origKey: string): string {
61+
const lowerKey = this.normalizeKey(origKey);
62+
this._originalKeys.set(lowerKey, origKey);
63+
return lowerKey;
64+
}
65+
66+
public deleteKey(origKey: string): string {
67+
const lowerKey = this.normalizeKey(origKey);
68+
this._originalKeys.delete(lowerKey);
69+
return lowerKey;
70+
}
71+
72+
public normalizeKey(key: string) {
73+
return key ? key.toLowerCase() : key;
74+
}
75+
}
Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,46 @@
1+
import { CaseInsensitiveKeysStore } from "./CaseInsensitiveKeysStore";
2+
3+
4+
function validateKey(key) {
5+
if (!(key && key.toLowerCase)) {
6+
throw Error("Key must be a string.");
7+
}
8+
}
19

210
export class CaseInsensitiveStringSet {
311
public static create(): Set<string> {
4-
const result = new Set();
12+
const result = new Set<string>();
513
const origAdd = result.add;
614
const origHas = result.has;
715
const origDelete = result.delete;
816

9-
function validateKey(key) {
10-
if (!(key && key.toLowerCase)) {
11-
throw Error("Key must be a string.");
12-
}
13-
}
14-
17+
const originalKeysStore = new CaseInsensitiveKeysStore();
1518
result.add = function (...args) {
1619
const [ key, ...rest ] = args;
1720
validateKey(key);
18-
return origAdd.call(result, key ? key.toLowerCase() : key, ...rest);
21+
const lowerKey = originalKeysStore.setKey(key);
22+
return origAdd.call(result, lowerKey, ...rest);
1923
};
2024

2125
result.has = function (...args) {
2226
const [ key, ...rest ] = args;
23-
validateKey(key);
24-
return origHas.call(result, key ? key.toLowerCase() : key, ...rest);
27+
const lowerKey = originalKeysStore.normalizeKey(key);
28+
return origHas.call(result, lowerKey, ...rest);
2529
};
2630

2731
result.delete = function (...args) {
2832
const [ key, ...rest ] = args;
29-
validateKey(key);
30-
return origDelete.call(result, key ? key.toLowerCase() : key, ...rest);
33+
const lowerKey = originalKeysStore.deleteKey(key);
34+
return origDelete.call(result, lowerKey, ...rest);
3135
};
3236

37+
result.entries = () =>
38+
[...originalKeysStore.getKeys()]
39+
.map(x => [x, x] as [string, string])[Symbol.iterator]();
40+
41+
result[Symbol.iterator] = () =>
42+
[...originalKeysStore.getKeys()][Symbol.iterator]();
43+
3344
return result;
3445
}
3546
}

test/Primitives/CaseInsensitivePrimitivesTests.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ describe("CaseInsensitiveKeyMap", function () {
1818

1919
// gives actual set entries
2020
const entries = Array.from(map.entries());
21-
assert.strictEqual(entries[0][0], "TEst_KEY");
21+
assert.strictEqual(entries[0][0], "TEsT_KEY");
22+
23+
const iterable = [...map];
24+
assert.strictEqual(iterable[0][0], "TEsT_KEY");
25+
assert.strictEqual(iterable[0][1], 1);
2226

2327
assert.ok(map.delete("teST_KEY"));
2428
assert.ok(!map.has("TeSt_kEy"));
@@ -36,6 +40,10 @@ describe("CaseInsensitiveStringSet", function () {
3640
it("set, has and get with case insensitive strings", async () => {
3741
set.add("TEsT_KEY");
3842
assert.ok(set.has("TeSt_kEy"));
43+
assert.strictEqual(Array.from(set)[0], "TEsT_KEY");
44+
assert.strictEqual(Array.from(set.entries())[0][0], "TEsT_KEY");
45+
3946
assert.ok(set.delete("teST_KEY"));
47+
assert.ok(!set.has("TeSt_kEy"));
4048
});
4149
});

0 commit comments

Comments
 (0)