-
-
Notifications
You must be signed in to change notification settings - Fork 62
fix(Cache): typescript Map generic type fixed
#308
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 27 commits
3d4784f
41137fd
95492ad
dfe4ddd
8e32e9c
7e54cf4
0130bdb
3abcc5d
af55eba
e663b44
8cb3c0f
ae3780f
06d32c6
c9b8997
da25618
fb6b487
7943cfd
e239a39
55ab91f
d233f1b
992a9fc
287f2cb
61dbdd1
1ed3491
1ece3d5
cb3b0b3
0f416fe
5617efd
b29c506
5706883
1553dcf
7147f60
d5b37ef
c2a8dbe
40b8a19
1622437
1fd5511
bb697bf
41210cf
2ba8147
055391d
2cb48ad
d984e19
db24238
ddc98e3
6134ed2
9c40705
722f7d2
b9a3449
ddb89ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| export class CacheMapper<K, V> implements Map<K, V> { | ||
| private _innerMap: Map<K, V>; | ||
| size: number; | ||
dimaslanjaka marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| constructor() { | ||
| this._innerMap = new Map(); | ||
| } | ||
| clear(): void { | ||
| this._innerMap.clear(); | ||
| } | ||
| delete(key: K): boolean { | ||
| throw this._innerMap.delete(key); | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void { | ||
| return this._innerMap.forEach(callbackfn, thisArg); | ||
| } | ||
| entries(): IterableIterator<[K, V]> { | ||
| return this._innerMap.entries(); | ||
| } | ||
| keys(): IterableIterator<K> { | ||
| return this._innerMap.keys(); | ||
| } | ||
| values(): IterableIterator<V> { | ||
| return this._innerMap.values(); | ||
| } | ||
| [Symbol.iterator](): IterableIterator<[K, V]> { | ||
| return this._innerMap.entries(); | ||
| } | ||
| [Symbol.toStringTag]: string; | ||
|
|
||
| typeof() { | ||
| return typeof this._innerMap; | ||
| } | ||
|
|
||
| set(id: K, value: V) { | ||
| this._innerMap.set(id, value); | ||
| // set cache size while set new value | ||
| this.size = this._innerMap.size; | ||
| return this; | ||
| } | ||
|
|
||
| has(id: K) { | ||
| return this._innerMap.has(id); | ||
| } | ||
|
|
||
| get(id: K) { | ||
| return this._innerMap.get(id); | ||
| } | ||
|
|
||
| del(id: K) { | ||
| this._innerMap.delete(id); | ||
| // set cache size while delete value | ||
| this.size = this._innerMap.size; | ||
| } | ||
|
|
||
| apply(id: K, value: unknown) { | ||
| if (this.has(id)) return this.get(id); | ||
|
|
||
| if (typeof value === 'function') value = value(); | ||
|
|
||
| this.set(id, value as V); | ||
| return value as V; | ||
| } | ||
|
|
||
| flush() { | ||
| this._innerMap.clear(); | ||
|
|
||
| // set cache size while flusing cache | ||
| this.size = this._innerMap.size; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Generic Mutable Cache with `Map` | ||
| * * A Map holds key-value pairs where the keys can be any datatype (Generic) | ||
| * @example | ||
| * import { Cache } from 'hexo-util'; | ||
| * const c = new Cache<number>(); | ||
| * // error | ||
| * c.set('key', 'xxxx'); // cache value must be instance of number | ||
| * // pass | ||
| * c.set('key', 1); | ||
| */ | ||
| export class Cache<V> { | ||
| private cache: CacheMapper<string, V>; | ||
| constructor() { | ||
| this.cache = new CacheMapper<string, V>(); | ||
| } | ||
|
|
||
| /** | ||
| * check cache is exist with given key | ||
| * @param key cache key string | ||
| * @returns | ||
| */ | ||
| has(key: string) { | ||
| return this.cache.has(key); | ||
| } | ||
|
|
||
| /** | ||
| * get cache | ||
| * @param key | ||
| * @returns | ||
| */ | ||
| get(key: string) { | ||
| return this.cache.get(key); | ||
| } | ||
|
|
||
| /** | ||
| * set cache | ||
| * @param key | ||
| * @param value cache value must same as constructor generic type | ||
| * @returns | ||
| */ | ||
| set(key: string, value: V) { | ||
| return this.cache.set(key, value); | ||
| } | ||
|
|
||
| /** | ||
| * dump cache | ||
| * @returns | ||
| */ | ||
| dump() { | ||
| return Object.fromEntries(this.cache); | ||
| } | ||
|
|
||
| /** | ||
| * get cache total | ||
| * @returns | ||
| */ | ||
| size() { | ||
| return this.cache.size; | ||
| } | ||
|
|
||
| /** | ||
| * apply cache non-function | ||
| * @param key cache key string | ||
| * @param value cache value must same as constructor generic type | ||
| */ | ||
| apply(key: string, value: V): V; | ||
|
|
||
| /** | ||
| * apply cache with function | ||
| * @param key cache key string | ||
| * @param value cache value must same as constructor generic type | ||
| */ | ||
| apply(key: string, value: () => V): V; | ||
|
|
||
| /** | ||
| * apply cache | ||
| * @param key cache key string | ||
| * @param value cache value must same as constructor generic type | ||
| */ | ||
| apply(key: string, value: (() => V) | V) { | ||
| return this.cache.apply(key, value); | ||
| } | ||
| del(key: string) { | ||
| return this.cache.del(key); | ||
| } | ||
| flush() { | ||
| return this.cache.flush(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,44 +1,3 @@ | ||
| export = class Cache<T> { | ||
| cache: Map<string, T>; | ||
| import { Cache } from './CacheMapper'; | ||
|
|
||
| constructor() { | ||
| this.cache = new Map(); | ||
| } | ||
|
|
||
| set(id: string, value: T) { | ||
| this.cache.set(id, value); | ||
| } | ||
|
|
||
| has(id: string) { | ||
| return this.cache.has(id); | ||
| } | ||
|
|
||
| get(id: string) { | ||
| return this.cache.get(id); | ||
| } | ||
|
|
||
| del(id: string) { | ||
| this.cache.delete(id); | ||
| } | ||
|
|
||
| apply(id: string, value): T { | ||
| if (this.has(id)) return this.get(id); | ||
|
|
||
| if (typeof value === 'function') value = value(); | ||
|
|
||
| this.set(id, value); | ||
| return value; | ||
| } | ||
|
|
||
| flush() { | ||
| this.cache.clear(); | ||
| } | ||
|
|
||
| size() { | ||
| return this.cache.size; | ||
| } | ||
|
|
||
| dump() { | ||
| return Object.fromEntries(this.cache); | ||
| } | ||
| }; | ||
| export = Cache; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,15 @@ | ||
| { | ||
| "extends": "hexo/test", | ||
| "overrides": [ | ||
| { | ||
| "files": ["*.ts"], | ||
| "rules": { | ||
| "node/no-unsupported-features/es-syntax": 0 | ||
| } | ||
| } | ||
| ], | ||
| "rules": { | ||
| "@typescript-eslint/no-var-requires": 0, | ||
| "@typescript-eslint/no-empty-function": 0 | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| 'use strict'; | ||
|
|
||
| import { describe, it } from 'mocha'; | ||
| import * as Hutil from '../lib'; | ||
| import { expect } from 'chai'; | ||
|
|
||
| // to run single test | ||
| // mocha --require ts-node/register --exit --grep "Cache - Typescript" | ||
|
|
||
| describe('Cache - Typescript', () => { | ||
| describe('Cache - number', () => { | ||
| const cache = new Hutil.Cache<number>(); | ||
| const dumpExpect = { foo: 1, bar: 2 }; | ||
|
|
||
| it('should be number', () => { | ||
| // apply non-function | ||
| expect(cache.apply('foo', 1)).to.be.an('number'); | ||
| // apply with function | ||
| expect(cache.apply('bar', () => 2)).to.be.an('number'); | ||
| }); | ||
|
|
||
| it('add another and delete it', () => { | ||
| // add `another` | ||
| expect(cache.apply('another', 3)).to.equal(3); | ||
| // size should be 3 | ||
| expect(cache.size()).to.equal(3); | ||
| // add with function | ||
| expect(cache.apply('another', () => 3)).to.equal(3); | ||
| // size should be still 3 | ||
| expect(cache.size()).to.equal(3); | ||
| // delete `another` | ||
| cache.del('another'); | ||
| }); | ||
|
|
||
| it('final size should be 2', () => { | ||
| // final size should be 2 | ||
| expect(cache.size()).to.equal(2); | ||
| }); | ||
|
|
||
| it('should dump matches', () => { | ||
| expect(cache.dump()).deep.equal(dumpExpect); | ||
| }); | ||
|
|
||
| it('should be empty after flush', () => { | ||
| cache.flush(); | ||
| expect(cache.size()).to.be.equal(0); | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,63 +1,74 @@ | ||
| 'use strict'; | ||
|
|
||
| require('chai').should(); | ||
| const chai = require('chai'); | ||
| const should = chai.should(); | ||
| const expect = chai.expect; | ||
|
|
||
| describe('Cache', () => { | ||
| // const Cache = require('../dist').Cache; // <-- this also works | ||
| const Cache = require('../dist/cache'); | ||
| const cache = new Cache(); | ||
|
|
||
| it('get & set', () => { | ||
| cache.set('foo', 123); | ||
| cache.get('foo').should.eql(123); | ||
| should.equal(cache.get('foo'), 123); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
at my device using prototype.should getting error (throw undefined and make all tests failed), instead giving result test failure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i dont know, why. But using normal chai API can give result failure correctly instead throw all tests runner, that was made me confused, because throw from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. emm, i think this error caused by running on monorepo/workspace project. cuz all dependents grouped at single There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. error says: cannot read property 'should' of undefined There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sometimes got error like: cannot read property 'eql' ... so on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so to prevent useless error, prefer using original chai |
||
| }); | ||
|
|
||
| it('size', () => { | ||
| cache.set('foobar', 456); | ||
| cache.size().should.eql(2); | ||
| should.equal(cache.size(), 2); | ||
| }); | ||
|
|
||
| it('has', () => { | ||
| cache.has('foo').should.eql(true); | ||
| cache.has('bar').should.eql(false); | ||
| should.equal(cache.has('foo'), true); | ||
| should.equal(cache.has('bar'), false); | ||
| }); | ||
|
|
||
| it('apply - non function', () => { | ||
| cache.apply('bar', 123).should.eql(123); | ||
| cache.apply('bar', 456).should.eql(123); | ||
|
|
||
| cache.apply('foo', 456).should.eql(123); | ||
| should.equal(cache.apply('bar', 123), 123); | ||
| should.equal(cache.apply('bar', 456), 123); | ||
| should.equal(cache.apply('foo', 456), 123); | ||
| }); | ||
|
|
||
| it('apply - function', () => { | ||
| cache.apply('baz', () => 123).should.eql(123); | ||
| cache.apply('baz', () => 456).should.eql(123); | ||
| should.equal( | ||
| cache.apply('baz', () => 123), | ||
| 123 | ||
| ); | ||
| should.equal( | ||
| cache.apply('baz', () => 456), | ||
| 123 | ||
| ); | ||
| }); | ||
|
|
||
| it('dump', () => { | ||
| cache.dump().should.eql({ | ||
| 'bar': 123, | ||
| 'baz': 123, | ||
| 'foo': 123, | ||
| 'foobar': 456 | ||
| expect(cache.dump()).to.include({ | ||
| bar: 123, | ||
| baz: 123, | ||
| foo: 123, | ||
| foobar: 456 | ||
| }); | ||
| }); | ||
|
|
||
| it('del', () => { | ||
| cache.del('baz'); | ||
| cache.has('foo').should.eql(true); | ||
| cache.has('baz').should.eql(false); | ||
| should.equal(cache.has('foo'), true); | ||
| should.equal(cache.has('baz'), false); | ||
| }); | ||
|
|
||
| it('flush', () => { | ||
| cache.flush(); | ||
| cache.has('foo').should.eql(false); | ||
| cache.has('bar').should.eql(false); | ||
| cache.has('baz').should.eql(false); | ||
| cache.size().should.eql(0); | ||
| should.equal(cache.has('foo'), false); | ||
| should.equal(cache.has('bar'), false); | ||
| should.equal(cache.has('baz'), false); | ||
| should.equal(cache.size(), 0); | ||
| }); | ||
|
|
||
| it('cache null', () => { | ||
| cache.apply('foo', null); | ||
| (cache.apply('foo', 123) === null).should.eql(true); | ||
| should.equal(cache.apply('foo', 123) === null, true); | ||
| }); | ||
|
|
||
| // include typescript test | ||
| require('./cache.number.test.ts'); | ||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.