typescript-memoize
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -1,2 +0,9 @@ | ||
export declare function Memoize(autoHashOrHashFn?: boolean | ((...args: any[]) => any)): (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => void; | ||
export declare function MemoizeExpiring(duration: number, autoHashOrHashFn?: boolean | ((...args: any[]) => any)): (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => void; | ||
interface MemoizeArgs { | ||
expiring?: number; | ||
hashFunction?: boolean | ((...args: any[]) => any); | ||
tags?: string[]; | ||
} | ||
export declare function Memoize(args?: MemoizeArgs | MemoizeArgs['hashFunction']): (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => void; | ||
export declare function MemoizeExpiring(expiring: number, hashFunction?: MemoizeArgs['hashFunction']): (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => void; | ||
export declare function clear(tags: string[]): number; | ||
export {}; |
@@ -1,8 +0,19 @@ | ||
export function Memoize(autoHashOrHashFn) { | ||
export function Memoize(args) { | ||
let hashFunction; | ||
let duration; | ||
let tags; | ||
if (typeof args === 'object') { | ||
hashFunction = args.hashFunction; | ||
duration = args.expiring; | ||
tags = args.tags; | ||
} | ||
else { | ||
hashFunction = args; | ||
} | ||
return (target, propertyKey, descriptor) => { | ||
if (descriptor.value != null) { | ||
descriptor.value = getNewFunction(descriptor.value, autoHashOrHashFn); | ||
descriptor.value = getNewFunction(descriptor.value, hashFunction, duration, tags); | ||
} | ||
else if (descriptor.get != null) { | ||
descriptor.get = getNewFunction(descriptor.get, autoHashOrHashFn); | ||
descriptor.get = getNewFunction(descriptor.get, hashFunction, duration, tags); | ||
} | ||
@@ -14,38 +25,54 @@ else { | ||
} | ||
export function MemoizeExpiring(duration, autoHashOrHashFn) { | ||
return (target, propertyKey, descriptor) => { | ||
if (descriptor.value != null) { | ||
descriptor.value = getNewFunction(descriptor.value, autoHashOrHashFn, duration); | ||
export function MemoizeExpiring(expiring, hashFunction) { | ||
return Memoize({ | ||
expiring, | ||
hashFunction | ||
}); | ||
} | ||
const clearCacheTagsMap = new Map(); | ||
export function clear(tags) { | ||
const cleared = new Set(); | ||
for (const tag of tags) { | ||
const maps = clearCacheTagsMap.get(tag); | ||
if (maps) { | ||
for (const mp of maps) { | ||
if (!cleared.has(mp)) { | ||
mp.clear(); | ||
cleared.add(mp); | ||
} | ||
} | ||
} | ||
else if (descriptor.get != null) { | ||
descriptor.get = getNewFunction(descriptor.get, autoHashOrHashFn, duration); | ||
} | ||
else { | ||
throw 'Only put a Memoize() decorator on a method or get accessor.'; | ||
} | ||
}; | ||
} | ||
return cleared.size; | ||
} | ||
let counter = 0; | ||
function getNewFunction(originalMethod, autoHashOrHashFn, duration = 0) { | ||
const identifier = ++counter; | ||
function getNewFunction(originalMethod, hashFunction, duration = 0, tags) { | ||
const propMapName = Symbol(`__memoized_map__`); | ||
return function (...args) { | ||
const propValName = `__memoized_value_${identifier}`; | ||
const propMapName = `__memoized_map_${identifier}`; | ||
let returnedValue; | ||
if (autoHashOrHashFn || args.length > 0 || duration > 0) { | ||
if (!this.hasOwnProperty(propMapName)) { | ||
Object.defineProperty(this, propMapName, { | ||
configurable: false, | ||
enumerable: false, | ||
writable: false, | ||
value: new Map() | ||
}); | ||
if (!this.hasOwnProperty(propMapName)) { | ||
Object.defineProperty(this, propMapName, { | ||
configurable: false, | ||
enumerable: false, | ||
writable: false, | ||
value: new Map() | ||
}); | ||
} | ||
let myMap = this[propMapName]; | ||
if (Array.isArray(tags)) { | ||
for (const tag of tags) { | ||
if (clearCacheTagsMap.has(tag)) { | ||
clearCacheTagsMap.get(tag).push(myMap); | ||
} | ||
else { | ||
clearCacheTagsMap.set(tag, [myMap]); | ||
} | ||
} | ||
let myMap = this[propMapName]; | ||
} | ||
if (hashFunction || args.length > 0 || duration > 0) { | ||
let hashKey; | ||
if (autoHashOrHashFn === true) { | ||
if (hashFunction === true) { | ||
hashKey = args.map(a => a.toString()).join('!'); | ||
} | ||
else if (autoHashOrHashFn) { | ||
hashKey = autoHashOrHashFn.apply(this, args); | ||
else if (hashFunction) { | ||
hashKey = hashFunction.apply(this, args); | ||
} | ||
@@ -78,13 +105,9 @@ else { | ||
else { | ||
if (this.hasOwnProperty(propValName)) { | ||
returnedValue = this[propValName]; | ||
const hashKey = this; | ||
if (myMap.has(hashKey)) { | ||
returnedValue = myMap.get(hashKey); | ||
} | ||
else { | ||
returnedValue = originalMethod.apply(this, args); | ||
Object.defineProperty(this, propValName, { | ||
configurable: false, | ||
enumerable: false, | ||
writable: false, | ||
value: returnedValue | ||
}); | ||
myMap.set(hashKey, returnedValue); | ||
} | ||
@@ -91,0 +114,0 @@ } |
@@ -1,2 +0,9 @@ | ||
export declare function Memoize(autoHashOrHashFn?: boolean | ((...args: any[]) => any)): (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => void; | ||
export declare function MemoizeExpiring(duration: number, autoHashOrHashFn?: boolean | ((...args: any[]) => any)): (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => void; | ||
interface MemoizeArgs { | ||
expiring?: number; | ||
hashFunction?: boolean | ((...args: any[]) => any); | ||
tags?: string[]; | ||
} | ||
export declare function Memoize(args?: MemoizeArgs | MemoizeArgs['hashFunction']): (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => void; | ||
export declare function MemoizeExpiring(expiring: number, hashFunction?: MemoizeArgs['hashFunction']): (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => void; | ||
export declare function clear(tags: string[]): number; | ||
export {}; |
@@ -12,10 +12,21 @@ (function (factory) { | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.MemoizeExpiring = exports.Memoize = void 0; | ||
function Memoize(autoHashOrHashFn) { | ||
exports.clear = exports.MemoizeExpiring = exports.Memoize = void 0; | ||
function Memoize(args) { | ||
var hashFunction; | ||
var duration; | ||
var tags; | ||
if (typeof args === 'object') { | ||
hashFunction = args.hashFunction; | ||
duration = args.expiring; | ||
tags = args.tags; | ||
} | ||
else { | ||
hashFunction = args; | ||
} | ||
return function (target, propertyKey, descriptor) { | ||
if (descriptor.value != null) { | ||
descriptor.value = getNewFunction(descriptor.value, autoHashOrHashFn); | ||
descriptor.value = getNewFunction(descriptor.value, hashFunction, duration, tags); | ||
} | ||
else if (descriptor.get != null) { | ||
descriptor.get = getNewFunction(descriptor.get, autoHashOrHashFn); | ||
descriptor.get = getNewFunction(descriptor.get, hashFunction, duration, tags); | ||
} | ||
@@ -28,20 +39,31 @@ else { | ||
exports.Memoize = Memoize; | ||
function MemoizeExpiring(duration, autoHashOrHashFn) { | ||
return function (target, propertyKey, descriptor) { | ||
if (descriptor.value != null) { | ||
descriptor.value = getNewFunction(descriptor.value, autoHashOrHashFn, duration); | ||
function MemoizeExpiring(expiring, hashFunction) { | ||
return Memoize({ | ||
expiring: expiring, | ||
hashFunction: hashFunction | ||
}); | ||
} | ||
exports.MemoizeExpiring = MemoizeExpiring; | ||
var clearCacheTagsMap = new Map(); | ||
function clear(tags) { | ||
var cleared = new Set(); | ||
for (var _i = 0, tags_1 = tags; _i < tags_1.length; _i++) { | ||
var tag = tags_1[_i]; | ||
var maps = clearCacheTagsMap.get(tag); | ||
if (maps) { | ||
for (var _a = 0, maps_1 = maps; _a < maps_1.length; _a++) { | ||
var mp = maps_1[_a]; | ||
if (!cleared.has(mp)) { | ||
mp.clear(); | ||
cleared.add(mp); | ||
} | ||
} | ||
} | ||
else if (descriptor.get != null) { | ||
descriptor.get = getNewFunction(descriptor.get, autoHashOrHashFn, duration); | ||
} | ||
else { | ||
throw 'Only put a Memoize() decorator on a method or get accessor.'; | ||
} | ||
}; | ||
} | ||
return cleared.size; | ||
} | ||
exports.MemoizeExpiring = MemoizeExpiring; | ||
var counter = 0; | ||
function getNewFunction(originalMethod, autoHashOrHashFn, duration) { | ||
exports.clear = clear; | ||
function getNewFunction(originalMethod, hashFunction, duration, tags) { | ||
if (duration === void 0) { duration = 0; } | ||
var identifier = ++counter; | ||
var propMapName = Symbol("__memoized_map__"); | ||
return function () { | ||
@@ -52,21 +74,30 @@ var args = []; | ||
} | ||
var propValName = "__memoized_value_" + identifier; | ||
var propMapName = "__memoized_map_" + identifier; | ||
var returnedValue; | ||
if (autoHashOrHashFn || args.length > 0 || duration > 0) { | ||
if (!this.hasOwnProperty(propMapName)) { | ||
Object.defineProperty(this, propMapName, { | ||
configurable: false, | ||
enumerable: false, | ||
writable: false, | ||
value: new Map() | ||
}); | ||
if (!this.hasOwnProperty(propMapName)) { | ||
Object.defineProperty(this, propMapName, { | ||
configurable: false, | ||
enumerable: false, | ||
writable: false, | ||
value: new Map() | ||
}); | ||
} | ||
var myMap = this[propMapName]; | ||
if (Array.isArray(tags)) { | ||
for (var _a = 0, tags_2 = tags; _a < tags_2.length; _a++) { | ||
var tag = tags_2[_a]; | ||
if (clearCacheTagsMap.has(tag)) { | ||
clearCacheTagsMap.get(tag).push(myMap); | ||
} | ||
else { | ||
clearCacheTagsMap.set(tag, [myMap]); | ||
} | ||
} | ||
var myMap = this[propMapName]; | ||
} | ||
if (hashFunction || args.length > 0 || duration > 0) { | ||
var hashKey = void 0; | ||
if (autoHashOrHashFn === true) { | ||
if (hashFunction === true) { | ||
hashKey = args.map(function (a) { return a.toString(); }).join('!'); | ||
} | ||
else if (autoHashOrHashFn) { | ||
hashKey = autoHashOrHashFn.apply(this, args); | ||
else if (hashFunction) { | ||
hashKey = hashFunction.apply(this, args); | ||
} | ||
@@ -99,13 +130,9 @@ else { | ||
else { | ||
if (this.hasOwnProperty(propValName)) { | ||
returnedValue = this[propValName]; | ||
var hashKey = this; | ||
if (myMap.has(hashKey)) { | ||
returnedValue = myMap.get(hashKey); | ||
} | ||
else { | ||
returnedValue = originalMethod.apply(this, args); | ||
Object.defineProperty(this, propValName, { | ||
configurable: false, | ||
enumerable: false, | ||
writable: false, | ||
value: returnedValue | ||
}); | ||
myMap.set(hashKey, returnedValue); | ||
} | ||
@@ -112,0 +139,0 @@ } |
{ | ||
"name": "typescript-memoize", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "Memoize decorator for Typescript", | ||
@@ -5,0 +5,0 @@ "main": "./dist/memoize-decorator.js", |
@@ -166,2 +166,13 @@ # typescript-memoize | ||
// Memoize also accepts parameters via a single object argument | ||
@Memoize({ | ||
expiring: 10000, | ||
hashFunction: (name: string, planet: string) => { | ||
return name + ';' + string; | ||
} | ||
}) | ||
public getSameBetterGreeting(name: string, planet: string) { | ||
return 'Hello, ' + name + '! Welcome to ' + planet; | ||
} | ||
} | ||
@@ -179,3 +190,3 @@ ``` | ||
// 'Hello, Darryl! Welcome to Mars' | ||
let greeeterVal2 = moreComplicatedFoo.getBetterGreeting('Darryl', 'Mars'); | ||
let greeterVal2 = moreComplicatedFoo.getBetterGreeting('Darryl', 'Mars'); | ||
@@ -186,1 +197,73 @@ // Fill up the computer with useless greetings: | ||
``` | ||
## Memoize accepts one or more "tag" strings that allow the cache to be invalidated on command | ||
Passing an array with one or more "tag" strings these will allow you to later clear the cache of results associated with methods or the `get`accessors using the `clear()` function. | ||
The `clear()` function also requires an array of "tag" strings. | ||
```typescript | ||
import {Memoize} from 'typescript-memoize'; | ||
class ClearableFoo { | ||
// Memoize accepts tags | ||
@Memoize({ tags: ["foo", "bar"] }) | ||
public getClearableGreeting(name: string, planet: string) { | ||
return 'Hello, ' + name + '! Welcome to ' + planet; | ||
} | ||
// Memoize accepts tags | ||
@Memoize({ tags: ["bar"] }) | ||
public getClearableSum(a: number, b: number) { | ||
return a + b; | ||
} | ||
} | ||
``` | ||
We call these methods from somewhere else in our code. | ||
```typescript | ||
import {clear} from 'typescript-memoize'; | ||
let clearableFoo = new ClearableFoo(); | ||
// 'Hello, Darryl! Welcome to Earth' | ||
let greeterVal1 = clearableFoo.getClearableGreeting('Darryl', 'Earth'); | ||
// Ignores the second parameter, and returns memoized value | ||
// 'Hello, Darryl! Welcome to Earth' | ||
let greeterVal2 = clearableFoo.getClearableGreeting('Darryl', 'Mars'); | ||
// '3' | ||
let sum1 = clearableFoo.getClearableSum(2, 1); | ||
// Ignores the second parameter, and returns memoized value | ||
// '3' | ||
let sum2 = clearableFoo.getClearableSum(2, 2); | ||
clear(["foo"]); | ||
// The memoized values are cleared, return a new value | ||
// 'Hello, Darryl! Welcome to Mars' | ||
let greeterVal3 = clearableFoo.getClearableGreeting('Darryl', 'Mars'); | ||
// The memoized value is not associated with 'foo' tag, returns memoized value | ||
// '3' | ||
let sum3 = clearableFoo.getClearableSum(2, 2); | ||
clear(["bar"]); | ||
// The memoized values are cleared, return a new value | ||
// 'Hello, Darryl! Welcome to Earth' | ||
let greeterVal4 = clearableFoo.getClearableGreeting('Darryl', 'Earth'); | ||
// The memoized values are cleared, return a new value | ||
// '4' | ||
let sum4 = clearableFoo.getClearableSum(2, 2); | ||
``` |
@@ -1,60 +0,92 @@ | ||
export function Memoize(autoHashOrHashFn?: boolean | ((...args: any[]) => any)) { | ||
interface MemoizeArgs { | ||
expiring?: number; | ||
hashFunction?: boolean | ((...args: any[]) => any); | ||
tags?: string[]; | ||
} | ||
export function Memoize(args?: MemoizeArgs | MemoizeArgs['hashFunction']) { | ||
let hashFunction: MemoizeArgs['hashFunction']; | ||
let duration: MemoizeArgs['expiring']; | ||
let tags: MemoizeArgs['tags']; | ||
if (typeof args === 'object') { | ||
hashFunction = args.hashFunction; | ||
duration = args.expiring; | ||
tags = args.tags; | ||
} else { | ||
hashFunction = args; | ||
} | ||
return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => { | ||
if (descriptor.value != null) { | ||
descriptor.value = getNewFunction(descriptor.value, autoHashOrHashFn); | ||
descriptor.value = getNewFunction(descriptor.value, hashFunction, duration, tags); | ||
} else if (descriptor.get != null) { | ||
descriptor.get = getNewFunction(descriptor.get, autoHashOrHashFn); | ||
descriptor.get = getNewFunction(descriptor.get, hashFunction, duration, tags); | ||
} else { | ||
throw 'Only put a Memoize() decorator on a method or get accessor.'; | ||
} | ||
}; | ||
} | ||
export function MemoizeExpiring(duration: number, autoHashOrHashFn?: boolean | ((...args: any[]) => any)) { | ||
return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => { | ||
export function MemoizeExpiring(expiring: number, hashFunction?: MemoizeArgs['hashFunction']) { | ||
return Memoize({ | ||
expiring, | ||
hashFunction | ||
}); | ||
} | ||
if (descriptor.value != null) { | ||
descriptor.value = getNewFunction(descriptor.value, autoHashOrHashFn, duration); | ||
} else if (descriptor.get != null) { | ||
descriptor.get = getNewFunction(descriptor.get, autoHashOrHashFn, duration); | ||
} else { | ||
throw 'Only put a Memoize() decorator on a method or get accessor.'; | ||
const clearCacheTagsMap: Map<string, Map<any, any>[]> = new Map(); | ||
export function clear (tags: string[]): number { | ||
const cleared: Set<Map<any, any>> = new Set(); | ||
for (const tag of tags) { | ||
const maps = clearCacheTagsMap.get(tag); | ||
if (maps) { | ||
for (const mp of maps) { | ||
if (!cleared.has(mp)) { | ||
mp.clear(); | ||
cleared.add(mp); | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
return cleared.size; | ||
} | ||
let counter = 0; | ||
function getNewFunction(originalMethod: () => void, autoHashOrHashFn?: boolean | ((...args: any[]) => any), duration: number = 0) { | ||
const identifier = ++counter; | ||
function getNewFunction(originalMethod: () => void, hashFunction?: MemoizeArgs['hashFunction'], duration: number = 0, tags?: MemoizeArgs['tags']) { | ||
const propMapName = Symbol(`__memoized_map__`); | ||
// The function returned here gets called instead of originalMethod. | ||
return function (...args: any[]) { | ||
const propValName = `__memoized_value_${identifier}`; | ||
const propMapName = `__memoized_map_${identifier}`; | ||
let returnedValue: any; | ||
if (autoHashOrHashFn || args.length > 0 || duration > 0) { | ||
// Get or create map | ||
if (!this.hasOwnProperty(propMapName)) { | ||
Object.defineProperty(this, propMapName, { | ||
configurable: false, | ||
enumerable: false, | ||
writable: false, | ||
value: new Map<any, any>() | ||
}); | ||
} | ||
let myMap: Map<any, any> = this[propMapName]; | ||
// Get or create map | ||
if (!this.hasOwnProperty(propMapName)) { | ||
Object.defineProperty(this, propMapName, { | ||
configurable: false, | ||
enumerable: false, | ||
writable: false, | ||
value: new Map<any, any>() | ||
}); | ||
if (Array.isArray(tags)) { | ||
for (const tag of tags) { | ||
if (clearCacheTagsMap.has(tag)) { | ||
clearCacheTagsMap.get(tag).push(myMap); | ||
} else { | ||
clearCacheTagsMap.set(tag, [myMap]); | ||
} | ||
} | ||
let myMap: Map<any, any> = this[propMapName]; | ||
} | ||
if (hashFunction || args.length > 0 || duration > 0) { | ||
let hashKey: any; | ||
// If true is passed as first parameter, will automatically use every argument, passed to string | ||
if (autoHashOrHashFn === true) { | ||
if (hashFunction === true) { | ||
hashKey = args.map(a => a.toString()).join('!'); | ||
} else if (autoHashOrHashFn) { | ||
hashKey = autoHashOrHashFn.apply(this, args); | ||
} else if (hashFunction) { | ||
hashKey = hashFunction.apply(this, args); | ||
} else { | ||
@@ -87,13 +119,8 @@ hashKey = args[0]; | ||
} else { | ||
if (this.hasOwnProperty(propValName)) { | ||
returnedValue = this[propValName]; | ||
const hashKey = this; | ||
if (myMap.has(hashKey)) { | ||
returnedValue = myMap.get(hashKey); | ||
} else { | ||
returnedValue = originalMethod.apply(this, args); | ||
Object.defineProperty(this, propValName, { | ||
configurable: false, | ||
enumerable: false, | ||
writable: false, | ||
value: returnedValue | ||
}); | ||
myMap.set(hashKey, returnedValue); | ||
} | ||
@@ -100,0 +127,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29883
386
267